summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore1
-rw-r--r--README.md5
-rw-r--r--alpine/APKBUILD.in9
-rw-r--r--bgpd/bgp_attr.c6
-rw-r--r--bgpd/bgp_evpn_private.h5
-rw-r--r--bgpd/bgp_route.c10
-rw-r--r--doc/developer/building-frr-for-fedora.rst122
-rw-r--r--doc/developer/building-frr-for-fedora24.rst169
-rw-r--r--doc/developer/building-frr-for-ubuntu1404.rst187
-rw-r--r--doc/developer/building-frr-for-ubuntu1604.rst216
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst205
-rw-r--r--doc/developer/building.rst2
-rw-r--r--doc/developer/conf.py2
-rw-r--r--doc/developer/include-compile.rst37
-rw-r--r--doc/developer/subdir.am3
-rw-r--r--doc/developer/workflow.rst11
-rw-r--r--doc/manpages/conf.py2
-rw-r--r--docker/alpine/Dockerfile81
-rwxr-xr-xdocker/alpine/alpine-build.sh11
-rwxr-xr-xdocker/alpine/build.sh33
-rw-r--r--docker/alpine/builder1
-rwxr-xr-xdocker/alpine/docker-start (renamed from alpine/docker-start)6
-rw-r--r--isisd/isis_zebra.c4
-rw-r--r--lib/log.c10
-rw-r--r--lib/zclient.c7
-rw-r--r--ospf6d/ospf6_zebra.c3
-rw-r--r--ospfd/ospf_packet.c28
-rw-r--r--ripngd/ripng_zebra.c3
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/zebra.conf6
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/zebra.conf5
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/zebra.conf5
-rw-r--r--tests/topotests/lib/topogen.py4
-rw-r--r--tests/topotests/lib/topotest.py33
-rwxr-xr-xtests/topotests/pim-basic/mcast-rx.py83
-rwxr-xr-xtests/topotests/pim-basic/mcast-tx.py72
-rw-r--r--tests/topotests/pim-basic/r1/pimd.conf10
-rw-r--r--tests/topotests/pim-basic/r1/zebra.conf8
-rw-r--r--tests/topotests/pim-basic/r2/pimd.conf1
-rw-r--r--tests/topotests/pim-basic/r2/zebra.conf8
-rw-r--r--tests/topotests/pim-basic/test_pim.py158
-rwxr-xr-xtools/frr.in4
-rw-r--r--zebra/connected.c6
-rw-r--r--zebra/connected.h7
-rw-r--r--zebra/debug.c28
-rw-r--r--zebra/debug.h15
-rw-r--r--zebra/if_netlink.h8
-rw-r--r--zebra/interface.h8
-rw-r--r--zebra/ioctl.h8
-rw-r--r--zebra/ioctl_solaris.h8
-rw-r--r--zebra/ipforward.h8
-rw-r--r--zebra/irdp.h7
-rw-r--r--zebra/kernel_netlink.c46
-rw-r--r--zebra/kernel_netlink.h8
-rw-r--r--zebra/kernel_socket.h8
-rw-r--r--zebra/label_manager.h8
-rw-r--r--zebra/main.c2
-rw-r--r--zebra/redistribute.h9
-rw-r--r--zebra/rib.h27
-rw-r--r--zebra/router-id.h8
-rw-r--r--zebra/rt.h11
-rw-r--r--zebra/rt_netlink.c9
-rw-r--r--zebra/rt_netlink.h8
-rw-r--r--zebra/rt_socket.c54
-rw-r--r--zebra/rtadv.h7
-rw-r--r--zebra/rule_netlink.h8
-rw-r--r--zebra/table_manager.h8
-rw-r--r--zebra/zapi_msg.c8
-rw-r--r--zebra/zapi_msg.h8
-rw-r--r--zebra/zebra_dplane.h8
-rw-r--r--zebra/zebra_errors.h8
-rw-r--r--zebra/zebra_fpm_private.h9
-rw-r--r--zebra/zebra_l2.h9
-rw-r--r--zebra/zebra_memory.h8
-rw-r--r--zebra/zebra_mlag.h9
-rw-r--r--zebra/zebra_mpls.h40
-rw-r--r--zebra/zebra_mroute.h8
-rw-r--r--zebra/zebra_netns_id.h8
-rw-r--r--zebra/zebra_netns_notify.h8
-rw-r--r--zebra/zebra_ns.h8
-rw-r--r--zebra/zebra_pbr.h8
-rw-r--r--zebra/zebra_ptm.h9
-rw-r--r--zebra/zebra_ptm_redistribute.h10
-rw-r--r--zebra/zebra_pw.h8
-rw-r--r--zebra/zebra_rib.c354
-rw-r--r--zebra/zebra_rnh.c196
-rw-r--r--zebra/zebra_rnh.h19
-rw-r--r--zebra/zebra_routemap.h8
-rw-r--r--zebra/zebra_router.c2
-rw-r--r--zebra/zebra_router.h9
-rw-r--r--zebra/zebra_vrf.c16
-rw-r--r--zebra/zebra_vrf.h9
-rw-r--r--zebra/zebra_vty.c2
-rw-r--r--zebra/zebra_vxlan.c10
-rw-r--r--zebra/zebra_vxlan.h8
-rw-r--r--zebra/zebra_vxlan_private.h10
-rw-r--r--zebra/zserv.c12
-rw-r--r--zebra/zserv.h15
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
diff --git a/README.md b/README.md
index 995c1b50ba..a7725d5e4e 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/lib/log.c b/lib/log.c
index e98040eb06..cf623a4c19 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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 */