diff options
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 |
