summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/developer/building-frr-for-fedora.rst122
-rw-r--r--doc/developer/building-frr-for-fedora24.rst169
-rw-r--r--doc/developer/building-frr-for-ubuntu1404.rst187
-rw-r--r--doc/developer/building-frr-for-ubuntu1604.rst216
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst205
-rw-r--r--doc/developer/building.rst2
-rw-r--r--doc/developer/conf.py2
-rw-r--r--doc/developer/include-compile.rst37
-rw-r--r--doc/developer/subdir.am3
-rw-r--r--doc/manpages/conf.py2
-rw-r--r--isisd/isis_zebra.c4
-rw-r--r--ospf6d/ospf6_zebra.c3
-rw-r--r--ripngd/ripng_zebra.c3
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/zebra.conf6
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/zebra.conf5
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/zebra.conf5
-rw-r--r--tests/topotests/lib/topogen.py4
-rw-r--r--tests/topotests/lib/topotest.py33
-rw-r--r--zebra/connected.c6
-rw-r--r--zebra/debug.c28
-rw-r--r--zebra/debug.h7
-rw-r--r--zebra/kernel_netlink.c46
-rw-r--r--zebra/main.c2
-rw-r--r--zebra/rib.h18
-rw-r--r--zebra/rt.h3
-rw-r--r--zebra/rt_netlink.c9
-rw-r--r--zebra/rt_socket.c54
-rw-r--r--zebra/zapi_msg.c8
-rw-r--r--zebra/zebra_mpls.h33
-rw-r--r--zebra/zebra_rib.c354
-rw-r--r--zebra/zebra_rnh.c196
-rw-r--r--zebra/zebra_rnh.h10
-rw-r--r--zebra/zebra_router.c2
-rw-r--r--zebra/zebra_vrf.c16
-rw-r--r--zebra/zebra_vty.c2
-rw-r--r--zebra/zebra_vxlan.c10
-rw-r--r--zebra/zserv.c12
-rw-r--r--zebra/zserv.h7
38 files changed, 1026 insertions, 805 deletions
diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst
new file mode 100644
index 0000000000..6900aed0e0
--- /dev/null
+++ b/doc/developer/building-frr-for-fedora.rst
@@ -0,0 +1,122 @@
+Fedora 24+
+==========
+
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
+
+These instructions have been tested on Fedora 24+.
+
+Installing Dependencies
+-----------------------
+
+.. code-block:: console
+
+ sudo dnf install git autoconf automake libtool make gawk \
+ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \
+ pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \
+ perl-core patch
+
+.. include:: building-libyang.rst
+
+Building & Installing FRR
+-------------------------
+
+Add FRR user and groups
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo groupadd -g 92 frr
+ sudo groupadd -r -g 85 frrvty
+ sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
+ -c "FRR FRRouting suite" -d /var/run/frr frr
+
+Compile
+^^^^^^^
+
+.. include:: include-compile.rst
+
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -m 775 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following
+content:
+
+::
+
+ #
+ # Enable packet forwarding
+ #
+ net.ipv4.conf.all.forwarding=1
+ net.ipv6.conf.all.forwarding=1
+ #
+ # Enable MPLS Label processing on all interfaces
+ #
+ #net.mpls.conf.eth0.input=1
+ #net.mpls.conf.eth1.input=1
+ #net.mpls.conf.eth2.input=1
+ #net.mpls.platform_labels=100000
+
+.. note::
+
+ MPLS must be invidividually enabled on each interface that requires it. See
+ the example in the config block above.
+
+Load the modifed sysctls on the system:
+
+.. code-block:: console
+
+ sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
+
+Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content:
+
+::
+
+ # Load MPLS Kernel Modules
+ mpls-router
+ mpls-iptunnel
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
+
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
+ sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+ sudo systemctl enable frr
+
+Enable daemons
+^^^^^^^^^^^^^^
+
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
+
+Start FRR
+^^^^^^^^^
+
+.. code-block:: frr
+
+ sudo systemctl start frr
diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst
deleted file mode 100644
index 708baec3ee..0000000000
--- a/doc/developer/building-frr-for-fedora24.rst
+++ /dev/null
@@ -1,169 +0,0 @@
-Fedora 24
-=========================================
-
-This document describes installation from source. If you want to build an RPM,
-see :ref:`packaging-redhat`.
-
-Install required packages
--------------------------
-
-Add packages:
-
-::
-
- sudo dnf install git autoconf automake libtool make gawk \
- readline-devel texinfo net-snmp-devel groff pkgconfig \
- json-c-devel pam-devel pytest bison flex c-ares-devel \
- python3-devel python3-sphinx
-
-.. include:: building-libyang.rst
-
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
-
-Add frr groups and user
-^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo groupadd -g 92 frr
- sudo groupadd -r -g 85 frrvty
- sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
- -c "FRR FRRouting suite" -d /var/run/frr frr
-
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-(You may prefer different options on configure statement. These are just
-an example.)
-
-::
-
- git clone https://github.com/frrouting/frr.git frr
- cd frr
- ./bootstrap.sh
- ./configure \
- --bindir=/usr/bin \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --libdir=/usr/lib/frr \
- --libexecdir=/usr/lib/frr \
- --localstatedir=/var/run/frr \
- --with-moduledir=/usr/lib/frr/modules \
- --enable-snmp=agentx \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --disable-exampledir \
- --enable-fpm \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo mkdir /var/log/frr
- sudo mkdir /etc/frr
- sudo touch /etc/frr/zebra.conf
- sudo touch /etc/frr/bgpd.conf
- sudo touch /etc/frr/ospfd.conf
- sudo touch /etc/frr/ospf6d.conf
- sudo touch /etc/frr/isisd.conf
- sudo touch /etc/frr/ripd.conf
- sudo touch /etc/frr/ripngd.conf
- sudo touch /etc/frr/pimd.conf
- sudo touch /etc/frr/ldpd.conf
- sudo touch /etc/frr/nhrpd.conf
- sudo touch /etc/frr/eigrpd.conf
- sudo touch /etc/frr/babeld.conf
- sudo chown -R frr:frr /etc/frr/
- sudo touch /etc/frr/vtysh.conf
- sudo chown frr:frrvty /etc/frr/vtysh.conf
- sudo chmod 640 /etc/frr/*.conf
-
-Install daemon config file
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo install -p -m 644 redhat/daemons /etc/frr/
- sudo chown frr:frr /etc/frr/daemons
-
-Edit /etc/frr/daemons as needed to select the required daemons
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
-Enable the daemons as required by changing the value to ``yes``
-
-Enable IP & IPv6 forwarding (and MPLS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
-following content: (Please make sure to list all interfaces with
-required MPLS similar to ``net.mpls.conf.eth0.input=1``)
-
-::
-
- # Sysctl for routing
- #
- # Routing: We need to forward packets
- net.ipv4.conf.all.forwarding=1
- net.ipv6.conf.all.forwarding=1
- #
- # Enable MPLS Label processing on all interfaces
- net.mpls.conf.eth0.input=1
- net.mpls.conf.eth1.input=1
- net.mpls.conf.eth2.input=1
- net.mpls.platform_labels=100000
-
-Load the modified sysctl's on the system:
-
-::
-
- sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-
-Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
-content:
-
-::
-
- # Load MPLS Kernel Modules
- mpls-router
- mpls-iptunnel
-
-And load the kernel modules on the running system:
-
-::
-
- sudo modprobe mpls-router mpls-iptunnel
-
-Install frr Service and redhat init files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
- sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
-
-Enable required frr at startup
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo systemctl enable frr
-
-Reboot or start FRR manually
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo systemctl start frr
diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst
index b1eaf57e8d..0942f19737 100644
--- a/doc/developer/building-frr-for-ubuntu1404.rst
+++ b/doc/developer/building-frr-for-ubuntu1404.rst
@@ -1,35 +1,30 @@
-Ubuntu 14.04LTS
-===============================================
+Ubuntu 14.04 LTS
+================
-- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
- requires Linux Kernel 4.5 or higher (LDP can be built, but may have
- limited use without MPLS) For an updated Ubuntu Kernel, see
- http://kernel.ubuntu.com/~kernel-ppa/mainline/
-
-Install required packages
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Add packages:
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ apt-get update
apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \
- dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
- libc-ares-dev python3-dev python3-sphinx install-info build-essential
+ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
+ libc-ares-dev python3-dev python3-sphinx install-info build-essential \
+ libsnmp-dev perl
.. include:: building-libyang.rst
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
@@ -37,102 +32,104 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- git clone https://github.com/frrouting/frr.git frr
- cd frr
- ./bootstrap.sh
- ./configure \
- --prefix=/usr \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --enable-configfile-mask=0640 \
- --enable-logfile-mask=0640 \
- --enable-fpm \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
+
+ sudo install -m 775 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
+other settings):
::
- sudo install -m 755 -o frr -g frr -d /var/log/frr
- sudo install -m 775 -o frr -g frrvty -d /etc/frr
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
- sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
-
-Enable IP & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
-other settings)
+ # Uncomment the next line to enable packet forwarding for IPv4
+ net.ipv4.ip_forward=1
+
+ # Uncomment the next line to enable packet forwarding for IPv6
+ # Enabling this option disables Stateless Address Autoconfiguration
+ # based on Router Advertisements for this host
+ net.ipv6.conf.all.forwarding=1
+
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+ MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires
+ kernel 4.5 or higher. LDPD can be built, but may have limited use without
+ MPLS. For an updated Ubuntu Kernel, see
+ http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
- # Uncomment the next line to enable packet forwarding for IPv4
- net.ipv4.ip_forward=1
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
+
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
+
+Enable MPLS Forwarding
+""""""""""""""""""""""
- # Uncomment the next line to enable packet forwarding for IPv6
- # Enabling this option disables Stateless Address Autoconfiguration
- # based on Router Advertisements for this host
- net.ipv6.conf.all.forwarding=1
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+::
+
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
Install the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
- sudo install -m 755 tools/frr /etc/init.d/frr
- sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 755 tools/frr /etc/init.d/frr
Enable daemons
^^^^^^^^^^^^^^
-| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
- those daemons you want to start by systemd.
-| For example.
-
-::
-
- zebra=yes
- bgpd=yes
- ospfd=yes
- ospf6d=yes
- ripd=yes
- ripngd=yes
- isisd=yes
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
Start the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^
-- /etc/init.d/frr start
-- use ``/etc/init.d/frr status`` to check its status.
+.. code-block:: console
+
+ /etc/init.d/frr start
+
+Use ``/etc/init.d/frr status`` to check its status.
diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst
index 0762e07eb9..63cb9aa13a 100644
--- a/doc/developer/building-frr-for-ubuntu1604.rst
+++ b/doc/developer/building-frr-for-ubuntu1604.rst
@@ -1,172 +1,134 @@
-Ubuntu 16.04LTS
-===============================================
+Ubuntu 16.04 LTS
+================
-- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
- requires Linux Kernel 4.5 or higher (LDP can be built, but may have
- limited use without MPLS) For an updated Ubuntu Kernel, see
- http://kernel.ubuntu.com/~kernel-ppa/mainline/
-
-Install required packages
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Add packages:
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ apt-get update
apt-get install \
- git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
+ git autoconf automake libtool make gawk libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
- libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
- python3-sphinx install-info build-essential libsystemd-dev
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
- sudo groupadd -r -g 92 frr
- sudo groupadd -r -g 85 frrvty
- sudo adduser --system --ingroup frr --home /var/run/frr/ \
- --gecos "FRR suite" --shell /sbin/nologin frr
- sudo usermod -a -G frrvty frr
+ sudo groupadd -r -g 92 frr
+ sudo groupadd -r -g 85 frrvty
+ sudo adduser --system --ingroup frr --home /var/run/frr/ \
+ --gecos "FRR suite" --shell /sbin/nologin frr
+ sudo usermod -a -G frrvty frr
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- git clone https://github.com/frrouting/frr.git frr
- cd frr
- ./bootstrap.sh
- ./configure \
- --prefix=/usr \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --enable-configfile-mask=0640 \
- --enable-logfile-mask=0640 \
- --enable-fpm \
- --enable-systemd=yes \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
-::
+ sudo install -m 775 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frrvty -d /etc/frr
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 755 -o frr -g frr -d /var/log/frr
- sudo install -m 775 -o frr -g frrvty -d /etc/frr
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
- sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
-
-Enable IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
-other settings)
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
+other settings):
::
- # Uncomment the next line to enable packet forwarding for IPv4
- net.ipv4.ip_forward=1
+ # Uncomment the next line to enable packet forwarding for IPv4
+ net.ipv4.ip_forward=1
+
+ # Uncomment the next line to enable packet forwarding for IPv6
+ # Enabling this option disables Stateless Address Autoconfiguration
+ # based on Router Advertisements for this host
+ net.ipv6.conf.all.forwarding=1
- # Uncomment the next line to enable packet forwarding for IPv6
- # Enabling this option disables Stateless Address Autoconfiguration
- # based on Router Advertisements for this host
- net.ipv6.conf.all.forwarding=1
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
-Enable MPLS Forwarding (with Linux Kernel >= 4.5)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+ MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires
+ kernel 4.5 or higher. LDPD can be built, but may have limited use without
+ MPLS. For an updated Ubuntu Kernel, see
+ http://kernel.ubuntu.com/~kernel-ppa/mainline/
-Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
-line equal to ``net.mpls.conf.eth0.input`` or each interface used with
-MPLS
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
- # Enable MPLS Label processing on all interfaces
- net.mpls.conf.eth0.input=1
- net.mpls.conf.eth1.input=1
- net.mpls.conf.eth2.input=1
- net.mpls.platform_labels=100000
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
-Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
-Add the following lines to ``/etc/modules-load.d/modules.conf``:
+And load the kernel modules on the running system:
-::
+.. code-block:: console
- # Load MPLS Kernel Modules
- mpls-router
- mpls-iptunnel
+ sudo modprobe mpls-router mpls-iptunnel
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+Enable MPLS Forwarding
+""""""""""""""""""""""
-Install the systemd service (if rebooted from last step, change directory back to frr directory)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
::
- sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
- sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
-Enable daemons
-^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
-| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
- those daemons you want to start by systemd.
-| For example.
+.. code-block:: console
-::
+ sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
+ sudo systemctl enable frr
- zebra=yes
- bgpd=yes
- ospfd=yes
- ospf6d=yes
- ripd=yes
- ripngd=yes
- isisd=yes
+Enable daemons
+^^^^^^^^^^^^^^
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
-- systemctl enable frr
+Start FRR
+^^^^^^^^^
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
-- systemctl start frr
-- use ``systemctl status frr`` to check its status.
+ systemctl start frr
diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst
index 089d5a216a..6f7f0acd11 100644
--- a/doc/developer/building-frr-for-ubuntu1804.rst
+++ b/doc/developer/building-frr-for-ubuntu1804.rst
@@ -1,55 +1,44 @@
Ubuntu 18.04 LTS
================
-Install dependencies
---------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Required packages
-^^^^^^^^^^^^^^^^^
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ sudo apt update
sudo apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
- libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
- python3-sphinx install-info build-essential libsystemd-dev
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst
-Optional packages
-^^^^^^^^^^^^^^^^^
-
-Dependencies for additional functionality can be installed as-desired.
-
Protobuf
-~~~~~~~~
+^^^^^^^^
-::
+.. code-block:: console
- sudo apt-get install \
- protobuf-c-compiler \
- libprotobuf-c-dev
+ sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
ZeroMQ
-~~~~~~
-
-::
+^^^^^^
- sudo apt-get install \
- libzmq5 \
- libzmq3-dev
+.. code-block:: console
-Get FRR, compile it and install it (from Git)
----------------------------------------------
+ sudo apt-get install libzmq5 libzmq3-dev
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
@@ -57,104 +46,29 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
-Download source
-^^^^^^^^^^^^^^^
-
-::
-
- git clone https://github.com/frrouting/frr.git frr
-
-Configure
-^^^^^^^^^
-Options below are provided as an example.
-
-.. seealso:: *Installation* section of user guide
-
-.. code-block:: shell
-
- cd frr
- ./bootstrap.sh
- ./configure \
- --prefix=/usr \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --enable-configfile-mask=0640 \
- --enable-logfile-mask=0640 \
- --enable-fpm \
- --enable-systemd=yes \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
-
-If optional packages were installed, the associated feature may now be
-enabled.
-
-.. option:: --enable-protobuf
-
-Enable support for protobuf transport
-
-.. option:: --enable-zeromq
-
-Enable support for ZeroMQ transport
-
Compile
^^^^^^^
-::
-
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. include:: include-compile.rst
-Although not strictly necessary, it's good practice to create empty
-configuration files _before_ starting FRR. This assures that the permissions
-are correct. If the files are not already present, FRR will create them.
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-It's also important to consider _which_ files to create. FRR supports writing
-configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
+.. code-block:: console
-.. seealso:: *VTYSH* section of user guide
-
-The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR
-to ignore daemon-specific configuration files.
-
-Daemon-specific configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
- sudo install -m 755 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
-
-Monolithic configuration
-~~~~~~~~~~~~~~~~~~~~~~~~
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
-::
+Tweak sysctls
+^^^^^^^^^^^^^
- sudo install -m 755 -o frr -g frr -d /var/log/frr
- sudo install -m 775 -o frr -g frrvty -d /etc/frr
- sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf
-
-Enable IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings):
@@ -169,8 +83,10 @@ other settings):
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
+"""""""""""""""""""""""
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
@@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
mpls_router
mpls_iptunnel
-Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
Enable MPLS Forwarding
-^^^^^^^^^^^^^^^^^^^^^^
+""""""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
@@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
-Install the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
- sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo systemctl enable frr
Enable daemons
^^^^^^^^^^^^^^
-Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those
-daemons you want to start by systemd. For example:
-
-::
-
- zebra=yes
- bgpd=yes
- ospfd=yes
- ospf6d=yes
- ripd=yes
- ripngd=yes
- isisd=yes
-
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
-Enabling the systemd service causes FRR to be started upon boot. To enable it,
-use the following command:
-
-.. code-block:: shell
-
- systemctl enable frr
-
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+Start FRR
+^^^^^^^^^
.. code-block:: shell
systemctl start frr
-
-After starting the service, you can use ``systemctl status frr`` to check its
-status.
diff --git a/doc/developer/building.rst b/doc/developer/building.rst
index 96559b0abe..c13fb10ffc 100644
--- a/doc/developer/building.rst
+++ b/doc/developer/building.rst
@@ -12,7 +12,7 @@ Building FRR
building-frr-for-centos7
building-frr-for-debian8
building-frr-for-debian9
- building-frr-for-fedora24
+ building-frr-for-fedora
building-frr-for-freebsd10
building-frr-for-freebsd11
building-frr-for-freebsd9
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index af8673e5fa..9acfab739a 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -131,7 +131,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
+exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst
new file mode 100644
index 0000000000..0ff0ae3ffe
--- /dev/null
+++ b/doc/developer/include-compile.rst
@@ -0,0 +1,37 @@
+Clone the FRR git repo and use the included ``configure`` script to configure
+FRR's build time options to your liking. The full option listing can be
+obtained by running ``./configure -h``. The options shown below are examples.
+
+.. note::
+
+ If your platform uses ``systemd``, please make sure to add
+ ``--enable-systemd=yes`` to your configure options.
+
+.. code-block:: console
+
+ git clone https://github.com/frrouting/frr.git frr
+ cd frr
+ ./bootstrap.sh
+ ./configure \
+ --prefix=/usr \
+ --includedir=\${prefix}/include \
+ --enable-exampledir=\${prefix}/share/doc/frr/examples \
+ --bindir=\${prefix}/bin \
+ --sbindir=\${prefix}/lib/frr \
+ --libdir=\${prefix}/lib/frr \
+ --libexecdir=\${prefix}/lib/frr \
+ --localstatedir=/var/run/frr \
+ --sysconfdir=/etc/frr \
+ --with-moduledir=\${prefix}/lib/frr/modules \
+ --with-libyang-pluginsdir=\${prefix}/lib/frr/libyang_plugins \
+ --enable-configfile-mask=0640 \
+ --enable-logfile-mask=0640 \
+ --enable-snmp=agentx \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --with-pkg-git-version \
+ --with-pkg-extra-version=-MyOwnFRRVersion
+ make
+ sudo make install
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index a0c5e6fc9d..7ae48881ab 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -10,7 +10,7 @@ dev_RSTFILES = \
doc/developer/building-frr-for-centos7.rst \
doc/developer/building-frr-for-debian8.rst \
doc/developer/building-frr-for-debian9.rst \
- doc/developer/building-frr-for-fedora24.rst \
+ doc/developer/building-frr-for-fedora.rst \
doc/developer/building-frr-for-freebsd10.rst \
doc/developer/building-frr-for-freebsd11.rst \
doc/developer/building-frr-for-freebsd9.rst \
@@ -27,6 +27,7 @@ dev_RSTFILES = \
doc/developer/cli.rst \
doc/developer/conf.py \
doc/developer/hooks.rst \
+ doc/developer/include-compile.rst \
doc/developer/index.rst \
doc/developer/library.rst \
doc/developer/logging.rst \
diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py
index f57bc1d278..46240de1c0 100644
--- a/doc/manpages/conf.py
+++ b/doc/manpages/conf.py
@@ -129,7 +129,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst']
+exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index dfe74e325e..79d79f8911 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient,
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
+ if (api.prefix.family == AF_INET6
+ && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 54f1735e7a..abdc82a738 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient,
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
ifindex = api.nexthops[0].ifindex;
nexthop = &api.nexthops[0].gate.ipv6;
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index 28a57f25d0..c68c066f0c 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -126,6 +126,9 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient,
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
nexthop = api.nexthops[0].gate.ipv6;
ifindex = api.nexthops[0].ifindex;
diff --git a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf
index d0ec9f5d75..edfa1780a9 100644
--- a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf
+++ b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf
@@ -2,10 +2,12 @@ log file zebra.log
!
hostname r1
!
-debug zebra rib
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
debug zebra nht
debug zebra pseudowires
-debug zebra packet
+debug zebra mpls
!
interface lo
ip address 1.1.1.1/32
diff --git a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf
index 8bd800714c..6b95efdce8 100644
--- a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf
+++ b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf
@@ -2,10 +2,11 @@ log file zebra.log
!
hostname r2
!
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
debug zebra nht
debug zebra pseudowires
-debug zebra packet
!
interface lo
ip address 2.2.2.2/32
diff --git a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf
index 2ff61365b5..85ec68ff32 100644
--- a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf
+++ b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf
@@ -2,10 +2,11 @@ log file zebra.log
!
hostname r3
!
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
debug zebra nht
debug zebra pseudowires
-debug zebra packet
!
interface lo
ip address 3.3.3.3/32
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 8688a13aef..d989240a16 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -586,9 +586,9 @@ class TopoRouter(TopoGear):
os.system('chmod -R go+rw /tmp/topotests')
# Open router log file
- logfile = '{0}/{1}.log'.format(dir, name)
-
+ logfile = '{0}/{1}.log'.format(self.logdir, name)
self.logger = logger_config.get_logger(name=name, target=logfile)
+
self.tgen.topo.addNode(self.name, cls=self.cls, **params)
def __str__(self):
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 84358b94bc..e0da20e07f 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -63,23 +63,6 @@ class json_cmp_result(object):
def __str__(self):
return '\n'.join(self.errors)
-def get_test_logdir(node=None, init=False):
- """
- Return the current test log directory based on PYTEST_CURRENT_TEST
- environment variable.
- Optional paramters:
- node: when set, adds the node specific log directory to the init dir
- init: when set, initializes the log directory and fixes path permissions
- """
- cur_test = os.environ['PYTEST_CURRENT_TEST']
-
- ret = '/tmp/topotests/' + cur_test[0:cur_test.find(".py")].replace('/','.')
- if node != None:
- dir = ret + "/" + node
- if init:
- os.system('mkdir -p ' + dir)
- os.system('chmod -R go+rw /tmp/topotests')
- return ret
def json_diff(d1, d2):
"""
@@ -612,7 +595,21 @@ class Router(Node):
def __init__(self, name, **params):
super(Router, self).__init__(name, **params)
- self.logdir = params.get('logdir', get_test_logdir(name, True))
+ self.logdir = params.get('logdir')
+
+ # If this topology is using old API and doesn't have logdir
+ # specified, then attempt to generate an unique logdir.
+ if self.logdir is None:
+ cur_test = os.environ['PYTEST_CURRENT_TEST']
+ self.logdir = ('/tmp/topotests/' +
+ cur_test[0:cur_test.find(".py")].replace('/', '.'))
+
+ # If the logdir is not created, then create it and set the
+ # appropriated permissions.
+ if not os.path.isdir(self.logdir):
+ os.system('mkdir -p ' + self.logdir + '/' + name)
+ os.system('chmod -R go+rw /tmp/topotests')
+
self.daemondir = None
self.hasmpls = False
self.routertype = 'frr'
diff --git a/zebra/connected.c b/zebra/connected.c
index 128f397552..7114a3286b 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -272,7 +272,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
ifp->vrf_id, ifp->name,
prefix2str(&p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
}
}
@@ -437,7 +437,7 @@ void connected_down(struct interface *ifp, struct connected *ifc)
ifp->vrf_id, ifp->name,
prefix2str(&p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
}
}
@@ -471,7 +471,7 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
ifp->vrf_id, ifp->name,
prefix2str(p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), p);
}
}
diff --git a/zebra/debug.c b/zebra/debug.c
index 87999a1bbc..8e5fb0ea10 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -87,7 +87,9 @@ DEFUN_NOSH (show_debugging_zebra,
if (IS_ZEBRA_DEBUG_FPM)
vty_out(vty, " Zebra FPM debugging is on\n");
- if (IS_ZEBRA_DEBUG_NHT)
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ vty_out(vty, " Zebra detailed next-hop tracking debugging is on\n");
+ else if (IS_ZEBRA_DEBUG_NHT)
vty_out(vty, " Zebra next-hop tracking debugging is on\n");
if (IS_ZEBRA_DEBUG_MPLS)
vty_out(vty, " Zebra MPLS debugging is on\n");
@@ -119,12 +121,19 @@ DEFUN (debug_zebra_events,
DEFUN (debug_zebra_nht,
debug_zebra_nht_cmd,
- "debug zebra nht",
+ "debug zebra nht [detailed]",
DEBUG_STR
"Zebra configuration\n"
- "Debug option set for zebra next hop tracking\n")
+ "Debug option set for zebra next hop tracking\n"
+ "Debug option set for detailed info\n")
{
+ int idx = 0;
+
zebra_debug_nht = ZEBRA_DEBUG_NHT;
+
+ if (argv_find(argv, argc, "detailed", &idx))
+ zebra_debug_nht |= ZEBRA_DEBUG_NHT_DETAILED;
+
return CMD_SUCCESS;
}
@@ -320,11 +329,12 @@ DEFUN (no_debug_zebra_events,
DEFUN (no_debug_zebra_nht,
no_debug_zebra_nht_cmd,
- "no debug zebra nht",
+ "no debug zebra nht [detailed]",
NO_STR
DEBUG_STR
"Zebra configuration\n"
- "Debug option set for zebra next hop tracking\n")
+ "Debug option set for zebra next hop tracking\n"
+ "Debug option set for detailed info\n")
{
zebra_debug_nht = 0;
return CMD_SUCCESS;
@@ -490,10 +500,15 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug zebra fpm\n");
write++;
}
- if (IS_ZEBRA_DEBUG_NHT) {
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ vty_out(vty, "debug zebra nht detailed\n");
+ write++;
+ } else if (IS_ZEBRA_DEBUG_NHT) {
vty_out(vty, "debug zebra nht\n");
write++;
}
+
if (IS_ZEBRA_DEBUG_MPLS) {
vty_out(vty, "debug zebra mpls\n");
write++;
@@ -530,6 +545,7 @@ void zebra_debug_init(void)
zebra_debug_pw = 0;
zebra_debug_dplane = 0;
zebra_debug_mlag = 0;
+ zebra_debug_nht = 0;
install_node(&debug_node, config_write_debug);
diff --git a/zebra/debug.h b/zebra/debug.h
index 944ad6d68b..176226f7ae 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -44,7 +44,9 @@ extern "C" {
#define ZEBRA_DEBUG_RIB_DETAILED 0x02
#define ZEBRA_DEBUG_FPM 0x01
-#define ZEBRA_DEBUG_NHT 0x01
+
+#define ZEBRA_DEBUG_NHT 0x01
+#define ZEBRA_DEBUG_NHT_DETAILED 0x02
#define ZEBRA_DEBUG_MPLS 0x01
@@ -76,7 +78,10 @@ extern "C" {
#define IS_ZEBRA_DEBUG_RIB_DETAILED (zebra_debug_rib & ZEBRA_DEBUG_RIB_DETAILED)
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
+
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
+#define IS_ZEBRA_DEBUG_NHT_DETAILED (zebra_debug_nht & ZEBRA_DEBUG_NHT_DETAILED)
+
#define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW)
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index c5fbfd4481..fe37a33358 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -606,50 +606,56 @@ const char *nl_rttype_to_str(uint8_t rttype)
return lookup_msg(rttype_str, rttype, "");
}
-#define NL_OK(nla, len) \
+#define NLA_OK(nla, len) \
((len) >= (int)sizeof(struct nlattr) \
&& (nla)->nla_len >= sizeof(struct nlattr) \
&& (nla)->nla_len <= (len))
-#define NL_NEXT(nla, attrlen) \
- ((attrlen) -= RTA_ALIGN((nla)->nla_len), \
- (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
-#define NL_RTA(r) \
- ((struct nlattr *)(((char *)(r)) \
- + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+#define NLA_NEXT(nla, attrlen) \
+ ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
+ (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
+#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len))
+#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0)))
+
+#define ERR_NLA(err, inner_len) \
+ ((struct nlattr *)(((char *)(err)) \
+ + NLMSG_ALIGN(sizeof(struct nlmsgerr)) \
+ + NLMSG_ALIGN((inner_len))))
static void netlink_parse_nlattr(struct nlattr **tb, int max,
struct nlattr *nla, int len)
{
- while (NL_OK(nla, len)) {
+ while (NLA_OK(nla, len)) {
if (nla->nla_type <= max)
tb[nla->nla_type] = nla;
- nla = NL_NEXT(nla, len);
+ nla = NLA_NEXT(nla, len);
}
}
static void netlink_parse_extended_ack(struct nlmsghdr *h)
{
- struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
- const struct nlmsgerr *err =
- (const struct nlmsgerr *)((uint8_t *)h
- + NLMSG_ALIGN(
- sizeof(struct nlmsghdr)));
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h);
const struct nlmsghdr *err_nlh = NULL;
- uint32_t hlen = sizeof(*err);
+ /* Length not including nlmsghdr */
+ uint32_t len = 0;
+ /* Inner error netlink message length */
+ uint32_t inner_len = 0;
const char *msg = NULL;
uint32_t off = 0;
if (!(h->nlmsg_flags & NLM_F_CAPPED))
- hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0);
+
+ len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len);
- memset(tb, 0, sizeof(tb));
- netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+ netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len),
+ len);
if (tb[NLMSGERR_ATTR_MSG])
- msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+ msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]);
if (tb[NLMSGERR_ATTR_OFFS]) {
- off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+ off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]);
if (off > h->nlmsg_len) {
zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");
diff --git a/zebra/main.c b/zebra/main.c
index c605050c57..184e798bd0 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -153,7 +153,9 @@ static void sigint(void)
for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
zserv_close_client(client);
+ zserv_close();
list_delete_all_node(zrouter.client_list);
+
zebra_ptm_finish();
if (retain_mode)
diff --git a/zebra/rib.h b/zebra/rib.h
index ced6692b9b..e26831e1a6 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -145,6 +145,15 @@ typedef struct rib_dest_t_ {
uint32_t flags;
/*
+ * The list of nht prefixes that have ended up
+ * depending on this route node.
+ * After route processing is returned from
+ * the data plane we will run evaluate_rnh
+ * on these prefixes.
+ */
+ struct list *nht;
+
+ /*
* Linkage to put dest on the FPM processing queue.
*/
TAILQ_ENTRY(rib_dest_t_) fpm_q_entries;
@@ -172,6 +181,8 @@ typedef struct rib_dest_t_ {
*/
#define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2))
+#define RIB_DEST_UPDATE_LSPS (1 << (ZEBRA_MAX_QINDEX + 3))
+
/*
* Macro to iterate over each route for a destination (prefix).
*/
@@ -359,6 +370,8 @@ extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter);
extern uint8_t route_distance(int type);
+extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq);
+
/*
* Inline functions.
*/
@@ -431,6 +444,11 @@ static inline struct zebra_vrf *rib_dest_vrf(rib_dest_t *dest)
}
/*
+ * Create the rib_dest_t and attach it to the specified node
+ */
+extern rib_dest_t *zebra_rib_create_dest(struct route_node *rn);
+
+/*
* rib_tables_iter_init
*/
static inline void rib_tables_iter_init(rib_tables_iter_t *iter)
diff --git a/zebra/rt.h b/zebra/rt.h
index bc91edd802..2c77af2aad 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -35,6 +35,9 @@
extern "C" {
#endif
+#define RSYSTEM_ROUTE(type) \
+ ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT)
+
/*
* Update or delete a route, LSP, or pseudowire from the kernel,
* using info from a dataplane context.
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index cf61eb6cb4..289ed5a15b 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1836,7 +1836,9 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
* of the route delete. If that happens yeah we're
* screwed.
*/
- (void)netlink_route_multipath(RTM_DELROUTE, ctx);
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+ (void)netlink_route_multipath(RTM_DELROUTE,
+ ctx);
cmd = RTM_NEWROUTE;
}
@@ -1844,7 +1846,10 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- ret = netlink_route_multipath(cmd, ctx);
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
+ ret = netlink_route_multipath(cmd, ctx);
+ else
+ ret = 0;
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
/* Update installed nexthops to signal which have been
* installed.
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index f25259f300..8d8bdd0a6d 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -304,33 +304,41 @@ static int kernel_rtm(int cmd, const struct prefix *p,
enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
{
enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ uint32_t type, old_type;
if (dplane_ctx_get_src(ctx) != NULL) {
zlog_err("route add: IPv6 sourcedest routes unsupported!");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
+ type = dplane_ctx_get_type(ctx);
+ old_type = dplane_ctx_get_old_type(ctx);
+
frr_elevate_privs(&zserv_privs) {
- if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
- kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
- else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL)
- kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
- else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
+ } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
+ } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
/* Must do delete and add separately -
* no update available
*/
- kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_old_ng(ctx),
- dplane_ctx_get_old_metric(ctx));
-
- kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
+ if (!RSYSTEM_ROUTE(old_type))
+ kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_old_ng(ctx),
+ dplane_ctx_get_old_metric(ctx));
+
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
} else {
zlog_err("Invalid routing socket update op %s (%u)",
dplane_op2str(dplane_ctx_get_op(ctx)),
@@ -339,6 +347,20 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
}
} /* Elevated privs */
+ if (RSYSTEM_ROUTE(type)
+ && dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) {
+ struct nexthop *nexthop;
+
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+ }
+
return res;
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 4e97c272fb..2eeb1f2788 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1036,6 +1036,8 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
uint8_t flags = 0;
uint16_t type = cmd2type[hdr->command];
bool exist;
+ bool flag_changed = false;
+ uint8_t orig_flags;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
@@ -1084,6 +1086,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
if (!rnh)
return;
+ orig_flags = rnh->flags;
if (type == RNH_NEXTHOP_TYPE) {
if (flags
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
@@ -1101,9 +1104,12 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
}
+ if (orig_flags != rnh->flags)
+ flag_changed = true;
+
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
/* Anything not AF_INET/INET6 has been filtered out above */
- if (!exist)
+ if (!exist || flag_changed)
zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type,
&p);
}
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index f8c6c794a4..3a131e1aaf 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -510,28 +510,41 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
return "Unknown";
}
-static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf,
+ struct prefix *p)
{
+ struct route_table *table;
+ struct route_node *rn;
+ rib_dest_t *dest;
+
if (!zvrf)
return;
- zvrf->mpls_flags |= MPLS_FLAG_SCHEDULE_LSPS;
+ table = zvrf->table[family2afi(p->family)][SAFI_UNICAST];
+ if (!table)
+ return;
+
+ rn = route_node_match(table, p);
+ if (!rn)
+ return;
+
+
+ dest = rib_dest_from_rnode(rn);
+ SET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
-static inline void mpls_unmark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_unmark_lsps_for_processing(struct route_node *rn)
{
- if (!zvrf)
- return;
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
- zvrf->mpls_flags &= ~MPLS_FLAG_SCHEDULE_LSPS;
+ UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
-static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf)
+static inline int mpls_should_lsps_be_processed(struct route_node *rn)
{
- if (!zvrf)
- return 0;
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
- return ((zvrf->mpls_flags & MPLS_FLAG_SCHEDULE_LSPS) ? 1 : 0);
+ return !!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
/* Global variables. */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 5fa51ada45..557e6876e2 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1175,10 +1175,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
if (zebra_rib_labeled_unicast(re))
zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
- if (!RIB_SYSTEM_ROUTE(re))
- rib_uninstall_kernel(rn, re);
- else
- UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ rib_uninstall_kernel(rn, re);
dest->selected_fib = NULL;
@@ -1208,6 +1205,16 @@ static int rib_can_delete_dest(rib_dest_t *dest)
}
/*
+ * Unresolved rnh's are stored on the default route's list
+ *
+ * dest->rnode can also be the source prefix node in an
+ * ipv6 sourcedest table. Fortunately the prefix of a
+ * source prefix node can never be the default prefix.
+ */
+ if (is_default_prefix(&dest->rnode->p))
+ return 0;
+
+ /*
* Don't delete the dest if we have to update the FPM about this
* prefix.
*/
@@ -1218,6 +1225,88 @@ static int rib_can_delete_dest(rib_dest_t *dest)
return 1;
}
+void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
+{
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
+ struct listnode *node, *nnode;
+ struct rnh *rnh;
+
+ /*
+ * We are storing the rnh's associated withb
+ * the tracked nexthop as a list of the rn's.
+ * Unresolved rnh's are placed at the top
+ * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 )
+ * As such for each rn we need to walk up the tree
+ * and see if any rnh's need to see if they
+ * would match a more specific route
+ */
+ while (rn) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+
+ zlog_debug("%s: %s Being examined for Nexthop Tracking",
+ __PRETTY_FUNCTION__,
+ srcdest_rnode2str(rn, buf, sizeof(buf)));
+ }
+ if (!dest) {
+ rn = rn->parent;
+ if (rn)
+ dest = rib_dest_from_rnode(rn);
+ continue;
+ }
+ /*
+ * If we have any rnh's stored in the nht list
+ * then we know that this route node was used for
+ * nht resolution and as such we need to call the
+ * nexthop tracking evaluation code
+ */
+ for (ALL_LIST_ELEMENTS(dest->nht, node, nnode, rnh)) {
+ struct zebra_vrf *zvrf =
+ zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct prefix *p = &rnh->node->p;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf1[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+
+ zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u",
+ zvrf->vrf->vrf_id,
+ srcdest_rnode2str(rn, buf1,
+ sizeof(buf1)),
+ prefix2str(p, buf2, sizeof(buf2)),
+ seq, rnh->seqno);
+ }
+
+ /*
+ * If we have evaluated this node on this pass
+ * already, due to following the tree up
+ * then we know that we can move onto the next
+ * rnh to process.
+ *
+ * Additionally we call zebra_evaluate_rnh
+ * when we gc the dest. In this case we know
+ * that there must be no other re's where
+ * we were originally as such we know that
+ * that sequence number is ok to respect.
+ */
+ if (rnh->seqno == seq) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNode processed and moved already");
+ continue;
+ }
+
+ rnh->seqno = seq;
+ zebra_evaluate_rnh(zvrf, family2afi(p->family), 0,
+ rnh->type, p);
+ }
+
+ rn = rn->parent;
+ if (rn)
+ dest = rib_dest_from_rnode(rn);
+ }
+}
+
/*
* rib_gc_dest
*
@@ -1244,7 +1333,10 @@ int rib_gc_dest(struct route_node *rn)
rnode_debug(rn, zvrf_id(zvrf), "removing dest from table");
}
+ zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence());
+
dest->rnode = NULL;
+ list_delete(&dest->nht);
XFREE(MTYPE_RIB_DEST, dest);
rn->info = NULL;
@@ -1258,8 +1350,6 @@ int rib_gc_dest(struct route_node *rn)
static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *new)
{
- rib_dest_t *dest = rib_dest_from_rnode(rn);
-
hook_call(rib_update, rn, "new route selected");
/* Update real nexthop. This may actually determine if nexthop is active
@@ -1281,10 +1371,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (zebra_rib_labeled_unicast(new))
zebra_mpls_lsp_install(zvrf, rn, new);
- if (!RIB_SYSTEM_ROUTE(new))
- rib_install_kernel(rn, new, NULL);
- else
- dest->selected_fib = new;
+ rib_install_kernel(rn, new, NULL);
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
}
@@ -1292,7 +1379,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *old)
{
- rib_dest_t *dest = rib_dest_from_rnode(rn);
hook_call(rib_update, rn, "removing existing route");
/* Uninstall from kernel. */
@@ -1308,20 +1394,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- if (!RIB_SYSTEM_ROUTE(old))
- rib_uninstall_kernel(rn, old);
- else {
- UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
- /*
- * We are setting this to NULL here
- * because that is what we traditionally
- * have been doing. I am not positive
- * that this is the right thing to do
- * but let's leave the code alone
- * for the RIB_SYSTEM_ROUTE case
- */
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, old);
/* Update nexthop for route, reset changed flag. */
/* Note: this code also handles the Linux case when an interface goes
@@ -1340,9 +1413,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
struct route_entry *old,
struct route_entry *new)
{
- struct nexthop *nexthop = NULL;
int nh_active = 0;
- rib_dest_t *dest = rib_dest_from_rnode(rn);
/*
* We have to install or update if a new route has been selected or
@@ -1384,48 +1455,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- /* Non-system route should be installed. */
- if (!RIB_SYSTEM_ROUTE(new)) {
- /* If labeled-unicast route, install transit
- * LSP. */
- if (zebra_rib_labeled_unicast(new))
- zebra_mpls_lsp_install(zvrf, rn, new);
+ /*
+ * Non-system route should be installed.
+ * If labeled-unicast route, install transit
+ * LSP.
+ */
+ if (zebra_rib_labeled_unicast(new))
+ zebra_mpls_lsp_install(zvrf, rn, new);
- rib_install_kernel(rn, new, old);
- } else {
- UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED);
- /*
- * We do not need to install the
- * selected route because it
- * is already isntalled by
- * the system( ie not us )
- * so just mark it as winning
- * we do need to ensure that
- * if we uninstall a route
- * from ourselves we don't
- * over write this pointer
- */
- dest->selected_fib = new;
- }
- /* If install succeeded or system route, cleanup flags
- * for prior route. */
- if (new != old) {
- if (RIB_SYSTEM_ROUTE(new)) {
- if (!RIB_SYSTEM_ROUTE(old))
- rib_uninstall_kernel(rn, old);
- else
- UNSET_FLAG(
- old->status,
- ROUTE_ENTRY_INSTALLED);
- } else {
- UNSET_FLAG(old->status,
- ROUTE_ENTRY_INSTALLED);
- for (nexthop = old->ng.nexthop; nexthop;
- nexthop = nexthop->next)
- UNSET_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB);
- }
- }
+ rib_install_kernel(rn, new, old);
}
/*
@@ -1455,25 +1493,18 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- if (!RIB_SYSTEM_ROUTE(old))
- rib_uninstall_kernel(rn, old);
- else {
- UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, old);
}
} else {
/*
* Same route selected; check if in the FIB and if not,
- * re-install. This
- * is housekeeping code to deal with race conditions in kernel
- * with linux
- * netlink reporting interface up before IPv4 or IPv6 protocol
- * is ready
+ * re-install. This is housekeeping code to deal with
+ * race conditions in kernel with linux netlink reporting
+ * interface up before IPv4 or IPv6 protocol is ready
* to add routes.
*/
- if (!RIB_SYSTEM_ROUTE(new)
- && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED))
+ if (!CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED) ||
+ RIB_SYSTEM_ROUTE(new))
rib_install_kernel(rn, new, NULL);
}
@@ -1725,18 +1756,9 @@ static void rib_process(struct route_node *rn)
UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED);
}
- if (new_selected) {
+ if (new_selected)
SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
- /* Special case: new route is system route, so
- * dataplane update will not be done - ensure we
- * redistribute the route.
- */
- if (RIB_SYSTEM_ROUTE(new_selected))
- redistribute_update(p, src_p, new_selected,
- old_selected);
- }
-
if (old_selected) {
if (!new_selected)
redistribute_delete(p, src_p, old_selected);
@@ -1763,6 +1785,24 @@ static void rib_process(struct route_node *rn)
rib_gc_dest(rn);
}
+static void zebra_rib_evaluate_mpls(struct route_node *rn)
+{
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
+ struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+
+ if (!dest)
+ return;
+
+ if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS)) {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug(
+ "%u: Scheduling all LSPs upon RIB completion",
+ zvrf_id(zvrf));
+ zebra_mpls_lsp_schedule(zvrf);
+ mpls_unmark_lsps_for_processing(rn);
+ }
+}
+
/*
* Utility to match route with dplane context data
*/
@@ -1821,6 +1861,30 @@ done:
return (result);
}
+static void zebra_rib_fixup_system(struct route_node *rn)
+{
+ struct route_entry *re;
+
+ RNODE_FOREACH_RE(rn, re) {
+ struct nexthop *nhop;
+
+ if (!RIB_SYSTEM_ROUTE(re))
+ continue;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+ continue;
+
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+
+ for (ALL_NEXTHOPS(re->ng, nhop)) {
+ if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+}
+
/*
* Route-update results processing after async dataplane update.
*/
@@ -1836,6 +1900,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
enum dplane_op_e op;
enum zebra_dplane_result status;
const struct prefix *dest_pfx, *src_pfx;
+ uint32_t seq;
/* Locate rn and re(s) from ctx */
@@ -1912,11 +1977,13 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
break;
}
+ seq = dplane_ctx_get_seq(ctx);
+
/*
* Check sequence number(s) to detect stale results before continuing
*/
if (re) {
- if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) {
+ if (re->dplane_sequence != seq) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("%u:%s Stale dplane result for re %p",
dplane_ctx_get_vrf(ctx),
@@ -1932,7 +1999,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_vrf(ctx),
dest_str, old_re);
} else
- UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
}
switch (op) {
@@ -1987,6 +2054,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
NEXTHOP_FLAG_FIB);
}
+ /*
+ * System routes are weird in that they
+ * allow multiple to be installed that match
+ * to the same prefix, so after we get the
+ * result we need to clean them up so that
+ * we can actually use them.
+ */
+ if ((re && RIB_SYSTEM_ROUTE(re)) ||
+ (old_re && RIB_SYSTEM_ROUTE(old_re)))
+ zebra_rib_fixup_system(rn);
+
if (zvrf) {
zvrf->installs++;
/* Set flag for nexthop tracking processing */
@@ -2010,9 +2088,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
} else {
- if (re)
+ if (re) {
SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
- if (old_re)
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ } if (old_re)
SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
if (re)
zsend_route_notify_owner(re, dest_pfx,
@@ -2052,10 +2131,24 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
prefix2str(dest_pfx,
dest_str, sizeof(dest_str)));
}
+
+ /*
+ * System routes are weird in that they
+ * allow multiple to be installed that match
+ * to the same prefix, so after we get the
+ * result we need to clean them up so that
+ * we can actually use them.
+ */
+ if ((re && RIB_SYSTEM_ROUTE(re)) ||
+ (old_re && RIB_SYSTEM_ROUTE(old_re)))
+ zebra_rib_fixup_system(rn);
break;
default:
break;
}
+
+ zebra_rib_evaluate_rn_nexthops(rn, seq);
+ zebra_rib_evaluate_mpls(rn);
done:
if (rn)
@@ -2110,47 +2203,12 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
return 1;
}
+
/*
* Perform next-hop tracking processing after RIB updates.
*/
static void do_nht_processing(void)
{
- struct vrf *vrf;
- struct zebra_vrf *zvrf;
-
- /* Evaluate nexthops for those VRFs which underwent route processing.
- * This
- * should limit the evaluation to the necessary VRFs in most common
- * situations.
- */
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- zvrf = vrf->info;
- if (zvrf == NULL || !(zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED))
- continue;
-
- if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHT)
- zlog_debug("NHT processing check for zvrf %s",
- zvrf_name(zvrf));
-
- zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED;
- zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
- zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_IMPORT_CHECK_TYPE,
- NULL);
- zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
- zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE,
- NULL);
- }
-
- /* Schedule LSPs for processing, if needed. */
- zvrf = vrf_info_lookup(VRF_DEFAULT);
- if (mpls_should_lsps_be_processed(zvrf)) {
- if (IS_ZEBRA_DEBUG_MPLS)
- zlog_debug(
- "%u: Scheduling all LSPs upon RIB completion",
- zvrf_id(zvrf));
- zebra_mpls_lsp_schedule(zvrf);
- mpls_unmark_lsps_for_processing(zvrf);
- }
}
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
@@ -2340,6 +2398,19 @@ static void rib_queue_init(void)
return;
}
+rib_dest_t *zebra_rib_create_dest(struct route_node *rn)
+{
+ rib_dest_t *dest;
+
+ dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
+ dest->nht = list_new();
+ route_lock_node(rn); /* rn route table reference */
+ rn->info = dest;
+ dest->rnode = rn;
+
+ return dest;
+}
+
/* RIB updates are processed via a queue of pointers to route_nodes.
*
* The queue length is bounded by the maximal size of the routing table,
@@ -2392,10 +2463,7 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn);
- dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
- route_lock_node(rn); /* rn route table reference */
- rn->info = dest;
- dest->rnode = rn;
+ dest = zebra_rib_create_dest(rn);
}
head = dest->routes;
@@ -2654,7 +2722,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
* revalidation
* of the rest of the RE.
*/
- if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) {
+ if (dest->selected_fib) {
changed = 1;
if (IS_ZEBRA_DEBUG_RIB) {
char buf[PREFIX_STRLEN];
@@ -2676,7 +2744,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct route_table *table;
struct route_node *rn;
struct route_entry *same = NULL;
- struct nexthop *nexthop;
int ret = 0;
if (!re)
@@ -2740,13 +2807,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
break;
}
- /* If this route is kernel route, set FIB flag to the route. */
- if (RIB_SYSTEM_ROUTE(re)) {
- SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
-
/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
rnode_debug(rn, re->vrf_id,
@@ -3222,10 +3282,8 @@ void rib_close_table(struct route_table *table)
if (info->safi == SAFI_UNICAST)
hook_call(rib_update, rn, NULL);
- if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) {
- rib_uninstall_kernel(rn, dest->selected_fib);
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, dest->selected_fib);
+ dest->selected_fib = NULL;
}
}
}
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index f601ab7e7b..a1519e45cd 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -94,6 +94,61 @@ char *rnh_str(struct rnh *rnh, char *buf, int size)
return buf;
}
+static void zebra_rnh_remove_from_routing_table(struct rnh *rnh)
+{
+ struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+ struct route_node *rn;
+ rib_dest_t *dest;
+
+ if (!table)
+ return;
+
+ rn = route_node_match(table, &rnh->resolved_route);
+ if (!rn)
+ return;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s removed from tracking on %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
+ dest = rib_dest_from_rnode(rn);
+ listnode_delete(dest->nht, rnh);
+ route_unlock_node(rn);
+}
+
+static void zebra_rnh_store_in_routing_table(struct rnh *rnh)
+{
+ struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+ struct route_node *rn;
+ rib_dest_t *dest;
+
+ rn = route_node_match(table, &rnh->resolved_route);
+ if (!rn)
+ return;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s added for tracking on %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
+ dest = rib_dest_from_rnode(rn);
+ listnode_add(dest->nht, rnh);
+ route_unlock_node(rn);
+}
+
struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
bool *exists)
{
@@ -101,12 +156,13 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
struct route_node *rn;
struct rnh *rnh = NULL;
char buf[PREFIX2STR_BUFFER];
+ afi_t afi = family2afi(p->family);
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(p, buf, sizeof(buf));
zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type);
}
- table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type);
+ table = get_rnh_table(vrfid, afi, type);
if (!table) {
prefix2str(p, buf, sizeof(buf));
flog_warn(EC_ZEBRA_RNH_NO_TABLE,
@@ -124,13 +180,26 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
if (!rn->info) {
rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
+
+ /*
+ * The resolved route is already 0.0.0.0/0 or
+ * 0::0/0 due to the calloc right above, but
+ * we should set the family so that future
+ * comparisons can just be done
+ */
+ rnh->resolved_route.family = p->family;
rnh->client_list = list_new();
rnh->vrf_id = vrfid;
+ rnh->type = type;
+ rnh->seqno = 0;
+ rnh->afi = afi;
rnh->zebra_pseudowire_list = list_new();
route_lock_node(rn);
rn->info = rnh;
rnh->node = rn;
*exists = false;
+
+ zebra_rnh_store_in_routing_table(rnh);
} else
*exists = true;
@@ -161,9 +230,30 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
void zebra_free_rnh(struct rnh *rnh)
{
+ struct zebra_vrf *zvrf;
+ struct route_table *table;
+
+ zebra_rnh_remove_from_routing_table(rnh);
rnh->flags |= ZEBRA_NHT_DELETED;
list_delete(&rnh->client_list);
list_delete(&rnh->zebra_pseudowire_list);
+
+ zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST];
+
+ if (table) {
+ struct route_node *rern;
+
+ rern = route_node_match(table, &rnh->resolved_route);
+ if (rern) {
+ rib_dest_t *dest;
+
+ route_unlock_node(rern);
+
+ dest = rib_dest_from_rnode(rern);
+ listnode_delete(dest->nht, rnh);
+ }
+ }
free_state(rnh->vrf_id, rnh->state, rnh->node);
XFREE(MTYPE_RNH, rnh);
}
@@ -344,6 +434,16 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
&& !prefix_same(&nrn->p, &rn->p))
return NULL;
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s Resolved Import Entry to %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
/* Identify appropriate route entry. */
RNODE_FOREACH_RE (rn, re) {
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
@@ -354,6 +454,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
if (re)
*prn = rn;
+
+ if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("\tRejected due to removed or is a bgp route");
+
return re;
}
@@ -361,9 +465,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
* See if a tracked route entry for import (by BGP) has undergone any
* change, and if so, notify the client.
*/
-static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi,
+static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi,
int force, struct route_node *nrn,
struct rnh *rnh,
+ struct route_node *prn,
struct route_entry *re)
{
int state_changed = 0;
@@ -371,25 +476,40 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi,
char bufn[INET6_ADDRSTRLEN];
struct listnode *node;
+ zebra_rnh_remove_from_routing_table(rnh);
+ if (prn) {
+ prefix_copy(&rnh->resolved_route, &prn->p);
+ } else {
+ int family = rnh->resolved_route.family;
+
+ memset(&rnh->resolved_route.family, 0, sizeof(struct prefix));
+ rnh->resolved_route.family = family;
+ }
+ zebra_rnh_store_in_routing_table(rnh);
+
if (re && (rnh->state == NULL)) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
state_changed = 1;
} else if (!re && (rnh->state != NULL))
state_changed = 1;
- if (compare_state(re, rnh->state))
+ if (compare_state(re, rnh->state)) {
copy_state(rnh, re, nrn);
+ state_changed = 1;
+ }
if (state_changed || force) {
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
- zlog_debug("%u:%s: Route import check %s %s", vrfid,
+ zlog_debug("%u:%s: Route import check %s %s",
+ zvrf->vrf->vrf_id,
bufn, rnh->state ? "passed" : "failed",
state_changed ? "(state changed)" : "");
}
/* state changed, notify clients */
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
- send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
+ send_client(rnh, client,
+ RNH_IMPORT_CHECK_TYPE, zvrf->vrf->vrf_id);
}
}
}
@@ -412,7 +532,7 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
if (prn && re) {
- prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
+ srcdest_rnode2str(prn, bufp, INET6_ADDRSTRLEN);
zlog_debug("%u:%s: NH resolved over route %s",
zvrf->vrf->vrf_id, bufn, bufp);
} else
@@ -545,19 +665,43 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
* most-specific match. Do similar logic as in zebra_rib.c
*/
while (rn) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s Possible Match to %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
/* Do not resolve over default route unless allowed &&
* match route to be exact if so specified
*/
if (is_default_prefix(&rn->p)
- && !rnh_resolve_via_default(rn->p.family))
+ && !rnh_resolve_via_default(rn->p.family)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNot allowed to resolve through default prefix");
return NULL;
+ }
/* Identify appropriate route entry. */
RNODE_FOREACH_RE (rn, re) {
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s removed",
+ zebra_route_string(re->type));
continue;
- if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+ }
+ if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s !selected",
+ zebra_route_string(re->type));
continue;
+ }
/* Just being SELECTED isn't quite enough - must
* have an installed nexthop to be useful.
@@ -567,8 +711,13 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
break;
}
- if (nexthop == NULL)
+ if (nexthop == NULL) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s no nexthops",
+ zebra_route_string(re->type));
continue;
+ }
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
if ((re->type == ZEBRA_ROUTE_CONNECT)
@@ -594,10 +743,14 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
return re;
}
- if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+ if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
rn = rn->parent;
- else
+ else {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNexthop must be connected, cannot recurse up");
return NULL;
+ }
}
return NULL;
@@ -629,11 +782,20 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
* the resolving route has some change (e.g., metric), there is a state
* change.
*/
- if (!prefix_same(&rnh->resolved_route, &prn->p)) {
+ zebra_rnh_remove_from_routing_table(rnh);
+ if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) {
if (prn)
prefix_copy(&rnh->resolved_route, &prn->p);
- else
+ else {
+ /*
+ * Just quickly store the family of the resolved
+ * route so that we can reset it in a second here
+ */
+ int family = rnh->resolved_route.family;
+
memset(&rnh->resolved_route, 0, sizeof(struct prefix));
+ rnh->resolved_route.family = family;
+ }
copy_state(rnh, re, nrn);
state_changed = 1;
@@ -641,6 +803,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
copy_state(rnh, re, nrn);
state_changed = 1;
}
+ zebra_rnh_store_in_routing_table(rnh);
if (state_changed || force) {
/* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
@@ -689,8 +852,8 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi,
/* Process based on type of entry. */
if (type == RNH_IMPORT_CHECK_TYPE)
- zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, afi, force,
- nrn, rnh, re);
+ zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh,
+ prn, re);
else
zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn,
re);
@@ -790,7 +953,6 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
static void free_state(vrf_id_t vrf_id, struct route_entry *re,
struct route_node *rn)
{
-
if (!re)
return;
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index 0e71e8a68d..7d823c7acc 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -29,6 +29,8 @@
extern "C" {
#endif
+typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
+
/* Nexthop structure. */
struct rnh {
uint8_t flags;
@@ -40,6 +42,12 @@ struct rnh {
/* VRF identifier. */
vrf_id_t vrf_id;
+ afi_t afi;
+
+ rnh_type_t type;
+
+ uint32_t seqno;
+
struct route_entry *state;
struct prefix resolved_route;
struct list *client_list;
@@ -55,8 +63,6 @@ struct rnh {
int filtered[ZEBRA_ROUTE_MAX];
};
-typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
-
extern int zebra_rnh_ip_default_route;
extern int zebra_rnh_ipv6_default_route;
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index cabc8be8dd..9e09cbca3f 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -164,8 +164,6 @@ static void zebra_router_free_table(struct zebra_router_table *zrt)
{
void *table_info;
- rib_close_table(zrt->table);
-
table_info = route_table_get_info(zrt->table);
route_table_finish(zrt->table);
RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 90f94902f3..2d721ec8a1 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -354,7 +354,12 @@ void zebra_rtable_node_cleanup(struct route_table *table,
rib_unlink(node, re);
}
- XFREE(MTYPE_RIB_DEST, node->info);
+ if (node->info) {
+ rib_dest_t *dest = node->info;
+
+ list_delete(&dest->nht);
+ XFREE(MTYPE_RIB_DEST, node->info);
+ }
}
static void zebra_rnhtable_node_cleanup(struct route_table *table,
@@ -370,10 +375,19 @@ static void zebra_rnhtable_node_cleanup(struct route_table *table,
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi)
{
+ struct route_node *rn;
+ struct prefix p;
+
assert(!zvrf->table[afi][safi]);
zvrf->table[afi][safi] =
zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
+
+ memset(&p, 0, sizeof(p));
+ p.family = afi2family(afi);
+
+ rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL);
+ zebra_rib_create_dest(rn);
}
/* Allocate new zebra VRF. */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 82fbe68bfe..97e841692b 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1369,7 +1369,7 @@ static void vty_show_ip_route_summary(struct vty *vty,
else
rib_cnt[re->type]++;
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
if (is_ibgp)
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index b44c314d5b..04209ded53 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -2191,6 +2191,7 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
memcpy(&n->emac, mac, ETH_ALEN);
n->state = ZEBRA_NEIGH_INACTIVE;
n->zvni = zvni;
+ n->dad_ip_auto_recovery_timer = NULL;
/* Associate the neigh to mac */
zmac = zvni_mac_lookup(zvni, mac);
@@ -2212,6 +2213,9 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
if (zmac)
listnode_delete(zmac->neigh_list, n);
+ /* Cancel auto recovery */
+ THREAD_OFF(n->dad_ip_auto_recovery_timer);
+
/* Free the VNI hash entry and allocated memory. */
tmp_n = hash_release(zvni->neigh_table, n);
XFREE(MTYPE_NEIGH, tmp_n);
@@ -3308,6 +3312,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
assert(mac);
+ mac->zvni = zvni;
+ mac->dad_mac_auto_recovery_timer = NULL;
+
mac->neigh_list = list_new();
mac->neigh_list->cmp = neigh_list_cmp;
@@ -3321,6 +3328,9 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
{
zebra_mac_t *tmp_mac;
+ /* Cancel auto recovery */
+ THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+
list_delete(&mac->neigh_list);
/* Free the VNI hash entry and allocated memory. */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 6532491cef..f5bb3aabb7 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -773,6 +773,18 @@ static int zserv_accept(struct thread *thread)
return 0;
}
+void zserv_close(void)
+{
+ /*
+ * On shutdown, let's close the socket down
+ * so that long running processes of killing the
+ * routing table doesn't leave us in a bad
+ * state where a client tries to reconnect
+ */
+ close(zsock);
+ zsock = -1;
+}
+
void zserv_start(char *path)
{
int ret;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index c4c3e1328b..86863d961c 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -184,6 +184,13 @@ extern unsigned int multipath_num;
extern void zserv_init(void);
/*
+ * Stop the Zebra API server.
+ *
+ * closes the socket
+ */
+extern void zserv_close(void);
+
+/*
* Start Zebra API server.
*
* Allocates resources, creates the server socket and begins listening on the