diff options
78 files changed, 7319 insertions, 1330 deletions
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 0eeb9b2bbb..7f9a13c271 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -86,16 +86,10 @@ babel_interface_up (ZAPI_CALLBACK_ARGS) } int -babel_interface_down (ZAPI_CALLBACK_ARGS) +babel_ifp_down(struct interface *ifp) { - struct stream *s = NULL; - struct interface *ifp = NULL; - debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */ - if (ifp == NULL) { return 0; } @@ -104,45 +98,23 @@ babel_interface_down (ZAPI_CALLBACK_ARGS) return 0; } -int -babel_interface_add (ZAPI_CALLBACK_ARGS) +int babel_ifp_create (struct interface *ifp) { - struct interface *ifp = NULL; - debugf(BABEL_DEBUG_IF, "receive a 'interface add'"); - /* read and add the interface in the iflist. */ - ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); - - if (ifp == NULL) { - return 0; - } - interface_recalculate(ifp); - return 0; -} + + return 0; + } int -babel_interface_delete (ZAPI_CALLBACK_ARGS) +babel_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */ - - if (ifp == NULL) - return 0; - if (IS_ENABLE(ifp)) interface_reset(ifp); - /* To support pseudo interface do not free interface structure. */ - /* if_delete(ifp); */ - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } @@ -1095,7 +1067,7 @@ DEFUN (show_babel_route_prefix, vty_out (vty, "%% Malformed address\n"); return CMD_WARNING; } - + routes = route_stream(0); if(routes) { while(1) { @@ -1260,6 +1232,11 @@ DEFUN (show_babel_parameters, return CMD_SUCCESS; } +int babel_ifp_up(struct interface *ifp) +{ + return 0; +} + void babel_if_init(void) { diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index d9e2745827..9833827927 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -121,6 +121,11 @@ int babel_interface_delete (int, struct zclient *, zebra_size_t, vrf_id_t); int babel_interface_address_add (int, struct zclient *, zebra_size_t, vrf_id_t); int babel_interface_address_delete (int, struct zclient *, zebra_size_t, vrf_id_t); +int babel_ifp_create(struct interface *ifp); +int babel_ifp_up(struct interface *ifp); +int babel_ifp_down(struct interface *ifp); +int babel_ifp_destroy(struct interface *ifp); + unsigned jitter(babel_interface_nfo *, int); unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); /* return "true" if "address" is one of our ipv6 addresses */ diff --git a/babeld/babel_main.c b/babeld/babel_main.c index a3f2b4e7d8..4bb8408157 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -202,6 +202,8 @@ main(int argc, char **argv) babel_replace_by_null(STDIN_FILENO); /* init some quagga's dependencies, and babeld's commands */ + if_zapi_callbacks(babel_ifp_create, babel_ifp_up, + babel_ifp_down, babel_ifp_destroy); babeld_quagga_init(); /* init zebra client's structure and it's commands */ /* this replace kernel_setup && kernel_setup_socket */ diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index d70823544a..5a336df7b5 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -240,10 +240,6 @@ void babelz_zebra_init(void) zclient_init(zclient, ZEBRA_ROUTE_BABEL, 0, &babeld_privs); zclient->zebra_connected = babel_zebra_connected; - zclient->interface_add = babel_interface_add; - zclient->interface_delete = babel_interface_delete; - zclient->interface_up = babel_interface_up; - zclient->interface_down = babel_interface_down; zclient->interface_address_add = babel_interface_address_add; zclient->interface_address_delete = babel_interface_address_delete; zclient->redistribute_route_add = babel_zebra_read_route; diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index ae6d04e77d..1b3219c235 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -673,33 +673,10 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf) } } -static int bfdd_interface_update(ZAPI_CALLBACK_ARGS) +static int bfd_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - - /* - * `zebra_interface_add_read` will handle the interface creation - * on `lib/if.c`. We'll use that data structure instead of - * rolling our own. - */ - if (cmd == ZEBRA_INTERFACE_ADD) { - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - - bfdd_sessions_enable_interface(ifp); - return 0; - } - - /* Update interface information. */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - bfdd_sessions_disable_interface(ifp); - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } @@ -756,8 +733,16 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS) return 0; } +static int bfd_ifp_create(struct interface *ifp) +{ + bfdd_sessions_enable_interface(ifp); + + return 0; +} + void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) { + if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy); zclient = zclient_new(master, &zclient_options_default); assert(zclient != NULL); zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv); @@ -772,10 +757,6 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) /* Send replay request on zebra connect. */ zclient->zebra_connected = bfdd_zebra_connected; - /* Learn interfaces from zebra instead of the OS. */ - zclient->interface_add = bfdd_interface_update; - zclient->interface_delete = bfdd_interface_update; - /* Learn about interface VRF. */ zclient->interface_vrf_update = bfdd_interface_vrf_update; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 551102151e..ff655048a8 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1632,7 +1632,7 @@ static void bmp_active_connect(struct bmp_active *ba) ba->hostname); continue; } - + set_nonblocking(ba->socket); res = sockunion_connect(ba->socket, &ba->addrs[ba->addrpos], htons(ba->port), 0); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 30380f6add..66681db520 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1012,6 +1012,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, int header = 1; char rd_str[BUFSIZ]; char buf[BUFSIZ]; + int no_display; unsigned long output_count = 0; unsigned long total_count = 0; @@ -1049,6 +1050,11 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, tbl_ver = table->version; for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) { + pi = bgp_node_get_bgp_path_info(rm); + if (pi == NULL) + continue; + + no_display = 0; if (use_json) { json_array = json_object_new_array(); json_prefix_info = json_object_new_object(); @@ -1065,8 +1071,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_nroute = json_object_new_object(); } - for (pi = bgp_node_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (; pi; pi = pi->next) { total_count++; if (type == bgp_show_type_neighbor) { struct peer *peer = output_arg; @@ -1101,16 +1106,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, vty_out(vty, V4_HEADER_OVERLAY); else { - vty_out(vty, - "BGP table version is %" PRIu64 ", local router ID is %s\n", - tbl_ver, - inet_ntoa( - bgp->router_id)); - vty_out(vty, - "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n"); - vty_out(vty, - "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"); - vty_out(vty, V4_HEADER); + bgp_evpn_show_route_header(vty, bgp, tbl_ver, NULL); } } header = 0; @@ -1172,18 +1168,23 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, } if (option == SHOW_DISPLAY_TAGS) - route_vty_out_tag(vty, &rm->p, pi, 0, - SAFI_EVPN, + route_vty_out_tag(vty, &rm->p, pi, + no_display, SAFI_EVPN, json_array); else if (option == SHOW_DISPLAY_OVERLAY) route_vty_out_overlay(vty, &rm->p, pi, - 0, json_array); + no_display, + json_array); else - route_vty_out(vty, &rm->p, pi, 0, - SAFI_EVPN, json_array); - output_count++; + route_vty_out(vty, &rm->p, pi, + no_display, SAFI_EVPN, + json_array); + no_display = 1; } - rd_header = 0; + + if (no_display) + output_count++; + if (use_json) { json_object_object_add(json_prefix_info, "paths", json_array); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 37360a559a..d083586c93 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6562,6 +6562,7 @@ DEFUN (aggregate_address_mask, argv_find(argv, argc, "A.B.C.D", &idx); char *prefix = argv[idx]->arg; char *mask = argv[idx + 1]->arg; + bool rmap_found; char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6570,8 +6571,8 @@ DEFUN (aggregate_address_mask, ? AGGREGATE_SUMMARY_ONLY : 0; - argv_find(argv, argc, "WORD", &idx); - if (idx) + rmap_found = argv_find(argv, argc, "WORD", &idx); + if (rmap_found) rmap = argv[idx]->arg; char prefix_str[BUFSIZ]; @@ -6588,14 +6589,16 @@ DEFUN (aggregate_address_mask, DEFUN (no_aggregate_address, no_aggregate_address_cmd, - "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D/M", &idx); @@ -6605,7 +6608,7 @@ DEFUN (no_aggregate_address, DEFUN (no_aggregate_address_mask, no_aggregate_address_mask_cmd, - "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" @@ -6613,7 +6616,9 @@ DEFUN (no_aggregate_address_mask, "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D", &idx); @@ -6647,6 +6652,7 @@ DEFUN (ipv6_aggregate_address, argv_find(argv, argc, "X:X::X:X/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; + bool rmap_found; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6655,8 +6661,8 @@ DEFUN (ipv6_aggregate_address, ? AGGREGATE_SUMMARY_ONLY : 0; - argv_find(argv, argc, "WORD", &idx); - if (idx) + rmap_found = argv_find(argv, argc, "WORD", &idx); + if (rmap_found) rmap = argv[idx]->arg; return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap, @@ -6665,14 +6671,16 @@ DEFUN (ipv6_aggregate_address, DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, - "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index c266440899..f31f8cd31b 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -46,7 +46,7 @@ /* BGP TRAP. */ #define BGPESTABLISHED 1 -#define BGPBACKWARDTRANSITION 2 +#define BGPBACKWARDTRANSITION 2 /* BGP MIB bgpVersion. */ #define BGPVERSION 0 diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 17bc83ed2e..f290b6cfb4 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7918,7 +7918,7 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, msg_str); } - } + } json_object_string_add(json_peer, "lastResetDueTo", peer_down_str[(int)peer->last_reset]); json_object_int_add(json_peer, "lastResetCode", @@ -8003,7 +8003,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp, false); } } - + /* Show BGP peer's summary information. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, @@ -8049,7 +8049,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (peer_dynamic_neighbor(peer)) dn_count++; } - + } else { /* Loop over all neighbors that will be displayed to determine * how many @@ -8078,7 +8078,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (len > max_neighbor_width) max_neighbor_width = len; - + /* See if we have at least a single failed peer */ if (bgp_has_peer_failed(peer, afi, safi)) failed_count++; @@ -8097,7 +8097,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (use_json) { json_object_int_add(json, "failedPeersCount", 0); json_object_int_add(json, "dynamicPeers", dn_count); - json_object_int_add(json, "totalPeers", count); + json_object_int_add(json, "totalPeers", count); vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); @@ -8108,7 +8108,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, } return CMD_SUCCESS; } - + count = 0; /* Reset the value as its used again */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 71f7f6d0e3..de39e295ff 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -202,75 +202,36 @@ static void bgp_nbr_connected_delete(struct bgp *bgp, struct nbr_connected *ifc, } } -/* Inteface addition message from zebra. */ -static int bgp_interface_add(ZAPI_CALLBACK_ARGS) +static int bgp_ifp_destroy(struct interface *ifp) { - struct interface *ifp; struct bgp *bgp; - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (!ifp) // unexpected - return 0; - - if (BGP_DEBUG(zebra, ZEBRA) && ifp) - zlog_debug("Rx Intf add VRF %u IF %s", vrf_id, ifp->name); - - bgp = bgp_lookup_by_vrf_id(vrf_id); - if (!bgp) - return 0; - - bgp_mac_add_mac_entry(ifp); - - bgp_update_interface_nbrs(bgp, ifp, ifp); - return 0; -} - -static int bgp_interface_delete(ZAPI_CALLBACK_ARGS) -{ - struct stream *s; - struct interface *ifp; - struct bgp *bgp; - - bgp = bgp_lookup_by_vrf_id(vrf_id); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - if (!ifp) /* This may happen if we've just unregistered for a VRF. */ - return 0; + bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name); + zlog_debug("Rx Intf del VRF %u IF %s", bgp->vrf_id, ifp->name); if (bgp) bgp_update_interface_nbrs(bgp, ifp, NULL); bgp_mac_del_mac_entry(ifp); - if_set_index(ifp, IFINDEX_INTERNAL); return 0; } -static int bgp_interface_up(ZAPI_CALLBACK_ARGS) +static int bgp_ifp_up(struct interface *ifp) { - struct stream *s; - struct interface *ifp; struct connected *c; struct nbr_connected *nc; struct listnode *node, *nnode; struct bgp *bgp; - bgp = bgp_lookup_by_vrf_id(vrf_id); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - - if (!ifp) - return 0; + bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name); + zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf_id, ifp->name); if (!bgp) return 0; @@ -284,27 +245,20 @@ static int bgp_interface_up(ZAPI_CALLBACK_ARGS) return 0; } -static int bgp_interface_down(ZAPI_CALLBACK_ARGS) +static int bgp_ifp_down(struct interface *ifp) { - struct stream *s; - struct interface *ifp; struct connected *c; struct nbr_connected *nc; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; - bgp = bgp_lookup_by_vrf_id(vrf_id); - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - if (!ifp) - return 0; + bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name); + zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf_id, ifp->name); if (!bgp) return 0; @@ -2721,17 +2675,35 @@ stream_failure: /* for STREAM_GETX */ extern struct zebra_privs_t bgpd_privs; +static int bgp_ifp_create(struct interface *ifp) +{ + struct bgp *bgp; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf_id, ifp->name); + + bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + if (!bgp) + return 0; + + bgp_mac_add_mac_entry(ifp); + + bgp_update_interface_nbrs(bgp, ifp, ifp); + return 0; +} + void bgp_zebra_init(struct thread_master *master, unsigned short instance) { zclient_num_connects = 0; + if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up, + bgp_ifp_down, bgp_ifp_destroy); + /* Set default values. */ zclient = zclient_new(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; zclient->router_id_update = bgp_router_id_update; - zclient->interface_add = bgp_interface_add; - zclient->interface_delete = bgp_interface_delete; zclient->interface_address_add = bgp_interface_address_add; zclient->interface_address_delete = bgp_interface_address_delete; zclient->interface_nbr_address_add = bgp_interface_nbr_address_add; @@ -2740,8 +2712,6 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance) zclient->interface_vrf_update = bgp_interface_vrf_update; zclient->redistribute_route_add = zebra_read_route; zclient->redistribute_route_del = zebra_read_route; - zclient->interface_up = bgp_interface_up; - zclient->interface_down = bgp_interface_down; zclient->nexthop_update = bgp_read_nexthop_update; zclient->import_check_update = bgp_read_import_check_update; zclient->fec_update = bgp_read_fec_update; diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 5d2cfbc337..af465f6fd4 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -839,8 +839,11 @@ zebra Terminal Mode Commands .. index:: show ipv6 route .. clicmd:: show ipv6 route -.. index:: show interface -.. clicmd:: show interface +.. index:: show interface [{vrf VRF|brief}] +.. clicmd:: show interface [{vrf VRF|brief}] + +.. index:: show interface [{vrf all|brief}] +.. clicmd:: show interface [{vrf all|brief}] .. index:: show ip prefix-list [NAME] .. clicmd:: show ip prefix-list [NAME] diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index fd1d3f5cb9..6294c0dd0f 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -54,6 +54,7 @@ #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_dump.h" struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, struct prefix *p) @@ -122,10 +123,101 @@ int eigrp_if_delete_hook(struct interface *ifp) return 0; } +static int eigrp_ifp_create(struct interface *ifp) +{ + struct eigrp_interface *ei = ifp->info; + + if (!ei) + return 0; + + ei->params.type = eigrp_default_iftype(ifp); + + eigrp_if_update(ifp); + + return 0; +} + +static int eigrp_ifp_up(struct interface *ifp) +{ + /* Interface is already up. */ + if (if_is_operative(ifp)) { + /* Temporarily keep ifp values. */ + struct interface if_tmp; + memcpy(&if_tmp, ifp, sizeof(struct interface)); + + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state update.", + ifp->name); + + if (if_tmp.bandwidth != ifp->bandwidth) { + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, if_tmp.bandwidth, + ifp->bandwidth); + + // eigrp_if_recalculate_output_cost (ifp); + } + + if (if_tmp.mtu != ifp->mtu) { + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] MTU change %u -> %u.", + ifp->name, if_tmp.mtu, ifp->mtu); + + /* Must reset the interface (simulate down/up) when MTU + * changes. */ + eigrp_if_reset(ifp); + } + return 0; + } + + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state change to up.", + ifp->name); + + if (ifp->info) + eigrp_if_up(ifp->info); + + return 0; +} + +static int eigrp_ifp_down(struct interface *ifp) +{ + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state change to down.", + ifp->name); + + if (ifp->info) + eigrp_if_down(ifp->info); + + return 0; +} + +static int eigrp_ifp_destroy(struct interface *ifp) +{ + if (if_is_up(ifp)) + zlog_warn("Zebra: got delete of %s, but interface is still up", + ifp->name); + + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: interface delete %s index %d flags %llx metric %d mtu %d", + ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); + + if (ifp->info) + eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA); + + return 0; +} + struct list *eigrp_iflist; void eigrp_if_init(void) { + if_zapi_callbacks(eigrp_ifp_create, eigrp_ifp_up, + eigrp_ifp_down, eigrp_ifp_destroy); /* Initialize Zebra interface data structure. */ // hook_register_prio(if_add, 0, eigrp_if_new); hook_register_prio(if_del, 0, eigrp_if_delete_hook); diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h index a18b0b7015..1e66dafde2 100644 --- a/eigrpd/eigrp_interface.h +++ b/eigrpd/eigrp_interface.h @@ -63,5 +63,4 @@ extern uint32_t eigrp_scaled_to_bandwidth(uint32_t); extern uint32_t eigrp_delay_to_scaled(uint32_t); extern uint32_t eigrp_scaled_to_delay(uint32_t); - #endif /* ZEBRA_EIGRP_INTERFACE_H_ */ diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 63cbe84ef2..9a0fdda0f9 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -53,14 +53,8 @@ #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -static int eigrp_interface_add(ZAPI_CALLBACK_ARGS); -static int eigrp_interface_delete(ZAPI_CALLBACK_ARGS); static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS); static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS); -static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS); -static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS); -static struct interface *zebra_interface_if_lookup(struct stream *, - vrf_id_t vrf_id); static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS); @@ -114,10 +108,6 @@ void eigrp_zebra_init(void) zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); zclient->zebra_connected = eigrp_zebra_connected; zclient->router_id_update = eigrp_router_id_update_zebra; - zclient->interface_add = eigrp_interface_add; - zclient->interface_delete = eigrp_interface_delete; - zclient->interface_up = eigrp_interface_state_up; - zclient->interface_down = eigrp_interface_state_down; zclient->interface_address_add = eigrp_interface_address_add; zclient->interface_address_delete = eigrp_interface_address_delete; zclient->redistribute_route_add = eigrp_zebra_read_route; @@ -151,56 +141,6 @@ static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS) return 0; } -/* Inteface addition message from zebra. */ -static int eigrp_interface_add(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct eigrp_interface *ei; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (!ifp->info) - return 0; - - ei = ifp->info; - - ei->params.type = eigrp_default_iftype(ifp); - - eigrp_if_update(ifp); - - return 0; -} - -static int eigrp_interface_delete(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - /* zebra_interface_state_read () updates interface structure in iflist - */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - - if (if_is_up(ifp)) - zlog_warn("Zebra: got delete of %s, but interface is still up", - ifp->name); - - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: interface delete %s index %d flags %llx metric %d mtu %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu); - - if (ifp->info) - eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA); - - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; -} - static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS) { struct connected *c; @@ -254,93 +194,6 @@ static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - /* Interface is already up. */ - if (if_is_operative(ifp)) { - /* Temporarily keep ifp values. */ - struct interface if_tmp; - memcpy(&if_tmp, ifp, sizeof(struct interface)); - - zebra_interface_if_set_value(zclient->ibuf, ifp); - - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state update.", - ifp->name); - - if (if_tmp.bandwidth != ifp->bandwidth) { - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] bandwidth change %d -> %d.", - ifp->name, if_tmp.bandwidth, - ifp->bandwidth); - - // eigrp_if_recalculate_output_cost (ifp); - } - - if (if_tmp.mtu != ifp->mtu) { - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] MTU change %u -> %u.", - ifp->name, if_tmp.mtu, ifp->mtu); - - /* Must reset the interface (simulate down/up) when MTU - * changes. */ - eigrp_if_reset(ifp); - } - return 0; - } - - zebra_interface_if_set_value(zclient->ibuf, ifp); - - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state change to up.", - ifp->name); - - if (ifp->info) - eigrp_if_up(ifp->info); - - return 0; -} - -static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state change to down.", - ifp->name); - - if (ifp->info) - eigrp_if_down(ifp->info); - - return 0; -} - -static struct interface *zebra_interface_if_lookup(struct stream *s, - vrf_id_t vrf_id) -{ - 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_id); -} - void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p, struct list *successors, uint32_t distance) { diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 0a4d733177..750a36be67 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -16,7 +16,7 @@ #define NETLINK_SELINUX 7 /* SELinux event notifications */ #define NETLINK_ISCSI 8 /* Open-iSCSI */ #define NETLINK_AUDIT 9 /* auditing */ -#define NETLINK_FIB_LOOKUP 10 +#define NETLINK_FIB_LOOKUP 10 #define NETLINK_CONNECTOR 11 #define NETLINK_NETFILTER 12 /* netfilter subsystem */ #define NETLINK_IP6_FW 13 @@ -32,7 +32,7 @@ #define NETLINK_INET_DIAG NETLINK_SOCK_DIAG -#define MAX_LINKS 32 +#define MAX_LINKS 32 struct sockaddr_nl { __kernel_sa_family_t nl_family; /* AF_NETLINK */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index ce2a623abb..eddbc04504 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -172,7 +172,7 @@ enum { #define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2) #define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2) -/* +/* Generic structure for encapsulation of optional route information. It is reminiscent of sockaddr, but with sa_family replaced with attribute type. @@ -212,7 +212,7 @@ struct rtmsg { unsigned char rtm_table; /* Routing table id */ unsigned char rtm_protocol; /* Routing protocol; see below */ - unsigned char rtm_scope; /* See below */ + unsigned char rtm_scope; /* See below */ unsigned char rtm_type; /* See below */ unsigned rtm_flags; @@ -523,7 +523,7 @@ struct ifinfomsg { }; /******************************************************************** - * prefix information + * prefix information ****/ struct prefixmsg { @@ -537,7 +537,7 @@ struct prefixmsg { unsigned char prefix_pad3; }; -enum +enum { PREFIX_UNSPEC, PREFIX_ADDRESS, diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 5da8e6ee9e..29fb725b04 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -61,6 +61,8 @@ DEFINE_QOBJ_TYPE(isis_circuit) +DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) + /* * Prototypes. */ @@ -1389,6 +1391,51 @@ int isis_if_delete_hook(struct interface *ifp) return 0; } +static int isis_ifp_create(struct interface *ifp) +{ + if (if_is_operative(ifp)) + isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), + ifp); + + hook_call(isis_if_new_hook, ifp); + + return 0; +} + +static int isis_ifp_up(struct interface *ifp) +{ + isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); + + return 0; +} + +static int isis_ifp_down(struct interface *ifp) +{ + struct isis_circuit *circuit; + + circuit = isis_csm_state_change(IF_DOWN_FROM_Z, + circuit_scan_by_ifp(ifp), ifp); + if (circuit) + SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); + + return 0; +} + +static int isis_ifp_destroy(struct interface *ifp) +{ + if (if_is_operative(ifp)) + zlog_warn("Zebra: got delete of %s, but interface is still up", + ifp->name); + + isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp); + + /* Cannot call if_delete because we should retain the pseudo interface + in case there is configuration info attached to it. */ + if_delete_retain(ifp); + + return 0; +} + void isis_circuit_init(void) { /* Initialize Zebra interface data structure */ @@ -1398,4 +1445,6 @@ void isis_circuit_init(void) /* Install interface node */ install_node(&interface_node, isis_interface_config_write); if_cmd_init(); + if_zapi_callbacks(isis_ifp_create, isis_ifp_up, + isis_ifp_down, isis_ifp_destroy); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index b77c8ce352..f677d3aded 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -32,6 +32,8 @@ #include "isis_constants.h" #include "isis_common.h" +DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); + struct isis_lsp; struct password { diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 46b013ddd0..a637ff003f 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -187,7 +187,7 @@ static int process_p2p_hello(struct iih_info *iih) adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } - if (tw_adj && adj->threeway_state == ISIS_THREEWAY_DOWN) + if (tw_adj) adj->ext_circuit_id = tw_adj->local_circuit_id; /* 8.2.6 Monitoring point-to-point adjacencies */ diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 39a2f6ef35..bdf6869f5c 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -53,8 +53,6 @@ struct zclient *zclient = NULL; -DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) - /* Router-id update message from zebra. */ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) { @@ -74,79 +72,6 @@ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; } -static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (if_is_operative(ifp)) - isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), - ifp); - - hook_call(isis_if_new_hook, ifp); - - return 0; -} - -static int isis_zebra_if_del(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - - if (!ifp) - return 0; - - if (if_is_operative(ifp)) - zlog_warn("Zebra: got delete of %s, but interface is still up", - ifp->name); - - isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp); - - /* Cannot call if_delete because we should retain the pseudo interface - in case there is configuration info attached to it. */ - if_delete_retain(ifp); - - if_set_index(ifp, IFINDEX_INTERNAL); - - return 0; -} - -static int isis_zebra_if_state_up(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); - - return 0; -} - -static int isis_zebra_if_state_down(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct isis_circuit *circuit; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - circuit = isis_csm_state_change(IF_DOWN_FROM_Z, - circuit_scan_by_ifp(ifp), ifp); - if (circuit) - SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); - - return 0; -} - static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS) { struct connected *c; @@ -388,10 +313,6 @@ void isis_zebra_init(struct thread_master *master) zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs); zclient->zebra_connected = isis_zebra_connected; zclient->router_id_update = isis_router_id_update_zebra; - zclient->interface_add = isis_zebra_if_add; - zclient->interface_delete = isis_zebra_if_del; - zclient->interface_up = isis_zebra_if_state_up; - zclient->interface_down = isis_zebra_if_state_down; zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; zclient->interface_link_params = isis_zebra_link_params; diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 83a32108eb..d00f348c8e 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -24,8 +24,6 @@ extern struct zclient *zclient; -DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); - void isis_zebra_init(struct thread_master *); void isis_zebra_stop(void); diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 884ae159be..4df1fc0304 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -39,9 +39,6 @@ static void ifc2kaddr(struct interface *, struct connected *, struct kaddr *); static int ldp_zebra_send_mpls_labels(int, struct kroute *); static int ldp_router_id_update(ZAPI_CALLBACK_ARGS); -static int ldp_interface_add(ZAPI_CALLBACK_ARGS); -static int ldp_interface_delete(ZAPI_CALLBACK_ARGS); -static int ldp_interface_status_change(ZAPI_CALLBACK_ARGS); static int ldp_interface_address_add(ZAPI_CALLBACK_ARGS); static int ldp_interface_address_delete(ZAPI_CALLBACK_ARGS); static int ldp_zebra_read_route(ZAPI_CALLBACK_ARGS); @@ -264,39 +261,27 @@ ldp_router_id_update(ZAPI_CALLBACK_ARGS) } static int -ldp_interface_add(ZAPI_CALLBACK_ARGS) +ldp_ifp_create(struct interface *ifp) { - struct interface *ifp; struct kif kif; - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); debug_zebra_in("interface add %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu); ifp2kif(ifp, &kif); main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); - return (0); + return 0; } static int -ldp_interface_delete(ZAPI_CALLBACK_ARGS) +ldp_ifp_destroy(struct interface *ifp) { - struct interface *ifp; struct kif kif; - /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return (0); - debug_zebra_in("interface delete %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu); - /* To support pseudo interface do not free interface structure. */ - /* if_delete(ifp); */ - if_set_index(ifp, IFINDEX_INTERNAL); - ifp2kif(ifp, &kif); main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); @@ -304,22 +289,13 @@ ldp_interface_delete(ZAPI_CALLBACK_ARGS) } static int -ldp_interface_status_change(ZAPI_CALLBACK_ARGS) +ldp_interface_status_change_helper(struct interface *ifp) { - struct interface *ifp; struct listnode *node; struct connected *ifc; struct kif kif; struct kaddr ka; - /* - * zebra_interface_state_read() updates interface structure in - * iflist. - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return (0); - debug_zebra_in("interface %s state update", ifp->name); ifp2kif(ifp, &kif); @@ -342,6 +318,16 @@ ldp_interface_status_change(ZAPI_CALLBACK_ARGS) return (0); } +static int ldp_ifp_up(struct interface *ifp) +{ + return ldp_interface_status_change_helper(ifp); +} + +static int ldp_ifp_down(struct interface *ifp) +{ + return ldp_interface_status_change_helper(ifp); +} + static int ldp_interface_address_add(ZAPI_CALLBACK_ARGS) { @@ -535,6 +521,9 @@ extern struct zebra_privs_t ldpd_privs; void ldp_zebra_init(struct thread_master *master) { + if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up, + ldp_ifp_down, ldp_ifp_destroy); + /* Set default values. */ zclient = zclient_new(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs); @@ -542,10 +531,6 @@ ldp_zebra_init(struct thread_master *master) /* set callbacks */ zclient->zebra_connected = ldp_zebra_connected; zclient->router_id_update = ldp_router_id_update; - zclient->interface_add = ldp_interface_add; - zclient->interface_delete = ldp_interface_delete; - zclient->interface_up = ldp_interface_status_change; - zclient->interface_down = ldp_interface_status_change; zclient->interface_address_add = ldp_interface_address_add; zclient->interface_address_delete = ldp_interface_address_delete; zclient->redistribute_route_add = ldp_zebra_read_route; @@ -58,6 +58,13 @@ DEFINE_QOBJ_TYPE(interface) DEFINE_HOOK(if_add, (struct interface * ifp), (ifp)) DEFINE_KOOH(if_del, (struct interface * ifp), (ifp)) +struct interface_master{ + int (*create_hook)(struct interface *ifp); + int (*up_hook)(struct interface *ifp); + int (*down_hook)(struct interface *ifp); + int (*destroy_hook)(struct interface *ifp); +} ifp_master = { 0, }; + /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the * relationship between ifp1 and ifp2. Interface names consist of an @@ -168,6 +175,34 @@ static struct interface *if_create_backend(const char *name, ifindex_t ifindex, return ifp; } +void if_new_via_zapi(struct interface *ifp) +{ + if (ifp_master.create_hook) + (*ifp_master.create_hook)(ifp); +} + +void if_destroy_via_zapi(struct interface *ifp) +{ + if (ifp_master.destroy_hook) + (*ifp_master.destroy_hook)(ifp); + + if_set_index(ifp, IFINDEX_INTERNAL); + if (!ifp->configured) + if_delete(ifp); +} + +void if_up_via_zapi(struct interface *ifp) +{ + if (ifp_master.up_hook) + (*ifp_master.up_hook)(ifp); +} + +void if_down_via_zapi(struct interface *ifp) +{ + if (ifp_master.down_hook) + (*ifp_master.down_hook)(ifp); +} + struct interface *if_create(const char *name, vrf_id_t vrf_id) { return if_create_backend(name, IFINDEX_INTERNAL, vrf_id); @@ -1367,6 +1402,17 @@ void if_cmd_init(void) install_element(INTERFACE_NODE, &no_interface_desc_cmd); } +void if_zapi_callbacks(int (*create)(struct interface *ifp), + int (*up)(struct interface *ifp), + int (*down)(struct interface *ifp), + int (*destroy)(struct interface *ifp)) +{ + ifp_master.create_hook = create; + ifp_master.up_hook = up; + ifp_master.down_hook = down; + ifp_master.destroy_hook = destroy; +} + /* ------- Northbound callbacks ------- */ /* @@ -1423,6 +1469,8 @@ static int lib_interface_create(enum nb_event event, #else ifp = if_get_by_name(ifname, vrf->vrf_id); #endif /* SUNOS_5 */ + + ifp->configured = true; nb_running_set_entry(dnode, ifp); break; } @@ -1450,6 +1498,8 @@ static int lib_interface_destroy(enum nb_event event, break; case NB_EV_APPLY: ifp = nb_running_unset_entry(dnode); + + ifp->configured = false; if_delete(ifp); break; } @@ -293,6 +293,12 @@ struct interface { struct route_node *node; vrf_id_t vrf_id; + /* + * Has the end users entered `interface XXXX` from the cli in some + * fashion? + */ + bool configured; + QOBJ_FIELDS }; @@ -552,6 +558,16 @@ void if_link_params_free(struct interface *); /* Northbound. */ extern void if_cmd_init(void); +extern void if_zapi_callbacks(int (*create)(struct interface *ifp), + int (*up)(struct interface *ifp), + int (*down)(struct interface *ifp), + int (*destroy)(struct interface *ifp)); + +extern void if_new_via_zapi(struct interface *ifp); +extern void if_up_via_zapi(struct interface *ifp); +extern void if_down_via_zapi(struct interface *ifp); +extern void if_destroy_via_zapi(struct interface *ifp); + extern const struct frr_yang_module_info frr_interface_info; #ifdef __cplusplus diff --git a/lib/printf/printf-pos.c b/lib/printf/printf-pos.c index 1f5f283e82..45e4f86229 100644 --- a/lib/printf/printf-pos.c +++ b/lib/printf/printf-pos.c @@ -98,7 +98,7 @@ inittypes(struct typetable *types) types->table = types->stattable; types->tablesize = STATIC_ARG_TBL_SIZE; - types->tablemax = 0; + types->tablemax = 0; types->nextarg = 1; for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) types->table[n] = T_UNUSED; @@ -106,7 +106,7 @@ inittypes(struct typetable *types) /* * struct typetable destructor. - */ + */ static inline void freetypes(struct typetable *types) { @@ -255,7 +255,7 @@ addwaster(struct typetable *types, wchar_t **fmtp) * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. * It will be replaces with a malloc-ed one if it overflows. * Returns 0 on success. On failure, returns nonzero and sets errno. - */ + */ int _frr_find_arguments (const char *fmt0, va_list ap, union arg **argtable) { diff --git a/lib/typesafe.c b/lib/typesafe.c index 7e5939d5b3..6635cf7506 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -473,7 +473,7 @@ void typesafe_heap_resize(struct heap_head *head, bool grow) newsize &= ~(HEAP_NARY - 1); if (newsize == head->arraysz) return; - + head->array = XREALLOC(MTYPE_HEAP_ARRAY, head->array, newsize * sizeof(struct heap_item *)); head->arraysz = newsize; diff --git a/lib/zclient.c b/lib/zclient.c index 92a495ac61..91dbe30a09 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -49,6 +49,9 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; /* Prototype for event manager. */ static void zclient_event(enum event, struct zclient *); +static void zebra_interface_if_set_value(struct stream *s, + struct interface *ifp); + struct zclient_options zclient_options_default = {.receive_notify = false}; struct sockaddr_storage zclient_addr; @@ -1547,10 +1550,11 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id) vrf_delete(vrf); } -struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id) +static void zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id) { struct interface *ifp; char ifname_tmp[INTERFACE_NAMSIZ]; + struct stream *s = zclient->ibuf; /* Read interface name. */ stream_get(ifname_tmp, s, INTERFACE_NAMSIZ); @@ -1560,15 +1564,14 @@ struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id) zebra_interface_if_set_value(s, ifp); - return ifp; + if_new_via_zapi(ifp); } /* * Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN) * from zebra server. The format of this message is the same as - * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE (see - * comments for zebra_interface_add_read), except that no sockaddr_dl - * is sent at the tail of the message. + * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE, + * except that no sockaddr_dl is sent at the tail of the message. */ struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id) { @@ -1592,6 +1595,46 @@ struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id) return ifp; } +static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s = zclient->ibuf; + + ifp = zebra_interface_state_read(s, vrf_id); + + if (ifp == NULL) + return; + + if_destroy_via_zapi(ifp); + return; +} + +static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s = zclient->ibuf; + + ifp = zebra_interface_state_read(s, vrf_id); + + if (!ifp) + return; + + if_up_via_zapi(ifp); +} + +static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s = zclient->ibuf; + + ifp = zebra_interface_state_read(s, vrf_id); + + if (!ifp) + return; + + if_down_via_zapi(ifp); +} + static void link_params_set_value(struct stream *s, struct if_link_params *iflp) { @@ -1656,7 +1699,8 @@ struct interface *zebra_interface_link_params_read(struct stream *s, return ifp; } -void zebra_interface_if_set_value(struct stream *s, struct interface *ifp) +static void zebra_interface_if_set_value(struct stream *s, + struct interface *ifp) { uint8_t link_params_status = 0; ifindex_t old_ifindex; @@ -1944,7 +1988,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s, } /* Fetch new VRF Id. */ - new_id = stream_getw(s); + new_id = stream_getl(s); *new_vrf_id = new_id; return ifp; @@ -2789,14 +2833,10 @@ static int zclient_read(struct thread *thread) zclient_vrf_delete(zclient, vrf_id); break; case ZEBRA_INTERFACE_ADD: - if (zclient->interface_add) - (*zclient->interface_add)(command, zclient, length, - vrf_id); + zclient_interface_add(zclient, vrf_id); break; case ZEBRA_INTERFACE_DELETE: - if (zclient->interface_delete) - (*zclient->interface_delete)(command, zclient, length, - vrf_id); + zclient_interface_delete(zclient, vrf_id); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) @@ -2824,14 +2864,10 @@ static int zclient_read(struct thread *thread) command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_UP: - if (zclient->interface_up) - (*zclient->interface_up)(command, zclient, length, - vrf_id); + zclient_interface_up(zclient, vrf_id); break; case ZEBRA_INTERFACE_DOWN: - if (zclient->interface_down) - (*zclient->interface_down)(command, zclient, length, - vrf_id); + zclient_interface_down(zclient, vrf_id); break; case ZEBRA_INTERFACE_VRF_UPDATE: if (zclient->interface_vrf_update) diff --git a/lib/zclient.h b/lib/zclient.h index eb3c97b111..5f9edc36ff 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -240,10 +240,6 @@ struct zclient { void (*zebra_connected)(struct zclient *); void (*zebra_capabilities)(struct zclient_capabilities *cap); int (*router_id_update)(ZAPI_CALLBACK_ARGS); - int (*interface_add)(ZAPI_CALLBACK_ARGS); - int (*interface_delete)(ZAPI_CALLBACK_ARGS); - int (*interface_up)(ZAPI_CALLBACK_ARGS); - int (*interface_down)(ZAPI_CALLBACK_ARGS); int (*interface_address_add)(ZAPI_CALLBACK_ARGS); int (*interface_address_delete)(ZAPI_CALLBACK_ARGS); int (*interface_link_params)(ZAPI_CALLBACK_ARGS); @@ -617,7 +613,6 @@ extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr); extern void zclient_interface_set_master(struct zclient *client, struct interface *master, struct interface *slave); -extern struct interface *zebra_interface_add_read(struct stream *, vrf_id_t); extern struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t); extern struct connected *zebra_interface_address_read(int, struct stream *, vrf_id_t); @@ -626,7 +621,6 @@ zebra_interface_nbr_address_read(int, struct stream *, vrf_id_t); extern struct interface *zebra_interface_vrf_update_read(struct stream *s, vrf_id_t vrf_id, vrf_id_t *new_vrf_id); -extern void zebra_interface_if_set_value(struct stream *, struct interface *); extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid); extern struct interface *zebra_interface_link_params_read(struct stream *s, diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 8f1ba14fe4..e4f614c7c4 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -296,15 +296,8 @@ void nhrp_interface_update(struct interface *ifp) } } -int nhrp_interface_add(ZAPI_CALLBACK_ARGS) +int nhrp_ifp_create(struct interface *ifp) { - struct interface *ifp; - - /* read and add the interface in the iflist. */ - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s", ifp->name, ifp->ifindex, ifp->ll_type, if_link_type_str(ifp->ll_type)); @@ -314,49 +307,28 @@ int nhrp_interface_add(ZAPI_CALLBACK_ARGS) return 0; } -int nhrp_interface_delete(ZAPI_CALLBACK_ARGS) +int nhrp_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - if (ifp == NULL) - return 0; - debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name); nhrp_interface_update(ifp); - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } -int nhrp_interface_up(ZAPI_CALLBACK_ARGS) +int nhrp_ifp_up(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name); nhrp_interface_update_nbma(ifp); return 0; } -int nhrp_interface_down(ZAPI_CALLBACK_ARGS) +int nhrp_ifp_down(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name); nhrp_interface_update(ifp); + return 0; } diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 969638cd77..c6c83614ef 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -152,6 +152,8 @@ int main(int argc, char **argv) nhrp_vc_init(); nhrp_packet_init(); vici_init(); + if_zapi_callbacks(nhrp_ifp_create, nhrp_ifp_up, + nhrp_ifp_down, nhrp_ifp_destroy); nhrp_zebra_init(); nhrp_shortcut_init(); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index a788eb2efb..cfca86a9bf 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -345,10 +345,6 @@ void nhrp_zebra_init(void) zclient = zclient_new(master, &zclient_options_default); zclient->zebra_connected = nhrp_zebra_connected; - zclient->interface_add = nhrp_interface_add; - zclient->interface_delete = nhrp_interface_delete; - zclient->interface_up = nhrp_interface_up; - zclient->interface_down = nhrp_interface_down; zclient->interface_address_add = nhrp_interface_address_add; zclient->interface_address_delete = nhrp_interface_address_delete; zclient->redistribute_route_add = nhrp_route_read; diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 670c9f4f18..50746d9ad5 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -319,6 +319,10 @@ void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n); void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile); void nhrp_interface_set_source(struct interface *ifp, const char *ifname); +extern int nhrp_ifp_create(struct interface *ifp); +extern int nhrp_ifp_up(struct interface *ifp); +extern int nhrp_ifp_down(struct interface *ifp); +extern int nhrp_ifp_destroy(struct interface *ifp); int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 4d7c75a330..a56ba0a694 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -42,6 +42,7 @@ #include "ospf6_spf.h" #include "ospf6d.h" #include "ospf6_bfd.h" +#include "ospf6_zebra.h" DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names") DEFINE_QOBJ_TYPE(ospf6_interface) @@ -1946,11 +1947,64 @@ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; +static int ospf6_ifp_create(struct interface *ifp) +{ + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name, + ifp->ifindex, ifp->mtu6); + ospf6_interface_if_add(ifp); + + return 0; +} + +static int ospf6_ifp_up(struct interface *ifp) +{ + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug( + "Zebra Interface state change: " + "%s index %d flags %llx metric %d mtu %d bandwidth %d", + ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6, ifp->bandwidth); + + ospf6_interface_state_update(ifp); + + return 0; +} + +static int ospf6_ifp_down(struct interface *ifp) +{ + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug( + "Zebra Interface state change: " + "%s index %d flags %llx metric %d mtu %d bandwidth %d", + ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6, ifp->bandwidth); + + ospf6_interface_state_update(ifp); + + return 0; +} + +static int ospf6_ifp_destroy(struct interface *ifp) +{ + if (if_is_up(ifp)) + zlog_warn("Zebra: got delete of %s, but interface is still up", + ifp->name); + + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug("Zebra Interface delete: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu6); + + return 0; +} + void ospf6_interface_init(void) { /* Install interface node. */ install_node(&interface_node, config_write_ospf6_interface); if_cmd_init(); + if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up, + ospf6_ifp_down, ospf6_ifp_destroy); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 8454016b2e..d8a6a39e1e 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -97,57 +97,6 @@ void ospf6_zebra_no_redistribute(int type) AFI_IP6, type, 0, VRF_DEFAULT); } -/* Inteface addition message from zebra. */ -static int ospf6_zebra_if_add(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name, - ifp->ifindex, ifp->mtu6); - ospf6_interface_if_add(ifp); - return 0; -} - -static int ospf6_zebra_if_del(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - if (!(ifp = zebra_interface_state_read(zclient->ibuf, vrf_id))) - return 0; - - if (if_is_up(ifp)) - zlog_warn("Zebra: got delete of %s, but interface is still up", - ifp->name); - - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug("Zebra Interface delete: %s index %d mtu %d", - ifp->name, ifp->ifindex, ifp->mtu6); - - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; -} - -static int ospf6_zebra_if_state_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug( - "Zebra Interface state change: " - "%s index %d flags %llx metric %d mtu %d bandwidth %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6, ifp->bandwidth); - - ospf6_interface_state_update(ifp); - return 0; -} - static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS) { struct connected *c; @@ -583,10 +532,6 @@ void ospf6_zebra_init(struct thread_master *master) zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs); zclient->zebra_connected = ospf6_zebra_connected; zclient->router_id_update = ospf6_router_id_update_zebra; - zclient->interface_add = ospf6_zebra_if_add; - zclient->interface_delete = ospf6_zebra_if_del; - zclient->interface_up = ospf6_zebra_if_state_update; - zclient->interface_down = ospf6_zebra_if_state_update; zclient->interface_address_add = ospf6_zebra_if_address_update_add; zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 9492de544f..44244f651e 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -190,7 +190,7 @@ ospf_ase_calculate_asbr_route (struct ospf *ospf, zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR"); return NULL; } - + if (al->e[0].fwd_addr.s_addr != 0) { if (IS_DEBUG_OSPF (lsa, LSA)) @@ -215,7 +215,7 @@ ospf_ase_calculate_asbr_route (struct ospf *ospf, asbr.prefixlen = IPV4_MAX_BITLEN; rn = route_node_match (rt_network, (struct prefix *) &asbr); - + if (rn == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 3877708708..3407d1bad1 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -50,6 +50,8 @@ DEFINE_QOBJ_TYPE(ospf_interface) DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)) DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)) +DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) +DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) int ospf_interface_neighbor_count(struct ospf_interface *oi) { @@ -1218,8 +1220,133 @@ uint8_t ospf_default_iftype(struct interface *ifp) return OSPF_IFTYPE_BROADCAST; } +void ospf_if_interface(struct interface *ifp) +{ + hook_call(ospf_if_update, ifp); +} + +static int ospf_ifp_create(struct interface *ifp) +{ + struct ospf *ospf = NULL; + + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u", + ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), + ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu, + ifp->speed); + + assert(ifp->info); + + 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); + } + + ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + if (!ospf) + return 0; + + ospf_if_recalculate_output_cost(ifp); + + ospf_if_update(ospf, ifp); + + hook_call(ospf_if_update, ifp); + + return 0; +} + +static int ospf_ifp_up(struct interface *ifp) +{ + struct ospf_interface *oi; + struct route_node *rn; + + /* Interface is already up. */ + if (if_is_operative(ifp)) { + /* Temporarily keep ifp values. */ + struct interface if_tmp; + memcpy(&if_tmp, ifp, sizeof(struct interface)); + + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] state update speed %u -> %u, bw %d -> %d", + ifp->name, if_tmp.speed, ifp->speed, + if_tmp.bandwidth, ifp->bandwidth); + + ospf_if_recalculate_output_cost(ifp); + + if (if_tmp.mtu != ifp->mtu) { + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] MTU change %u -> %u.", + ifp->name, if_tmp.mtu, ifp->mtu); + + /* Must reset the interface (simulate down/up) when MTU + * changes. */ + ospf_if_reset(ifp); + } + return 0; + } + + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state change to up.", + ifp->name); + + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + if ((oi = rn->info) == NULL) + continue; + + ospf_if_up(oi); + } + + return 0; +} + +static int ospf_ifp_down(struct interface *ifp) +{ + struct ospf_interface *oi; + struct route_node *node; + + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state change to down.", + ifp->name); + + for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) { + if ((oi = node->info) == NULL) + continue; + ospf_if_down(oi); + } + + return 0; +} + +static int ospf_ifp_destroy(struct interface *ifp) +{ + struct route_node *rn; + + if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: interface delete %s vrf %s[%u] index %d flags %llx metric %d mtu %d", + ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), + ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + + hook_call(ospf_if_delete, ifp); + + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) + if (rn->info) + ospf_if_free((struct ospf_interface *)rn->info); + + return 0; +} + void ospf_if_init(void) { + if_zapi_callbacks(ospf_ifp_create, ospf_ifp_up, + ospf_ifp_down, ospf_ifp_destroy); + /* Initialize Zebra interface data structure. */ hook_register_prio(if_add, 0, ospf_if_new_hook); hook_register_prio(if_del, 0, ospf_if_delete_hook); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 0c903954d3..cde52dbb9e 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -321,7 +321,12 @@ extern int ospf_interface_neighbor_count(struct ospf_interface *oi); state of the interface. */ extern void ospf_if_set_multicast(struct ospf_interface *); +extern void ospf_if_interface(struct interface *ifp); + DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)) DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)) +DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) +DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) + #endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index db41df7c47..5ab0927e71 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2437,7 +2437,7 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_install(struct ospf *ospf, #if 0 /* These don't exist yet... */ ospf_summary_incremental_update(new); - /* Isn't this done by the above call? + /* Isn't this done by the above call? - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index b478832d84..5678d545ba 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -55,9 +55,6 @@ DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table") DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute") DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments") -DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) -DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) - /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -97,167 +94,6 @@ static int ospf_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; } -/* Inteface addition message from zebra. */ -static int ospf_interface_add(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp = NULL; - struct ospf *ospf = NULL; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (ifp == NULL) - return 0; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u", - ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), - ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu, - ifp->speed); - - assert(ifp->info); - - 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); - } - - ospf = ospf_lookup_by_vrf_id(vrf_id); - if (!ospf) - return 0; - - ospf_if_recalculate_output_cost(ifp); - - ospf_if_update(ospf, ifp); - - hook_call(ospf_if_update, ifp); - - return 0; -} - -static int ospf_interface_delete(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct stream *s; - struct route_node *rn; - - s = zclient->ibuf; - /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: interface delete %s vrf %s[%u] index %d flags %llx metric %d mtu %d", - ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), - ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); - - hook_call(ospf_if_delete, ifp); - - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) - if (rn->info) - ospf_if_free((struct ospf_interface *)rn->info); - - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; -} - -static struct interface *zebra_interface_if_lookup(struct stream *s, - vrf_id_t vrf_id) -{ - 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_id); -} - -static int ospf_interface_state_up(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct ospf_interface *oi; - struct route_node *rn; - - ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - /* Interface is already up. */ - if (if_is_operative(ifp)) { - /* Temporarily keep ifp values. */ - struct interface if_tmp; - memcpy(&if_tmp, ifp, sizeof(struct interface)); - - zebra_interface_if_set_value(zclient->ibuf, ifp); - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] state update speed %u -> %u, bw %d -> %d", - ifp->name, if_tmp.speed, ifp->speed, - if_tmp.bandwidth, ifp->bandwidth); - - ospf_if_recalculate_output_cost(ifp); - - if (if_tmp.mtu != ifp->mtu) { - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] MTU change %u -> %u.", - ifp->name, if_tmp.mtu, ifp->mtu); - - /* Must reset the interface (simulate down/up) when MTU - * changes. */ - ospf_if_reset(ifp); - } - return 0; - } - - zebra_interface_if_set_value(zclient->ibuf, ifp); - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state change to up.", - ifp->name); - - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { - if ((oi = rn->info) == NULL) - continue; - - ospf_if_up(oi); - } - - return 0; -} - -static int ospf_interface_state_down(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct ospf_interface *oi; - struct route_node *node; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state change to down.", - ifp->name); - - for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) { - if ((oi = node->info) == NULL) - continue; - ospf_if_down(oi); - } - - return 0; -} - static int ospf_interface_address_add(ZAPI_CALLBACK_ARGS) { struct connected *c; @@ -283,7 +119,7 @@ static int ospf_interface_address_add(ZAPI_CALLBACK_ARGS) ospf_if_update(ospf, c->ifp); - hook_call(ospf_if_update, c->ifp); + ospf_if_interface(c->ifp); return 0; } @@ -325,7 +161,7 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS) /* Call interface hook functions to clean up */ ospf_if_free(oi); - hook_call(ospf_if_update, c->ifp); + ospf_if_interface(c->ifp); connected_free(c); @@ -1524,10 +1360,6 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance) zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs); zclient->zebra_connected = ospf_zebra_connected; zclient->router_id_update = ospf_router_id_update_zebra; - zclient->interface_add = ospf_interface_add; - zclient->interface_delete = ospf_interface_delete; - zclient->interface_up = ospf_interface_state_up; - zclient->interface_down = ospf_interface_state_down; zclient->interface_address_add = ospf_interface_address_add; zclient->interface_address_delete = ospf_interface_address_delete; zclient->interface_link_params = ospf_interface_link_params; diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 6737306532..d3f8a0380b 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -87,7 +87,4 @@ extern void ospf_zebra_init(struct thread_master *, unsigned short); extern void ospf_zebra_vrf_register(struct ospf *ospf); extern void ospf_zebra_vrf_deregister(struct ospf *ospf); -DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) -DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) - #endif /* _ZEBRA_OSPF_ZEBRA_H */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index f4de255877..b12fa63723 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1339,6 +1339,7 @@ void ospf_if_update(struct ospf *ospf, struct interface *ifp) /* Update connected redistribute. */ update_redistributed(ospf, 1); + } void ospf_remove_vls_through_area(struct ospf *ospf, struct ospf_area *area) diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index 246d836acf..bb92703ae4 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -166,6 +166,8 @@ int main(int argc, char **argv, char **envp) access_list_init(); pbr_nht_init(); pbr_map_init(); + if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up, + pbr_ifp_down, pbr_ifp_destroy); pbr_zebra_init(); pbr_vty_init(); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index d74d0fcd23..2bba837389 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -59,15 +59,8 @@ struct pbr_interface *pbr_if_new(struct interface *ifp) } /* Inteface addition message from zebra. */ -static int interface_add(ZAPI_CALLBACK_ARGS) +int pbr_ifp_create(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - DEBUGD(&pbr_dbg_zebra, "%s: %s", __PRETTY_FUNCTION__, ifp->name); @@ -79,24 +72,11 @@ static int interface_add(ZAPI_CALLBACK_ARGS) return 0; } -static int interface_delete(ZAPI_CALLBACK_ARGS) +int pbr_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - /* zebra_interface_state_read () updates interface structure in iflist - */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - DEBUGD(&pbr_dbg_zebra, "%s: %s", __PRETTY_FUNCTION__, ifp->name); - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } @@ -133,12 +113,8 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -static int interface_state_up(ZAPI_CALLBACK_ARGS) +int pbr_ifp_up(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - DEBUGD(&pbr_dbg_zebra, "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); @@ -147,12 +123,8 @@ static int interface_state_up(ZAPI_CALLBACK_ARGS) return 0; } -static int interface_state_down(ZAPI_CALLBACK_ARGS) +int pbr_ifp_down(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - DEBUGD(&pbr_dbg_zebra, "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); @@ -447,10 +419,6 @@ void pbr_zebra_init(void) zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs); zclient->zebra_connected = zebra_connected; - zclient->interface_add = interface_add; - zclient->interface_delete = interface_delete; - zclient->interface_up = interface_state_up; - zclient->interface_down = interface_state_down; zclient->interface_address_add = interface_address_add; zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; diff --git a/pbrd/pbr_zebra.h b/pbrd/pbr_zebra.h index 4cbefe2636..d5d938021a 100644 --- a/pbrd/pbr_zebra.h +++ b/pbrd/pbr_zebra.h @@ -39,4 +39,10 @@ extern void pbr_send_pbr_map(struct pbr_map_sequence *pbrms, struct pbr_map_interface *pmi, bool install); extern struct pbr_interface *pbr_if_new(struct interface *ifp); + +extern int pbr_ifp_create(struct interface *ifp); +extern int pbr_ifp_up(struct interface *ifp); +extern int pbr_ifp_down(struct interface *ifp); +extern int pbr_ifp_destroy(struct interface *ifp); + #endif diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 721d153d76..34c5eb43bc 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -104,7 +104,7 @@ static void tlv_trace(const char *label, const char *tlv_name, char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s", - label, + label, src_str, ifname, tlv_name); } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index bdeda2d76b..bc8dedc4f6 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1526,3 +1526,169 @@ int pim_if_ifchannel_count(struct pim_interface *pim_ifp) return count; } + +int pim_ifp_create(struct interface *ifp) +{ + struct pim_instance *pim; + + pim = pim_get_pim_instance(ifp->vrf_id); + if (PIM_DEBUG_ZEBRA) { + zlog_debug( + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, + if_is_operative(ifp)); + } + + if (if_is_operative(ifp)) { + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + /* + * If we have a pim_ifp already and this is an if_add + * that means that we probably have a vrf move event + * If that is the case, set the proper vrfness. + */ + if (pim_ifp) + pim_ifp->pim = pim; + pim_if_addr_add_all(ifp); + } + + /* + * If we are a vrf device that is up, open up the pim_socket for + * listening + * to incoming pim messages irrelevant if the user has configured us + * for pim or not. + */ + if (pim_if_is_vrf_device(ifp)) { + struct pim_interface *pim_ifp; + + if (!ifp->info) { + pim_ifp = pim_if_new(ifp, false, false, false, + false /*vxlan_term*/); + ifp->info = pim_ifp; + } + + pim_sock_add(ifp); + } + + if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME, + sizeof(PIM_VXLAN_TERM_DEV_NAME))) + pim_vxlan_add_term_dev(pim, ifp); + + return 0; +} + +int pim_ifp_up(struct interface *ifp) +{ + struct pim_instance *pim; + uint32_t table_id; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug( + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, + if_is_operative(ifp)); + } + + pim = pim_get_pim_instance(ifp->vrf_id); + if (if_is_operative(ifp)) { + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + /* + * If we have a pim_ifp already and this is an if_add + * that means that we probably have a vrf move event + * If that is the case, set the proper vrfness. + */ + if (pim_ifp) + pim_ifp->pim = pim; + + /* + pim_if_addr_add_all() suffices for bringing up both IGMP and + PIM + */ + pim_if_addr_add_all(ifp); + } + + /* + * If we have a pimreg device callback and it's for a specific + * table set the master appropriately + */ + if (sscanf(ifp->name, "pimreg%" SCNu32, &table_id) == 1) { + struct vrf *vrf; + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if ((table_id == vrf->data.l.table_id) + && (ifp->vrf_id != vrf->vrf_id)) { + struct interface *master = if_lookup_by_name( + vrf->name, vrf->vrf_id); + + if (!master) { + zlog_debug( + "%s: Unable to find Master interface for %s", + __PRETTY_FUNCTION__, vrf->name); + return 0; + } + pim_zebra_interface_set_master(master, ifp); + } + } + } + return 0; +} + +int pim_ifp_down(struct interface *ifp) +{ + if (PIM_DEBUG_ZEBRA) { + zlog_debug( + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, + if_is_operative(ifp)); + } + + if (!if_is_operative(ifp)) { + pim_ifchannel_delete_all(ifp); + /* + pim_if_addr_del_all() suffices for shutting down IGMP, + but not for shutting down PIM + */ + pim_if_addr_del_all(ifp); + + /* + pim_sock_delete() closes the socket, stops read and timer + threads, + and kills all neighbors. + */ + if (ifp->info) { + pim_sock_delete(ifp, "link down"); + } + } + + if (ifp->info) + pim_if_del_vif(ifp); + + return 0; +} + +int pim_ifp_destroy(struct interface *ifp) +{ + struct pim_instance *pim; + + if (PIM_DEBUG_ZEBRA) { + zlog_debug( + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, + if_is_operative(ifp)); + } + + if (!if_is_operative(ifp)) + pim_if_addr_del_all(ifp); + + pim = pim_get_pim_instance(ifp->vrf_id); + if (pim && pim->vxlan.term_if == ifp) + pim_vxlan_del_term_dev(pim); + + return 0; +} diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 1c11e85705..1b76b52305 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -227,4 +227,10 @@ int pim_update_source_set(struct interface *ifp, struct in_addr source); bool pim_if_is_vrf_device(struct interface *ifp); int pim_if_ifchannel_count(struct pim_interface *pim_ifp); + +extern int pim_ifp_create(struct interface *ifp); +extern int pim_ifp_up(struct interface *ifp); +extern int pim_ifp_down(struct interface *ifp); +extern int pim_ifp_destroy(struct interface *ifp); + #endif /* PIM_IFACE_H */ diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 5a8991c4c0..6a7dbe769f 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -127,6 +127,8 @@ int main(int argc, char **argv, char **envp) /* * Initialize zclient "update" and "lookup" sockets */ + if_zapi_callbacks(pim_ifp_create, pim_ifp_up, + pim_ifp_down, pim_ifp_destroy); pim_zebra_init(); pim_bfd_init(); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 37cb12548c..dadcbbe65d 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -63,218 +63,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; } -static int pim_zebra_if_add(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct pim_instance *pim; - - /* - zebra api adds/dels interfaces using the same call - interface_add_read below, see comments in lib/zclient.c - */ - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - if (!ifp) - return 0; - - pim = pim_get_pim_instance(vrf_id); - if (PIM_DEBUG_ZEBRA) { - zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); - } - - if (if_is_operative(ifp)) { - struct pim_interface *pim_ifp; - - pim_ifp = ifp->info; - /* - * If we have a pim_ifp already and this is an if_add - * that means that we probably have a vrf move event - * If that is the case, set the proper vrfness. - */ - if (pim_ifp) - pim_ifp->pim = pim; - pim_if_addr_add_all(ifp); - } - - /* - * If we are a vrf device that is up, open up the pim_socket for - * listening - * to incoming pim messages irrelevant if the user has configured us - * for pim or not. - */ - if (pim_if_is_vrf_device(ifp)) { - struct pim_interface *pim_ifp; - - if (!ifp->info) { - pim_ifp = pim_if_new(ifp, false, false, false, - false /*vxlan_term*/); - ifp->info = pim_ifp; - } - - pim_sock_add(ifp); - } - - if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME, - sizeof(PIM_VXLAN_TERM_DEV_NAME))) - pim_vxlan_add_term_dev(pim, ifp); - - return 0; -} - -static int pim_zebra_if_del(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - struct pim_instance *pim; - - /* - zebra api adds/dels interfaces using the same call - interface_add_read below, see comments in lib/zclient.c - - comments in lib/zclient.c seem to indicate that calling - zebra_interface_add_read is the correct call, but that - results in an attemted out of bounds read which causes - pimd to assert. Other clients use zebra_interface_state_read - and it appears to work just fine. - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (!ifp) - return 0; - - if (PIM_DEBUG_ZEBRA) { - zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); - } - - if (!if_is_operative(ifp)) - pim_if_addr_del_all(ifp); - - if_set_index(ifp, IFINDEX_INTERNAL); - - pim = pim_get_pim_instance(vrf_id); - if (pim && pim->vxlan.term_if == ifp) - pim_vxlan_del_term_dev(pim); - - return 0; -} - -static int pim_zebra_if_state_up(ZAPI_CALLBACK_ARGS) -{ - struct pim_instance *pim; - struct interface *ifp; - uint32_t table_id; - - /* - zebra api notifies interface up/down events by using the same call - zebra_interface_state_read below, see comments in lib/zclient.c - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (!ifp) - return 0; - - if (PIM_DEBUG_ZEBRA) { - zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); - } - - pim = pim_get_pim_instance(vrf_id); - if (if_is_operative(ifp)) { - struct pim_interface *pim_ifp; - - pim_ifp = ifp->info; - /* - * If we have a pim_ifp already and this is an if_add - * that means that we probably have a vrf move event - * If that is the case, set the proper vrfness. - */ - if (pim_ifp) - pim_ifp->pim = pim; - - /* - pim_if_addr_add_all() suffices for bringing up both IGMP and - PIM - */ - pim_if_addr_add_all(ifp); - } - - /* - * If we have a pimreg device callback and it's for a specific - * table set the master appropriately - */ - if (sscanf(ifp->name, "pimreg%" SCNu32, &table_id) == 1) { - struct vrf *vrf; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if ((table_id == vrf->data.l.table_id) - && (ifp->vrf_id != vrf->vrf_id)) { - struct interface *master = if_lookup_by_name( - vrf->name, vrf->vrf_id); - - if (!master) { - zlog_debug( - "%s: Unable to find Master interface for %s", - __PRETTY_FUNCTION__, vrf->name); - return 0; - } - zclient_interface_set_master(zclient, master, - ifp); - } - } - } - return 0; -} - -static int pim_zebra_if_state_down(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - - /* - zebra api notifies interface up/down events by using the same call - zebra_interface_state_read below, see comments in lib/zclient.c - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - if (!ifp) - return 0; - - if (PIM_DEBUG_ZEBRA) { - zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); - } - - if (!if_is_operative(ifp)) { - pim_ifchannel_delete_all(ifp); - /* - pim_if_addr_del_all() suffices for shutting down IGMP, - but not for shutting down PIM - */ - pim_if_addr_del_all(ifp); - - /* - pim_sock_delete() closes the socket, stops read and timer - threads, - and kills all neighbors. - */ - if (ifp->info) { - pim_sock_delete(ifp, "link down"); - } - } - - if (ifp->info) - pim_if_del_vif(ifp); - - return 0; -} - static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS) { struct interface *ifp; @@ -793,10 +581,6 @@ void pim_zebra_init(void) zclient->zebra_capabilities = pim_zebra_capabilities; zclient->zebra_connected = pim_zebra_connected; zclient->router_id_update = pim_router_id_update_zebra; - zclient->interface_add = pim_zebra_if_add; - zclient->interface_delete = pim_zebra_if_del; - zclient->interface_up = pim_zebra_if_state_up; - zclient->interface_down = pim_zebra_if_state_down; zclient->interface_address_add = pim_zebra_if_address_add; zclient->interface_address_delete = pim_zebra_if_address_del; zclient->interface_vrf_update = pim_zebra_interface_vrf_update; @@ -1246,3 +1030,9 @@ struct zclient *pim_zebra_zclient_get(void) else return NULL; } + +void pim_zebra_interface_set_master(struct interface *vrf, + struct interface *ifp) +{ + zclient_interface_set_master(zclient, vrf, ifp); +} diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index c9ed89863c..0f216cf5c9 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -51,4 +51,7 @@ void pim_zebra_update_all_interfaces(struct pim_instance *pim); void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old); + +void pim_zebra_interface_set_master(struct interface *vrf, + struct interface *ifp); #endif /* PIM_ZEBRA_H */ diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 80561f350b..3173277ba7 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -346,20 +346,8 @@ int if_check_address(struct rip *rip, struct in_addr addr) } /* Inteface link down message processing. */ -int rip_interface_down(ZAPI_CALLBACK_ARGS) +static int rip_ifp_down(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - - /* zebra_interface_state_read() updates interface structure in - iflist. */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - rip_interface_sync(ifp); rip_if_down(ifp); @@ -373,17 +361,8 @@ int rip_interface_down(ZAPI_CALLBACK_ARGS) } /* Inteface link up message processing */ -int rip_interface_up(ZAPI_CALLBACK_ARGS) +static int rip_ifp_up(struct interface *ifp) { - struct interface *ifp; - - /* zebra_interface_state_read () updates interface structure in - iflist. */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp == NULL) - return 0; - if (IS_RIP_DEBUG_ZEBRA) zlog_debug( "interface %s vrf %u index %d flags %#llx metric %d mtu %d is up", @@ -405,11 +384,8 @@ int rip_interface_up(ZAPI_CALLBACK_ARGS) } /* Inteface addition message from zebra. */ -int rip_interface_add(ZAPI_CALLBACK_ARGS) +static int rip_ifp_create(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); rip_interface_sync(ifp); if (IS_RIP_DEBUG_ZEBRA) @@ -435,19 +411,8 @@ int rip_interface_add(ZAPI_CALLBACK_ARGS) return 0; } -int rip_interface_delete(ZAPI_CALLBACK_ARGS) +static int rip_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - - s = zclient->ibuf; - /* zebra_interface_state_read() updates interface structure in iflist */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - rip_interface_sync(ifp); if (if_is_up(ifp)) { rip_if_down(ifp); @@ -458,10 +423,6 @@ int rip_interface_delete(ZAPI_CALLBACK_ARGS) ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); - /* To support pseudo interface do not free interface structure. */ - /* if_delete(ifp); */ - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } @@ -1263,4 +1224,6 @@ void rip_if_init(void) /* Install interface node. */ install_node(&interface_node, rip_interface_config_write); if_cmd_init(); + if_zapi_callbacks(rip_ifp_create, rip_ifp_up, + rip_ifp_down, rip_ifp_destroy); } diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 5a6b71fbaa..7260a40b19 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -551,7 +551,7 @@ static uint8_t *rip2PeerTable(struct variable *v, oid name[], size_t *length, return (uint8_t *)&domain; case RIP2PEERLASTUPDATE: -#if 0 +#if 0 /* We don't know the SNMP agent startup time. We have two choices here: * - assume ripd startup time equals SNMP agent startup time * - don't support this variable, at all diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 0c88cb202b..90ee667f05 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -238,12 +238,8 @@ void rip_zclient_init(struct thread_master *master) zclient = zclient_new(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_RIP, 0, &ripd_privs); zclient->zebra_connected = rip_zebra_connected; - zclient->interface_add = rip_interface_add; - zclient->interface_delete = rip_interface_delete; zclient->interface_address_add = rip_interface_address_add; zclient->interface_address_delete = rip_interface_address_delete; - zclient->interface_up = rip_interface_up; - zclient->interface_down = rip_interface_down; zclient->interface_vrf_update = rip_interface_vrf_update; zclient->redistribute_route_add = rip_zebra_read_route; zclient->redistribute_route_del = rip_zebra_read_route; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 9ed9dc28fe..9209a76460 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -43,10 +43,10 @@ /* If RFC2133 definition is used. */ #ifndef IPV6_JOIN_GROUP -#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif #ifndef IPV6_LEAVE_GROUP -#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface") @@ -196,19 +196,8 @@ static int ripng_if_down(struct interface *ifp) } /* Inteface link up message processing. */ -int ripng_interface_up(ZAPI_CALLBACK_ARGS) +static int ripng_ifp_up(struct interface *ifp) { - struct stream *s; - struct interface *ifp; - - /* zebra_interface_state_read() updates interface structure in iflist. - */ - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface up %s vrf %u index %d flags %llx metric %d mtu %d", @@ -230,19 +219,8 @@ int ripng_interface_up(ZAPI_CALLBACK_ARGS) } /* Inteface link down message processing. */ -int ripng_interface_down(ZAPI_CALLBACK_ARGS) +static int ripng_ifp_down(struct interface *ifp) { - struct stream *s; - struct interface *ifp; - - /* zebra_interface_state_read() updates interface structure in iflist. - */ - s = zclient->ibuf; - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - ripng_interface_sync(ifp); ripng_if_down(ifp); @@ -256,11 +234,8 @@ int ripng_interface_down(ZAPI_CALLBACK_ARGS) } /* Inteface addition message from zebra. */ -int ripng_interface_add(ZAPI_CALLBACK_ARGS) +static int ripng_ifp_create(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); ripng_interface_sync(ifp); if (IS_RIPNG_DEBUG_ZEBRA) @@ -281,19 +256,8 @@ int ripng_interface_add(ZAPI_CALLBACK_ARGS) return 0; } -int ripng_interface_delete(ZAPI_CALLBACK_ARGS) +static int ripng_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - /* zebra_interface_state_read() updates interface structure in iflist - */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - ripng_interface_sync(ifp); if (if_is_up(ifp)) { ripng_if_down(ifp); @@ -304,10 +268,6 @@ int ripng_interface_delete(ZAPI_CALLBACK_ARGS) ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); - /* To support pseudo interface do not free interface structure. */ - /* if_delete(ifp); */ - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } @@ -999,4 +959,6 @@ void ripng_if_init(void) /* Install interface node. */ install_node(&interface_node, interface_config_write); if_cmd_init(); + if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up, + ripng_ifp_down, ripng_ifp_destroy); } diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index a557a90c82..fa61d69caa 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -242,10 +242,6 @@ void zebra_init(struct thread_master *master) zclient_init(zclient, ZEBRA_ROUTE_RIPNG, 0, &ripngd_privs); zclient->zebra_connected = ripng_zebra_connected; - zclient->interface_up = ripng_interface_up; - zclient->interface_down = ripng_interface_down; - zclient->interface_add = ripng_interface_add; - zclient->interface_delete = ripng_interface_delete; zclient->interface_address_add = ripng_interface_address_add; zclient->interface_address_delete = ripng_interface_address_delete; zclient->interface_vrf_update = ripng_interface_vrf_update; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index ef4e474737..ad2ddd0dba 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2361,7 +2361,7 @@ DEFUN (show_ipv6_protocols, return CMD_SUCCESS; vty_out (vty, "Routing Protocol is \"ripng\"\n"); - + vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds\n", ripng->update_time, 0); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 6263f429ea..da2aa2f539 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -46,51 +46,19 @@ struct zclient *zclient = NULL; /* For registering threads. */ extern struct thread_master *master; -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); -} - /* Inteface addition message from zebra. */ -static int interface_add(ZAPI_CALLBACK_ARGS) +static int sharp_ifp_create(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (!ifp->info) - return 0; - return 0; } -static int interface_delete(ZAPI_CALLBACK_ARGS) +static int sharp_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - /* zebra_interface_state_read () updates interface structure in iflist - */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } static int interface_address_add(ZAPI_CALLBACK_ARGS) { - zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); return 0; @@ -109,19 +77,13 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -static int interface_state_up(ZAPI_CALLBACK_ARGS) +static int sharp_ifp_up(struct interface *ifp) { - - zebra_interface_if_lookup(zclient->ibuf); - return 0; } -static int interface_state_down(ZAPI_CALLBACK_ARGS) +static int sharp_ifp_down(struct interface *ifp) { - - zebra_interface_state_read(zclient->ibuf, vrf_id); - return 0; } @@ -243,6 +205,15 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) static void zebra_connected(struct zclient *zclient) { zclient_send_reg_requests(zclient, VRF_DEFAULT); + + /* + * Do not actually turn this on yet + * This is just the start of the infrastructure needed here + * This can be fixed at a later time. + * + * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, + * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); + */ } void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) @@ -338,28 +309,13 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, __PRETTY_FUNCTION__); } -static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) +static int sharp_debug_nexthops(struct zapi_route *api) { - struct sharp_nh_tracker *nht; - struct zapi_route nhr; - char buf[PREFIX_STRLEN]; int i; + char buf[PREFIX_STRLEN]; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { - zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__); - - return 0; - } - - zlog_debug("Received update for %s", - prefix2str(&nhr.prefix, buf, sizeof(buf))); - - nht = sharp_nh_tracker_get(&nhr.prefix); - nht->nhop_num = nhr.nexthop_num; - nht->updates++; - - for (i = 0; i < nhr.nexthop_num; i++) { - struct zapi_nexthop *znh = &nhr.nexthops[i]; + for (i = 0; i < api->nexthop_num; i++) { + struct zapi_nexthop *znh = &api->nexthops[i]; switch (znh->type) { case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -389,6 +345,45 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) break; } } + + return i; +} +static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) +{ + struct sharp_nh_tracker *nht; + struct zapi_route nhr; + + if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__); + + return 0; + } + + zlog_debug("Received update for %pFX", &nhr.prefix); + + nht = sharp_nh_tracker_get(&nhr.prefix); + nht->nhop_num = nhr.nexthop_num; + nht->updates++; + + sharp_debug_nexthops(&nhr); + + return 0; +} + +static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) +{ + struct zapi_route api; + + if (zapi_route_decode(zclient->ibuf, &api) < 0) + zlog_warn("%s: Decode of redistribute failed: %d", + __PRETTY_FUNCTION__, + ZEBRA_REDISTRIBUTE_ROUTE_ADD); + + zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), + &api.prefix, zebra_route_string(api.type)); + + sharp_debug_nexthops(&api); + return 0; } @@ -398,17 +393,19 @@ void sharp_zebra_init(void) { struct zclient_options opt = {.receive_notify = true}; + if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, + sharp_ifp_down, sharp_ifp_destroy); + zclient = zclient_new(master, &opt); zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); zclient->zebra_connected = zebra_connected; - zclient->interface_add = interface_add; - zclient->interface_delete = interface_delete; - zclient->interface_up = interface_state_up; - zclient->interface_down = interface_state_down; zclient->interface_address_add = interface_address_add; zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; zclient->nexthop_update = sharp_nexthop_update; zclient->import_check_update = sharp_nexthop_update; + + zclient->redistribute_route_add = sharp_redistribute_route; + zclient->redistribute_route_del = sharp_redistribute_route; } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 2944cdad32..976f892efb 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -49,46 +49,16 @@ bool debug; struct zclient *zclient; static struct hash *static_nht_hash; -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); -} - /* Inteface addition message from zebra. */ -static int interface_add(ZAPI_CALLBACK_ARGS) +static int static_ifp_create(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - static_ifindex_update(ifp, true); + return 0; } -static int interface_delete(ZAPI_CALLBACK_ARGS) +static int static_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - struct stream *s; - - s = zclient->ibuf; - /* zebra_interface_state_read () updates interface structure in iflist - */ - ifp = zebra_interface_state_read(s, vrf_id); - - if (ifp == NULL) - return 0; - - if_set_index(ifp, IFINDEX_INTERNAL); - static_ifindex_update(ifp, false); return 0; } @@ -113,37 +83,25 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -static int interface_state_up(ZAPI_CALLBACK_ARGS) +static int static_ifp_up(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_if_lookup(zclient->ibuf); - - if (ifp) { - if (if_is_vrf(ifp)) { - struct static_vrf *svrf = - static_vrf_lookup_by_id(vrf_id); + if (if_is_vrf(ifp)) { + struct static_vrf *svrf = static_vrf_lookup_by_id(ifp->vrf_id); - static_fixup_vrf_ids(svrf); - static_config_install_delayed_routes(svrf); - } - - /* Install any static reliant on this interface coming up */ - static_install_intf_nh(ifp); - static_ifindex_update(ifp, true); + static_fixup_vrf_ids(svrf); + static_config_install_delayed_routes(svrf); } + /* Install any static reliant on this interface coming up */ + static_install_intf_nh(ifp); + static_ifindex_update(ifp, true); + return 0; } -static int interface_state_down(ZAPI_CALLBACK_ARGS) +static int static_ifp_down(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (ifp) - static_ifindex_update(ifp, false); + static_ifindex_update(ifp, false); return 0; } @@ -504,19 +462,19 @@ extern void static_zebra_route_add(struct route_node *rn, ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient, &api); } + void static_zebra_init(void) { struct zclient_options opt = { .receive_notify = true }; + if_zapi_callbacks(static_ifp_create, static_ifp_up, + static_ifp_down, static_ifp_destroy); + zclient = zclient_new(master, &opt); zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs); zclient->zebra_capabilities = static_zebra_capabilities; zclient->zebra_connected = zebra_connected; - zclient->interface_add = interface_add; - zclient->interface_delete = interface_delete; - zclient->interface_up = interface_state_up; - zclient->interface_down = interface_state_down; zclient->interface_address_add = interface_address_add; zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index 7ff210cae3..f20bbc52d9 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -280,7 +280,7 @@ static void concat(test_, TYPE)(void) assert(!tmp || tmp->val >= j); } else assert(gteq == list_first(&head)); - + if (gteq) assert(gteq->val >= j); } diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo1.json b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json new file mode 100644 index 0000000000..e89263961d --- /dev/null +++ b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json @@ -0,0 +1,187 @@ +{ + "address_types": ["ipv4","ipv6"], + "ipv4base":"10.0.0.0", + "ipv4mask":30, + "ipv6base":"fd00::", + "ipv6mask":64, + "link_ip_start":{"ipv4":"10.0.0.0", "v4mask":30, "ipv6":"fd00::", "v6mask":64}, + "lo_prefix":{"ipv4":"1.0.", "v4mask":32, "ipv6":"2001:DB8:F::", "v6mask":128}, + "routers":{ + "r1":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r2":{"ipv4":"auto", "ipv6":"auto"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r1":{"ipv4":"auto", "ipv6":"auto"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r1":{"ipv4":"auto", "ipv6":"auto"}, + "r2":{"ipv4":"auto", "ipv6":"auto"}, + "r4":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo2.json b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json new file mode 100755 index 0000000000..c22a4c3ea7 --- /dev/null +++ b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json @@ -0,0 +1,316 @@ +{ + "address_types": ["ipv4", "ipv6"], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + }, + + "static_routes": [{ + "network": "10.0.20.1/32", + "no_of_ip": 2, + "next_hop": "10.0.0.2" + }, + { + "network": "1::1/128", + "no_of_ip": 2, + "next_hop": "fd00::2" + }] + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py new file mode 100755 index 0000000000..86ec6c82d2 --- /dev/null +++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py @@ -0,0 +1,1361 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +------- | R2 | + | +-------+ + | | + +-------+ | + | R1 | | + +-------+ | + | | + | +-------+ +-------+ + +---------- | R3 |----------| R4 | + +-------+ +-------+ + +""" + +################################# +# TEST SUMMARY +################################# +""" +Following tests are covered to test route-map functionality: +TC_34: + Verify if route-maps is applied in both inbound and + outbound direction to same neighbor/interface. +TC_36: + Test permit/deny statements operation in route-maps with a + permutation and combination of permit/deny in prefix-lists +TC_35: + Test multiple sequence numbers in a single route-map for different + match/set clauses. +TC_37: + Test add/remove route-maps with multiple set + clauses and without any match statement.(Set only) +TC_38: + Test add/remove route-maps with multiple match + clauses and without any set statement.(Match only) +""" + +import sys +import json +import time +import pytest +import inspect +import os +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +# Required to instantiate the topology builder class. +from lib.topojson import * +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, verify_bgp_community, + verify_rib, delete_route_maps, create_bgp_community_lists, + interface_status, create_route_maps, create_prefix_lists, + verify_route_maps, check_address_types, + shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify, verify_bgp_attributes) +from lib.topojson import build_topo_from_json, build_config_from_json + + +# Global variables +bgp_convergence = False +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_route_map_topo1.json".format(CWD) +try: + with open(jsonFile, 'r') as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["11.0.20.1/32", "20.0.20.1/32"], + "ipv6": ["1::1/128", "2::1/128"] +} +MASK = {"ipv4": "32", "ipv6": "128"} +NEXT_HOP = { + "ipv4": "10.0.0.2", + "ipv6": "fd00::2" +} +ADDR_TYPES = check_address_types() + + +class CreateTopo(Topo): + """ + Test topology builder + + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function""" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(CreateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ("setup_module :Failed \n Error:" + " {}".format(bgp_convergence)) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}". + format(time.asctime(time.localtime(time.time())))) + logger.info("=" * 40) + + +def test_route_map_inbound_outbound_same_neighbor_p0(request): + """ + TC_34: + Verify if route-maps is applied in both inbound and + outbound direction to same neighbor/interface. + """ + + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[adt][0], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + input_dict_2 = { + "r4": { + "static_routes": [ + { + "network": NETWORK[adt][1], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = create_static_routes(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_5 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "action": "permit", + "network": NETWORK["ipv4"][0] + }], + "pf_list_2_ipv4": [{ + "seqid": 10, + "action": "permit", + "network": NETWORK["ipv4"][1] + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "action": "permit", + "network": NETWORK["ipv6"][0] + }], + "pf_list_2_ipv6": [{ + "seqid": 100, + "action": "permit", + "network": NETWORK["ipv6"][1] + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + "r3": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + }], + "rmap_match_tag_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_tag_1_ipv4", + "direction": "in"}, + {"name": + "rmap_match_tag_1_ipv4", + "direction": "out"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_tag_1_ipv6", + "direction": "in"}, + {"name": + "rmap_match_tag_1_ipv6", + "direction": "out"} + ] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + dut = "r3" + protocol = "bgp" + input_dict_2 = { + "r4": { + "static_routes": [ + { + "network": [NETWORK[adt][1]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + assert result is not True, "Testcase {} : Failed \n" + "Expected behavior: routes are not present in rib \n" + "Error: {}".format( + tc_name, result) + + # Verifying RIB routes + dut = "r4" + input_dict = { + "r1": { + "static_routes": [ + { + "network": [NETWORK[adt][0]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + result = verify_rib(tgen, adt, dut, input_dict, protocol=protocol) + assert result is not True, "Testcase {} : Failed \n " + "Expected behavior: routes are not present in rib \n " + "Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +@pytest.mark.parametrize("prefix_action, rmap_action", [("permit", "permit"), + ("permit", "deny"), ("deny", "permit"), + ("deny", "deny")]) +def test_route_map_with_action_values_combination_of_prefix_action_p0( + request, prefix_action, rmap_action): + """ + TC_36: + Test permit/deny statements operation in route-maps with a permutation and + combination of permit/deny in prefix-lists + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[adt][0], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Permit in perfix list and route-map + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": prefix_action + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": prefix_action + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": rmap_action, + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_pf_1_ipv4", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_pf_1_ipv6", + "direction": "in"} + ] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + dut = "r3" + protocol = "bgp" + input_dict_2 = { + "r1": { + "static_routes": [ + { + "network": [NETWORK[adt][0]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + if "deny" in [prefix_action, rmap_action]: + assert result is not True, "Testcase {} : Failed \n Error: {}".\ + format(tc_name, result) + else: + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + +def test_route_map_multiple_seq_different_match_set_clause_p0(request): + """ + TC_35: + Test multiple sequence numbers in a single route-map for different + match/set clauses. + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [ + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + }, + "set": { + "aspath": { + "as_num": 500 + } + } + }, + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }, + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + dut = "r3" + protocol = "bgp" + input_dict = { + "r3": { + "route_maps": { + "rmap_match_pf_list1": [{ + "set": { + "med": 50, + } + }], + } + } + } + + static_routes = [NETWORK[adt][0]] + + time.sleep(2) + result = verify_bgp_attributes(tgen, adt, dut, static_routes, + "rmap_match_pf_list1", input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + dut = "r4" + result = verify_bgp_attributes(tgen, adt, dut, static_routes, + "rmap_match_pf_list1", input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + logger.info("Testcase " + tc_name + " :Passed \n") + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_map_set_only_no_match_p0(request): + """ + TC_37: + Test add/remove route-maps with multiple set + clauses and without any match statement.(Set only) + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1": [ + { + "action": "permit", + "set": { + "med": 50, + "localpref": 150, + "weight": 4000 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + time.sleep(2) + for adt in ADDR_TYPES: + input_dict_4 = { + "r3": { + "route_maps": { + "rmap_match_pf_1": [ + { + "action": "permit", + "set": { + "med": 50, + } + } + ] + } + } + } + # Verifying RIB routes + static_routes = [NETWORK[adt][0]] + result = verify_bgp_attributes(tgen, adt, "r3", static_routes, + "rmap_match_pf_1", input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + result = verify_bgp_attributes(tgen, adt, "r4", static_routes, + "rmap_match_pf_1", input_dict_4) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + logger.info("Testcase " + tc_name + " :Passed \n") + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_map_match_only_no_set_p0(request): + """ + TC_38: + Test add/remove route-maps with multiple match + clauses and without any set statement.(Match only) + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + "r1": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "set": { + "med": 50, + "localpref": 150, + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_5 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + "r3": { + "route_maps": { + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + static_routes = [NETWORK[adt][0]] + result = verify_bgp_attributes(tgen, adt, "r3", static_routes, + "rmap_match_pf_1", input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + + diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py new file mode 100755 index 0000000000..7009fc97ce --- /dev/null +++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py @@ -0,0 +1,3916 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +"""Following tests are covered to test route-map functionality. +TC_57: + Create route map to match prefix-list and permit inbound + and outbound prefixes and set criteria on match +TC_52: + Test modify set/match clauses in a route-map to see + if it takes immediate effect. +TC_61: + Delete the route maps. +TC_50_1: + Test modify/remove prefix-lists referenced by a + route-map for match statement. +TC_50_1: + Remove prefix-list referencec by route-map match cluase + and verifying it reflecting as intended +TC_51: + Add and remove community-list referencec by route-map match cluase + and verifying it reflecting as intended +TC_45: + Test multiple match statements as part of a route-map's single + sequence number. (Logical OR-ed of multiple match statements) +TC_44: + Test multiple match statements as part of a route-map's single + sequence number. (Logical AND of multiple match statements) +TC_41: + Test add/remove route-maps to specific neighbor and see if + it takes effect as intended +TC_56: + Test clear BGP sessions and interface flaps to see if + route-map properties are intact. +TC_46: + Verify if a blank sequence number can be create(without any + match/set clause) and check if it allows all the traffic/prefixes +TC_48: + Create route map setting local preference and weight to eBGP peeer + and metric to ibgp peer and verifying it should not get advertised +TC_43: + Test multiple set statements as part of a route-map's + single sequence number. +TC_54: + Verify route-maps continue clause functionality. +TC_55: + Verify route-maps goto clause functionality. +TC_53: + Verify route-maps call clause functionality. +TC_58: + Create route map deny inbound and outbound prefixes on + match prefix list and set criteria on match +TC_59: + Create route map to permit inbound prefixes with filter + match tag and set criteria +TC_60 + Create route map to deny outbound prefixes with filter match tag, + and set criteria +""" + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +--------- | R2 | + | +-------+ + |iBGP | + +-------+ | + | R1 | |iBGP + +-------+ | + | | + | iBGP +-------+ eBGP +-------+ + +---------- | R3 |----------| R4 | + +-------+ +-------+ + | + |eBGP + | + +-------+ + | R5 | + +-------+ + + +""" + +import sys +import json +import time +import pytest +import inspect +import os +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +# Required to instantiate the topology builder class. +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, create_static_routes, + verify_rib, delete_route_maps, create_bgp_community_lists, + interface_status, create_route_maps, create_prefix_lists, + verify_route_maps, check_address_types, verify_bgp_community, + shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify, verify_bgp_attributes) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_route_map_topo2.json".format(CWD) + +try: + with open(jsonFile, 'r') as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["11.0.20.1/32", "11.0.20.2/32"], + "ipv6": ["2::1/128", "2::2/128"] +} + +bgp_convergence = False +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() + + +class BGPRmapTopo(Topo): + """BGPRmapTopo. + + BGPRmap topology 1 + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function.""" + tgen = get_topogen(self) + + # Building topology and configuration from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """setup_module. + + Set up the pytest environment + * `mod`: module name + """ + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("="*40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(BGPRmapTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ('setup_module :Failed \n Error:' + ' {}'.format(bgp_convergence)) + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """teardown_module. + + Teardown the pytest environment. + * `mod`: module name + """ + logger.info("Running teardown_module to delete topology") + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}".format( + time.asctime(time.localtime(time.time())))) + logger.info("="*40) + + +##################################################### +# Tests starting +##################################################### + + +def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): + """ + TC: 57 + Create route map to match prefix-list and permit inbound + and outbound prefixes and set criteria on match + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + } + } + } + } + + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + for addr_type in ADDR_TYPES: + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }, + ], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "med": 50 + } + }, + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_modify_set_match_clauses_in_rmap_p0(): + """ + TC_52: + Test modify set/match clauses in a route-map to see + if it takes immediate effect. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }], + 'pf_list_2_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }], + 'pf_list_2_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Modify set/match clause of in-used route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 1000, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 2000 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_delete_route_maps_p1(): + """ + TC_61: + Delete the route maps. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Delete route maps + for addr_type in ADDR_TYPES: + input_dict = { + 'r3': { + 'route_maps': ['rmap_match_tag_1_{}'.format(addr_type)] + } + } + result = delete_route_maps(tgen, input_dict) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + result = verify_route_maps(tgen, input_dict) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_modify_prefix_list_referenced_by_rmap_p0(): + """ + TC_50_1: + Test modify/remove prefix-lists referenced by a + route-map for match statement. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit', + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Modify ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'deny' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'deny' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + sleep(5) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_remove_prefix_list_referenced_by_rmap_p0(): + """ + TC_50_1: + Remove prefix-list referencec by route-map match cluase + and verifying it reflecting as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Remove/Delete prefix list + input_dict_3 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + 'delete': True + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit', + 'delete': True + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + result = verify_prefix_lists(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Api call to clear bgp, so config changes would be reflected + dut = 'r3' + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_add_and_remove_community_list_referenced_by_rmap_p0(): + """ + TC_51: + Add and remove community-list referencec by route-map match cluase + and verifying it reflecting as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Creating configuration from JSON + # build_config_from_json(tgen, topo) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_5 = { + "r1": { + "route_maps": { + "rm_r1_out_{}".format(addr_type): [{ + "action": "permit", + "set": { + "large_community": {"num": "1:1:1 1:2:3 2:1:1 2:2:2"} + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_6 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rm_r1_out_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rm_r1_out_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create standard large commumity-list + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create route map + input_dict_2 = { + "r3": { + "route_maps": { + "rm_r3_in_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type : { + "large-community-list": {"id": "rmap_lcomm_"+ + addr_type} + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_3 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rm_r3_in_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rm_r3_in_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + sleep(5) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verify large-community-list + dut = 'r3' + networks = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + input_dict_4 = { + 'largeCommunity': '1:1:1 1:2:3 2:1:1 2:2:2' + } + for addr_type in ADDR_TYPES: + result = verify_bgp_community(tgen, addr_type, dut, networks[ + addr_type],input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_match_statement_in_route_map_logical_ORed_p0(): + """ + TC_45: + Test multiple match statements as part of a route-map's single + sequence number. (Logical OR-ed of multiple match statements) + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Api call to advertise networks + input_dict_nw1 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": '10.0.30.1/32'} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": '1::1/128'} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_nw1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Api call to advertise networks + input_dict_nw2 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": '20.0.30.1/32'} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": '2::1/128'} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_nw2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_2_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_2_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + input_dict_3_addr_type ={} + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 200 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_6 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.30.1/32"], + "ipv6": ["1::1/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + routes = { + "ipv4": ["20.0.30.1/32"], + "ipv6": ["2::1/128"] + } + for addr_type in ADDR_TYPES: + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_match_statement_in_route_map_logical_ANDed(): + """ + TC_44: + Test multiple match statements as part of a route-map's single + sequence number. (Logical AND of multiple match statements) + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_5 = { + "r1": { + "route_maps": { + "rm_r1_out_{}".format(addr_type): [{ + "action": "permit", + "set": { + "large_community": { + "num": "1:1:1 1:2:3 2:1:1 2:2:2"} + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + 'r1': { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rm_r1_out_{}".format(addr_type), + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create standard large commumity-list + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type : { + "large_community_list": {"id": "rmap_lcomm_"+ + addr_type} + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_{}".format(addr_type), + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # sleep(10) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_add_remove_rmap_to_specific_neighbor_p0(): + """ + TC_41: + Test add/remove route-maps to specific neighbor and see if + it takes effect as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'deny' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'deny' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : \n' + 'Expected Behavior: Routes are not present in RIB \n' + ' Error: {}'.format( + tc_name, result) + + # Remove applied rmap from neighbor + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in', + "delete": True + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in', + "delete": True + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): + """ + TC_56: + Test clear BGP sessions and interface flaps to see if + route-map properties are intact. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # clear bgp, so config changes would be reflected + dut = 'r3' + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Flap interface to see if route-map properties are intact + # Shutdown interface + dut = "r3" + intf = "r3-r1-eth0" + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(5) + + # Bringup interface + dut = "r3" + intf = "r3-r1-eth0" + shutdown_bringup_interface(tgen, dut, intf, True) + + # Verify BGP convergence once interface is up + result = verify_bgp_convergence(tgen, topo) + assert result is True, ( + 'setup_module :Failed \n Error:' ' {}'.format(result)) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_rmap_without_match_and_set_clause_p0(): + """ + TC_46: + Verify if a blank sequence number can be create(without any + match/set clause) and check if it allows all the traffic/prefixes + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_no_match_set_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5' + }], + "rmap_no_match_set_2_{}".format(addr_type): [{ + "action": "deny", + 'seq_id': '5' + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): + """ + TC_48: + Create route map setting local preference and weight to eBGP peeer + and metric to ibgp peer and verifying it should not get advertised + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + input_dict_3_addr_type ={} + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + } + }, + "set": { + "med": 50 + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + }}, + "set": { + "localpref": 150 + } + }], + "rmap_match_pf_3_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + }}, + "set": { + "weight": 1000 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_3_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_3_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_2" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: Attributes are not set \n' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r5' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # Verifying BGP set attributes + dut = 'r5' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + rmap_name = "rmap_match_pf_3" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_3_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: Attributes are not set \n' + 'Error: {}'.format( + tc_name, result) + + logger.info("Expected behaviour: {}".format(result)) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_set_on_single_sequence_in_rmap_p0(): + """ + TC_43: + Test multiple set statements as part of a route-map's + single sequence number. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100, + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_continue_clause_p0(): + """ + TC_54: + Verify route-maps continue clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '10', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + }, + "continue": "30" + }, + { + "action": "permit", + 'seq_id': '20', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + }, + { + "action": "permit", + 'seq_id': '30', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 100 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + rmap_name = "rmap_match_pf_1" + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + seq_id = { + "ipv4": ["10", "30"], + "ipv6": ["10", "30"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3, seq_id[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_goto_clause_p0(): + """ + TC_55: + Verify route-maps goto clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '10', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "goto": "30" + }, + { + "action": "permit", + 'seq_id': '20', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 100 + } + }, + { + "action": "permit", + 'seq_id': '30', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + rmap_name = "rmap_match_pf_1" + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + seq_id = { + "ipv4": ["10", "30"], + "ipv6": ["10", "30"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3, seq_id[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_call_clause_p0(): + """ + TC_53: + Verify route-maps call clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + }, + "call": "rmap_match_pf_2_{}".format(addr_type) + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + rmap_name = "rmap_match_pf_2" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): + """ + TC_58: + Create route map deny inbound and outbound prefixes on + match prefix list and set criteria on match + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): + """ + TC_59: + Create route map to permit inbound prefixes with filter + match tag and set criteria + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + + for addr_type in ADDR_TYPES: + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): + """ + TC_60 + Create route map to deny outbound prefixes with filter match tag, + and set criteria + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + + for addr_type in ADDR_TYPES: + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behavior: routes are denied \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 49e48ba927..76b0ab017e 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -74,3 +74,9 @@ def pytest_runtest_makereport(item, call): parent._previousfailed = item logger.error('assert failed at "{}/{}": {}'.format( modname, item.name, call.excinfo.value)) + + # (topogen) Set topology error to avoid advancing in the test. + tgen = get_topogen() + if tgen is not None: + # This will cause topogen to report error on `routers_have_failure`. + tgen.set_error('{}/{}'.format(modname, item.name)) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index c05e14a95e..bfc34c25e4 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1229,6 +1229,150 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): return True +@retry(attempts=3, wait=4, return_is_str=True) +def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, + input_dict, seq_id=None): + """ + API will verify BGP attributes set by Route-map for given prefix and + DUT. it will run "show bgp ipv4/ipv6 {prefix_address} json" command + in DUT to verify BGP attributes set by route-map, Set attributes + values will be read from input_dict and verified with command output. + + * `tgen`: topogen object + * `addr_type` : ip type, ipv4/ipv6 + * `dut`: Device Under Test + * `static_routes`: Static Routes for which BGP set attributes needs to be + verified + * `rmap_name`: route map name for which set criteria needs to be verified + * `input_dict`: defines for which router, AS numbers needs + * `seq_id`: sequence number of rmap, default is None + + Usage + ----- + input_dict = { + "r3": { + "route_maps": { + "rmap_match_pf_1_ipv4": [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }], + "rmap_match_pf_2_ipv6": [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = verify_bgp_attributes(tgen, 'ipv4', "r1", "10.0.20.1/32", + rmap_match_pf_1_ipv4, input_dict) + + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_bgp_attributes()") + for router, rnode in tgen.routers().iteritems(): + if router != dut: + continue + + logger.info('Verifying BGP set attributes for dut {}:'.format(router)) + + for static_route in static_routes: + cmd = "show bgp {} {} json".format(addr_type, static_route) + show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True) + print("show_bgp_json $$$$$", show_bgp_json) + + dict_to_test = [] + tmp_list = [] + for rmap_router in input_dict.keys(): + for rmap, values in input_dict[rmap_router][ + "route_maps"].items(): + print("rmap == rmap_name $$$$1", rmap, rmap_name) + if rmap == rmap_name: + print("rmap == rmap_name $$$$", rmap, rmap_name) + dict_to_test = values + for rmap_dict in values: + if seq_id is not None: + if type(seq_id) is not list: + seq_id = [seq_id] + + if "seq_id" in rmap_dict: + rmap_seq_id = \ + rmap_dict["seq_id"] + for _seq_id in seq_id: + if _seq_id == rmap_seq_id: + tmp_list.append(rmap_dict) + if tmp_list: + dict_to_test = tmp_list + + print("dict_to_test $$$$", dict_to_test) + for rmap_dict in dict_to_test: + if "set" in rmap_dict: + for criteria in rmap_dict["set"].keys(): + if criteria not in show_bgp_json[ + "paths"][0]: + errormsg = ("BGP attribute: {}" + " is not found in" + " cli: {} output " + "in router {}". + format(criteria, + cmd, + router)) + return errormsg + + if rmap_dict["set"][criteria] == \ + show_bgp_json["paths"][0][ + criteria]: + logger.info("Verifying BGP " + "attribute {} for" + " route: {} in " + "router: {}, found" + " expected value:" + " {}". + format(criteria, + static_route, + dut, + rmap_dict[ + "set"][ + criteria])) + else: + errormsg = \ + ("Failed: Verifying BGP " + "attribute {} for route:" + " {} in router: {}, " + " expected value: {} but" + " found: {}". + format(criteria, + static_route, + dut, + rmap_dict["set"] + [criteria], + show_bgp_json[ + 'paths'][ + 0][criteria])) + return errormsg + + logger.debug("Exiting lib API: verify_bgp_attributes()") + return True + @retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute): diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index f2d33f94ae..ba8a4cb0f4 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -21,6 +21,7 @@ from collections import OrderedDict from datetime import datetime from time import sleep +from copy import deepcopy from subprocess import call from subprocess import STDOUT as SUB_STDOUT from subprocess import PIPE as SUB_PIPE @@ -208,6 +209,7 @@ def create_common_configuration(tgen, router, data, config_type=None, "interface_config": "! Interfaces Config\n", "static_route": "! Static Route Config\n", "prefix_list": "! Prefix List Config\n", + "bgp_community_list": "! Community List Config\n", "route_maps": "! Route Maps Config\n", "bgp": "! BGP Config\n" }) @@ -547,13 +549,11 @@ def generate_ips(network, no_of_ips): Returns list of IPs. based on start_ip and no_of_ips - * `network` : from here the ip will start generating, start_ip will be - first ip + * `network` : from here the ip will start generating, + start_ip will be * `no_of_ips` : these many IPs will be generated - - Limitation: It will generate IPs only for ip_mask 32 - """ + ipaddress_list = [] if type(network) is not list: network = [network] @@ -893,6 +893,7 @@ def create_static_routes(tgen, input_dict, build=False): """ result = False logger.debug("Entering lib API: create_static_routes()") + input_dict = deepcopy(input_dict) try: for router in input_dict.keys(): if "static_routes" not in input_dict[router]: @@ -918,16 +919,21 @@ def create_static_routes(tgen, input_dict, build=False): next_hop = static_route["next_hop"] network = static_route["network"] - ip_list = generate_ips([network], no_of_ip) + if type(network) is not list: + network = [network] + + ip_list = generate_ips(network, no_of_ip) for ip in ip_list: addr_type = validate_ip_address(ip) + if addr_type == "ipv4": cmd = "ip route {} {}".format(ip, next_hop) else: cmd = "ipv6 route {} {}".format(ip, next_hop) if tag: - cmd = "{} {}".format(cmd, str(tag)) + cmd = "{} tag {}".format(cmd, str(tag)) + if admin_distance: cmd = "{} {}".format(cmd, admin_distance) @@ -1112,11 +1118,11 @@ def create_route_maps(tgen, input_dict, build=False): "prefix_list": "pf_list_1" } - "large-community-list": "{ + "large-community-list": { "id": "community_1", "exact_match": True } - "community": { + "community_list": { "id": "community_2", "exact_match": True } @@ -1152,12 +1158,11 @@ def create_route_maps(tgen, input_dict, build=False): result = False logger.debug("Entering lib API: create_route_maps()") - + input_dict = deepcopy(input_dict) try: for router in input_dict.keys(): if "route_maps" not in input_dict[router]: - errormsg = "route_maps not present in input_dict" - logger.debug(errormsg) + logger.debug("route_maps not present in input_dict") continue rmap_data = [] for rmap_name, rmap_value in \ @@ -1187,10 +1192,41 @@ def create_route_maps(tgen, input_dict, build=False): rmap_name, rmap_action, seq_id )) + if "continue" in rmap_dict: + continue_to = rmap_dict["continue"] + if continue_to: + rmap_data.append("on-match goto {}". + format(continue_to)) + else: + logger.error("In continue, 'route-map entry " + "sequence number' is not provided") + return False + + if "goto" in rmap_dict: + go_to = rmap_dict["goto"] + if go_to: + rmap_data.append("on-match goto {}". + format(go_to)) + else: + logger.error("In goto, 'Goto Clause number' is not" + " provided") + return False + + if "call" in rmap_dict: + call_rmap = rmap_dict["call"] + if call_rmap: + rmap_data.append("call {}". + format(call_rmap)) + else: + logger.error("In call, 'destination Route-Map' is" + " not provided") + return False + # Verifying if SET criteria is defined if "set" in rmap_dict: set_data = rmap_dict["set"] - + ipv4_data = set_data.setdefault("ipv4", {}) + ipv6_data = set_data.setdefault("ipv6", {}) local_preference = set_data.setdefault("localpref", None) metric = set_data.setdefault("med", None) @@ -1199,7 +1235,10 @@ def create_route_maps(tgen, input_dict, build=False): community = set_data.setdefault("community", {}) large_community = set_data.setdefault( "large_community", {}) + large_comm_list = set_data.setdefault( + "large_comm_list", {}) set_action = set_data.setdefault("set_action", None) + nexthop = set_data.setdefault("nexthop", None) # Local Preference if local_preference: @@ -1243,42 +1282,84 @@ def create_route_maps(tgen, input_dict, build=False): rmap_data.append(cmd) else: - logger.errror("In large_community, AS Num not" - " provided") + logger.error("In large_community, AS Num not" + " provided") + return False + if large_comm_list: + id = large_comm_list.setdefault("id", None) + del_comm = large_comm_list.setdefault("delete", + None) + if id: + cmd = "set large-comm-list {}".format(id) + if del_comm: + cmd = "{} delete".format(cmd) + + rmap_data.append(cmd) + else: + logger.error("In large_comm_list 'id' not" + " provided") return False # Weight if weight: - rmap_data.append("set weight {}".format( + rmap_data.append("set weight {} \n".format( weight)) - + if ipv6_data: + nexthop = ipv6_data.setdefault("nexthop",None) + if nexthop: + rmap_data.append("set ipv6 next-hop \ + {}".format(nexthop)) # Adding MATCH and SET sequence to RMAP if defined if "match" in rmap_dict: match_data = rmap_dict["match"] ipv4_data = match_data.setdefault("ipv4", {}) ipv6_data = match_data.setdefault("ipv6", {}) - community = match_data.setdefault("community-list", - {}) + community = match_data.setdefault( + "community_list",{}) large_community = match_data.setdefault( - "large-community-list", {} + "large_community", {} + ) + large_community_list = match_data.setdefault( + "large_community_list", {} ) - tag = match_data.setdefault("tag", None) if ipv4_data: - prefix_name = ipv4_data.setdefault("prefix_lists", - None) + # fetch prefix list data from rmap + prefix_name = \ + ipv4_data.setdefault("prefix_lists", + None) if prefix_name: - rmap_data.append("match ip address prefix-list" - " {}".format(prefix_name)) + rmap_data.append("match ip address" + " prefix-list {}".format(prefix_name)) + + # fetch tag data from rmap + tag = ipv4_data.setdefault("tag", None) + if tag: + rmap_data.append("match tag {}".format(tag)) + + # fetch large community data from rmap + large_community_list = ipv4_data.setdefault( + "large_community_list",{}) + large_community = match_data.setdefault( + "large_community", {}) + if ipv6_data: prefix_name = ipv6_data.setdefault("prefix_lists", None) if prefix_name: - rmap_data.append("match ipv6 address " - "prefix-list {}". - format(prefix_name)) - if tag: - rmap_data.append("match tag {}".format(tag)) + rmap_data.append("match ipv6 address" + " prefix-list {}".format(prefix_name)) + + # fetch tag data from rmap + tag = ipv6_data.setdefault("tag", None) + if tag: + rmap_data.append("match tag {}".format(tag)) + + # fetch large community data from rmap + large_community_list = ipv6_data.setdefault( + "large_community_list",{}) + large_community = match_data.setdefault( + "large_community", {}) if community: if "id" not in community: @@ -1293,10 +1374,9 @@ def create_route_maps(tgen, input_dict, build=False): cmd = "{} exact-match".format(cmd) rmap_data.append(cmd) - if large_community: if "id" not in large_community: - logger.error("'num' is mandatory for " + logger.error("'id' is mandatory for " "large-community-list in match " "criteria") return False @@ -1306,7 +1386,19 @@ def create_route_maps(tgen, input_dict, build=False): "exact_match", False) if exact_match: cmd = "{} exact-match".format(cmd) - + rmap_data.append(cmd) + if large_community_list: + if "id" not in large_community_list: + logger.error("'id' is mandatory for " + "large-community-list in match " + "criteria") + return False + cmd = "match large-community {}".format( + large_community_list["id"]) + exact_match = large_community_list.setdefault( + "exact_match", False) + if exact_match: + cmd = "{} exact-match".format(cmd) rmap_data.append(cmd) result = create_common_configuration(tgen, router, @@ -1320,10 +1412,178 @@ def create_route_maps(tgen, input_dict, build=False): logger.error(errormsg) return errormsg - logger.debug("Exiting lib API: create_prefix_lists()") + logger.debug("Exiting lib API: create_route_maps()") + return result + + +def delete_route_maps(tgen, input_dict): + """ + Delete ip route maps from device + + * `tgen` : Topogen object + * `input_dict` : for which router, + route map has to be deleted + + Usage + ----- + # Delete route-map rmap_1 and rmap_2 from router r1 + input_dict = { + "r1": { + "route_maps": ["rmap_1", "rmap__2"] + } + } + result = delete_route_maps("ipv4", input_dict) + + Returns + ------- + errormsg(str) or True + """ + logger.info("Entering lib API: delete_route_maps()") + + for router in input_dict.keys(): + route_maps = input_dict[router]["route_maps"][:] + rmap_data = input_dict[router] + rmap_data["route_maps"] = {} + for route_map_name in route_maps: + rmap_data["route_maps"].update({ + route_map_name: + [{ + "delete": True + }] + }) + + return create_route_maps(tgen, input_dict) + + +def create_bgp_community_lists(tgen, input_dict, build=False): + """ + Create bgp community-list or large-community-list on the devices as per + the arguments passed. Takes list of communities in input. + + Parameters + ---------- + * `tgen` : Topogen object + * `input_dict` : Input dict data, required when configuring from testcase + * `build` : Only for initial setup phase this is set as True. + Usage + ----- + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + """ + + result = False + logger.debug("Entering lib API: create_bgp_community_lists()") + input_dict = deepcopy(input_dict) + try: + for router in input_dict.keys(): + if "bgp_community_lists" not in input_dict[router]: + errormsg = "bgp_community_lists not present in input_dict" + logger.debug(errormsg) + continue + + config_data = [] + + community_list = input_dict[router]["bgp_community_lists"] + for community_dict in community_list: + del_action = community_dict.setdefault("delete", False) + community_type = community_dict.setdefault("community_type", + None) + action = community_dict.setdefault("action", None) + value = community_dict.setdefault("value", '') + large = community_dict.setdefault("large", None) + name = community_dict.setdefault("name", None) + if large: + cmd = "bgp large-community-list" + else: + cmd = "bgp community-list" + + if not large and not (community_type and action and value): + errormsg = "community_type, action and value are " \ + "required in bgp_community_list" + logger.error(errormsg) + return False + + try: + community_type = int(community_type) + cmd = "{} {} {} {}".format(cmd, community_type, action, + value) + except ValueError: + + cmd = "{} {} {} {} {}".format( + cmd, community_type, name, action, value) + + if del_action: + cmd = "no {}".format(cmd) + + config_data.append(cmd) + + result = create_common_configuration(tgen, router, config_data, + "bgp_community_list", + build=build) + + except InvalidCLIError: + # Traceback + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: create_bgp_community_lists()") return result +def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False): + """ + Shutdown or bringup router's interface " + + * `tgen` : Topogen object + * `dut` : Device under test + * `intf_name` : Interface name to be shut/no shut + * `ifaceaction` : Action, to shut/no shut interface, + by default is False + + Usage + ----- + dut = "r3" + intf = "r3-r1-eth0" + # Shut down ineterface + shutdown_bringup_interface(tgen, dut, intf, False) + + # Bring up ineterface + shutdown_bringup_interface(tgen, dut, intf, True) + + Returns + ------- + errormsg(str) or True + """ + + from topotest import interface_set_status + router_list = tgen.routers() + if ifaceaction: + logger.info("Bringing up interface : {}".format(intf_name)) + else: + logger.info("Shutting down interface : {}".format(intf_name)) + + interface_set_status(router_list[dut], intf_name, + ifaceaction) + + if ifaceaction: + # Disabling v6 link local once interfac comes up back + disable_v6_link_local(tgen, dut, intf_name=intf_name) + + ############################################# # Verification APIs ############################################# @@ -1625,5 +1885,133 @@ def verify_prefix_lists(tgen, input_dict): logger.info("Prefix list %s is/are not present in the router" " from router %s", prefix_list, router) - logger.debug("Exiting lib API: verify_prefix_lissts()") + logger.debug("Exiting lib API: verify_prefix_lists()") + return True + + +@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2) +def verify_route_maps(tgen, input_dict): + """ + Running "show route-map" command and verifying given route-map + is present in router. + Parameters + ---------- + * `tgen` : topogen object + * `input_dict`: data to verify prefix lists + Usage + ----- + # To verify rmap_1 and rmap_2 are present in router r1 + input_dict = { + "r1": { + "route_maps": ["rmap_1", "rmap_2"] + } + } + result = verify_route_maps(tgen, input_dict) + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_route_maps()") + + for router in input_dict.keys(): + if router not in tgen.routers(): + continue + + rnode = tgen.routers()[router] + # Show ip route-map + show_route_maps = rnode.vtysh_cmd("show route-map") + + # Verify route-map is deleted + route_maps = input_dict[router]["route_maps"] + for route_map in route_maps: + if route_map in show_route_maps: + errormsg = ("Route map {} is not deleted from router" + " {}".format(route_map, router)) + return errormsg + + logger.info("Route map %s is/are deleted successfully from" + " router %s", route_maps, router) + + logger.debug("Exiting lib API: verify_route_maps()") + return True + + +@retry(attempts=3, wait=4, return_is_str=True) +def verify_bgp_community(tgen, addr_type, router, network, input_dict=None): + """ + API to veiryf BGP large community is attached in route for any given + DUT by running "show bgp ipv4/6 {route address} json" command. + + Parameters + ---------- + * `tgen`: topogen object + * `addr_type` : ip type, ipv4/ipv6 + * `dut`: Device Under Test + * `network`: network for which set criteria needs to be verified + * `input_dict`: having details like - for which router, community and + values needs to be verified + Usage + ----- + networks = ["200.50.2.0/32"] + input_dict = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None) + + Returns + ------- + errormsg(str) or True + """ + + logger.info("Entering lib API: verify_bgp_community()") + if router not in tgen.routers(): + return False + + rnode = tgen.routers()[router] + + logger.debug("Verifying BGP community attributes on dut %s: for %s " + "network %s", router, addr_type, network) + + for net in network: + cmd = "show bgp {} {} json".format(addr_type, net) + show_bgp_json = rnode.vtysh_cmd(cmd, isjson=True) + logger.info(show_bgp_json) + if "paths" not in show_bgp_json: + return "Prefix {} not found in BGP table of router: {}". \ + format(net, router) + + as_paths = show_bgp_json["paths"] + found = False + for i in range(len(as_paths)): + if "largeCommunity" in show_bgp_json["paths"][i] or \ + "community" in show_bgp_json["paths"][i]: + found = True + logger.info("Large Community attribute is found for route:" + " %s in router: %s", net, router) + if input_dict is not None: + for criteria, comm_val in input_dict.items(): + show_val = show_bgp_json["paths"][i][criteria][ + "string"] + if comm_val == show_val: + logger.info("Verifying BGP %s for prefix: %s" + " in router: %s, found expected" + " value: %s", criteria, net, router, + comm_val) + else: + errormsg = "Failed: Verifying BGP attribute" \ + " {} for route: {} in router: {}" \ + ", expected value: {} but found" \ + ": {}".format( + criteria, net, router, comm_val, + show_val) + return errormsg + + if not found: + errormsg = ( + "Large Community attribute is not found for route: " + "{} in router: {} ".format(net, router)) + return errormsg + + logger.debug("Exiting lib API: verify_bgp_community()") return True diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index 7a00fe4c50..fff5a1e82f 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -35,6 +35,7 @@ from lib.common_config import ( create_static_routes, create_prefix_lists, create_route_maps, + create_bgp_community_lists ) from lib.bgp import create_router_bgp @@ -179,6 +180,7 @@ def build_config_from_json(tgen, topo, save_bkup=True): ("links", create_interfaces_cfg), ("static_routes", create_static_routes), ("prefix_lists", create_prefix_lists), + ("bgp_community_list", create_bgp_community_lists), ("route_maps", create_route_maps), ("bgp", create_router_bgp) ]) diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 2dc3d3f8a3..f71b343140 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -30,6 +30,7 @@ #include "vrrp.h" #include "vrrp_debug.h" #include "vrrp_vty.h" +#include "vrrp_zebra.h" #ifndef VTYSH_EXTRACT_PL #include "vrrpd/vrrp_vty_clippy.c" #endif diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index 72b77c1313..a6c575f8da 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -80,83 +80,36 @@ static int vrrp_router_id_update_zebra(int command, struct zclient *zclient, return 0; } -static int vrrp_zebra_if_add(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +int vrrp_ifp_create(struct interface *ifp) { - struct interface *ifp; - - /* - * zebra api adds/dels interfaces using the same call - * interface_add_read below, see comments in lib/zclient.c - */ - ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - - vrrp_zebra_debug_if_state(ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); vrrp_if_add(ifp); return 0; } -static int vrrp_zebra_if_del(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +int vrrp_ifp_destroy(struct interface *ifp) { - struct interface *ifp; - - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - - vrrp_zebra_debug_if_state(ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); vrrp_if_del(ifp); - if_set_index(ifp, IFINDEX_INTERNAL); - return 0; } -static int vrrp_zebra_if_state_up(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +int vrrp_ifp_up(struct interface *ifp) { - struct interface *ifp; - - /* - * zebra api notifies interface up/down events by using the same call - * zebra_interface_state_read below, see comments in lib/zclient.c ifp = - * zebra_interface_state_read(zclient->ibuf, vrf_id); - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - - vrrp_zebra_debug_if_state(ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); vrrp_if_up(ifp); return 0; } -static int vrrp_zebra_if_state_down(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +int vrrp_ifp_down(struct interface *ifp) { - struct interface *ifp; - - /* - * zebra api notifies interface up/down events by using the same call - * zebra_interface_state_read below, see comments in lib/zclient.c - */ - ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - - if (!ifp) - return 0; - - vrrp_zebra_debug_if_state(ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); vrrp_if_down(ifp); @@ -238,15 +191,14 @@ int vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down) void vrrp_zebra_init(void) { + if_zapi_callbacks(vrrp_ifp_create, vrrp_ifp_up, + vrrp_ifp_down, vrrp_ifp_destroy); + /* Socket for receiving updates from Zebra daemon */ zclient = zclient_new(master, &zclient_options_default); zclient->zebra_connected = vrrp_zebra_connected; zclient->router_id_update = vrrp_router_id_update_zebra; - zclient->interface_add = vrrp_zebra_if_add; - zclient->interface_delete = vrrp_zebra_if_del; - zclient->interface_up = vrrp_zebra_if_state_up; - zclient->interface_down = vrrp_zebra_if_state_down; zclient->interface_address_add = vrrp_zebra_if_address_add; zclient->interface_address_delete = vrrp_zebra_if_address_del; diff --git a/vrrpd/vrrp_zebra.h b/vrrpd/vrrp_zebra.h index 84bcba23c1..02d7055b86 100644 --- a/vrrpd/vrrp_zebra.h +++ b/vrrpd/vrrp_zebra.h @@ -29,4 +29,9 @@ extern void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable); extern int vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down); +extern int vrrp_ifp_create(struct interface *ifp); +extern int vrrp_ifp_up(struct interface *ifp); +extern int vrrp_ifp_down(struct interface *ifp); +extern int vrrp_ifp_destroy(struct interface *ifp); + #endif /* __VRRP_ZEBRA_H__ */ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 59ab8c9d33..35cb3a6f5f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1385,6 +1385,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex); } + + zif = ifp->info; + if (zif) { + XFREE(MTYPE_TMP, zif->desc); + if (desc) + zif->desc = XSTRDUP(MTYPE_TMP, desc); + } } else { /* Delete interface notification from kernel */ if (ifp == NULL) { @@ -1411,13 +1418,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if_delete_update(ifp); } - zif = ifp->info; - if (zif) { - XFREE(MTYPE_TMP, zif->desc); - if (desc) - zif->desc = XSTRDUP(MTYPE_TMP, desc); - } - return 0; } diff --git a/zebra/interface.c b/zebra/interface.c index a724006e27..ef03cf87f6 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -778,6 +778,13 @@ void if_delete_update(struct interface *ifp) memset(&zif->brslave_info, 0, sizeof(struct zebra_l2info_brslave)); } + + if (!ifp->configured) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("interface %s is being deleted from the system", + ifp->name); + if_delete(ifp); + } } /* VRF change for an interface */ @@ -3207,6 +3214,11 @@ void zebra_if_init(void) install_node(&interface_node, if_config_write); install_node(&link_params_node, NULL); if_cmd_init(); + /* + * This is *intentionally* setting this to NULL, signaling + * that interface creation for zebra acts differently + */ + if_zapi_callbacks(NULL, NULL, NULL, NULL); install_element(VIEW_NODE, &show_interface_cmd); install_element(VIEW_NODE, &show_interface_vrf_all_cmd); diff --git a/zebra/irdp.h b/zebra/irdp.h index ff4ab8dfbd..c1ea34f3aa 100644 --- a/zebra/irdp.h +++ b/zebra/irdp.h @@ -51,7 +51,7 @@ extern "C" { #endif /* INADDR_ALLRTRS_GROUP */ /* Default irdp packet interval */ -#define IRDP_DEFAULT_INTERVAL 300 +#define IRDP_DEFAULT_INTERVAL 300 /* Router constants from RFC1256 */ #define MAX_INITIAL_ADVERT_INTERVAL 16 @@ -123,10 +123,10 @@ struct irdp_interface { #define IF_ACTIVE (1<<0) /* ICMP Active */ #define IF_BROADCAST (1<<1) /* 255.255.255.255 */ #define IF_SOLICIT (1<<2) /* Solicit active */ -#define IF_DEBUG_MESSAGES (1<<3) -#define IF_DEBUG_PACKET (1<<4) -#define IF_DEBUG_MISC (1<<5) -#define IF_SHUTDOWN (1<<6) +#define IF_DEBUG_MESSAGES (1<<3) +#define IF_DEBUG_PACKET (1<<4) +#define IF_DEBUG_MISC (1<<5) +#define IF_SHUTDOWN (1<<6) struct interface *ifp; struct thread *t_advertise; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 227226b5f9..0dc9de0c59 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -263,8 +263,11 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, } /* Add DISTANCE_INFINITY check. */ - if (old_re && (old_re->distance == DISTANCE_INFINITY)) + if (old_re && (old_re->distance == DISTANCE_INFINITY)) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("\tSkipping due to Infinite Distance"); return; + } afi = family2afi(p->family); if (!afi) { @@ -310,14 +313,14 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, /* Send a delete for the 'old' re to any subscribed client. */ if (old_re - && ((old_re->instance - && redist_check_instance( - &client->mi_redist[afi] - [old_re->type], - old_re->instance)) - || vrf_bitmap_check( - client->redist[afi][old_re->type], - old_re->vrf_id))) { + && (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], + old_re->vrf_id) + || (old_re->instance + && redist_check_instance( + &client->mi_redist[afi][old_re->type], + old_re->instance)) + || vrf_bitmap_check(client->redist[afi][old_re->type], + old_re->vrf_id))) { zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, client, p, src_p, old_re); } diff --git a/zebra/rtadv.c b/zebra/rtadv.c index b084fb99ca..2228fcfd3f 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -58,10 +58,10 @@ DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix") /* If RFC2133 definition is used. */ #ifndef IPV6_JOIN_GROUP -#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif #ifndef IPV6_LEAVE_GROUP -#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif #define ALLNODE "ff02::1" diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index fef54d5828..4a726b3e07 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1046,14 +1046,18 @@ static struct route_entry *rib_choose_best(struct route_entry *current, struct nexthop *nexthop = NULL; for (ALL_NEXTHOPS(alternate->ng, nexthop)) { - if (if_is_loopback_or_vrf(if_lookup_by_index( - nexthop->ifindex, alternate->vrf_id))) + struct interface *ifp = if_lookup_by_index( + nexthop->ifindex, alternate->vrf_id); + + if (ifp && if_is_loopback_or_vrf(ifp)) return alternate; } for (ALL_NEXTHOPS(current->ng, nexthop)) { - if (if_is_loopback_or_vrf(if_lookup_by_index( - nexthop->ifindex, current->vrf_id))) + struct interface *ifp = if_lookup_by_index( + nexthop->ifindex, current->vrf_id); + + if (ifp && if_is_loopback_or_vrf(ifp)) return current; } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 4f1868311c..f425c0e49e 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -487,7 +487,11 @@ static int vrf_config_write(struct vty *vty) if (zvrf_id(zvrf) == VRF_DEFAULT) { if (zvrf->l3vni) - vty_out(vty, "vni %u\n", zvrf->l3vni); + vty_out(vty, "vni %u%s\n", zvrf->l3vni, + is_l3vni_for_prefix_routes_only( + zvrf->l3vni) + ? " prefix-routes-only" + : ""); if (zvrf->zebra_rnh_ip_default_route) vty_out(vty, "ip nht resolve-via-default\n"); |
