diff options
97 files changed, 1854 insertions, 890 deletions
diff --git a/.dockerignore b/.dockerignore index f2fc34583d..d613e18dfc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,4 @@ **/*.lo **/*.so **/.libs +docker/alpine/pkgs @@ -51,8 +51,9 @@ lists: | Users & Operators | frog@lists.frrouting.org | | Announcements | announce@lists.frrouting.org | -For chat, we currently use [Slack](https://frrouting.slack.com). Please email -the mailing list to request an invite as we do not issue automatic invites. +For chat, we currently use [Slack](https://frrouting.slack.com). You can join +by clicking the "Slack" link under the +[Participate](https://frrouting.org/#participate) section of our website. Contributing diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 969b85f524..0f56a427dd 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -9,13 +9,13 @@ license="GPL-2.0" depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash" makedepends="ncurses-dev net-snmp-dev gawk texinfo perl acct autoconf automake bash - binutils binutils-libs bison bsd-compat-headers build-base + binutils bison bsd-compat-headers build-base c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod lddtree libacl libatomic libattr libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc libgomp libisoburn libisofs libltdl libressl libssh2 - libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 + libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python2 python2-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs @@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" -source="$pkgname-$pkgver.tar.gz docker-start daemons" +source="$pkgname-$pkgver.tar.gz" builddir="$srcdir"/$pkgname-$pkgver @@ -60,8 +60,7 @@ package() { cd "$builddir" make DESTDIR="$pkgdir" install - install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir - install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir + install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir install -d "$pkgdir"/etc/init.d ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr } diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 226bf99d2c..bea46f3e45 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: interface not set appropriately to handle some attributes", + zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: interface not set appropriately to handle some attributes", + zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } if (!peer->nexthop.ifp) { - zlog_warn("%s: Interface not set appropriately to handle this some attributes", + zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index c7f2671b78..785139865e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -30,8 +30,9 @@ #define RT_ADDRSTRLEN 28 -/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */ -#define EVPN_ROUTE_PREFIXLEN 224 +/* EVPN prefix lengths. This represents the sizeof struct evpn_addr + * in bits */ +#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8) /* EVPN route types. */ typedef enum { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index eca632dd44..f7768f921c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10774,7 +10774,11 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, return; } - table = bgp->rib[afi][safi]; + /* labeled-unicast routes live in the unicast table */ + if (safi == SAFI_LABELED_UNICAST) + table = bgp->rib[afi][SAFI_UNICAST]; + else + table = bgp->rib[afi][safi]; output_count = filtered_count = 0; subgrp = peer_subgroup(peer, afi, safi); @@ -11028,10 +11032,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, if (use_json) json = json_object_new_object(); - /* labeled-unicast routes live in the unicast table */ - if (safi == SAFI_LABELED_UNICAST) - safi = SAFI_UNICAST; - if (!peer || !peer->afc[afi][safi]) { if (use_json) { json_object_string_add( 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/developer/workflow.rst b/doc/developer/workflow.rst index b66392f7ca..b3b3a47cb0 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next ``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs, bugfix releases may occur sooner. -Bugfixes are applied to the two most recent releases. Security fixes are -backported to all releases less than or equal to at least one year old. Security -fixes may also be backported to older releases depending on severity. +Bugfixes are applied to the two most recent releases. However, backporting of bug +fixes to older than the two most recent releases will not be prevented, if acked +under the classical development workflow applying for a pull request. + +Security fixes are backported to all releases less than or equal to at least one +year old. Security fixes may also be backported to older releases depending on +severity. + Long term support branches ( LTS ) ----------------------------------------- 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/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index dd29358b07..815983a394 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,35 +1,58 @@ -FROM alpine:3.7 as source-builder -ARG commit -RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \ - binutils binutils-libs bison bsd-compat-headers build-base \ - c-ares c-ares-dev ca-certificates cryptsetup-libs curl \ - device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \ - git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \ - libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \ - libgomp libisoburn libisofs libltdl libressl libssh2 \ - libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \ - mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \ - patch pax-utils pcre perl pkgconf python2 python2-dev readline \ - readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \ - groff gzip bc py-sphinx -ADD . /src -RUN (cd /src && \ - ./bootstrap.sh && \ - ./configure \ +# This stage builds a dist tarball from the source +FROM alpine:edge as source-builder + +RUN mkdir -p /src/alpine +COPY alpine/APKBUILD.in /src/alpine +RUN source /src/alpine/APKBUILD.in \ + && echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --no-cache \ + --update-cache \ + $makedepends \ + gzip + +COPY . /src +ARG PKGVER +RUN cd /src \ + && ./bootstrap.sh \ + && ./configure \ --enable-numeric-version \ - --with-pkg-extra-version=_git$commit && \ - make dist) -FROM alpine:3.7 as alpine-builder -RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk -ADD docker/alpine/alpine-build.sh /usr/bin/ -ADD docker/alpine/builder /etc/sudoers.d -COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/ + --with-pkg-extra-version="_git$PKGVER" \ + && make dist + +# This stage builds an apk from the dist tarball +FROM alpine:edge as alpine-builder +# Don't use nocache here so that abuild can use the cache +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --update-cache \ + abuild \ + alpine-conf \ + alpine-sdk \ + && setup-apkcache /var/cache/apk \ + && mkdir -p /pkgs/apk \ + && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/ RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs USER builder -RUN /usr/bin/alpine-build.sh -FROM alpine:3.7 +RUN cd /dist \ + && abuild-keygen -a -n \ + && abuild checksum \ + && abuild -r -P /pkgs/apk + +# This stage installs frr from the apk +FROM alpine:edge RUN mkdir -p /pkgs/apk COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/ -RUN apk add --no-cache tini -RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --no-cache \ + --update-cache \ + tini \ + && apk add \ + --no-cache \ + --allow-untrusted /pkgs/apk/*/*.apk \ + && rm -rf /pkgs +COPY docker/alpine/docker-start /usr/lib/frr/docker-start ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] diff --git a/docker/alpine/alpine-build.sh b/docker/alpine/alpine-build.sh deleted file mode 100755 index d4c0311122..0000000000 --- a/docker/alpine/alpine-build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -e - -cd /dist - -sudo apk --update add alpine-conf -sudo setup-apkcache /var/cache/apk -abuild-keygen -a -n -abuild checksum -abuild -r -P /pkgs/apk diff --git a/docker/alpine/build.sh b/docker/alpine/build.sh index 40ed1194fe..22a36877c0 100755 --- a/docker/alpine/build.sh +++ b/docker/alpine/build.sh @@ -1,17 +1,30 @@ #!/bin/sh set -e -set -v set -x ## -# commit must be converted to decimal +# Package version needs to be decimal ## -c=`git rev-parse --short=10 HEAD` -commit=`printf '%u\n' 0x$c` -docker build -f docker/alpine/Dockerfile \ - --build-arg commit=$commit -t frr:alpine-$c . -id=`docker create frr:alpine-$c` -docker cp ${id}:/pkgs/ docker -docker rm $id -docker rmi frr:alpine-$c +GITREV="$(git rev-parse --short=10 HEAD)" +PKGVER="$(printf '%u\n' 0x$GITREV)" + +docker build \ + --pull \ + --file=docker/alpine/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:alpine-builder-$GITREV" \ + --target=alpine-builder \ + . + +CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")" +docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine +docker rm "${CONTAINER_ID}" + +docker build \ + --file=docker/alpine/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:alpine-$GITREV" \ + . + +docker rmi "frr:alpine-builder-$GITREV" diff --git a/docker/alpine/builder b/docker/alpine/builder deleted file mode 100644 index a950b8abaf..0000000000 --- a/docker/alpine/builder +++ /dev/null @@ -1 +0,0 @@ -builder ALL=(ALL) NOPASSWD:ALL diff --git a/alpine/docker-start b/docker/alpine/docker-start index 43854ab142..52cfb664ce 100755 --- a/alpine/docker-start +++ b/docker/alpine/docker-start @@ -6,5 +6,7 @@ set -e # For volume mounts... ## chown -R frr:frr /etc/frr -/etc/init.d/frr start -exec sleep 10000d +/usr/lib/frr/frrinit.sh start + +# Sleep forever +exec tail -f /dev/null 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 @@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE), DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE), DESC_ENTRY(ZEBRA_HELLO), + DESC_ENTRY(ZEBRA_CAPABILITIES), DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE), @@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VRF_LABEL), DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE), DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER), + DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV), DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB), @@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC), DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), + DESC_ENTRY(ZEBRA_FEC_REGISTER), + DESC_ENTRY(ZEBRA_FEC_UNREGISTER), + DESC_ENTRY(ZEBRA_FEC_UPDATE), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP), @@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_IPSET_DESTROY), DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD), DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE), + DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER), + DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER), + DESC_ENTRY(ZEBRA_IPTABLE_ADD), + DESC_ENTRY(ZEBRA_IPTABLE_DELETE), + DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER), DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL), }; #undef DESC_ENTRY diff --git a/lib/zclient.c b/lib/zclient.c index 39a75710a4..3e26cd9e6c 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -634,7 +634,7 @@ void zclient_init(struct zclient *zclient, int redist_default, } if (zclient_debug) - zlog_debug("zclient_start is called"); + zlog_debug("scheduling zclient connection"); zclient_event(ZCLIENT_SCHEDULE, zclient); } @@ -2509,8 +2509,9 @@ static int zclient_read(struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x VRF %u", - (void *)zclient, command, vrf_id); + zlog_debug("zclient 0x%p command %s VRF %u", + (void *)zclient, zserv_command_string(command), + vrf_id); switch (command) { case ZEBRA_CAPABILITIES: 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/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b3c91b9006..43c5e338b0 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length, oi = nbr->oi; - /* LS Request packet overflows interface MTU. */ + /* LS Request packet overflows interface MTU + * delta is just number of bytes required for 1 LS Req + * ospf_packet_max will return the number of bytes can + * be accomodated without ospf header. So length+delta + * can be compared to ospf_packet_max + * to check if it can fit another lsreq in the same packet. + */ + if (*length + delta > ospf_packet_max(oi)) return 0; @@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s) { struct ospf_lsa *lsa; uint16_t length = OSPF_LS_REQ_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 12; + unsigned long delta = 12; struct route_table *table; struct route_node *rn; int i; @@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, assert(lsa->data); - /* Will it fit? */ - if (length + delta + ntohs(lsa->data->length) > size_noauth) + /* Will it fit? Minimum it has to fit atleast one */ + if ((length + delta + ntohs(lsa->data->length) > size_noauth) && + (count > 0)) break; /* Keep pointer to LS age. */ @@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, { struct listnode *node, *nnode; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 24; + unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { assert(lsa); - if (length + delta > ospf_packet_max(oi)) + /* LS Ack packet overflows interface MTU + * delta is just number of bytes required for + * 1 LS Ack(1 LS Hdr) ospf_packet_max will return + * the number of bytes can be accomodated without + * ospf header. So length+delta can be compared + * against ospf_packet_max to check if it can fit + * another ls header in the same packet. + */ + if ((length + delta) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); 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/tests/topotests/pim-basic/mcast-rx.py b/tests/topotests/pim-basic/mcast-rx.py new file mode 100755 index 0000000000..9e3484e12a --- /dev/null +++ b/tests/topotests/pim-basic/mcast-rx.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# mcast-rx.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# +""" +Subscribe to a multicast group so that the kernel sends an IGMP JOIN +for the multicast group we subscribed to. +""" + +import argparse +import logging +import re +import os +import socket +import subprocess +import struct +import sys +import time + + +def ifname_to_ifindex(ifname): + output = subprocess.check_output("ip link show %s" % ifname, shell=True) + first_line = output.split('\n')[0] + re_index = re.search('^(\d+):', first_line) + + if re_index: + return int(re_index.group(1)) + + log.error("Could not parse the ifindex for %s out of\n%s" % (ifname, first_line)) + return None + + +# Thou shalt be root +if os.geteuid() != 0: + sys.stderr.write('ERROR: You must have root privileges\n') + sys.exit(1) + + +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s') + +# Color the errors and warnings in red +logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) +logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) +log = logging.getLogger(__name__) + +parser = argparse.ArgumentParser(description='Multicast RX utility', + version='1.0.0') +parser.add_argument('group', help='Multicast IP') +parser.add_argument('ifname', help='Interface name') +parser.add_argument('--port', help='UDP port', default=1000) +parser.add_argument('--sleep', help='Time to sleep before we stop waiting', + default = 5) +args = parser.parse_args() + +# Create the datagram socket +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +sock.bind((args.group, args.port)) + +newpid = os.fork() + +if newpid == 0: + ifindex = ifname_to_ifindex(args.ifname) + mreq = struct.pack("=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + time.sleep(float(args.sleep)) + sock.close() diff --git a/tests/topotests/pim-basic/mcast-tx.py b/tests/topotests/pim-basic/mcast-tx.py new file mode 100755 index 0000000000..c469e47d4c --- /dev/null +++ b/tests/topotests/pim-basic/mcast-tx.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# +# mcast-tx.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import argparse +import logging +import socket +import struct +import time + + +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s') + +# Color the errors and warnings in red +logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) +logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) +log = logging.getLogger(__name__) + +parser = argparse.ArgumentParser(description='Multicast packet generator', version='1.0.0') +parser.add_argument('group', help='Multicast IP') +parser.add_argument('ifname', help='Interface name') +parser.add_argument('--port', type=int, help='UDP port number', default=1000) +parser.add_argument('--ttl', type=int, help='time-to-live', default=20) +parser.add_argument('--count', type=int, help='Packets to send', default=1) +parser.add_argument('--interval', type=int, help='ms between packets', default=100) +args = parser.parse_args() + +# Create the datagram socket +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +# IN.SO_BINDTODEVICE is not defined in some releases of python but it is 25 +# https://github.com/sivel/bonding/issues/10 +# +# Bind our socket to ifname +sock.setsockopt(socket.SOL_SOCKET, + 25, + struct.pack("%ds" % len(args.ifname), args.ifname)) + +# We need to make sure our sendto() finishes before we close the socket +sock.setblocking(1) + +# Set the time-to-live +sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack('b', args.ttl)) + +ms = args.interval / 1000.0 + +# Send data to the multicast group +for x in xrange(args.count): + log.info('TX multicast UDP packet to %s:%d on %s' % (args.group, args.port, args.ifname)) + sent = sock.sendto('foobar %d' % x, (args.group, args.port)) + + if args.count > 1 and ms: + time.sleep(ms) + +sock.close() diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf new file mode 100644 index 0000000000..5740c66e24 --- /dev/null +++ b/tests/topotests/pim-basic/r1/pimd.conf @@ -0,0 +1,10 @@ +hostname r1 +! +interface r1-eth0 + ip igmp + ip pim sm +! +interface lo + ip pim sm +! +ip pim rp 10.254.0.1 diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf new file mode 100644 index 0000000000..2bf71294d0 --- /dev/null +++ b/tests/topotests/pim-basic/r1/zebra.conf @@ -0,0 +1,8 @@ +hostname r1 +! +interface r1-eth0 + ip address 10.0.20.1/24 +! +interface lo + ip address 10.254.0.1/32 +! diff --git a/tests/topotests/pim-basic/r2/pimd.conf b/tests/topotests/pim-basic/r2/pimd.conf new file mode 100644 index 0000000000..932cff6f3b --- /dev/null +++ b/tests/topotests/pim-basic/r2/pimd.conf @@ -0,0 +1 @@ +hostname r2 diff --git a/tests/topotests/pim-basic/r2/zebra.conf b/tests/topotests/pim-basic/r2/zebra.conf new file mode 100644 index 0000000000..cb30858f58 --- /dev/null +++ b/tests/topotests/pim-basic/r2/zebra.conf @@ -0,0 +1,8 @@ +hostname r2 +! +interface r2-eth0 + ip address 10.0.20.2/24 +! +interface lo + ip address 10.254.0.2/32 +! diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py new file mode 100644 index 0000000000..6d54b8f2f0 --- /dev/null +++ b/tests/topotests/pim-basic/test_pim.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python + +# +# test_pim.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_pim.py: Test pim +""" + +import os +import sys +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from mininet.topo import Topo + +class PIMTopo(Topo): + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + # r1 <- sw1 -> r2 + sw = tgen.add_switch('sw1') + sw.add_link(tgen.gears['r1']) + sw.add_link(tgen.gears['r2']) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(PIMTopo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_PIM, + os.path.join(CWD, '{}/pimd.conf'.format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_pim_send_mcast_stream(): + "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate" + logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears['r2'] + r1 = tgen.gears['r1'] + + # Let's establish a S,G stream from r2 -> r1 + CWD = os.path.dirname(os.path.realpath(__file__)) + r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD)) + + # Let's see that it shows up and we have established some basic state + out = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + expected = { + '229.1.1.1': { + '10.0.20.2': { + 'firstHopRouter': 1, + 'joinState': 'NotJoined', + 'regState': 'RegPrune', + 'inboundInterface': 'r1-eth0', + } + } + } + + assert topotest.json_cmp(out, expected) is None, 'failed to converge pim' + + +def test_pim_igmp_report(): + "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1" + logger.info("Send a igmp report from r2-r1 and ensure *,G created") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears['r2'] + r1 = tgen.gears['r1'] + + # Let's send a igmp report from r2->r1 + CWD = os.path.dirname(os.path.realpath(__file__)) + r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD)) + + out = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + expected = { + '229.1.1.2': { + '*': { + 'sourceIgmp': 1, + 'joinState': 'Joined', + 'regState': 'RegNoInfo', + 'sptBit': 0, + } + } + } + + assert topotest.json_cmp(out, expected) is None, 'failed to converge pim' + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tools/frr.in b/tools/frr.in index a443191fd0..2e3a094589 100755 --- a/tools/frr.in +++ b/tools/frr.in @@ -504,7 +504,9 @@ check_status() # Load configuration . "$C_PATH/daemons" -. "$C_PATH/daemons.conf" +if [ -e "$C_PATH/daemons.conf" ]; then + . "$C_PATH/daemons.conf" +fi # Read configuration variable file if it is present [ -r /etc/default/frr ] && . /etc/default/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/connected.h b/zebra/connected.h index faba30b0d5..7672bec006 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -28,6 +28,10 @@ #include "lib/if.h" #include "lib/prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + extern struct connected *connected_check(struct interface *ifp, union prefixconstptr p); extern struct connected *connected_check_ptp(struct interface *ifp, @@ -58,4 +62,7 @@ extern void connected_delete_ipv6(struct interface *ifp, extern int connected_is_unnumbered(struct interface *); +#ifdef __cplusplus +} +#endif #endif /*_ZEBRA_CONNECTED_H */ 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 c79cd96c21..176226f7ae 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -24,6 +24,10 @@ #include "lib/vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Debug flags. */ #define ZEBRA_DEBUG_EVENT 0x01 @@ -40,7 +44,9 @@ #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 @@ -72,7 +78,10 @@ #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) @@ -99,4 +108,8 @@ extern void zebra_debug_init(void); DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DEBUG_H */ diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 65a266a519..710fd52558 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -23,11 +23,19 @@ #ifdef HAVE_NETLINK +#ifdef __cplusplus +extern "C" { +#endif + extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int interface_lookup_netlink(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_IF_NETLINK_H */ diff --git a/zebra/interface.h b/zebra/interface.h index 1dbcf33fad..ce404e8253 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -28,6 +28,10 @@ #include "zebra/zebra_l2.h" +#ifdef __cplusplus +extern "C" { +#endif + /* For interface multicast configuration. */ #define IF_ZEBRA_MULTICAST_UNSPEC 0 #define IF_ZEBRA_MULTICAST_ON 1 @@ -432,4 +436,8 @@ extern int interface_list_proc(void); extern int ifaddr_proc_ipv6(void); #endif /* HAVE_PROC_NET_IF_INET6 */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_INTERFACE_H */ diff --git a/zebra/ioctl.h b/zebra/ioctl.h index 2a8ea77909..67ffd45a08 100644 --- a/zebra/ioctl.h +++ b/zebra/ioctl.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_IOCTL_H #define _ZEBRA_IOCTL_H +#ifdef __cplusplus +extern "C" { +#endif + /* Prototypes. */ extern void ifreq_set_name(struct ifreq *, struct interface *); extern int if_ioctl(unsigned long, caddr_t); @@ -53,4 +57,8 @@ extern struct connected *if_lookup_linklocal(struct interface *); #endif /* SOLARIS_IPV6 */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IOCTL_H */ diff --git a/zebra/ioctl_solaris.h b/zebra/ioctl_solaris.h index 3507e563cd..363f382896 100644 --- a/zebra/ioctl_solaris.h +++ b/zebra/ioctl_solaris.h @@ -22,7 +22,15 @@ #ifndef _ZEBRA_IF_IOCTL_SOLARIS_H #define _ZEBRA_IF_IOCTL_SOLARIS_H +#ifdef __cplusplus +extern "C" { +#endif + void lifreq_set_name(struct lifreq *, const char *); int if_get_flags_direct(const char *, uint64_t *, unsigned int af); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */ diff --git a/zebra/ipforward.h b/zebra/ipforward.h index fe9f2db911..9884678c7a 100644 --- a/zebra/ipforward.h +++ b/zebra/ipforward.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_IPFORWARD_H #define _ZEBRA_IPFORWARD_H +#ifdef __cplusplus +extern "C" { +#endif + extern int ipforward(void); extern int ipforward_on(void); extern int ipforward_off(void); @@ -29,4 +33,8 @@ extern int ipforward_ipv6(void); extern int ipforward_ipv6_on(void); extern int ipforward_ipv6_off(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IPFORWARD_H */ diff --git a/zebra/irdp.h b/zebra/irdp.h index 4800e75be3..3f4fa93460 100644 --- a/zebra/irdp.h +++ b/zebra/irdp.h @@ -28,6 +28,10 @@ #include "lib/vty.h" +#ifdef __cplusplus +extern "C" { +#endif + #define TRUE 1 #define FALSE 0 @@ -150,5 +154,8 @@ extern int irdp_read_raw(struct thread *r); extern void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, struct prefix *p, uint32_t ttl); +#ifdef __cplusplus +} +#endif #endif /* _IRDP_H */ 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/kernel_netlink.h b/zebra/kernel_netlink.h index 9918729eb6..076ca5c5c7 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_KERNEL_NETLINK_H #define _ZEBRA_KERNEL_NETLINK_H +#ifdef __cplusplus +extern "C" { +#endif + #ifdef HAVE_NETLINK #define NL_RCV_PKT_BUF_SIZE 32768 @@ -68,4 +72,8 @@ extern int netlink_request(struct nlsock *nl, struct nlmsghdr *n); #endif /* HAVE_NETLINK */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_KERNEL_NETLINK_H */ diff --git a/zebra/kernel_socket.h b/zebra/kernel_socket.h index 096a21f782..15079d796d 100644 --- a/zebra/kernel_socket.h +++ b/zebra/kernel_socket.h @@ -22,6 +22,10 @@ #ifndef __ZEBRA_KERNEL_SOCKET_H #define __ZEBRA_KERNEL_SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + /* Error codes of zebra. */ #define ZEBRA_ERR_NOERROR 0 #define ZEBRA_ERR_RTEXIST -1 @@ -38,4 +42,8 @@ extern int rtm_write(int, union sockunion *, union sockunion *, enum blackhole_type, int); extern const struct message rtm_type_str[]; +#ifdef __cplusplus +} +#endif + #endif /* __ZEBRA_KERNEL_SOCKET_H */ diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 3e3def5f98..3ea89fbfc3 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -31,6 +31,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NO_PROTO 0 /* @@ -74,4 +78,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, int release_daemon_label_chunks(struct zserv *client); void label_manager_close(void); +#ifdef __cplusplus +} +#endif + #endif /* _LABEL_MANAGER_H */ 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/redistribute.h b/zebra/redistribute.h index f0dc79574c..74a593b240 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -29,6 +29,10 @@ #include "zebra/zserv.h" #include "zebra/rib.h" +#ifdef __cplusplus +extern "C" { +#endif + /* ZAPI command handlers */ extern void zebra_redistribute_add(ZAPI_HANDLER_ARGS); extern void zebra_redistribute_delete(ZAPI_HANDLER_ARGS); @@ -73,4 +77,9 @@ extern int is_zebra_import_table_enabled(afi_t, uint32_t table_id); extern int zebra_import_table_config(struct vty *); extern void zebra_import_table_rm_update(const char *rmap); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_REDISTRIBUTE_H */ diff --git a/zebra/rib.h b/zebra/rib.h index a478fffddb..e26831e1a6 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -35,6 +35,10 @@ #include "mpls.h" #include "srcdest_table.h" +#ifdef __cplusplus +extern "C" { +#endif + #define DISTANCE_INFINITY 255 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */ @@ -141,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; @@ -168,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). */ @@ -355,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. */ @@ -427,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) @@ -464,4 +486,9 @@ extern void zebra_vty_init(void); extern pid_t pid; extern bool v6_rr_semantics; + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/router-id.h b/zebra/router-id.h index 6b15159fdb..f7d16853f1 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -30,6 +30,10 @@ #include "zclient.h" #include "if.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void router_id_add_address(struct connected *); extern void router_id_del_address(struct connected *); extern void router_id_init(struct zebra_vrf *); @@ -37,4 +41,8 @@ extern void router_id_cmd_init(void); extern void router_id_write(struct vty *); extern void router_id_get(struct prefix *, vrf_id_t); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/rt.h b/zebra/rt.h index 4080b0ccb2..2c77af2aad 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -31,6 +31,13 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_dplane.h" +#ifdef __cplusplus +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. @@ -91,4 +98,8 @@ extern void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if); extern void route_read(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_RT_H */ 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_netlink.h b/zebra/rt_netlink.h index 473ad98a3f..29e0152bb2 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -26,6 +26,10 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_dplane.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NL_DEFAULT_ROUTE_METRIC 20 /* @@ -79,6 +83,10 @@ extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, extern int netlink_neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ 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/rtadv.h b/zebra/rtadv.h index f7c27ebcb3..53c497fc09 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -25,6 +25,10 @@ #include "vty.h" #include "zebra/interface.h" +#ifdef __cplusplus +extern "C" { +#endif + /* NB: RTADV is defined in zebra/interface.h above */ #if defined(HAVE_RTADV) @@ -137,5 +141,8 @@ extern void rtadv_cmd_init(void); extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); +#ifdef __cplusplus +} +#endif #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h index 4547a1bb3b..8c4741dc06 100644 --- a/zebra/rule_netlink.h +++ b/zebra/rule_netlink.h @@ -26,6 +26,10 @@ #ifdef HAVE_NETLINK +#ifdef __cplusplus +extern "C" { +#endif + /* * Handle netlink notification informing a rule add or delete. */ @@ -36,6 +40,10 @@ extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); */ extern int netlink_rules_read(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RULE_NETLINK_H */ diff --git a/zebra/table_manager.h b/zebra/table_manager.h index 5196162c4c..4f78f5097e 100644 --- a/zebra/table_manager.h +++ b/zebra/table_manager.h @@ -27,6 +27,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Table chunk struct * Client daemon which the chunk belongs to can be identified by either @@ -63,4 +67,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start, int release_daemon_table_chunks(struct zserv *client); void table_manager_disable(ns_id_t ns_id); +#ifdef __cplusplus +} +#endif + #endif /* _TABLE_MANAGER_H */ 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/zapi_msg.h b/zebra/zapi_msg.h index b770b8e881..d30fa2d0ef 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -30,6 +30,10 @@ #include "zebra/zebra_pbr.h" #include "zebra/zebra_errors.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * This is called to process inbound ZAPI messages. * @@ -86,3 +90,7 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); extern void zsend_capabilities_all_clients(void); + +#ifdef __cplusplus +} +#endif diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 149ff8dc60..1246fcc8ec 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -30,6 +30,10 @@ #include "zebra/zserv.h" #include "zebra/zebra_mpls.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Key netlink info from zebra ns */ struct zebra_dplane_info { ns_id_t ns_id; @@ -394,4 +398,8 @@ void zebra_dplane_pre_finish(void); void zebra_dplane_finish(void); void zebra_dplane_shutdown(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DPLANE_H */ diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 0af5f8a551..2b7831a408 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -23,6 +23,10 @@ #include "lib/ferr.h" +#ifdef __cplusplus +extern "C" { +#endif + enum zebra_log_refs { EC_ZEBRA_LM_RESPONSE = ZEBRA_FERR_START, EC_ZEBRA_LM_NO_SUCH_CLIENT, @@ -126,4 +130,8 @@ enum zebra_log_refs { void zebra_error_init(void); +#ifdef __cplusplus +} +#endif + #endif /* __EC_ZEBRAORS_H__ */ diff --git a/zebra/zebra_fpm_private.h b/zebra/zebra_fpm_private.h index 969ab6cfee..943aad9864 100644 --- a/zebra/zebra_fpm_private.h +++ b/zebra/zebra_fpm_private.h @@ -26,6 +26,10 @@ #include "zebra/debug.h" +#ifdef __cplusplus +extern "C" { +#endif + #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define zfpm_debug(...) \ @@ -61,4 +65,9 @@ extern int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re, uint8_t *in_buf, size_t in_buf_len); extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FPM_PRIVATE_H */ diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 68c9d4a7a1..2e3e5b4a85 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -29,6 +29,10 @@ #include "vlan.h" #include "vxlan.h" +#ifdef __cplusplus +extern "C" { +#endif + /* zebra L2 interface information - bridge slave (linkage to bridge) */ struct zebra_l2info_brslave { ifindex_t bridge_ifindex; /* Bridge Master */ @@ -96,4 +100,9 @@ extern void zebra_l2if_update_bridge_slave(struct interface *ifp, extern void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_L2_H */ diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h index de55478de2..667c73b227 100644 --- a/zebra/zebra_memory.h +++ b/zebra/zebra_memory.h @@ -24,6 +24,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MGROUP(ZEBRA) DECLARE_MTYPE(RTADV_PREFIX) DECLARE_MTYPE(ZEBRA_NS) @@ -37,4 +41,8 @@ DECLARE_MTYPE(RNH) DECLARE_MTYPE(DP_CTX) DECLARE_MTYPE(DP_PROV) +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_ZEBRA_MEMORY_H */ diff --git a/zebra/zebra_mlag.h b/zebra/zebra_mlag.h index c5c147c833..90a5a41fa4 100644 --- a/zebra/zebra_mlag.h +++ b/zebra/zebra_mlag.h @@ -24,8 +24,17 @@ #include "mlag.h" +#ifdef __cplusplus +extern "C" { +#endif + void zebra_mlag_init(void); void zebra_mlag_terminate(void); enum mlag_role zebra_mlag_get_role(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 39f084ad2f..3a131e1aaf 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -34,6 +34,9 @@ #include "zebra/zserv.h" #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif /* Definitions and macros. */ @@ -507,31 +510,48 @@ 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. */ extern int mpls_enabled; +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_MPLS_H */ diff --git a/zebra/zebra_mroute.h b/zebra/zebra_mroute.h index 3385153600..3c12b82da3 100644 --- a/zebra/zebra_mroute.h +++ b/zebra/zebra_mroute.h @@ -24,6 +24,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + struct mcast_route_data { struct prefix_sg sg; unsigned int ifindex; @@ -32,4 +36,8 @@ struct mcast_route_data { void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h index d6530e6694..7a5f6851f4 100644 --- a/zebra/zebra_netns_id.h +++ b/zebra/zebra_netns_id.h @@ -20,7 +20,15 @@ #include "zebra.h" #include "ns.h" +#ifdef __cplusplus +extern "C" { +#endif + extern ns_id_t zebra_ns_id_get(const char *netnspath); extern ns_id_t zebra_ns_id_get_default(void); +#ifdef __cplusplus +} +#endif + #endif /* __ZEBRA_NS_ID_H__ */ diff --git a/zebra/zebra_netns_notify.h b/zebra/zebra_netns_notify.h index 0ced749ae8..18939283a7 100644 --- a/zebra/zebra_netns_notify.h +++ b/zebra/zebra_netns_notify.h @@ -20,10 +20,18 @@ #ifndef _NETNS_NOTIFY_H #define _NETNS_NOTIFY_H +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_ns_notify_init(void); extern void zebra_ns_notify_parse(void); extern void zebra_ns_notify_close(void); extern struct zebra_privs_t zserv_privs; +#ifdef __cplusplus +} +#endif + #endif /* NETNS_NOTIFY_H */ diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 01af64c17b..dc79a83db0 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -28,6 +28,10 @@ #include "zebra/rib.h" #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifdef HAVE_NETLINK /* Socket interface to kernel */ struct nlsock { @@ -68,4 +72,8 @@ int zebra_ns_final_shutdown(struct ns *ns); int zebra_ns_config_write(struct vty *vty, struct ns *ns); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 5b6c23896c..0d55491107 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -32,6 +32,10 @@ #include "rt.h" #include "pbr.h" +#ifdef __cplusplus +extern "C" { +#endif + struct zebra_pbr_rule { int sock; @@ -252,4 +256,8 @@ DECLARE_HOOK(zebra_pbr_ipset_entry_update, DECLARE_HOOK(zebra_pbr_ipset_update, (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset)); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PBR_H */ diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index d0cdaf0bce..e578a02a94 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -31,6 +31,10 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #include "zebra/zserv.h" #include "zebra/interface.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Zebra ptm context block */ struct zebra_ptm_cb { int ptm_sock; /* ptm file descriptor. */ @@ -87,4 +91,9 @@ void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_ptm_redistribute.h b/zebra/zebra_ptm_redistribute.h index c1b12bd0d1..4daf405825 100644 --- a/zebra/zebra_ptm_redistribute.h +++ b/zebra/zebra_ptm_redistribute.h @@ -21,7 +21,17 @@ #ifndef _ZEBRA_PTM_REDISTRIBUTE_H #define _ZEBRA_PTM_REDISTRIBUTE_H + +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_interface_bfd_update(struct interface *, struct prefix *, struct prefix *, int, vrf_id_t); extern void zebra_bfd_peer_replay_req(void); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PTM_REDISTRIBUTE_H */ diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 9692fb4d40..bbb3776725 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -29,6 +29,10 @@ #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PW_INSTALL_RETRY_INTERVAL 30 struct zebra_pw { @@ -74,4 +78,8 @@ void zebra_pw_init(struct zebra_vrf *); void zebra_pw_exit(struct zebra_vrf *); void zebra_pw_vty_init(void); +#ifdef __cplusplus +} +#endif + #endif /* ZEBRA_PW_H_ */ 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 00ee60dc1a..7d823c7acc 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -25,6 +25,12 @@ #include "prefix.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t; + /* Nexthop structure. */ struct rnh { uint8_t flags; @@ -36,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; @@ -51,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; @@ -83,4 +93,9 @@ extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, rnh_type_t); extern char *rnh_str(struct rnh *rnh, char *buf, int size); + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index abd2ad78f7..6a630e1ac0 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -24,6 +24,10 @@ #include "lib/routemap.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_route_map_init(void); extern void zebra_routemap_config_write_protocol(struct vty *vty, struct zebra_vrf *vrf); @@ -48,4 +52,8 @@ zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, struct zebra_vrf *zvrf, struct route_entry *, struct nexthop *nexthop); +#ifdef __cplusplus +} +#endif + #endif 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_router.h b/zebra/zebra_router.h index e5043f38ae..61f2902233 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -26,6 +26,10 @@ #include "zebra/zebra_ns.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * This header file contains the idea of a router and as such * owns data that is associated with a router from zebra's @@ -129,4 +133,9 @@ extern void zebra_router_sweep_route(void); extern void zebra_router_show_table_summary(struct vty *vty); extern uint32_t zebra_router_get_next_sequence(void); + +#ifdef __cplusplus +} +#endif + #endif 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_vrf.h b/zebra/zebra_vrf.h index e35101d833..502fc343c5 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -28,6 +28,10 @@ #include <zebra/zebra_pw.h> #include <lib/vxlan.h> +#ifdef __cplusplus +extern "C" { +#endif + /* MPLS (Segment Routing) global block */ typedef struct mpls_srgb_t_ { uint32_t start_label; @@ -203,4 +207,9 @@ extern void zebra_vrf_init(void); extern void zebra_rtable_node_cleanup(struct route_table *table, struct route_node *node); + +#ifdef __cplusplus +} +#endif + #endif /* ZEBRA_VRF_H */ 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/zebra_vxlan.h b/zebra/zebra_vxlan.h index 2cf21ff90b..206f65044a 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -35,6 +35,10 @@ #include "zebra/zebra_vrf.h" #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Is EVPN enabled? */ #define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni static inline int is_evpn_enabled(void) @@ -206,4 +210,8 @@ extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VXLAN_H */ diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index c36d156359..5081c08d19 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -26,12 +26,14 @@ #include <zebra.h> -#include <zebra.h> - #include "if.h" #include "linklist.h" #include "zebra_vxlan.h" +#ifdef __cplusplus +extern "C" { +#endif + #define ERR_STR_SZ 256 /* definitions */ @@ -421,4 +423,8 @@ struct nh_walk_ctx { struct json_object *json; }; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VXLAN_PRIVATE_H */ 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 ac016e65f3..86863d961c 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -40,6 +40,10 @@ #include "zebra/zebra_vrf.h" /* for zebra_vrf */ /* clang-format on */ +#ifdef __cplusplus +extern "C" { +#endif + /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -180,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 @@ -234,4 +245,8 @@ extern void zserv_read_file(char *input); /* TODO */ int zebra_finalize(struct thread *event); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_ZEBRA_H */ |
