]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2057 from donaldsharp/fix_1916
authorRuss White <russ@riw.us>
Fri, 20 Apr 2018 11:56:48 +0000 (07:56 -0400)
committerGitHub <noreply@github.com>
Fri, 20 Apr 2018 11:56:48 +0000 (07:56 -0400)
Fix 1916

147 files changed:
alpine/APKBUILD.in
alpine/docker-start [new file with mode: 0755]
alpine/frr.post-deinstall [new file with mode: 0755]
alpine/frr.pre-deinstall [new file with mode: 0755]
alpine/frr.pre-install [new file with mode: 0755]
babeld/route.c
bgpd/Makefile.am
bgpd/bgp_attr_evpn.h
bgpd/bgp_clist.c
bgpd/bgp_clist.h
bgpd/bgp_damp.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn_vty.c
bgpd/bgp_flowspec_vty.c
bgpd/bgp_labelpool.c [new file with mode: 0644]
bgpd/bgp_labelpool.h [new file with mode: 0644]
bgpd/bgp_mpath.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/rfapi_import.c
doc/Makefile.am
doc/developer/_static/overrides.css
doc/developer/building-frr-on-alpine.rst
doc/developer/building-frr-on-centos6.rst
doc/developer/building-frr-on-centos7.rst
doc/developer/building-frr-on-debian8.rst
doc/developer/building-frr-on-debian9.rst
doc/developer/building-frr-on-fedora24.rst
doc/developer/building-frr-on-freebsd10.rst
doc/developer/building-frr-on-freebsd11.rst
doc/developer/building-frr-on-freebsd9.rst
doc/developer/building-frr-on-lede-openwrt.rst
doc/developer/building-frr-on-netbsd6.rst
doc/developer/building-frr-on-netbsd7.rst
doc/developer/building-frr-on-omnios.rst
doc/developer/building-frr-on-openbsd6.rst
doc/developer/building-frr-on-ubuntu1204.rst
doc/developer/building-frr-on-ubuntu1404.rst
doc/developer/building-frr-on-ubuntu1604.rst
doc/developer/building-frr-on-ubuntu1804.rst
doc/developer/building.rst
doc/developer/conf.py
doc/developer/hooks.rst
doc/developer/library.rst
doc/developer/memtypes.rst
doc/developer/next-hop-tracking.rst
doc/developer/ospf-sr.rst
doc/developer/workflow.rst
doc/extra/frrlexer.py [new file with mode: 0644]
doc/manpages/conf.py
doc/user/_static/overrides.css
doc/user/basic.rst
doc/user/bgp.rst
doc/user/conf.py
doc/user/eigrpd.rst
doc/user/filter.rst
doc/user/isisd.rst
doc/user/nhrpd.rst
doc/user/ospf6d.rst
doc/user/ospf_fundamentals.rst
doc/user/ospfd.rst
doc/user/overview.rst
doc/user/pim.rst
doc/user/ripd.rst
doc/user/routemap.rst
doc/user/routeserver.rst
doc/user/rpki.rst
doc/user/snmp.rst
doc/user/snmptrap.rst
doc/user/vnc.rst
doc/user/zebra.rst
docker/alpine/Dockerfile
eigrpd/eigrp_snmp.c
lib/buffer.c
lib/command_lex.l
lib/command_match.c
lib/imsg.c
lib/libfrr.c
lib/log.c
lib/mpls.c [new file with mode: 0644]
lib/mpls.h
lib/netns_linux.c
lib/netns_other.c
lib/nexthop_group.c
lib/nexthop_group.h
lib/ns.h
lib/pbr.h [new file with mode: 0644]
lib/route_types.pl
lib/route_types.txt
lib/subdir.am
lib/vrf.c
lib/vrf.h
lib/zclient.c
lib/zclient.h
ospf6d/ospf6_abr.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_zebra.c
ospfd/ospf_lsa.c
ospfd/ospf_snmp.c
ospfd/ospf_te.c
ospfd/ospf_zebra.c
pbrd/pbr_debug.c
pbrd/pbr_debug.h
pbrd/pbr_main.c
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_nht.c
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
pimd/mtracebis_routeget.c
tests/ospf6d/test_lsdb.c
tools/frr
tools/lsan-suppressions.txt
vtysh/vtysh_main.c
zebra/client_main.c
zebra/connected.c
zebra/connected.h
zebra/if_ioctl.c
zebra/if_ioctl_solaris.c
zebra/if_netlink.c
zebra/kernel_socket.c
zebra/redistribute.c
zebra/rule_netlink.c
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_netns_notify.c
zebra/zebra_ns.c
zebra/zebra_ns.h
zebra/zebra_pbr.c
zebra/zebra_pbr.h
zebra/zebra_rnh.c
zebra/zserv.c
zebra/zserv.h

index 2b211ccafdb53e9367a5ff47cfe969f4ae562fc6..c3e7e939e4d29b67c9f85afcc36a7f1a20784ce4 100644 (file)
@@ -4,9 +4,9 @@ pkgver=@VERSION@
 pkgrel=0
 pkgdesc="Free Range Routing is a fork of quagga"
 url="https://frrouting.org/"
-arch="all"
+arch="x86_64"
 license="GPL-2.0"
-depends="iproute2 json-c c-ares ipsec-tools iproute2"
+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
@@ -20,18 +20,42 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
     patch pax-utils pcre perl pkgconf python2 python2-dev readline
     readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
     py-sphinx"
+install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
 subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
-source="$pkgname-$pkgver.tar.gz"
+source="$pkgname-$pkgver.tar.gz docker-start daemons daemons.conf"
 
 builddir="$srcdir"/$pkgname-$pkgver
 
+_sbindir=/usr/lib/frr
+_sysconfdir=/etc/frr
+_libdir=/usr/lib
+_localstatedir=/var/run/frr
+_user=frr
+
 build() {
        cd "$builddir"
-       ./configure --prefix=/usr || return 1
+       ./configure \
+               --prefix=/usr \
+               --sbindir=$_sbindir \
+               --sysconfdir=$_sysconfdir \
+               --libdir=$_libdir \
+               --localstatedir=$_localstatedir \
+               --enable-systemd=no \
+               --enable-vtysh \
+               --enable-multipath=64 \
+               --enable-vty-group=frrvty \
+               --enable-user=$_user \
+               --enable-group=$_user || return 1
        make || return 1
 }
 
 package() {
        cd "$builddir"
        make DESTDIR="$pkgdir" install || return 1
+
+       install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
+       install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
+       install -Dm644 "$srcdir"/daemons.conf "$pkgdir"$_sysconfdir
+       install -d "$pkgdir"/etc/init.d
+       ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
 }
diff --git a/alpine/docker-start b/alpine/docker-start
new file mode 100755 (executable)
index 0000000..43854ab
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+##
+# For volume mounts...
+##
+chown -R frr:frr /etc/frr
+/etc/init.d/frr start
+exec sleep 10000d
diff --git a/alpine/frr.post-deinstall b/alpine/frr.post-deinstall
new file mode 100755 (executable)
index 0000000..8f5d3dc
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+getent passwd frr > /dev/null && deluser frr
+getent group frrvty > /dev/null && delgroup frrvty
+getent group frr > /dev/null && delgroup frr
+exit 0
diff --git a/alpine/frr.pre-deinstall b/alpine/frr.pre-deinstall
new file mode 100755 (executable)
index 0000000..72cf73b
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+/etc/init.d/frr stop
+exit 0
diff --git a/alpine/frr.pre-install b/alpine/frr.pre-install
new file mode 100755 (executable)
index 0000000..da608cd
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+for g in frr frrvty; do
+       ! getent group $g > /dev/null && addgroup -S $g
+done
+
+! getent passwd frr > /dev/null && \
+       adduser -S -D -h /var/run/frr -s /sbin/nologin -G frr -g frr frr
+
+adduser frr frrvty
index 501dd1f4dfb143e33291c1bd41159d7f444c86c0..bc7590fb39b4478e5f7fe8f24c9b4c515065f16c 100644 (file)
@@ -176,6 +176,7 @@ insert_route(struct babel_route *route)
             resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots);
         if(route_slots >= max_route_slots)
             return NULL;
+        assert(routes);
         route->next = NULL;
         if(n < route_slots)
             memmove(routes + n + 1, routes + n,
index 61d46dfcb96a29c8d422f94342186c50c943e443..a2880b7b94801d0e56f22950d9bc99dac8254333 100644 (file)
@@ -87,7 +87,7 @@ libbgp_a_SOURCES = \
        bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
        bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \
        bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c \
-       bgp_flowspec_vty.c
+       bgp_flowspec_vty.c bgp_labelpool.c
 
 noinst_HEADERS = \
        bgp_memory.h \
@@ -100,7 +100,8 @@ noinst_HEADERS = \
        bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \
        $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
         bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \
-       bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h
+       bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h \
+       bgp_labelpool.h
 
 bgpd_SOURCES = bgp_main.c
 bgpd_LDADD = libbgp.a  $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
index cb1c131ef76f60788b931873d7b31e0c91df97be..7454b81b966870903f72b4ce05365aebef73fa8d 100644 (file)
@@ -37,6 +37,7 @@
 unsigned long eth_tag_id;
 struct attr;
 
+/* EVPN ESI */
 struct eth_segment_id {
        uint8_t val[ESI_LEN];
 };
index 8f38f5765f20c349d6a7eba695c88fe46b75e9c6..d1bc7f6e535a849bfb9530c9069792d186d1fd67 100644 (file)
@@ -852,7 +852,7 @@ int community_list_set(struct community_list_handler *ch, const char *name,
 
 /* Unset community-list */
 int community_list_unset(struct community_list_handler *ch, const char *name,
-                        const char *str, int direct, int style, int delete_all)
+                        const char *str, int direct, int style)
 {
        struct community_entry *entry = NULL;
        struct community_list *list;
@@ -864,16 +864,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
                return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
 
        /* Delete all of entry belongs to this community-list.  */
-       if (delete_all) {
+       if (!str) {
                community_list_delete(list);
                route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
                return 0;
        }
 
-       if (style == COMMUNITY_LIST_STANDARD) {
-               if (str)
-                       com = community_str2com(str);
-       }
+       if (style == COMMUNITY_LIST_STANDARD)
+               com = community_str2com(str);
 
        if (com) {
                entry = community_list_entry_lookup(list, com, direct);
@@ -1117,11 +1115,13 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
        return 0;
 }
 
-/* Unset extcommunity-list.  When str is NULL, delete all of
-   extcommunity-list entry belongs to the specified name.  */
+/* Unset extcommunity-list.
+ *
+ * When str is NULL, delete all extcommunity-list entries belonging to the
+ * specified name.
+ */
 int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
-                           const char *str, int direct, int style,
-                           int delete_all)
+                           const char *str, int direct, int style)
 {
        struct community_entry *entry = NULL;
        struct community_list *list;
@@ -1133,16 +1133,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
                return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
 
        /* Delete all of entry belongs to this extcommunity-list.  */
-       if (delete_all) {
+       if (!str) {
                community_list_delete(list);
                route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
                return 0;
        }
 
-       if (style == EXTCOMMUNITY_LIST_STANDARD) {
-               if (str)
-                       ecom = ecommunity_str2com(str, 0, 1);
-       }
+       if (style == EXTCOMMUNITY_LIST_STANDARD)
+               ecom = ecommunity_str2com(str, 0, 1);
 
        if (ecom) {
                entry = community_list_entry_lookup(list, ecom, direct);
index 0dbde2a45378ccca7c2f925617501d0470ddb880..9efb34d7b92d980486ce0b91b9c34545da24e1f9 100644 (file)
@@ -133,13 +133,13 @@ extern int community_list_set(struct community_list_handler *ch,
                              int style);
 extern int community_list_unset(struct community_list_handler *ch,
                                const char *name, const char *str, int direct,
-                               int style, int delete_all);
+                               int style);
 extern int extcommunity_list_set(struct community_list_handler *ch,
                                 const char *name, const char *str, int direct,
                                 int style);
 extern int extcommunity_list_unset(struct community_list_handler *ch,
                                   const char *name, const char *str,
-                                  int direct, int style, int delete_all);
+                                  int direct, int style);
 extern int lcommunity_list_set(struct community_list_handler *ch,
                               const char *name, const char *str, int direct,
                               int style);
index 1ed557e07494e98d0d763cc1b2ce822ec551f316..bce6056ded4adaae98f71431e86ebcffd618ccfb 100644 (file)
@@ -233,7 +233,7 @@ int bgp_damp_withdraw(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
        /* Remove the route from a reuse list if it is on one.  */
        if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)) {
                /* If decay rate isn't equal to 0, reinsert brn. */
-               if (bdi->penalty != last_penalty) {
+               if (bdi->penalty != last_penalty && bdi->index >= 0) {
                        bgp_reuse_list_delete(bdi);
                        bgp_reuse_list_add(bdi);
                }
index ae4ff5d67e3f0e55b33a71d0016045a1843c03c5..29ac5f520de9ac7a979426db4a7b40db9659be3e 100644 (file)
@@ -58,6 +58,7 @@ unsigned long conf_bgp_debug_nht;
 unsigned long conf_bgp_debug_update_groups;
 unsigned long conf_bgp_debug_vpn;
 unsigned long conf_bgp_debug_flowspec;
+unsigned long conf_bgp_debug_labelpool;
 
 unsigned long term_bgp_debug_as4;
 unsigned long term_bgp_debug_neighbor_events;
@@ -73,6 +74,7 @@ unsigned long term_bgp_debug_nht;
 unsigned long term_bgp_debug_update_groups;
 unsigned long term_bgp_debug_vpn;
 unsigned long term_bgp_debug_flowspec;
+unsigned long term_bgp_debug_labelpool;
 
 struct list *bgp_debug_neighbor_events_peers = NULL;
 struct list *bgp_debug_keepalive_peers = NULL;
@@ -1655,6 +1657,44 @@ DEFUN (no_debug_bgp_vpn,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_bgp_labelpool,
+       debug_bgp_labelpool_cmd,
+       "debug bgp labelpool",
+       DEBUG_STR
+       BGP_STR
+       "label pool\n")
+{
+       if (vty->node == CONFIG_NODE)
+               DEBUG_ON(labelpool, LABELPOOL);
+       else
+               TERM_DEBUG_ON(labelpool, LABELPOOL);
+
+       if (vty->node != CONFIG_NODE)
+               vty_out(vty, "enabled debug bgp labelpool\n");
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_labelpool,
+       no_debug_bgp_labelpool_cmd,
+       "no debug bgp labelpool",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "label pool\n")
+{
+       if (vty->node == CONFIG_NODE)
+               DEBUG_OFF(labelpool, LABELPOOL);
+       else
+               TERM_DEBUG_OFF(labelpool, LABELPOOL);
+
+
+       if (vty->node != CONFIG_NODE)
+               vty_out(vty, "disabled debug bgp labelpool\n");
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_bgp,
        no_debug_bgp_cmd,
        "no debug bgp",
@@ -1692,6 +1732,7 @@ DEFUN (no_debug_bgp,
        TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
        TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL);
        TERM_DEBUG_OFF(flowspec, FLOWSPEC);
+       TERM_DEBUG_OFF(labelpool, LABELPOOL);
        vty_out(vty, "All possible debugging has been turned off\n");
 
        return CMD_SUCCESS;
@@ -1764,6 +1805,8 @@ DEFUN_NOSH (show_debugging_bgp,
                vty_out(vty, "  BGP vpn label event debugging is on\n");
        if (BGP_DEBUG(flowspec, FLOWSPEC))
                vty_out(vty, "  BGP flowspec debugging is on\n");
+       if (BGP_DEBUG(labelpool, LABELPOOL))
+               vty_out(vty, "  BGP labelpool debugging is on\n");
 
        vty_out(vty, "\n");
        return CMD_SUCCESS;
@@ -1819,6 +1862,8 @@ int bgp_debug_count(void)
                ret++;
        if (BGP_DEBUG(flowspec, FLOWSPEC))
                ret++;
+       if (BGP_DEBUG(labelpool, LABELPOOL))
+               ret++;
 
        return ret;
 }
@@ -1916,6 +1961,10 @@ static int bgp_config_write_debug(struct vty *vty)
                vty_out(vty, "debug bgp flowspec\n");
                write++;
        }
+       if (CONF_BGP_DEBUG(labelpool, LABELPOOL)) {
+               vty_out(vty, "debug bgp labelpool\n");
+               write++;
+       }
 
        return write;
 }
@@ -2015,6 +2064,11 @@ void bgp_debug_init(void)
        install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
        install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
        install_element(CONFIG_NODE, &no_debug_bgp_vpn_cmd);
+
+       install_element(ENABLE_NODE, &debug_bgp_labelpool_cmd);
+       install_element(CONFIG_NODE, &debug_bgp_labelpool_cmd);
+       install_element(ENABLE_NODE, &no_debug_bgp_labelpool_cmd);
+       install_element(CONFIG_NODE, &no_debug_bgp_labelpool_cmd);
 }
 
 /* Return true if this prefix is on the per_prefix_list of prefixes to debug
index a0b179e2139aa9f78bcd3ba7e7b8d4668a72e986..ad476ee918a54ec738c818667e45a26d57511a8e 100644 (file)
@@ -74,6 +74,7 @@ extern unsigned long conf_bgp_debug_nht;
 extern unsigned long conf_bgp_debug_update_groups;
 extern unsigned long conf_bgp_debug_vpn;
 extern unsigned long conf_bgp_debug_flowspec;
+extern unsigned long conf_bgp_debug_labelpool;
 
 extern unsigned long term_bgp_debug_as4;
 extern unsigned long term_bgp_debug_neighbor_events;
@@ -87,6 +88,7 @@ extern unsigned long term_bgp_debug_nht;
 extern unsigned long term_bgp_debug_update_groups;
 extern unsigned long term_bgp_debug_vpn;
 extern unsigned long term_bgp_debug_flowspec;
+extern unsigned long term_bgp_debug_labelpool;
 
 extern struct list *bgp_debug_neighbor_events_peers;
 extern struct list *bgp_debug_keepalive_peers;
@@ -120,6 +122,7 @@ struct bgp_debug_filter {
 #define BGP_DEBUG_VPN_LEAK_RMAP_EVENT 0x04
 #define BGP_DEBUG_VPN_LEAK_LABEL      0x08
 #define BGP_DEBUG_FLOWSPEC            0x01
+#define BGP_DEBUG_LABELPOOL           0x01
 
 #define BGP_DEBUG_PACKET_SEND         0x01
 #define BGP_DEBUG_PACKET_SEND_DETAIL  0x02
index 54ec7d392b341d7a35e62c7924a8c54870666d46..80166dd32bed22410d7f304c4c89340bf6ce14a8 100644 (file)
@@ -736,6 +736,14 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                                      "MM:%u", seqnum);
                        } else
                                unk_ecom = 1;
+               } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
+                       sub_type = *pnt++;
+                       if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
+                               len = sprintf(
+                                       str_buf + str_pnt,
+                                       "FS:redirect IP 0x%x", *(pnt+5));
+                       } else
+                               unk_ecom = 1;
                } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP) {
                        sub_type = *pnt++;
 
@@ -785,10 +793,6 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                len = sprintf(
                                        str_buf + str_pnt,
                                        "FS:marking %u", *(pnt+5));
-                       } else if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
-                               len = sprintf(
-                                       str_buf + str_pnt,
-                                       "FS:redirect IP 0x%x", *(pnt+5));
                        } else
                                unk_ecom = 1;
                } else
index 31ff1481ba1feda89c3c5c82d760829aa7910e9b..0c22c5a149c6aa9f7368c8083704e7fd3643ba15 100644 (file)
@@ -28,6 +28,7 @@
 #define ECOMMUNITY_ENCODE_OPAQUE            0x03
 #define ECOMMUNITY_ENCODE_EVPN              0x06
 #define ECOMMUNITY_ENCODE_TRANS_EXP         0x80 /* Flow Spec */
+#define ECOMMUNITY_ENCODE_REDIRECT_IP_NH    0x08 /* Flow Spec */
 /* RFC7674 */
 #define ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 0x81
 #define ECOMMUNITY_EXTENDED_COMMUNITY_PART_3 0x82
index e5e5f72699f40d71b21ba343f3f5e1f2554ea0fd..483d65be719f2fd022f4ff92a7f09c57f8c16300 100644 (file)
@@ -2810,10 +2810,12 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
 {
        struct prefix_rd prd;
        struct prefix_evpn p;
+       struct bgp_route_evpn evpn;
        uint8_t ipaddr_len;
        uint8_t macaddr_len;
        mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
        uint32_t num_labels = 0;
+       uint32_t eth_tag;
        int ret;
 
        /* Type-2 route should be either 33, 37 or 49 bytes or an
@@ -2829,6 +2831,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
                return -1;
        }
 
+       memset(&evpn, 0, sizeof(evpn));
+
        /* Make prefix_rd */
        prd.family = AF_UNSPEC;
        prd.prefixlen = 64;
@@ -2841,10 +2845,13 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
        p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
 
-       /* Skip over Ethernet Seg Identifier for now. */
-       pfx += 10;
+       /* Copy Ethernet Seg Identifier */
+       memcpy(&evpn.eth_s_id.val, pfx, ESI_LEN);
+       pfx += ESI_LEN;
 
-       /* Skip over Ethernet Tag for now. */
+       /* Copy Ethernet Tag */
+       memcpy(&eth_tag, pfx, 4);
+       p.prefix.eth_tag = ntohl(eth_tag);
        pfx += 4;
 
        /* Get the MAC Addr len */
@@ -2902,11 +2909,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        if (attr)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, &label[0], num_labels, 0, NULL);
+                                &prd, &label[0], num_labels, 0, &evpn);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, &label[0], num_labels, NULL);
+                                  &prd, &label[0], num_labels, &evpn);
        return ret;
 }
 
@@ -2920,6 +2927,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
        struct prefix_rd prd;
        struct prefix_evpn p;
        uint8_t ipaddr_len;
+       uint32_t eth_tag;
        int ret;
 
        /* Type-3 route should be either 17 or 29 bytes: RD (8), Eth Tag (4),
@@ -2956,7 +2964,9 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
        p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
        p.prefix.route_type = BGP_EVPN_IMET_ROUTE;
 
-       /* Skip over Ethernet Tag for now. */
+       /* Copy Ethernet Tag */
+       memcpy(&eth_tag, pfx, 4);
+       p.prefix.eth_tag = ntohl(eth_tag);
        pfx += 4;
 
        /* Get the IP. */
@@ -3574,7 +3584,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
 
        if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
                json_object_int_add(json, "routeType", p->prefix.route_type);
-               json_object_int_add(json, "ethTag", 0);
+               json_object_int_add(json, "ethTag", p->prefix.eth_tag);
                json_object_int_add(json, "ipLen",
                                    IS_EVPN_PREFIX_IPADDR_V4(p)
                                            ? IPV4_MAX_BITLEN
@@ -3585,10 +3595,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
                if (IS_EVPN_PREFIX_IPADDR_NONE(p)) {
                        json_object_int_add(json, "routeType",
                                            p->prefix.route_type);
-                       json_object_int_add(
-                               json, "esi",
-                               0); /* TODO: we don't support esi yet */
-                       json_object_int_add(json, "ethTag", 0);
+                       json_object_int_add(json, "ethTag", p->prefix.eth_tag);
                        json_object_int_add(json, "macLen", 8 * ETH_ALEN);
                        json_object_string_add(json, "mac",
                                               prefix_mac2str(&p->prefix.mac,
@@ -3602,10 +3609,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
 
                        json_object_int_add(json, "routeType",
                                            p->prefix.route_type);
-                       json_object_int_add(
-                               json, "esi",
-                               0); /* TODO: we don't support esi yet */
-                       json_object_int_add(json, "ethTag", 0);
+                       json_object_int_add(json, "ethTag", p->prefix.eth_tag);
                        json_object_int_add(json, "macLen", 8 * ETH_ALEN);
                        json_object_string_add(json, "mac",
                                               prefix_mac2str(&p->prefix.mac,
@@ -3635,14 +3639,17 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
        char buf2[PREFIX2STR_BUFFER];
 
        if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
-               snprintf(buf, len, "[%d]:[0]:[%d]:[%s]", p->prefix.route_type,
+               snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type,
+                        p->prefix.eth_tag,
                         IS_EVPN_PREFIX_IPADDR_V4(p) ? IPV4_MAX_BITLEN
                                                     : IPV6_MAX_BITLEN,
                         inet_ntoa(p->prefix.ip.ipaddr_v4));
        } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
                if (IS_EVPN_PREFIX_IPADDR_NONE(p))
-                       snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
-                                p->prefix.route_type, 8 * ETH_ALEN,
+                       snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]",
+                                p->prefix.route_type,
+                                p->prefix.eth_tag,
+                                8 * ETH_ALEN,
                                 prefix_mac2str(&p->prefix.mac, buf1,
                                                sizeof(buf1)));
                else {
@@ -3650,8 +3657,10 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
 
                        family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET
                                                             : AF_INET6;
-                       snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]",
-                                p->prefix.route_type, 8 * ETH_ALEN,
+                       snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]:[%d]:[%s]",
+                                p->prefix.route_type,
+                                p->prefix.eth_tag,
+                                8 * ETH_ALEN,
                                 prefix_mac2str(&p->prefix.mac, buf1,
                                                sizeof(buf1)),
                                 family == AF_INET ? IPV4_MAX_BITLEN
@@ -3660,8 +3669,10 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
                                           PREFIX2STR_BUFFER));
                }
        } else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
-               snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
-                        p->prefix.route_type, p->prefix.ip_prefix_length,
+               snprintf(buf, len, "[%d]:[%d]:[%d]:[%s]",
+                        p->prefix.route_type,
+                        p->prefix.eth_tag,
+                        p->prefix.ip_prefix_length,
                         IS_EVPN_PREFIX_IPADDR_V4(p)
                                 ? inet_ntoa(p->prefix.ip.ipaddr_v4)
                                 : inet6_ntoa(p->prefix.ip.ipaddr_v6));
@@ -3703,8 +3714,11 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
                        len += 3;
                stream_putc(s, len);
                stream_put(s, prd->val, 8);   /* RD */
-               stream_put(s, 0, 10);    /* ESI */
-               stream_putl(s, 0);          /* Ethernet Tag ID */
+               if (attr)
+                       stream_put(s, &attr->evpn_overlay.eth_s_id, ESI_LEN);
+               else
+                       stream_put(s, 0, 10);
+               stream_putl(s, evp->prefix.eth_tag);        /* Ethernet Tag ID */
                stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
                stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */
                stream_putc(s, 8 * ipa_len);             /* IP address Length */
@@ -3720,7 +3734,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
        case BGP_EVPN_IMET_ROUTE:
                stream_putc(s, 17); // TODO: length - assumes IPv4 address
                stream_put(s, prd->val, 8);      /* RD */
-               stream_putl(s, 0);               /* Ethernet Tag ID */
+               stream_putl(s, evp->prefix.eth_tag);             /* Ethernet Tag ID */
                stream_putc(s, IPV4_MAX_BITLEN); /* IP address Length - bits */
                /* Originating Router's IP Addr */
                stream_put_in_addr(s, &evp->prefix.ip.ipaddr_v4);
index 6cb5c9d8da6eab2ad9816f1cf6a3272d205a0601..c74a1bfb7cf8bcd4398de2b4305eaa73d75dc101 100644 (file)
@@ -327,9 +327,9 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
                "* valid, > best, i - internal\n");
        vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
        vty_out(vty,
-               "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
+               "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
        vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
-       vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
+       vty_out(vty, "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
        vty_out(vty, "%s", ri_header);
 }
 
@@ -2110,11 +2110,11 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                        /* RD header and legend - once overall. */
                        if (rd_header && !json) {
                                vty_out(vty,
-                                       "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]\n");
+                                       "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]\n");
                                vty_out(vty,
                                        "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
                                vty_out(vty,
-                                       "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
+                                       "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
                                rd_header = 0;
                        }
 
index 247da5d18347897a372a56ccbbd23ba29ba1095d..7bf11f12aa1747919f9bbee5bd0a2f91bd0946d8 100644 (file)
@@ -312,6 +312,9 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                                json_object_array_add(json_paths,
                                                      json_ecom_path);
                }
+               if (attr->nexthop.s_addr != 0 &&
+                   display == NLRI_STRING_FORMAT_LARGE)
+                       vty_out(vty, "\tNH %-16s\n", inet_ntoa(attr->nexthop));
                XFREE(MTYPE_ECOMMUNITY_STR, s);
        }
        peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
new file mode 100644 (file)
index 0000000..2c98cd9
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * BGP Label Pool - Manage label chunk allocations from zebra asynchronously
+ *
+ * Copyright (C) 2018 LabN Consulting, L.L.C.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+#include "mpls.h"
+#include "vty.h"
+#include "fifo.h"
+#include "linklist.h"
+#include "skiplist.h"
+#include "workqueue.h"
+#include "zclient.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_labelpool.h"
+#include "bgpd/bgp_debug.h"
+
+/*
+ * Definitions and external declarations.
+ */
+extern struct zclient *zclient;
+
+/*
+ * Remember where pool data are kept
+ */
+static struct labelpool *lp;
+
+/* request this many labels at a time from zebra */
+#define LP_CHUNK_SIZE  50
+
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk")
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO")
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment")
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback")
+
+#define LABEL_FIFO_ADD(F, N)                                           \
+       do {                                                            \
+               FIFO_ADD((F), (N));                                     \
+               (F)->count++;                                           \
+       } while (0)
+
+#define LABEL_FIFO_DEL(F, N)                                           \
+       do {                                                            \
+               FIFO_DEL((N));                                          \
+               (F)->count--;                                           \
+       } while (0)
+
+#define LABEL_FIFO_INIT(F)                                             \
+       do {                                                            \
+               FIFO_INIT((F));                                         \
+               (F)->count = 0;                                         \
+       } while (0)
+
+#define LABEL_FIFO_COUNT(F) ((F)->count)
+
+#define LABEL_FIFO_EMPTY(F) FIFO_EMPTY(F)
+
+#define LABEL_FIFO_HEAD(F) ((F)->next == (F) ? NULL : (F)->next)
+
+struct lp_chunk {
+       uint32_t        first;
+       uint32_t        last;
+};
+
+/*
+ * label control block
+ */
+struct lp_lcb {
+       mpls_label_t    label;          /* MPLS_LABEL_NONE = not allocated */
+       int             type;
+       void            *labelid;       /* unique ID */
+       /*
+        * callback for label allocation and loss
+        *
+        * allocated: false = lost
+        */
+       int             (*cbfunc)(mpls_label_t label, void *lblid, bool alloc);
+};
+
+/* XXX same first elements as "struct fifo" */
+struct lp_fifo {
+       struct lp_fifo  *next;
+       struct lp_fifo  *prev;
+
+       uint32_t        count;
+       struct lp_lcb   lcb;
+};
+
+struct lp_cbq_item {
+       int             (*cbfunc)(mpls_label_t label, void *lblid, bool alloc);
+       int             type;
+       mpls_label_t    label;
+       void            *labelid;
+       bool            allocated;      /* false = lost */
+};
+
+static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data)
+{
+       struct lp_cbq_item *lcbq = data;
+       int rc;
+       int debug = BGP_DEBUG(labelpool, LABELPOOL);
+
+       if (debug)
+               zlog_debug("%s: calling callback with labelid=%p label=%u allocated=%d",
+                       __func__, lcbq->labelid, lcbq->label, lcbq->allocated);
+
+       if (lcbq->label == MPLS_LABEL_NONE) {
+               /* shouldn't happen */
+               zlog_err("%s: error: label==MPLS_LABEL_NONE", __func__);
+               return WQ_SUCCESS;
+       }
+
+       rc = (*(lcbq->cbfunc))(lcbq->label, lcbq->labelid, lcbq->allocated);
+
+       if (lcbq->allocated && rc) {
+               /*
+                * Callback rejected allocation. This situation could arise
+                * if there was a label request followed by the requestor
+                * deciding it didn't need the assignment (e.g., config
+                * change) while the reply to the original request (with
+                * label) was in the work queue.
+                */
+               if (debug)
+                       zlog_debug("%s: callback rejected allocation, releasing labelid=%p label=%u",
+                               __func__, lcbq->labelid, lcbq->label);
+
+               uintptr_t lbl = lcbq->label;
+               void *labelid;
+               struct lp_lcb *lcb;
+
+               /*
+                * If the rejected label was marked inuse by this labelid,
+                * release the label back to the pool.
+                *
+                * Further, if the rejected label was still assigned to
+                * this labelid in the LCB, delete the LCB.
+                */
+               if (!skiplist_search(lp->inuse, (void *)lbl, &labelid)) {
+                       if (labelid == lcbq->labelid) {
+                               if (!skiplist_search(lp->ledger, labelid,
+                                       (void **)&lcb)) {
+                                       if (lcbq->label == lcb->label)
+                                               skiplist_delete(lp->ledger,
+                                                       labelid, NULL);
+                               }
+                               skiplist_delete(lp->inuse, (void *)lbl, NULL);
+                       }
+               }
+       }
+
+       return WQ_SUCCESS;
+}
+
+static void lp_cbq_item_free(struct work_queue *wq, void *data)
+{
+       XFREE(MTYPE_BGP_LABEL_CBQ, data);
+}
+
+static void lp_lcb_free(void *goner)
+{
+       if (goner)
+               XFREE(MTYPE_BGP_LABEL_CB, goner);
+}
+
+static void lp_chunk_free(void *goner)
+{
+       if (goner)
+               XFREE(MTYPE_BGP_LABEL_CHUNK, goner);
+}
+
+void bgp_lp_init(struct thread_master *master, struct labelpool *pool)
+{
+       if (BGP_DEBUG(labelpool, LABELPOOL))
+               zlog_debug("%s: entry", __func__);
+
+       lp = pool;      /* Set module pointer to pool data */
+
+       lp->ledger = skiplist_new(0, NULL, lp_lcb_free);
+       lp->inuse = skiplist_new(0, NULL, NULL);
+       lp->chunks = list_new();
+       lp->chunks->del = lp_chunk_free;
+       lp->requests = XCALLOC(MTYPE_BGP_LABEL_FIFO, sizeof(struct lp_fifo));
+       LABEL_FIFO_INIT(lp->requests);
+       lp->callback_q = work_queue_new(master, "label callbacks");
+       if (!lp->callback_q) {
+               zlog_err("%s: Failed to allocate work queue", __func__);
+               exit(1);
+       }
+
+       lp->callback_q->spec.workfunc = lp_cbq_docallback;
+       lp->callback_q->spec.del_item_data = lp_cbq_item_free;
+       lp->callback_q->spec.max_retries = 0;
+}
+
+void bgp_lp_finish(void)
+{
+       struct lp_fifo *lf;
+
+       if (!lp)
+               return;
+
+       skiplist_free(lp->ledger);
+       lp->ledger = NULL;
+
+       skiplist_free(lp->inuse);
+       lp->inuse = NULL;
+
+       list_delete_and_null(&lp->chunks);
+
+       while ((lf = LABEL_FIFO_HEAD(lp->requests))) {
+
+               LABEL_FIFO_DEL(lp->requests, lf);
+               XFREE(MTYPE_BGP_LABEL_FIFO, lf);
+       }
+       XFREE(MTYPE_BGP_LABEL_FIFO, lp->requests);
+       lp->requests = NULL;
+
+       work_queue_free_and_null(&lp->callback_q);
+
+       lp = NULL;
+}
+
+static mpls_label_t get_label_from_pool(void *labelid)
+{
+       struct listnode *node;
+       struct lp_chunk *chunk;
+       int debug = BGP_DEBUG(labelpool, LABELPOOL);
+
+       /*
+        * Find a free label
+        * Linear search is not efficient but should be executed infrequently.
+        */
+       for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
+               uintptr_t lbl;
+
+               if (debug)
+                       zlog_debug("%s: chunk first=%u last=%u",
+                               __func__, chunk->first, chunk->last);
+
+               for (lbl = chunk->first; lbl <= chunk->last; ++lbl) {
+                       /* labelid is key to all-request "ledger" list */
+                       if (!skiplist_insert(lp->inuse, (void *)lbl, labelid)) {
+                               /*
+                                * Success
+                                */
+                               return lbl;
+                       }
+               }
+       }
+       return MPLS_LABEL_NONE;
+}
+
+/*
+ * Success indicated by value of "label" field in returned LCB
+ */
+static struct lp_lcb *lcb_alloc(
+       int     type,
+       void    *labelid,
+       int     (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
+{
+       /*
+        * Set up label control block
+        */
+       struct lp_lcb *new = XCALLOC(MTYPE_BGP_LABEL_CB,
+               sizeof(struct lp_lcb));
+
+       new->label = get_label_from_pool(labelid);
+       new->type = type;
+       new->labelid = labelid;
+       new->cbfunc = cbfunc;
+
+       return new;
+}
+
+/*
+ * Callers who need labels must supply a type, labelid, and callback.
+ * The type is a value defined in bgp_labelpool.h (add types as needed).
+ * The callback is for asynchronous notification of label allocation.
+ * The labelid is passed as an argument to the callback. It should be unique
+ * to the requested label instance.
+ *
+ * If zebra is not connected, callbacks with labels will be delayed
+ * until connection is established. If zebra connection is lost after
+ * labels have been assigned, existing assignments via this labelpool
+ * module will continue until reconnection.
+ *
+ * When connection to zebra is reestablished, previous label assignments
+ * will be invalidated (via callbacks having the "allocated" parameter unset)
+ * and new labels will be automatically reassigned by this labelpool module
+ * (that is, a requestor does not need to call lp_get() again if it is
+ * notified via callback that its label has been lost: it will eventually
+ * get another callback with a new label assignment).
+ *
+ * Prior requests for a given labelid are detected so that requests and
+ * assignments are not duplicated.
+ */
+void bgp_lp_get(
+       int     type,
+       void    *labelid,
+       int     (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
+{
+       struct lp_lcb *lcb;
+       int requested = 0;
+       int debug = BGP_DEBUG(labelpool, LABELPOOL);
+
+       if (debug)
+               zlog_debug("%s: labelid=%p", __func__, labelid);
+
+       /*
+        * Have we seen this request before?
+        */
+       if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
+               requested = 1;
+       } else {
+               lcb = lcb_alloc(type, labelid, cbfunc);
+               if (debug)
+                       zlog_debug("%s: inserting lcb=%p label=%u",
+                               __func__, lcb, lcb->label);
+               int rc = skiplist_insert(lp->ledger, labelid, lcb);
+
+               if (rc) {
+                       /* shouldn't happen */
+                       zlog_err("%s: can't insert new LCB into ledger list",
+                               __func__);
+                       XFREE(MTYPE_BGP_LABEL_CB, lcb);
+                       return;
+               }
+       }
+
+       if (lcb->label != MPLS_LABEL_NONE) {
+               /*
+                * Fast path: we filled the request from local pool (or
+                * this is a duplicate request that we filled already).
+                * Enqueue response work item with new label.
+                */
+               struct lp_cbq_item *q;
+
+               q = XCALLOC(MTYPE_BGP_LABEL_CBQ, sizeof(struct lp_cbq_item));
+
+               q->cbfunc = lcb->cbfunc;
+               q->type = lcb->type;
+               q->label = lcb->label;
+               q->labelid = lcb->labelid;
+               q->allocated = true;
+
+               work_queue_add(lp->callback_q, q);
+
+               return;
+       }
+
+       if (requested)
+               return;
+
+       if (debug)
+               zlog_debug("%s: slow path. lcb=%p label=%u",
+                       __func__, lcb, lcb->label);
+
+       /*
+        * Slow path: we are out of labels in the local pool,
+        * so remember the request and also get another chunk from
+        * the label manager.
+        *
+        * We track number of outstanding label requests: don't
+        * need to get a chunk for each one.
+        */
+
+       struct lp_fifo *lf = XCALLOC(MTYPE_BGP_LABEL_FIFO,
+               sizeof(struct lp_fifo));
+
+       lf->lcb = *lcb;
+       LABEL_FIFO_ADD(lp->requests, lf);
+
+       if (LABEL_FIFO_COUNT(lp->requests) > lp->pending_count) {
+               if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE)) {
+                       lp->pending_count += LP_CHUNK_SIZE;
+                       return;
+               }
+       }
+}
+
+void bgp_lp_release(
+       int             type,
+       void            *labelid,
+       mpls_label_t    label)
+{
+       struct lp_lcb *lcb;
+
+       if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
+               if (label == lcb->label && type == lcb->type) {
+                       uintptr_t lbl = label;
+
+                       /* no longer in use */
+                       skiplist_delete(lp->inuse, (void *)lbl, NULL);
+
+                       /* no longer requested */
+                       skiplist_delete(lp->ledger, labelid, NULL);
+               }
+       }
+}
+
+/*
+ * zebra response giving us a chunk of labels
+ */
+void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
+{
+       struct lp_chunk *chunk;
+       int debug = BGP_DEBUG(labelpool, LABELPOOL);
+       struct lp_fifo *lf;
+
+       if (last < first) {
+               zlog_err("%s: zebra label chunk invalid: first=%u, last=%u",
+                       __func__, first, last);
+               return;
+       }
+
+       chunk = XCALLOC(MTYPE_BGP_LABEL_CHUNK, sizeof(struct lp_chunk));
+
+       chunk->first = first;
+       chunk->last = last;
+
+       listnode_add(lp->chunks, chunk);
+
+       lp->pending_count -= (last - first + 1);
+
+       if (debug) {
+               zlog_debug("%s: %u pending requests", __func__,
+                       LABEL_FIFO_COUNT(lp->requests));
+       }
+
+       while ((lf = LABEL_FIFO_HEAD(lp->requests))) {
+
+               struct lp_lcb *lcb;
+               void *labelid = lf->lcb.labelid;
+
+               if (skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
+                       /* request no longer in effect */
+
+                       if (debug) {
+                               zlog_debug("%s: labelid %p: request no longer in effect",
+                                               __func__, labelid);
+                       }
+                       goto finishedrequest;
+               }
+
+               /* have LCB */
+               if (lcb->label != MPLS_LABEL_NONE) {
+                       /* request already has a label */
+                       if (debug) {
+                               zlog_debug("%s: labelid %p: request already has a label: %u=0x%x, lcb=%p",
+                                               __func__, labelid,
+                                               lcb->label, lcb->label, lcb);
+                       }
+                       goto finishedrequest;
+               }
+
+               lcb->label = get_label_from_pool(lcb->labelid);
+
+               if (lcb->label == MPLS_LABEL_NONE) {
+                       /*
+                        * Out of labels in local pool, await next chunk
+                        */
+                       if (debug) {
+                               zlog_debug("%s: out of labels, await more",
+                                               __func__);
+                       }
+                       break;
+               }
+
+               /*
+                * we filled the request from local pool.
+                * Enqueue response work item with new label.
+                */
+               struct lp_cbq_item *q = XCALLOC(MTYPE_BGP_LABEL_CBQ,
+                       sizeof(struct lp_cbq_item));
+
+               q->cbfunc = lcb->cbfunc;
+               q->type = lcb->type;
+               q->label = lcb->label;
+               q->labelid = lcb->labelid;
+               q->allocated = true;
+
+               if (debug)
+                       zlog_debug("%s: assigning label %u to labelid %p",
+                               __func__, q->label, q->labelid);
+
+               work_queue_add(lp->callback_q, q);
+
+finishedrequest:
+               LABEL_FIFO_DEL(lp->requests, lf);
+               XFREE(MTYPE_BGP_LABEL_FIFO, lf);
+       }
+}
+
+/*
+ * continue using allocated labels until zebra returns
+ */
+void bgp_lp_event_zebra_down(void)
+{
+       /* rats. */
+}
+
+/*
+ * Inform owners of previously-allocated labels that their labels
+ * are not valid. Request chunk from zebra large enough to satisfy
+ * previously-allocated labels plus any outstanding requests.
+ */
+void bgp_lp_event_zebra_up(void)
+{
+       int labels_needed;
+       int chunks_needed;
+       void *labelid;
+       struct lp_lcb *lcb;
+
+       /*
+        * Get label chunk allocation request dispatched to zebra
+        */
+       labels_needed = LABEL_FIFO_COUNT(lp->requests) +
+               skiplist_count(lp->inuse);
+
+       /* round up */
+       chunks_needed = (labels_needed / LP_CHUNK_SIZE) + 1;
+       labels_needed = chunks_needed * LP_CHUNK_SIZE;
+
+       zclient_send_get_label_chunk(zclient, 0, labels_needed);
+       lp->pending_count = labels_needed;
+
+       /*
+        * Invalidate current list of chunks
+        */
+       list_delete_all_node(lp->chunks);
+
+       /*
+        * Invalidate any existing labels and requeue them as requests
+        */
+       while (!skiplist_first(lp->inuse, NULL, &labelid)) {
+
+               /*
+                * Get LCB
+                */
+               if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
+
+                       if (lcb->label != MPLS_LABEL_NONE) {
+                               /*
+                                * invalidate
+                                */
+                               struct lp_cbq_item *q;
+
+                               q = XCALLOC(MTYPE_BGP_LABEL_CBQ,
+                                       sizeof(struct lp_cbq_item));
+                               q->cbfunc = lcb->cbfunc;
+                               q->type = lcb->type;
+                               q->label = lcb->label;
+                               q->labelid = lcb->labelid;
+                               q->allocated = false;
+                               work_queue_add(lp->callback_q, q);
+
+                               lcb->label = MPLS_LABEL_NONE;
+                       }
+
+                       /*
+                        * request queue
+                        */
+                       struct lp_fifo *lf = XCALLOC(MTYPE_BGP_LABEL_FIFO,
+                               sizeof(struct lp_fifo));
+
+                       lf->lcb = *lcb;
+                       LABEL_FIFO_ADD(lp->requests, lf);
+               }
+
+               skiplist_delete_first(lp->inuse);
+       }
+}
diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h
new file mode 100644 (file)
index 0000000..fa35cde
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * BGP Label Pool - Manage label chunk allocations from zebra asynchronously
+ *
+ * Copyright (C) 2018 LabN Consulting, L.L.C.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_LABELPOOL_H
+#define _FRR_BGP_LABELPOOL_H
+
+#include <zebra.h>
+
+#include "mpls.h"
+
+/*
+ * Types used in bgp_lp_get for debug tracking; add more as needed
+ */
+#define LP_TYPE_VRF    0x00000001
+
+struct labelpool {
+       struct skiplist         *ledger;        /* all requests */
+       struct skiplist         *inuse;         /* individual labels */
+       struct list             *chunks;        /* granted by zebra */
+       struct lp_fifo          *requests;      /* blocked on zebra */
+       struct work_queue       *callback_q;
+       uint32_t                pending_count;  /* requested from zebra */
+};
+
+extern void bgp_lp_init(struct thread_master *master, struct labelpool *pool);
+extern void bgp_lp_finish(void);
+extern void bgp_lp_get(int type, void *labelid,
+       int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated));
+extern void bgp_lp_release(int type, void *labelid, mpls_label_t label);
+extern void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last);
+extern void bgp_lp_event_zebra_down(void);
+extern void bgp_lp_event_zebra_up(void);
+
+#endif /* _FRR_BGP_LABELPOOL_H */
index e33f3d34779933eb28a0d08dbe12edcdd77805f5..915387ca2defc86c42030743f8686fcb9c847fd7 100644 (file)
@@ -592,6 +592,8 @@ void bgp_info_mpath_update(struct bgp_node *rn, struct bgp_info *new_best,
                         */
                        new_mpath = listgetdata(mp_node);
                        list_delete_node(mp_list, mp_node);
+                       assert(new_mpath);
+                       assert(prev_mpath);
                        if ((mpath_count < maxpaths) && (new_mpath != new_best)
                            && bgp_info_nexthop_cmp(prev_mpath, new_mpath)) {
                                if (new_mpath == next_mpath)
index 13a283a058c33ef514debd577d75c50ebe633054..08aaed6577438899f461c7ef2952b99601a97d5e 100644 (file)
@@ -310,6 +310,65 @@ void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
        bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
 }
 
+int vpn_leak_label_callback(
+       mpls_label_t label,
+       void *labelid,
+       bool allocated)
+{
+       struct vpn_policy *vp = (struct vpn_policy *)labelid;
+       int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+
+       if (debug)
+               zlog_debug("%s: label=%u, allocated=%d",
+                       __func__, label, allocated);
+
+       if (!allocated) {
+               /*
+                * previously-allocated label is now invalid
+                */
+               if (CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
+                       (vp->tovpn_label != MPLS_LABEL_NONE)) {
+
+                       vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
+                               vp->afi, bgp_get_default(), vp->bgp);
+                       vp->tovpn_label = MPLS_LABEL_NONE;
+                       vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
+                               vp->afi, bgp_get_default(), vp->bgp);
+               }
+               return 0;
+       }
+
+       /*
+        * New label allocation
+        */
+       if (!CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
+
+               /*
+                * not currently configured for auto label, reject allocation
+                */
+               return -1;
+       }
+
+       if (vp->tovpn_label != MPLS_LABEL_NONE) {
+               if (label == vp->tovpn_label) {
+                       /* already have same label, accept but do nothing */
+                       return 0;
+               }
+               /* Shouldn't happen: different label allocation */
+               zlog_err("%s: %s had label %u but got new assignment %u",
+                       __func__, vp->bgp->name_pretty, vp->tovpn_label, label);
+               /* use new one */
+       }
+
+       vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
+               vp->afi, bgp_get_default(), vp->bgp);
+       vp->tovpn_label = label;
+       vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
+               vp->afi, bgp_get_default(), vp->bgp);
+
+       return 0;
+}
+
 static int ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
 {
        int i;
@@ -331,6 +390,57 @@ static int ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
        return 0;
 }
 
+static bool labels_same(struct bgp_info *bi, mpls_label_t *label, uint32_t n)
+{
+       uint32_t i;
+
+       if (!bi->extra) {
+               if (!n)
+                       return true;
+               else
+                       return false;
+       }
+
+       if (n != bi->extra->num_labels)
+               return false;
+
+       for (i = 0; i < n; ++i) {
+               if (label[i] != bi->extra->label[i])
+                       return false;
+       }
+       return true;
+}
+
+/*
+ * make encoded route labels match specified encoded label set
+ */
+static void setlabels(
+       struct bgp_info *bi,
+       mpls_label_t *label,            /* array of labels */
+       uint32_t num_labels)
+{
+       if (num_labels)
+               assert(label);
+       assert(num_labels <= BGP_MAX_LABELS);
+
+       if (!num_labels) {
+               if (bi->extra)
+                       bi->extra->num_labels = 0;
+               return;
+       }
+
+       struct bgp_info_extra *extra = bgp_info_extra_get(bi);
+       uint32_t i;
+
+       for (i = 0; i < num_labels; ++i) {
+               extra->label[i] = label[i];
+               if (!bgp_is_valid_label(&label[i])) {
+                       bgp_set_valid_label(&extra->label[i]);
+               }
+       }
+       extra->num_labels = num_labels;
+}
+
 /*
  * returns pointer to new bgp_info upon success
  */
@@ -343,7 +453,7 @@ leak_update(
        safi_t          safi,
        struct bgp_info *source_bi,
        mpls_label_t    *label,
-       int             num_labels,
+       uint32_t        num_labels,
        void            *parent,
        struct bgp      *bgp_orig,
        struct prefix   *nexthop_orig,
@@ -371,7 +481,10 @@ leak_update(
        }
 
        if (bi) {
+               bool labelssame = labels_same(bi, label, num_labels);
+
                if (attrhash_cmp(bi->attr, new_attr)
+                   && labelssame
                    && !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) {
 
                        bgp_attr_unintern(&new_attr);
@@ -395,6 +508,12 @@ leak_update(
                bi->attr = new_attr;
                bi->uptime = bgp_clock();
 
+               /*
+                * rewrite labels
+                */
+               if (!labelssame)
+                       setlabels(bi, label, num_labels);
+
                if (nexthop_self_flag)
                        bgp_info_set_flag(bn, bi, BGP_INFO_ANNC_NH_SELF);
 
@@ -442,23 +561,10 @@ leak_update(
        if (nexthop_self_flag)
                bgp_info_set_flag(bn, new, BGP_INFO_ANNC_NH_SELF);
 
+       if (num_labels)
+               setlabels(new, label, num_labels);
+
        bgp_info_extra_get(new);
-       if (label) {
-               int i;
-
-               for (i = 0; i < num_labels; ++i) {
-                       new->extra->label[i] = label[i];
-                       if (!bgp_is_valid_label(&label[i])) {
-                               if (debug) {
-                                       zlog_debug(
-                                               "%s: %s: marking label %d valid",
-                                               __func__, buf_prefix, i);
-                               }
-                               bgp_set_valid_label(&new->extra->label[i]);
-                       }
-               }
-               new->extra->num_labels = num_labels;
-       }
        new->extra->parent = parent;
 
        if (bgp_orig)
@@ -889,8 +995,10 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf,       /* to */
        const char *debugmsg;
        struct prefix nexthop_orig;
        mpls_label_t *pLabels = NULL;
-       int num_labels = 0;
+       uint32_t num_labels = 0;
        int nexthop_self_flag = 1;
+       struct bgp_info *bi_ultimate = NULL;
+       int origin_local = 0;
 
        int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
 
@@ -982,13 +1090,40 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf,       /* to */
 
        /*
         * ensure labels are copied
+        *
+        * However, there is a special case: if the route originated in
+        * another local VRF (as opposed to arriving via VPN), then the
+        * nexthop is reached by hairpinning through this router (me)
+        * using IP forwarding only (no LSP). Therefore, the route
+        * imported to the VRF should not have labels attached. Note
+        * that nexthop tracking is also involved: eliminating the
+        * labels for these routes enables the non-labeled nexthops
+        * from the originating VRF to be considered valid for this route.
         */
-       if (info_vpn->extra && info_vpn->extra->num_labels) {
+
+       /* work back to original route */
+       for (bi_ultimate = info_vpn;
+               bi_ultimate->extra && bi_ultimate->extra->parent;
+               bi_ultimate = bi_ultimate->extra->parent)
+               ;
+
+       /* if original route was unicast, then it did not arrive over vpn */
+       if (bi_ultimate->net) {
+               struct bgp_table *table;
+
+               table = bgp_node_table(bi_ultimate->net);
+               if (table && (table->safi == SAFI_UNICAST))
+                       origin_local = 1;
+       }
+
+       /* copy labels */
+       if (!origin_local && info_vpn->extra && info_vpn->extra->num_labels) {
                num_labels = info_vpn->extra->num_labels;
                if (num_labels > BGP_MAX_LABELS)
                        num_labels = BGP_MAX_LABELS;
                pLabels = info_vpn->extra->label;
        }
+
        if (debug) {
                char buf_prefix[PREFIX_STRLEN];
                prefix2str(p, buf_prefix, sizeof(buf_prefix));
index 64303325ee01a6cad5531812bd4ce5931db9ef4b..739855949830f71451c380a6786abbfcbfa6d5d2 100644 (file)
@@ -77,6 +77,7 @@ extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
 
 extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
 extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi);
+extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
 
 static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
                                         const char **pmsg)
@@ -111,6 +112,17 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
                        *pmsg = "rd not defined";
                return 0;
        }
+
+       /* Is there an "auto" export label that isn't allocated yet? */
+       if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+               BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
+               (bgp_vrf->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)) {
+
+               if (pmsg)
+                       *pmsg = "auto label not allocated";
+               return 0;
+       }
+
        return 1;
 }
 
index f0b30f018603e68721ebfccc0a61a08786c2f829..9ea2f22cec15c9ea0285abc54b7e79f218576963 100644 (file)
@@ -649,7 +649,6 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
                               uint8_t sub_code, uint8_t *data, size_t datalen)
 {
        struct stream *s;
-       int length;
 
        /* Lock I/O mutex to prevent other threads from pushing packets */
        pthread_mutex_lock(&peer->io_mtx);
@@ -670,7 +669,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
                stream_write(s, data, datalen);
 
        /* Set BGP packet length. */
-       length = bgp_packet_set_size(s);
+       bgp_packet_set_size(s);
 
        /* wipe output buffer */
        stream_fifo_clean(peer->obuf);
@@ -697,13 +696,13 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
                bgp_notify.code = code;
                bgp_notify.subcode = sub_code;
                bgp_notify.data = NULL;
-               bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE;
+               bgp_notify.length = datalen;
                bgp_notify.raw_data = data;
 
                peer->notify.code = bgp_notify.code;
                peer->notify.subcode = bgp_notify.subcode;
 
-               if (bgp_notify.length) {
+               if (bgp_notify.length && data) {
                        bgp_notify.data =
                                XMALLOC(MTYPE_TMP, bgp_notify.length * 3);
                        for (i = 0; i < bgp_notify.length; i++)
index 944ae5b5dc7a1a7b237740127242e7d72962ec7f..a71f5ac95659e9be650c53a307458d305b8c304a 100644 (file)
@@ -1874,7 +1874,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
                        if (debug) {
                                bgp_info_path_with_addpath_rx_str(new_select,
                                                                  path_buf);
-                               zlog_debug("%s: %s is the bestpath from AS %d",
+                               zlog_debug("%s: %s is the bestpath from AS %u",
                                           pfx_buf, path_buf,
                                           aspath_get_first_as(
                                                   new_select->attr->aspath));
@@ -6545,8 +6545,20 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                } else
                        vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
        } else if (safi == SAFI_FLOWSPEC) {
-               /* already done */
-       /* IPv4 Next Hop */
+               if (attr->nexthop.s_addr != 0) {
+                       if (json_paths) {
+                               json_nexthop_global = json_object_new_object();
+                               json_object_string_add(
+                                              json_nexthop_global, "ip",
+                                              inet_ntoa(attr->nexthop));
+                               json_object_string_add(json_nexthop_global,
+                                                      "afi", "ipv4");
+                               json_object_boolean_true_add(json_nexthop_global,
+                                                            "used");
+                       } else {
+                               vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
+                       }
+               }
        } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
                if (json_paths) {
                        json_nexthop_global = json_object_new_object();
@@ -7035,32 +7047,36 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p,
                default:
                        vty_out(vty, "?");
                }
+
+               char *str = esi2str(&(attr->evpn_overlay.eth_s_id));
+
+               vty_out(vty, "%s", str);
+               XFREE(MTYPE_TMP, str);
+
+               if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) {
+                       vty_out(vty, "/%s",
+                               inet_ntoa(attr->evpn_overlay.gw_ip.ipv4));
+               } else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) {
+                       vty_out(vty, "/%s",
+                               inet_ntop(AF_INET6,
+                                         &(attr->evpn_overlay.gw_ip.ipv6), buf,
+                                         BUFSIZ));
+               }
+               if (attr->ecommunity) {
+                       char *mac = NULL;
+                       struct ecommunity_val *routermac = ecommunity_lookup(
+                               attr->ecommunity, ECOMMUNITY_ENCODE_EVPN,
+                               ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
+                       if (routermac)
+                               mac = ecom_mac2str((char *)routermac->val);
+                       if (mac) {
+                               vty_out(vty, "/%s", (char *)mac);
+                               XFREE(MTYPE_TMP, mac);
+                       }
+               }
+               vty_out(vty, "\n");
        }
 
-       struct eth_segment_id *id = &(attr->evpn_overlay.eth_s_id);
-       char *str = esi2str(id);
-       vty_out(vty, "%s", str);
-       XFREE(MTYPE_TMP, str);
-       if (IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)) {
-               vty_out(vty, "/%s", inet_ntoa(attr->evpn_overlay.gw_ip.ipv4));
-       } else if (IS_EVPN_PREFIX_IPADDR_V6((struct prefix_evpn *)p)) {
-               vty_out(vty, "/%s",
-                       inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6),
-                                 buf, BUFSIZ));
-       }
-       if (attr->ecommunity) {
-               char *mac = NULL;
-               struct ecommunity_val *routermac = ecommunity_lookup(
-                       attr->ecommunity, ECOMMUNITY_ENCODE_EVPN,
-                       ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
-               if (routermac)
-                       mac = ecom_mac2str((char *)routermac->val);
-               if (mac) {
-                       vty_out(vty, "/%s", (char *)mac);
-                       XFREE(MTYPE_TMP, mac);
-               }
-       }
-       vty_out(vty, "\n");
 }
 
 /* dampening route */
index 3e577317ad399efa52798fb66ab2b12b1789894e..6bc50fb77e7a667f66b3bfba72c96d9001833282 100644 (file)
@@ -6245,12 +6245,13 @@ ALIAS (af_rd_vpn_export,
 
 DEFPY (af_label_vpn_export,
        af_label_vpn_export_cmd,
-       "[no] label vpn export (0-1048575)$label_val",
+       "[no] label vpn export <(0-1048575)$label_val|auto$label_auto>",
        NO_STR
        "label value for VRF\n"
        "Between current address-family and vpn\n"
        "For routes leaked from current address-family to vpn\n"
-       "Label Value <0-1048575>\n")
+       "Label Value <0-1048575>\n"
+       "Automatically assign a label\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        mpls_label_t label = MPLS_LABEL_NONE;
@@ -6263,8 +6264,10 @@ DEFPY (af_label_vpn_export,
        if (argv_find(argv, argc, "no", &idx))
                yes = 0;
 
-       if (yes)
-               label = label_val; /* rely on parser to force unsigned */
+       if (yes) {
+               if (!label_auto)
+                       label = label_val; /* parser should force unsigned */
+       }
 
        ret = vpn_policy_getafi(vty, doafi);
        if (ret != CMD_SUCCESS)
@@ -6274,13 +6277,48 @@ DEFPY (af_label_vpn_export,
                if (!doafi[afi])
                        continue;
 
+               if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
+                       BGP_VPN_POLICY_TOVPN_LABEL_AUTO))
+
+                       continue; /* no change */
+
                /*
                 * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
                 */
                vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
                                   bgp_get_default(), bgp);
 
+               if (!label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
+                       BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
+
+                       if (bgp->vpn_policy[afi].tovpn_label !=
+                               MPLS_LABEL_NONE) {
+
+                               /*
+                                * label has previously been automatically
+                                * assigned by labelpool: release it
+                                *
+                                * NB if tovpn_label == MPLS_LABEL_NONE it
+                                * means the automatic assignment is in flight
+                                * and therefore the labelpool callback must
+                                * detect that the auto label is not needed.
+                                */
+
+                               bgp_lp_release(LP_TYPE_VRF,
+                                       &bgp->vpn_policy[afi],
+                                       bgp->vpn_policy[afi].tovpn_label);
+                       }
+                       UNSET_FLAG(bgp->vpn_policy[afi].flags,
+                               BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
+               }
+
                bgp->vpn_policy[afi].tovpn_label = label;
+               if (label_auto) {
+                       SET_FLAG(bgp->vpn_policy[afi].flags,
+                               BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
+                       bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi],
+                               vpn_leak_label_callback);
+               }
 
                /* post-change: re-export vpn routes */
                vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
@@ -11706,9 +11744,16 @@ void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
 {
        int indent = 2;
 
-       if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
-               vty_out(vty, "%*slabel vpn export %u\n", indent, "",
-                       bgp->vpn_policy[afi].tovpn_label);
+       if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
+               BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
+
+               vty_out(vty, "%*slabel vpn export %s\n", indent, "", "auto");
+
+       } else {
+               if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
+                       vty_out(vty, "%*slabel vpn export %u\n", indent, "",
+                               bgp->vpn_policy[afi].tovpn_label);
+               }
        }
        if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
                       BGP_VPN_POLICY_TOVPN_RD_SET)) {
@@ -13161,8 +13206,6 @@ DEFUN (no_ip_community_list_standard_all,
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
 {
-       int delete_all = 0;
-
        char *cl_name_or_number = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_STANDARD;
@@ -13177,7 +13220,7 @@ DEFUN (no_ip_community_list_standard_all,
        char *str = argv_concat(argv, argc, idx);
 
        int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
-                                      direct, style, delete_all);
+                                      direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -13242,8 +13285,6 @@ DEFUN (no_ip_community_list_expanded_all,
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
 {
-       int delete_all = 0;
-
        char *cl_name_or_number = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_EXPANDED;
@@ -13258,7 +13299,7 @@ DEFUN (no_ip_community_list_expanded_all,
        char *str = argv_concat(argv, argc, idx);
 
        int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
-                                      direct, style, delete_all);
+                                      direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -13795,8 +13836,6 @@ DEFUN (no_ip_extcommunity_list_standard_all,
        "Specify community to accept\n"
        EXTCOMMUNITY_VAL_STR)
 {
-       int deleteall = 0;
-
        int style = EXTCOMMUNITY_LIST_STANDARD;
        int direct = 0;
        char *cl_number_or_name = NULL;
@@ -13811,7 +13850,7 @@ DEFUN (no_ip_extcommunity_list_standard_all,
        char *str = argv_concat(argv, argc, idx);
 
        int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
-                                         direct, style, deleteall);
+                                         direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -13836,8 +13875,6 @@ DEFUN (no_ip_extcommunity_list_expanded_all,
        "Specify community to accept\n"
        "An ordered list as a regular-expression\n")
 {
-       int deleteall = 0;
-
        int style = EXTCOMMUNITY_LIST_EXPANDED;
        int direct = 0;
        char *cl_number_or_name = NULL;
@@ -13852,7 +13889,7 @@ DEFUN (no_ip_extcommunity_list_expanded_all,
        char *str = argv_concat(argv, argc, idx);
 
        int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
-                                         direct, style, deleteall);
+                                         direct, style);
 
        XFREE(MTYPE_TMP, str);
 
index 023a86631558ac129de1ab33bad5e8636644b285..b564fccf436bf014e42f9507e63913dff36f7f81 100644 (file)
@@ -55,6 +55,7 @@
 #endif
 #include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_labelpool.h"
 
 /* All information about zebra. */
 struct zclient *zclient = NULL;
@@ -1876,6 +1877,9 @@ static void bgp_zebra_connected(struct zclient *zclient)
        /* Send the client registration */
        bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
 
+       /* tell label pool that zebra is connected */
+       bgp_lp_event_zebra_up();
+
        /* TODO - What if we have peers and networks configured, do we have to
         * kick-start them?
         */
@@ -2042,6 +2046,41 @@ static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient,
        }
 }
 
+static void bgp_zebra_process_label_chunk(
+       int cmd,
+       struct zclient *zclient,
+       zebra_size_t length,
+       vrf_id_t vrf_id)
+{
+       struct stream *s = NULL;
+       uint8_t response_keep;
+       uint32_t first;
+       uint32_t last;
+
+       s = zclient->ibuf;
+       STREAM_GETC(s, response_keep);
+       STREAM_GETL(s, first);
+       STREAM_GETL(s, last);
+
+       if (first > last ||
+               first < MPLS_LABEL_UNRESERVED_MIN ||
+               last > MPLS_LABEL_UNRESERVED_MAX) {
+
+               zlog_err("%s: Invalid Label chunk: %u - %u",
+                       __func__, first, last);
+               return;
+       }
+       if (BGP_DEBUG(zebra, ZEBRA)) {
+               zlog_debug("Label Chunk assign: %u - %u (%u) ",
+                       first, last, response_keep);
+       }
+
+       bgp_lp_event_chunk(response_keep, first, last);
+
+stream_failure:                /* for STREAM_GETX */
+       return;
+}
+
 extern struct zebra_privs_t bgpd_privs;
 
 void bgp_zebra_init(struct thread_master *master)
@@ -2076,6 +2115,7 @@ void bgp_zebra_init(struct thread_master *master)
        zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
        zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
        zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
+       zclient->label_chunk = bgp_zebra_process_label_chunk;
 }
 
 void bgp_zebra_destroy(void)
index c46111e1fb325eb6c1847ad3446f752aed5a2aa6..df0f1bd19cb5fecd3d3e79117eb0c66645926ac6 100644 (file)
@@ -81,7 +81,7 @@
 #include "bgpd/bgp_io.h"
 #include "bgpd/bgp_ecommunity.h"
 #include "bgpd/bgp_flowspec.h"
-
+#include "bgpd/bgp_labelpool.h"
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
 DEFINE_QOBJ_TYPE(bgp_master)
@@ -2951,6 +2951,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
 #endif /* ENABLE_BGP_VNC */
 
        for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               bgp->vpn_policy[afi].bgp = bgp;
+               bgp->vpn_policy[afi].afi = afi;
                bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
                bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent =
                        MPLS_LABEL_NONE;
@@ -7536,6 +7538,9 @@ void bgp_master_init(struct thread_master *master)
        /* Enable multiple instances by default. */
        bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
 
+       /* mpls label dynamic allocation pool */
+       bgp_lp_init(bm->master, &bm->labelpool);
+
        QOBJ_REG(bm, bgp_master);
 }
 
@@ -7714,4 +7719,6 @@ void bgp_terminate(void)
 
        if (bm->t_rmap_update)
                BGP_TIMER_OFF(bm->t_rmap_update);
+
+       bgp_lp_finish();
 }
index 0c5f72662cf4ce7307df94781ceeccb17d547611..680bac0214b576e672ec1e329d0b604c95727192 100644 (file)
@@ -37,6 +37,7 @@
 #include "bgp_memory.h"
 #include "bitfield.h"
 #include "vxlan.h"
+#include "bgp_labelpool.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
 #define BGP_PEER_MAX_HASH_SIZE 16384
@@ -140,6 +141,9 @@ struct bgp_master {
        /* Id space for automatic RD derivation for an EVI/VRF */
        bitfield_t rd_idspace;
 
+       /* dynamic mpls label allocation pool */
+       struct labelpool labelpool;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp_master)
@@ -167,6 +171,25 @@ typedef enum {
        BGP_VPN_POLICY_DIR_MAX = 2
 } vpn_policy_direction_t;
 
+struct vpn_policy {
+       struct bgp *bgp; /* parent */
+       afi_t afi;
+       struct ecommunity *rtlist[BGP_VPN_POLICY_DIR_MAX];
+       struct ecommunity *import_redirect_rtlist;
+       char *rmap_name[BGP_VPN_POLICY_DIR_MAX];
+       struct route_map *rmap[BGP_VPN_POLICY_DIR_MAX];
+
+       /* should be mpls_label_t? */
+       uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
+       uint32_t tovpn_zebra_vrf_label_last_sent;
+       struct prefix_rd tovpn_rd;
+       struct prefix tovpn_nexthop; /* unset => set to 0 */
+       uint32_t flags;
+#define BGP_VPN_POLICY_TOVPN_LABEL_AUTO        (1 << 0)
+#define BGP_VPN_POLICY_TOVPN_RD_SET            (1 << 1)
+#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET       (1 << 2)
+};
+
 /*
  * Type of 'struct bgp'.
  * - Default: The default instance
@@ -465,22 +488,7 @@ struct bgp {
        /* route map for advertise ipv4/ipv6 unicast (type-5 routes) */
        struct bgp_rmap adv_cmd_rmap[AFI_MAX][SAFI_MAX];
 
-       /* vpn-policy */
-       struct {
-               struct ecommunity *rtlist[BGP_VPN_POLICY_DIR_MAX];
-               struct ecommunity *import_redirect_rtlist;
-               char *rmap_name[BGP_VPN_POLICY_DIR_MAX];
-               struct route_map *rmap[BGP_VPN_POLICY_DIR_MAX];
-
-               /* should be mpls_label_t? */
-               uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
-               uint32_t tovpn_zebra_vrf_label_last_sent;
-               struct prefix_rd tovpn_rd;
-               struct prefix tovpn_nexthop; /* unset => set to 0 */
-               uint32_t flags;
-#define BGP_VPN_POLICY_TOVPN_RD_SET            0x00000004
-#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET       0x00000008
-       } vpn_policy[AFI_MAX];
+       struct vpn_policy vpn_policy[AFI_MAX];
 
        QOBJ_FIELDS
 };
index 8c4d5ab04363b44b4ae403d8831a65e1c7846470..3e9722d92047e402e4cecbb1870b99a3d5dd0ac0 100644 (file)
@@ -548,13 +548,12 @@ rfapi_group_new(struct bgp *bgp, rfapi_group_cfg_type_t type, const char *name)
 
        rfg = XCALLOC(MTYPE_RFAPI_GROUP_CFG,
                      sizeof(struct rfapi_nve_group_cfg));
-       if (rfg) {
-               rfg->type = type;
-               rfg->name = strdup(name);
-               /* add to tail of list */
-               listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg);
-       }
+       rfg->type = type;
+       rfg->name = strdup(name);
+       /* add to tail of list */
+       listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg);
        rfg->label = MPLS_LABEL_NONE;
+
        QOBJ_REG(rfg, rfapi_nve_group_cfg);
 
        return rfg;
index d5208f69666dfa110b3504a4b96d52939b2e820d..c1af269d3fc7ee15e9c2de2f4bb1e72daac05ae4 100644 (file)
@@ -1543,10 +1543,15 @@ static int rfapiNhlAddNodeRoutes(
        int count = 0;
        int is_l2 = (rn->p.family == AF_ETHERNET);
 
-       if (rfapiRibFTDFilterRecentPrefix(
-                   (struct rfapi_descriptor *)(rfd_rib_node->table->info), rn,
-                   pfx_target_original)) {
-               return 0;
+       if (rfd_rib_node && rfd_rib_node->table && rfd_rib_node->table->info) {
+               struct rfapi_descriptor *rfd;
+
+               rfd = (struct rfapi_descriptor *)(rfd_rib_node->table->info);
+
+               if (rfapiRibFTDFilterRecentPrefix(
+                       rfd, rn, pfx_target_original))
+
+                       return 0;
        }
 
        seen_nexthops =
@@ -2797,19 +2802,16 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
        uint32_t lifetime;
        struct rfapi_withdraw *wcb;
 
-       if
-               CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)
-               {
-                       /*
-                        * Already on the path to being withdrawn,
-                        * should already have a timer set up to
-                        * delete it.
-                        */
-                       vnc_zlog_debug_verbose(
-                               "%s: already being withdrawn, do nothing",
-                               __func__);
-                       return;
-               }
+       if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) {
+               /*
+                * Already on the path to being withdrawn,
+                * should already have a timer set up to
+                * delete it.
+                */
+               vnc_zlog_debug_verbose(
+                       "%s: already being withdrawn, do nothing", __func__);
+               return;
+       }
 
        rfapiGetVncLifetime(bi->attr, &lifetime);
        vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime);
index a6e693c0c91090091bea8fd5f672e59dbfdceadd..dec6b53e0fe5624eb84ed8af0ef5dc853f99659c 100644 (file)
@@ -264,4 +264,5 @@ EXTRA_DIST = frr-sphinx.mk \
        figures/ospf_api_architecture.png \
        figures/ospf_api_msghdr.png \
        figures/ospf_api_msgs1.png \
-       figures/ospf_api_msgs2.png
+       figures/ospf_api_msgs2.png \
+       extra/frrlexer.py
index 1e0de66c55864032738587d0cbd8b8f5a535e477..0d871c961a898405fd9d11f1a6cdd8d713869cce 100644 (file)
@@ -2,3 +2,7 @@
 div.body {
     max-width: none;
 }
+
+pre {
+    background-color: #e2e2e2;
+}
index f0f2aee138be256279db7d71cf1ccbd7124d3498..d303784d4e50fde1e19db1f211a6d409cf7ef305 100644 (file)
@@ -10,6 +10,28 @@ Depending on your host, there are different ways of installing docker.  Refer
 to the documentation here for instructions on how to install a free version of
 docker: https://www.docker.com/community-edition
 
+Pre-built packages and docker images
+------------------------------------
+
+The master branch of https://github.com/frrouting/frr.git has a
+continuous delivery of docker images to docker hub at:
+https://hub.docker.com/r/ajones17/frr/. These images have the frr packages
+in /pkgs/apk and have the frr package pre-installed.  To copy Alpine
+packages out of these images:
+
+::
+
+   id=`docker create ajones17/frr:latest`
+   docker cp ${id}:/pkgs _some_directory_
+   docker rm $id
+
+To run the frr daemons (see below for how to configure them):
+
+::
+
+   docker run -it --rm --name frr ajones17/frr:latest
+   docker exec -it frr /bin/sh
+
 Work with sources
 -----------------
 
@@ -52,13 +74,32 @@ And to run the image:
 
 ::
 
-   docker run -it --rm frr:latest /bin/sh
+   docker run -it --rm --name frr frr:latest
+
+In the default configuration, none of the frr daemons will  be running.
+To configure the daemons, exec into the container and edit the configuration
+files or mount a volume with configuration files into the container on
+startup.  To configure by hand:
+
+::
+
+   docker exec -it frr /bin/sh
+   vi /etc/frr/daemons
+   vi /etc/frr/daemons.conf
+   cp /etc/frr/zebra.conf.sample /etc/frr/zebra.conf
+   vi /etc/frr/zebra.conf
+   /etc/init.d/frr start
+
+Or, to configure the daemons using /etc/frr from a host volume, put the
+config files in, say, ./docker/etc and bind mount that into the
+container:
+
+::
 
-Currently, we only package the raw daemons and example files, so, you'll
-need to run the daemons by hand (or, better, orchestrate in the Dockerfile).
+   docker run -it --rm -v `pwd`/docker/etc:/etc/frr frr:latest
 
-We can also build directly from docker-compose, with a docker-compose.yml file
-like this one:
+We can also build the base image directly from docker-compose, with a
+docker-compose.yml file like this one:
 
 ::
 
index 1c53ea6ba334bcc39da708ec26eafd0031d0e39b..d50376548fb566d849c5d4c1ed31725a9e9f200e 100644 (file)
@@ -125,7 +125,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -135,7 +135,7 @@ Add frr groups and user
       -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.)
@@ -176,7 +176,7 @@ an example.)
     sudo make SPHINXBUILD=sphinx-build2.7 install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -198,7 +198,7 @@ Create empty FRR configuration files
     sudo chmod 640 /etc/frr/*.conf
 
 Install daemon config file
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -206,13 +206,13 @@ Install daemon config file
     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
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Edit ``/etc/sysctl.conf`` and set the following values (ignore the other
 settings)
@@ -233,7 +233,7 @@ Load the modifed sysctl's on the system:
     sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
 
 Add init.d startup files
-~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -241,14 +241,14 @@ Add init.d startup files
     sudo chkconfig --add frr
 
 Enable frr daemon at startup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
     sudo chkconfig frr on
 
 Start FRR manually (or reboot)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
index 9807543e170fe3d8d19824ca0c33fc4604294d83..31cd4dcc49ed8a67c62d87af2ee0dcaf935f5b5a 100644 (file)
@@ -31,7 +31,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -41,7 +41,7 @@ Add frr groups and user
       -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.)
@@ -83,7 +83,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -106,7 +106,7 @@ Create empty FRR configuration files
     sudo chmod 640 /etc/frr/*.conf
 
 Install daemon config file
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -114,13 +114,13 @@ Install daemon config file
     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
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
 following content:
@@ -140,7 +140,7 @@ Load the modifed sysctl's on the system:
     sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
 
 Install frr Service and redhat init files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -148,21 +148,21 @@ Install frr Service and redhat init files
     sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
 
 Register the systemd files
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
     sudo systemctl preset frr.service
 
 Enable required frr at startup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
     sudo systemctl enable frr
 
 Reboot or start FRR manually
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
index 36ed0c4e6621f57452a1f654439498e0293d1b03..d1e65a472d9811bb0849a8b1ed1f97fd38156b2e 100644 (file)
@@ -32,7 +32,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -43,7 +43,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -80,7 +80,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -99,7 +99,7 @@ Create empty FRR configuration files
     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)
@@ -118,7 +118,7 @@ other settings)
 system
 
 Troubleshooting
-~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^
 
 **Local state directory**
 
index a1aa63236cd7e4b4c6071917a38fab4911498187..7dad9a7bd441de586df3e0fa3ac8d043519eb2e3 100644 (file)
@@ -19,7 +19,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -30,7 +30,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -68,7 +68,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -88,7 +88,7 @@ Create empty FRR configuration files
     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)
@@ -110,7 +110,7 @@ Troubleshooting
 ---------------
 
 Shared library error
-~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^
 
 If you try and start any of the frrouting daemons you may see the below
 error due to the frrouting shared library directory not being found:
index ed81d3f59c40802cd15c7426f2c2f1af22cdbac0..208c580b63dea4192e94c4c2a83b6d718f9f8986 100644 (file)
@@ -24,7 +24,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -34,7 +34,7 @@ Add frr groups and user
       -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.)
@@ -75,7 +75,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -99,7 +99,7 @@ Create empty FRR configuration files
     sudo chmod 640 /etc/frr/*.conf
 
 Install daemon config file
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -107,13 +107,13 @@ Install daemon config file
     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
@@ -155,7 +155,7 @@ And load the kernel modules on the running system:
     sudo modprobe mpls-router mpls-iptunnel
 
 Install frr Service and redhat init files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -163,14 +163,14 @@ Install frr Service and redhat init files
     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
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
index ccbe8c55c331e5e013af2f72008b6e1936215697..5d14db5fa74162e985a95b4becedf712b3ec1ced 100644 (file)
@@ -34,7 +34,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr group and user
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -76,7 +76,7 @@ an example)
     sudo gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -95,7 +95,7 @@ Create empty FRR configuration files
     sudo chmod 640 /usr/local/etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/sysctl.conf``:
 
index 214fdbf9c8464c2effcae3669a4f78192cd1232c..87fb30226db43b2ae97f4cd2f9e91c848f28ab4d 100644 (file)
@@ -34,7 +34,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr group and user
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -76,7 +76,7 @@ an example)
     sudo gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -95,7 +95,7 @@ Create empty FRR configuration files
     sudo chmod 640 /usr/local/etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/sysctl.conf``:
 
index 909b3a8d64562509eddb5992629ed27113bbc484..02279debea8ae3724b92a983a583316374cee3c7 100644 (file)
@@ -47,7 +47,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr group and user
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -89,7 +89,7 @@ an example)
     sudo gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -108,7 +108,7 @@ Create empty FRR configuration files
     sudo chmod 640 /usr/local/etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/sysctl.conf``:
 
index b9ee9c51e139ac7b68fdebab92f3b617672bb7e4..d14754b37fcd11f7517f195a1a2c2e1b6f8258ba 100644 (file)
@@ -98,11 +98,11 @@ DAEMONS= or don't install unneded packages For example: zebra bgpd ldpd
 isisd nhrpd ospfd ospf6d pimd ripd ripngd
 
 Enable the serivce
-~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^
 
 -  service frr enable
 
 Start the service
-~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^
 
 -  service frr start
index ce5c58045f10a98a217fa58fba6ce553a7fab4b9..ca0845d0d096bd1c795b25f093574fe2c6799b1f 100644 (file)
@@ -44,7 +44,7 @@ Get FRR, compile it and install it (from Git)
 ---------------------------------------------
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -54,7 +54,7 @@ Add frr groups and user
         -d /nonexistent -s /sbin/nologin frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example)
@@ -89,7 +89,7 @@ an example)
     sudo gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -109,7 +109,7 @@ Create empty FRR configuration files
     sudo chmod 640 /usr/pkg/etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/sysctl.conf``:
 
@@ -123,7 +123,7 @@ Add the following lines to the end of ``/etc/sysctl.conf``:
 system
 
 Install rc.d init files
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -131,7 +131,7 @@ Install rc.d init files
     chmod 555 /etc/rc.d/*.sh
 
 Enable FRR processes
-~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^
 
 (Enable the required processes only)
 
index eaaf87fd1909e26decaebe64b97afbe9f415e984..86242ef965a2e481ebc13b950f24d48c83c518f0 100644 (file)
@@ -35,7 +35,7 @@ Get FRR, compile it and install it (from Git)
 ---------------------------------------------
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -45,7 +45,7 @@ Add frr groups and user
         -d /nonexistent -s /sbin/nologin frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example)
@@ -80,7 +80,7 @@ an example)
     sudo gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -99,7 +99,7 @@ Create empty FRR configuration files
     sudo chmod 640 /usr/pkg/etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/sysctl.conf``:
 
@@ -113,7 +113,7 @@ Add the following lines to the end of ``/etc/sysctl.conf``:
 system
 
 Install rc.d init files
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -121,7 +121,7 @@ Install rc.d init files
     chmod 555 /etc/rc.d/*.sh
 
 Enable FRR processes
-~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^
 
 (Enable the required processes only)
 
index 0eb2b9fec8f865e797e24cb6f796e3236f04efd6..03f3845de8261c0c5997d5782ccb25bae44560bb 100644 (file)
@@ -9,7 +9,7 @@ OmniOS restrictions:
    use without MPLS
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -93,7 +93,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr group and user
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -138,7 +138,7 @@ an example)
     sudo gmake install
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
index 895048886e8f50ec334e2019b9bc6ed2f97d438b..1f3aec8d92064f61496244c7d93548e217d10e87 100644 (file)
@@ -30,7 +30,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr group and user
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -40,7 +40,7 @@ Add frr group and user
         -d /nonexistent -s /sbin/nologin _frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example)
@@ -75,7 +75,7 @@ an example)
     doas gmake install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -100,7 +100,7 @@ Create empty FRR configuration files
     doas chmod 640 /etc/frr/*.conf
 
 Enable IP & IPv6 forwarding
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to the end of ``/etc/rc.conf``:
 
@@ -113,7 +113,7 @@ Add the following lines to the end of ``/etc/rc.conf``:
 **Reboot** to apply the config to the system
 
 Enable MPLS Forwarding
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 To enable MPLS forwarding on a given interface, use the following
 command:
@@ -132,7 +132,7 @@ Example:
     inet 10.0.1.1 255.255.255.0 mpls
 
 Install rc.d init files
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 (create them in /etc/rc.d - no example are included at this time with
 FRR source)
@@ -152,7 +152,7 @@ Example (for zebra - store as ``/etc/rc.d/frr_zebra.sh``)
     rc_cmd $1
 
 Enable FRR processes
-~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^
 
 (Enable the required processes only)
 
index 68e476fec29febf14e7b2d25783bf1acad5c5b23..bba49c1ce7707dc9ac7f0039e9e8972ead80e673 100644 (file)
@@ -70,7 +70,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -81,7 +81,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -116,7 +116,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -135,7 +135,7 @@ Create empty FRR configuration files
     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)
@@ -154,7 +154,7 @@ other settings)
 system
 
 Install the init.d service
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -164,7 +164,7 @@ Install the init.d service
     sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
 
 Enable daemons
-~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^
 
 | Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
   those daemons you want to start by systemd.
@@ -181,7 +181,7 @@ Enable daemons
     isisd=yes
 
 Start the init.d service
-~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  /etc/init.d/frr start
 -  use ``/etc/init.d/frr status`` to check its status.
index 10944cb8e183283f0072a8603a778ecf5781bacf..c86f1124a775aa0d71097a352960454f47651a77 100644 (file)
@@ -24,7 +24,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -35,7 +35,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -71,7 +71,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -90,7 +90,7 @@ Create empty FRR configuration files
     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)
@@ -106,7 +106,10 @@ other settings)
     net.ipv6.conf.all.forwarding=1
 
 **Reboot** or use ``sysctl -p`` to apply the same config to the running
-system ### Install the init.d service
+system
+
+Install the init.d service
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -116,7 +119,7 @@ system ### Install the init.d service
     sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
 
 Enable daemons
-~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^
 
 | Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
   those daemons you want to start by systemd.
@@ -133,7 +136,7 @@ Enable daemons
     isisd=yes
 
 Start the init.d service
-~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  /etc/init.d/frr start
 -  use ``/etc/init.d/frr status`` to check its status.
index 9c296f8edf6aaa856cb7a64479651adc65183ed3..1b371893e2394662ca6aacc141c612c3f7151152 100644 (file)
@@ -25,7 +25,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -36,7 +36,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -72,7 +72,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -91,7 +91,7 @@ Create empty FRR configuration files
     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)
@@ -107,7 +107,7 @@ other settings)
     net.ipv6.conf.all.forwarding=1
 
 Enable MPLS Forwarding (with Linux Kernel >= 4.5)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 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
@@ -122,7 +122,7 @@ MPLS
     net.mpls.platform_labels=100000
 
 Add MPLS kernel modules
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to ``/etc/modules-load.d/modules.conf``:
 
@@ -136,7 +136,7 @@ Add the following lines to ``/etc/modules-load.d/modules.conf``:
 system
 
 Install the systemd service (if rebooted from last step, change directory back to frr directory)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -148,7 +148,7 @@ Install the systemd service (if rebooted from last step, change directory back t
     sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
 
 Enable daemons
-~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^
 
 | Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
   those daemons you want to start by systemd.
@@ -165,12 +165,12 @@ Enable daemons
     isisd=yes
 
 Enable the systemd service
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  systemctl enable frr
 
 Start the systemd service
-~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  systemctl start frr
 -  use ``systemctl status frr`` to check its status.
index 6c79ed87d6a951e5b6a9741529d3c8d678f91daf..17edb7ef4f9138e34a11a0395479a6b00112dac8 100644 (file)
@@ -20,7 +20,7 @@ Get FRR, compile it and install it (from Git)
 using any packages**
 
 Add frr groups and user
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -31,7 +31,7 @@ Add frr groups and user
     sudo usermod -a -G frrvty frr
 
 Download Source, configure and compile it
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 (You may prefer different options on configure statement. These are just
 an example.)
@@ -67,7 +67,7 @@ an example.)
     sudo make install
 
 Create empty FRR configuration files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -86,7 +86,7 @@ Create empty FRR configuration files
     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)
@@ -102,7 +102,7 @@ other settings)
     net.ipv6.conf.all.forwarding=1
 
 Enable MPLS Forwarding (with Linux Kernel >= 4.5)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 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
@@ -117,7 +117,7 @@ MPLS
     net.mpls.platform_labels=100000
 
 Add MPLS kernel modules
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 Add the following lines to ``/etc/modules-load.d/modules.conf``:
 
@@ -131,7 +131,7 @@ Add the following lines to ``/etc/modules-load.d/modules.conf``:
 system
 
 Install the systemd service (if rebooted from last step, change directory back to frr directory)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -143,7 +143,7 @@ Install the systemd service (if rebooted from last step, change directory back t
     sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
 
 Enable daemons
-~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^
 
 | Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
   those daemons you want to start by systemd.
@@ -160,12 +160,12 @@ Enable daemons
     isisd=yes
 
 Enable the systemd service
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  systemctl enable frr
 
 Start the systemd service
-~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^
 
 -  systemctl start frr
 -  use ``systemctl status frr`` to check its status.
index c7a53734d9b42c2d6f2f1761bca81eb6e5669a19..92fd1bb63a755ef97aeb72e8f5dc0f6614145f36 100644 (file)
@@ -1,5 +1,6 @@
+************
 Building FRR
-=========================
+************
 
 .. toctree::
    :maxdepth: 2
index 9ae19918170dd11cab16ca48a6e0cd4963405ded..a3968b60ffd781f29a35aecd1f237ccd57a9642f 100644 (file)
@@ -15,6 +15,8 @@
 import sys
 import os
 import re
+import pygments
+from sphinx.highlighting import lexers
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -51,7 +53,7 @@ master_doc = 'index'
 # General information about the project.
 project = u'FRR'
 copyright = u'2017, FRR'
-author = u'FRR'
+author = u'FRR authors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -67,34 +69,40 @@ release = u'?.?-?'
 # Extract values from codebase for substitution into docs.
 # -----------------------------------------------------------------------------
 
-# Various installation prefixes. Reasonable defaults are set where possible.
-# Values are overridden by logic below.
+# Various installation prefixes. Values are extracted from config.status.
+# Reasonable defaults are set in case that file does not exist.
 replace_vars = {
-    'AUTHORS': 'Kunihiro Ishiguro, et al.',
+    'AUTHORS': author,
     'COPYRIGHT_YEAR': '1999-2005',
-    'COPYRIGHT_STR': None,
+    'COPYRIGHT_STR': 'Copyright (c) 1999-2005',
     'PACKAGE_NAME': project.lower(),
     'PACKAGE_TARNAME': project.lower(),
-    'PACKAGE_STRING': None,
+    'PACKAGE_STRING': project.lower() + ' latest',
     'PACKAGE_URL': 'https://frrouting.org/',
-    'PACKAGE_VERSION': None,
-    'INSTALL_PREFIX_ETC': None,
-    'INSTALL_PREFIX_SBIN': None,
-    'INSTALL_PREFIX_STATE': None,
-    'INSTALL_PREFIX_MODULES': None,
-    'INSTALL_USER': None,
-    'INSTALL_GROUP': None,
-    'INSTALL_VTY_GROUP': None,
+    'PACKAGE_VERSION': 'latest',
+    'INSTALL_PREFIX_ETC': '/etc/frr',
+    'INSTALL_PREFIX_SBIN': '/usr/lib/frr',
+    'INSTALL_PREFIX_STATE': '/var/run/frr',
+    'INSTALL_PREFIX_MODULES': '/usr/lib/frr/modules',
+    'INSTALL_USER': 'frr',
+    'INSTALL_GROUP': 'frr',
+    'INSTALL_VTY_GROUP': 'frrvty',
+    'GROUP': 'frr',
+    'USER': 'frr',
 }
 
 # extract version information, installation location, other stuff we need to
 # use when building final documents
 val = re.compile('^S\["([^"]+)"\]="(.*)"$')
-with open('../../config.status', 'r') as cfgstatus:
-    for ln in cfgstatus.readlines():
-        m = val.match(ln)
-        if not m or m.group(1) not in replace_vars.keys(): continue
-        replace_vars[m.group(1)] = m.group(2)
+try:
+    with open('../../config.status', 'r') as cfgstatus:
+        for ln in cfgstatus.readlines():
+            m = val.match(ln)
+            if not m or m.group(1) not in replace_vars.keys(): continue
+            replace_vars[m.group(1)] = m.group(2)
+except IOError:
+    # if config.status doesn't exist, just ignore it
+    pass
 
 # manually fill out some of these we can't get from config.status
 replace_vars['COPYRIGHT_STR'] = "Copyright (c)"
@@ -341,3 +349,13 @@ def setup(app):
     app.add_object_type('clicmd', 'clicmd')
     # css overrides for HTML theme
     app.add_stylesheet('overrides.css')
+    # load Pygments lexer for FRR config syntax
+    #
+    # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we
+    # do it manually since not all of our supported build platforms have 2.2
+    # yet.
+    #
+    # frrlexer = pygments.lexers.load_lexer_from_file('../extra/frrlexer.py', lexername="FRRLexer")
+    custom_namespace = {}
+    exec(open('../extra/frrlexer.py', 'rb').read(), custom_namespace)
+    lexers['frr'] = custom_namespace['FRRLexer']()
index 0afa297aa713b4f6db09e40af9b2e6b35dc2d4de..4140a0d171e4f940b6b55a5cacef66f593fe8db6 100644 (file)
@@ -12,26 +12,26 @@ the appropriate function signature (parameters) for the hook.
 Example:
 
 .. code-block:: c
-     :caption: mydaemon.h
+   :caption: mydaemon.h
 
-     #include "hook.h"
-     DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
+   #include "hook.h"
+   DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
 
 .. code-block:: c
-     :caption: mydaemon.c
+   :caption: mydaemon.c
 
-     #include "mydaemon.h"
-     DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
-     ...
-     hook_call(some_update_event, info);
+   #include "mydaemon.h"
+   DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
+   ...
+   hook_call(some_update_event, info);
 
 .. code-block:: c
-     :caption: mymodule.c
+   :caption: mymodule.c
 
-     #include "mydaemon.h"
-     static int event_handler(struct eventinfo *info);
-     ...
-     hook_register(some_update_event, event_handler);
+   #include "mydaemon.h"
+   static int event_handler(struct eventinfo *info);
+   ...
+   hook_register(some_update_event, event_handler);
 
 Do not use parameter names starting with "hook", these can collide with
 names used by the hook code itself.
index 791aedb62431f9bc6b9669736aec267452696fe6..c5ce1f5982f539fea793def1114afa12e312bc42 100644 (file)
@@ -1,5 +1,6 @@
-libfrr library facilities
-=========================
+***************************
+Library Facilities (libfrr)
+***************************
 
 .. toctree::
    :maxdepth: 2
index d40ebe31cd20f0bfe3346d23deca3044ac1170b1..d43bc2555effa2ccc2f9365ca9d6cd04e4d3e54f 100644 (file)
@@ -6,37 +6,37 @@ Memtypes
 FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
 of objects currently allocated, for each of a defined ``MTYPE``.
 
-To this extent, there are `memory groups` and `memory types`.  Each memory
+To this extent, there are *memory groups* and *memory types*.  Each memory
 type must belong to a memory group, this is used just to provide some basic
 structure.
 
 Example:
 
 .. code-block:: c
-     :caption: mydaemon.h
+   :caption: mydaemon.h
 
-     DECLARE_MGROUP(MYDAEMON)
-     DECLARE_MTYPE(MYNEIGHBOR)
+   DECLARE_MGROUP(MYDAEMON)
+   DECLARE_MTYPE(MYNEIGHBOR)
 
 .. code-block:: c
-     :caption: mydaemon.c
-
-     DEFINE_MGROUP(      MYDAEMON, "My daemon's memory")
-     DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry")
-     DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
-
-     struct neigh *neighbor_new(const char *name)
-     {
-        struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
-        n->name = XSTRDUP(MYNEIGHBORNAME, name);
-        return n;
-     }
-
-     void neighbor_free(struct neigh *n)
-     {
-        XFREE(MYNEIGHBORNAME, n->name);
-        XFREE(MYNEIGHBOR, n);
-     }
+   :caption: mydaemon.c
+
+   DEFINE_MGROUP(      MYDAEMON, "My daemon's memory")
+   DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry")
+   DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
+
+   struct neigh *neighbor_new(const char *name)
+   {
+           struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
+           n->name = XSTRDUP(MYNEIGHBORNAME, name);
+           return n;
+   }
+
+   void neighbor_free(struct neigh *n)
+   {
+           XFREE(MYNEIGHBORNAME, n->name);
+           XFREE(MYNEIGHBOR, n);
+   }
 
 
 Definition
index 25e2d1fe1ae6f4f413deb04b6e75b3bcd80bd68b..8a6a4ccb33c890d4b06eb1dbdbf6a1b4bb8e1512 100644 (file)
@@ -100,7 +100,7 @@ Design
 ------
 
 Modules
-~~~~~~~
+^^^^^^^
 
 The core design introduces an "nht" (next hop tracking) module in BGP
 and "rnh" (recursive nexthop) module in Zebra. The "nht" module
@@ -178,7 +178,7 @@ The next hop notification control flow is the following:
 
 
 zclient message format
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are
 encoded in the following way:
@@ -233,7 +233,7 @@ encoded in the following way:
 
 
 BGP data structure
-~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^
 Legend:
 
 ::
@@ -260,7 +260,7 @@ Legend:
 
 
 Zebra data structure
-~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^
 
 RNH table::
 
@@ -279,7 +279,7 @@ RNH table::
    };
 
 User interface changes
-~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^
 
 ::
 
@@ -338,7 +338,7 @@ User interface changes
       + no shut all links to r4
 
 Future work
-~~~~~~~~~~~
+^^^^^^^^^^^
 
 - route-policy for next hop validation (e.g. ignore default route)
 - damping for rapid next hop changes
index 3f8b549df3098c3de968f629b55363991a12a9eb..4a673b155b1670f0c88f77aaa05cb39c4e7832b2 100644 (file)
@@ -29,7 +29,7 @@ Implementation details
 ----------------------
 
 Concepts
-~~~~~~~~
+^^^^^^^^
 
 Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
 information:
@@ -47,7 +47,7 @@ Segment Routing functions (see below) when an Extended Link / Prefix or Router
 Information LSA s are received.
 
 Overview
-~~~~~~~~
+^^^^^^^^
 
 Following files where modified or added:
 
@@ -113,7 +113,7 @@ The figure below shows the relation between the various files:
       Figure 1: Overview of Segment Routing interaction
 
 Module interactions
-~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^
 
 To process incoming LSA, the code is based on the capability to call `hook()`
 functions when LSA are inserted or delete to / from the LSDB and the
@@ -186,7 +186,7 @@ Configuration
 -------------
 
 Linux Kernel
-~~~~~~~~~~~~
+^^^^^^^^^^^^
 
 In order to use OSPF Segment Routing, you must setup MPLS data plane. Up to
 know, only Linux Kernel version >= 4.5 is supported.
@@ -231,7 +231,7 @@ especially the `lo` one. For that purpose, disable RP filtering with:
    sysctl -w net.ipv4.conf.lo.rp_filter=0
 
 OSPFd
-~~~~~
+^^^^^
 
 Here it is a simple example of configuration to enable Segment Routing. Note
 that `opaque capability` and `router information` must be set to activate
index f6519ea8f6c2789b32f31032e16c6e0818dd03c8..f025c47bb4d0ffcd823489333d1547831e32e69c 100644 (file)
@@ -668,7 +668,7 @@ AddressSanitizer
    instrumentation and run through a series of tests to look for any results.
    Testing your own code with this tool before submission is encouraged. You
    can enable it by passing::
-   
+
       --enable-address-sanitizer
 
    to ``configure``.
@@ -678,7 +678,7 @@ ThreadSanitizer
    detecting data races. If you are working on or around multithreaded code,
    extensive testing with this instrumtation enabled is *highly* recommended.
    You can enable it by passing::
-   
+
       --enable-thread-sanitizer
 
    to ``configure``.
@@ -687,7 +687,7 @@ MemorySanitizer
    Similar to AddressSanitizer, this tool provides runtime instrumentation for
    detecting use of uninitialized heap memory. Testing your own code with this
    tool before submission is encouraged. You can enable it by passing::
-   
+
       --enable-memory-sanitizer
 
    to ``configure``.
@@ -775,27 +775,33 @@ FRR uses Sphinx+RST as its documentation system. The document you are currently
 reading was generated by Sphinx from RST source in
 :file:`doc/developer/workflow.rst`. The documentation is structured as follows:
 
-+-----------------------+--------------------------------------------------------------+
-| Directory             | Contents                                                     |
-+=======================+==============================================================+
-| :file:`doc/user`      | User documentation; configuration guides; protocol overviews |
-+-----------------------+--------------------------------------------------------------+
-| :file:`doc/developer` | Developer's documentation; API specs; datastructures;        |
-|                       | architecture overviews; project management procedure         |
-+-----------------------+--------------------------------------------------------------+
-| :file:`doc/manpages`  | Source for manpages                                          |
-+-----------------------+--------------------------------------------------------------+
-| :file:`doc/figures`   | Images and diagrams                                          |
-+-----------------------+--------------------------------------------------------------+
-
-Each of these directories, with the exception of :file:`doc/figures`, contains
-a Sphinx-generated Makefile and configuration script :file:`conf.py` used to
-set various document parameters. The makefile can be used for a variety of
-targets; invoke `make help` in any of these directories for a listing of
-available output formats. For convenience, there is a top-level
-:file:`Makefile.am` that has targets for PDF and HTML documentation for both
-developer and user documentation, respectively. That makefile is also
-responsible for building manual pages packed with distribution builds.
++-----------------------+-------------------------------------------+
+| Directory             | Contents                                  |
++=======================+===========================================+
+| :file:`doc/user`      | User documentation; configuration guides; |
+|                       | protocol overviews                        |
++-----------------------+-------------------------------------------+
+| :file:`doc/developer` | Developer's documentation; API specs;     |
+|                       | datastructures; architecture overviews;   |
+|                       | project management procedure              |
++-----------------------+-------------------------------------------+
+| :file:`doc/manpages`  | Source for manpages                       |
++-----------------------+-------------------------------------------+
+| :file:`doc/figures`   | Images and diagrams                       |
++-----------------------+-------------------------------------------+
+| :file:`doc/extra`     | Miscellaneous Sphinx extensions, scripts, |
+|                       | customizations, etc.                      |
++-----------------------+-------------------------------------------+
+
+Each of these directories, with the exception of :file:`doc/figures` and
+:file:`doc/extra`, contains a Sphinx-generated Makefile and configuration
+script :file:`conf.py` used to set various document parameters. The makefile
+can be used for a variety of targets; invoke `make help` in any of these
+directories for a listing of available output formats. For convenience, there
+is a top-level :file:`Makefile.am` that has targets for PDF and HTML
+documentation for both developer and user documentation, respectively. That
+makefile is also responsible for building manual pages packed with distribution
+builds.
 
 Indent and styling should follow existing conventions:
 
@@ -890,6 +896,15 @@ your implementation of a new BGP draft should go in the BGP chapter instead of
 being its own chapter. If you are adding a new protocol daemon, please create a
 new chapter.
 
+FRR Specific Markup
+-------------------
+
+FRR has some customizations applied to the Sphinx markup that go a long way
+towards making documentation easier to use, write and maintain.
+
+CLI Commands
+^^^^^^^^^^^^
+
 When documenting CLI please use a combination of the ``.. index::`` and
 ``.. clicmd::`` directives. For example, the command :clicmd:`show pony` would
 be documented as follows:
@@ -923,6 +938,29 @@ When documented this way, CLI commands can be cross referenced with the
 This is very helpful for users who want to quickly remind themselves what a
 particular command does.
 
+Configuration Snippets
+^^^^^^^^^^^^^^^^^^^^^^
+
+When putting blocks of example configuration please use the
+``.. code-block::`` directive and specify ``frr`` as the highlighting language,
+as in the following example. This will tell Sphinx to use a custom Pygments
+lexer to highlight FRR configuration syntax.
+
+.. code-block:: rest
+
+   .. code-block:: frr
+
+      !
+      ! Example configuration file.
+      !
+      log file /tmp/log.log
+      service integrated-vtysh-config
+      !
+      ip route 1.2.3.0/24 reject
+      ipv6 route de:ea:db:ee:ff::/64 reject
+      !
+
+
 .. _GitHub: https://github.com/frrouting/frr
 .. _GitHub issues: https://github.com/frrouting/frr/issues
 
diff --git a/doc/extra/frrlexer.py b/doc/extra/frrlexer.py
new file mode 100644 (file)
index 0000000..528bec9
--- /dev/null
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017 Vincent Bernat <bernat@luffy.cx>
+#
+# 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+
+from pygments.lexer import RegexLexer, bygroups
+from pygments.token import Text, Comment, Keyword
+from pygments.token import String, Number, Name
+
+
+class FRRLexer(RegexLexer):
+    name = "frr"
+    aliases = ["frr"]
+    tokens = {
+        'root': [
+            (r'^[ \t]*!.*?\n', Comment.Singleline),
+            (r'"(\\\\|\\"|[^"])*"', String.Double),
+            (r'[a-f0-9]*:[a-f0-9]*:[a-f0-9:]*(:\d+\.\d+\.\d+\.\d+)?(/\d+)?',
+             Number),  # IPv6
+            (r'\d+\.\d+\.\d+\.\d+(/\d+)?', Number),  # IPv4
+            (r'^([ \t]*)(no[ \t]+)?([-\w]+)',
+             bygroups(Text, Keyword, Name.Function)),
+            (r'[ \t]+', Text),
+            (r'\n', Text),
+            (r'\d+', Number),
+            (r'\S+', Text),
+        ],
+    }
index b5ea537faa8e571a2fef8dd4cc88a9d2724940d3..41683ed678b5f98ea9b492d3e6232d7ef2a4808e 100644 (file)
@@ -51,7 +51,7 @@ master_doc = 'index'
 # General information about the project.
 project = u'FRR'
 copyright = u'2017, FRR'
-author = u'Kunihiro Ishiguro, et al.'
+author = u'FRR authors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -67,24 +67,24 @@ release = u'?.?-?'
 # Extract values from codebase for substitution into docs.
 # -----------------------------------------------------------------------------
 
-# Various installation prefixes. Reasonable defaults are set where possible.
-# Values are overridden by logic below.
+# Various installation prefixes. Values are extracted from config.status.
+# Reasonable defaults are set in case that file does not exist.
 replace_vars = {
     'AUTHORS': author,
     'COPYRIGHT_YEAR': '1999-2005',
-    'COPYRIGHT_STR': None,
+    'COPYRIGHT_STR': 'Copyright (c) 1999-2005',
     'PACKAGE_NAME': project.lower(),
     'PACKAGE_TARNAME': project.lower(),
-    'PACKAGE_STRING': None,
+    'PACKAGE_STRING': project.lower() + ' latest',
     'PACKAGE_URL': 'https://frrouting.org/',
-    'PACKAGE_VERSION': None,
-    'INSTALL_PREFIX_ETC': None,
-    'INSTALL_PREFIX_SBIN': None,
-    'INSTALL_PREFIX_STATE': None,
-    'INSTALL_PREFIX_MODULES': None,
-    'INSTALL_USER': None,
-    'INSTALL_GROUP': None,
-    'INSTALL_VTY_GROUP': None,
+    'PACKAGE_VERSION': 'latest',
+    'INSTALL_PREFIX_ETC': '/etc/frr',
+    'INSTALL_PREFIX_SBIN': '/usr/lib/frr',
+    'INSTALL_PREFIX_STATE': '/var/run/frr',
+    'INSTALL_PREFIX_MODULES': '/usr/lib/frr/modules',
+    'INSTALL_USER': 'frr',
+    'INSTALL_GROUP': 'frr',
+    'INSTALL_VTY_GROUP': 'frrvty',
     'GROUP': 'frr',
     'USER': 'frr',
 }
@@ -92,11 +92,15 @@ replace_vars = {
 # extract version information, installation location, other stuff we need to
 # use when building final documents
 val = re.compile('^S\["([^"]+)"\]="(.*)"$')
-with open('../../config.status', 'r') as cfgstatus:
-    for ln in cfgstatus.readlines():
-        m = val.match(ln)
-        if not m or m.group(1) not in replace_vars.keys(): continue
-        replace_vars[m.group(1)] = m.group(2)
+try:
+    with open('../../config.status', 'r') as cfgstatus:
+        for ln in cfgstatus.readlines():
+            m = val.match(ln)
+            if not m or m.group(1) not in replace_vars.keys(): continue
+            replace_vars[m.group(1)] = m.group(2)
+except IOError:
+    # if config.status doesn't exist, just ignore it
+    pass
 
 # manually fill out some of these we can't get from config.status
 replace_vars['COPYRIGHT_STR'] = "Copyright (c)"
index 1e0de66c55864032738587d0cbd8b8f5a535e477..0d871c961a898405fd9d11f1a6cdd8d713869cce 100644 (file)
@@ -2,3 +2,7 @@
 div.body {
     max-width: none;
 }
+
+pre {
+    background-color: #e2e2e2;
+}
index 29d05abba7f2fbc99688cd4ad1814c0d8a9576bb..4a5056e2333ab0ca0598245e42b8a8a751f5fb24 100644 (file)
@@ -42,7 +42,7 @@ Config files are generally found in |INSTALL_PREFIX_ETC|.
 Each of the daemons has its own config file. The daemon name plus ``.conf`` is
 the default config file name. For example, zebra's default config file name is
 :file:`zebra.conf`. You can specify a config file using the :option:`-f` or
-:option:`--config-file` options when starting the daemon.
+:option:`--config_file` options when starting the daemon.
 
 .. _basic-config-commands:
 
@@ -261,27 +261,27 @@ Sample Config File
 
 Below is a sample configuration file for the zebra daemon.
 
-::
+.. code-block:: frr
 
-  !
-  ! Zebra configuration file
-  !
-  hostname Router
-  password zebra
-  enable password zebra
-  !
-  log stdout
-  !
-  !
+   !
+   ! Zebra configuration file
+   !
+   hostname Router
+   password zebra
+   enable password zebra
+   !
+   log stdout
+   !
+   !
 
 
 '!' and '#' are comment characters. If the first character of the word
 is one of the comment characters then from the rest of the line forward
 will be ignored as a comment.
 
-::
+.. code-block:: frr
 
-  password zebra!password
+   password zebra!password
 
 If a comment character is not the first character of the word, it's a
 normal character. So in the above example '!' will not be regarded as a
@@ -358,13 +358,11 @@ Common Invocation Options
 These options apply to all |PACKAGE_NAME| daemons.
 
 
-.. option:: -d
-.. option:: --daemon
+.. option:: -d, --daemon
 
    Run in daemon mode.
 
-.. option:: -f <file>
-.. option:: --config-file <file>
+.. option:: -f, --config_file <file>
 
    Set configuration file name.
 
@@ -372,8 +370,7 @@ These options apply to all |PACKAGE_NAME| daemons.
 
    Display this help and exit.
 
-.. option:: -i <file>
-.. option:: --pid-file <file>
+.. option:: -i, --pid_file <file>
 
    Upon startup the process identifier of the daemon is written to a file,
    typically in :file:`/var/run`. This file can be used by the init system
@@ -386,25 +383,21 @@ These options apply to all |PACKAGE_NAME| daemons.
    machine can be used to collect differing routing views from differing
    points in the network.
 
-.. option:: -A <address>
-.. option:: --vty-addr <address>
+.. option:: -A, --vty_addr <address>
 
    Set the VTY local address to bind to. If set, the VTY socket will only
    be bound to this address.
 
-.. option:: -P <port>
-.. option:: --vty-port <port>
+.. option:: -P, --vty_port <port>
 
    Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not
    be opened.
 
 .. option:: -u <user>
-.. option:: --vty_addr <user>
 
    Set the user and group to run as.
 
-.. option:: -v
-.. option:: --version
+.. option:: -v, --version
 
    Print program version.
 
@@ -418,8 +411,7 @@ unloading modules at runtime is not supported (yet). To load a module, use
 the following command line option at daemon startup:
 
 
-.. option:: -M <module:options>
-.. option:: --module <module:options>
+.. option:: -M, --module <module:options>
 
    Load the specified module, optionally passing options to it. If the module
    name contains a slash (/), it is assumed to be a full pathname to a file to
@@ -474,32 +466,32 @@ is no VTY password, one cannot connect to the VTY interface at all.
 
 ::
 
-  % telnet localhost 2601
-  Trying 127.0.0.1...
-  Connected to localhost.
-  Escape character is '^]'.
+   % telnet localhost 2601
+   Trying 127.0.0.1...
+   Connected to localhost.
+   Escape character is '^]'.
 
-  Hello, this is |PACKAGE_NAME| (version |PACKAGE_VERSION|)
-  |COPYRIGHT_STR|
+   Hello, this is |PACKAGE_NAME| (version |PACKAGE_VERSION|)
+   |COPYRIGHT_STR|
 
-  User Access Verification
+   User Access Verification
 
-  Password: XXXXX
-  Router> ?
-    enable .  .  .  Turn on privileged commands
-    exit   .  .  .  Exit current mode and down to previous mode
-    help   .  .  .  Description of the interactive help system
-    list   .  .  .  Print command list
-    show   .  .  .  Show system inform
+   Password: XXXXX
+   Router> ?
+     enable .  .  .  Turn on privileged commands
+     exit   .  .  .  Exit current mode and down to previous mode
+     help   .  .  .  Description of the interactive help system
+     list   .  .  .  Print command list
+     show   .  .  .  Show system inform
 
-    wh. . .  Display who is on a vty
-  Router> enable
-  Password: XXXXX
-  Router# configure terminal
-  Router(config)# interface eth0
-  Router(config-if)# ip address 10.0.0.1/8
-  Router(config-if)# ^Z
-  Router#
+     wh. . .  Display who is on a vty
+   Router> enable
+   Password: XXXXX
+   Router# configure terminal
+   Router(config)# interface eth0
+   Router(config-if)# ip address 10.0.0.1/8
+   Router(config-if)# ^Z
+   Router#
 
 
 :kbd:`?` and the ``find`` command are very useful for looking up commands.
@@ -553,22 +545,22 @@ These commands are used for moving the CLI cursor. The :kbd:`C` character
 means press the Control Key.
 
 :kbd:`C-f` / :kbd:`LEFT`
-  Move forward one character.
+   Move forward one character.
 
 :kbd:`C-b` / :kbd:`RIGHT`
-  Move backward one character.
+   Move backward one character.
 
 :kbd:`M-f`
-  Move forward one word.
+   Move forward one word.
 
 :kbd:`M-b`
-  Move backward one word.
+   Move backward one word.
 
 :kbd:`C-a`
-  Move to the beginning of the line.
+   Move to the beginning of the line.
 
 :kbd:`C-e`
-  Move to the end of the line.
+   Move to the end of the line.
 
 
 .. _cli-editing-commands:
@@ -581,31 +573,31 @@ character means press the Control Key.
 
 
 :kbd:`C-h` / :kbd:`DEL`
-  Delete the character before point.
+   Delete the character before point.
 
 
 :kbd:`C-d`
-  Delete the character after point.
+   Delete the character after point.
 
 
 :kbd:`M-d`
-  Forward kill word.
+   Forward kill word.
 
 
 :kbd:`C-w`
-  Backward kill word.
+   Backward kill word.
 
 
 :kbd:`C-k`
-  Kill to the end of the line.
+   Kill to the end of the line.
 
 
 :kbd:`C-u`
-  Kill line from the beginning, erasing input.
+   Kill line from the beginning, erasing input.
 
 
 :kbd:`C-t`
-  Transpose character.
+   Transpose character.
 
 
 CLI Advanced Commands
@@ -616,27 +608,27 @@ insta-help, and VTY session management.
 
 
 :kbd:`C-c`
-  Interrupt current input and moves to the next line.
+   Interrupt current input and moves to the next line.
 
 
 :kbd:`C-z`
-  End current configuration session and move to top node.
+   End current configuration session and move to top node.
 
 
 :kbd:`C-n` / :kbd:`DOWN`
-  Move down to next line in the history buffer.
+   Move down to next line in the history buffer.
 
 
 :kbd:`C-p` / :kbd:`UP`
-  Move up to previous line in the history buffer.
+   Move up to previous line in the history buffer.
 
 
 :kbd:`TAB`
-  Use command line completion by typing :kbd:`TAB`.
+   Use command line completion by typing :kbd:`TAB`.
 
 
 :kbd:`?`
-  You can use command line help by typing `help` at the beginning of
-  the line. Typing :kbd:`?` at any point in the line will show possible
-  completions.
+   You can use command line help by typing ``help`` at the beginning of the
+   line.  Typing :kbd:`?` at any point in the line will show possible
+   completions.
 
index 7a508b0df60293845d6fdf89fbc7acccc90e32f7..899977e8309cb13c27738ffb50a56670fce93427 100644 (file)
@@ -26,19 +26,16 @@ be specified (:ref:`common-invocation-options`).
 
 .. program:: bgpd
 
-.. option:: -p <port>
-.. option:: --bgp_port <port>
+.. option:: -p, --bgp_port <port>
 
    Set the bgp protocol's port number. When port number is 0, that means do not
    listen bgp port.
 
-.. option:: -r
-.. option:: --retain
+.. option:: -r, --retain
 
    When program terminates, retain BGP routes added by zebra.
 
-.. option:: -l
-.. option:: --listenon
+.. option:: -l, --listenon
 
    Specify a specific IP address for bgpd to listen on, rather than its
    default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd
@@ -473,12 +470,14 @@ BGP route
 .. index:: network A.B.C.D/M
 .. clicmd:: network A.B.C.D/M
 
-   This command adds the announcement network.::
+   This command adds the announcement network.
 
-     router bgp 1
-      address-family ipv4 unicast
-       network 10.0.0.0/8
-      exit-address-family
+   .. code-block:: frr
+
+      router bgp 1
+       address-family ipv4 unicast
+        network 10.0.0.0/8
+       exit-address-family
 
    This configuration example says that network 10.0.0.0/8 will be
    announced to all neighbors. Some vendors' routers don't advertise
@@ -606,15 +605,17 @@ Defining Peer
 .. clicmd:: neighbor PEER remote-as ASN
 
    Creates a new neighbor whose remote-as is ASN. PEER can be an IPv4 address
-   or an IPv6 address or an interface to use for the connection.::
+   or an IPv6 address or an interface to use for the connection.
 
-      router bgp 1
-       neighbor 10.0.0.1 remote-as 2
+   .. code-block:: frr
+
+       router bgp 1
+        neighbor 10.0.0.1 remote-as 2
 
    In this case my router, in AS-1, is trying to peer with AS-2 at 10.0.0.1.
 
    This command must be the first command used when configuring a neighbor.  If
-   the remote-as is not specified, *bgpd* will complain like this:::
+   the remote-as is not specified, *bgpd* will complain like this: ::
 
       can't find neighbor 10.0.0.1
 
@@ -714,7 +715,9 @@ required.
    Specify the IPv4 source address to use for the :abbr:`BGP` session to this
    neighbour, may be specified as either an IPv4 address directly or as an
    interface name (in which case the *zebra* daemon MUST be running in order
-   for *bgpd* to be able to retrieve interface state).::
+   for *bgpd* to be able to retrieve interface state).
+
+   .. code-block:: frr
 
       router bgp 64555
        neighbor foo update-source 192.168.0.1
@@ -1190,7 +1193,10 @@ Following configuration is the most typical usage of BGP communities
 attribute. AS 7675 provides upstream Internet connection to AS 100.
 When following configuration exists in AS 7675, AS 100 networks
 operator can set local preference in AS 7675 network by setting BGP
-communities attribute to the updates.::
+communities attribute to the updates.
+
+
+.. code-block:: frr
 
    router bgp 7675
     neighbor 192.168.0.1 remote-as 100
@@ -1221,7 +1227,9 @@ communities attribute to the updates.::
 Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675.
 The route has communities value 7675:80 so when above configuration
 exists in AS 7675, announced route's local preference will be set to
-value 80.::
+value 80.
+
+.. code-block:: frr
 
    router bgp 100
     network 10.0.0.0/8
@@ -1241,7 +1249,9 @@ Following configuration is an example of BGP route filtering using
 communities attribute. This configuration only permit BGP routes
 which has BGP communities value 0:80 or 0:90. Network operator can
 put special internal communities value at BGP border router, then
-limit the BGP routes announcement into the internal network.::
+limit the BGP routes announcement into the internal network.
+
+.. code-block:: frr
 
    router bgp 7675
     neighbor 192.168.0.1 remote-as 100
@@ -1257,7 +1267,9 @@ limit the BGP routes announcement into the internal network.::
 
 Following exmaple filter BGP routes which has communities value 1:1.
 When there is no match community-list returns deny. To avoid
-filtering all of routes, we need to define permit any at last.::
+filtering all of routes, we need to define permit any at last.
+
+.. code-block:: frr
 
    router bgp 7675
     neighbor 192.168.0.1 remote-as 100
@@ -1276,7 +1288,9 @@ Communities value keyword `internet` has special meanings in
 standard community lists. In below example `internet` act as
 match any. It matches all of BGP routes even if the route does not
 have communities attribute at all. So community list ``INTERNET``
-is same as above example's ``FILTER``.::
+is same as above example's ``FILTER``.
+
+.. code-block:: frr
 
    ip community-list standard INTERNET deny 1:1
    ip community-list standard INTERNET permit internet
@@ -1285,7 +1299,9 @@ is same as above example's ``FILTER``.::
 Following configuration is an example of communities value deletion.
 With this configuration communities value 100:1 and 100:2 is removed
 from BGP updates. For communities value deletion, only `permit`
-community-list is used. `deny` community-list is ignored.::
+community-list is used. `deny` community-list is ignored.
+
+.. code-block:: frr
 
    router bgp 7675
     neighbor 192.168.0.1 remote-as 100
@@ -1382,11 +1398,9 @@ Lists.
 .. clicmd:: show ip extcommunity-list NAME
 
    This command displays current extcommunity-list information. When `name` is
-   specified the community list's information is shown.
-
-::
+   specified the community list's information is shown.::
 
-    # show ip extcommunity-list
+      # show ip extcommunity-list
 
 
 .. _bgp-extended-communities-in-route-map:
@@ -1607,14 +1621,17 @@ address-family:
 
    Deletes any previously-configured import or export route-target list.
 
-.. index:: label vpn export (0..1048575)
-.. clicmd:: label vpn export (0..1048575)
+.. index:: label vpn export (0..1048575)|auto
+.. clicmd:: label vpn export (0..1048575)|auto
 
    Specifies an optional MPLS label to be attached to a route exported from the
-   current unicast VRF to VPN.
+   current unicast VRF to VPN. If label is specified as ``auto``, the label
+   value is automatically assigned from a pool maintained by the zebra
+   daemon. If zebra is not running, automatic label assignment will not
+   complete, which will block corresponding route export.
 
-.. index:: no label vpn export [(0..1048575)]
-.. clicmd:: no label vpn export [(0..1048575)]
+.. index:: no label vpn export [(0..1048575)|auto]
+.. clicmd:: no label vpn export [(0..1048575)|auto]
 
    Deletes any previously-configured export label.
 
@@ -1933,7 +1950,9 @@ neighbor. If a user manually disables the feature, the community attribute is
 not sent to the neighbor. When ``bgp config-type cisco`` is specified, the
 community attribute is not sent to the neighbor by default. To send the
 community attribute user has to specify *neighbor A.B.C.D send-community*
-command.::
+command.
+
+.. code-block:: frr
 
    !
    router bgp 1
@@ -1969,17 +1988,17 @@ multiple instance feature is enabled.
 
    Make a new BGP instance. You can use an arbitrary word for the `name`.
 
-  ::
+   .. code-block:: frr
 
-     bgp multiple-instance
-     !
-     router bgp 1
-      neighbor 10.0.0.1 remote-as 2
-      neighbor 10.0.0.2 remote-as 3
-     !
-     router bgp 2
-      neighbor 10.0.0.3 remote-as 4
-      neighbor 10.0.0.4 remote-as 5
+      bgp multiple-instance
+      !
+      router bgp 1
+       neighbor 10.0.0.1 remote-as 2
+       neighbor 10.0.0.2 remote-as 3
+      !
+      router bgp 2
+       neighbor 10.0.0.3 remote-as 4
+       neighbor 10.0.0.4 remote-as 5
 
 
 BGP view is almost same as normal BGP process. The result of route selection
@@ -1994,7 +2013,7 @@ routing information.
 
    With this command, you can setup Route Server like below.
 
-   ::
+   .. code-block:: frr
 
       bgp multiple-instance
       !
@@ -2013,7 +2032,9 @@ Routing policy
 --------------
 
 You can set different routing policy for a peer. For example, you can set
-different filter for a peer.::
+different filter for a peer.
+
+.. code-block:: frr
 
    bgp multiple-instance
    !
 How to set up a 6-Bone connection
 =================================
 
-::
+.. code-block:: frr
 
-   bgpd configuration
-   ==================
+   bgpd configuration
+   ==================
    !
    ! MP-BGP configuration
    !
@@ -2174,7 +2195,9 @@ Dump BGP packets and table
 BGP Configuration Examples
 ==========================
 
-Example of a session to an upstream, advertising only one prefix to it.::
+Example of a session to an upstream, advertising only one prefix to it.
+
+.. code-block:: frr
 
    router bgp 64512
     bgp router-id 10.236.87.1
@@ -2199,7 +2222,7 @@ feature to support selective advertising of prefixes. This example is intended
 as guidance only, it has NOT been tested and almost certainly containts silly
 mistakes, if not serious flaws.
 
-::
+.. code-block:: frr
 
    router bgp 64512
     bgp router-id 10.236.87.1
index 7a77e492ce4bdef0b8284b9a1145a3b0c0da47a7..886403b69d4d4d20e15843232164ea0a67535b6c 100644 (file)
@@ -15,6 +15,8 @@
 import sys
 import os
 import re
+import pygments
+from sphinx.highlighting import lexers
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -51,7 +53,7 @@ master_doc = 'index'
 # General information about the project.
 project = u'FRR'
 copyright = u'2017, FRR'
-author = u'FRR'
+author = u'FRR authors'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -67,34 +69,40 @@ release = u'?.?-?'
 # Extract values from codebase for substitution into docs.
 # -----------------------------------------------------------------------------
 
-# Various installation prefixes. Reasonable defaults are set where possible.
-# Values are overridden by logic below.
+# Various installation prefixes. Values are extracted from config.status.
+# Reasonable defaults are set in case that file does not exist.
 replace_vars = {
-    'AUTHORS': 'Kunihiro Ishiguro, et al.',
+    'AUTHORS': author,
     'COPYRIGHT_YEAR': '1999-2005',
-    'COPYRIGHT_STR': None,
+    'COPYRIGHT_STR': 'Copyright (c) 1999-2005',
     'PACKAGE_NAME': project.lower(),
     'PACKAGE_TARNAME': project.lower(),
-    'PACKAGE_STRING': None,
+    'PACKAGE_STRING': project.lower() + ' latest',
     'PACKAGE_URL': 'https://frrouting.org/',
-    'PACKAGE_VERSION': None,
-    'INSTALL_PREFIX_ETC': None,
-    'INSTALL_PREFIX_SBIN': None,
-    'INSTALL_PREFIX_STATE': None,
-    'INSTALL_PREFIX_MODULES': None,
-    'INSTALL_USER': None,
-    'INSTALL_GROUP': None,
-    'INSTALL_VTY_GROUP': None,
+    'PACKAGE_VERSION': 'latest',
+    'INSTALL_PREFIX_ETC': '/etc/frr',
+    'INSTALL_PREFIX_SBIN': '/usr/lib/frr',
+    'INSTALL_PREFIX_STATE': '/var/run/frr',
+    'INSTALL_PREFIX_MODULES': '/usr/lib/frr/modules',
+    'INSTALL_USER': 'frr',
+    'INSTALL_GROUP': 'frr',
+    'INSTALL_VTY_GROUP': 'frrvty',
+    'GROUP': 'frr',
+    'USER': 'frr',
 }
 
 # extract version information, installation location, other stuff we need to
 # use when building final documents
 val = re.compile('^S\["([^"]+)"\]="(.*)"$')
-with open('../../config.status', 'r') as cfgstatus:
-    for ln in cfgstatus.readlines():
-        m = val.match(ln)
-        if not m or m.group(1) not in replace_vars.keys(): continue
-        replace_vars[m.group(1)] = m.group(2)
+try:
+    with open('../../config.status', 'r') as cfgstatus:
+        for ln in cfgstatus.readlines():
+            m = val.match(ln)
+            if not m or m.group(1) not in replace_vars.keys(): continue
+            replace_vars[m.group(1)] = m.group(2)
+except IOError:
+    # if config.status doesn't exist, just ignore it
+    pass
 
 # manually fill out some of these we can't get from config.status
 replace_vars['COPYRIGHT_STR'] = "Copyright (c)"
@@ -341,3 +349,13 @@ def setup(app):
     app.add_object_type('clicmd', 'clicmd')
     # css overrides for HTML theme
     app.add_stylesheet('overrides.css')
+    # load Pygments lexer for FRR config syntax
+    #
+    # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we
+    # do it manually since not all of our supported build platforms have 2.2
+    # yet.
+    #
+    # frrlexer = pygments.lexers.load_lexer_from_file('../extra/frrlexer.py', lexername="FRRLexer")
+    custom_namespace = {}
+    exec(open('../extra/frrlexer.py', 'rb').read(), custom_namespace)
+    lexers['frr'] = custom_namespace['FRRLexer']()
index 309ee27cc48ee5d5d887e46df49e42764ca6d660..c626faf4e2d3c4b7874ff3b3f51cdd9d3d5d2f5f 100644 (file)
@@ -60,8 +60,7 @@ Certain signals have special meanings to *eigrpd*.
 
 .. program:: eigrpd
 
-.. option:: -r
-.. option:: --retain
+.. option:: -r, --retain
 
    When the program terminates, retain routes added by *eigrpd*.
 
@@ -100,7 +99,7 @@ EIGRP Configuration
    Below is very simple EIGRP configuration. Interface `eth0` and
    interface which address match to `10.0.0.0/8` are EIGRP enabled.
 
-   ::
+   .. code-block:: frr
 
       !
       router eigrp 1
index 57f9fbe4263a13cd0ba2722e2b2ac71c424720b1..9d7361443d2ef23129378f667ab9ee0d376c2bab 100644 (file)
@@ -18,7 +18,7 @@ IP Access List
    Basic filtering is done by `access-list` as shown in the
    following example.
 
-   ::
+   .. code-block:: frr
 
       access-list filter deny 10.0.0.0/9
       access-list filter permit 10.0.0.0/8
index b6989809a7c0645ddb21e0d015e07cf7941c5140..54f82f683255836bfccf4bd4e167658aafdb606b 100644 (file)
@@ -559,7 +559,9 @@ Debugging ISIS
 ISIS Configuration Examples
 ===========================
 
-A simple example, with MD5 authentication enabled:::
+A simple example, with MD5 authentication enabled:
+
+.. code-block:: frr
 
    !
    interface eth0
@@ -575,7 +577,9 @@ A simple example, with MD5 authentication enabled:::
 
 A Traffic Engineering configuration, with Inter-ASv2 support.
 
-First, the 'zebra.conf' part:::
+First, the :file:`zebra.conf` part:
+
+.. code-block:: frr
 
    hostname HOSTNAME
    password PASSWORD
@@ -614,7 +618,9 @@ First, the 'zebra.conf' part:::
      neighbor 10.1.1.2 as 65000
 
 
-Then the 'isisd.conf' itself:::
+Then the :file:`isisd.conf` itself:
+
+.. code-block:: frr
 
    hostname HOSTNAME
    password PASSWORD
index 28e78f66fbf2f18d2a94f9e306968b7cbb2c8f7c..33cdbd95913a5df586d2e15d8254e5ce3ae16556 100644 (file)
@@ -52,7 +52,9 @@ hub nodes, these routes should be internally redistributed using some
 routing protocol (e.g. iBGP) to allow hubs to be able to relay all traffic.
 
 This can be achieved in hubs with the following bgp configuration (network
-command defines the GRE subnet):::
+command defines the GRE subnet):
+
+.. code-block:: frr
 
   router bgp 65555
    address-family ipv4 unicast
@@ -82,12 +84,12 @@ using NFLOG. Typically you want to send Traffic Indications for network
 traffic that is routed from gre1 back to gre1 in rate limited manner.
 This can be achieved with the following iptables rule.
 
-::
+.. code-block:: shell
 
-  iptables -A FORWARD -i gre1 -o gre1 \\
-       -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \\
-       --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 \\
-       --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128
+   iptables -A FORWARD -i gre1 -o gre1 \\
+       -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \\
+       --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 \\
+       --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128
 
 
 You can fine tune the src/dstmask according to the prefix lengths you
@@ -95,15 +97,20 @@ announce internal, add additional IP range matches, or rate limitation
 if needed. However, the above should be good in most cases.
 
 This kernel NFLOG target's nflog-group is configured in global nhrp config
-with:::
+with:
+
+.. code-block:: frr
 
-  nhrp nflog-group 1
+   nhrp nflog-group 1
 
 To start sending these traffic notices out from hubs, use the nhrp
-per-interface directive:::
+per-interface directive:
+
+.. code-block:: frr
+
+   interface gre1
+    ip nhrp redirect
 
-  interface gre1
-   ip nhrp redirect
 
 .. _integration-with-ike:
 
index b0823f21e7646dde803f5d6925b2c2a068ecb542..3c84135405ee07e7f70cb686c8fec2dd5a721554 100644 (file)
@@ -49,7 +49,9 @@ OSPF6 router
    will cause the holdtime to be increased by `initial-holdtime`, bounded
    by the `maximum-holdtime` configured with this command. If the adaptive
    hold-time elapses without any SPF-triggering event occuring then
-   the current holdtime is reset to the `initial-holdtime`.::
+   the current holdtime is reset to the `initial-holdtime`.
+
+   .. code-block:: frr
 
       router ospf6
        timers throttle spf 200 400 10000
@@ -187,7 +189,7 @@ OSPF6 Configuration Examples
 
 Example of ospf6d configured on one interface and area:
 
-::
+.. code-block:: frr
 
    interface eth0
     ipv6 ospf6 instance-id 0
index 5a4f7095edf2af764a91e90cf61336e0c4fbc40a..c35df85ddf0f81062a96b1439acfc604cf9e0f12 100644 (file)
@@ -336,61 +336,61 @@ are fully adjacent with 192.168.0.49.
 
 ::
 
-  # show ip ospf database router 192.168.0.49
-
-         OSPF Router with ID (192.168.0.53)
-
-                  Router Link States (Area 0.0.0.0)
-
-    LS age: 38
-    Options: 0x2  : *|-|-|-|-|-|E|*
-    LS Flags: 0x6
-    Flags: 0x2 : ASBR
-    LS Type: router-LSA
-    Link State ID: 192.168.0.49
-    Advertising Router: 192.168.0.49
-    LS Seq Number: 80000f90
-    Checksum: 0x518b
-    Length: 60
-     Number of Links: 3
-
-      Link connected to: a Transit Network
-       (Link ID) Designated Router address: 192.168.1.3
-       (Link Data) Router Interface address: 192.168.1.3
-        Number of TOS metrics: 0
-         TOS 0 Metric: 10
-
-      Link connected to: a Transit Network
-       (Link ID) Designated Router address: 192.168.0.49
-       (Link Data) Router Interface address: 192.168.0.49
-        Number of TOS metrics: 0
-         TOS 0 Metric: 10
-
-      Link connected to: Stub Network
-       (Link ID) Net: 192.168.3.190
-       (Link Data) Network Mask: 255.255.255.255
-        Number of TOS metrics: 0
-         TOS 0 Metric: 39063
-  # show ip ospf database network 192.168.0.49
-
-         OSPF Router with ID (192.168.0.53)
-
-                  Net Link States (Area 0.0.0.0)
-
-    LS age: 285
-    Options: 0x2  : *|-|-|-|-|-|E|*
-    LS Flags: 0x6
-    LS Type: network-LSA
-    Link State ID: 192.168.0.49 (address of Designated Router)
-    Advertising Router: 192.168.0.49
-    LS Seq Number: 80000074
-    Checksum: 0x0103
-    Length: 40
-    Network Mask: /29
-          Attached Router: 192.168.0.49
-          Attached Router: 192.168.0.52
-          Attached Router: 192.168.0.53
-          Attached Router: 192.168.0.54
+   # show ip ospf database router 192.168.0.49
+
+          OSPF Router with ID (192.168.0.53)
+
+                   Router Link States (Area 0.0.0.0)
+
+     LS age: 38
+     Options: 0x2  : *|-|-|-|-|-|E|*
+     LS Flags: 0x6
+     Flags: 0x2 : ASBR
+     LS Type: router-LSA
+     Link State ID: 192.168.0.49
+     Advertising Router: 192.168.0.49
+     LS Seq Number: 80000f90
+     Checksum: 0x518b
+     Length: 60
+      Number of Links: 3
+
+       Link connected to: a Transit Network
+        (Link ID) Designated Router address: 192.168.1.3
+        (Link Data) Router Interface address: 192.168.1.3
+         Number of TOS metrics: 0
+          TOS 0 Metric: 10
+
+       Link connected to: a Transit Network
+        (Link ID) Designated Router address: 192.168.0.49
+        (Link Data) Router Interface address: 192.168.0.49
+         Number of TOS metrics: 0
+          TOS 0 Metric: 10
+
+       Link connected to: Stub Network
+        (Link ID) Net: 192.168.3.190
+        (Link Data) Network Mask: 255.255.255.255
+         Number of TOS metrics: 0
+          TOS 0 Metric: 39063
+   # show ip ospf database network 192.168.0.49
+
+          OSPF Router with ID (192.168.0.53)
+
+                   Net Link States (Area 0.0.0.0)
+
+     LS age: 285
+     Options: 0x2  : *|-|-|-|-|-|E|*
+     LS Flags: 0x6
+     LS Type: network-LSA
+     Link State ID: 192.168.0.49 (address of Designated Router)
+     Advertising Router: 192.168.0.49
+     LS Seq Number: 80000074
+     Checksum: 0x0103
+     Length: 40
+     Network Mask: /29
+           Attached Router: 192.168.0.49
+           Attached Router: 192.168.0.52
+           Attached Router: 192.168.0.53
+           Attached Router: 192.168.0.54
 
 
 Note that from one LSA, you can find the other. E.g. Given the
@@ -412,26 +412,26 @@ following partial topology:
 
 ::
 
-  ------------------------ Network: ......
-              |            Designated Router IP: 192.168.1.3
-              |
-        IP: 192.168.1.3
-         (transit link)
-          (cost: 10)
-     Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32
-          (cost: 10)        (cost: 39063)
-         (transit link)
-        IP: 192.168.0.49
-              |
-              |
-  ------------------------------ Network: 192.168.0.48/29
-    |        |           |       Designated Router IP: 192.168.0.49
-    |        |           |
-    |        |     Router ID: 192.168.0.54
-    |        |
-    |   Router ID: 192.168.0.53
-    |
-  Router ID: 192.168.0.52
+   ------------------------ Network: ......
+               |            Designated Router IP: 192.168.1.3
+               |
+         IP: 192.168.1.3
+          (transit link)
+           (cost: 10)
+      Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32
+           (cost: 10)        (cost: 39063)
+          (transit link)
+         IP: 192.168.0.49
+               |
+               |
+   ------------------------------ Network: 192.168.0.48/29
+     |        |           |       Designated Router IP: 192.168.0.49
+     |        |           |
+     |        |     Router ID: 192.168.0.54
+     |        |
+     |   Router ID: 192.168.0.53
+     |
+   Router ID: 192.168.0.52
 
 
 Note the Router IDs, though they look like IP addresses and often are
@@ -495,22 +495,22 @@ should forward to the originating ASBR if selected.
 
 ::
 
-  # show ip ospf database external 192.168.165.0
-    LS age: 995
-    Options: 0x2  : *|-|-|-|-|-|E|*
-    LS Flags: 0x9
-    LS Type: AS-external-LSA
-    Link State ID: 192.168.165.0 (External Network Number)
-    Advertising Router: 192.168.0.49
-    LS Seq Number: 800001d8
-    Checksum: 0xea27
-    Length: 36
-    Network Mask: /24
-          Metric Type: 2 (Larger than any link state path)
-          TOS: 0
-          Metric: 20
-          Forward Address: 0.0.0.0
-          External Route Tag: 0
+   # show ip ospf database external 192.168.165.0
+     LS age: 995
+     Options: 0x2  : *|-|-|-|-|-|E|*
+     LS Flags: 0x9
+     LS Type: AS-external-LSA
+     Link State ID: 192.168.165.0 (External Network Number)
+     Advertising Router: 192.168.0.49
+     LS Seq Number: 800001d8
+     Checksum: 0xea27
+     Length: 36
+     Network Mask: /24
+           Metric Type: 2 (Larger than any link state path)
+           TOS: 0
+           Metric: 20
+           Forward Address: 0.0.0.0
+           External Route Tag: 0
 
 
 We can add this to our partial topology from above, which now looks
index 59917f5262220eed3b4a6ea99a5069901b06751d..f1b77ffe09e68001f5e8f245932af3e143059c0c 100644 (file)
@@ -163,7 +163,7 @@ writing, *ospfd* does not support multiple OSPF processes.
    holdtime can be viewed with :clicmd:`show ip ospf`, where it is expressed as
    a multiplier of the `initial-holdtime`.
 
-   ::
+   .. code-block:: frr
 
       router ospf
       timers throttle spf 200 400 10000
@@ -249,11 +249,10 @@ writing, *ospfd* does not support multiple OSPF processes.
    on this interface so router can provide network information to the other
    ospf routers via this interface.
 
-::
-
-    router ospf
-   network 192.168.1.0/24 area 0.0.0.0
+   .. code-block:: frr
 
+      router ospf
+      network 192.168.1.0/24 area 0.0.0.0
 
    Prefix length in interface must be equal or bigger (ie. smaller network) than
    prefix length in network statement. For example statement above doesn't enable
@@ -288,23 +287,23 @@ OSPF area
 .. index:: no area (0-4294967295) range A.B.C.D/M
 .. clicmd:: no area (0-4294967295) range A.B.C.D/M
 
-  Summarize intra area paths from specified area into one Type-3 summary-LSA
-  announced to other areas. This command can be used only in ABR and ONLY
-  router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can
-  be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS.
-  Summarizing Type-7 AS-external-LSAs isn't supported yet by FRR.
+   Summarize intra area paths from specified area into one Type-3 summary-LSA
+   announced to other areas. This command can be used only in ABR and ONLY
+   router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can
+   be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS.
+   Summarizing Type-7 AS-external-LSAs isn't supported yet by FRR.
 
-::
+   .. code-block:: frr
 
-   router ospf
-    network 192.168.1.0/24 area 0.0.0.0
-    network 10.0.0.0/8 area 0.0.0.10
-    area 0.0.0.10 range 10.0.0.0/8
+      router ospf
+       network 192.168.1.0/24 area 0.0.0.0
+       network 10.0.0.0/8 area 0.0.0.10
+       area 0.0.0.10 range 10.0.0.0/8
 
 
-  With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is
-  announced into backbone area if area 0.0.0.10 contains at least one intra-area
-  network (ie. described with router or network LSA) from this range.
+   With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is
+   announced into backbone area if area 0.0.0.10 contains at least one intra-area
+   network (ie. described with router or network LSA) from this range.
 
 .. index:: area A.B.C.D range IPV4_PREFIX not-advertise
 .. clicmd:: area A.B.C.D range IPV4_PREFIX not-advertise
@@ -324,12 +323,12 @@ OSPF area
 
    Substitute summarized prefix with another prefix.
 
-::
+   .. code-block:: frr
 
-    router ospf
-     network 192.168.1.0/24 area 0.0.0.0
-     network 10.0.0.0/8 area 0.0.0.10
-     area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8
+      router ospf
+       network 192.168.1.0/24 area 0.0.0.0
+       network 10.0.0.0/8 area 0.0.0.10
+       area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8
 
 
    One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if
@@ -421,16 +420,15 @@ OSPF area
    Filter Type-3 summary-LSAs announced to other areas originated from intra-
    area paths from specified area.
 
-::
-
-     router ospf
-      network 192.168.1.0/24 area 0.0.0.0
-      network 10.0.0.0/8 area 0.0.0.10
-      area 0.0.0.10 export-list foo
-     !
-     access-list foo permit 10.10.0.0/16
-     access-list foo deny any
+   .. code-block:: frr
 
+      router ospf
+       network 192.168.1.0/24 area 0.0.0.0
+       network 10.0.0.0/8 area 0.0.0.10
+       area 0.0.0.10 export-list foo
+      !
+      access-list foo permit 10.10.0.0/16
+      access-list foo deny any
 
    With example above any intra-area paths from area 0.0.0.10 and from range
    10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into
@@ -452,8 +450,8 @@ OSPF area
 .. index:: no area (0-4294967295) import-list NAME
 .. clicmd:: no area (0-4294967295) import-list NAME
 
-   Same as export-list, but it applies to paths announced into specified area as
-   Type-3 summary-LSAs.
+   Same as export-list, but it applies to paths announced into specified area
+   as Type-3 summary-LSAs.
 
 .. index:: area A.B.C.D filter-list prefix NAME in
 .. clicmd:: area A.B.C.D filter-list prefix NAME in
@@ -479,8 +477,8 @@ OSPF area
 .. index:: no area (0-4294967295) filter-list prefix NAME out
 .. clicmd:: no area (0-4294967295) filter-list prefix NAME out
 
-     Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
-     makes sense in ABR only.
+   Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
+   makes sense in ABR only.
 
 .. index:: area A.B.C.D authentication
 .. clicmd:: area A.B.C.D authentication
@@ -494,8 +492,8 @@ OSPF area
 .. index:: no area (0-4294967295) authentication
 .. clicmd:: no area (0-4294967295) authentication
 
-    Specify that simple password authentication should be used for the given
-    area.
+   Specify that simple password authentication should be used for the given
+   area.
 
 .. index:: area A.B.C.D authentication message-digest
 .. clicmd:: area A.B.C.D authentication message-digest
@@ -568,12 +566,11 @@ OSPF interface
    Set OSPF authentication key to a cryptographic password. The cryptographic
    algorithm is MD5.
 
-   KEYID identifies secret key used to create the message digest. This ID
-   is part of the protocol and must be consistent across routers on a
-   link.
+   KEYID identifies secret key used to create the message digest. This ID is
+   part of the protocol and must be consistent across routers on a link.
 
-   KEY is the actual message digest key, of up to 16 chars (larger strings
-   will be truncated), and is associated with the given KEYID.
+   KEY is the actual message digest key, of up to 16 chars (larger strings will
+   be truncated), and is associated with the given KEYID.
 
 .. index:: ip ospf cost (1-65535)
 .. clicmd:: ip ospf cost (1-65535)
@@ -581,8 +578,8 @@ OSPF interface
 .. index:: no ip ospf cost
 .. clicmd:: no ip ospf cost
 
-   Set link cost for the specified interface. The cost value is set to router-LSA's
-   metric field and used for SPF calculation.
+   Set link cost for the specified interface. The cost value is set to
+   router-LSA's metric field and used for SPF calculation.
 
 .. index:: ip ospf dead-interval (1-65535)
 .. clicmd:: ip ospf dead-interval (1-65535)
@@ -635,10 +632,9 @@ OSPF interface
 .. index:: no ip ospf priority
 .. clicmd:: no ip ospf priority
 
-    Set RouterPriority integer value. The router with the highest priority
-    will be more eligible to become Designated Router. Setting the value
-    to 0, makes the router ineligible to become Designated Router. The
-    default value is 1.
+   Set RouterPriority integer value. The router with the highest priority will
+   be more eligible to become Designated Router. Setting the value to 0, makes
+   the router ineligible to become Designated Router. The default value is 1.
 
 .. index:: ip ospf retransmit-interval (1-65535)
 .. clicmd:: ip ospf retransmit-interval (1-65535)
@@ -646,9 +642,9 @@ OSPF interface
 .. index:: no ip ospf retransmit interval
 .. clicmd:: no ip ospf retransmit interval
 
-   Set number of seconds for RxmtInterval timer value. This value is used
-   when retransmitting Database Description and Link State Request packets.
-   The default value is 5 seconds.
+   Set number of seconds for RxmtInterval timer value. This value is used when
+   retransmitting Database Description and Link State Request packets. The
+   default value is 5 seconds.
 
 .. index:: ip ospf transmit-delay
 .. clicmd:: ip ospf transmit-delay
@@ -657,8 +653,7 @@ OSPF interface
 .. clicmd:: no ip ospf transmit-delay
 
    Set number of seconds for InfTransDelay value. LSAs' age should be
-   incremented by this value when transmitting.
-   The default value is 1 seconds.
+   incremented by this value when transmitting. The default value is 1 second.
 
 .. index:: ip ospf area (A.B.C.D|(0-4294967295))
 .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))
@@ -666,7 +661,7 @@ OSPF interface
 .. index:: no ip ospf area
 .. clicmd:: no ip ospf area
 
-    Enable ospf on an interface and set associated area.
+   Enable ospf on an interface and set associated area.
 
 .. _redistribute-routes-to-ospf:
 
@@ -702,16 +697,16 @@ Redistribute routes to OSPF
 
 .. _ospf-redistribute:
 
-   Redistribute routes of the specified protocol
-   or kind into OSPF, with the metric type and metric set if specified,
-   filtering the routes using the given route-map if specified.
-   Redistributed routes may also be filtered with distribute-lists, see
+   Redistribute routes of the specified protocol or kind into OSPF, with the
+   metric type and metric set if specified, filtering the routes using the
+   given route-map if specified.  Redistributed routes may also be filtered
+   with distribute-lists, see
    :ref:`ospf distribute-list configuration <ospf-distribute-list>`.
 
-   Redistributed routes are distributed as into OSPF as Type-5 External
-   LSAs into links to areas that accept external routes, Type-7 External LSAs
-   for NSSA areas and are not redistributed at all into Stub areas, where
-   external routes are not permitted.
+   Redistributed routes are distributed as into OSPF as Type-5 External LSAs
+   into links to areas that accept external routes, Type-7 External LSAs for
+   NSSA areas and are not redistributed at all into Stub areas, where external
+   routes are not permitted.
 
    Note that for connected routes, one may instead use the `passive-interface`
    configuration.
@@ -747,10 +742,10 @@ Redistribute routes to OSPF
 .. index:: no default-information originate
 .. clicmd:: no default-information originate
 
-   Originate an AS-External (type-5) LSA describing a default route into
-   all external-routing capable areas, of the specified metric and metric
-   type. If the 'always' keyword is given then the default is always
-   advertised, even when there is no default present in the routing table.
+   Originate an AS-External (type-5) LSA describing a default route into all
+   external-routing capable areas, of the specified metric and metric type. If
+   the 'always' keyword is given then the default is always advertised, even
+   when there is no default present in the routing table.
 
 .. index:: distribute-list NAME out (kernel|connected|static|rip|ospf
 .. clicmd:: distribute-list NAME out (kernel|connected|static|rip|ospf
@@ -760,9 +755,9 @@ Redistribute routes to OSPF
 
 .. _ospf-distribute-list:
 
-   Apply the access-list filter, NAME, to
-   redistributed routes of the given type before allowing the routes to
-   redistributed into OSPF (:ref:`ospf redistribution <ospf-redistribute>`).
+   Apply the access-list filter, NAME, to redistributed routes of the given
+   type before allowing the routes to redistributed into OSPF
+   (:ref:`ospf redistribution <ospf-redistribute>`).
 
 .. index:: default-metric (0-16777214)
 .. clicmd:: default-metric (0-16777214)
@@ -850,7 +845,8 @@ Showing OSPF information
 .. index:: show ip ospf route
 .. clicmd:: show ip ospf route
 
-   Show the OSPF routing table, as determined by the most recent SPF calculation.
+   Show the OSPF routing table, as determined by the most recent SPF
+   calculation.
 
 .. _opaque-lsa:
 
@@ -869,9 +865,9 @@ Opaque LSA
 .. index:: no capability opaque
 .. clicmd:: no capability opaque
 
-   *ospfd* support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering
-   LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration
-   file. Alternate command could be "mpls-te on"
+   *ospfd* support Opaque LSA (:rfc:`2370`) as fondment for MPLS Traffic
+   Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the
+   configuration file. Alternate command could be "mpls-te on"
    (:ref:`ospf-traffic-engineering`).
 
 .. index:: show ip ospf database (opaque-link|opaque-area|opaque-external)
@@ -981,18 +977,19 @@ Router Information
 .. index:: no pce scope
 .. clicmd:: no pce scope
 
-  The commands are conform to :rfc:`5088` and allow OSPF router announce Path
-  Compuatation Elemenent (PCE) capabilities through the Router Information (RI)
-  LSA. Router Information must be enable prior to this. The command set/unset
-  respectively the PCE IP adress, Autonomous System (AS) numbers of controlled
-  domains, neighbor ASs, flag and scope. For flag and scope, please refer to
-  :rfc`5088` for the BITPATTERN recognition. Multiple 'pce neighbor' command
-  could be specified in order to specify all PCE neighbours.
+   The commands are conform to :rfc:`5088` and allow OSPF router announce Path
+   Compuatation Elemenent (PCE) capabilities through the Router Information
+   (RI) LSA. Router Information must be enable prior to this. The command
+   set/unset respectively the PCE IP adress, Autonomous System (AS) numbers of
+   controlled domains, neighbor ASs, flag and scope. For flag and scope, please
+   refer to :rfc`5088` for the BITPATTERN recognition. Multiple 'pce neighbor'
+   command could be specified in order to specify all PCE neighbours.
 
 .. index:: show ip ospf router-info
 .. clicmd:: show ip ospf router-info
 
    Show Router Capabilities flag.
+
 .. index:: show ip ospf router-info pce
 .. clicmd:: show ip ospf router-info pce
 
@@ -1028,10 +1025,10 @@ This is an EXPERIMENTAL support of Segment Routing as per draft
 .. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
 .. clicmd:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
 
-   Set the Segment Rounting index for the specifyed prefix. Note
-   that, only prefix with /32 corresponding to a loopback interface are
-   currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that
-   allows SR node to request to its neighbor to not pop the label.
+   Set the Segment Rounting index for the specifyed prefix. Note that, only
+   prefix with /32 corresponding to a loopback interface are currently
+   supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR
+   node to request to its neighbor to not pop the label.
 
 .. index:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]
 .. clicmd:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]
@@ -1140,7 +1137,7 @@ OSPF Configuration Examples
 
 A simple example, with MD5 authentication enabled:
 
-::
+.. code-block:: frr
 
    !
    interface bge0
@@ -1155,7 +1152,7 @@ A simple example, with MD5 authentication enabled:
 An :abbr:`ABR` router, with MD5 authentication and performing summarisation
 of networks between the areas:
 
-::
+.. code-block:: frr
 
    !
    password ABCDEF
@@ -1189,7 +1186,9 @@ of networks between the areas:
 
 A Traffic Engineering configuration, with Inter-ASv2 support.
 
-First, the 'zebra.conf' part:::
+First, the :file:`zebra.conf` part:
+
+.. code-block:: frr
 
    interface eth0
     ip address 198.168.1.1/24
@@ -1262,7 +1261,9 @@ First, the 'zebra.conf' part:::
         unrsv-bw 7 1.25e+06
         neighbor 192.168.2.2 as 65000
 
-Then the 'ospfd.conf' itself:::
+Then the :file:`ospfd.conf` itself:
+
+.. code-block:: frr
 
    hostname HOSTNAME
    password PASSWORD
@@ -1288,8 +1289,9 @@ Then the 'ospfd.conf' itself:::
    !
    line vty
 
+A router information example with PCE advsertisement:
 
-A router information example with PCE advsertisement:::
+.. code-block:: frr
 
    !
    router ospf
index 064dc436ea4018a0e3a259e31c12e3f9520e8c6a..38d55d68ad969e92ee375bdc2af20f044b3b9297 100644 (file)
@@ -95,17 +95,17 @@ architecture creates new possibilities for the routing system.
 
 ::
 
-  +----+  +----+  +-----+  +-----+
-  |bgpd|  |ripd|  |ospfd|  |zebra|
-  +----+  +----+  +-----+  +-----+
-                              |
-  +---------------------------|--+
-  |                           v  |
-  |  UNIX Kernel  routing table  |
-  |                              |
-  +------------------------------+
-
-      FRR System Architecture
+   +----+  +----+  +-----+  +-----+
+   |bgpd|  |ripd|  |ospfd|  |zebra|
+   +----+  +----+  +-----+  +-----+
+                               |
+   +---------------------------|--+
+   |                           v  |
+   |  UNIX Kernel  routing table  |
+   |                              |
+   +------------------------------+
+
+       FRR System Architecture
 
 
 Multi-process architecture brings extensibility, modularity and
index b9945680cf7cdc237e7f352a154c0c19b8feefe5..2dda88a6d1e09e2dcf399e3180574689336fd119 100644 (file)
@@ -214,8 +214,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
 
 .. _pim-multicast-rib-insertion:
 
-PIM Multicast RIB insertion::
-=============================
+PIM Multicast RIB insertion:
+============================
 
 In order to influence Multicast RPF lookup, it is possible to insert
 into zebra routes for the Multicast RIB. These routes are only
index b8cbd161c64b63ea7a87badff12262352b99677a..d2686d2eaef552fad83200241d898efb5a1b979c 100644 (file)
@@ -60,8 +60,7 @@ Certain signals have special meaningss to *ripd*.
 *ripd* invocation options. Common options that can be specified
 (:ref:`common-invocation-options`).
 
-.. option:: -r
-.. option:: --retain
+.. option:: -r, --retain
 
    When the program terminates, retain routes added by *ripd*.
 
@@ -147,7 +146,7 @@ RIP Configuration
    Below is very simple RIP configuration. Interface `eth0` and interface which
    address match to `10.0.0.0/8` are RIP enabled.
 
-   ::
+   .. code-block:: frr
 
       !
       router rip
@@ -355,7 +354,7 @@ RIP routes can be filtered by a distribute-list.
    the distribute-list command. For example, in the following configuration
    ``eth0`` will permit only the paths that match the route 10.0.0.0/8
 
-   ::
+   .. code-block:: frr
 
        !
        router rip
@@ -447,11 +446,11 @@ Usage of *ripd*'s route-map support.
 Optional argument route-map MAP_NAME can be added to each `redistribute`
 statement.
 
-::
+.. code-block:: frr
 
-  redistribute static [route-map MAP_NAME]
-  redistribute connected [route-map MAP_NAME]
-  .....
+   redistribute static [route-map MAP_NAME]
+   redistribute connected [route-map MAP_NAME]
+   .....
 
 
 Cisco applies route-map _before_ routes will exported to rip route table.  In
@@ -573,17 +572,17 @@ To prevent such unauthenticated querying of routes disable RIPv1,
 
    Specifiy Keyed MD5 chain.
 
-::
+   .. code-block:: frr
 
-    !
-    key chain test
-     key 1
-      key-string test
-    !
-    interface eth1
-     ip rip authentication mode md5
-     ip rip authentication key-chain test
-    !
+      !
+      key chain test
+       key 1
+        key-string test
+      !
+      interface eth1
+       ip rip authentication mode md5
+       ip rip authentication key-chain test
+      !
 
 
 .. _rip-timers:
index 97094c2d6bf79a28dd75771d4beaa29b084e0a4c..a0f28b5fc88224f778c52c343c985c1770f11d90 100644 (file)
@@ -302,11 +302,11 @@ Route Map Examples
 
 A simple example of a route-map:
 
-::
+.. code-block:: frr
 
-  route-map test permit 10
-   match ip address 10
-   set local-preference 200
+   route-map test permit 10
+    match ip address 10
+    set local-preference 200
 
 
 This means that if a route matches ip access-list number 10 it's
index 890897bb623197e570ae91cf59e126ba762d73bc..f2c2c6d33e9b6f7038ce1df747b33e3bceea892c 100644 (file)
@@ -246,7 +246,7 @@ against the other two routers. These peerings have In and Out route-maps
 configured, named like 'PEER-X-IN' or 'PEER-X-OUT'. For example the
 configuration file for router RA could be the following:
 
-::
+.. code-block:: frr
 
    #Configuration for router 'RA'
    !
@@ -319,29 +319,29 @@ modify the configuration of routers RA, RB and RC. Now they must not peer
 between them, but only with the route server. For example, RA's
 configuration would turn into:
 
-::
+.. code-block:: frr
+
+   # Configuration for router 'RA'
+   !
+   hostname RA
+   password ****
+   !
+   router bgp 65001
+     no bgp default ipv4-unicast
+     neighbor 2001:0DB8::FFFF remote-as 65000
+   !
+     address-family ipv6
+       network 2001:0DB8:AAAA:1::/64
+       network 2001:0DB8:AAAA:2::/64
+       network 2001:0DB8:0000:1::/64
+       network 2001:0DB8:0000:2::/64
 
-  # Configuration for router 'RA'
-  !
-  hostname RA
-  password ****
-  !
-  router bgp 65001
-    no bgp default ipv4-unicast
-    neighbor 2001:0DB8::FFFF remote-as 65000
-  !
-    address-family ipv6
-      network 2001:0DB8:AAAA:1::/64
-      network 2001:0DB8:AAAA:2::/64
-      network 2001:0DB8:0000:1::/64
-      network 2001:0DB8:0000:2::/64
-
-      neighbor 2001:0DB8::FFFF activate
-      neighbor 2001:0DB8::FFFF soft-reconfiguration inbound
-    exit-address-family
-  !
-  line vty
-  !
+       neighbor 2001:0DB8::FFFF activate
+       neighbor 2001:0DB8::FFFF soft-reconfiguration inbound
+     exit-address-family
+   !
+   line vty
+   !
 
 
 Which is logically much simpler than its initial configuration, as it now
@@ -362,84 +362,84 @@ server.
 This is a fragment of the route server configuration (we only show
 the policies for client RA):
 
-::
+.. code-block:: frr
 
-  # Configuration for Route Server ('RS')
-  !
-  hostname RS
-  password ix
-  !
-  bgp multiple-instance
-  !
-  router bgp 65000 view RS
-    no bgp default ipv4-unicast
-    neighbor 2001:0DB8::A  remote-as 65001
-    neighbor 2001:0DB8::B  remote-as 65002
-    neighbor 2001:0DB8::C  remote-as 65003
-  !
-    address-family ipv6
-      neighbor 2001:0DB8::A activate
-      neighbor 2001:0DB8::A route-server-client
-      neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import
-      neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export
-      neighbor 2001:0DB8::A soft-reconfiguration inbound
-
-      neighbor 2001:0DB8::B activate
-      neighbor 2001:0DB8::B route-server-client
-      neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import
-      neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export
-      neighbor 2001:0DB8::B soft-reconfiguration inbound
-
-      neighbor 2001:0DB8::C activate
-      neighbor 2001:0DB8::C route-server-client
-      neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import
-      neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export
-      neighbor 2001:0DB8::C soft-reconfiguration inbound
-    exit-address-family
-  !
-  ipv6 prefix-list COMMON-PREFIXES seq  5 permit 2001:0DB8:0000::/48 ge 64 le 64
-  ipv6 prefix-list COMMON-PREFIXES seq 10 deny any
-  !
-  ipv6 prefix-list PEER-A-PREFIXES seq  5 permit 2001:0DB8:AAAA::/48 ge 64 le 64
-  ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any
-  !
-  ipv6 prefix-list PEER-B-PREFIXES seq  5 permit 2001:0DB8:BBBB::/48 ge 64 le 64
-  ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any
-  !
-  ipv6 prefix-list PEER-C-PREFIXES seq  5 permit 2001:0DB8:CCCC::/48 ge 64 le 64
-  ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any
-  !
-  route-map RSCLIENT-A-IMPORT permit 10
-    match peer 2001:0DB8::B
-    call A-IMPORT-FROM-B
-  route-map RSCLIENT-A-IMPORT permit 20
-    match peer 2001:0DB8::C
-    call A-IMPORT-FROM-C
-  !
-  route-map A-IMPORT-FROM-B permit 10
-    match ipv6 address prefix-list COMMON-PREFIXES
-    set metric 100
-  route-map A-IMPORT-FROM-B permit 20
-    match ipv6 address prefix-list PEER-B-PREFIXES
-    set community 65001:11111
-  !
-  route-map A-IMPORT-FROM-C permit 10
-    match ipv6 address prefix-list COMMON-PREFIXES
-    set metric 200
-  route-map A-IMPORT-FROM-C permit 20
-    match ipv6 address prefix-list PEER-C-PREFIXES
-    set community 65001:22222
-  !
-  route-map RSCLIENT-A-EXPORT permit 10
-    match peer 2001:0DB8::B
-    match ipv6 address prefix-list PEER-A-PREFIXES
-  route-map RSCLIENT-A-EXPORT permit 20
-    match peer 2001:0DB8::C
-    match ipv6 address prefix-list PEER-A-PREFIXES
-  !
-  ...
-  ...
-  ...
+   # Configuration for Route Server ('RS')
+   !
+   hostname RS
+   password ix
+   !
+   bgp multiple-instance
+   !
+   router bgp 65000 view RS
+     no bgp default ipv4-unicast
+     neighbor 2001:0DB8::A  remote-as 65001
+     neighbor 2001:0DB8::B  remote-as 65002
+     neighbor 2001:0DB8::C  remote-as 65003
+   !
+     address-family ipv6
+       neighbor 2001:0DB8::A activate
+       neighbor 2001:0DB8::A route-server-client
+       neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import
+       neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export
+       neighbor 2001:0DB8::A soft-reconfiguration inbound
+
+       neighbor 2001:0DB8::B activate
+       neighbor 2001:0DB8::B route-server-client
+       neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import
+       neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export
+       neighbor 2001:0DB8::B soft-reconfiguration inbound
+
+       neighbor 2001:0DB8::C activate
+       neighbor 2001:0DB8::C route-server-client
+       neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import
+       neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export
+       neighbor 2001:0DB8::C soft-reconfiguration inbound
+     exit-address-family
+   !
+   ipv6 prefix-list COMMON-PREFIXES seq  5 permit 2001:0DB8:0000::/48 ge 64 le 64
+   ipv6 prefix-list COMMON-PREFIXES seq 10 deny any
+   !
+   ipv6 prefix-list PEER-A-PREFIXES seq  5 permit 2001:0DB8:AAAA::/48 ge 64 le 64
+   ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any
+   !
+   ipv6 prefix-list PEER-B-PREFIXES seq  5 permit 2001:0DB8:BBBB::/48 ge 64 le 64
+   ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any
+   !
+   ipv6 prefix-list PEER-C-PREFIXES seq  5 permit 2001:0DB8:CCCC::/48 ge 64 le 64
+   ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any
+   !
+   route-map RSCLIENT-A-IMPORT permit 10
+     match peer 2001:0DB8::B
+     call A-IMPORT-FROM-B
+   route-map RSCLIENT-A-IMPORT permit 20
+     match peer 2001:0DB8::C
+     call A-IMPORT-FROM-C
+   !
+   route-map A-IMPORT-FROM-B permit 10
+     match ipv6 address prefix-list COMMON-PREFIXES
+     set metric 100
+   route-map A-IMPORT-FROM-B permit 20
+     match ipv6 address prefix-list PEER-B-PREFIXES
+     set community 65001:11111
+   !
+   route-map A-IMPORT-FROM-C permit 10
+     match ipv6 address prefix-list COMMON-PREFIXES
+     set metric 200
+   route-map A-IMPORT-FROM-C permit 20
+     match ipv6 address prefix-list PEER-C-PREFIXES
+     set community 65001:22222
+   !
+   route-map RSCLIENT-A-EXPORT permit 10
+     match peer 2001:0DB8::B
+     match ipv6 address prefix-list PEER-A-PREFIXES
+   route-map RSCLIENT-A-EXPORT permit 20
+     match peer 2001:0DB8::C
+     match ipv6 address prefix-list PEER-A-PREFIXES
+   !
+   ...
+   ...
+   ...
 
 
 If you compare the initial configuration of RA with the route server
@@ -487,7 +487,7 @@ any limitation, as all kinds of filters can be included in import/export
 route-maps. For example suppose that in the non-route-server scenario peer
 RA had the following filters configured for input from peer B:
 
-::
+.. code-block:: frr
 
    neighbor 2001:0DB8::B prefix-list LIST-1 in
    neighbor 2001:0DB8::B filter-list LIST-2 in
@@ -507,7 +507,7 @@ the three filters (the community-list, the prefix-list and the
 route-map). That route-map can then be used inside the Import
 policy in the route server. Lets see how to do it:
 
-::
+.. code-block:: frr
 
    neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import
    ...
index 86d88dcf9b2f83798b11c839d1fe5d4a264c9098..93a8e4396a261d113ea2e13f992ebcb530fe8447 100644 (file)
@@ -164,7 +164,7 @@ Validating BGP Updates
     In the following example, the router prefers valid routes over invalid
     prefixes because invalid routes have a lower local preference.
 
-    ::
+    .. code-block:: frr
 
        ! Allow for invalid routes in route selection process
        route bgp 60001
@@ -213,7 +213,7 @@ Displaying RPKI
 RPKI Configuration Example
 --------------------------
 
-::
+.. code-block:: frr
 
    hostname bgpd1
    password zebra
index 114f1f7dfceac6577165f7ced993b221b8bd419e..1a24d56cb76ef01d22d1c801036883ab7ff907c6 100644 (file)
@@ -42,22 +42,23 @@ master SNMP agent (snmpd) and each of the FRR daemons must be configured. In
 :file:`/etc/snmp/snmpd.conf`, the ``master agentx`` directive should be added.
 In each of the FRR daemons, ``agentx`` command will enable AgentX support.
 
-::
+:file:`/etc/snmp/snmpd.conf`:
+   #
+   # example access restrictions setup
+   #
+   com2sec readonly default public
+   group MyROGroup v1 readonly
+   view all included .1 80
+   access MyROGroup "" any noauth exact all none none
+   #
+   # enable master agent for AgentX subagents
+   #
+   master agentx
+
+:file:`/etc/frr/ospfd.conf:`
+
+   .. code-block:: frr
 
-   /etc/snmp/snmpd.conf:
-      #
-      # example access restrictions setup
-      #
-      com2sec readonly default public
-      group MyROGroup v1 readonly
-      view all included .1 80
-      access MyROGroup "" any noauth exact all none none
-      #
-      # enable master agent for AgentX subagents
-      #
-      master agentx
-
-   /etc/frr/ospfd.conf:
       ! ... the rest of ospfd.conf has been omitted for clarity ...
       !
       agentx
@@ -69,16 +70,16 @@ each FRR daemons:
 
 ::
 
-  2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected
+   2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected
 
 
 Then, you can use the following command to check everything works as expected:
 
 ::
 
-  # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1
-  OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109
-  [...]
+   # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1
+   OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109
+   [...]
 
 
 The AgentX protocol can be transported over a Unix socket or using TCP or UDP.
@@ -88,10 +89,9 @@ need to configure FRR to use another transport, you can configure it through
 
 ::
 
-   /etc/snmp/frr.conf:
-      [snmpd]
-      # Use a remote master agent
-      agentXSocket tcp:192.168.15.12:705
+   [snmpd]
+   # Use a remote master agent
+   agentXSocket tcp:192.168.15.12:705
 
 
 .. _smux-configuration:
@@ -112,26 +112,24 @@ In the following example the ospfd daemon will be connected to the snmpd daemon
 using the password "frr_ospfd". For testing it is recommending to take exactly
 the below snmpd.conf as wrong access restrictions can be hard to debug.
 
-::
-
-   /etc/snmp/snmpd.conf:
-      #
-      # example access restrictions setup
-      #
-      com2sec readonly default public
-      group MyROGroup v1 readonly
-      view all included .1 80
-      access MyROGroup "" any noauth exact all none none
-      #
-      # the following line is relevant for FRR
-      #
-      smuxpeer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
-
-   /etc/frr/ospf:
-      ! ... the rest of ospfd.conf has been omitted for clarity ...
-      !
-      smux peer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
-      !
+:file:`/etc/snmp/snmpd.conf`:
+   #
+   # example access restrictions setup
+   #
+   com2sec readonly default public
+   group MyROGroup v1 readonly
+   view all included .1 80
+   access MyROGroup "" any noauth exact all none none
+   #
+   # the following line is relevant for FRR
+   #
+   smuxpeer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
+
+:file:`/etc/frr/ospf`:
+   ! ... the rest of ospfd.conf has been omitted for clarity ...
+   !
+   smux peer .1.3.6.1.4.1.3317.1.2.5 frr_ospfd
+   !
 
 
 After restarting snmpd and frr, a successful connection can be verified in the
index 9e642a5d4dfbbe4fbac81561ae53ab30eac8c044..4bc6d401225d5959014e902efcf6dc14fb90568e 100644 (file)
@@ -42,7 +42,7 @@ The snmptrap_handle.sh script I personally use for handling BGP4 traps is
 below. You can of course do all sorts of things when handling traps, like sound
 a siren, have your display flash, etc., be creative ;).
 
-::
+.. code-block:: shell
 
    #!/bin/bash
 
index 8be4ff62dea613cb50919acb539b263c11ef6265..ff6050ca688701fe5a0c588edfea8ddfd51419c2 100644 (file)
@@ -90,7 +90,7 @@ Default values are overridden by :ref:`vnc-nve-group-configuration`.
 Enter VNC configuration mode for specifying VNC default behaviors. Use
 `exit-vnc` to leave VNC configuration mode. `vnc defaults` is optional.
 
-::
+.. code-block:: frr
 
    vnc defaults
    ... various VNC defaults
@@ -142,7 +142,7 @@ Defaults section.
   Enter VNC configuration mode for defining the NVE group `name`.
   Use `exit` or `exit-vnc` to exit group configuration mode.
 
-  ::
+  .. code-block:: frr
 
      vnc nve-group group1
      ... configuration commands
@@ -315,7 +315,7 @@ L2 Group Configuration.
    Enter VNC configuration mode for defining the L2 group `name`.
    Use `exit` or `exit-vnc` to exit group configuration mode.
 
-   ::
+   .. code-block:: frr
 
        vnc l2-group group1
          ... configuration commands
@@ -851,7 +851,9 @@ Tunnel Encapsulation Attribute.
 
    A three-way full mesh with three NVEs per NVA.
 
-:file:`bgpd.conf` for ``NVA 1`` (192.168.1.100):::
+:file:`bgpd.conf` for ``NVA 1`` (192.168.1.100):
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -883,7 +885,9 @@ Tunnel Encapsulation Attribute.
 
    exit
 
-:file:`bgpd.conf` for ``NVA 2`` (192.168.1.101):::
+:file:`bgpd.conf` for ``NVA 2`` (192.168.1.101):
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -905,7 +909,9 @@ Tunnel Encapsulation Attribute.
        exit-vnc
    exit
 
-:file:`bgpd.conf` for ``NVA 3`` (192.168.1.102):::
+:file:`bgpd.conf` for ``NVA 3`` (192.168.1.102):
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -959,7 +965,9 @@ registrations exported this way have a next-hop address of the CE behind the
 connected (registering) NVE. Exporting VNC routes as IPv4 unicast is enabled
 with the ``vnc export`` command below.
 
-The configuration for ``VNC-GW 1`` is shown below.::
+The configuration for ``VNC-GW 1`` is shown below.
+
+.. code-block:: frr
 
    router bgp 64512
     bgp router-id 192.168.1.101
@@ -994,7 +1002,9 @@ have a statement disabling the IPv4 unicast address family. IPv4 unicast is on
 by default and this prevents the other VNC-GW and NVAs from learning unicast
 routes advertised by the route-reflector clients.
 
-Configuration for ``NVA 2``:::
+Configuration for ``NVA 2``:
+
+.. code-block:: frr
 
    router bgp 64512
     bgp router-id 192.168.1.104
@@ -1077,7 +1087,9 @@ As in the example of :ref:`vnc-mesh-nva-config`, there are two NVE groups.  The
 7``, and ``NVE 8`` are members of the NVE group ``group1``.  The NVEs ``NVE
 5``, ``NVE 6``, and ``NVE 9`` are members of the NVE group ``group2``.
 
-:file:`bgpd.conf` for ``BGP Route Reflector 1`` on 192.168.1.100:::
+:file:`bgpd.conf` for ``BGP Route Reflector 1`` on 192.168.1.100:
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1106,7 +1118,9 @@ As in the example of :ref:`vnc-mesh-nva-config`, there are two NVE groups.  The
 
    exit
 
-:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1126,28 +1140,30 @@ As in the example of :ref:`vnc-mesh-nva-config`, there are two NVE groups.  The
        exit-vnc
    exit
 
-:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.102:::
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.102:
 
-  router bgp 64512
+.. code-block:: frr
 
-      bgp router-id 192.168.1.102
+   router bgp 64512
 
-      neighbor 192.168.1.100  remote-as 64512
+       bgp router-id 192.168.1.102
 
-      address-family ipv4 vpn
-          neighbor 192.168.1.100 activate
-      exit-address-family
+       neighbor 192.168.1.100  remote-as 64512
 
-      vnc defaults
-          rd 64512:1
-          response-lifetime 200
-          rt both 1000:1 1000:2
-      exit-vnc
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+       exit-address-family
 
-      vnc nve-group group1
-          prefix vn 172.16.128.0/17
-      exit-vnc
-  exit
+       vnc defaults
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+
+       vnc nve-group group1
+           prefix vn 172.16.128.0/17
+       exit-vnc
+   exit
 
 While not shown, an NVA can also be configured as a route reflector.
 
@@ -1218,7 +1234,9 @@ VNC-relevant configuration is provided.
        }
    }
 
-:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1238,7 +1256,9 @@ VNC-relevant configuration is provided.
        exit-vnc
    exit
 
-:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
+:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1277,7 +1297,9 @@ reflector configuration.  BGP route reflectors ``BGP Route Reflector 1`` and
 
    FRR-based NVA with redundant route reflectors
 
-:file:`bgpd.conf` for ``Bgpd Route Reflector 1`` on 192.168.1.100:::
+:file:`bgpd.conf` for ``Bgpd Route Reflector 1`` on 192.168.1.100:
+
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1304,29 +1326,33 @@ reflector configuration.  BGP route reflectors ``BGP Route Reflector 1`` and
     exit-address-family
    exit
 
-:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:
 
-    router bgp 64512
+.. code-block:: frr
 
-     bgp router-id 192.168.1.101
+   router bgp 64512
 
-     neighbor 192.168.1.100  remote-as 64512
-     neighbor 192.168.1.104  remote-as 64512
+    bgp router-id 192.168.1.101
 
-     address-family ipv4 vpn
-      neighbor 192.168.1.100 activate
-      neighbor 192.168.1.104 activate
-     exit-address-family
+    neighbor 192.168.1.100  remote-as 64512
+    neighbor 192.168.1.104  remote-as 64512
 
-     vnc nve-group group1
-      prefix vn 172.16.0.0/17
-      rd 64512:1
-      response-lifetime 200
-      rt both 1000:1 1000:2
-     exit-vnc
-    exit
+    address-family ipv4 vpn
+     neighbor 192.168.1.100 activate
+     neighbor 192.168.1.104 activate
+    exit-address-family
+
+    vnc nve-group group1
+     prefix vn 172.16.0.0/17
+     rd 64512:1
+     response-lifetime 200
+     rt both 1000:1 1000:2
+    exit-vnc
+   exit
+
+:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:
 
-:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
+.. code-block:: frr
 
    router bgp 64512
 
@@ -1417,7 +1443,7 @@ reflector configuration.  BGP route reflectors ``BGP Route Reflector 1`` and
        }
    }
 
-.. [#] The nve-id is carriedin the route distinguisher. It is the second octet
+.. [#] The nve-id is carried in the route distinguisher. It is the second octet
        of the eight-octet route distinguisher generated for Ethernet / L2
        advertisements. The first octet is a constant 0xFF, and the third
        through eighth octets are set to the L2
index 70a69cf0d45b18c09995170d7e544ad9cd357dda..7c886e785e54977d83577c1f7b23f0e6df3e77b8 100644 (file)
@@ -18,19 +18,16 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
 
 .. program:: zebra
 
-.. option:: -b
-.. option:: --batch
+.. option:: -b, --batch
 
    Runs in batch mode. *zebra* parses configuration file and terminates
    immediately.
 
-.. option:: -k
-.. option:: --keep_kernel
+.. option:: -k, --keep_kernel
 
    When zebra starts up, don't delete old self inserted routes.
 
-.. option:: -r
-.. option:: --retain
+.. option:: -r, --retain
 
    When program terminates, retain routes added by zebra.
 
@@ -243,7 +240,8 @@ defines static prefix and gateway.
 
    Some example configuration:
 
-   ::
+   .. code-block:: frr
+
       ip route 10.0.0.0/8 10.0.0.2
       ip route 10.0.0.0/8 ppp0
       ip route 10.0.0.0/8 null0
@@ -259,7 +257,7 @@ defines static prefix and gateway.
    A.B.C.D format, user must define NETMASK value with A.B.C.D
    format. GATEWAY is same option as above command.
 
-   ::
+   .. code-block:: frr
 
       ip route 10.0.0.0 255.255.255.0 10.0.0.2
       ip route 10.0.0.0 255.255.255.0 ppp0
@@ -273,9 +271,9 @@ defines static prefix and gateway.
 
    Installs the route with the specified distance.
 
-Multiple nexthop static route
+Multiple nexthop static route:
 
-::
+.. code-block:: frr
 
    ip route 10.0.0.1/32 10.0.0.2
    ip route 10.0.0.1/32 10.0.0.3
@@ -297,7 +295,7 @@ nexthops, if the platform supports this.
      *       is directly connected, eth0
 
 
-::
+.. code-block:: frr
 
    ip route 10.0.0.0/8 10.0.0.2
    ip route 10.0.0.0/8 10.0.0.3
@@ -376,30 +374,30 @@ unicast topology!
 
    MODE sets the method used to perform RPF lookups. Supported modes:
 
-urib-only
-   Performs the lookup on the Unicast RIB. The Multicast RIB is never used.
+   urib-only
+      Performs the lookup on the Unicast RIB. The Multicast RIB is never used.
 
-mrib-only
-   Performs the lookup on the Multicast RIB. The Unicast RIB is never used.
+   mrib-only
+      Performs the lookup on the Multicast RIB. The Unicast RIB is never used.
 
-mrib-then-urib
-   Tries to perform the lookup on the Multicast RIB. If any route is found,
-   that route is used. Otherwise, the Unicast RIB is tried.
+   mrib-then-urib
+      Tries to perform the lookup on the Multicast RIB. If any route is found,
+      that route is used. Otherwise, the Unicast RIB is tried.
 
-lower-distance
-   Performs a lookup on the Multicast RIB and Unicast RIB each. The result
-   with the lower administrative distance is used;  if they're equal, the
-   Multicast RIB takes precedence.
+   lower-distance
+      Performs a lookup on the Multicast RIB and Unicast RIB each. The result
+      with the lower administrative distance is used;  if they're equal, the
+      Multicast RIB takes precedence.
 
-longer-prefix
-   Performs a lookup on the Multicast RIB and Unicast RIB each. The result
-   with the longer prefix length is used;  if they're equal, the
-   Multicast RIB takes precedence.
+   longer-prefix
+      Performs a lookup on the Multicast RIB and Unicast RIB each. The result
+      with the longer prefix length is used;  if they're equal, the
+      Multicast RIB takes precedence.
 
-   The `mrib-then-urib` setting is the default behavior if nothing is
-   configured. If this is the desired behavior, it should be explicitly
-   configured to make the configuration immune against possible changes in
-   what the default behavior is.
+      The `mrib-then-urib` setting is the default behavior if nothing is
+      configured. If this is the desired behavior, it should be explicitly
+      configured to make the configuration immune against possible changes in
+      what the default behavior is.
 
 .. warning::
    Unreachable routes do not receive special treatment and do not cause
@@ -480,7 +478,7 @@ The following creates a prefix-list that matches all addresses, a route-map
 that sets the preferred source address, and applies the route-map to all
 *rip* routes.
 
-::
+.. code-block:: frr
 
    ip prefix-list ANY permit 0.0.0.0/0 le 32
    route-map RM1 permit 10
index 6bd7d90aef4de859834ccb6b86c5163ede50846b..dd29358b07368e78ab625d79291fc8e979a60e3d 100644 (file)
@@ -23,11 +23,13 @@ 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/APKBUILD /dist/
+COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /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 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
+ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
index e418b403439bbd8d338a634cb13bbfed09fbb774..7dd95b7bc6c860177b8d3dc0209fca72be2efa9e 100644 (file)
@@ -516,7 +516,7 @@ eigrp_snmp_nbr_lookup_next(struct in_addr *nbr_addr, unsigned int *ifindex,
        struct eigrp_neighbor *nbr;
        struct route_node *rn;
        struct eigrp_neighbor *min = NULL;
-       struct eigrp *eigrp = eigrp;
+       struct eigrp *eigrp;
 
        eigrp = eigrp_lookup();
 
index 03202f125307b4d7425db7aba25749cc89254e8d..b573981c1b686d4bc692fe5b1768923abdf221e3 100644 (file)
@@ -429,6 +429,9 @@ in one shot. */
        size_t iovcnt = 0;
        size_t nbyte = 0;
 
+       if (fd < 0)
+               return BUFFER_ERROR;
+
        for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
             d = d->next, iovcnt++) {
                iov[iovcnt].iov_base = d->data + d->sp;
index 530900659b6c9edd2b95a95cc15044d29f3b8ad0..0d6e6ee7e5fc60b0ac55918d38acc258face2219 100644 (file)
@@ -23,6 +23,9 @@
  */
 
 %{
+/* ignore flex generated code in static analyzer */
+#ifndef __clang_analyzer__
+
 /* ignore harmless bugs in old versions of flex */
 #pragma GCC diagnostic ignored "-Wsign-compare"
 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
@@ -91,3 +94,5 @@ void cleanup_lexer (yyscan_t *scn)
   // yy_delete_buffer (buffer, *scn);
   yylex_destroy(*scn);
 }
+
+#endif /* __clang_analyzer__ */
index f6b07a0b20892d4bac482aa512c20cf109d3729a..99ec03e0c2486d3e4a3f9c1aa03b6a35f7bcbd06 100644 (file)
@@ -99,6 +99,9 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
                struct listnode *head = listhead(*argv);
                struct listnode *tail = listtail(*argv);
 
+               assert(head);
+               assert(tail);
+
                // delete dummy start node
                cmd_token_del((struct cmd_token *)head->data);
                list_delete_node(*argv, head);
index 0ea1dd6302bbbe6be333db6da64b5d9549994c24..6419f805abb57c6ed2f568d4ccf05e1dfe29cff1 100644 (file)
@@ -241,6 +241,8 @@ struct ibuf *imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
        struct ibuf *wbuf;
        struct imsg_hdr hdr;
 
+       memset(&hdr, 0x00, IMSG_HEADER_SIZE);
+
        datalen += IMSG_HEADER_SIZE;
        if (datalen > MAX_IMSGSIZE) {
                errno = ERANGE;
index 8d4a3ff8dfced094969453e7d1bde944779bad1e..99311836340993adf117da00a7367014c9254d25 100644 (file)
@@ -531,12 +531,12 @@ struct thread_master *frr_init(void)
                snprintf(p_instance, sizeof(p_instance), "-%d", di->instance);
        }
        if (di->pathspace)
-               snprintf(p_pathspace, sizeof(p_pathspace), "/%s",
+               snprintf(p_pathspace, sizeof(p_pathspace), "%s/",
                         di->pathspace);
 
        snprintf(config_default, sizeof(config_default), "%s%s%s%s.conf",
                 frr_sysconfdir, p_pathspace, di->name, p_instance);
-       snprintf(pidfile_default, sizeof(pidfile_default), "%s%s/%s%s.pid",
+       snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s%s%s.pid",
                 frr_vtydir, p_pathspace, di->name, p_instance);
 
        zprivs_preinit(di->privs);
index f5aff756dde5e2587986c87afa35e3ff5052cb97..dbfc95da86251fd6cbf2925637d2cae4f9b93a5a 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -968,6 +968,10 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_TABLE_MANAGER_CONNECT),
        DESC_ENTRY(ZEBRA_GET_TABLE_CHUNK),
        DESC_ENTRY(ZEBRA_RELEASE_TABLE_CHUNK),
+       DESC_ENTRY(ZEBRA_IPSET_CREATE),
+       DESC_ENTRY(ZEBRA_IPSET_DESTROY),
+       DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
+       DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
 };
 #undef DESC_ENTRY
 
diff --git a/lib/mpls.c b/lib/mpls.c
new file mode 100644 (file)
index 0000000..759fe12
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * mpls functions
+ *
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *                    Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include <mpls.h>
+#include <memory.h>
+
+/*
+ * String to label conversion, labels separated by '/'.
+ *
+ * @param label_str labels separated by /
+ * @param num_labels number of labels; zero if conversion was unsuccessful
+ * @param labels preallocated mpls_label_t array of size MPLS_MAX_LABELS; only
+ *               modified if the conversion succeeded
+ * @return  0 on success
+ *         -1 if the string could not be parsed as integers
+ *         -2 if a label was inside the reserved range (0-15)
+ *         -3 if the number of labels given exceeds MPLS_MAX_LABELS
+ */
+int mpls_str2label(const char *label_str, uint8_t *num_labels,
+                  mpls_label_t *labels)
+{
+       char *ostr;                       // copy of label string (start)
+       char *lstr;                       // copy of label string
+       char *nump;                       // pointer to next segment
+       char *endp;                       // end pointer
+       int i;                            // for iterating label_str
+       int rc;                           // return code
+       mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels
+
+       /* labels to zero until we have a successful parse */
+       ostr = lstr = XSTRDUP(MTYPE_TMP, label_str);
+       *num_labels = 0;
+       rc = 0;
+
+       for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) {
+               nump = strsep(&lstr, "/");
+               pl[i] = strtoul(nump, &endp, 10);
+
+               /* format check */
+               if (*endp != '\0')
+                       rc = -1;
+               /* validity check */
+               else if (!IS_MPLS_UNRESERVED_LABEL(pl[i]))
+                       rc = -2;
+       }
+
+       /* excess labels */
+       if (!rc && i == MPLS_MAX_LABELS && lstr)
+               rc = -3;
+
+       if (!rc) {
+               *num_labels = i;
+               memcpy(labels, pl, *num_labels * sizeof(mpls_label_t));
+       }
+
+       XFREE(MTYPE_TMP, ostr);
+
+       return rc;
+}
+
+/*
+ * Label to string conversion, labels in string separated by '/'.
+ */
+char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+                    int len, int pretty)
+{
+       char label_buf[BUFSIZ];
+       int i;
+
+       buf[0] = '\0';
+       for (i = 0; i < num_labels; i++) {
+               if (i != 0)
+                       strlcat(buf, "/", len);
+               if (pretty)
+                       label2str(labels[i], label_buf, sizeof(label_buf));
+               else
+                       snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
+               strlcat(buf, label_buf, len);
+       }
+
+       return buf;
+}
index 4e5c70cf8cf73be7c44007a5c5d078333bfab2dc..ff6f1d6c98350e303b2110d1efe83bbb4d9121d6 100644 (file)
 #undef MPLS_LABEL_MAX
 #endif
 
+#define MPLS_LABEL_HELPSTR                                                     \
+       "Specify label(s) for this route\nOne or more "                        \
+       "labels in the range (16-1048575) separated by '/'\n"
+
 /* Well-known MPLS label values (RFC 3032 etc). */
 #define MPLS_LABEL_IPV4_EXPLICIT_NULL  0       /* [RFC3032] */
 #define MPLS_LABEL_ROUTER_ALERT        1       /* [RFC3032] */
@@ -192,5 +196,16 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
        }
 }
 
+/*
+ * String to label conversion, labels separated by '/'.
+ */
+int mpls_str2label(const char *label_str, uint8_t *num_labels,
+                  mpls_label_t *labels);
+
+/*
+ * Label to string conversion, labels in string separated by '/'.
+ */
+char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+                    int len, int pretty);
 
 #endif
index 3d61cecc03e94d7d9dbc0267fae01d088db04a08..a3fae8f39fab05a591a12acf35af9d9c1a651e77 100644 (file)
@@ -59,6 +59,26 @@ static int ns_default_ns_fd;
 
 static int ns_debug;
 
+struct ns_map_nsid {
+       RB_ENTRY(ns_map_nsid) id_entry;
+       ns_id_t ns_id_external;
+       ns_id_t ns_id;
+};
+
+static inline int ns_map_compare(const struct ns_map_nsid *a,
+                                  const struct ns_map_nsid *b)
+{
+       return (a->ns_id - b->ns_id);
+}
+
+RB_HEAD(ns_map_nsid_head, ns_map_nsid);
+RB_PROTOTYPE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
+RB_GENERATE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
+struct ns_map_nsid_head ns_map_nsid_list = RB_INITIALIZER(&ns_map_nsid_list);
+
+static ns_id_t ns_id_external_numbering;
+
+
 #ifndef CLONE_NEWNET
 #define CLONE_NEWNET 0x40000000
 /* New network namespace (lo, device, names sockets, etc) */
@@ -262,6 +282,38 @@ static void ns_disable_internal(struct ns *ns)
        }
 }
 
+/* VRF list existance check by name. */
+static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id)
+{
+       struct ns_map_nsid ns_map;
+
+       ns_map.ns_id = ns_id;
+       return RB_FIND(ns_map_nsid_head, &ns_map_nsid_list, &ns_map);
+}
+
+ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool map)
+{
+       struct ns_map_nsid *ns_map;
+       vrf_id_t ns_id_external;
+
+       ns_map = ns_map_nsid_lookup_by_nsid(ns_id);
+       if (ns_map && !map) {
+               ns_id_external = ns_map->ns_id_external;
+               RB_REMOVE(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
+               return ns_id_external;
+       }
+       if (ns_map)
+               return ns_map->ns_id_external;
+       ns_map = XCALLOC(MTYPE_NS, sizeof(struct ns_map_nsid));
+       /* increase vrf_id
+        * default vrf is the first one : 0
+        */
+       ns_map->ns_id_external = ns_id_external_numbering++;
+       ns_map->ns_id = ns_id;
+       RB_INSERT(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
+       return ns_map->ns_id_external;
+}
+
 struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id)
 {
        return ns_get_created_internal(ns, name, ns_id);
@@ -430,7 +482,7 @@ void ns_init(void)
 }
 
 /* Initialize NS module. */
-void ns_init_management(ns_id_t default_ns_id)
+void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
 {
        int fd;
 
@@ -444,6 +496,8 @@ void ns_init_management(ns_id_t default_ns_id)
                fd = open(NS_DEFAULT_NAME, O_RDONLY);
                default_ns->fd = fd;
        }
+       default_ns->internal_ns_id = internal_ns;
+
        /* Set the default NS name. */
        default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME);
        if (ns_debug)
index 2402dd17d6e6909bd52f6b3cff606c3ce2902169..4c7be05fab2524b393fb8e3c34cae919fa5b7afe 100644 (file)
@@ -153,6 +153,11 @@ int ns_enable(struct ns *ns, int (*func)(ns_id_t, void *))
        return 0;
 }
 
+ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool maporunmap)
+{
+       return NS_UNKNOWN;
+}
+
 struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id)
 {
        return NULL;
index 1ec49c2a02766a384c4d60d47c0a6bfa20c9ae83..5ac38d66853cc91a09aa4ebca1ff008c8ba00ad5 100644 (file)
@@ -20,6 +20,7 @@
 #include <zebra.h>
 
 #include <vrf.h>
+#include <sockunion.h>
 #include <nexthop.h>
 #include <nexthop_group.h>
 #include <vty.h>
@@ -112,6 +113,9 @@ void nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
 
        if (nexthop->next)
                nexthop->next->prev = nexthop->prev;
+
+       nh->prev = NULL;
+       nh->next = NULL;
 }
 
 void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
@@ -151,6 +155,7 @@ static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
        while (nexthop) {
                struct nexthop *next = nexthop_next(nexthop);
 
+               nexthop_del(&nhgc->nhg, nexthop);
                if (nhg_hooks.del_nexthop)
                        nhg_hooks.del_nexthop(nhgc, nexthop);
 
@@ -169,6 +174,46 @@ struct nexthop_group_cmd *nhgc_find(const char *name)
        return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
 }
 
+static int nhgc_cmp_helper(const char *a, const char *b)
+{
+       if (!a && !b)
+               return 0;
+
+       if (a && !b)
+               return -1;
+
+       if (!a && b)
+               return 1;
+
+       return strcmp(a, b);
+}
+
+static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
+{
+       int ret;
+
+       ret = sockunion_cmp(&nh1->addr, &nh2->addr);
+       if (ret)
+               return ret;
+
+       ret = nhgc_cmp_helper(nh1->intf, nh2->intf);
+       if (ret)
+               return ret;
+
+       return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+}
+
+static void nhgl_delete(struct nexthop_hold *nh)
+{
+       if (nh->intf)
+               XFREE(MTYPE_TMP, nh->intf);
+
+       if (nh->nhvrf_name)
+               XFREE(MTYPE_TMP, nh->nhvrf_name);
+
+       XFREE(MTYPE_TMP, nh);
+}
+
 static struct nexthop_group_cmd *nhgc_get(const char *name)
 {
        struct nexthop_group_cmd *nhgc;
@@ -181,6 +226,10 @@ static struct nexthop_group_cmd *nhgc_get(const char *name)
                QOBJ_REG(nhgc, nexthop_group_cmd);
                RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
 
+               nhgc->nhg_list = list_new();
+               nhgc->nhg_list->cmp = (int (*)(void *, void *))nhgl_cmp;
+               nhgc->nhg_list->del = (void (*)(void *))nhgl_delete;
+
                if (nhg_hooks.new)
                        nhg_hooks.new(name);
        }
@@ -196,6 +245,10 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc)
                nhg_hooks.delete(nhgc->name);
 
        RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
+
+       list_delete_and_null(&nhgc->nhg_list);
+
+       XFREE(MTYPE_TMP, nhgc);
 }
 
 DEFINE_QOBJ_TYPE(nexthop_group_cmd)
@@ -228,65 +281,125 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME",
        return CMD_SUCCESS;
 }
 
-DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
-      "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
-      NO_STR
-      "Specify one of the nexthops in this ECMP group\n"
-      "v4 Address\n"
-      "v6 Address\n"
-      "Interface to use\n"
-      "If the nexthop is in a different vrf tell us\n"
-      "The nexthop-vrf Name\n")
+static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
+                                   const char *nhvrf_name,
+                                   const union sockunion *addr,
+                                   const char *intf)
+{
+       struct nexthop_hold *nh;
+
+       nh = XCALLOC(MTYPE_TMP, sizeof(*nh));
+
+       if (nhvrf_name)
+               nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
+       if (intf)
+               nh->intf = XSTRDUP(MTYPE_TMP, intf);
+
+       nh->addr = *addr;
+
+       listnode_add_sort(nhgc->nhg_list, nh);
+}
+
+static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
+                                     const char *nhvrf_name,
+                                     const union sockunion *addr,
+                                     const char *intf)
+{
+       struct nexthop_hold *nh;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
+               if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
+                   sockunion_cmp(addr, &nh->addr) == 0 &&
+                   nhgc_cmp_helper(intf, nh->intf) == 0)
+                       break;
+       }
+
+       /*
+        * Something has gone seriously wrong, fail gracefully
+        */
+       if (!nh)
+               return;
+
+       list_delete_node(nhgc->nhg_list, node);
+
+       if (nh->nhvrf_name)
+               XFREE(MTYPE_TMP, nh->nhvrf_name);
+       if (nh->intf)
+               XFREE(MTYPE_TMP, nh->intf);
+
+       XFREE(MTYPE_TMP, nh);
+}
+
+static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
+                                       const union sockunion *addr,
+                                       const char *intf, const char *name)
 {
-       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
        struct vrf *vrf;
-       struct nexthop nhop;
-       struct nexthop *nh;
+
+       memset(nhop, 0, sizeof(*nhop));
 
        if (name)
                vrf = vrf_lookup_by_name(name);
        else
                vrf = vrf_lookup_by_id(VRF_DEFAULT);
 
-       if (!vrf) {
-               vty_out(vty, "Specified: %s is non-existent\n", name);
-               return CMD_WARNING;
-       }
+       if (!vrf)
+               return false;
 
-       memset(&nhop, 0, sizeof(nhop));
-       nhop.vrf_id = vrf->vrf_id;
+       nhop->vrf_id = vrf->vrf_id;
 
        if (addr->sa.sa_family == AF_INET) {
-               nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+               nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
                if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING;
-                       }
+                       nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+                       if (nhop->ifindex == IFINDEX_INTERNAL)
+                               return false;
                } else
-                       nhop.type = NEXTHOP_TYPE_IPV4;
+                       nhop->type = NEXTHOP_TYPE_IPV4;
        } else {
-               memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
+               memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
                if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING;
-                       }
+                       nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+                       if (nhop->ifindex == IFINDEX_INTERNAL)
+                               return false;
                } else
-                       nhop.type = NEXTHOP_TYPE_IPV6;
+                       nhop->type = NEXTHOP_TYPE_IPV6;
+       }
+
+       return true;
+}
+
+DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
+      "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+      NO_STR
+      "Specify one of the nexthops in this ECMP group\n"
+      "v4 Address\n"
+      "v6 Address\n"
+      "Interface to use\n"
+      "If the nexthop is in a different vrf tell us\n"
+      "The nexthop-vrf Name\n")
+{
+       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+       struct nexthop nhop;
+       struct nexthop *nh;
+       bool legal;
+
+       legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
+
+       if (nhop.type == NEXTHOP_TYPE_IPV6
+           && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+               vty_out(vty,
+                       "Specified a v6 LL with no interface, rejecting\n");
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        nh = nexthop_exists(&nhgc->nhg, &nhop);
 
        if (no) {
+               nexthop_group_unsave_nhop(nhgc, name, addr, intf);
                if (nh) {
                        nexthop_del(&nhgc->nhg, nh);
 
@@ -297,12 +410,16 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
                }
        } else if (!nh) {
                /* must be adding new nexthop since !no and !nexthop_exists */
-               nh = nexthop_new();
+               if (legal) {
+                       nh = nexthop_new();
+
+                       memcpy(nh, &nhop, sizeof(nhop));
+                       nexthop_add(&nhgc->nhg.nexthop, nh);
+               }
 
-               memcpy(nh, &nhop, sizeof(nhop));
-               nexthop_add(&nhgc->nhg.nexthop, nh);
+               nexthop_group_save_nhop(nhgc, name, addr, intf);
 
-               if (nhg_hooks.add_nexthop)
+               if (legal && nhg_hooks.add_nexthop)
                        nhg_hooks.add_nexthop(nhgc, nh);
        }
 
@@ -353,17 +470,37 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
        vty_out(vty, "\n");
 }
 
+static void nexthop_group_write_nexthop_internal(struct vty *vty,
+                                                struct nexthop_hold *nh)
+{
+       char buf[100];
+
+       vty_out(vty, "nexthop ");
+
+       vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
+
+       if (nh->intf)
+               vty_out(vty, " %s", nh->intf);
+
+       if (nh->nhvrf_name)
+               vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
+
+       vty_out(vty, "\n");
+}
+
 static int nexthop_group_write(struct vty *vty)
 {
        struct nexthop_group_cmd *nhgc;
-       struct nexthop *nh;
+       struct nexthop_hold *nh;
 
        RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
                vty_out(vty, "nexthop-group %s\n", nhgc->name);
 
-               for (nh = nhgc->nhg.nexthop; nh; nh = nh->next) {
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
                        vty_out(vty, "  ");
-                       nexthop_group_write_nexthop(vty, nh);
+                       nexthop_group_write_nexthop_internal(vty, nh);
                }
 
                vty_out(vty, "!\n");
@@ -372,6 +509,152 @@ static int nexthop_group_write(struct vty *vty)
        return 1;
 }
 
+void nexthop_group_enable_vrf(struct vrf *vrf)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                       struct nexthop nhop;
+                       struct nexthop *nh;
+
+                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                                                        nhh->intf,
+                                                        nhh->nhvrf_name))
+                               continue;
+
+                       nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                       if (nh)
+                               continue;
+
+                       if (nhop.vrf_id != vrf->vrf_id)
+                               continue;
+
+                       nh = nexthop_new();
+
+                       memcpy(nh, &nhop, sizeof(nhop));
+                       nexthop_add(&nhgc->nhg.nexthop, nh);
+
+                       if (nhg_hooks.add_nexthop)
+                               nhg_hooks.add_nexthop(nhgc, nh);
+               }
+       }
+}
+
+void nexthop_group_disable_vrf(struct vrf *vrf)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+
+               for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                       struct nexthop nhop;
+                       struct nexthop *nh;
+
+                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                                                        nhh->intf,
+                                                        nhh->nhvrf_name))
+                               continue;
+
+                       nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                       if (!nh)
+                               continue;
+
+                       if (nh->vrf_id != vrf->vrf_id)
+                               continue;
+
+                       nexthop_del(&nhgc->nhg, nh);
+
+                       if (nhg_hooks.del_nexthop)
+                               nhg_hooks.del_nexthop(nhgc, nh);
+
+                       nexthop_free(nh);
+               }
+       }
+}
+
+void nexthop_group_interface_state_change(struct interface *ifp,
+                                         ifindex_t oldifindex)
+{
+       struct nexthop_group_cmd *nhgc;
+       struct nexthop_hold *nhh;
+
+       RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
+               struct listnode *node;
+               struct nexthop *nh;
+
+               if (if_is_up(ifp)) {
+                       for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
+                               struct nexthop nhop;
+
+                               if (!nexthop_group_parse_nexthop(
+                                           &nhop, &nhh->addr, nhh->intf,
+                                           nhh->nhvrf_name))
+                                       continue;
+
+                               switch (nhop.type) {
+                               case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV6:
+                               case NEXTHOP_TYPE_BLACKHOLE:
+                                       continue;
+                               case NEXTHOP_TYPE_IFINDEX:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                                       break;
+                               }
+                               nh = nexthop_exists(&nhgc->nhg, &nhop);
+
+                               if (nh)
+                                       continue;
+
+                               if (ifp->ifindex != nhop.ifindex)
+                                       continue;
+
+                               nh = nexthop_new();
+
+                               memcpy(nh, &nhop, sizeof(nhop));
+                               nexthop_add(&nhgc->nhg.nexthop, nh);
+
+                               if (nhg_hooks.add_nexthop)
+                                       nhg_hooks.add_nexthop(nhgc, nh);
+                       }
+               } else {
+                       struct nexthop *next_nh;
+
+                       for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
+                               next_nh = nh->next;
+                               switch (nh->type) {
+                               case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV6:
+                               case NEXTHOP_TYPE_BLACKHOLE:
+                                       continue;
+                               case NEXTHOP_TYPE_IFINDEX:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                                       break;
+                               }
+
+                               if (oldifindex != nh->ifindex)
+                                       continue;
+
+                               nexthop_del(&nhgc->nhg, nh);
+
+                               if (nhg_hooks.del_nexthop)
+                                       nhg_hooks.del_nexthop(nhgc, nh);
+
+                               nexthop_free(nh);
+                       }
+               }
+       }
+}
+
 void nexthop_group_init(void (*new)(const char *name),
                        void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
                                            const struct nexthop *nhop),
index c2e4c4d7573cc46998fc2cc94398f2bb7bb312e1..a44f4e35426e65f21b072d0347975d7a3fa43af5 100644 (file)
@@ -56,6 +56,13 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
        (nhop);                                                         \
        (nhop) = nexthop_next(nhop)
 
+
+struct nexthop_hold {
+       char *nhvrf_name;
+       union sockunion addr;
+       char *intf;
+};
+
 struct nexthop_group_cmd {
 
        RB_ENTRY(nexthop_group_cmd) nhgc_entry;
@@ -64,6 +71,8 @@ struct nexthop_group_cmd {
 
        struct nexthop_group nhg;
 
+       struct list *nhg_list;
+
        QOBJ_FIELDS
 };
 RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
@@ -85,6 +94,11 @@ void nexthop_group_init(
                            const struct nexthop *nhop),
        void (*delete)(const char *name));
 
+void nexthop_group_enable_vrf(struct vrf *vrf);
+void nexthop_group_disable_vrf(struct vrf *vrf);
+void nexthop_group_interface_state_change(struct interface *ifp,
+                                         ifindex_t oldifindex);
+
 extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
                                      struct nexthop *nh);
 
index fac91a40da1c88a167e6d78472216290515f13f6..b3810f069b46b8914b24c565b5c8daa524247990 100644 (file)
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -46,6 +46,9 @@ struct ns {
        /* Identifier, same as the vector index */
        ns_id_t ns_id;
 
+       /* Identifier, mapped on the NSID value */
+       ns_id_t internal_ns_id;
+
        /* Name */
        char *name;
 
@@ -100,7 +103,7 @@ extern void ns_terminate(void);
 /* API to initialize NETNS managerment
  * parameter is the default ns_id
  */
-extern void ns_init_management(ns_id_t ns_id);
+extern void ns_init_management(ns_id_t ns_id, ns_id_t internal_ns_idx);
 
 
 /*
@@ -133,6 +136,11 @@ extern int ns_have_netns(void);
 /* API to get context information of a NS */
 extern void *ns_info_lookup(ns_id_t ns_id);
 
+/* API to map internal ns id value with
+ * user friendly ns id external value
+ */
+extern ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool map);
+
 /*
  * NS init routine
  * should be called from backendx
diff --git a/lib/pbr.h b/lib/pbr.h
new file mode 100644 (file)
index 0000000..b49cb56
--- /dev/null
+++ b/lib/pbr.h
@@ -0,0 +1,86 @@
+/* Policy Based Routing (PBR) main header
+ * Copyright (C) 2018 6WIND
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _PBR_H
+#define _PBR_H
+
+/*
+ * A PBR filter
+ *
+ * The filter or match criteria in a PBR rule.
+ * For simplicity, all supported filters are grouped into a structure rather
+ * than delineating further. A bitmask denotes which filters are actually
+ * specified.
+ */
+struct pbr_filter {
+       uint32_t filter_bm; /* not encoded by zapi
+                            */
+#define PBR_FILTER_SRC_IP     (1 << 0)
+#define PBR_FILTER_DST_IP     (1 << 1)
+#define PBR_FILTER_SRC_PORT   (1 << 2)
+#define PBR_FILTER_DST_PORT   (1 << 3)
+#define PBR_FILTER_FWMARK     (1 << 4)
+
+       /* Source and Destination IP address with masks. */
+       struct prefix src_ip;
+       struct prefix dst_ip;
+
+       /* Source and Destination higher-layer (TCP/UDP) port numbers. */
+       uint16_t src_port;
+       uint16_t dst_port;
+
+       /* Filter with fwmark */
+       uint32_t fwmark;
+};
+
+/*
+ * A PBR action
+ *
+ * The action corresponding to a PBR rule.
+ * While the user specifies the action in a particular way, the forwarding
+ * plane implementation (Linux only) requires that to be encoded into a
+ * route table and the rule then point to that route table; in some cases,
+ * the user criteria may directly point to a table too.
+ */
+struct pbr_action {
+       uint32_t table;
+};
+
+/*
+ * A PBR rule
+ *
+ * This is a combination of the filter criteria and corresponding action.
+ * Rules also have a user-defined sequence number which defines the relative
+ * order amongst rules.
+ */
+struct pbr_rule {
+       vrf_id_t vrf_id;
+
+       uint32_t seq;
+       uint32_t priority;
+       uint32_t unique;
+       struct pbr_filter filter;
+       struct pbr_action action;
+       uint32_t ifindex;
+};
+
+extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
+                               struct pbr_rule *zrule);
+
+#endif /* _PBR_H */
index 9d50acaaeda8bb9c9e9e6a0a85cd00680e73d605..66384fe4492af8e3f59037dbf7c178557308e295 100755 (executable)
@@ -54,15 +54,15 @@ while (<STDIN>) {
 
        $_ =~ s/\s*,\s*/,/g;
 
-       # else: 7-field line
+       # else: 8-field line
        my @f = split(/,/, $_);
-       unless (@f == 7 || @f == 8) {
+       unless (@f == 8 || @f == 9) {
                die "invalid input on route_types line $.\n";
        }
 
        my $proto = $f[0];
        $f[3] = $1 if ($f[3] =~ /^'(.*)'$/);
-       $f[6] = $1 if ($f[6] =~ /^"(.*)"$/);
+       $f[7] = $1 if ($f[7] =~ /^"(.*)"$/);
 
        $protodetail{$proto} = {
                "number" => scalar @protos,
@@ -72,8 +72,9 @@ while (<STDIN>) {
                "char" => $f[3],
                "ipv4" => int($f[4]),
                "ipv6" => int($f[5]),
-               "shorthelp" => $f[6],
-               "restrict2" => $f[7],
+               "redist" => int($f[6]),
+               "shorthelp" => $f[7],
+               "restrict2" => $f[8],
        };
        push @protos, $proto;
        $daemons{$f[2]} = {
@@ -136,8 +137,9 @@ sub collect {
                next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra");
                next if ($protodetail{$p}->{"restrict2"} ne "" && 
                         $protodetail{$p}->{"restrict2"} ne $daemon);
+               next if ($protodetail{$p}->{"redist"} eq 0);
                next unless (($ipv4 && $protodetail{$p}->{"ipv4"})
-                               || ($ipv6 && $protodetail{$p}->{"ipv6"}));
+                            || ($ipv6 && $protodetail{$p}->{"ipv6"}));
                push @names, $protodetail{$p}->{"cname"};
                push @help, "  \"".$protodetail{$p}->{"longhelp"}."\\n\"";
        }
index 91eaf94d958bbf4c0854131f54217d89a82d4992..cfa55e468cd328b4fdb55bc36de93aa2a7419866 100644 (file)
@@ -7,8 +7,8 @@
 # Lines /beginning/ with # are comments.
 #
 ####
-# 7 field line has format:
-# ZServ route type, canonical name, daemon, route char, ipv4, ipv6, short desc
+# 9 field line has format:
+# ZServ route type, canonical name, daemon, route char, ipv4, ipv6, redist, short desc, Restrictions
 #
 # Zserv route type:    Corresponding with zebra.h. Key field.
 # canonical name:      Typically derived from the route type definition.
 #                      'X' is reserved as the 'not needed' placeholder.
 # ipv4:                        IPv4 capable? yes/no, or 1/0.
 # ipv6:                        IPv6 capable? ditto.
+# redist:               Allow this protocol to be used in redistribution statements
 # short desc:          Very brief description. Used in header of
 #                      'show ip route'. May be specified as NULL
 #                      if the canonical name suffices.
+# Restriction:          If this cannot be used with the listed protocol for redistribution events
 #
 # Key fields obviously must be a unique ASCII alpha-numeric word.
 #   Lower-case is required, brevity is optional but highly desirable.
 # If you add a new routing protocol here, make sure you also update
 # meta_queue_map in zebra_rib.c
 #
-##  type                cname      daemon  C    4  6  short help
-ZEBRA_ROUTE_SYSTEM,     system,    NULL,   'X', 0, 0, "Reserved"
-ZEBRA_ROUTE_KERNEL,     kernel,    zebra,  'K', 1, 1, "kernel route"
-ZEBRA_ROUTE_CONNECT,    connected, zebra,  'C', 1, 1, "connected"
-ZEBRA_ROUTE_STATIC,     static,    zebra,  'S', 1, 1, "static"
-ZEBRA_ROUTE_RIP,        rip,       ripd,   'R', 1, 0, "RIP"
-ZEBRA_ROUTE_RIPNG,      ripng,     ripngd, 'R', 0, 1, "RIPng"
-ZEBRA_ROUTE_OSPF,       ospf,      ospfd,  'O', 1, 0, "OSPF"
-ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, "OSPFv3"
-ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, "IS-IS"
-ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, "BGP"
-ZEBRA_ROUTE_PIM,       pim,       pimd,   'P', 1, 0, "PIM"
-ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'E', 1, 0, "EIGRP"
-ZEBRA_ROUTE_NHRP,       nhrp,      nhrpd,  'N', 1, 1, "NHRP"
+##  type                cname      daemon  C    4  6  Redist short help  Restrictions
+ZEBRA_ROUTE_SYSTEM,     system,    NULL,   'X', 0, 0, 0,     "Reserved"
+ZEBRA_ROUTE_KERNEL,     kernel,    zebra,  'K', 1, 1, 1,     "kernel route"
+ZEBRA_ROUTE_CONNECT,    connected, zebra,  'C', 1, 1, 1,     "connected"
+ZEBRA_ROUTE_STATIC,     static,    zebra,  'S', 1, 1, 1,     "static"
+ZEBRA_ROUTE_RIP,        rip,       ripd,   'R', 1, 0, 1,     "RIP"
+ZEBRA_ROUTE_RIPNG,      ripng,     ripngd, 'R', 0, 1, 1,     "RIPng"
+ZEBRA_ROUTE_OSPF,       ospf,      ospfd,  'O', 1, 0, 1,     "OSPF"
+ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, 1,     "OSPFv3"
+ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, 1,     "IS-IS"
+ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, 1,     "BGP"
+ZEBRA_ROUTE_PIM,       pim,       pimd,   'P', 0, 0, 0,     "PIM"
+ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'E', 1, 0, 1,     "EIGRP"
+ZEBRA_ROUTE_NHRP,       nhrp,      nhrpd,  'N', 1, 1, 1,     "NHRP"
 # HSLS and OLSR both are AFI independent (so: 1, 1), however
 # we want to disable for them for general Quagga distribution.
 # This at least makes it trivial for users of these protocols
 # to 'switch on' redist support (direct numeric entry remaining
 # possible).
-ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, "HSLS"
-ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, "OLSR"
-ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, "Table"
-ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, "LDP"
+ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, 0,     "HSLS"
+ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, 0,     "OLSR"
+ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, 1,     "Table"
+ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, 0,     "LDP"
 #vnc when sent to zebra 
-ZEBRA_ROUTE_VNC,        vnc,       NULL,   'v', 1, 1, "VNC"
+ZEBRA_ROUTE_VNC,        vnc,       NULL,   'v', 1, 1, 1,     "VNC"
 # vnc when sent to bgp
-ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL,   'V', 1, 1, "VNC-Direct", bgpd
+ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL,   'V', 1, 1, 1,     "VNC-Direct", bgpd
 # vnc when sent to bgp (resolve NVE mode)
-ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL,   'V', 0, 0, "VNC-RN"
+ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL,   'V', 0, 0, 0,     "VNC-RN"
 #  bgp unicast -> vnc 
-ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL,  'b', 0, 0, "BGP-Direct"
+ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL,  'b', 0, 0, 0,     "BGP-Direct"
 #  bgp unicast -> vnc 
-ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
-ZEBRA_ROUTE_BABEL,      babel,     babeld, 'A', 1, 1, "Babel"
-ZEBRA_ROUTE_SHARP,    sharp,     sharpd, 'D', 1, 1, "SHARP"
-ZEBRA_ROUTE_PBR,      pbr,       pbrd, 'F', 1, 1, "PBR"
-ZEBRA_ROUTE_ALL,        wildcard,  none,   '-', 0, 0, "-"
+ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2VNC"
+ZEBRA_ROUTE_BABEL,      babel,     babeld, 'A', 1, 1, 1,     "Babel"
+ZEBRA_ROUTE_SHARP,      sharp,     sharpd, 'D', 1, 1, 1,     "SHARP"
+ZEBRA_ROUTE_PBR,        pbr,       pbrd,   'F', 1, 1, 0,     "PBR"
+ZEBRA_ROUTE_ALL,        wildcard,  none,   '-', 0, 0, 0,     "-"
 
 
 ## help strings
index 7d85b7a24dae3f7592b385f97598c0cf29cc15e7..3b469d4524216d46df56019de6cc9b3f22a857b4 100644 (file)
@@ -41,6 +41,7 @@ lib_libfrr_la_SOURCES = \
        lib/memory.c \
        lib/memory_vty.c \
        lib/module.c \
+       lib/mpls.c \
        lib/network.c \
        lib/nexthop.c \
        lib/netns_linux.c \
@@ -167,6 +168,7 @@ pkginclude_HEADERS += \
        lib/zclient.h \
        lib/zebra.h \
        lib/logicalrouter.h \
+       lib/pbr.h \
        # end
 
 nodist_pkginclude_HEADERS += \
index 1ed96cd0a4e169389f2c511bf11b99260d179fe0..db539d375dda73bb015363528af9ec10116c0565 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -34,6 +34,7 @@
 #include "command.h"
 #include "ns.h"
 #include "privs.h"
+#include "nexthop_group.h"
 
 /* default VRF ID value used when VRF backend is not NETNS */
 #define VRF_DEFAULT_INTERNAL 0
@@ -159,11 +160,13 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
        if (!name && vrf_id == VRF_UNKNOWN)
                return NULL;
 
+       /* attempt to find already available VRF
+        */
+       if (name)
+               vrf = vrf_lookup_by_name(name);
        /* Try to find VRF both by ID and name */
-       if (vrf_id != VRF_UNKNOWN)
+       if (!vrf && vrf_id != VRF_UNKNOWN)
                vrf = vrf_lookup_by_id(vrf_id);
-       if (!vrf && name)
-               vrf = vrf_lookup_by_name(name);
 
        if (vrf == NULL) {
                vrf = XCALLOC(MTYPE_VRF, sizeof(struct vrf));
@@ -267,6 +270,13 @@ int vrf_enable(struct vrf *vrf)
        if (vrf_master.vrf_enable_hook)
                (*vrf_master.vrf_enable_hook)(vrf);
 
+       /*
+        * If we have any nexthop group entries that
+        * are awaiting vrf initialization then
+        * let's let people know about it
+        */
+       nexthop_group_enable_vrf(vrf);
+
        return 1;
 }
 
@@ -537,7 +547,8 @@ void vrf_configure_backend(int vrf_backend_netns)
        vrf_backend = vrf_backend_netns;
 }
 
-int vrf_handler_create(struct vty *vty, const char *vrfname, struct vrf **vrf)
+int vrf_handler_create(struct vty *vty, const char *vrfname,
+                      struct vrf **vrf)
 {
        struct vrf *vrfp;
 
@@ -564,7 +575,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, struct vrf **vrf)
 }
 
 int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
-                            ns_id_t ns_id)
+                            ns_id_t ns_id, ns_id_t internal_ns_id)
 {
        struct ns *ns = NULL;
 
@@ -611,6 +622,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
                return CMD_WARNING_CONFIG_FAILED;
        }
        ns = ns_get_created(ns, pathname, ns_id);
+       ns->internal_ns_id = internal_ns_id;
        ns->vrf_ctxt = (void *)vrf;
        vrf->ns_ctxt = (void *)ns;
        /* update VRF netns NAME */
@@ -716,7 +728,8 @@ DEFUN_NOSH (vrf_netns,
            vrf_daemon_privs->change(ZPRIVS_RAISE))
                zlog_err("%s: Can't raise privileges", __func__);
 
-       ret = vrf_netns_handler_create(vty, vrf, pathname, NS_UNKNOWN);
+       ret = vrf_netns_handler_create(vty, vrf, pathname,
+                                      NS_UNKNOWN, NS_UNKNOWN);
 
        if (vrf_daemon_privs &&
            vrf_daemon_privs->change(ZPRIVS_LOWER))
@@ -825,6 +838,9 @@ vrf_id_t vrf_get_default_id(void)
 
        if (vrf)
                return vrf->vrf_id;
+       /* backend netns is only known by zebra
+        * for other daemons, we return VRF_DEFAULT_INTERNAL
+        */
        if (vrf_is_backend_netns())
                return ns_get_default_id();
        else
index 85a5309279b8e7c47e2250010c55115f5867cdc6..8aa0fc2215b2d938e9a860db3e612d42413e1b85 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -272,7 +272,8 @@ extern int vrf_handler_create(struct vty *vty, const char *name,
  * should be called from zebra only
  */
 extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
-                                   char *pathname, ns_id_t ns_id);
+                                   char *pathname, ns_id_t ext_ns_id,
+                                   ns_id_t ns_id);
 
 /* used internally to enable or disable VRF.
  * Notify a change in the VRF ID of the VRF
index d23f62dcd72732526c439772a14d777d10bec93e..48182d6b2c515652e8c176a30eb1f501a2058a96 100644 (file)
@@ -36,6 +36,8 @@
 #include "nexthop.h"
 #include "mpls.h"
 #include "sockopt.h"
+#include "pbr.h"
+#include "nexthop_group.h"
 
 DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
 DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -1229,6 +1231,55 @@ stream_failure:
        return 0;
 }
 
+static void zapi_encode_prefix(struct stream *s,
+                             struct prefix *p,
+                             uint8_t family)
+{
+       struct prefix any;
+
+       if (!p) {
+               memset(&any, 0, sizeof(any));
+               any.family = family;
+               p = &any;
+       }
+
+       stream_putc(s, p->family);
+       stream_putc(s, p->prefixlen);
+       stream_put(s, &p->u.prefix, prefix_blen(p));
+}
+
+int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
+                        struct pbr_rule *zrule)
+{
+       stream_reset(s);
+       zclient_create_header(s, cmd, zrule->vrf_id);
+
+       /*
+        * We are sending one item at a time at the moment
+        */
+       stream_putl(s, 1);
+
+       stream_putl(s, zrule->seq);
+       stream_putl(s, zrule->priority);
+       stream_putl(s, zrule->unique);
+
+       zapi_encode_prefix(s, &(zrule->filter.src_ip),
+                          zrule->filter.src_ip.family);
+       stream_putw(s, zrule->filter.src_port);  /* src port */
+       zapi_encode_prefix(s, &(zrule->filter.dst_ip),
+                          zrule->filter.src_ip.family);
+       stream_putw(s, zrule->filter.dst_port);  /* dst port */
+       stream_putw(s, zrule->filter.fwmark);    /* fwmark */
+
+       stream_putl(s, zrule->action.table);
+       stream_putl(s, zrule->ifindex);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
 bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
                              uint32_t *tableid,
                              enum zapi_route_notify_owner *note)
@@ -1279,6 +1330,50 @@ stream_failure:
        return false;
 }
 
+bool zapi_ipset_notify_decode(struct stream *s,
+                             uint32_t *unique,
+                            enum zapi_ipset_notify_owner *note)
+{
+       uint32_t uni;
+
+       STREAM_GET(note, s, sizeof(*note));
+
+       STREAM_GETL(s, uni);
+
+       if (zclient_debug)
+               zlog_debug("%s: %u", __PRETTY_FUNCTION__, uni);
+       *unique = uni;
+
+       return true;
+
+stream_failure:
+       return false;
+}
+
+bool zapi_ipset_entry_notify_decode(struct stream *s,
+               uint32_t *unique,
+               char *ipset_name,
+               enum zapi_ipset_entry_notify_owner *note)
+{
+       uint32_t uni;
+
+       STREAM_GET(note, s, sizeof(*note));
+
+       STREAM_GETL(s, uni);
+
+       STREAM_GET(ipset_name, s,
+                  ZEBRA_IPSET_NAME_SIZE);
+
+       if (zclient_debug)
+               zlog_debug("%s: %u", __PRETTY_FUNCTION__, uni);
+       *unique = uni;
+
+       return true;
+
+stream_failure:
+       return false;
+}
+
 struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
 {
        struct nexthop *n = nexthop_new();
@@ -1603,7 +1698,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
 void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
 {
        uint8_t link_params_status = 0;
+       ifindex_t old_ifindex;
 
+       old_ifindex = ifp->ifindex;
        /* Read interface's index. */
        if_set_index(ifp, stream_getl(s));
        ifp->status = stream_getc(s);
@@ -1630,6 +1727,8 @@ void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
                struct if_link_params *iflp = if_link_params_get(ifp);
                link_params_set_value(s, iflp);
        }
+
+       nexthop_group_interface_state_change(ifp, old_ifindex);
 }
 
 size_t zebra_interface_link_params_write(struct stream *s,
@@ -1991,6 +2090,40 @@ int lm_label_manager_connect(struct zclient *zclient)
        return (int)result;
 }
 
+/*
+ * Asynchronous label chunk request
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @param keep Avoid garbage collection
+ * @param chunk_size Amount of labels requested
+ * @result 0 on success, -1 otherwise
+ */
+int zclient_send_get_label_chunk(
+       struct zclient  *zclient,
+       uint8_t         keep,
+       uint32_t        chunk_size)
+{
+       struct stream *s;
+
+       if (zclient_debug)
+               zlog_debug("Getting Label Chunk");
+
+       if (zclient->sock < 0)
+               return -1;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT);
+       stream_putc(s, keep);
+       stream_putl(s, chunk_size);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 /**
  * Function to request a label chunk in a syncronous way
  *
@@ -2604,6 +2737,12 @@ static int zclient_read(struct thread *thread)
                if (zclient->rule_notify_owner)
                        (*zclient->rule_notify_owner)(command, zclient, length,
                                                      vrf_id);
+               break;
+       case ZEBRA_GET_LABEL_CHUNK:
+               if (zclient->label_chunk)
+                       (*zclient->label_chunk)(command, zclient, length,
+                                                     vrf_id);
+               break;
        default:
                break;
        }
index 9d3e5c370297e2d9abf03de311eb1e9d01d2377d..985239b3260a6de7a30ae8e92c08df54c9549cff 100644 (file)
  */
 #define ZAPI_TCP_PATHNAME             "@tcp"
 
+/* IPset size name stands for the name of the ipset entry
+ * that can be created by using some zapi interfaces
+ */
+#define ZEBRA_IPSET_NAME_SIZE   32
+
+/* IPTable action is defined by two values: either
+ * forward or drop
+ */
+#define ZEBRA_IPTABLES_FORWARD 0
+#define ZEBRA_IPTABLES_DROP    1
+
 extern struct sockaddr_storage zclient_addr;
 extern socklen_t zclient_addr_len;
 
@@ -135,6 +146,15 @@ typedef enum {
        ZEBRA_TABLE_MANAGER_CONNECT,
        ZEBRA_GET_TABLE_CHUNK,
        ZEBRA_RELEASE_TABLE_CHUNK,
+       ZEBRA_IPSET_CREATE,
+       ZEBRA_IPSET_DESTROY,
+       ZEBRA_IPSET_ENTRY_ADD,
+       ZEBRA_IPSET_ENTRY_DELETE,
+       ZEBRA_IPSET_NOTIFY_OWNER,
+       ZEBRA_IPSET_ENTRY_NOTIFY_OWNER,
+       ZEBRA_IPTABLE_ADD,
+       ZEBRA_IPTABLE_DELETE,
+       ZEBRA_IPTABLE_NOTIFY_OWNER,
 } zebra_message_types_t;
 
 struct redist_proto {
@@ -223,6 +243,14 @@ struct zclient {
                                  uint16_t length, vrf_id_t vrf_id);
        int (*rule_notify_owner)(int command, struct zclient *zclient,
                                 uint16_t length, vrf_id_t vrf_id);
+       void (*label_chunk)(int command, struct zclient *zclient,
+                               uint16_t length, vrf_id_t vrf_id);
+       int (*ipset_notify_owner)(int command, struct zclient *zclient,
+                                uint16_t length, vrf_id_t vrf_id);
+       int (*ipset_entry_notify_owner)(int command,
+                                      struct zclient *zclient,
+                                      uint16_t length,
+                                      vrf_id_t vrf_id);
 };
 
 /* Zebra API message flag. */
@@ -371,6 +399,31 @@ enum zapi_rule_notify_owner {
        ZAPI_RULE_REMOVED,
 };
 
+enum ipset_type {
+       IPSET_NET_NET = 1,
+       IPSET_NET_PORT_NET,
+       IPSET_NET_PORT,
+       IPSET_NET
+};
+
+enum zapi_ipset_notify_owner {
+       ZAPI_IPSET_FAIL_INSTALL,
+       ZAPI_IPSET_INSTALLED,
+       ZAPI_IPSET_REMOVED,
+};
+
+enum zapi_ipset_entry_notify_owner {
+       ZAPI_IPSET_ENTRY_FAIL_INSTALL,
+       ZAPI_IPSET_ENTRY_INSTALLED,
+       ZAPI_IPSET_ENTRY_REMOVED,
+};
+
+enum zapi_iptable_notify_owner {
+       ZAPI_IPTABLE_FAIL_INSTALL,
+       ZAPI_IPTABLE_INSTALLED,
+       ZAPI_IPTABLE_REMOVED,
+};
+
 /* Zebra MAC types */
 #define ZEBRA_MACIP_TYPE_STICKY                0x01 /* Sticky MAC*/
 #define ZEBRA_MACIP_TYPE_GW                    0x02 /* gateway (SVI) mac*/
@@ -535,6 +588,11 @@ extern int zapi_ipv4_route(uint8_t, struct zclient *, struct prefix_ipv4 *,
 extern struct interface *zebra_interface_link_params_read(struct stream *);
 extern size_t zebra_interface_link_params_write(struct stream *,
                                                struct interface *);
+extern int zclient_send_get_label_chunk(
+       struct zclient  *zclient,
+       uint8_t         keep,
+       uint32_t        chunk_size);
+
 extern int lm_label_manager_connect(struct zclient *zclient);
 extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
                              uint32_t chunk_size, uint32_t *start,
@@ -605,6 +663,17 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
                             uint32_t *priority, uint32_t *unique,
                             ifindex_t *ifindex,
                             enum zapi_rule_notify_owner *note);
+bool zapi_ipset_notify_decode(struct stream *s,
+                             uint32_t *unique,
+                            enum zapi_ipset_notify_owner *note);
+
+#define ZEBRA_IPSET_NAME_SIZE   32
+
+bool zapi_ipset_entry_notify_decode(struct stream *s,
+           uint32_t *unique,
+           char *ipset_name,
+           enum zapi_ipset_entry_notify_owner *note);
+
 extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
 extern bool zapi_nexthop_update_decode(struct stream *s,
                                       struct zapi_route *nhr);
index 01b8055b6609b154f1bf4c670f4b0d9ed40770df..b895b5ad8b5ff034f0a45dd10e8504a503894792 100644 (file)
@@ -786,6 +786,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        /* (3) if the prefix is equal to an active configured address range */
        /*     or if the NU bit is set in the prefix */
        if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) {
+               /* must have been set in previous block */
+               assert(prefix_lsa);
+
                range = ospf6_route_lookup(&prefix, oa->range_table);
                if (range) {
                        if (is_debug)
index 7c60749d7e76d468a27c93d2d4d3e2c232f515c2..cc8577b94e7a2f8021106d4b8162bc43c3eae736 100644 (file)
@@ -349,28 +349,6 @@ void ospf6_interface_if_add(struct interface *ifp)
        ospf6_interface_state_update(oi->interface);
 }
 
-void ospf6_interface_if_del(struct interface *ifp)
-{
-       struct ospf6_interface *oi;
-
-       oi = (struct ospf6_interface *)ifp->info;
-       if (oi == NULL)
-               return;
-
-       /* interface stop */
-       if (oi->area)
-               thread_execute(master, interface_down, oi, 0);
-
-       listnode_delete(oi->area->if_list, oi);
-       oi->area = (struct ospf6_area *)NULL;
-
-       /* cut link */
-       oi->interface = NULL;
-       ifp->info = NULL;
-
-       ospf6_interface_delete(oi);
-}
-
 void ospf6_interface_state_update(struct interface *ifp)
 {
        struct ospf6_interface *oi;
index 553e89a227678a9208c017f000799c7c03604993..8fd43f099a03c0b3bca4c549e4d3afdc543afc88 100644 (file)
@@ -176,7 +176,6 @@ extern void ospf6_interface_enable(struct ospf6_interface *);
 extern void ospf6_interface_disable(struct ospf6_interface *);
 
 extern void ospf6_interface_if_add(struct interface *);
-extern void ospf6_interface_if_del(struct interface *);
 extern void ospf6_interface_state_update(struct interface *);
 extern void ospf6_interface_connected_route_update(struct interface *);
 
index 519c5e170ff73365768b4486beaca51c07534a5c..de4ee2e1ac31c0c6f5f765240b5045f668641cd2 100644 (file)
@@ -1844,6 +1844,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
                                                                INTRA_PREFIX)) {
                                                prefix2str(&route->prefix, buf,
                                                           sizeof(buf));
+                                               assert(route->nh_list);
                                                zlog_debug("%s: route %s update paths %u nh %u"
                                                        , __PRETTY_FUNCTION__,
                                                        buf,
index 6455f606bd85114931a64843f44e5d51bcd0e601..b5a1812ffa823f9b849eac7170096991f8127823 100644 (file)
@@ -193,8 +193,9 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
 
                OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
 
-               if (prev_state == OSPF6_NEIGHBOR_LOADING
-                   && next_state == OSPF6_NEIGHBOR_FULL) {
+               if ((prev_state == OSPF6_NEIGHBOR_LOADING ||
+                    prev_state == OSPF6_NEIGHBOR_EXCHANGE) &&
+                   next_state == OSPF6_NEIGHBOR_FULL) {
                        OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
                        on->ospf6_if->area->full_nbrs++;
                }
index 8c2e706d170726c8b0bc841df76cec83f656cd3d..8458d19952e0ad5b64303f217b46a53dcb5f7ec4 100644 (file)
@@ -127,13 +127,6 @@ static int ospf6_zebra_if_del(int command, struct zclient *zclient,
                zlog_debug("Zebra Interface delete: %s index %d mtu %d",
                           ifp->name, ifp->ifindex, ifp->mtu6);
 
-#if 0
-  /* XXX: ospf6_interface_if_del is not the right way to handle this,
-   * because among other thinkable issues, it will also clear all
-   * settings as they are contained in the struct ospf6_interface. */
-  ospf6_interface_if_del (ifp);
-#endif /*0*/
-
        if_set_index(ifp, IFINDEX_INTERNAL);
        return 0;
 }
index fd3da45f78a78f8b245802ba5573a136e9873bf6..6623790837031d7cc850d00fb2cd60debad11a20 100644 (file)
@@ -1756,6 +1756,7 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf,
        ei.route_map_set.metric = -1;
        ei.route_map_set.metric_type = -1;
        ei.tag = 0;
+       ei.instance = 0;
 
        if ((new = ospf_external_lsa_new(ospf, &ei, &type7->data->id))
            == NULL) {
index 7464b14b1f71a2e77414cab4b6470f327ef5233f..6825be83ac89b007078e9ee369690c771f2d34ec 100644 (file)
@@ -2117,7 +2117,7 @@ static struct ospf_neighbor *ospf_snmp_nbr_lookup_next(struct in_addr *nbr_addr,
        struct ospf_neighbor *nbr;
        struct route_node *rn;
        struct ospf_neighbor *min = NULL;
-       struct ospf *ospf = ospf;
+       struct ospf *ospf;
 
        ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
 
index 05adc5aa4fe8aa2fdd10b6d64f6f92f1faa1d3ea..26df7a24cd1736b66dfb2a007d8d3bfadb0d7901 100644 (file)
@@ -1161,16 +1161,13 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf,
 
        /* Set opaque-LSA header fields depending of the type of RFC */
        if (IS_INTER_AS(lp->type)) {
-               if
-                       IS_FLOOD_AS(lp->type)
-                       {
-                               options |= OSPF_OPTION_E; /* Enable AS external
-                                                            as we flood
-                                                            Inter-AS with
-                                                            Opaque Type 11 */
-                               lsa_type = OSPF_OPAQUE_AS_LSA;
-                       }
-               else {
+               if (IS_FLOOD_AS(lp->type)) {
+                       /* Enable AS external as we flood Inter-AS with Opaque
+                        * Type 11
+                        */
+                       options |= OSPF_OPTION_E;
+                       lsa_type = OSPF_OPAQUE_AS_LSA;
+               } else {
                        options |= LSA_OPTIONS_GET(
                                area); /* Get area default option */
                        options |= LSA_OPTIONS_NSSA_GET(area);
@@ -1210,12 +1207,12 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf,
 
        /* Now, create an OSPF LSA instance. */
        if ((new = ospf_lsa_new()) == NULL) {
-               zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
+               zlog_warn("%s: ospf_lsa_new() ?", __func__);
                stream_free(s);
                return NULL;
        }
        if ((new->data = ospf_lsa_data_new(length)) == NULL) {
-               zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
+               zlog_warn("%s: ospf_lsa_data_new() ?", __func__);
                ospf_lsa_unlock(&new);
                new = NULL;
                stream_free(s);
index 23d00633d444890efaa0b39a8c71b6cc34d799c3..6487596706bb92b6fabc0891ce746d6dcd07e2c3 100644 (file)
@@ -118,7 +118,8 @@ static int ospf_interface_add(int command, struct zclient *zclient,
 
        assert(ifp->info);
 
-       if (!OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) {
+       if (IF_DEF_PARAMS(ifp)
+           && !OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) {
                SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
                IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp);
        }
index e9b4a52955899d4c7d12cfac74019a3ea4ceb6ca..82f045c4624ca1bd06b9eaddb7f8f6ac82a19412 100644 (file)
@@ -43,16 +43,7 @@ const char *pbr_debugs_conflines[] = {
        "debug pbr events",
 };
 
-/*
- * Set or unset flags on all debugs for pbrd.
- *
- * flags
- *    The flags to set
- *
- * set
- *    Whether to set or unset the specified flags
- */
-static void pbr_debug_set_all(uint32_t flags, bool set)
+void pbr_debug_set_all(uint32_t flags, bool set)
 {
        for (unsigned int i = 0; i < array_size(pbr_debugs); i++) {
                DEBUG_FLAGS_SET(pbr_debugs[i], flags, set);
@@ -63,36 +54,13 @@ static void pbr_debug_set_all(uint32_t flags, bool set)
        }
 }
 
-/*
- * Check flags on all debugs for pbrd.
- *
- * flags
- *    The flags to set
- *
- * Returns:
- *    The subset of the given flags that were set in all pbrd debugs
- */
-static uint32_t pbr_debug_check_all(uint32_t flags)
-{
-       uint32_t mode = DEBUG_MODE_ALL;
-
-       for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
-               mode &= DEBUG_MODE_CHECK(pbr_debugs[i], flags);
-       return mode;
-}
-
-static int pbr_debug_config_write_helper(struct vty *vty, bool config)
+int pbr_debug_config_write_helper(struct vty *vty, bool config)
 {
        uint32_t mode = DEBUG_MODE_ALL;
 
        if (config)
                mode = DEBUG_MODE_CONF;
 
-       if (pbr_debug_check_all(DEBUG_MODE_CONF) == mode) {
-               vty_out(vty, "debug pbr\n");
-               return 0;
-       }
-
        for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
                if (DEBUG_MODE_CHECK(pbr_debugs[i], mode))
                        vty_out(vty, "%s\n", pbr_debugs_conflines[i]);
@@ -104,70 +72,9 @@ int pbr_debug_config_write(struct vty *vty)
        return pbr_debug_config_write_helper(vty, true);
 }
 
-/* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
-
-DEFPY(debug_pbr,
-      debug_pbr_cmd,
-      "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
-      NO_STR
-      DEBUG_STR
-      "Policy Based Routing\n"
-      "Policy maps\n"
-      "PBRD <-> Zebra communications\n"
-      "Nexthop tracking\n"
-      "Events\n")
-{
-       uint32_t mode = DEBUG_NODE2MODE(vty->node);
-
-       if (map)
-               DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
-       if (zebra)
-               DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
-       if (nht)
-               DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
-       if (events)
-               DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
-
-       /* no specific debug --> act on all of them */
-       if (strmatch(argv[argc - 1]->text, "pbr"))
-               pbr_debug_set_all(mode, !no);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN_NOSH(show_debugging_pbr,
-          show_debugging_pbr_cmd,
-          "show debugging [pbr]",
-          SHOW_STR
-          DEBUG_STR
-          "Policy Based Routing\n")
-{
-       vty_out(vty, "PBR debugging status:\n");
-
-       pbr_debug_config_write_helper(vty, false);
-
-       return CMD_SUCCESS;
-}
-
-/* clang-format on */
-/* ------------------------------------------------------------------------- */
-
-static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
-
 struct debug_callbacks pbr_dbg_cbs = {.debug_set_all = pbr_debug_set_all};
 
 void pbr_debug_init(void)
 {
        debug_init(&pbr_dbg_cbs);
 }
-
-void pbr_debug_init_vty(void)
-{
-       install_node(&debug_node, pbr_debug_config_write);
-
-       install_element(VIEW_NODE, &debug_pbr_cmd);
-       install_element(CONFIG_NODE, &debug_pbr_cmd);
-
-       install_element(VIEW_NODE, &show_debugging_pbr_cmd);
-}
index 27447246291339837896f185611ac06f18ff99f3..e72fb88bebcc613e3a4015226ce976d78bf1016b 100644 (file)
@@ -38,9 +38,29 @@ extern struct debug pbr_dbg_event;
 void pbr_debug_init(void);
 
 /*
- * Install PBR debugging VTY commands.
+ * Set or unset flags on all debugs for pbrd.
+ *
+ * flags
+ *    The flags to set
+ *
+ * set
+ *    Whether to set or unset the specified flags
+ */
+void pbr_debug_set_all(uint32_t flags, bool set);
+
+/*
+ * Config write helper.
+ *
+ * vty
+ *    Vty to write to
+ *
+ * config
+ *    Whether we are writing to show run or saving config file
+ *
+ * Returns:
+ *    0 for convenience
  */
-void pbr_debug_init_vty(void);
+int pbr_debug_config_write_helper(struct vty *vty, bool config);
 
 /*
  * Print PBR debugging configuration.
index 638e284a1a7d64affee6b91bd8e592909b9a7bac..ba0962108375eeabdd75a2282a8c41e44325bd4e 100644 (file)
@@ -152,6 +152,11 @@ int main(int argc, char **argv, char **envp)
                           pbr_nhgroup_del_nexthop_cb,
                           pbr_nhgroup_delete_cb);
 
+       /*
+        * So we safely ignore these commands since
+        * we are getting them at this point in time
+        */
+       access_list_init();
        pbr_nht_init();
        pbr_map_init();
        pbr_zebra_init();
index ea79320a712501a12bbd9adc61d3667b383366f6..eb2c082fb927651b7ad13c26f649405586e18656 100644 (file)
@@ -152,8 +152,9 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
        pmi->pbrm = pbrm;
        listnode_add_sort(pbrm->incoming, pmi);
 
+       bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
        pbr_map_check_valid(pbrm->name);
-       if (pbrm->valid && !pbrm->installed)
+       if (pbrm->valid)
                pbr_map_install(pbrm);
 }
 
@@ -193,6 +194,8 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
 
        if (pbrm->seqnumbers->count == 0) {
                RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
+
+               bf_free(pbrm->ifi_bitfield);
                XFREE(MTYPE_PBR_MAP, pbrm);
        }
 }
@@ -210,13 +213,12 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
 
        pbrm->valid = false;
        pbrms->nhs_installed = false;
-       pbrms->installed = false;
        pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
        pbrms->nhgrp_name = NULL;
 }
 
-struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
-                                            ifindex_t ifindex)
+struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+                                            struct pbr_map_interface **ppmi)
 {
        struct pbr_map_sequence *pbrms;
        struct listnode *snode, *inode;
@@ -228,6 +230,9 @@ struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
                        if (pmi->ifp->ifindex != ifindex)
                                continue;
 
+                       if (ppmi)
+                               *ppmi = pmi;
+
                        for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
                                                  pbrms)) {
                                DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
@@ -268,7 +273,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
        pbrm = pbrm_find(name);
        if (!pbrm) {
                pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
-               strcpy(pbrm->name, name);
+               snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
 
                pbrm->seqnumbers = list_new();
                pbrm->seqnumbers->cmp =
@@ -284,6 +289,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
 
                RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
 
+               bf_init(pbrm->ifi_bitfield, 64);
                pbr_map_add_interfaces(pbrm);
        }
 
@@ -305,8 +311,6 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
 
                QOBJ_REG(pbrms, pbr_map_sequence);
                listnode_add_sort(pbrm->seqnumbers, pbrms);
-
-               pbrm->installed = false;
        }
 
        return pbrms;
@@ -463,6 +467,8 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
 
        listnode_delete(pbrm->incoming, pmi);
        pmi->pbrm = NULL;
+
+       bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
        XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
 }
 
@@ -541,8 +547,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
                       pbrms->seqno, pbrms->reason);
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
+       for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
                pbr_send_pbr_map(pbrms, pmi, install);
+       }
 }
 
 void pbr_map_install(struct pbr_map *pbrm)
@@ -557,8 +564,6 @@ void pbr_map_install(struct pbr_map *pbrm)
        for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
                for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
                        pbr_send_pbr_map(pbrms, pmi, true);
-
-       pbrm->installed = true;
 }
 
 void pbr_map_init(void)
index 5cb22d7429ebb3a4acf2198e441d98dc09f243bb..7cd079d169aa50de4bc84532011ac159c7f86f2e 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __PBR_MAP_H__
 #define __PBR_MAP_H__
 
+#include <bitfield.h>
+
 struct pbr_map {
        /*
         * RB Tree of the pbr_maps
@@ -40,20 +42,21 @@ struct pbr_map {
         */
        struct list *incoming;
 
+       bitfield_t ifi_bitfield;
        /*
         * If valid is true we think the pbr_map is valid,
         * If false, look in individual pbrms to see
         * what we think is the invalid reason
         */
        bool valid;
-
-       bool installed;
 };
 
 RB_HEAD(pbr_map_entry_head, pbr_map);
 RB_PROTOTYPE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
 
 struct pbr_map_interface {
+       uint32_t install_bit;
+
        struct interface *ifp;
 
        struct pbr_map *pbrm;
@@ -112,7 +115,7 @@ struct pbr_map_sequence {
        /*
         * Are we installed
         */
-       bool installed;
+       uint64_t installed;
 
        /*
         * A reason of 0 means we think the pbr_map_sequence is good to go
@@ -134,8 +137,9 @@ DECLARE_QOBJ_TYPE(pbr_map_sequence)
 extern struct pbr_map_entry_head pbr_maps;
 
 extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno);
-extern struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
-                                                   ifindex_t ifindex);
+extern struct pbr_map_sequence *
+pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+                   struct pbr_map_interface **ppmi);
 
 extern struct pbr_map *pbrm_find(const char *name);
 extern void pbr_map_delete(struct pbr_map_sequence *pbrms);
index 1ce8c2104d249a9221d579f0f524ac9210b5e432..1ccf3ebffac8255377905d617f644703efbcf71f 100644 (file)
@@ -209,6 +209,13 @@ void pbr_nhgroup_add_cb(const char *name)
        struct nexthop_group_cmd *nhgc;
 
        nhgc = nhgc_find(name);
+
+       if (!nhgc) {
+               DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
+                      __PRETTY_FUNCTION__, name);
+               return;
+       }
+
        pnhgc = pbr_nht_add_group(name);
 
        DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
@@ -312,8 +319,16 @@ static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b,
        if (pnhgc->table_id == *table_id) {
                DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
                       __PRETTY_FUNCTION__, *table_id, pnhgc->name);
-               pnhgc->installed = true;
-               pbr_map_schedule_policy_from_nhg(pnhgc->name);
+
+               /*
+                * If the table has been re-handled by zebra
+                * and we are already installed no need to do
+                * anything here.
+                */
+               if (!pnhgc->installed) {
+                       pnhgc->installed = true;
+                       pbr_map_schedule_policy_from_nhg(pnhgc->name);
+               }
        }
 }
 
@@ -402,8 +417,6 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
 
        install_afi = pbr_nht_which_afi(nhg, nh_afi);
 
-       pnhgc->installed = false;
-
        route_add(pnhgc, nhg, install_afi);
 }
 
@@ -433,7 +446,7 @@ void pbr_nht_change_group(const char *name)
                return;
 
        memset(&find, 0, sizeof(find));
-       strcpy(find.name, name);
+       snprintf(find.name, sizeof(find.name), "%s", name);
        pnhgc = hash_lookup(pbr_nhg_hash, &find);
 
        if (!pnhgc) {
@@ -504,11 +517,10 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
 
        pbrm->valid = false;
        pbrms->nhs_installed = false;
-       pbrms->installed = false;
        pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
 
        memset(&find, 0, sizeof(find));
-       strcpy(&find.name[0], pbrms->internal_nhg_name);
+       snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
        pnhgc = hash_lookup(pbr_nhg_hash, &find);
 
        nh = pbrms->nhg->nexthop;
@@ -543,7 +555,7 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
                return NULL;
        }
 
-       strcpy(lookup.name, name);
+       snprintf(lookup.name, sizeof(lookup.name), "%s", name);
        pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
        DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
               pnhgc);
@@ -602,7 +614,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
 
        DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
 
-       strcpy(lookup.name, name);
+       snprintf(lookup.name, sizeof(lookup.name), "%s", name);
        pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
        if (!pnhgc)
                return false;
@@ -757,7 +769,7 @@ uint32_t pbr_nht_get_table(const char *name)
        struct pbr_nexthop_group_cache *pnhgc;
 
        memset(&find, 0, sizeof(find));
-       strcpy(find.name, name);
+       snprintf(find.name, sizeof(find.name), "%s", name);
        pnhgc = hash_lookup(pbr_nhg_hash, &find);
 
        if (!pnhgc) {
@@ -776,7 +788,7 @@ bool pbr_nht_get_installed(const char *name)
        struct pbr_nexthop_group_cache *pnhgc;
 
        memset(&find, 0, sizeof(find));
-       strcpy(find.name, name);
+       snprintf(find.name, sizeof(find.name), "%s", name);
 
        pnhgc = hash_lookup(pbr_nhg_hash, &find);
 
index 87ec3804a53778164475fc6ed100f29a0aed7317..475ad86b5885b8a77cd13b4df0bdc207b8aee312 100644 (file)
@@ -251,8 +251,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
                                        intf, vrf->name);
                                return CMD_WARNING_CONFIG_FAILED;
                        }
-               } else
+               } else {
+                       if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+                               vty_out(vty,
+                                       "Specified a v6 LL with no interface, rejecting\n");
+                               return CMD_WARNING_CONFIG_FAILED;
+                       }
                        nhop.type = NEXTHOP_TYPE_IPV6;
+               }
        }
 
        if (pbrms->nhg)
@@ -313,36 +319,30 @@ DEFPY (pbr_policy,
        pbrm = pbrm_find(mapname);
 
        if (!pbr_ifp) {
-               /*
-                * Some one could have fat fingered the interface
-                * name
-                */
+               /* we don't want one and we don't have one, so... */
+               if (no)
+                       return CMD_SUCCESS;
+
+               /* Some one could have fat fingered the interface name */
                pbr_ifp = pbr_if_new(ifp);
        }
 
        if (no) {
                if (strcmp(pbr_ifp->mapname, mapname) == 0) {
-                       strcpy(pbr_ifp->mapname, "");
-
+                       pbr_ifp->mapname[0] = '\0';
                        if (pbrm)
                                pbr_map_interface_delete(pbrm, ifp);
                }
        } else {
-               if (strcmp(pbr_ifp->mapname, "") == 0) {
-                       strcpy(pbr_ifp->mapname, mapname);
-
-                       if (pbrm)
-                               pbr_map_add_interface(pbrm, ifp);
-               } else {
-                       if (!(strcmp(pbr_ifp->mapname, mapname) == 0)) {
-                               old_pbrm = pbrm_find(pbr_ifp->mapname);
-                               if (old_pbrm)
-                                       pbr_map_interface_delete(old_pbrm, ifp);
-                               strcpy(pbr_ifp->mapname, mapname);
-                               if (pbrm)
-                                       pbr_map_add_interface(pbrm, ifp);
-                       }
+               if (strcmp(pbr_ifp->mapname, "") != 0) {
+                       old_pbrm = pbrm_find(pbr_ifp->mapname);
+                       if (old_pbrm)
+                               pbr_map_interface_delete(old_pbrm, ifp);
                }
+               snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
+                        "%s", mapname);
+               if (pbrm)
+                       pbr_map_add_interface(pbrm, ifp);
        }
 
        return CMD_SUCCESS;
@@ -389,7 +389,7 @@ DEFPY (show_pbr_map,
                                pbr_map_reason_string(pbrms->reason, rbuf,
                                                      sizeof(rbuf));
                        vty_out(vty,
-                               "    Seq: %u rule: %u Installed: %d(%u) Reason: %s\n",
+                               "    Seq: %u rule: %u Installed: %" PRIu64 "(%u) Reason: %s\n",
                                pbrms->seqno, pbrms->ruleno, pbrms->installed,
                                pbrms->unique, pbrms->reason ? rbuf : "Valid");
 
@@ -483,6 +483,58 @@ DEFPY (show_pbr_interface,
        return CMD_SUCCESS;
 }
 
+/* PBR debugging CLI ------------------------------------------------------- */
+/* clang-format off */
+
+static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
+
+DEFPY(debug_pbr,
+      debug_pbr_cmd,
+      "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
+      NO_STR
+      DEBUG_STR
+      "Policy Based Routing\n"
+      "Policy maps\n"
+      "PBRD <-> Zebra communications\n"
+      "Nexthop tracking\n"
+      "Events\n")
+{
+       uint32_t mode = DEBUG_NODE2MODE(vty->node);
+
+       if (map)
+               DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
+       if (zebra)
+               DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
+       if (nht)
+               DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
+       if (events)
+               DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
+
+       /* no specific debug --> act on all of them */
+       if (strmatch(argv[argc - 1]->text, "pbr"))
+               pbr_debug_set_all(mode, !no);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_NOSH(show_debugging_pbr,
+          show_debugging_pbr_cmd,
+          "show debugging [pbr]",
+          SHOW_STR
+          DEBUG_STR
+          "Policy Based Routing\n")
+{
+       vty_out(vty, "PBR debugging status:\n");
+
+       pbr_debug_config_write_helper(vty, false);
+
+       return CMD_SUCCESS;
+}
+
+/* clang-format on */
+/* ------------------------------------------------------------------------- */
+
+
 static struct cmd_node interface_node = {
        INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
 };
@@ -567,6 +619,12 @@ void pbr_vty_init(void)
        install_node(&pbr_map_node,
                     pbr_vty_map_config_write);
 
+       /* debug */
+       install_node(&debug_node, pbr_debug_config_write);
+       install_element(VIEW_NODE, &debug_pbr_cmd);
+       install_element(CONFIG_NODE, &debug_pbr_cmd);
+       install_element(VIEW_NODE, &show_debugging_pbr_cmd);
+
        install_default(PBRMAP_NODE);
 
        install_element(CONFIG_NODE, &pbr_map_cmd);
@@ -580,6 +638,4 @@ void pbr_vty_init(void)
        install_element(VIEW_NODE, &show_pbr_map_cmd);
        install_element(VIEW_NODE, &show_pbr_interface_cmd);
        install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
-
-       pbr_debug_init_vty();
 }
index a1a2d34ac1d8499d64e2f4604fdce407b44979fa..4e5b5f3dde90d1142a59935b77251190063f53b8 100644 (file)
@@ -45,17 +45,6 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
 /* Zebra structure to hold current status. */
 struct zclient *zclient;
 
-static struct interface *zebra_interface_if_lookup(struct stream *s)
-{
-       char ifname_tmp[INTERFACE_NAMSIZ];
-
-       /* Read interface name. */
-       stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
-       /* And look it up. */
-       return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
-}
-
 struct pbr_interface *pbr_if_new(struct interface *ifp)
 {
        struct pbr_interface *pbr_ifp;
@@ -140,7 +129,7 @@ static int interface_state_up(int command, struct zclient *zclient,
                              zebra_size_t length, vrf_id_t vrf_id)
 {
 
-       zebra_interface_if_lookup(zclient->ibuf);
+       zebra_interface_state_read(zclient->ibuf, vrf_id);
 
        return 0;
 }
@@ -206,13 +195,16 @@ static int rule_notify_owner(int command, struct zclient *zclient,
        uint32_t seqno, priority, unique;
        enum zapi_rule_notify_owner note;
        struct pbr_map_sequence *pbrms;
+       struct pbr_map_interface *pmi;
        ifindex_t ifi;
+       uint64_t installed;
 
        if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
                                     &ifi, &note))
                return -1;
 
-       pbrms = pbrms_lookup_unique(unique, ifi);
+       pmi = NULL;
+       pbrms = pbrms_lookup_unique(unique, ifi, &pmi);
        if (!pbrms) {
                DEBUGD(&pbr_dbg_zebra,
                       "%s: Failure to lookup pbrms based upon %u",
@@ -220,18 +212,21 @@ static int rule_notify_owner(int command, struct zclient *zclient,
                return 0;
        }
 
+       installed = 1 << pmi->install_bit;
+
        switch (note) {
        case ZAPI_RULE_FAIL_INSTALL:
                DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
                       __PRETTY_FUNCTION__);
-               pbrms->installed = false;
+               pbrms->installed &= ~installed;
                break;
        case ZAPI_RULE_INSTALLED:
-               pbrms->installed = true;
+               pbrms->installed |= installed;
                DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
                       __PRETTY_FUNCTION__);
                break;
        case ZAPI_RULE_REMOVED:
+               pbrms->installed &= ~installed;
                DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
                       __PRETTY_FUNCTION__);
                break;
@@ -499,9 +494,23 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
 {
        struct pbr_map *pbrm = pbrms->parent;
        struct stream *s;
+       uint64_t is_installed = 1 << pmi->install_bit;
 
-       DEBUGD(&pbr_dbg_zebra, "%s: for %s %d", __PRETTY_FUNCTION__, pbrm->name,
-              install);
+       is_installed &= pbrms->installed;
+
+       DEBUGD(&pbr_dbg_zebra, "%s: for %s %d(%" PRIu64 ")",
+              __PRETTY_FUNCTION__, pbrm->name, install, is_installed);
+
+       /*
+        * If we are installed and asked to do so again
+        * just return.  If we are not installed and asked
+        * and asked to delete just return;
+        */
+       if (install && is_installed)
+               return;
+
+       if (!install && !is_installed)
+               return;
 
        s = zclient->obuf;
        stream_reset(s);
index d75aaa3708bb5e6436552dcfb30056442b257857..8c1cd8d96303b03995347409b10db6ddd3960986 100644 (file)
@@ -81,7 +81,7 @@ int routeget(struct in_addr dst, struct in_addr *src, struct in_addr *gw)
 
        ret = rtnl_open(&rth, 0);
 
-       if (ret < 0)
+       if (ret < 0 || rth.fd <= 0)
                return ret;
 
        if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
index 633e88e76980952b0a1bee22dade471bbe1ef170..ec0835c7191258667c93f5e8d7be7a66214f86c7 100644 (file)
@@ -38,9 +38,15 @@ static size_t lsa_count = 0;
 
 static void lsa_check_resize(size_t len)
 {
+       struct ospf6_lsa **templsas;
+
        if (lsa_count >= len)
                return;
-       lsas = realloc(lsas, len * sizeof(lsas[0]));
+       templsas = realloc(lsas, len * sizeof(lsas[0]));
+       if (templsas)
+               lsas = templsas;
+       else
+               return;
        memset(lsas + lsa_count, 0, sizeof(lsas[0]) * (len - lsa_count));
 
        lsa_count = len;
index 09f1fa493f6c85735b8f1a238e64fe789c566436..27136bb762135c608285584aca8cfe0a44160dcb 100755 (executable)
--- a/tools/frr
+++ b/tools/frr
@@ -25,7 +25,9 @@ DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd
 MAX_INSTANCES=5
 RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
 
-. /lib/lsb/init-functions
+if [ -e /lib/lsb/init-functions ]; then
+    . /lib/lsb/init-functions
+fi
 
 if [ -f /usr/lib/frr/ssd ]; then
     SSD=/usr/lib/frr/ssd
index dd5577bd240aa1dfe86062f4aad42ec9d6c8de11..5184b55699397512b9559ed74fd5c50f98e91afe 100644 (file)
@@ -1 +1,5 @@
 leak:clippy
+leak:PyObject_Malloc
+leak:PyObject_Realloc
+leak:PyList_Append
+leak:malloc
index 4de671b7faf1d7533e66cf18de36bf318abb5b3c..cd59d8094b95c35541f17cea470ba93a2c68397f 100644 (file)
@@ -306,6 +306,7 @@ int main(int argc, char **argv, char **env)
        char *homedir = NULL;
        int ditch_suid = 0;
        char sysconfdir[MAXPATHLEN];
+       const char *pathspace_arg = NULL;
        char pathspace[MAXPATHLEN] = "";
 
        /* SUID: drop down to calling user & go back up when needed */
@@ -363,7 +364,8 @@ int main(int argc, char **argv, char **env)
                                        "slashes or dots are not permitted in the --pathspace option.\n");
                                exit(1);
                        }
-                       snprintf(pathspace, sizeof(pathspace), "/%s", optarg);
+                       pathspace_arg = optarg;
+                       snprintf(pathspace, sizeof(pathspace), "%s/", optarg);
                        break;
                case 'd':
                        daemon_name = optarg;
@@ -419,7 +421,11 @@ int main(int argc, char **argv, char **env)
                 pathspace, VTYSH_CONFIG_NAME);
        snprintf(frr_config, sizeof(frr_config), "%s%s%s", sysconfdir,
                 pathspace, FRR_CONFIG_NAME);
-       strlcat(vtydir, pathspace, sizeof(vtydir));
+
+       if (pathspace_arg) {
+               strlcat(vtydir, "/", sizeof(vtydir));
+               strlcat(vtydir, pathspace_arg, sizeof(vtydir));
+       }
 
        /* Initialize user input buffer. */
        line_read = NULL;
index 4035e53f7ce89c72c2902c21b093e8a55c307ce7..1ead7ee1fd377ca77cd0b805d6032d0ba95449bc 100644 (file)
@@ -148,9 +148,8 @@ void zebra_sim(FILE *fp)
                                continue;
                }
 
-               for (i = 0; i < 10; i++) {
-                       if (!zebra_type[i].str)
-                               break;
+               i = 0;
+               while (zebra_type[i++].str) {
                        if (strcmp(zebra_type[i].str, str) == 0) {
                                type = zebra_type[i].type;
                                break;
index 2198ddf5ea1c513b87d81c18dc0059d30741242a..23f2f666a0593c3b0665714b44098e3d8dc0b857 100644 (file)
@@ -495,7 +495,8 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
 
 /* Add connected IPv6 route to the interface. */
 void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
-                       uint8_t prefixlen, const char *label)
+                       struct in6_addr *broad, uint8_t prefixlen,
+                       const char *label)
 {
        struct prefix_ipv6 *p;
        struct connected *ifc;
@@ -518,6 +519,20 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
        p->prefixlen = prefixlen;
        ifc->address = (struct prefix *)p;
 
+       if (broad) {
+               p = prefix_ipv6_new();
+               p->family = AF_INET6;
+               IPV6_ADDR_COPY(&p->prefix, broad);
+               p->prefixlen = prefixlen;
+               ifc->destination = (struct prefix *)p;
+       } else {
+               if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) {
+                       zlog_warn("warning: %s called for interface %s with peer flag set, but no peer address supplied",
+                                 __func__, ifp->name);
+                       UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
+               }
+       }
+
        /* Label of this address. */
        if (label)
                ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
@@ -536,9 +551,9 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
 }
 
 void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
-                          uint8_t prefixlen)
+                          struct in6_addr *broad, uint8_t prefixlen)
 {
-       struct prefix p;
+       struct prefix p, d;
        struct connected *ifc;
 
        memset(&p, 0, sizeof(struct prefix));
@@ -546,7 +561,14 @@ void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
        memcpy(&p.u.prefix6, address, sizeof(struct in6_addr));
        p.prefixlen = prefixlen;
 
-       ifc = connected_check(ifp, &p);
+       if (broad) {
+               memset(&d, 0, sizeof(struct prefix));
+               d.family = AF_INET6;
+               IPV6_ADDR_COPY(&d.u.prefix, broad);
+               d.prefixlen = prefixlen;
+               ifc = connected_check_ptp(ifp, &p, &d);
+       } else
+               ifc = connected_check_ptp(ifp, &p, NULL);
 
        connected_delete_helper(ifc, &p);
 }
index 9b69a3f2467c81d32a63e07c22fc48f90579aa95..2a2b0933951df16c226a8d88aa0a812b13ae7061 100644 (file)
@@ -42,10 +42,11 @@ extern void connected_up(struct interface *ifp, struct connected *ifc);
 extern void connected_down(struct interface *ifp, struct connected *ifc);
 
 extern void connected_add_ipv6(struct interface *ifp, int flags,
-                              struct in6_addr *address, uint8_t prefixlen,
-                              const char *label);
+                              struct in6_addr *address, struct in6_addr *broad,
+                              uint8_t prefixlen, const char *label);
 extern void connected_delete_ipv6(struct interface *ifp,
-                                 struct in6_addr *address, uint8_t prefixlen);
+                                 struct in6_addr *address,
+                                 struct in6_addr *broad, uint8_t prefixlen);
 
 extern int connected_is_unnumbered(struct interface *);
 
index b506315ebfcf7e720cbd9b758ffc8d0f98f3d82b..f5ed9455279c0fc90c542752da32f765facb2a59 100644 (file)
@@ -249,7 +249,7 @@ static int if_getaddrs(void)
                        }
 #endif
 
-                       connected_add_ipv6(ifp, flags, &addr->sin6_addr,
+                       connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
                                           prefixlen, NULL);
                }
        }
index e9182304ddd167b1dd2966b69631c5350a399e93..6cf98e85f58da359dd6a92c1ec9a49838ff24a6b 100644 (file)
@@ -315,7 +315,7 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
                connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
                                   (struct in_addr *)dest_pnt, label);
        else if (af == AF_INET6)
-               connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr,
+               connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
                                   prefixlen, label);
 
        return 0;
index 4a37c14b9296aaf839c5a4ba6235679d413aa499..e28c189f8643647be215f4884c6e34675c80545c 100644 (file)
@@ -1006,9 +1006,11 @@ int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h,
                              & (IFA_F_DADFAILED | IFA_F_TENTATIVE)))
                                connected_add_ipv6(ifp, flags,
                                                   (struct in6_addr *)addr,
+                                                  (struct in6_addr *)broad,
                                                   ifa->ifa_prefixlen, label);
                } else
                        connected_delete_ipv6(ifp, (struct in6_addr *)addr,
+                                             (struct in6_addr *)broad,
                                              ifa->ifa_prefixlen);
        }
 
index 4ac3bed4b42735ff7edf2cade0e6b3fd87c2c82c..1a94807317242f6f9a850d334cc0c2b071ad0d30 100644 (file)
@@ -771,10 +771,11 @@ int ifam_read(struct ifa_msghdr *ifam)
 
                if (ifam->ifam_type == RTM_NEWADDR)
                        connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr,
+                                          NULL,
                                           ip6_masklen(mask.sin6.sin6_addr),
                                           (isalias ? ifname : NULL));
                else
-                       connected_delete_ipv6(ifp, &addr.sin6.sin6_addr,
+                       connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL,
                                              ip6_masklen(mask.sin6.sin6_addr));
                break;
        default:
index 15e7d4437a73d777c6c8454d0b1377c5f4d98d04..2e19d6fb75c1cac47f004dcdc98d1994b44e10b1 100644 (file)
@@ -531,6 +531,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
                        re->tag, rmap_name);
 
        if (ret != RMAP_MATCH) {
+               UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
                zebra_del_import_table_entry(rn, re);
                return 0;
        }
@@ -547,8 +548,10 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
                        break;
        }
 
-       if (same)
+       if (same) {
+               UNSET_FLAG(same->flags, ZEBRA_FLAG_SELECTED);
                zebra_del_import_table_entry(rn, same);
+       }
 
        newre = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
        newre->type = ZEBRA_ROUTE_TABLE;
index dc942204a4ba39b4e3e6be823613828a1705a7ca..310f0952faa3e4c11a3a64686718a7141294af59 100644 (file)
@@ -66,7 +66,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
        char buf2[PREFIX_STRLEN];
 
        memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
-       family = PREFIX_FAMILY(&rule->filter.src_ip);
+       family = PREFIX_FAMILY(&rule->rule.filter.src_ip);
        bytelen = (family == AF_INET ? 4 : 16);
 
        req.n.nlmsg_type = cmd;
@@ -78,7 +78,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
        req.frh.action = FR_ACT_TO_TBL;
 
        /* rule's pref # */
-       addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->priority);
+       addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority);
 
        /* interface on which applied */
        if (rule->ifp)
@@ -87,24 +87,24 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
 
        /* source IP, if specified */
        if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
-               req.frh.src_len = rule->filter.src_ip.prefixlen;
+               req.frh.src_len = rule->rule.filter.src_ip.prefixlen;
                addattr_l(&req.n, sizeof(req), FRA_SRC,
-                         &rule->filter.src_ip.u.prefix, bytelen);
+                         &rule->rule.filter.src_ip.u.prefix, bytelen);
        }
        /* destination IP, if specified */
        if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
-               req.frh.dst_len = rule->filter.dst_ip.prefixlen;
+               req.frh.dst_len = rule->rule.filter.dst_ip.prefixlen;
                addattr_l(&req.n, sizeof(req), FRA_DST,
-                         &rule->filter.dst_ip.u.prefix, bytelen);
+                         &rule->rule.filter.dst_ip.u.prefix, bytelen);
        }
 
        /* Route table to use to forward, if filter criteria matches. */
-       if (rule->action.table < 256)
-               req.frh.table = rule->action.table;
+       if (rule->rule.action.table < 256)
+               req.frh.table = rule->rule.action.table;
        else {
                req.frh.table = RT_TABLE_UNSPEC;
                addattr32(&req.n, sizeof(req), FRA_TABLE,
-                         rule->action.table);
+                         rule->rule.action.table);
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -112,10 +112,12 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
                        "Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
                        nl_msg_type_to_str(cmd), nl_family_to_str(family),
                        rule->ifp ? rule->ifp->name : "Unknown",
-                       rule->ifp ? rule->ifp->ifindex : 0, rule->priority,
-                       prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)),
-                       prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)),
-                       rule->action.table);
+                       rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority,
+                       prefix2str(&rule->rule.filter.src_ip, buf1,
+                                  sizeof(buf1)),
+                       prefix2str(&rule->rule.filter.dst_ip, buf2,
+                                  sizeof(buf2)),
+                       rule->rule.action.table);
 
        /* Ship off the message.
         * Note: Currently, netlink_talk() is a blocking call which returns
@@ -210,44 +212,46 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
        memset(&rule, 0, sizeof(rule));
        if (tb[FRA_PRIORITY])
-               rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
+               rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
 
        if (tb[FRA_SRC]) {
                if (frh->family == AF_INET)
-                       memcpy(&rule.filter.src_ip.u.prefix4,
+                       memcpy(&rule.rule.filter.src_ip.u.prefix4,
                               RTA_DATA(tb[FRA_SRC]), 4);
                else
-                       memcpy(&rule.filter.src_ip.u.prefix6,
+                       memcpy(&rule.rule.filter.src_ip.u.prefix6,
                               RTA_DATA(tb[FRA_SRC]), 16);
-               rule.filter.src_ip.prefixlen = frh->src_len;
-               rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
+               rule.rule.filter.src_ip.prefixlen = frh->src_len;
+               rule.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
        }
 
        if (tb[FRA_DST]) {
                if (frh->family == AF_INET)
-                       memcpy(&rule.filter.dst_ip.u.prefix4,
+                       memcpy(&rule.rule.filter.dst_ip.u.prefix4,
                               RTA_DATA(tb[FRA_DST]), 4);
                else
-                       memcpy(&rule.filter.dst_ip.u.prefix6,
+                       memcpy(&rule.rule.filter.dst_ip.u.prefix6,
                               RTA_DATA(tb[FRA_DST]), 16);
-               rule.filter.dst_ip.prefixlen = frh->dst_len;
-               rule.filter.filter_bm |= PBR_FILTER_DST_IP;
+               rule.rule.filter.dst_ip.prefixlen = frh->dst_len;
+               rule.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
        }
 
        if (tb[FRA_TABLE])
-               rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]);
+               rule.rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]);
        else
-               rule.action.table = frh->table;
+               rule.rule.action.table = frh->table;
 
        if (IS_ZEBRA_DEBUG_KERNEL)
                zlog_debug(
                        "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
                        nl_msg_type_to_str(h->nlmsg_type),
                        nl_family_to_str(frh->family), rule.ifp->name,
-                       rule.ifp->ifindex, rule.priority,
-                       prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)),
-                       prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)),
-                       rule.action.table);
+                       rule.ifp->ifindex, rule.rule.priority,
+                       prefix2str(&rule.rule.filter.src_ip, buf1,
+                                  sizeof(buf1)),
+                       prefix2str(&rule.rule.filter.dst_ip, buf2,
+                                  sizeof(buf2)),
+                       rule.rule.action.table);
 
        return kernel_pbr_rule_del(&rule);
 }
index 3cc1848ee3c15350cf8c5f124ba8afd0bb866d45..7df03efc10b65f758ae70cf07b12c6d2b0fbb9cd 100644 (file)
@@ -1722,83 +1722,6 @@ void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum southbound_results res)
        }
 }
 
-/*
- * String to label conversion, labels separated by '/'.
- *
- * @param label_str labels separated by /
- * @param num_labels number of labels; zero if conversion was unsuccessful
- * @param labels preallocated mpls_label_t array of size MPLS_MAX_LABELS; only
- *               modified if the conversion succeeded
- * @return  0 on success
- *         -1 if the string could not be parsed as integers
- *         -2 if a label was inside the reserved range (0-15)
- *         -3 if the number of labels given exceeds MPLS_MAX_LABELS
- */
-int mpls_str2label(const char *label_str, uint8_t *num_labels,
-                  mpls_label_t *labels)
-{
-       char *ostr;                       // copy of label string (start)
-       char *lstr;                       // copy of label string
-       char *nump;                       // pointer to next segment
-       char *endp;                       // end pointer
-       int i;                            // for iterating label_str
-       int rc;                           // return code
-       mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels
-
-       /* labels to zero until we have a successful parse */
-       ostr = lstr = XSTRDUP(MTYPE_TMP, label_str);
-       *num_labels = 0;
-       rc = 0;
-
-       for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) {
-               nump = strsep(&lstr, "/");
-               pl[i] = strtoul(nump, &endp, 10);
-
-               /* format check */
-               if (*endp != '\0')
-                       rc = -1;
-               /* validity check */
-               else if (!IS_MPLS_UNRESERVED_LABEL(pl[i]))
-                       rc = -2;
-       }
-
-       /* excess labels */
-       if (!rc && i == MPLS_MAX_LABELS && lstr)
-               rc = -3;
-
-       if (!rc) {
-               *num_labels = i;
-               memcpy(labels, pl, *num_labels * sizeof(mpls_label_t));
-       }
-
-       XFREE(MTYPE_TMP, ostr);
-
-       return rc;
-}
-
-/*
- * Label to string conversion, labels in string separated by '/'.
- */
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
-                    int len, int pretty)
-{
-       char label_buf[BUFSIZ];
-       int i;
-
-       buf[0] = '\0';
-       for (i = 0; i < num_labels; i++) {
-               if (i != 0)
-                       strlcat(buf, "/", len);
-               if (pretty)
-                       label2str(labels[i], label_buf, sizeof(label_buf));
-               else
-                       snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
-               strlcat(buf, label_buf, len);
-       }
-
-       return buf;
-}
-
 /*
  * Install dynamic LSP entry.
  */
index 2637327a7e9038784f655659d675d7ae1e175762..98905a28315057afd1c9b1a5471f99d0c9b6fd39 100644 (file)
                 ? AF_INET6                                                    \
                 : AF_INET)
 
-#define MPLS_LABEL_HELPSTR                                                     \
-       "Specify label(s) for this route\nOne or more "                        \
-       "labels in the range (16-1048575) separated by '/'\n"
-
 /* Typedefs */
 
 typedef struct zebra_ile_t_ zebra_ile_t;
@@ -167,18 +163,6 @@ struct zebra_fec_t_ {
 
 /* Function declarations. */
 
-/*
- * String to label conversion, labels separated by '/'.
- */
-int mpls_str2label(const char *label_str, uint8_t *num_labels,
-                  mpls_label_t *labels);
-
-/*
- * Label to string conversion, labels in string separated by '/'.
- */
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
-                    int len, int pretty);
-
 /*
  * Add/update global label block.
  */
index f9beb32ac4751ba09715e0e4dad6b1d2407463cd..30f850597c65c0b848ceddb96115bf4a4a37a71a 100644 (file)
@@ -70,7 +70,7 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
        char *netnspath = ns_netns_pathname(NULL, name);
        struct vrf *vrf;
        int ret;
-       ns_id_t ns_id;
+       ns_id_t ns_id, ns_id_external;
 
        if (netnspath == NULL)
                return;
@@ -80,8 +80,9 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
        ns_id = zebra_ns_id_get(netnspath);
        if (zserv_privs.change(ZPRIVS_LOWER))
                zlog_err("Can't lower privileges");
+       ns_id_external = ns_map_nsid_with_external(ns_id, true);
        /* if VRF with NS ID already present */
-       vrf = vrf_lookup_by_id((vrf_id_t)ns_id);
+       vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
        if (vrf) {
                zlog_warn(
                        "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
@@ -90,15 +91,18 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
        }
        if (vrf_handler_create(NULL, name, &vrf) != CMD_SUCCESS) {
                zlog_warn("NS notify : failed to create VRF %s", name);
+               ns_map_nsid_with_external(ns_id, false);
                return;
        }
        if (zserv_privs.change(ZPRIVS_RAISE))
                zlog_err("Can't raise privileges");
-       ret = vrf_netns_handler_create(NULL, vrf, netnspath, ns_id);
+       ret = vrf_netns_handler_create(NULL, vrf, netnspath,
+                                      ns_id_external, ns_id);
        if (zserv_privs.change(ZPRIVS_LOWER))
                zlog_err("Can't lower privileges");
        if (ret != CMD_SUCCESS) {
                zlog_warn("NS notify : failed to create NS %s", netnspath);
+               ns_map_nsid_with_external(ns_id, false);
                return;
        }
        zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
index 7393f767afa3d20b72c67670c5b40e84cca94e32..5c62e366a63293ab96c961c6d3f01f79ebbb4993 100644 (file)
@@ -140,6 +140,20 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
                hash_create_size(8, zebra_pbr_rules_hash_key,
                                 zebra_pbr_rules_hash_equal, "Rules Hash");
 
+       zns->ipset_hash =
+               hash_create_size(8, zebra_pbr_ipset_hash_key,
+                                zebra_pbr_ipset_hash_equal, "IPset Hash");
+
+       zns->ipset_entry_hash =
+               hash_create_size(8, zebra_pbr_ipset_entry_hash_key,
+                                zebra_pbr_ipset_entry_hash_equal,
+                                "IPset Hash Entry");
+
+       zns->iptable_hash =
+               hash_create_size(8, zebra_pbr_iptable_hash_key,
+                                zebra_pbr_iptable_hash_equal,
+                                "IPtable Hash Entry");
+
 #if defined(HAVE_RTADV)
        rtadv_init(zns);
 #endif
@@ -248,6 +262,15 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
 
        hash_clean(zns->rules_hash, zebra_pbr_rules_free);
        hash_free(zns->rules_hash);
+       hash_clean(zns->ipset_hash, zebra_pbr_ipset_free);
+       hash_free(zns->ipset_hash);
+       hash_clean(zns->ipset_entry_hash,
+                  zebra_pbr_ipset_entry_free),
+       hash_free(zns->ipset_entry_hash);
+       hash_clean(zns->iptable_hash,
+                  zebra_pbr_iptable_free);
+       hash_free(zns->iptable_hash);
+
        while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) {
                znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables);
 
@@ -274,6 +297,7 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
 int zebra_ns_init(void)
 {
        ns_id_t ns_id;
+       ns_id_t ns_id_external;
 
        dzns = zebra_ns_alloc();
 
@@ -282,8 +306,8 @@ int zebra_ns_init(void)
        ns_id = zebra_ns_id_get_default();
        if (zserv_privs.change(ZPRIVS_LOWER))
                zlog_err("Can't lower privileges");
-
-       ns_init_management(ns_id);
+       ns_id_external = ns_map_nsid_with_external(ns_id, true);
+       ns_init_management(ns_id_external, ns_id);
 
        logicalrouter_init(logicalrouter_config_write);
 
@@ -295,7 +319,7 @@ int zebra_ns_init(void)
        zebra_vrf_init();
 
        /* Default NS is activated */
-       zebra_ns_enable(ns_id, (void **)&dzns);
+       zebra_ns_enable(ns_id_external, (void **)&dzns);
 
        if (vrf_is_backend_netns()) {
                ns_add_hook(NS_NEW_HOOK, zebra_ns_new);
index 66b73148d2111f283943518ecc01d2bbfb691662..fbf88ae6ea0795349750161317ff915cabba6331 100644 (file)
@@ -73,6 +73,12 @@ struct zebra_ns {
 
        struct hash *rules_hash;
 
+       struct hash *ipset_hash;
+
+       struct hash *ipset_entry_hash;
+
+       struct hash *iptable_hash;
+
        /* Back pointer */
        struct ns *ns;
 };
index 4b931688468c6b1947eb8efdb12b1f45b3ccaf01..758365d716aab84a9e27067251fe7e936867646d 100644 (file)
@@ -50,16 +50,22 @@ uint32_t zebra_pbr_rules_hash_key(void *arg)
        uint32_t key;
 
        rule = (struct zebra_pbr_rule *)arg;
-       key = jhash_3words(rule->seq, rule->priority, rule->action.table,
-                          prefix_hash_key(&rule->filter.src_ip));
+       key = jhash_3words(rule->rule.seq, rule->rule.priority,
+                          rule->rule.action.table,
+                          prefix_hash_key(&rule->rule.filter.src_ip));
        if (rule->ifp)
                key = jhash_1word(rule->ifp->ifindex, key);
        else
                key = jhash_1word(0, key);
 
-       return jhash_3words(rule->filter.src_port, rule->filter.dst_port,
-                           prefix_hash_key(&rule->filter.dst_ip),
-                           jhash_1word(rule->unique, key));
+       if (rule->rule.filter.fwmark)
+               key = jhash_1word(rule->rule.filter.fwmark, key);
+       else
+               key = jhash_1word(0, key);
+       return jhash_3words(rule->rule.filter.src_port,
+                           rule->rule.filter.dst_port,
+                           prefix_hash_key(&rule->rule.filter.dst_ip),
+                           jhash_1word(rule->rule.unique, key));
 }
 
 int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
@@ -69,28 +75,31 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
        r1 = (const struct zebra_pbr_rule *)arg1;
        r2 = (const struct zebra_pbr_rule *)arg2;
 
-       if (r1->seq != r2->seq)
+       if (r1->rule.seq != r2->rule.seq)
                return 0;
 
-       if (r1->priority != r2->priority)
+       if (r1->rule.priority != r2->rule.priority)
                return 0;
 
-       if (r1->unique != r2->unique)
+       if (r1->rule.unique != r2->rule.unique)
                return 0;
 
-       if (r1->action.table != r2->action.table)
+       if (r1->rule.action.table != r2->rule.action.table)
                return 0;
 
-       if (r1->filter.src_port != r2->filter.src_port)
+       if (r1->rule.filter.src_port != r2->rule.filter.src_port)
                return 0;
 
-       if (r1->filter.dst_port != r2->filter.dst_port)
+       if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
                return 0;
 
-       if (!prefix_same(&r1->filter.src_ip, &r2->filter.src_ip))
+       if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
                return 0;
 
-       if (!prefix_same(&r1->filter.dst_ip, &r2->filter.dst_ip))
+       if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
+               return 0;
+
+       if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
                return 0;
 
        if (r1->ifp != r2->ifp)
@@ -99,17 +108,18 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
        return 1;
 }
 
-struct pbr_unique_lookup {
+struct pbr_rule_unique_lookup {
        struct zebra_pbr_rule *rule;
        uint32_t unique;
+       struct interface *ifp;
 };
 
 static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
 {
-       struct pbr_unique_lookup *pul = data;
+       struct pbr_rule_unique_lookup *pul = data;
        struct zebra_pbr_rule *rule = b->data;
 
-       if (pul->unique == rule->unique) {
+       if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
                pul->rule = rule;
                return HASHWALK_ABORT;
        }
@@ -118,17 +128,139 @@ static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
 }
 
 static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
-                                                    uint32_t unique)
+                                                    uint32_t unique,
+                                                    struct interface *ifp)
 {
-       struct pbr_unique_lookup pul;
+       struct pbr_rule_unique_lookup pul;
 
        pul.unique = unique;
+       pul.ifp = ifp;
        pul.rule = NULL;
        hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
 
        return pul.rule;
 }
 
+void zebra_pbr_ipset_free(void *arg)
+{
+       struct zebra_pbr_ipset *ipset;
+
+       ipset = (struct zebra_pbr_ipset *)arg;
+
+       XFREE(MTYPE_TMP, ipset);
+}
+
+uint32_t zebra_pbr_ipset_hash_key(void *arg)
+{
+       struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg;
+       uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
+
+       return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de);
+}
+
+int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
+{
+       const struct zebra_pbr_ipset *r1, *r2;
+
+       r1 = (const struct zebra_pbr_ipset *)arg1;
+       r2 = (const struct zebra_pbr_ipset *)arg2;
+
+       if (r1->type != r2->type)
+               return 0;
+       if (r1->unique != r2->unique)
+               return 0;
+       if (strncmp(r1->ipset_name, r2->ipset_name,
+                   ZEBRA_IPSET_NAME_SIZE))
+               return 0;
+       return 1;
+}
+
+void zebra_pbr_ipset_entry_free(void *arg)
+{
+       struct zebra_pbr_ipset_entry *ipset;
+
+       ipset = (struct zebra_pbr_ipset_entry *)arg;
+
+       XFREE(MTYPE_TMP, ipset);
+}
+
+uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
+{
+       struct zebra_pbr_ipset_entry *ipset;
+       uint32_t key;
+
+       ipset = (struct zebra_pbr_ipset_entry *)arg;
+       key = prefix_hash_key(&ipset->src);
+       key = jhash_1word(ipset->unique, key);
+       key = jhash_1word(prefix_hash_key(&ipset->dst), key);
+
+       return key;
+}
+
+int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
+{
+       const struct zebra_pbr_ipset_entry *r1, *r2;
+
+       r1 = (const struct zebra_pbr_ipset_entry *)arg1;
+       r2 = (const struct zebra_pbr_ipset_entry *)arg2;
+
+       if (r1->unique != r2->unique)
+               return 0;
+
+       if (!prefix_same(&r1->src, &r2->src))
+               return 0;
+
+       if (!prefix_same(&r1->dst, &r2->dst))
+               return 0;
+
+       return 1;
+}
+
+void zebra_pbr_iptable_free(void *arg)
+{
+       struct zebra_pbr_iptable *iptable;
+
+       iptable = (struct zebra_pbr_iptable *)arg;
+
+       XFREE(MTYPE_TMP, iptable);
+}
+
+uint32_t zebra_pbr_iptable_hash_key(void *arg)
+{
+       struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg;
+       uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
+       uint32_t key;
+
+       key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
+                    0x63ab42de);
+       key = jhash_1word(iptable->fwmark, key);
+       return jhash_3words(iptable->filter_bm, iptable->type,
+                           iptable->unique, key);
+}
+
+int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
+{
+       const struct zebra_pbr_iptable *r1, *r2;
+
+       r1 = (const struct zebra_pbr_iptable *)arg1;
+       r2 = (const struct zebra_pbr_iptable *)arg2;
+
+       if (r1->type != r2->type)
+               return 0;
+       if (r1->unique != r2->unique)
+               return 0;
+       if (r1->filter_bm != r2->filter_bm)
+               return 0;
+       if (r1->fwmark != r2->fwmark)
+               return 0;
+       if (r1->action != r2->action)
+               return 0;
+       if (strncmp(r1->ipset_name, r2->ipset_name,
+                   ZEBRA_IPSET_NAME_SIZE))
+               return 0;
+       return 1;
+}
+
 static void *pbr_rule_alloc_intern(void *arg)
 {
        struct zebra_pbr_rule *zpr;
@@ -146,7 +278,7 @@ static void *pbr_rule_alloc_intern(void *arg)
 void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
 {
        struct zebra_pbr_rule *unique =
-               pbr_rule_lookup_unique(zns, rule->unique);
+               pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
 
        (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
        kernel_add_pbr_rule(rule);
@@ -194,6 +326,162 @@ void zebra_pbr_client_close_cleanup(int sock)
        hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
 }
 
+static void *pbr_ipset_alloc_intern(void *arg)
+{
+       struct zebra_pbr_ipset *zpi;
+       struct zebra_pbr_ipset *new;
+
+       zpi = (struct zebra_pbr_ipset *)arg;
+
+       new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
+
+       memcpy(new, zpi, sizeof(*zpi));
+
+       return new;
+}
+
+void zebra_pbr_create_ipset(struct zebra_ns *zns,
+                           struct zebra_pbr_ipset *ipset)
+{
+       (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern);
+       /* TODO:
+        * - Netlink call
+        */
+}
+
+void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
+                            struct zebra_pbr_ipset *ipset)
+{
+       struct zebra_pbr_ipset *lookup;
+
+       lookup = hash_lookup(zns->ipset_hash, ipset);
+       /* TODO:
+        * - Netlink destroy from kernel
+        * - ?? destroy ipset entries before
+        */
+       if (lookup)
+               XFREE(MTYPE_TMP, lookup);
+       else
+               zlog_warn("%s: IPSet Entry being deleted we know nothing about",
+                         __PRETTY_FUNCTION__);
+}
+
+struct pbr_ipset_name_lookup {
+       struct zebra_pbr_ipset *ipset;
+       char ipset_name[ZEBRA_IPSET_NAME_SIZE];
+};
+
+static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg)
+{
+       struct pbr_ipset_name_lookup *pinl =
+               (struct pbr_ipset_name_lookup *)arg;
+       struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
+
+       if (!strncmp(pinl->ipset_name, zpi->ipset_name,
+                    ZEBRA_IPSET_NAME_SIZE)) {
+               pinl->ipset = zpi;
+               return HASHWALK_ABORT;
+       }
+       return HASHWALK_CONTINUE;
+}
+
+struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns,
+                                                      char *ipsetname)
+{
+       struct pbr_ipset_name_lookup pinl;
+       struct pbr_ipset_name_lookup *ptr = &pinl;
+
+       if (!ipsetname)
+               return NULL;
+       memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
+       snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
+               ipsetname);
+       hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
+       return ptr->ipset;
+}
+
+static void *pbr_ipset_entry_alloc_intern(void *arg)
+{
+       struct zebra_pbr_ipset_entry *zpi;
+       struct zebra_pbr_ipset_entry *new;
+
+       zpi = (struct zebra_pbr_ipset_entry *)arg;
+
+       new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
+
+       memcpy(new, zpi, sizeof(*zpi));
+
+       return new;
+}
+
+void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
+                              struct zebra_pbr_ipset_entry *ipset)
+{
+       (void)hash_get(zns->ipset_entry_hash, ipset,
+                      pbr_ipset_entry_alloc_intern);
+       /* TODO:
+        * - attach to ipset list
+        * - Netlink add to kernel
+        */
+}
+
+void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
+                              struct zebra_pbr_ipset_entry *ipset)
+{
+       struct zebra_pbr_ipset_entry *lookup;
+
+       lookup = hash_lookup(zns->ipset_entry_hash, ipset);
+       /* TODO:
+        * - Netlink destroy
+        * - detach from ipset list
+        * - ?? if no more entres, delete ipset
+        */
+       if (lookup)
+               XFREE(MTYPE_TMP, lookup);
+       else
+               zlog_warn("%s: IPSet being deleted we know nothing about",
+                         __PRETTY_FUNCTION__);
+}
+
+static void *pbr_iptable_alloc_intern(void *arg)
+{
+       struct zebra_pbr_iptable *zpi;
+       struct zebra_pbr_iptable *new;
+
+       zpi = (struct zebra_pbr_iptable *)arg;
+
+       new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+
+       memcpy(new, zpi, sizeof(*zpi));
+
+       return new;
+}
+
+void zebra_pbr_add_iptable(struct zebra_ns *zns,
+                          struct zebra_pbr_iptable *iptable)
+{
+       (void)hash_get(zns->iptable_hash, iptable,
+                      pbr_iptable_alloc_intern);
+       /* TODO call netlink layer */
+}
+
+void zebra_pbr_del_iptable(struct zebra_ns *zns,
+                          struct zebra_pbr_iptable *iptable)
+{
+       struct zebra_pbr_ipset_entry *lookup;
+
+       lookup = hash_lookup(zns->iptable_hash, iptable);
+       /* TODO:
+        * - call netlink layer
+        * - detach from iptable list
+        */
+       if (lookup)
+               XFREE(MTYPE_TMP, lookup);
+       else
+               zlog_warn("%s: IPTable being deleted we know nothing about",
+                         __PRETTY_FUNCTION__);
+}
+
 /*
  * Handle success or failure of rule (un)install in the kernel.
  */
@@ -208,8 +496,73 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
                zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
+               break;
+       case SOUTHBOUND_DELETE_FAILURE:
+               zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
+               break;
+       }
+}
+
+/*
+ * Handle success or failure of ipset (un)install in the kernel.
+ */
+void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
+                                   enum southbound_results res)
+{
+       switch (res) {
+       case SOUTHBOUND_INSTALL_SUCCESS:
+               zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED);
+               break;
+       case SOUTHBOUND_INSTALL_FAILURE:
+               zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
+               break;
+       case SOUTHBOUND_DELETE_SUCCESS:
+       case SOUTHBOUND_DELETE_FAILURE:
+               /* TODO : handling of delete event */
+               break;
+       }
+}
+
+/*
+ * Handle success or failure of ipset (un)install in the kernel.
+ */
+void kernel_pbr_ipset_entry_add_del_status(
+                       struct zebra_pbr_ipset_entry *ipset,
+                       enum southbound_results res)
+{
+       switch (res) {
+       case SOUTHBOUND_INSTALL_SUCCESS:
+               zsend_ipset_entry_notify_owner(ipset,
+                                              ZAPI_IPSET_ENTRY_INSTALLED);
+               break;
+       case SOUTHBOUND_INSTALL_FAILURE:
+               zsend_ipset_entry_notify_owner(ipset,
+                                              ZAPI_IPSET_ENTRY_FAIL_INSTALL);
+               break;
+       case SOUTHBOUND_DELETE_SUCCESS:
+       case SOUTHBOUND_DELETE_FAILURE:
+               /* TODO : handling of delete event */
                break;
+       }
+}
+
+/*
+ * Handle success or failure of ipset (un)install in the kernel.
+ */
+void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
+                                      enum southbound_results res)
+{
+       switch (res) {
+       case SOUTHBOUND_INSTALL_SUCCESS:
+               zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
+               break;
+       case SOUTHBOUND_INSTALL_FAILURE:
+               zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
+               break;
+       case SOUTHBOUND_DELETE_SUCCESS:
        case SOUTHBOUND_DELETE_FAILURE:
+               /* TODO : handling of delete event */
                break;
        }
 }
index f910d8e742b8555eae08dd359daa4c3aa26b8099..0ac629cc659d7d254d55551196283e372a34414d 100644 (file)
 #include "if.h"
 
 #include "rt.h"
+#include "pbr.h"
 
-/*
- * A PBR filter
- *
- * The filter or match criteria in a PBR rule.
- * For simplicity, all supported filters are grouped into a structure rather
- * than delineating further. A bitmask denotes which filters are actually
- * specified.
- */
-struct zebra_pbr_filter {
-       uint32_t filter_bm;
-#define PBR_FILTER_SRC_IP     (1 << 0)
-#define PBR_FILTER_DST_IP     (1 << 1)
-#define PBR_FILTER_SRC_PORT   (1 << 2)
-#define PBR_FILTER_DST_PORT   (1 << 3)
-
-       /* Source and Destination IP address with masks. */
-       struct prefix src_ip;
-       struct prefix dst_ip;
-
-       /* Source and Destination higher-layer (TCP/UDP) port numbers. */
-       uint16_t src_port;
-       uint16_t dst_port;
+struct zebra_pbr_rule {
+       int sock;
+
+       struct pbr_rule rule;
+
+       struct interface *ifp;
 };
 
 #define IS_RULE_FILTERING_ON_SRC_IP(r) \
-       (r->filter.filter_bm & PBR_FILTER_SRC_IP)
+       (r->rule.filter.filter_bm & PBR_FILTER_SRC_IP)
 #define IS_RULE_FILTERING_ON_DST_IP(r) \
-       (r->filter.filter_bm & PBR_FILTER_DST_IP)
+       (r->rule.filter.filter_bm & PBR_FILTER_DST_IP)
 #define IS_RULE_FILTERING_ON_SRC_PORT(r) \
-       (r->filter.filter_bm & PBR_FILTER_SRC_PORT)
+       (r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT)
 #define IS_RULE_FILTERING_ON_DST_PORT(r) \
-       (r->filter.filter_bm & PBR_FILTER_DST_PORT)
+       (r->rule.filter.filter_bm & PBR_FILTER_DST_PORT)
 
 /*
- * A PBR action
+ * An IPSet Entry Filter
  *
- * The action corresponding to a PBR rule.
- * While the user specifies the action in a particular way, the forwarding
- * plane implementation (Linux only) requires that to be encoded into a
- * route table and the rule then point to that route table; in some cases,
- * the user criteria may directly point to a table too.
+ * This is a filter mapped on ipset entries
  */
-struct zebra_pbr_action {
-       uint32_t table;
+struct zebra_pbr_ipset {
+       /*
+        * Originating zclient sock fd, so we can know who to send
+        * back to.
+        */
+       int sock;
+
+       uint32_t unique;
+
+       /* type is encoded as uint32_t
+        * but value is an enum ipset_type
+        */
+       uint32_t type;
+       char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
 /*
- * A PBR rule
+ * An IPSet Entry Filter
  *
- * This is a combination of the filter criteria and corresponding action.
- * Rules also have a user-defined sequence number which defines the relative
- * order amongst rules.
+ * This is a filter mapped on ipset entries
  */
-struct zebra_pbr_rule {
+struct zebra_pbr_ipset_entry {
        /*
         * Originating zclient sock fd, so we can know who to send
         * back to.
         */
        int sock;
 
-       uint32_t seq;
-       uint32_t priority;
-       struct interface *ifp;
        uint32_t unique;
-       struct zebra_pbr_filter filter;
-       struct zebra_pbr_action action;
+
+       struct prefix src;
+       struct prefix dst;
+
+       uint32_t filter_bm;
+
+       struct zebra_pbr_ipset *backpointer;
+};
+
+/*
+ * An IPTables Action
+ *
+ * This is a filter mapped on ipset entries
+ */
+struct zebra_pbr_iptable {
+       /*
+        * Originating zclient sock fd, so we can know who to send
+        * back to.
+        */
+       int sock;
+
+       uint32_t unique;
+
+       /* include ipset type
+        */
+       uint32_t type;
+
+       /* include which IP is to be filtered
+        */
+       uint32_t filter_bm;
+
+       uint32_t fwmark;
+
+       uint32_t action;
+
+       char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
 void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
 void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
+void zebra_pbr_create_ipset(struct zebra_ns *zns,
+                           struct zebra_pbr_ipset *ipset);
+void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
+                            struct zebra_pbr_ipset *ipset);
+struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns,
+                                                      char *ipsetname);
+void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
+                              struct zebra_pbr_ipset_entry *ipset);
+void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
+                              struct zebra_pbr_ipset_entry *ipset);
+
+void zebra_pbr_add_iptable(struct zebra_ns *zns,
+                          struct zebra_pbr_iptable *iptable);
+void zebra_pbr_del_iptable(struct zebra_ns *zns,
+                          struct zebra_pbr_iptable *iptable);
 
 /*
  * Install specified rule for a specific interface.
@@ -127,6 +164,19 @@ enum southbound_results;
 extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
                                           enum southbound_results res);
 
+/*
+ * Handle success or failure of ipset kinds (un)install in the kernel.
+ */
+extern void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
+                                          enum southbound_results res);
+
+extern void kernel_pbr_ipset_entry_add_del_status(
+                               struct zebra_pbr_ipset_entry *ipset,
+                               enum southbound_results res);
+
+extern void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
+                             enum southbound_results res);
+
 /*
  * Handle rule delete notification from kernel.
  */
@@ -138,4 +188,21 @@ extern void zebra_pbr_rules_free(void *arg);
 extern uint32_t zebra_pbr_rules_hash_key(void *arg);
 extern int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2);
 
+/* has operates on 32bit pointer
+ * and field is a string of 8bit
+ */
+#define ZEBRA_IPSET_NAME_HASH_SIZE (ZEBRA_IPSET_NAME_SIZE / 4)
+
+extern void zebra_pbr_ipset_free(void *arg);
+extern uint32_t zebra_pbr_ipset_hash_key(void *arg);
+extern int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2);
+
+extern void zebra_pbr_ipset_entry_free(void *arg);
+extern uint32_t zebra_pbr_ipset_entry_hash_key(void *arg);
+extern int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2);
+
+extern void zebra_pbr_iptable_free(void *arg);
+extern uint32_t zebra_pbr_iptable_hash_key(void *arg);
+extern int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2);
+
 #endif /* _ZEBRA_PBR_H */
index 879da092f0e199f92dce93f19f4af4ebe067f4c4..22a04ee23dfa6929ae4a9cb302f820e00d1241a7 100644 (file)
@@ -561,8 +561,10 @@ static void zebra_rnh_process_pbr_tables(int family,
                         * just rethink it.  Yes this is a hammer, but
                         * a small one
                         */
-                       if (o_re)
+                       if (o_re) {
+                               SET_FLAG(o_re->status, ROUTE_ENTRY_CHANGED);
                                rib_queue_add(o_rn);
+                       }
                }
        }
 }
index c06efbfb4bf288d319c3a52e5dddcff6ed3a3e2d..94c20c1d136812ec3e0dabaa6f256686eeb4ec20 100644 (file)
@@ -725,10 +725,9 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
        struct zserv *client;
        struct stream *s;
 
-       if (IS_ZEBRA_DEBUG_PACKET) {
+       if (IS_ZEBRA_DEBUG_PACKET)
                zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
-                          rule->unique);
-       }
+                          rule->rule.unique);
 
        for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
                if (rule->sock == client->sock)
@@ -739,13 +738,12 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
                return;
 
        s = stream_new(ZEBRA_MAX_PACKET_SIZ);
-       stream_reset(s);
 
        zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT);
        stream_put(s, &note, sizeof(note));
-       stream_putl(s, rule->seq);
-       stream_putl(s, rule->priority);
-       stream_putl(s, rule->unique);
+       stream_putl(s, rule->rule.seq);
+       stream_putl(s, rule->rule.priority);
+       stream_putl(s, rule->rule.unique);
        if (rule->ifp)
                stream_putl(s, rule->ifp->ifindex);
        else
@@ -756,6 +754,98 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
        zebra_server_send_message(client, s);
 }
 
+void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset,
+                            enum zapi_ipset_notify_owner note)
+{
+       struct listnode *node;
+       struct zserv *client;
+       struct stream *s;
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
+                          ipset->unique);
+
+       for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+               if (ipset->sock == client->sock)
+                       break;
+       }
+
+       if (!client)
+               return;
+
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_IPSET_NOTIFY_OWNER, VRF_DEFAULT);
+       stream_put(s, &note, sizeof(note));
+       stream_putl(s, ipset->unique);
+       stream_put(s, ipset->ipset_name, ZEBRA_IPSET_NAME_SIZE);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       zebra_server_send_message(client, s);
+}
+
+void zsend_ipset_entry_notify_owner(
+                       struct zebra_pbr_ipset_entry *ipset,
+                       enum zapi_ipset_entry_notify_owner note)
+{
+       struct listnode *node;
+       struct zserv *client;
+       struct stream *s;
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
+                          ipset->unique);
+
+       for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+               if (ipset->sock == client->sock)
+                       break;
+       }
+
+       if (!client)
+               return;
+
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_IPSET_ENTRY_NOTIFY_OWNER,
+                             VRF_DEFAULT);
+       stream_put(s, &note, sizeof(note));
+       stream_putl(s, ipset->unique);
+       stream_put(s, ipset->backpointer->ipset_name,
+                  ZEBRA_IPSET_NAME_SIZE);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       zebra_server_send_message(client, s);
+}
+
+void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable,
+                            enum zapi_iptable_notify_owner note)
+{
+       struct listnode *node;
+       struct zserv *client;
+       struct stream *s;
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
+                          iptable->unique);
+
+       for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+               if (iptable->sock == client->sock)
+                       break;
+       }
+
+       if (!client)
+               return;
+
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_IPTABLE_NOTIFY_OWNER, VRF_DEFAULT);
+       stream_put(s, &note, sizeof(note));
+       stream_putl(s, iptable->unique);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       zebra_server_send_message(client, s);
+}
+
 /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
 int zsend_router_id_update(struct zserv *client, struct prefix *p,
                           vrf_id_t vrf_id)
@@ -2667,39 +2757,47 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
                memset(&zpr, 0, sizeof(zpr));
 
                zpr.sock = client->sock;
-               STREAM_GETL(s, zpr.seq);
-               STREAM_GETL(s, zpr.priority);
-               STREAM_GETL(s, zpr.unique);
-               STREAM_GETC(s, zpr.filter.src_ip.family);
-               STREAM_GETC(s, zpr.filter.src_ip.prefixlen);
-               STREAM_GET(&zpr.filter.src_ip.u.prefix, s,
-                          prefix_blen(&zpr.filter.src_ip));
-               STREAM_GETW(s, zpr.filter.src_port);
-               STREAM_GETC(s, zpr.filter.dst_ip.family);
-               STREAM_GETC(s, zpr.filter.dst_ip.prefixlen);
-               STREAM_GET(&zpr.filter.dst_ip.u.prefix, s,
-                          prefix_blen(&zpr.filter.dst_ip));
-               STREAM_GETW(s, zpr.filter.dst_port);
-               STREAM_GETL(s, zpr.action.table);
+               zpr.rule.vrf_id = hdr->vrf_id;
+               STREAM_GETL(s, zpr.rule.seq);
+               STREAM_GETL(s, zpr.rule.priority);
+               STREAM_GETL(s, zpr.rule.unique);
+               STREAM_GETC(s, zpr.rule.filter.src_ip.family);
+               STREAM_GETC(s, zpr.rule.filter.src_ip.prefixlen);
+               STREAM_GET(&zpr.rule.filter.src_ip.u.prefix, s,
+                          prefix_blen(&zpr.rule.filter.src_ip));
+               STREAM_GETW(s, zpr.rule.filter.src_port);
+               STREAM_GETC(s, zpr.rule.filter.dst_ip.family);
+               STREAM_GETC(s, zpr.rule.filter.dst_ip.prefixlen);
+               STREAM_GET(&zpr.rule.filter.dst_ip.u.prefix, s,
+                          prefix_blen(&zpr.rule.filter.dst_ip));
+               STREAM_GETW(s, zpr.rule.filter.dst_port);
+               STREAM_GETL(s, zpr.rule.filter.fwmark);
+               STREAM_GETL(s, zpr.rule.action.table);
                STREAM_GETL(s, ifindex);
 
-               zpr.ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN);
-               if (!zpr.ifp) {
-                       zlog_debug("FAiled to lookup ifindex: %u", ifindex);
-                       return;
+               if (ifindex) {
+                       zpr.ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN);
+                       if (!zpr.ifp) {
+                               zlog_debug("Failed to lookup ifindex: %u",
+                                          ifindex);
+                               return;
+                       }
                }
 
-               if (!is_default_prefix(&zpr.filter.src_ip))
-                       zpr.filter.filter_bm |= PBR_FILTER_SRC_IP;
+               if (!is_default_prefix(&zpr.rule.filter.src_ip))
+                       zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
+
+               if (!is_default_prefix(&zpr.rule.filter.dst_ip))
+                       zpr.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
 
-               if (!is_default_prefix(&zpr.filter.dst_ip))
-                       zpr.filter.filter_bm |= PBR_FILTER_DST_IP;
+               if (zpr.rule.filter.src_port)
+                       zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_PORT;
 
-               if (zpr.filter.src_port)
-                       zpr.filter.filter_bm |= PBR_FILTER_SRC_PORT;
+               if (zpr.rule.filter.dst_port)
+                       zpr.rule.filter.filter_bm |= PBR_FILTER_DST_PORT;
 
-               if (zpr.filter.dst_port)
-                       zpr.filter.filter_bm |= PBR_FILTER_DST_PORT;
+               if (zpr.rule.filter.fwmark)
+                       zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK;
 
                if (hdr->command == ZEBRA_RULE_ADD)
                        zebra_pbr_add_rule(zvrf->zns, &zpr);
@@ -2711,6 +2809,107 @@ stream_failure:
        return;
 }
 
+
+static inline void zread_ipset(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_pbr_ipset zpi;
+       struct stream *s;
+       uint32_t total, i;
+
+       s = msg;
+       STREAM_GETL(s, total);
+
+       for (i = 0; i < total; i++) {
+               memset(&zpi, 0, sizeof(zpi));
+
+               zpi.sock = client->sock;
+               STREAM_GETL(s, zpi.unique);
+               STREAM_GETL(s, zpi.type);
+               STREAM_GET(&zpi.ipset_name, s,
+                          ZEBRA_IPSET_NAME_SIZE);
+
+               if (hdr->command == ZEBRA_IPSET_CREATE)
+                       zebra_pbr_create_ipset(zvrf->zns, &zpi);
+               else
+                       zebra_pbr_destroy_ipset(zvrf->zns, &zpi);
+       }
+
+stream_failure:
+       return;
+}
+
+static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_pbr_ipset_entry zpi;
+       struct zebra_pbr_ipset ipset;
+       struct stream *s;
+       uint32_t total, i;
+
+       s = msg;
+       STREAM_GETL(s, total);
+
+       for (i = 0; i < total; i++) {
+               memset(&zpi, 0, sizeof(zpi));
+               memset(&ipset, 0, sizeof(ipset));
+
+               zpi.sock = client->sock;
+               STREAM_GETL(s, zpi.unique);
+               STREAM_GET(&ipset.ipset_name, s,
+                          ZEBRA_IPSET_NAME_SIZE);
+               STREAM_GETC(s, zpi.src.family);
+               STREAM_GETC(s, zpi.src.prefixlen);
+               STREAM_GET(&zpi.src.u.prefix, s,
+                          prefix_blen(&zpi.src));
+               STREAM_GETC(s, zpi.dst.family);
+               STREAM_GETC(s, zpi.dst.prefixlen);
+               STREAM_GET(&zpi.dst.u.prefix, s,
+                          prefix_blen(&zpi.dst));
+
+               if (!is_default_prefix(&zpi.src))
+                       zpi.filter_bm |= PBR_FILTER_SRC_IP;
+
+               if (!is_default_prefix(&zpi.dst))
+                       zpi.filter_bm |= PBR_FILTER_DST_IP;
+
+               /* calculate backpointer */
+               zpi.backpointer = zebra_pbr_lookup_ipset_pername(zvrf->zns,
+                                                        ipset.ipset_name);
+               if (hdr->command == ZEBRA_IPSET_ENTRY_ADD)
+                       zebra_pbr_add_ipset_entry(zvrf->zns, &zpi);
+               else
+                       zebra_pbr_del_ipset_entry(zvrf->zns, &zpi);
+       }
+
+stream_failure:
+       return;
+}
+
+static inline void zread_iptable(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_pbr_iptable zpi;
+       struct stream *s;
+
+       s = msg;
+
+       memset(&zpi, 0, sizeof(zpi));
+
+       zpi.sock = client->sock;
+       STREAM_GETL(s, zpi.unique);
+       STREAM_GETL(s, zpi.type);
+       STREAM_GETL(s, zpi.filter_bm);
+       STREAM_GETL(s, zpi.action);
+       STREAM_GETL(s, zpi.fwmark);
+       STREAM_GET(&zpi.ipset_name, s,
+                  ZEBRA_IPSET_NAME_SIZE);
+
+       if (hdr->command == ZEBRA_IPTABLE_ADD)
+               zebra_pbr_add_iptable(zvrf->zns, &zpi);
+       else
+               zebra_pbr_del_iptable(zvrf->zns, &zpi);
+stream_failure:
+       return;
+}
+
 void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_ROUTER_ID_ADD] = zread_router_id_add,
        [ZEBRA_ROUTER_ID_DELETE] = zread_router_id_delete,
@@ -2771,6 +2970,12 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_TABLE_MANAGER_CONNECT] = zread_table_manager_request,
        [ZEBRA_GET_TABLE_CHUNK] = zread_table_manager_request,
        [ZEBRA_RELEASE_TABLE_CHUNK] = zread_table_manager_request,
+       [ZEBRA_IPSET_CREATE] = zread_ipset,
+       [ZEBRA_IPSET_DESTROY] = zread_ipset,
+       [ZEBRA_IPSET_ENTRY_ADD] = zread_ipset_entry,
+       [ZEBRA_IPSET_ENTRY_DELETE] = zread_ipset_entry,
+       [ZEBRA_IPTABLE_ADD] = zread_iptable,
+       [ZEBRA_IPTABLE_DELETE] = zread_iptable,
 };
 
 static inline void zserv_handle_commands(struct zserv *client,
index 947e11e35bf6c05d7e75c1b07ba81ac0e9ffddec..503d85f5b6a39c652738d3dbd34c9a1e20899af6 100644 (file)
@@ -28,6 +28,7 @@
 #include "routemap.h"
 #include "vty.h"
 #include "zclient.h"
+#include "pbr.h"
 
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_pw.h"
@@ -187,9 +188,21 @@ extern int zsend_pw_update(struct zserv *, struct zebra_pw *);
 extern int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
                                    enum zapi_route_notify_owner note);
 
+struct zebra_pbr_ipset;
+struct zebra_pbr_ipset_entry;
+struct zebra_pbr_iptable;
 struct zebra_pbr_rule;
 extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
                                    enum zapi_rule_notify_owner note);
+extern void zsend_ipset_notify_owner(
+                       struct zebra_pbr_ipset *ipset,
+                       enum zapi_ipset_notify_owner note);
+extern void zsend_ipset_entry_notify_owner(
+                       struct zebra_pbr_ipset_entry *ipset,
+                       enum zapi_ipset_entry_notify_owner note);
+extern void zsend_iptable_notify_owner(
+                       struct zebra_pbr_iptable *iptable,
+                       enum zapi_iptable_notify_owner note);
 
 extern void zserv_nexthop_num_warn(const char *, const struct prefix *,
                                   const unsigned int);