diff options
| -rw-r--r-- | bgpd/bgp_vty.c | 43 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 48 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.h | 8 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 46 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 6 | ||||
| -rw-r--r-- | doc/user/bgp.rst | 22 | ||||
| -rw-r--r-- | pbrd/pbr_map.c | 13 | ||||
| -rw-r--r-- | pbrd/pbr_zebra.c | 8 | ||||
| -rw-r--r-- | pbrd/pbr_zebra.h | 2 | ||||
| -rw-r--r-- | tests/topotests/bgp_features/r1/ip_route.json | 382 | ||||
| -rw-r--r-- | tests/topotests/bgp_features/r1/ip_route_norib.json | 296 | ||||
| -rw-r--r-- | tests/topotests/bgp_features/test_bgp_features.py | 129 | ||||
| -rwxr-xr-x | tests/topotests/pim-basic/mcast-rx.py | 6 | ||||
| -rwxr-xr-x | tests/topotests/pim-basic/mcast-tx.py | 30 | ||||
| -rw-r--r-- | zebra/zebra_fpm_netlink.c | 16 |
15 files changed, 1036 insertions, 19 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 005fad1409..795a4adfc7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1411,6 +1411,41 @@ DEFUN (no_bgp_cluster_id, return CMD_SUCCESS; } +DEFPY (bgp_norib, + bgp_norib_cmd, + "bgp no-rib", + BGP_STR + "Disable BGP route installation to RIB (Zebra)\n") +{ + if (bgp_option_check(BGP_OPT_NO_FIB)) { + vty_out(vty, + "%% No-RIB option is already set, nothing to do here.\n"); + return CMD_SUCCESS; + } + + bgp_option_norib_set_runtime(); + + return CMD_SUCCESS; +} + +DEFPY (no_bgp_norib, + no_bgp_norib_cmd, + "no bgp no-rib", + NO_STR + BGP_STR + "Disable BGP route installation to RIB (Zebra)\n") +{ + if (!bgp_option_check(BGP_OPT_NO_FIB)) { + vty_out(vty, + "%% No-RIB option is not set, nothing to do here.\n"); + return CMD_SUCCESS; + } + + bgp_option_norib_unset_runtime(); + + return CMD_SUCCESS; +} + DEFUN (bgp_confederation_identifier, bgp_confederation_identifier_cmd, "bgp confederation identifier (1-4294967295)", @@ -15607,6 +15642,10 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, "bgp graceful-shutdown\n"); + /* No-RIB (Zebra) option flag configuration */ + if (bgp_option_check(BGP_OPT_NO_FIB)) + vty_out(vty, "bgp no-rib\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -16151,6 +16190,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_cluster_id_cmd); install_element(BGP_NODE, &no_bgp_cluster_id_cmd); + /* "bgp no-rib" commands. */ + install_element(CONFIG_NODE, &bgp_norib_cmd); + install_element(CONFIG_NODE, &no_bgp_norib_cmd); + /* "bgp confederation" commands. */ install_element(BGP_NODE, &bgp_confederation_identifier_cmd); install_element(BGP_NODE, &no_bgp_confederation_identifier_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index b203238520..a32e47f446 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1543,6 +1543,30 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) pi, bgp, afi, safi); } +/* Announce routes of any bgp subtype of a table to zebra */ +void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, + safi_t safi) +{ + struct bgp_dest *dest; + struct bgp_table *table; + struct bgp_path_info *pi; + + if (!bgp_install_info_to_zebra(bgp)) + return; + + table = bgp->rib[afi][safi]; + if (!table) + return; + + for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && + pi->type == ZEBRA_ROUTE_BGP) + bgp_zebra_announce(dest, + bgp_dest_get_prefix(dest), + pi, bgp, afi, safi); +} + void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, struct bgp *bgp, safi_t safi) { @@ -1586,6 +1610,30 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } +/* Withdraw all entries in a BGP instances RIB table from Zebra */ +void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_dest *dest; + struct bgp_table *table; + struct bgp_path_info *pi; + + if (!bgp_install_info_to_zebra(bgp)) + return; + + table = bgp->rib[afi][safi]; + if (!table) + return; + + for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) + && (pi->type == ZEBRA_ROUTE_BGP)) + bgp_zebra_withdraw(bgp_dest_get_prefix(dest), + pi, bgp, safi); + } + } +} + struct bgp_redist *bgp_redist_lookup(struct bgp *bgp, afi_t afi, uint8_t type, unsigned short instance) { diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index a068c03717..4b357c380a 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -43,6 +43,14 @@ extern void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *path, struct bgp *bgp, safi_t safi); +/* Announce routes of any bgp subtype of a table to zebra */ +extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, + safi_t safi); + +/* Withdraw all entries of any subtype in a BGP instances RIB table from Zebra */ +extern void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, + safi_t safi); + extern void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer); extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3c707b41ca..4260970541 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -202,6 +202,52 @@ int bgp_option_check(int flag) return CHECK_FLAG(bm->options, flag); } +/* set the bgp no-rib option during runtime and remove installed routes */ +void bgp_option_norib_set_runtime(void) +{ + struct bgp *bgp; + struct listnode *node; + afi_t afi; + safi_t safi; + + if (bgp_option_check(BGP_OPT_NO_FIB)) + return; + + bgp_option_set(BGP_OPT_NO_FIB); + + zlog_info("Disabled BGP route installation to RIB (Zebra)"); + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { + FOREACH_AFI_SAFI(afi, safi) + bgp_zebra_withdraw_table_all_subtypes(bgp, afi, safi); + } + + zlog_info("All routes have been withdrawn from RIB (Zebra)"); +} + +/* unset the bgp no-rib option during runtime and announce routes to Zebra */ +void bgp_option_norib_unset_runtime(void) +{ + struct bgp *bgp; + struct listnode *node; + afi_t afi; + safi_t safi; + + if (!bgp_option_check(BGP_OPT_NO_FIB)) + return; + + bgp_option_unset(BGP_OPT_NO_FIB); + + zlog_info("Enabled BGP route installation to RIB (Zebra)"); + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { + FOREACH_AFI_SAFI(afi, safi) + bgp_zebra_announce_table_all_subtypes(bgp, afi, safi); + } + + zlog_info("All routes have been installed in RIB (Zebra)"); +} + /* Internal function to set BGP structure configureation flag. */ static void bgp_config_set(struct bgp *bgp, int config) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e282e461df..9f72a3e19e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1807,6 +1807,12 @@ extern int bgp_option_set(int); extern int bgp_option_unset(int); extern int bgp_option_check(int); +/* set the bgp no-rib option during runtime and remove installed routes */ +extern void bgp_option_norib_set_runtime(void); + +/* unset the bgp no-rib option during runtime and reset all peers */ +extern void bgp_option_norib_unset_runtime(void); + extern int bgp_get(struct bgp **, as_t *, const char *, enum bgp_instance_type); extern void bgp_instance_up(struct bgp *); extern void bgp_instance_down(struct bgp *); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 723cb41f26..10eaaee9fb 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -42,6 +42,13 @@ be specified (:ref:`common-invocation-options`). processes in the same namespace. This option is different than the --no_zebra option in that a ZAPI connection is made. + This option can also be toggled during runtime by using the + ``[no] bgp no-rib`` commands in VTY shell. + + Note that this option will persist after saving the configuration during + runtime, unless unset by the ``no bgp no-rib`` command in VTY shell prior to + a configuration write operation. + .. option:: -S, --skip_runas Skip the normal process of checking capabilities and changing user and group @@ -3072,6 +3079,21 @@ by route reflectors to avoid looping. .. index:: bgp cluster-id A.B.C.D .. clicmd:: bgp cluster-id A.B.C.D +.. index:: [no] bgp no-rib +.. clicmd:: [no] bgp no-rib + +To set and unset the BGP daemon ``-n`` / ``--no_kernel`` options during runtime +to disable BGP route installation to the RIB (Zebra), the ``[no] bgp no-rib`` +commands can be used; + +Please note that setting the option during runtime will withdraw all routes in +the daemons RIB from Zebra and unsetting it will announce all routes in the +daemons RIB to Zebra. If the option is passed as a command line argument when +starting the daemon and the configuration gets saved, the option will persist +unless removed from the configuration with the negating command prior to the +configuration write operation. + + .. _routing-policy: Routing Policy diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index fe2778c877..01caff5b52 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -721,12 +721,23 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi) { struct listnode *node; struct pbr_map_sequence *pbrms; + bool sent = false; for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) - pbr_send_pbr_map(pbrms, pmi, false, false); + if (pbr_send_pbr_map(pbrms, pmi, false, true)) + sent = true; /* rule removal sent to zebra */ pmi->delete = true; + + /* + * If we actually sent something for deletion, wait on zapi callback + * before clearing data. + */ + if (sent) + return; + + pbr_map_final_interface_deletion(pbrm, pmi); } /* diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 269bd6da8d..8ef675186f 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -549,7 +549,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s, stream_put(s, ifp->name, INTERFACE_NAMSIZ); } -void pbr_send_pbr_map(struct pbr_map_sequence *pbrms, +bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms, struct pbr_map_interface *pmi, bool install, bool changed) { struct pbr_map *pbrm = pbrms->parent; @@ -569,10 +569,10 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms, * to delete just return. */ if (install && is_installed && !changed) - return; + return false; if (!install && !is_installed) - return; + return false; s = zclient->obuf; stream_reset(s); @@ -595,4 +595,6 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms, stream_putw_at(s, 0, stream_get_endp(s)); zclient_send_message(zclient); + + return true; } diff --git a/pbrd/pbr_zebra.h b/pbrd/pbr_zebra.h index cc42e21abe..e8f9bff5d9 100644 --- a/pbrd/pbr_zebra.h +++ b/pbrd/pbr_zebra.h @@ -35,7 +35,7 @@ extern void route_delete(struct pbr_nexthop_group_cache *pnhgc, extern void pbr_send_rnh(struct nexthop *nhop, bool reg); -extern void pbr_send_pbr_map(struct pbr_map_sequence *pbrms, +extern bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms, struct pbr_map_interface *pmi, bool install, bool changed); diff --git a/tests/topotests/bgp_features/r1/ip_route.json b/tests/topotests/bgp_features/r1/ip_route.json new file mode 100644 index 0000000000..cf1764140a --- /dev/null +++ b/tests/topotests/bgp_features/r1/ip_route.json @@ -0,0 +1,382 @@ +{ + "0.0.0.0\/0":[ + { + "prefix":"0.0.0.0\/0", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":20, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.101.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r1-eth3", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.0.1\/32":[ + { + "prefix":"192.168.0.1\/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.0.1\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "192.168.0.2\/32":[ + { + "prefix":"192.168.0.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.0.3\/32":[ + { + "prefix":"192.168.0.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "table":254, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.1.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + }, + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.3.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":5, + "interfaceName":"r1-eth0", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.6.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":5, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "192.168.7.0\/24":[ + { + "prefix":"192.168.7.0\/24", + "protocol":"bgp", + "distance":200, + "metric":0, + "nexthops":[ + { + "flags":5, + "ip":"192.168.0.2", + "afi":"ipv4", + "active":true, + "recursive":true, + "weight":1 + }, + { + "flags":1, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.8.0\/24":[ + { + "prefix":"192.168.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.101.0\/24":[ + { + "prefix":"192.168.101.0\/24", + "protocol":"bgp", + "distance":20, + "metric":0, + "nexthops":[ + { + "flags":0, + "ip":"192.168.101.2", + "afi":"ipv4", + "weight":1 + } + ] + }, + { + "prefix":"192.168.101.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r1-eth3", + "active":true + } + ] + } + ], + "192.168.102.0\/24":[ + { + "prefix":"192.168.102.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":20, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.101.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r1-eth3", + "active":true, + "weight":1 + } + ] + } + ] +} diff --git a/tests/topotests/bgp_features/r1/ip_route_norib.json b/tests/topotests/bgp_features/r1/ip_route_norib.json new file mode 100644 index 0000000000..30f67f53a4 --- /dev/null +++ b/tests/topotests/bgp_features/r1/ip_route_norib.json @@ -0,0 +1,296 @@ +{ + "192.168.0.1\/32":[ + { + "prefix":"192.168.0.1\/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.0.1\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "192.168.0.2\/32":[ + { + "prefix":"192.168.0.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.0.3\/32":[ + { + "prefix":"192.168.0.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.1.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + }, + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.3.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "flags":1, + "directlyConnected":true, + "interfaceIndex":5, + "interfaceName":"r1-eth0", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"192.168.6.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":5, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "192.168.7.0\/24":[ + { + "prefix":"192.168.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth1", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.8.0\/24":[ + { + "prefix":"192.168.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.3.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth2", + "active":true, + "weight":1 + } + ] + } + ], + "192.168.101.0\/24":[ + { + "prefix":"192.168.101.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r1-eth3", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 7c45ca8a29..4ec060b642 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -102,7 +102,7 @@ def setup_module(module): # Starting Routers router_list = tgen.routers() - for rname, router in router_list.items(): + for rname, router in router_list.iteritems(): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -538,6 +538,133 @@ def test_bgp_remove_metric_rmaps(): assert res is None, assertmsg +def test_bgp_norib(): + "Test BGP disable RIB (Zebra) Route Install" + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring 'bgp no-rib' on router r1") + + tgen.net['r1'].cmd('vtysh -c \"conf t\" -c \"bgp no-rib\"') + + # Checking BGP config - should show the "bgp no-rib" under the router bgp section + logger.info("Checking BGP configuration for 'bgp no-rib'") + + norib_cfg = tgen.net['r1'].cmd('vtysh -c "show running bgpd" | grep "^bgp no-rib"').rstrip() + + assertmsg = "'bgp no-rib' configuration applied, but not visible in configuration" + assert norib_cfg == 'bgp no-rib', assertmsg + + +def test_bgp_norib_routes(): + "Test Routes in Zebra and BGP with the 'bgp-norib' configuration" + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Checking local BGP routes - they need to be gone from Zebra + logger.info("Checking Zebra routes after removing bgp shutdown on router r1") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ip_route_norib.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip route json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "Zebra IPv4 Routes after configuring 'bgp no-rib' (There should be no BGP routes in Zebra anymore)" + assert res is None, assertmsg + + # Check BGP Summary on local and remote routers + for rtrNum in [1, 2, 4]: + logger.info("Checking BGP Summary after 'bgp no-rib' on router r1 on router r{}".format(rtrNum)) + + router = tgen.gears["r{}".format(rtrNum)] + reffile = os.path.join(CWD, "r{}/bgp_summary.json".format(rtrNum)) + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "BGP sessions on router R{} has incorrect routes after adding 'bgp no-rib on r1'".format(rtrNum) + assert res is None, assertmsg + + # tgen.mininet_cli() + + +def test_bgp_disable_norib(): + "Test BGP disabling the no-RIB (Zebra) Route Install" + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring 'no bgp no-rib' on router r1") + + tgen.net['r1'].cmd('vtysh -c \"conf t\" -c \"no bgp no-rib\"') + + # Checking BGP config - should show the "bgp no-rib" under the router bgp section + logger.info("Checking BGP configuration for 'bgp no-rib'") + + norib_cfg = tgen.net['r1'].cmd('vtysh -c "show running bgpd" | grep "^ bgp no-rib"').rstrip() + + assertmsg = "'no bgp no-rib'configuration applied, but still visible in configuration" + assert norib_cfg == '', assertmsg + + +def test_bgp_disable_norib_routes(): + "Test Routes in Zebra and BGP with the 'bgp-norib' configuration" + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Checking local BGP routes - they need to be gone from Zebra + logger.info("Checking Zebra routes after removing bgp shutdown on router r1") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ip_route.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip route json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "Zebra IPv4 Routes wrong after removing the 'bgp no-rib'" + assert res is None, assertmsg + + # Check BGP Summary on local and remote routers + for rtrNum in [1, 2, 4]: + logger.info("Checking BGP Summary after removing the 'bgp no-rib' on router r1 on router r{}".format(rtrNum)) + + router = tgen.gears["r{}".format(rtrNum)] + reffile = os.path.join(CWD, "r{}/bgp_summary.json".format(rtrNum)) + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "BGP sessions on router R{} has incorrect routes after removing 'bgp no-rib on r1'".format(rtrNum) + assert res is None, assertmsg + + # tgen.mininet_cli() + + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/pim-basic/mcast-rx.py b/tests/topotests/pim-basic/mcast-rx.py index 8a3a44ecb1..7aa4d4027e 100755 --- a/tests/topotests/pim-basic/mcast-rx.py +++ b/tests/topotests/pim-basic/mcast-rx.py @@ -35,7 +35,8 @@ import time def ifname_to_ifindex(ifname): - output = subprocess.check_output("ip link show %s" % ifname, shell=True) + output = subprocess.check_output("ip link show %s" % ifname, + shell=True, universal_newlines=True) first_line = output.split("\n")[0] re_index = re.search("^(\d+):", first_line) @@ -65,7 +66,8 @@ logging.addLevelName( ) log = logging.getLogger(__name__) -parser = argparse.ArgumentParser(description="Multicast RX utility", version="1.0.0") +parser = argparse.ArgumentParser(description="Multicast RX utility") + parser.add_argument("group", help="Multicast IP") parser.add_argument("ifname", help="Interface name") parser.add_argument("--port", help="UDP port", default=1000) diff --git a/tests/topotests/pim-basic/mcast-tx.py b/tests/topotests/pim-basic/mcast-tx.py index ad6fdc1062..7fb980c647 100755 --- a/tests/topotests/pim-basic/mcast-tx.py +++ b/tests/topotests/pim-basic/mcast-tx.py @@ -24,7 +24,7 @@ import logging import socket import struct import time - +import sys logging.basicConfig( level=logging.DEBUG, format="%(asctime)s %(levelname)5s: %(message)s" @@ -40,7 +40,7 @@ logging.addLevelName( log = logging.getLogger(__name__) parser = argparse.ArgumentParser( - description="Multicast packet generator", version="1.0.0" + description="Multicast packet generator" ) parser.add_argument("group", help="Multicast IP") parser.add_argument("ifname", help="Interface name") @@ -57,9 +57,18 @@ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # https://github.com/sivel/bonding/issues/10 # # Bind our socket to ifname -sock.setsockopt( - socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.ifname), args.ifname) -) +# +# Note ugly python version incompatibility +# +if sys.version_info[0] > 2: + sock.setsockopt( + socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.ifname), + args.ifname.encode('utf-8')) + ) +else: + sock.setsockopt( + socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.ifname), args.ifname) + ) # We need to make sure our sendto() finishes before we close the socket sock.setblocking(1) @@ -70,11 +79,18 @@ sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", arg ms = args.interval / 1000.0 # Send data to the multicast group -for x in xrange(args.count): +for x in range(args.count): log.info( "TX multicast UDP packet to %s:%d on %s" % (args.group, args.port, args.ifname) ) - sent = sock.sendto("foobar %d" % x, (args.group, args.port)) + + # + # Note ugly python version incompatibility + # + if sys.version_info[0] > 2: + sent = sock.sendto(b"foobar %d" % x, (args.group, args.port)) + else: + sent = sock.sendto("foobar %d" % x, (args.group, args.port)) if args.count > 1 and ms: time.sleep(ms) diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 3e11d53b16..2c07413638 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -335,10 +335,18 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, } } - /* If there is no useful nexthop then return. */ - if (ri->rtm_type != RTN_BLACKHOLE && ri->num_nhs == 0) { - zfpm_debug("netlink_encode_route(): No useful nexthop."); - return 0; + if (ri->num_nhs == 0) { + switch (ri->rtm_type) { + case RTN_PROHIBIT: + case RTN_UNREACHABLE: + case RTN_BLACKHOLE: + break; + default: + /* If there is no useful nexthop then return. */ + zfpm_debug( + "netlink_encode_route(): No useful nexthop."); + return 0; + } } return 1; |
