diff options
335 files changed, 17182 insertions, 5373 deletions
@@ -27,14 +27,15 @@ FRR currently supports the following protocols: Installation & Use ------------------ -Packages are available for various distributions on our +For source tarballs, see the [releases page](https://github.com/FRRouting/frr/releases). -Snaps are also available [here](https://snapcraft.io/frr). +For Debian and its derivatives, use the APT repository at +[https://deb.frrouting.org/](https://deb.frrouting.org/). Instructions on building and installing from source for supported platforms may -be found -[here](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html). +be found in the +[developer docs](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html). Once installed, please refer to the [user guide](http://docs.frrouting.org/) for instructions on use. diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index e0b00f9782..60753c1227 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -13,13 +13,13 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod lddtree libacl libatomic libattr - libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc + libblkid libburn libbz2 libc-dev libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs libltdl libressl libssh2 libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python2 python2-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs - py-sphinx rtrlib rtrlib-dev" + py-pip py-sphinx rtrlib rtrlib-dev" checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" 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/bfd.c b/bfdd/bfd.c index 1f1568f511..245f2dc5ee 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -391,10 +391,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, /* Search for session without using discriminator. */ ifp = if_lookup_by_index(ifindex, vrfid); - if (vrfid != VRF_DEFAULT) - vrf = vrf_lookup_by_id(vrfid); - else - vrf = NULL; + + vrf = vrf_lookup_by_id(vrfid); gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL, vrf ? vrf->name : VRF_DEFAULT_NAME); @@ -1632,6 +1630,16 @@ static int bfd_vrf_delete(struct vrf *vrf) return 0; } +static int bfd_vrf_update(struct vrf *vrf) +{ + if (!vrf_is_enabled(vrf)) + return 0; + log_debug("VRF update: %s(%u)", vrf->name, vrf->vrf_id); + /* a different name is given; update bfd list */ + bfdd_sessions_enable_vrf(vrf); + return 0; +} + static int bfd_vrf_enable(struct vrf *vrf) { struct bfd_vrf_global *bvrf; @@ -1719,7 +1727,7 @@ static int bfd_vrf_disable(struct vrf *vrf) void bfd_vrf_init(void) { vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable, - bfd_vrf_delete, NULL); + bfd_vrf_delete, bfd_vrf_update); } void bfd_vrf_terminate(void) @@ -1743,3 +1751,54 @@ struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd) return NULL; return bfd->vrf->info; } + +void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf) +{ + if (!vrf || !bs) + return; + /* update key */ + hash_release(bfd_key_hash, bs); + /* + * HACK: Change the BFD VRF in the running configuration directly, + * bypassing the northbound layer. This is necessary to avoid deleting + * the BFD and readding it in the new VRF, which would have + * several implications. + */ + if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) { + struct lyd_node *bfd_dnode; + char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32]; + char addr_buf[INET6_ADDRSTRLEN]; + int slen; + + /* build xpath */ + if (bs->key.mhop) { + inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf)); + snprintf(xpath_srcaddr, sizeof(xpath_srcaddr), "[source-addr='%s']", + addr_buf); + } else + xpath_srcaddr[0] = 0; + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']", + bs->key.mhop ? "multi-hop" : "single-hop", xpath_srcaddr, + addr_buf); + if (bs->key.ifname[0]) + slen += snprintf(xpath + slen, sizeof(xpath) - slen, + "[interface='%s']", bs->key.ifname); + else + slen += snprintf(xpath + slen, sizeof(xpath) - slen, + "[interface='']"); + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf", + bs->key.vrfname); + + bfd_dnode = yang_dnode_get(running_config->dnode, xpath, + bs->key.vrfname); + if (bfd_dnode) { + yang_dnode_change_leaf(bfd_dnode, vrf->name); + running_config->version++; + } + } + memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname)); + strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname)); + hash_get(bfd_key_hash, bs, hash_alloc_intern); +} diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 10aeb3e52c..cdec78d122 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -630,6 +630,7 @@ void bfdd_zclient_unregister(vrf_id_t vrf_id); void bfdd_zclient_register(vrf_id_t vrf_id); void bfdd_sessions_enable_vrf(struct vrf *vrf); void bfdd_sessions_disable_vrf(struct vrf *vrf); +void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf); int ptm_bfd_notify(struct bfd_session *bs); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index a211f34219..c98ae5c7b3 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -498,7 +498,7 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, /* * Show commands. */ -DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]", +DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf NAME] peers [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -516,7 +516,7 @@ DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]", } DEFPY(bfd_show_peer, bfd_show_peer_cmd, - "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]", + "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -528,7 +528,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd, /* Look up the BFD peer. */ bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str, - ifname, vrfname); + ifname, vrf_name); if (bs == NULL) return CMD_WARNING_CONFIG_FAILED; @@ -543,7 +543,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd, } DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, - "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]", + "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -564,7 +564,7 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, /* Look up the BFD peer. */ bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str, - ifname, vrfname); + ifname, vrf_name); if (bs == NULL) return CMD_WARNING_CONFIG_FAILED; @@ -577,7 +577,7 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, } DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd, - "show bfd [vrf <NAME>] peers counters [json]", + "show bfd [vrf NAME] peers counters [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -685,6 +685,9 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, snprintf(ebuf, ebuflen, "vrf name too long"); return -1; } + } else { + bpc->bpc_has_vrfname = true; + strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname)); } return 0; diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 3e2ace6ea6..1b3219c235 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -376,6 +376,9 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, log_error("ptm-read: vrf id %u could not be identified", vrf_id); return -1; } + } else { + bpc->bpc_has_vrfname = true; + strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname)); } STREAM_GETC(msg, bpc->bpc_cbit); @@ -627,6 +630,11 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf) /* it may affect configs without interfaces */ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { bs = bso->bso_bs; + /* update name */ + if (bs->vrf && bs->vrf == vrf) { + if (!strmatch(bs->key.vrfname, vrf->name)) + bfd_session_update_vrf_name(bs, vrf); + } if (bs->vrf) continue; if (bs->key.vrfname[0] && @@ -665,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; } @@ -748,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); @@ -764,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_aspath.c b/bgpd/bgp_aspath.c index f5652b07c5..6caeb7ca1f 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -2114,15 +2114,12 @@ static void *bgp_aggr_aspath_hash_alloc(void *p) static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) { - struct aspath *asmerge = NULL; struct aspath *hb_aspath = hb->data; struct aspath **aggr_aspath = arg; - if (*aggr_aspath) { - asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); - aspath_free(*aggr_aspath); - *aggr_aspath = asmerge; - } else + if (*aggr_aspath) + *aggr_aspath = aspath_aggregate(*aggr_aspath, hb_aspath); + else *aggr_aspath = aspath_dup(hb_aspath); } @@ -2136,6 +2133,15 @@ void bgp_aggr_aspath_remove(void *arg) void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, struct aspath *aspath) { + bgp_compute_aggregate_aspath_hash(aggregate, aspath); + + bgp_compute_aggregate_aspath_val(aggregate); + +} + +void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ struct aspath *aggr_aspath = NULL; if ((aggregate == NULL) || (aspath == NULL)) @@ -2154,17 +2160,29 @@ void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, */ aggr_aspath = hash_get(aggregate->aspath_hash, aspath, bgp_aggr_aspath_hash_alloc); + } - /* Compute aggregate's as-path. - */ + /* Increment reference counter. + */ + aggr_aspath->refcnt++; +} + +void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate) +{ + if (aggregate == NULL) + return; + /* Re-compute aggregate's as-path. + */ + if (aggregate->aspath) { + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + } + if (aggregate->aspath_hash + && aggregate->aspath_hash->count) { hash_iterate(aggregate->aspath_hash, bgp_aggr_aspath_prepare, &aggregate->aspath); } - - /* Increment refernce counter. - */ - aggr_aspath->refcnt++; } void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, @@ -2173,10 +2191,9 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, struct aspath *aggr_aspath = NULL; struct aspath *ret_aspath = NULL; - if ((aggregate == NULL) || (aspath == NULL)) - return; - - if (aggregate->aspath_hash == NULL) + if ((!aggregate) + || (!aggregate->aspath_hash) + || (!aspath)) return; /* Look-up the aspath in the hash. @@ -2189,17 +2206,41 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, ret_aspath = hash_release(aggregate->aspath_hash, aggr_aspath); aspath_free(ret_aspath); + ret_aspath = NULL; /* Remove aggregate's old as-path. */ aspath_free(aggregate->aspath); aggregate->aspath = NULL; - /* Compute aggregate's as-path. - */ - hash_iterate(aggregate->aspath_hash, - bgp_aggr_aspath_prepare, - &aggregate->aspath); + bgp_compute_aggregate_aspath_val(aggregate); } } } + +void bgp_remove_aspath_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + struct aspath *ret_aspath = NULL; + + if ((!aggregate) + || (!aggregate->aspath_hash) + || (!aspath)) + return; + + /* Look-up the aspath in the hash. + */ + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath) { + aggr_aspath->refcnt--; + + if (aggr_aspath->refcnt == 0) { + ret_aspath = hash_release(aggregate->aspath_hash, + aggr_aspath); + aspath_free(ret_aspath); + ret_aspath = NULL; + } + } +} + diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index f84b3740c9..10f6ee2821 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -134,8 +134,16 @@ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *); extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, struct aspath *aspath); + +extern void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate); extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, struct aspath *aspath); +extern void bgp_remove_aspath_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct aspath *aspath); + extern void bgp_aggr_aspath_remove(void *arg); #endif /* _QUAGGA_BGP_ASPATH_H */ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e21c84355e..10e78cbc96 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -519,8 +519,8 @@ unsigned int attrhash_key_make(const void *p) MIX(attr->mp_nexthop_len); key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); - MIX(attr->nh_ifindex); - MIX(attr->nh_lla_ifindex); + MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance); + MIX(attr->rmap_table_id); return key; } @@ -547,6 +547,7 @@ bool attrhash_cmp(const void *p1, const void *p2) && attr1->lcommunity == attr2->lcommunity && attr1->cluster == attr2->cluster && attr1->transit == attr2->transit + && attr1->rmap_table_id == attr2->rmap_table_id && (attr1->encap_tunneltype == attr2->encap_tunneltype) && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs) #if ENABLE_BGP_VNC @@ -562,7 +563,8 @@ bool attrhash_cmp(const void *p1, const void *p2) &attr2->originator_id) && overlay_index_same(attr1, attr2) && attr1->nh_ifindex == attr2->nh_ifindex - && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex) + && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex + && attr1->distance == attr2->distance) return true; } @@ -724,10 +726,13 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, struct community *community, struct ecommunity *ecommunity, struct lcommunity *lcommunity, - int as_set, uint8_t atomic_aggregate) + struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, + struct prefix *p) { struct attr attr; struct attr *new; + int ret; memset(&attr, 0, sizeof(struct attr)); @@ -778,7 +783,7 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, attr.label = MPLS_INVALID_LABEL; attr.weight = BGP_ATTR_DEFAULT_WEIGHT; attr.mp_nexthop_len = IPV6_MAX_BYTELEN; - if (!as_set || atomic_aggregate) + if (!aggregate->as_set || atomic_aggregate) attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) @@ -789,7 +794,42 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, attr.label_index = BGP_INVALID_LABEL_INDEX; attr.label = MPLS_INVALID_LABEL; - new = bgp_attr_intern(&attr); + /* Apply route-map */ + if (aggregate->rmap.name) { + struct attr attr_tmp = attr; + struct bgp_path_info rmap_path; + + memset(&rmap_path, 0, sizeof(struct bgp_path_info)); + rmap_path.peer = bgp->peer_self; + rmap_path.attr = &attr_tmp; + + SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE); + + ret = route_map_apply(aggregate->rmap.map, p, RMAP_BGP, + &rmap_path); + + bgp->peer_self->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) { + /* Free uninterned attribute. */ + bgp_attr_flush(&attr_tmp); + + /* Unintern original. */ + aspath_unintern(&attr.aspath); + return NULL; + } + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr_tmp); + + new = bgp_attr_intern(&attr_tmp); + } else { + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr); + + new = bgp_attr_intern(&attr); + } aspath_unintern(&new->aspath); return new; @@ -1267,14 +1307,20 @@ bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr) if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) || IPV4_CLASS_DE(nexthop_h)) && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { + uint8_t data[7]; /* type(2) + length(1) + nhop(4) */ char buf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, INET_ADDRSTRLEN); flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); + data[0] = BGP_ATTR_FLAG_TRANS; + data[1] = BGP_ATTR_NEXT_HOP; + data[2] = BGP_ATTR_NHLEN_IPV4; + memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4); + bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, + data, 7); return BGP_ATTR_PARSE_ERROR; } @@ -1647,8 +1693,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, #define BGP_MP_REACH_MIN_SIZE 5 #define LEN_LEFT (length - (stream_get_getp(s) - start)) if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) { - zlog_info("%s: %s sent invalid length, %lu", __func__, - peer->host, (unsigned long)length); + zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI", + __func__, peer->host, (unsigned long)length); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1664,7 +1710,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, */ if (bgp_debug_update(peer, NULL, NULL, 0)) zlog_debug( - "%s: MP_REACH received AFI %s or SAFI %s is unrecognized", + "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI", peer->host, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); return BGP_ATTR_PARSE_ERROR; @@ -1675,7 +1721,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, if (LEN_LEFT < attr->mp_nexthop_len) { zlog_info( - "%s: %s, MP nexthop length, %u, goes past end of attribute", + "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1684,7 +1730,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, switch (attr->mp_nexthop_len) { case 0: if (safi != SAFI_FLOWSPEC) { - zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", + zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1716,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1733,7 +1779,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1751,7 +1797,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, if (bgp_debug_update(peer, NULL, NULL, 1)) zlog_debug( - "%s rcvd nexthops %s, %s -- ignoring non-LL value", + "%s sent next-hops %s and %s. Ignoring non-LL value", peer->host, inet_ntop(AF_INET6, &attr->mp_nexthop_global, @@ -1763,21 +1809,21 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } if (!peer->nexthop.ifp) { - zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex; break; default: - zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", + zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!LEN_LEFT) { - zlog_info("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, - peer->host); + zlog_info("%s: %s sent SNPA which couldn't be read", + __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1793,12 +1839,13 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, /* must have nrli_len, what is left of the attribute */ nlri_len = LEN_LEFT; if (nlri_len > STREAM_READABLE(s)) { - zlog_info("%s: (%s) Failed to read NLRI", __func__, peer->host); + zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read", + __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!nlri_len) { - zlog_info("%s: (%s) No Reachability, Treating as a EOR marker", + zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker", __func__, peer->host); mp_update->afi = afi; @@ -2005,8 +2052,8 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ length -= 4; if (tlv_length != length) { - zlog_info("%s: tlv_length(%d) != length(%d)", __func__, - tlv_length, length); + zlog_info("%s: tlv_length(%d) != length(%d)", + __func__, tlv_length, length); } } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1592a8df4e..eacd37b652 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -206,6 +206,12 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; + + /* Distance as applied by Route map */ + uint8_t distance; + + /* rmap set table */ + uint32_t rmap_table_id; }; /* rmap_change_flags definition */ @@ -272,8 +278,9 @@ extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, struct community *community, struct ecommunity *ecommunity, struct lcommunity *lcommunity, - int as_set, - uint8_t atomic_aggregate); + struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, + struct prefix *p); extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct bpacket_attr_vec_arr *vecarr, diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 8fca202345..ff655048a8 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -663,6 +663,11 @@ static int bmp_peer_established(struct peer *peer) if (!bmpbgp) return 0; + /* Check if this peer just went to Established */ + if ((peer->last_major_event != OpenConfirm) || + !(peer_established(peer))) + return 0; + if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { struct bmp_bgp_peer *bbpeer, *bbdopp; @@ -1627,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); @@ -1762,7 +1767,7 @@ static struct cmd_node bmp_node = {BMP_NODE, "%s(config-bgp-bmp)# "}; #define BMP_STR "BGP Monitoring Protocol\n" #ifndef VTYSH_EXTRACT_PL -#include "bgp_bmp_clippy.c" +#include "bgpd/bgp_bmp_clippy.c" #endif DEFPY_NOSH(bmp_targets_main, @@ -2226,7 +2231,7 @@ static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); hook_register(bgp_packet_send, bmp_outgoing_packet); - hook_register(peer_established, bmp_peer_established); + hook_register(peer_status_changed, bmp_peer_established); hook_register(peer_backward_transition, bmp_peer_backward); hook_register(bgp_process, bmp_process); hook_register(bgp_inst_config_write, bmp_config_write); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 22d61f702d..432c922ea5 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -910,15 +910,13 @@ static void *bgp_aggr_communty_hash_alloc(void *p) static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) { - struct community *commerge = NULL; struct community *hb_community = hb->data; struct community **aggr_community = arg; - if (*aggr_community) { - commerge = community_merge(*aggr_community, hb_community); - *aggr_community = community_uniq_sort(commerge); - community_free(&commerge); - } else + if (*aggr_community) + *aggr_community = community_merge(*aggr_community, + hb_community); + else *aggr_community = community_dup(hb_community); } @@ -932,6 +930,14 @@ void bgp_aggr_community_remove(void *arg) void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, struct community *community) { + bgp_compute_aggregate_community_hash(aggregate, community); + bgp_compute_aggregate_community_val(aggregate); +} + + +void bgp_compute_aggregate_community_hash(struct bgp_aggregate *aggregate, + struct community *community) +{ struct community *aggr_community = NULL; if ((aggregate == NULL) || (community == NULL)) @@ -951,32 +957,47 @@ void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, */ aggr_community = hash_get(aggregate->community_hash, community, bgp_aggr_communty_hash_alloc); + } - /* Re-compute aggregate's community. - */ - if (aggregate->community) - community_free(&aggregate->community); + /* Increment reference counter. + */ + aggr_community->refcnt++; +} +void bgp_compute_aggregate_community_val(struct bgp_aggregate *aggregate) +{ + struct community *commerge = NULL; + + if (aggregate == NULL) + return; + + /* Re-compute aggregate's community. + */ + if (aggregate->community) + community_free(&aggregate->community); + if (aggregate->community_hash && + aggregate->community_hash->count) { hash_iterate(aggregate->community_hash, bgp_aggr_community_prepare, &aggregate->community); + commerge = aggregate->community; + aggregate->community = community_uniq_sort(commerge); + if (commerge) + community_free(&commerge); } - - /* Increment refernce counter. - */ - aggr_community->refcnt++; } + + void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, struct community *community) { struct community *aggr_community = NULL; struct community *ret_comm = NULL; - if ((aggregate == NULL) || (community == NULL)) - return; - - if (aggregate->community_hash == NULL) + if ((!aggregate) + || (!aggregate->community_hash) + || (!community)) return; /* Look-up the community in the hash. @@ -990,13 +1011,33 @@ void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, aggr_community); community_free(&ret_comm); - community_free(&aggregate->community); + bgp_compute_aggregate_community_val(aggregate); + } + } +} + +void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct community *community) +{ + + struct community *aggr_community = NULL; + struct community *ret_comm = NULL; - /* Compute aggregate's community. - */ - hash_iterate(aggregate->community_hash, - bgp_aggr_community_prepare, - &aggregate->community); + if ((!aggregate) + || (!aggregate->community_hash) + || (!community)) + return; + + /* Look-up the community in the hash. + */ + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community) { + aggr_community->refcnt--; + + if (aggr_community->refcnt == 0) { + ret_comm = hash_release(aggregate->community_hash, + aggr_community); + community_free(&ret_comm); } } } diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index f761a8f5e0..74a3a6b507 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -92,8 +92,16 @@ extern struct hash *community_hash(void); extern uint32_t community_val_get(struct community *com, int i); extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, struct community *community); + +extern void bgp_compute_aggregate_community_val( + struct bgp_aggregate *aggregate); +extern void bgp_compute_aggregate_community_hash( + struct bgp_aggregate *aggregate, + struct community *community); extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, struct community *community); +extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct community *community); extern void bgp_aggr_community_remove(void *arg); #endif /* _QUAGGA_BGP_COMMUNITY_H */ diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 535f36ab5e..640224e759 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -494,13 +494,13 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer, } /* Dump BGP status change. */ -void bgp_dump_state(struct peer *peer, int status_old, int status_new) +int bgp_dump_state(struct peer *peer) { struct stream *obuf; /* If dump file pointer is disabled return immediately. */ if (bgp_dump_all.fp == NULL) - return; + return 0; /* Make dump stream. */ obuf = bgp_dump_obuf; @@ -510,8 +510,8 @@ void bgp_dump_state(struct peer *peer, int status_old, int status_new) bgp_dump_all.type); bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/ - stream_putw(obuf, status_old); - stream_putw(obuf, status_new); + stream_putw(obuf, peer->ostatus); + stream_putw(obuf, peer->status); /* Set length. */ bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP); @@ -519,6 +519,7 @@ void bgp_dump_state(struct peer *peer, int status_old, int status_new) /* Write to the stream. */ fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp); fflush(bgp_dump_all.fp); + return 0; } static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer, @@ -867,6 +868,7 @@ void bgp_dump_init(void) install_element(CONFIG_NODE, &no_dump_bgp_all_cmd); hook_register(bgp_packet_dump, bgp_dump_packet); + hook_register(peer_status_changed, bgp_dump_state); } void bgp_dump_finish(void) @@ -878,4 +880,5 @@ void bgp_dump_finish(void) stream_free(bgp_dump_obuf); bgp_dump_obuf = NULL; hook_unregister(bgp_packet_dump, bgp_dump_packet); + hook_unregister(peer_status_changed, bgp_dump_state); } diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h index 5ec0561b05..86c80d481c 100644 --- a/bgpd/bgp_dump.h +++ b/bgpd/bgp_dump.h @@ -51,6 +51,6 @@ extern void bgp_dump_init(void); extern void bgp_dump_finish(void); -extern void bgp_dump_state(struct peer *, int, int); +extern int bgp_dump_state(struct peer *); #endif /* _QUAGGA_BGP_DUMP_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 850b85aa6a..11f5a326df 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1042,15 +1042,13 @@ static void *bgp_aggr_ecommunty_hash_alloc(void *p) static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) { - struct ecommunity *ecommerge = NULL; struct ecommunity *hb_ecommunity = hb->data; struct ecommunity **aggr_ecommunity = arg; - if (*aggr_ecommunity) { - ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); - *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else + if (*aggr_ecommunity) + *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity, + hb_ecommunity); + else *aggr_ecommunity = ecommunity_dup(hb_ecommunity); } @@ -1064,6 +1062,14 @@ void bgp_aggr_ecommunity_remove(void *arg) void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, struct ecommunity *ecommunity) { + bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity); + bgp_compute_aggregate_ecommunity_val(aggregate); +} + + +void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ struct ecommunity *aggr_ecommunity = NULL; if ((aggregate == NULL) || (ecommunity == NULL)) @@ -1083,20 +1089,34 @@ void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, aggr_ecommunity = hash_get(aggregate->ecommunity_hash, ecommunity, bgp_aggr_ecommunty_hash_alloc); + } - /* Re-compute aggregate's ecommunity. - */ - if (aggregate->ecommunity) - ecommunity_free(&aggregate->ecommunity); + /* Increment reference counter. + */ + aggr_ecommunity->refcnt++; +} +void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate) +{ + struct ecommunity *ecommerge = NULL; + + if (aggregate == NULL) + return; + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + if (aggregate->ecommunity_hash + && aggregate->ecommunity_hash->count) { hash_iterate(aggregate->ecommunity_hash, bgp_aggr_ecommunity_prepare, &aggregate->ecommunity); + ecommerge = aggregate->ecommunity; + aggregate->ecommunity = ecommunity_uniq_sort(ecommerge); + if (ecommerge) + ecommunity_free(&ecommerge); } - - /* Increment refernce counter. - */ - aggr_ecommunity->refcnt++; } void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -1105,10 +1125,9 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, struct ecommunity *aggr_ecommunity = NULL; struct ecommunity *ret_ecomm = NULL; - if ((aggregate == NULL) || (ecommunity == NULL)) - return; - - if (aggregate->ecommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) return; /* Look-up the ecommunity in the hash. @@ -1121,14 +1140,33 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, ret_ecomm = hash_release(aggregate->ecommunity_hash, aggr_ecommunity); ecommunity_free(&ret_ecomm); + bgp_compute_aggregate_ecommunity_val(aggregate); + } + } +} + +void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; - ecommunity_free(&aggregate->ecommunity); + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) + return; - /* Compute aggregate's ecommunity. - */ - hash_iterate(aggregate->ecommunity_hash, - bgp_aggr_ecommunity_prepare, - &aggregate->ecommunity); + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); } } } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 79be4ee422..249e5bf7de 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -190,9 +190,18 @@ extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, extern void bgp_compute_aggregate_ecommunity( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); + +extern void bgp_compute_aggregate_ecommunity_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_compute_aggregate_ecommunity_val( + struct bgp_aggregate *aggregate); extern void bgp_remove_ecommunity_from_aggregate( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); +extern void bgp_remove_ecomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); extern void bgp_aggr_ecommunity_remove(void *arg); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 4d02e39ae2..50fef00a96 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -505,7 +505,9 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl) { struct ecommunity_val eval; - struct ecommunity *ecomadd; + struct ecommunity *ecomadd, *ecom; + bool ecom_found = false; + struct listnode *node; if (bgp->advertise_autort_rfc8365) vni |= EVPN_AUTORT_VXLAN; @@ -513,7 +515,12 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl) ecomadd = ecommunity_new(); ecommunity_add_val(ecomadd, &eval); - listnode_add_sort(rtl, ecomadd); + for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom)) + if (ecommunity_cmp(ecomadd, ecom)) + ecom_found = true; + + if (!ecom_found) + listnode_add_sort(rtl, ecomadd); } /* @@ -5661,6 +5668,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn)) bgpevpn_unlink_from_l3vni(vpn); + UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY); + /* Delete the instance if it was autocreated */ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO)) bgp_delete(bgp_vrf); @@ -5803,6 +5812,9 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, It needs to be conveyed again to zebra */ bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, vpn->vni); + /* advertise svi mac-ip knob to zebra */ + bgp_zebra_advertise_svi_macip(bgp, vpn->advertise_svi_macip, vpn->vni); + return 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_fsm.c b/bgpd/bgp_fsm.c index cc7f81d9ff..0be8becbab 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -57,7 +57,7 @@ #include "bgpd/bgp_zebra.h" DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)) -DEFINE_HOOK(peer_established, (struct peer * peer), (peer)) +DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)) /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h @@ -962,8 +962,6 @@ void bgp_fsm_change_status(struct peer *peer, int status) struct bgp *bgp; uint32_t peer_count; - bgp_dump_state(peer, peer->status, status); - bgp = peer->bgp; peer_count = bgp->established_peers; @@ -1025,6 +1023,9 @@ void bgp_fsm_change_status(struct peer *peer, int status) /* Save event that caused status change. */ peer->last_major_event = peer->cur_event; + /* Operations after status change */ + hook_call(peer_status_changed, peer); + if (status == Established) UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); @@ -1323,7 +1324,7 @@ static int bgp_connect_check(struct thread *thread) /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { - zlog_info("can't get sockopt for nonblocking connect: %d(%s)", + zlog_err("can't get sockopt for nonblocking connect: %d(%s)", errno, safe_strerror(errno)); BGP_EVENT_ADD(peer, TCP_fatal_error); return -1; @@ -1657,8 +1658,6 @@ static int bgp_establish(struct peer *peer) peer->host); } - hook_call(peer_established, peer); - /* Reset uptime, turn on keepalives, send current table. */ if (!peer->v_holdtime) bgp_keepalives_on(peer); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 3476a3c3a9..9d0500ae2c 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -88,6 +88,5 @@ extern void bgp_adjust_routeadv(struct peer *); #include "hook.h" DECLARE_HOOK(peer_backward_transition, (struct peer * peer), (peer)) -DECLARE_HOOK(peer_established, (struct peer * peer), (peer)) #endif /* _QUAGGA_BGP_FSM_H */ diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 6de1c216a6..3a49e8bc00 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -97,11 +97,18 @@ static void peer_process(struct hash_bucket *hb, void *arg) static struct timeval tolerance = {0, 100000}; + uint32_t v_ka = atomic_load_explicit(&pkat->peer->v_keepalive, + memory_order_relaxed); + + /* 0 keepalive timer means no keepalives */ + if (v_ka == 0) + return; + /* calculate elapsed time since last keepalive */ monotime_since(&pkat->last, &elapsed); /* calculate difference between elapsed time and configured time */ - ka.tv_sec = pkat->peer->v_keepalive; + ka.tv_sec = v_ka; timersub(&ka, &elapsed, &diff); int send_keepalive = diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index aeb290719a..3243ce96b5 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -555,15 +555,13 @@ static void *bgp_aggr_lcommunty_hash_alloc(void *p) static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) { - struct lcommunity *lcommerge = NULL; struct lcommunity *hb_lcommunity = hb->data; struct lcommunity **aggr_lcommunity = arg; - if (*aggr_lcommunity) { - lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); - *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else + if (*aggr_lcommunity) + *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity, + hb_lcommunity); + else *aggr_lcommunity = lcommunity_dup(hb_lcommunity); } @@ -577,6 +575,15 @@ void bgp_aggr_lcommunity_remove(void *arg) void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, struct lcommunity *lcommunity) { + + bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); +} + +void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; if ((aggregate == NULL) || (lcommunity == NULL)) @@ -596,20 +603,34 @@ void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, aggr_lcommunity = hash_get(aggregate->lcommunity_hash, lcommunity, bgp_aggr_lcommunty_hash_alloc); + } - /* Re-compute aggregate's lcommunity. - */ - if (aggregate->lcommunity) - lcommunity_free(&aggregate->lcommunity); + /* Increment reference counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate) +{ + struct lcommunity *lcommerge = NULL; + + if (aggregate == NULL) + return; + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + if (aggregate->lcommunity_hash && + aggregate->lcommunity_hash->count) { hash_iterate(aggregate->lcommunity_hash, bgp_aggr_lcommunity_prepare, &aggregate->lcommunity); + lcommerge = aggregate->lcommunity; + aggregate->lcommunity = lcommunity_uniq_sort(lcommerge); + if (lcommerge) + lcommunity_free(&lcommerge); } - - /* Increment refernce counter. - */ - aggr_lcommunity->refcnt++; } void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -618,10 +639,9 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, struct lcommunity *aggr_lcommunity = NULL; struct lcommunity *ret_lcomm = NULL; - if ((aggregate == NULL) || (lcommunity == NULL)) - return; - - if (aggregate->lcommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) return; /* Look-up the lcommunity in the hash. @@ -635,13 +655,33 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, aggr_lcommunity); lcommunity_free(&ret_lcomm); - lcommunity_free(&aggregate->lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); + + } + } +} + +void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; - /* Compute aggregate's lcommunity. - */ - hash_iterate(aggregate->lcommunity_hash, - bgp_aggr_lcommunity_prepare, - &aggregate->lcommunity); + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); } } } diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index a512395492..7d63f4d26a 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -75,9 +75,19 @@ extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); extern void bgp_compute_aggregate_lcommunity( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); + +extern void bgp_compute_aggregate_lcommunity_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_compute_aggregate_lcommunity_val( + struct bgp_aggregate *aggregate); + extern void bgp_remove_lcommunity_from_aggregate( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); +extern void bgp_remove_lcomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); extern void bgp_aggr_lcommunity_remove(void *arg); #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index abd8586f4c..ef73b47ffb 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -269,12 +269,20 @@ static int bgp_vrf_enable(struct vrf *vrf) zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); bgp = bgp_lookup_by_name(vrf->name); - if (bgp) { + if (bgp && bgp->vrf_id != vrf->vrf_id) { if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { XFREE(MTYPE_BGP, bgp->name); bgp->name = NULL; XFREE(MTYPE_BGP, bgp->name_pretty); bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); + bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT; +#if ENABLE_BGP_VNC + if (!bgp->rfapi) { + bgp->rfapi = bgp_rfapi_new(bgp); + assert(bgp->rfapi); + assert(bgp->rfapi_cfg); + } +#endif /* ENABLE_BGP_VNC */ } old_vrf_id = bgp->vrf_id; /* We have instance configured, link to VRF and make it "up". */ @@ -343,7 +351,7 @@ static int bgp_vrf_disable(struct vrf *vrf) static void bgp_vrf_init(void) { vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, - bgp_vrf_delete, NULL); + bgp_vrf_delete, bgp_vrf_enable); } static void bgp_vrf_terminate(void) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 1156810510..1d15361416 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -109,7 +109,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, uint16_t type; struct rd_as rd_as; struct rd_ip rd_ip; - struct prefix_rd prd; + struct prefix_rd prd = {0}; mpls_label_t label = {0}; afi_t afi; safi_t safi; @@ -781,12 +781,12 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr; static_attr.mp_nexthop_global_in = nexthop->u.prefix4; - static_attr.mp_nexthop_len = 4; + static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; break; case AF_INET6: static_attr.mp_nexthop_global = nexthop->u.prefix6; - static_attr.mp_nexthop_len = 16; + static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; break; default: @@ -802,7 +802,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ */ static_attr.mp_nexthop_global_in = static_attr.nexthop; - static_attr.mp_nexthop_len = 4; + static_attr.mp_nexthop_len = + BGP_ATTR_NHLEN_IPV4; /* * XXX Leave static_attr.nexthop * intact for NHT @@ -821,7 +822,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ && !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) { static_attr.mp_nexthop_global_in.s_addr = static_attr.nexthop.s_addr; - static_attr.mp_nexthop_len = 4; + static_attr.mp_nexthop_len = + BGP_ATTR_NHLEN_IPV4; static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 7e5e07099d..f17bc7b8c0 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1031,7 +1031,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length) as_t as4 = 0; if (BGP_DEBUG(as4, AS4)) - zlog_info( + zlog_debug( "%s [AS4] rcv OPEN w/ OPTION parameter len: %u," " peeking for as4", peer->host, length); @@ -1075,7 +1075,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length) if (hdr.code == CAPABILITY_CODE_AS4) { if (BGP_DEBUG(as4, AS4)) - zlog_info( + zlog_debug( "[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4(peer, &hdr); diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 8359f59a41..5250a68581 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -68,13 +68,13 @@ struct graceful_restart_af { /* Cooperative Route Filtering Capability. */ /* ORF Type */ -#define ORF_TYPE_PREFIX 64 +#define ORF_TYPE_PREFIX 64 #define ORF_TYPE_PREFIX_OLD 128 /* ORF Mode */ -#define ORF_MODE_RECEIVE 1 -#define ORF_MODE_SEND 2 -#define ORF_MODE_BOTH 3 +#define ORF_MODE_RECEIVE 1 +#define ORF_MODE_SEND 2 +#define ORF_MODE_BOTH 3 /* Capability Message Action. */ #define CAPABILITY_ACTION_SET 0 diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index fc6fc66a4c..49e401790f 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -39,14 +39,14 @@ DECLARE_HOOK(bgp_packet_send, /* When to refresh */ #define REFRESH_IMMEDIATE 1 -#define REFRESH_DEFER 2 +#define REFRESH_DEFER 2 /* ORF Common part flag */ -#define ORF_COMMON_PART_ADD 0x00 -#define ORF_COMMON_PART_REMOVE 0x80 -#define ORF_COMMON_PART_REMOVE_ALL 0xC0 -#define ORF_COMMON_PART_PERMIT 0x00 -#define ORF_COMMON_PART_DENY 0x20 +#define ORF_COMMON_PART_ADD 0x00 +#define ORF_COMMON_PART_REMOVE 0x80 +#define ORF_COMMON_PART_REMOVE_ALL 0xC0 +#define ORF_COMMON_PART_PERMIT 0x00 +#define ORF_COMMON_PART_DENY 0x20 /* Packet send and receive function prototypes. */ extern void bgp_keepalive_send(struct peer *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 32c9fb16f3..fa64d3dd62 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1785,9 +1785,9 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, /* Route map & unsuppress-map apply. */ if (ROUTE_MAP_OUT_NAME(filter) || (pi->extra && pi->extra->suppress)) { - struct bgp_path_info rmap_path; - struct bgp_path_info_extra dummy_rmap_path_extra; - struct attr dummy_attr; + struct bgp_path_info rmap_path = {0}; + struct bgp_path_info_extra dummy_rmap_path_extra = {0}; + struct attr dummy_attr = {0}; memset(&rmap_path, 0, sizeof(struct bgp_path_info)); rmap_path.peer = peer; @@ -2748,8 +2748,8 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, return 0; zlog_info( - "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, " - "limit %ld", + "%%MAXPFXEXCEED: No. of %s prefix received from %s %" PRIu32 + " exceed, limit %" PRIu32, get_afi_safi_str(afi, safi, false), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); @@ -2810,7 +2810,8 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, return 0; zlog_info( - "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld", + "%%MAXPFX: No. of %s prefix received from %s reaches %" PRIu32 + ", max %" PRIu32, get_afi_safi_str(afi, safi, false), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG(peer->af_sflags[afi][safi], @@ -3164,6 +3165,13 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } + if (pi && pi->attr && + pi->attr->rmap_table_id != new_attr.rmap_table_id) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + /* remove from RIB previous entry */ + bgp_zebra_withdraw(p, pi, bgp, safi); + } + if (peer->sort == BGP_PEER_EBGP) { /* If we receive the graceful-shutdown community from an eBGP @@ -5704,6 +5712,8 @@ static struct bgp_aggregate *bgp_aggregate_new(void) static void bgp_aggregate_free(struct bgp_aggregate *aggregate) { + XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); + route_map_counter_decrement(aggregate->rmap.map); XFREE(MTYPE_BGP_AGGREGATE, aggregate); } @@ -5754,6 +5764,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_node *rn; struct bgp_table *table; struct bgp_path_info *pi, *orig, *new; + struct attr *attr; table = bgp->rib[afi][safi]; @@ -5791,14 +5802,18 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, if (pi) bgp_path_info_delete(rn, pi); + attr = bgp_attr_aggregate_intern( + bgp, origin, aspath, community, ecommunity, lcommunity, + aggregate, atomic_aggregate, p); + + if (!attr) { + bgp_aggregate_delete(bgp, p, afi, safi, aggregate); + return; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0, - bgp->peer_self, - bgp_attr_aggregate_intern(bgp, origin, aspath, - community, ecommunity, - lcommunity, - aggregate->as_set, - atomic_aggregate), - rn); + bgp->peer_self, attr, rn); + SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_add(rn, new); @@ -5821,7 +5836,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, } /* Update an aggregate as routes are added/removed from the BGP table */ -static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, +void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { @@ -5920,33 +5935,41 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, */ /* Compute aggregate route's as-path. */ - bgp_compute_aggregate_aspath(aggregate, - pi->attr->aspath); + bgp_compute_aggregate_aspath_hash(aggregate, + pi->attr->aspath); /* Compute aggregate route's community. */ if (pi->attr->community) - bgp_compute_aggregate_community( + bgp_compute_aggregate_community_hash( aggregate, pi->attr->community); /* Compute aggregate route's extended community. */ if (pi->attr->ecommunity) - bgp_compute_aggregate_ecommunity( + bgp_compute_aggregate_ecommunity_hash( aggregate, pi->attr->ecommunity); /* Compute aggregate route's large community. */ if (pi->attr->lcommunity) - bgp_compute_aggregate_lcommunity( + bgp_compute_aggregate_lcommunity_hash( aggregate, pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) { + bgp_compute_aggregate_aspath_val(aggregate); + bgp_compute_aggregate_community_val(aggregate); + bgp_compute_aggregate_ecommunity_val(aggregate); + bgp_compute_aggregate_lcommunity_val(aggregate); + } + + bgp_unlock_node(top); @@ -5982,7 +6005,7 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, aggregate); } -static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, +void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; @@ -6027,28 +6050,28 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (aggregate->as_set) { /* Remove as-path from aggregate. */ - bgp_remove_aspath_from_aggregate( + bgp_remove_aspath_from_aggregate_hash( aggregate, pi->attr->aspath); if (pi->attr->community) /* Remove community from aggregate. */ - bgp_remove_community_from_aggregate( + bgp_remove_comm_from_aggregate_hash( aggregate, pi->attr->community); if (pi->attr->ecommunity) /* Remove ecommunity from aggregate. */ - bgp_remove_ecommunity_from_aggregate( + bgp_remove_ecomm_from_aggregate_hash( aggregate, pi->attr->ecommunity); if (pi->attr->lcommunity) /* Remove lcommunity from aggregate. */ - bgp_remove_lcommunity_from_aggregate( + bgp_remove_lcomm_from_aggregate_hash( aggregate, pi->attr->lcommunity); } @@ -6059,6 +6082,17 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) { + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + if (aggregate->community) + community_free(&aggregate->community); + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + } + bgp_unlock_node(top); } @@ -6426,7 +6460,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, } static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, - safi_t safi, uint8_t summary_only, uint8_t as_set) + safi_t safi, const char *rmap, uint8_t summary_only, + uint8_t as_set) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -6451,8 +6486,9 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, /* Old configuration check. */ rn = bgp_node_get(bgp->aggregate[afi][safi], &p); + aggregate = bgp_node_get_bgp_aggregate_info(rn); - if (bgp_node_has_bgp_path_info_data(rn)) { + if (aggregate) { vty_out(vty, "There is already same aggregate network.\n"); /* try to remove the old entry */ ret = bgp_aggregate_unset(vty, prefix_str, afi, safi); @@ -6468,6 +6504,15 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, aggregate->summary_only = summary_only; aggregate->as_set = as_set; aggregate->safi = safi; + + if (rmap) { + XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); + route_map_counter_decrement(aggregate->rmap.map); + aggregate->rmap.name = + XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); + aggregate->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment(aggregate->rmap.map); + } bgp_node_set_bgp_aggregate_info(rn, aggregate); /* Aggregate address insert into BGP routing table. */ @@ -6478,17 +6523,20 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, DEFUN (aggregate_address, aggregate_address_cmd, - "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "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); char *prefix = argv[idx]->arg; + char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; idx = 0; @@ -6496,25 +6544,34 @@ DEFUN (aggregate_address, ? AGGREGATE_SUMMARY_ONLY : 0; + idx = 0; + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty), - summary_only, as_set); + rmap, summary_only, as_set); } DEFUN (aggregate_address_mask, aggregate_address_mask_cmd, - "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\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", &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; idx = 0; @@ -6522,6 +6579,10 @@ DEFUN (aggregate_address_mask, ? AGGREGATE_SUMMARY_ONLY : 0; + rmap_found = argv_find(argv, argc, "WORD", &idx); + if (rmap_found) + rmap = argv[idx]->arg; + char prefix_str[BUFSIZ]; int ret = netmask_str2prefix_str(prefix, mask, prefix_str); @@ -6531,19 +6592,21 @@ DEFUN (aggregate_address_mask, } return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), - summary_only, as_set); + rmap, summary_only, as_set); } 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); @@ -6553,7 +6616,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" @@ -6561,7 +6624,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); @@ -6581,17 +6646,21 @@ DEFUN (no_aggregate_address_mask, DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, - "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "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); 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; @@ -6599,20 +6668,27 @@ DEFUN (ipv6_aggregate_address, int sum_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY : 0; - return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only, - as_set); + + 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, + sum_only, as_set); } 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); @@ -7228,7 +7304,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, /* We display both LL & GL if both have been * received */ - if ((attr->mp_nexthop_len == 32) + if ((attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) || (path->peer->conf_if)) { json_nexthop_ll = json_object_new_object(); json_object_string_add( @@ -7260,7 +7337,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, } else { /* Display LL if LL/Global both in table unless * prefer-global is set */ - if (((attr->mp_nexthop_len == 32) + if (((attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && !attr->mp_nexthop_prefer_global) || (path->peer->conf_if)) { if (path->peer->conf_if) { @@ -10927,7 +11005,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, get_afi_safi_str(afi, safi, false)); } - vty_out(vty, "PfxCt: %ld\n", peer->pcount[afi][safi]); + vty_out(vty, "PfxCt: %" PRIu32 "\n", peer->pcount[afi][safi]); vty_out(vty, "\nCounts from RIB table walk:\n\n"); for (i = 0; i < PCOUNT_MAX; i++) @@ -11834,6 +11912,9 @@ uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo, peer = pinfo->peer; + if (pinfo->attr->distance) + return pinfo->attr->distance; + /* Check source address. */ sockunion2hostprefix(&peer->su, &q); rn = bgp_node_match(bgp_distance_table[afi][safi], &q); @@ -12467,6 +12548,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp_aggregate->summary_only) vty_out(vty, " summary-only"); + if (bgp_aggregate->rmap.name) + vty_out(vty, " route-map %s", bgp_aggregate->rmap.name); + vty_out(vty, "\n"); } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 704cd39710..a710873ea7 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -236,9 +236,9 @@ struct bgp_path_info { #define BGP_ROUTE_NORMAL 0 #define BGP_ROUTE_STATIC 1 #define BGP_ROUTE_AGGREGATE 2 -#define BGP_ROUTE_REDISTRIBUTE 3 +#define BGP_ROUTE_REDISTRIBUTE 3 #ifdef ENABLE_BGP_VNC -# define BGP_ROUTE_RFP 4 +# define BGP_ROUTE_RFP 4 #endif #define BGP_ROUTE_IMPORTED 5 /* from another bgp instance/safi */ @@ -313,7 +313,10 @@ struct bgp_aggregate { uint8_t as_set; /* Route-map for aggregated route. */ - struct route_map *map; + struct { + char *name; + struct route_map *map; + } rmap; /* Suppress-count. */ unsigned long count; @@ -545,6 +548,10 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t); extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t, safi_t); +extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate); +extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate); extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 545ca19762..a038b0e7a9 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -114,6 +114,7 @@ o Cisco route-map origin : Done tag : Done weight : Done + table : Done o Local extensions @@ -269,7 +270,8 @@ route_match_peer(void *rule, const struct prefix *prefix, /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, - REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH + REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route + => return RMAP_MATCH */ if (sockunion_same(su, &su_def)) { int ret; @@ -277,6 +279,8 @@ route_match_peer(void *rule, const struct prefix *prefix, || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || CHECK_FLAG(peer->rmap_type, + PEER_RMAP_TYPE_AGGREGATE) + || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) ret = RMAP_MATCH; else @@ -1207,10 +1211,26 @@ static void route_match_community_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom); } +/* + * In routemap processing there is a need to add the + * name as a rule_key in the dependency table. Routemap + * lib is unaware of rule_key when exact-match clause + * is in use. routemap lib uses the compiled output to + * get the rule_key value. + */ +static void *route_match_get_community_key(void *rule) +{ + struct rmap_community *rcom; + + rcom = rule; + return rcom->name; +} + + /* Route map commands for community matching. */ struct route_map_rule_cmd route_match_community_cmd = { "community", route_match_community, route_match_community_compile, - route_match_community_free}; + route_match_community_free, route_match_get_community_key}; /* Match function for lcommunity match. */ static enum route_map_cmd_result_t @@ -1281,7 +1301,8 @@ static void route_match_lcommunity_free(void *rule) /* Route map commands for community matching. */ struct route_map_rule_cmd route_match_lcommunity_cmd = { "large-community", route_match_lcommunity, - route_match_lcommunity_compile, route_match_lcommunity_free}; + route_match_lcommunity_compile, route_match_lcommunity_free, + route_match_get_community_key}; /* Match function for extcommunity match. */ @@ -1680,6 +1701,30 @@ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, route_value_compile, route_value_free, }; +/* `set distance DISTANCE */ +static enum route_map_cmd_result_t +route_set_distance(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_path_info *path = object; + struct rmap_value *rv = rule; + + if (type != RMAP_BGP) + return RMAP_OKAY; + + path->attr->distance = rv->value; + + return RMAP_OKAY; +} + +/* set distance rule structure */ +struct route_map_rule_cmd route_set_distance_cmd = { + "distance", + route_set_distance, + route_value_compile, + route_value_free, +}; + /* `set metric METRIC' */ /* Set metric to attribute. */ @@ -1710,6 +1755,32 @@ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_value_compile, route_value_free, }; +/* `set table (1-4294967295)' */ + +static enum route_map_cmd_result_t route_set_table_id(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object) +{ + struct rmap_value *rv; + struct bgp_path_info *path; + + if (type == RMAP_BGP) { + /* Fetch routemap's rule information. */ + rv = rule; + path = object; + + path->attr->rmap_table_id = rv->value; + } + return RMAP_OKAY; +} + +/* Set table_id rule structure. */ +static struct route_map_rule_cmd route_set_table_id_cmd = { + "table", route_set_table_id, + route_value_compile, route_value_free +}; + /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ @@ -2728,10 +2799,8 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, path = object; peer = path->peer; - if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) - || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) - && peer->su_remote - && sockunion_family(peer->su_remote) == AF_INET6) { + if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) + || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) { /* Set next hop preference to global */ path->attr->mp_nexthop_prefer_global = true; SET_FLAG(path->attr->rmap_change_flags, @@ -2853,12 +2922,15 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, /* Set next hop value and length in attribute. */ if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) { path->attr->mp_nexthop_local = peer_address; - if (path->attr->mp_nexthop_len != 32) - path->attr->mp_nexthop_len = 32; + if (path->attr->mp_nexthop_len + != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + path->attr->mp_nexthop_len = + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; } else { path->attr->mp_nexthop_global = peer_address; if (path->attr->mp_nexthop_len == 0) - path->attr->mp_nexthop_len = 16; + path->attr->mp_nexthop_len = + BGP_ATTR_NHLEN_IPV6_GLOBAL; } } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) { @@ -2923,7 +2995,7 @@ route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix, /* Set next hop value. */ path->attr->mp_nexthop_global_in = *address; - path->attr->mp_nexthop_len = 4; + path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; } return RMAP_OKAY; @@ -3070,11 +3142,6 @@ static int bgp_route_match_add(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - break; - case RMAP_DUPLICATE_RULE: /* * Intentionally doing nothing here. */ @@ -3108,7 +3175,7 @@ static int bgp_route_match_delete(struct vty *vty, const char *command, rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); } - ret = route_map_delete_match(index, command, dep_name); + ret = route_map_delete_match(index, command, dep_name, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% BGP Can't find rule.\n"); @@ -3119,10 +3186,6 @@ static int bgp_route_match_delete(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ @@ -3248,6 +3311,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, struct peer *peer; struct bgp_node *bn; struct bgp_static *bgp_static; + struct bgp_aggregate *aggregate; struct listnode *node, *nnode; struct route_map *map; char buf[INET6_ADDRSTRLEN]; @@ -3331,6 +3395,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, safi); } } + + /* For aggregate-address route-map updates. */ + for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn; + bn = bgp_route_next(bn)) { + aggregate = bgp_node_get_bgp_aggregate_info(bn); + if (!aggregate) + continue; + + if (!aggregate->rmap.name + || (strcmp(rmap_name, aggregate->rmap.name) != 0)) + continue; + + if (!aggregate->rmap.map) + route_map_counter_increment(map); + + aggregate->rmap.map = map; + + if (route_update) { + if (bgp_debug_zebra(&bn->p)) + zlog_debug( + "Processing route_map %s update on aggregate-address route %s", + rmap_name, + inet_ntop(bn->p.family, + &bn->p.u.prefix, buf, + INET6_ADDRSTRLEN)); + bgp_aggregate_route(bgp, &bn->p, afi, safi, + aggregate); + } + } } /* For redistribute route-map updates. */ @@ -3992,6 +4085,32 @@ DEFUN (no_match_origin, RMAP_EVENT_MATCH_DELETED); } +DEFUN (set_table_id, + set_table_id_cmd, + "set table (1-4294967295)", + SET_STR + "export route to non-main kernel table\n" + "Kernel routing table id\n") +{ + int idx_id = 2; + + VTY_DECLVAR_CONTEXT(route_map_index, index); + + return generic_set_add(vty, index, "table", argv[idx_id]->arg); +} + +DEFUN (no_set_table_id, + no_set_table_id_cmd, + "no set table", + NO_STR + SET_STR + "export route to non-main kernel table\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + + return generic_set_delete(vty, index, "table", NULL); +} + DEFUN (set_ip_nexthop_peer, set_ip_nexthop_peer_cmd, "[no] set ip next-hop peer-address", @@ -4028,6 +4147,29 @@ DEFUN (set_ip_nexthop_unchanged, "unchanged"); } +DEFUN (set_distance, + set_distance_cmd, + "set distance (0-255)", + SET_STR + "BGP Administrative Distance to use\n" + "Distance value\n") +{ + int idx_number = 2; + + return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), + "distance", argv[idx_number]->arg); +} + +DEFUN (no_set_distance, + no_set_distance_cmd, + "no set distance [(0-255)]", + NO_STR SET_STR + "BGP Administrative Distance to use\n" + "Distance value\n") +{ + return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), + "distance", NULL); +} DEFUN (set_local_pref, set_local_pref_cmd, @@ -5078,11 +5220,13 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_match(&route_match_vrl_source_vrf_cmd); + route_map_install_set(&route_set_table_id_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); route_map_install_set(&route_set_weight_cmd); route_map_install_set(&route_set_label_index_cmd); route_map_install_set(&route_set_metric_cmd); + route_map_install_set(&route_set_distance_cmd); route_map_install_set(&route_set_aspath_prepend_cmd); route_map_install_set(&route_set_aspath_exclude_cmd); route_map_install_set(&route_set_origin_cmd); @@ -5133,9 +5277,13 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &match_probability_cmd); install_element(RMAP_NODE, &no_match_probability_cmd); + install_element(RMAP_NODE, &no_set_table_id_cmd); + install_element(RMAP_NODE, &set_table_id_cmd); install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd); install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd); install_element(RMAP_NODE, &set_local_pref_cmd); + install_element(RMAP_NODE, &set_distance_cmd); + install_element(RMAP_NODE, &no_set_distance_cmd); install_element(RMAP_NODE, &no_set_local_pref_cmd); install_element(RMAP_NODE, &set_weight_cmd); install_element(RMAP_NODE, &set_label_index_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 2cfd65896c..1267e35097 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1234,7 +1234,8 @@ DEFPY (show_rpki_prefix, const struct pfx_record *record = &matches[i]; if (record->max_len >= prefix->prefixlen - && ((asn != 0 && asn == record->asn) || asn == 0)) { + && ((asn != 0 && (uint32_t)asn == record->asn) + || asn == 0)) { print_record(&matches[i], vty); } } @@ -1420,7 +1421,6 @@ DEFUN (match_rpki, vty_out(vty, "%% BGP Argument is malformed.\n"); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Intentionally doing nothing here */ @@ -1443,7 +1443,8 @@ DEFUN (no_match_rpki, VTY_DECLVAR_CONTEXT(route_map_index, index); enum rmap_compile_rets ret; - ret = route_map_delete_match(index, "rpki", argv[3]->arg); + ret = route_map_delete_match(index, "rpki", argv[3]->arg, + RMAP_EVENT_MATCH_DELETED); if (ret) { switch (ret) { case RMAP_RULE_MISSING: @@ -1453,7 +1454,6 @@ DEFUN (no_match_rpki, vty_out(vty, "%% BGP Argument is malformed.\n"); break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 44cbeabd69..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 @@ -894,6 +894,10 @@ static int bgpTrapEstablished(struct peer *peer) struct in_addr addr; oid index[sizeof(oid) * IN_ADDR_SIZE]; + /* Check if this peer just went to Established */ + if ((peer->last_major_event != OpenConfirm) || !(peer_established(peer))) + return 0; + ret = inet_aton(peer->host, &addr); if (ret == 0) return 0; @@ -935,7 +939,7 @@ static int bgp_snmp_init(struct thread_master *tm) static int bgp_snmp_module_init(void) { - hook_register(peer_established, bgpTrapEstablished); + hook_register(peer_status_changed, bgpTrapEstablished); hook_register(peer_backward_transition, bgpTrapBackwardTransition); hook_register(frr_late_init, bgp_snmp_init); return 0; diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index de7b05bdd9..4b6af935e0 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -570,8 +570,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; if (filter->map[RMAP_OUT].name) - vty_out(vty, " Outgoing route map: %s%s\n", - filter->map[RMAP_OUT].map ? "X" : "", + vty_out(vty, " Outgoing route map: %s\n", filter->map[RMAP_OUT].name); vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv); if (updgrp->conf->change_local_as) @@ -613,6 +612,9 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) subgrp->peer_refreshes_combined); vty_out(vty, " Merge checks triggered: %u\n", subgrp->merge_checks_triggered); + vty_out(vty, " Coalesce Time: %u%s\n", + (UPDGRP_INST(subgrp->update_group))->coalesce_time, + subgrp->t_coalesce ? "(Running)" : ""); vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version); vty_out(vty, " Packet queue length: %d\n", bpacket_queue_length(SUBGRP_PKTQ(subgrp))); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 21f1dff60d..5c1483a768 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -324,8 +324,9 @@ static int subgroup_coalesce_timer(struct thread *thread) subgrp = THREAD_ARG(thread); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) zlog_debug("u%" PRIu64 ":s%" PRIu64 - " announcing routes upon coalesce timer expiry", - (SUBGRP_UPDGRP(subgrp))->id, subgrp->id); + " announcing routes upon coalesce timer expiry(%u ms)", + (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, + subgrp->v_coalesce), subgrp->t_coalesce = NULL; subgrp->v_coalesce = 0; subgroup_announce_route(subgrp); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 688abae0e4..9329c8d892 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -391,6 +391,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, struct peer *peer; char buf[BUFSIZ]; char buf2[BUFSIZ]; + struct bgp_filter *filter; s = stream_dup(pkt->buffer); peer = PAF_PEER(paf); @@ -401,6 +402,8 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, afi_t nhafi; int route_map_sets_nh; nhlen = stream_getc_from(s, vec->offset); + filter = &peer->filter[paf->afi][paf->safi]; + if (peer_cap_enhe(peer, paf->afi, paf->safi)) nhafi = AFI_IP6; else @@ -439,25 +442,25 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, mod_v4nh = &v4nh; /* - * If route-map has set the nexthop, that is always - * used; if it is - * specified as peer-address, the peering address is - * picked up. - * Otherwise, if NH is unavailable from attribute, the - * peering addr - * is picked up; the "NH unavailable" case also covers - * next-hop-self - * and some other scenarios -- see - * subgroup_announce_check(). In - * all other cases, use the nexthop carried in the - * attribute unless - * it is EBGP non-multiaccess and there is no - * next-hop-unchanged setting. + * If route-map has set the nexthop, that is normally + * used; if it is specified as peer-address, the peering + * address is picked up. Otherwise, if NH is unavailable + * from attribute, the peering addr is picked up; the + * "NH unavailable" case also covers next-hop-self and + * some other scenarios - see subgroup_announce_check(). + * In all other cases, use the nexthop carried in the + * attribute unless it is EBGP non-multiaccess and there + * is no next-hop-unchanged setting or the peer is EBGP + * and the route-map that changed the next-hop value + * was applied inbound rather than outbound. Updates to + * an EBGP peer should only modify the next-hop if it + * was set in an outbound route-map to that peer. * Note: It is assumed route-map cannot set the nexthop - * to an - * invalid value. + * to an invalid value. */ - if (route_map_sets_nh) { + if (route_map_sets_nh + && ((peer->sort != BGP_PEER_EBGP) + || ROUTE_MAP_OUT(filter))) { if (CHECK_FLAG( vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) { @@ -543,7 +546,15 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, stream_get_from(&v6nhglobal, s, offset_nhglobal, IPV6_MAX_BYTELEN); - if (route_map_sets_nh) { + + /* + * Updates to an EBGP peer should only modify the + * next-hop if it was set in an outbound route-map + * to that peer. + */ + if (route_map_sets_nh + && ((peer->sort != BGP_PEER_EBGP) + || ROUTE_MAP_OUT(filter))) { if (CHECK_FLAG( vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 17bc83ed2e..e60dc0452b 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)) @@ -8447,9 +8447,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (peer->status == Established) if (peer->afc_recv[afi][safi]) - vty_out(vty, " %12ld", - peer->pcount[afi] - [pfx_rcd_safi]); + vty_out(vty, " %12" PRIu32, + peer->pcount + [afi] + [pfx_rcd_safi]); else vty_out(vty, " NoNeg"); else { @@ -9345,11 +9346,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->usmap.name); /* Receive prefix count */ - vty_out(vty, " %ld accepted prefixes\n", p->pcount[afi][safi]); + vty_out(vty, " %" PRIu32 " accepted prefixes\n", + p->pcount[afi][safi]); /* Maximum prefix */ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { - vty_out(vty, " Maximum prefixes allowed %ld%s\n", + vty_out(vty, + " Maximum prefixes allowed %" PRIu32 "%s\n", p->pmax[afi][safi], CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 71f7f6d0e3..7923f076c1 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", ifp->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; @@ -1274,6 +1228,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + /* Metric is currently based on the best-path only */ metric = info->attr->med; for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { @@ -1540,6 +1499,11 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info, api.safi = safi; api.prefix = *p; + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + /* If the route's source is EVPN, flag as such. */ if (is_route_parent_evpn(info)) SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE); @@ -2721,17 +2685,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 +2722,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/bgpd/bgpd.c b/bgpd/bgpd.c index 5b31fbb3a8..9c0e25bf25 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2053,7 +2053,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info( + zlog_debug( "peer(s) are now active for labeled-unicast, allocate MPLS labels"); bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1; @@ -2156,7 +2156,7 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) && !bgp_afi_safi_peer_exists(bgp, afi, safi)) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info( + zlog_debug( "peer(s) are no longer active for labeled-unicast, deallocate MPLS labels"); bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0; @@ -7348,7 +7348,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* maximum-prefix. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) { - vty_out(vty, " neighbor %s maximum-prefix %lu", addr, + vty_out(vty, " neighbor %s maximum-prefix %" PRIu32, addr, peer->pmax[afi][safi]); if (peer->pmax_threshold[afi][safi] @@ -7931,8 +7931,6 @@ static void bgp_pthreads_init(void) assert(!bgp_pth_io); assert(!bgp_pth_ka); - frr_pthread_init(); - struct frr_pthread_attr io = { .start = frr_pthread_attr_default.start, .stop = frr_pthread_attr_default.stop, @@ -7958,7 +7956,6 @@ void bgp_pthreads_run(void) void bgp_pthreads_finish(void) { frr_pthread_stop_all(); - frr_pthread_finish(); } void bgp_init(unsigned short instance) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 477c036009..9b0346da12 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1152,10 +1152,10 @@ struct peer { int rcvd_attr_printed; /* Prefix count. */ - unsigned long pcount[AFI_MAX][SAFI_MAX]; + uint32_t pcount[AFI_MAX][SAFI_MAX]; /* Max prefix count. */ - unsigned long pmax[AFI_MAX][SAFI_MAX]; + uint32_t pmax[AFI_MAX][SAFI_MAX]; uint8_t pmax_threshold[AFI_MAX][SAFI_MAX]; uint16_t pmax_restart[AFI_MAX][SAFI_MAX]; #define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75 @@ -1202,7 +1202,7 @@ struct peer { uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE]; /* The kind of route-map Flags.*/ - uint8_t rmap_type; + uint16_t rmap_type; #define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */ #define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */ #define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */ @@ -1211,6 +1211,7 @@ struct peer { #define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ #define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ #define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ +#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */ /* peer specific BFD information */ struct bfd_info *bfd_info; @@ -1935,4 +1936,7 @@ extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, const char *ip_str, bool use_json); +/* Hooks */ +DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer)) + #endif /* _QUAGGA_BGPD_H */ diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 9b8f64ee67..0aa102feab 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -880,12 +880,12 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ attr.nexthop.s_addr = nexthop->addr.v4.s_addr; attr.mp_nexthop_global_in = nexthop->addr.v4; - attr.mp_nexthop_len = 4; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; break; case AF_INET6: attr.mp_nexthop_global = nexthop->addr.v6; - attr.mp_nexthop_len = 16; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; break; default: diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 87a05a4f8c..655cf747de 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2179,8 +2179,8 @@ static struct bgp_path_info *rfapiItBiIndexSearch( { struct skiplist *sl; int rc; - struct bgp_path_info bpi_fake; - struct bgp_path_info_extra bpi_extra; + struct bgp_path_info bpi_fake = {0}; + struct bgp_path_info_extra bpi_extra = {0}; struct bgp_path_info *bpi_result; sl = RFAPI_RDINDEX(rn); diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 3d8d5bccb0..b97c8c3030 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -86,13 +86,13 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig, switch (use_nexthop->family) { case AF_INET: new->nexthop = use_nexthop->u.prefix4; - new->mp_nexthop_len = 4; /* bytes */ + new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */ new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); break; case AF_INET6: new->mp_nexthop_global = use_nexthop->u.prefix6; - new->mp_nexthop_len = 16; /* bytes */ + new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */ break; default: @@ -624,13 +624,13 @@ encap_attr_export(struct attr *new, struct attr *orig, switch (use_nexthop->family) { case AF_INET: new->nexthop = use_nexthop->u.prefix4; - new->mp_nexthop_len = 4; /* bytes */ + new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */ new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); break; case AF_INET6: new->mp_nexthop_global = use_nexthop->u.prefix6; - new->mp_nexthop_len = 16; /* bytes */ + new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */ break; default: diff --git a/configure.ac b/configure.ac index 6c1b35b5f2..730e2ae6f0 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.60]) -AC_INIT([frr], [7.2-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -328,8 +328,8 @@ if test "$enable_thread_sanitizer" = "yes"; then ]) fi if test "$enable_memory_sanitizer" = "yes"; then - AC_C_FLAG([-fsanitize=thread -fPIE -pie], [ - AC_MSG_ERROR([$CC does not support Thread Sanitizer.]) + AC_C_FLAG([-fsanitize=memory -fPIE -pie], [ + AC_MSG_ERROR([$CC does not support Memory Sanitizer.]) ], [ SAN_FLAGS="-fsanitize=memory -fPIE -pie" ]) @@ -1452,6 +1452,12 @@ if test "x$enable_pcreposix" = "xyes"; then fi AC_SUBST([HAVE_LIBPCREPOSIX]) +dnl ########################################################################## +dnl test "${enable_clippy_only}" != "yes" +fi +dnl END OF LARGE if block +dnl ########################################################################## + dnl ------------------ dnl check C-Ares library dnl ------------------ @@ -1462,12 +1468,6 @@ PKG_CHECK_MODULES([CARES], [libcares], [ ]) AM_CONDITIONAL([CARES], [$c_ares_found]) -dnl ########################################################################## -dnl test "${enable_clippy_only}" != "yes" -fi -dnl END OF LARGE if block -dnl ########################################################################## - dnl ---------------------------------------------------------------------------- dnl figure out if domainname is available in the utsname struct (GNU extension). @@ -1535,9 +1535,11 @@ case "$host_os" in no) ;; yes) + if test "${enable_clippy_only}" != "yes"; then if test "$c_ares_found" != "true" ; then AC_MSG_ERROR([nhrpd requires libcares. Please install c-ares and its -dev headers.]) fi + fi NHRPD="nhrpd" ;; *) @@ -2041,9 +2043,11 @@ if test "${enable_capabilities}" != "no"; then case "$host_os" in linux*) + if test "${enable_clippy_only}" != "yes"; then if test "$frr_ac_lcaps" != "yes"; then AC_MSG_ERROR([libcap and/or its headers were not found. Running FRR without libcap support built in causes a huge performance penalty.]) fi + fi ;; esac else diff --git a/debian/frr-pythontools.install b/debian/frr-pythontools.install index 28140382f6..5f7eaebed5 100644 --- a/debian/frr-pythontools.install +++ b/debian/frr-pythontools.install @@ -1 +1,2 @@ usr/lib/frr/frr-reload.py +usr/lib/frr/generate_support_bundle.py diff --git a/debian/rules b/debian/rules index a546f38d70..c8550ecb52 100755 --- a/debian/rules +++ b/debian/rules @@ -71,6 +71,7 @@ override_dh_auto_install: dh_auto_install sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/frr-reload.py + sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/generate_support_bundle.py # let dh_systemd_* and dh_installinit do their thing automatically ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index a0a574a79c..c2e72e2ec5 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -189,11 +189,8 @@ for ``master`` branch: git clone https://github.com/FRRouting/frr.git cd frr ./bootstrap.sh - export CC=gcc - export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" - export LD=gcc - export LDFLAGS="-g -fsanitize=address -ldl" - ./configure --enable-shared=no \ + ./configure \ + --enable-address-sanitizer \ --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 3c6887fbac..93d01bfbc1 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -499,8 +499,11 @@ your new claim at the end of the list. Code Formatting --------------- -FRR uses Linux kernel style except where noted below. Code which does not -comply with these style guidelines will not be accepted. +C Code +^^^^^^ + +For C code, FRR uses Linux kernel style except where noted below. Code which +does not comply with these style guidelines will not be accepted. The project provides multiple tools to allow you to correctly style your code as painlessly as possible, primarily built around ``clang-format``. @@ -707,6 +710,28 @@ BSD coding style applies to: - ``ldpd/`` +YANG +^^^^ + +FRR uses YANG to define data models for its northbound interface. YANG models +should follow conventions used by the IETF standard models. From a practical +standpoint, this corresponds to the output produced by the ``yanglint`` tool +included in the ``libyang`` project, which is used by FRR to parse and validate +YANG models. You should run the following command on all YANG documents you +write: + +.. code-block:: console + + yanglint -f yang <model> + +The output of this command should be identical to the input file. The sole +exception to this is comments. ``yanglint`` does not support comments and will +strip them from its output. You may include comments in your YANG documents, +but they should be indented appropriately (use spaces). Where possible, +comments should be eschewed in favor of a suitable ``description`` statement. + +In short, a diff between your input file and the output of ``yanglint`` should +either be empty or contain only comments. Specific Exceptions ^^^^^^^^^^^^^^^^^^^ diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 32ca5707d2..525a31d486 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -79,8 +79,8 @@ BFDd Commands `vrf` selects which domain we want to use. -.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}] -.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}] +.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] +.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] Stops and removes the selected peer. @@ -89,8 +89,8 @@ BFDd Commands Show all configured BFD peers information and current status. -.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] -.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] +.. index:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] +.. clicmd:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] Show status for a specific BFD peer. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index da339b4409..402085872e 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -368,6 +368,16 @@ Administrative Distance Metrics Sets the administrative distance for a particular route. +.. _bgp-requires-policy: + +Require policy on EBGP +------------------------------- + +.. index:: [no] bgp ebgp-requires-policy +.. clicmd:: [no] bgp ebgp-requires-policy + + This command requires incoming and outgoing filters to be applied for eBGP sessions. Without the incoming filter, no routes will be accepted. Without the outgoing filter, no routes will be announced. + .. _bgp-route-flap-dampening: Route Flap Dampening @@ -675,6 +685,11 @@ Route Aggregation-IPv4 Address Family This command specifies an aggregate address. +.. index:: aggregate-address A.B.C.D/M route-map NAME +.. clicmd:: aggregate-address A.B.C.D/M route-map NAME + + Apply a route-map for an aggregated prefix. + .. index:: aggregate-address A.B.C.D/M as-set .. clicmd:: aggregate-address A.B.C.D/M as-set @@ -689,11 +704,11 @@ Route Aggregation-IPv4 Address Family .. index:: no aggregate-address A.B.C.D/M .. clicmd:: no aggregate-address A.B.C.D/M - + This command removes an aggregate address. - This configuration example setup the aggregate-address under + This configuration example setup the aggregate-address under ipv4 address-family. .. code-block:: frr @@ -703,6 +718,7 @@ Route Aggregation-IPv4 Address Family aggregate-address 10.0.0.0/8 aggregate-address 20.0.0.0/8 as-set aggregate-address 40.0.0.0/8 summary-only + aggregate-address 50.0.0.0/8 route-map aggr-rmap exit-address-family @@ -716,6 +732,11 @@ Route Aggregation-IPv6 Address Family This command specifies an aggregate address. +.. index:: aggregate-address X:X::X:X/M route-map NAME +.. clicmd:: aggregate-address X:X::X:X/M route-map NAME + + Apply a route-map for an aggregated prefix. + .. index:: aggregate-address X:X::X:X/M as-set .. clicmd:: aggregate-address X:X::X:X/M as-set @@ -734,16 +755,17 @@ Route Aggregation-IPv6 Address Family This command removes an aggregate address. - This configuration example setup the aggregate-address under - ipv4 address-family. + This configuration example setup the aggregate-address under + ipv6 address-family. .. code-block:: frr router bgp 1 address-family ipv6 unicast aggregate-address 10::0/64 - aggregate-address 20::0/64 as-set - aggregate-address 40::0/64 summary-only + aggregate-address 20::0/64 as-set + aggregate-address 40::0/64 summary-only + aggregate-address 50::0/64 route-map aggr-rmap exit-address-family .. _bgp-redistribute-to-bgp: @@ -1118,11 +1140,8 @@ Capability Negotiation Negotiation. Please use *dont-capability-negotiate* command to disable the feature. -.. index:: neighbor PEER dont-capability-negotiate -.. clicmd:: neighbor PEER dont-capability-negotiate - -.. index:: no neighbor PEER dont-capability-negotiate -.. clicmd:: no neighbor PEER dont-capability-negotiate +.. index:: [no] neighbor PEER dont-capability-negotiate +.. clicmd:: [no] neighbor PEER dont-capability-negotiate Suppress sending Capability Negotiation as OPEN message optional parameter to the peer. This command only affects the peer is configured other than @@ -1137,6 +1156,11 @@ Capability Negotiation configured by *override-capability*, *bgpd* ignores received capabilities then override negotiated capabilities with configured values. + Additionally the operator should be reminded that this feature fundamentally + disables the ability to use widely deployed BGP features. BGP unnumbered, + hostname support, AS4, Addpath, Route Refresh, ORF, Dynamic Capabilities, + and graceful restart. + .. index:: neighbor PEER override-capability .. clicmd:: neighbor PEER override-capability @@ -2311,7 +2335,7 @@ attribute. Displaying Routes by Large Community Attribute ---------------------------------------------- -The following commands allow displaying routes based on their +The following commands allow displaying routes based on their large community attribute. .. index:: show [ip] bgp <ipv4|ipv6> large-community @@ -2328,8 +2352,8 @@ large community attribute. These commands display BGP routes which have the large community attribute. attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that - large community are displayed. When `exact-match` is specified, it display - only routes that have an exact match. When `json` is specified, it display + large community are displayed. When `exact-match` is specified, it display + only routes that have an exact match. When `json` is specified, it display routes in json format. .. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD @@ -2342,8 +2366,8 @@ large community attribute. .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json These commands display BGP routes for the address family specified that - match the specified large community list. When `exact-match` is specified, - it displays only routes that have an exact match. When `json` is specified, + match the specified large community list. When `exact-match` is specified, + it displays only routes that have an exact match. When `json` is specified, it display routes in json format. .. _bgp-display-routes-by-as-path: @@ -2374,6 +2398,23 @@ Displaying Routes by AS Path Print a summary of neighbor connections for the specified AFI/SAFI combination. +Displaying Update Group Information +----------------------------------- + +..index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue] +..clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue] + + Display Information about each individual update-group being used. + If SUBGROUP-ID is specified only display about that particular group. If + advertise-queue is specified the list of routes that need to be sent + to the peers in the update-group is displayed, advertised-routes means + the list of routes we have sent to the peers in the update-group and + packet-queue specifies the list of packets in the queue to be sent. + +..index:: show bgp update-groups statistics +..clicmd:: show bgp update-groups statistics + + Display Information about update-group events in FRR. .. _bgp-route-reflector: diff --git a/doc/user/index.rst b/doc/user/index.rst index 6c3b14e062..416c51f13b 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -58,6 +58,7 @@ Protocols vnc vrrp bmp + watchfrr ######## Appendix diff --git a/doc/user/ospf_fundamentals.rst b/doc/user/ospf_fundamentals.rst index 7db822c820..da348b02d2 100644 --- a/doc/user/ospf_fundamentals.rst +++ b/doc/user/ospf_fundamentals.rst @@ -24,7 +24,7 @@ Each router thus builds up an :abbr:`LSDB (Link State Database)` of all the link-state messages. From this collection of LSAs in the LSDB, each router can then calculate the shortest path to any other router, based on some common metric, by using an algorithm such as -`Edgar Djikstra's <http://www.cs.utexas.edu/users/EWD/>`_ +`Edsger Dijkstra's <http://www.cs.utexas.edu/users/EWD/>`_ :abbr:`SPF (Shortest Path First)` algorithm. .. index:: Link-state routing protocol advantages diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 805d6264a8..4f9c573a24 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -201,14 +201,15 @@ is in a vrf, enter the interface command with the vrf keyword at the end. .. clicmd:: ip pim sm Tell pim that we would like to use this interface to form pim neighbors - over. Please note we will *not* accept igmp reports over this interface with - this command. + over. Please note that this command does not enable the reception of IGMP + reports on the interface. Refer to the next `ip igmp` command for IGMP + management. .. index:: ip igmp .. clicmd:: ip igmp Tell pim to receive IGMP reports and Query on this interface. The default - version is v3. This command is useful on the LHR. + version is v3. This command is useful on a LHR. .. index:: ip igmp join A.B.C.D A.B.C.D .. clicmd:: ip igmp join A.B.C.D A.B.C.D diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 09cbd7c7b0..5c2b41b63c 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -270,6 +270,12 @@ Route Map Set Command Set the BGP local preference to `local_pref`. +.. index:: [no] set distance DISTANCE +.. clicmd:: [no] set distance DISTANCE + + Set the Administrative distance to DISTANCE to use for the route. + This is only locally significant and will not be dispersed to peers. + .. index:: set weight WEIGHT .. clicmd:: set weight WEIGHT @@ -300,6 +306,11 @@ Route Map Set Command Set BGP route origin. +.. index:: set table (1-4294967295) +.. clicmd:: set table (1-4294967295) + + Set the BGP table to a given table identifier + .. _route-map-call-command: Route Map Call Command diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 0f0a8a0774..ce519fbfbf 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -43,6 +43,7 @@ user_RSTFILES = \ doc/user/zebra.rst \ doc/user/bfd.rst \ doc/user/flowspec.rst \ + doc/user/watchfrr.rst \ # end EXTRA_DIST += \ diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst index a2dd950987..736d9e69a5 100644 --- a/doc/user/vrrp.rst +++ b/doc/user/vrrp.rst @@ -108,7 +108,7 @@ Suppose you have an interface ``eth0`` with the following configuration: .. code-block:: console - $ ip link show eth0 + $ ip addr show eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:17:45:00:aa:aa brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0 @@ -118,9 +118,10 @@ Suppose you have an interface ``eth0`` with the following configuration: inet6 fe80::17:45ff:fe00:aaaa/64 scope link valid_lft forever preferred_lft forever -Suppose the address you want to back up is ``10.0.2.16``, and will be managed -by the virtual router with id ``5``. A macvlan device with the appropriate MAC -address must be created before VRRP can begin to operate. +Suppose that the IPv4 and IPv6 addresses you want to back up are ``10.0.2.16`` +and ``2001:db8::370:7334``, and that they will be managed by the virtual router +with id ``5``. A macvlan device with the appropriate MAC address must be created +before VRRP can begin to operate. If you are using ``ifupdown2``, the configuration is as follows: @@ -426,10 +427,11 @@ Show commands, global defaults and debugging configuration commands. VRID will only show routers with that VRID. Specifying ``json`` will dump each router state in a JSON array. -.. index:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] -.. clicmd:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] +.. index:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] +.. clicmd:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] - Toggle debugging logs for some or all components of VRRP. + Toggle debugging logs for VRRP components. + If no component is specified, debugging for all components are turned on/off. protocol Logs state changes, election protocol decisions, and interface status @@ -482,7 +484,8 @@ execute the following command: .. clicmd:: [no] vrrp autoconfigure [version (2-3)] Generates VRRP configuration based on the interface configuration on the - base system. Any existing interfaces that are configured properly for VRRP - + base system. If the protocol version is not specified, the default is VRRPv3. + Any existing interfaces that are configured properly for VRRP - i.e. have the correct MAC address, link local address (when required), IPv4 and IPv6 addresses - are used to create a VRRP router on their parent interfaces, with VRRP IPvX addresses taken from the addresses assigned to diff --git a/doc/user/watchfrr.rst b/doc/user/watchfrr.rst new file mode 100644 index 0000000000..df04a1e375 --- /dev/null +++ b/doc/user/watchfrr.rst @@ -0,0 +1,30 @@ +.. _watchfrr: + +******** +WATCHFRR +******** + +:abbr:`WATCHFRR` is a daemon that handles failed daemon processes and +intelligently restarts them as needed. + +Starting WATCHFRR +================= + +WATCHFRR is started as per normal systemd startup and typically does not +require end users management. + +WATCHFRR commands +================= + +.. index:: show watchfrr +.. clicmd:: show watchfrr + + Give status information about the state of the different daemons being + watched by WATCHFRR + +.. index:: [no] watchfrr ignore DAEMON +.. clicmd:: [no] watchfrr ignore DAEMON + + Tell WATCHFRR to ignore a particular DAEMON if it goes unresponsive. + This is particularly useful when you are a developer and need to debug + a working system, without watchfrr pulling the rug out from under you. diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 50c518d456..af465f6fd4 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -292,6 +292,62 @@ Link Parameters Commands .. _zebra-vrf: +Administrative Distance +======================= + +Administrative distance allows FRR to make decisions about what routes +should be installed in the rib based upon the originating protocol. +The lowest Admin Distance is the route selected. This is purely a +subjective decision about ordering and care has been taken to choose +the same distances that other routing suites have choosen. + ++------------+-----------+ +| Protocol | Distance | ++------------+-----------+ +| System | 0 | ++------------+-----------+ +| Kernel | 0 | ++------------+-----------+ +| Connect | 0 | ++------------+-----------+ +| Static | 1 | ++------------+-----------+ +| NHRP | 10 | ++------------+-----------+ +| EBGP | 20 | ++------------+-----------+ +| EIGRP | 90 | ++------------+-----------+ +| BABEL | 100 | ++------------+-----------+ +| OSPF | 110 | ++------------+-----------+ +| ISIS | 115 | ++------------+-----------+ +| OPENFABRIC | 115 | ++------------+-----------+ +| RIP | 120 | ++------------+-----------+ +| Table | 150 | ++------------+-----------+ +| SHARP | 150 | ++------------+-----------+ +| IBGP | 200 | ++------------+-----------+ +| PBR | 200 | ++------------+-----------+ + +An admin distance of 255 indicates to Zebra that the route should not be +installed into the Data Plane. Additionally routes with an admin distance +of 255 will not be redistributed. + +Zebra does treat Kernel routes as special case for the purposes of Admin +Distance. Upon learning about a route that is not originated by FRR +we read the metric value as a uint32_t. The top byte of the value +is interpreted as the Administrative Distance and the low three bytes +are read in as the metric. This special case is to facilitate VRF +default routes. + Virtual Routing and Forwarding ============================== @@ -374,6 +430,14 @@ commands in relationship to VRF. Here is an extract of some of those commands: This command will dump the routing tables within the vrf scope. If `vrf all` is executed, all routing tables will be dumped. +.. index:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] +.. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] + + This command will dump a summary output of the specified VRF and TABLENO + combination. If neither VRF or TABLENO is specified FRR defaults to + the default vrf and default table. If prefix is specified dump the + number of prefix routes. + By using the :option:`-n` option, the *Linux network namespace* will be mapped over the *Zebra* VRF. One nice feature that is possible by handling *Linux network namespace* is the ability to name default VRF. At startup, *Zebra* @@ -599,19 +663,30 @@ kernel. .. clicmd:: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can - be **any** or one of + be: - - system, - - kernel, + - any, + - babel, + - bgp, - connected, - - static, - - rip, - - ripng, + - eigrp, + - isis, + - kernel, + - nhrp, + - openfabric, - ospf, - ospf6, - - isis, - - bgp, - - hsls. + - rip, + - sharp, + - static, + - ripng, + - table, + - vnc. + + If you choose any as the option that will cause all protocols that are sending + routes to zebra. You can specify a :dfn:`ip protocol PROTOCOL route-map ROUTEMAP` + on a per vrf basis, by entering this command under vrf mode for the vrf you + want to apply the route-map against. .. index:: set src ADDRESS .. clicmd:: set src ADDRESS @@ -764,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/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 815983a394..88c8f88f81 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -9,7 +9,8 @@ RUN source /src/alpine/APKBUILD.in \ --no-cache \ --update-cache \ $makedepends \ - gzip + gzip \ + && pip install pytest COPY . /src ARG PKGVER @@ -29,6 +30,8 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/reposit abuild \ alpine-conf \ alpine-sdk \ + py-pip \ + && pip install pytest \ && setup-apkcache /var/cache/apk \ && mkdir -p /pkgs/apk \ && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 6ffdd0ccb3..3f830348bc 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -1,13 +1,20 @@ FROM debian:buster MAINTAINER Rob Gil (rob@rem5.com) + ENV DEBIAN_FRONTEND noninteractive ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn -RUN apt-get update -RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \ - libc-ares2 libjson-c3 vim systemd procps libreadline7 gnupg2 lsb-release apt-utils + +RUN apt-get update && \ + apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \ + libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils && \ + rm -rf /var/lib/apt/lists/* + RUN curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add - RUN echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list -RUN apt-get update -RUN apt-get install -y frr frr-pythontools + +RUN apt-get update && \ + apt-get install -y frr frr-pythontools && \ + rm -rf /var/lib/apt/lists/* + ADD docker-start /usr/sbin/docker-start ENTRYPOINT ["/usr/sbin/docker-start"] 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_network.c b/eigrpd/eigrp_network.c index c7ffbf9f0e..3e09ec41bb 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -55,12 +55,15 @@ static void eigrp_network_run_interface(struct eigrp *, struct prefix *, int eigrp_sock_init(struct vrf *vrf) { - int eigrp_sock; + int eigrp_sock = -1; int ret; #ifdef IP_HDRINCL int hincl = 1; #endif + if (!vrf) + return eigrp_sock; + frr_with_privs(&eigrpd_privs) { eigrp_sock = vrf_socket( AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id, diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index d78588644f..e7a7cc56aa 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -148,7 +148,6 @@ static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Intentionally not handling these cases */ @@ -165,7 +164,7 @@ static int eigrp_route_match_delete(struct vty *vty, { enum rmap_compile_rets ret; - ret = route_map_delete_match(index, command, arg); + ret = route_map_delete_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% Can't find rule.\n"); @@ -176,7 +175,6 @@ static int eigrp_route_match_delete(struct vty *vty, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally ignored */ @@ -211,7 +209,6 @@ static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index, } break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally left blank here */ @@ -239,7 +236,6 @@ static int eigrp_route_set_delete(struct vty *vty, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally not handled */ 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/fpm/subdir.am b/fpm/subdir.am index a0fa3d274f..a645ca2b03 100644 --- a/fpm/subdir.am +++ b/fpm/subdir.am @@ -12,9 +12,13 @@ fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm_pb.c \ # end +if FPM +if HAVE_PROTOBUF nodist_fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm.pb-c.c \ # end +endif +endif CLEANFILES += \ fpm/fpm.pb-c.c \ diff --git a/grpc/subdir.am b/grpc/subdir.am index 3fb163fccf..048e12a024 100644 --- a/grpc/subdir.am +++ b/grpc/subdir.am @@ -5,10 +5,12 @@ endif grpc_libfrrgrpc_pb_la_LDFLAGS = -version-info 0:0:0 grpc_libfrrgrpc_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(GRPC_CXXFLAGS) +if GRPC nodist_grpc_libfrrgrpc_pb_la_SOURCES = \ grpc/frr-northbound.pb.cc \ grpc/frr-northbound.grpc.pb.cc \ # end +endif CLEANFILES += \ grpc/frr-northbound.pb.cc \ diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index bc6688012c..232df14e12 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_FIB_RULES_H #define __LINUX_FIB_RULES_H @@ -22,13 +23,23 @@ struct fib_rule_hdr { __u8 tos; __u8 table; - __u8 res1; /* reserved */ + __u8 res1; /* reserved */ __u8 res2; /* reserved */ __u8 action; __u32 flags; }; +struct fib_rule_uid_range { + __u32 start; + __u32 end; +}; + +struct fib_rule_port_range { + __u16 start; + __u16 end; +}; + enum { FRA_UNSPEC, FRA_DST, /* destination address */ @@ -43,7 +54,7 @@ enum { FRA_UNUSED5, FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ - FRA_UNUSED6, + FRA_TUN_ID, FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, /* Extended table id */ @@ -51,6 +62,11 @@ enum { FRA_OIFNAME, FRA_PAD, FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ + FRA_UID_RANGE, /* UID range */ + FRA_PROTOCOL, /* Originator of the rule */ + FRA_IP_PROTO, /* ip proto */ + FRA_SPORT_RANGE, /* sport */ + FRA_DPORT_RANGE, /* dport */ __FRA_MAX }; diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index a924606f36..dfcf3ce009 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -34,6 +34,7 @@ enum { IFA_MULTICAST, IFA_FLAGS, IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + IFA_TARGET_NETNSID, __IFA_MAX, }; @@ -63,7 +64,9 @@ struct ifa_cacheinfo { }; /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif #endif diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 156f4434ca..fb79481cb2 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Linux ethernet bridge * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_IF_BRIDGE_H -#define _LINUX_IF_BRIDGE_H +#ifndef _UAPI_LINUX_IF_BRIDGE_H +#define _UAPI_LINUX_IF_BRIDGE_H #include <linux/types.h> #include <linux/if_ether.h> @@ -96,7 +97,7 @@ struct __fdb_entry { __u32 ageing_timer_value; __u8 port_hi; __u8 pad0; - __u16 unused; + __u16 vlan; }; /* Bridge Flags */ @@ -236,6 +237,7 @@ struct br_mdb_entry { #define MDB_PERMANENT 1 __u8 state; #define MDB_FLAGS_OFFLOAD (1 << 0) +#define MDB_FLAGS_FAST_LEAVE (1 << 1) __u8 flags; __u16 vid; struct { @@ -291,4 +293,4 @@ struct br_mcast_stats { __u64 mcast_bytes[BR_MCAST_DIR_SIZE]; __u64 mcast_packets[BR_MCAST_DIR_SIZE]; }; -#endif /* _LINUX_IF_BRIDGE_H */ +#endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 1f97d0560b..22a45914a2 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_IF_LINK_H -#define _LINUX_IF_LINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_IF_LINK_H +#define _UAPI_LINUX_IF_LINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -158,6 +159,14 @@ enum { IFLA_PAD, IFLA_XDP, IFLA_EVENT, + IFLA_NEW_NETNSID, + IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, + IFLA_NEW_IFINDEX, + IFLA_MIN_MTU, + IFLA_MAX_MTU, __IFLA_MAX }; @@ -165,8 +174,10 @@ enum { #define IFLA_MAX (__IFLA_MAX - 1) /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif enum { IFLA_INET_UNSPEC, @@ -276,6 +287,7 @@ enum { IFLA_BR_MCAST_STATS_ENABLED, IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, __IFLA_BR_MAX, }; @@ -323,6 +335,14 @@ enum { IFLA_BRPORT_MCAST_TO_UCAST, IFLA_BRPORT_VLAN_TUNNEL, IFLA_BRPORT_BCAST_FLOOD, + IFLA_BRPORT_GROUP_FWD_MASK, + IFLA_BRPORT_NEIGH_SUPPRESS, + IFLA_BRPORT_ISOLATED, + IFLA_BRPORT_BACKUP_PORT, + IFLA_BRPORT_PEER_LINK = 60, /* MLAG peer link */ + IFLA_BRPORT_DUAL_LINK, /* MLAG Dual Connected link */ + IFLA_BRPORT_GROUP_FWD_MASKHI, + IFLA_BRPORT_DUAL_LINK_READY, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -448,6 +468,16 @@ enum { #define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + enum macsec_validation_type { MACSEC_VALIDATE_DISABLED = 0, MACSEC_VALIDATE_CHECK = 1, @@ -460,6 +490,7 @@ enum macsec_validation_type { enum { IFLA_IPVLAN_UNSPEC, IFLA_IPVLAN_MODE, + IFLA_IPVLAN_FLAGS, __IFLA_IPVLAN_MAX }; @@ -472,6 +503,9 @@ enum ipvlan_mode { IPVLAN_MODE_MAX }; +#define IPVLAN_F_PRIVATE 0x01 +#define IPVLAN_F_VEPA 0x02 + /* VXLAN section */ enum { IFLA_VXLAN_UNSPEC, @@ -502,6 +536,7 @@ enum { IFLA_VXLAN_COLLECT_METADATA, IFLA_VXLAN_LABEL, IFLA_VXLAN_GPE, + IFLA_VXLAN_TTL_INHERIT, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -585,6 +620,8 @@ enum { IFLA_BOND_AD_USER_PORT_KEY, IFLA_BOND_AD_ACTOR_SYSTEM, IFLA_BOND_TLB_DYNAMIC_LB, + IFLA_BOND_CL_START = 60, + IFLA_BOND_AD_LACP_BYPASS = IFLA_BOND_CL_START, __IFLA_BOND_MAX, }; @@ -612,6 +649,9 @@ enum { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + + IFLA_BOND_SLAVE_CL_START = 50, + IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START, __IFLA_BOND_SLAVE_MAX, }; @@ -721,6 +761,8 @@ enum { IFLA_VF_STATS_BROADCAST, IFLA_VF_STATS_MULTICAST, IFLA_VF_STATS_PAD, + IFLA_VF_STATS_RX_DROPPED, + IFLA_VF_STATS_TX_DROPPED, __IFLA_VF_STATS_MAX, }; @@ -872,6 +914,7 @@ enum { enum { LINK_XSTATS_TYPE_UNSPEC, LINK_XSTATS_TYPE_BRIDGE, + LINK_XSTATS_TYPE_BOND, __LINK_XSTATS_TYPE_MAX }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) @@ -902,6 +945,7 @@ enum { XDP_ATTACHED_DRV, XDP_ATTACHED_SKB, XDP_ATTACHED_HW, + XDP_ATTACHED_MULTI, }; enum { @@ -910,6 +954,9 @@ enum { IFLA_XDP_ATTACHED, IFLA_XDP_FLAGS, IFLA_XDP_PROG_ID, + IFLA_XDP_DRV_PROG_ID, + IFLA_XDP_SKB_PROG_ID, + IFLA_XDP_HW_PROG_ID, __IFLA_XDP_MAX, }; @@ -925,4 +972,43 @@ enum { IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */ }; -#endif /* _LINUX_IF_LINK_H */ +/* tun section */ + +enum { + IFLA_TUN_UNSPEC, + IFLA_TUN_OWNER, + IFLA_TUN_GROUP, + IFLA_TUN_TYPE, + IFLA_TUN_PI, + IFLA_TUN_VNET_HDR, + IFLA_TUN_PERSIST, + IFLA_TUN_MULTI_QUEUE, + IFLA_TUN_NUM_QUEUES, + IFLA_TUN_NUM_DISABLED_QUEUES, + __IFLA_TUN_MAX, +}; + +#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) + +/* rmnet section */ + +#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0) +#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1) +#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2) +#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3) + +enum { + IFLA_RMNET_UNSPEC, + IFLA_RMNET_MUX_ID, + IFLA_RMNET_FLAGS, + __IFLA_RMNET_MAX, +}; + +#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1) + +struct ifla_rmnet_flags { + __u32 flags; + __u32 mask; +}; + +#endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h index 3298426271..de696ca12f 100644 --- a/include/linux/lwtunnel.h +++ b/include/linux/lwtunnel.h @@ -1,5 +1,6 @@ -#ifndef _LWTUNNEL_H_ -#define _LWTUNNEL_H_ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LWTUNNEL_H_ +#define _UAPI_LWTUNNEL_H_ #include <linux/types.h> @@ -67,4 +68,4 @@ enum { #define LWT_BPF_MAX_HEADROOM 256 -#endif /* _LWTUNNEL_H_ */ +#endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h index 1a0e57b45a..521f2e605f 100644 --- a/include/linux/mpls_iptunnel.h +++ b/include/linux/mpls_iptunnel.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * mpls tunnel api * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_MPLS_IPTUNNEL_H -#define _LINUX_MPLS_IPTUNNEL_H +#ifndef _UAPI_LINUX_MPLS_IPTUNNEL_H +#define _UAPI_LINUX_MPLS_IPTUNNEL_H /* MPLS tunnel attributes * [RTA_ENCAP] = { @@ -27,4 +28,4 @@ enum { }; #define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) -#endif /* _LINUX_MPLS_IPTUNNEL_H */ +#endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */ diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h index 3199d28980..cd144e3099 100644 --- a/include/linux/neighbour.h +++ b/include/linux/neighbour.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_NEIGHBOUR_H #define __LINUX_NEIGHBOUR_H @@ -27,6 +28,7 @@ enum { NDA_MASTER, NDA_LINK_NETNSID, NDA_SRC_VNI, + NDA_PROTOCOL, /* Originator of entry */ __NDA_MAX }; @@ -42,6 +44,7 @@ enum { #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_EXT_LEARNED 0x10 #define NTF_OFFLOADED 0x20 +#define NTF_STICKY 0x40 #define NTF_ROUTER 0x80 /* diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h index 9a92b7e14a..0187c74d88 100644 --- a/include/linux/net_namespace.h +++ b/include/linux/net_namespace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* Copyright (c) 2015 6WIND S.A. * Author: Nicolas Dichtel <nicolas.dichtel@6wind.com> * @@ -5,8 +6,8 @@ * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. */ -#ifndef _LINUX_NET_NAMESPACE_H_ -#define _LINUX_NET_NAMESPACE_H_ +#ifndef _UAPI_LINUX_NET_NAMESPACE_H_ +#define _UAPI_LINUX_NET_NAMESPACE_H_ /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ enum { @@ -20,4 +21,4 @@ enum { #define NETNSA_MAX (__NETNSA_MAX - 1) -#endif /* _LINUX_NET_NAMESPACE_H_ */ +#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 0b2c29bd08..750a36be67 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef __LINUX_NETLINK_H -#define __LINUX_NETLINK_H +#ifndef _UAPI__LINUX_NETLINK_H +#define _UAPI__LINUX_NETLINK_H #include <linux/kernel.h> #include <linux/socket.h> /* for __kernel_sa_family_t */ @@ -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 */ @@ -147,12 +147,15 @@ enum nlmsgerr_attrs { #define NETLINK_PKTINFO 3 #define NETLINK_BROADCAST_ERROR 4 #define NETLINK_NO_ENOBUFS 5 +#ifndef __KERNEL__ #define NETLINK_RX_RING 6 #define NETLINK_TX_RING 7 +#endif #define NETLINK_LISTEN_ALL_NSID 8 #define NETLINK_LIST_MEMBERSHIPS 9 #define NETLINK_CAP_ACK 10 #define NETLINK_EXT_ACK 11 +#define NETLINK_GET_STRICT_CHK 12 struct nl_pktinfo { __u32 group; @@ -175,6 +178,7 @@ struct nl_mmap_hdr { __u32 nm_gid; }; +#ifndef __KERNEL__ enum nl_mmap_status { NL_MMAP_STATUS_UNUSED, NL_MMAP_STATUS_RESERVED, @@ -186,6 +190,7 @@ enum nl_mmap_status { #define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO #define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) #define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) +#endif #define NET_MAJOR 36 /* Major 36 is reserved for networking */ @@ -244,4 +249,4 @@ struct nla_bitfield32 { __u32 selector; }; -#endif /* __LINUX_NETLINK_H */ +#endif /* _UAPI__LINUX_NETLINK_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 813e9e0767..eddbc04504 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -1,5 +1,6 @@ -#ifndef __LINUX_RTNETLINK_H -#define __LINUX_RTNETLINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI__LINUX_RTNETLINK_H +#define _UAPI__LINUX_RTNETLINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -149,6 +150,20 @@ enum { RTM_NEWCACHEREPORT = 96, #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + RTM_NEWCHAIN = 100, +#define RTM_NEWCHAIN RTM_NEWCHAIN + RTM_DELCHAIN, +#define RTM_DELCHAIN RTM_DELCHAIN + RTM_GETCHAIN, +#define RTM_GETCHAIN RTM_GETCHAIN + + RTM_NEWNEXTHOP = 104, +#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP + RTM_DELNEXTHOP, +#define RTM_DELNEXTHOP RTM_DELNEXTHOP + RTM_GETNEXTHOP, +#define RTM_GETNEXTHOP RTM_GETNEXTHOP + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -157,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. @@ -197,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; @@ -253,6 +268,11 @@ enum { #define RTPROT_DHCP 16 /* DHCP client */ #define RTPROT_MROUTED 17 /* Multicast daemon */ #define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_BGP 186 /* BGP Routes */ +#define RTPROT_ISIS 187 /* ISIS Routes */ +#define RTPROT_OSPF 188 /* OSPF Routes */ +#define RTPROT_RIP 189 /* RIP Routes */ +#define RTPROT_EIGRP 192 /* EIGRP Routes */ /* rtm_scope @@ -326,6 +346,10 @@ enum rtattr_type_t { RTA_PAD, RTA_UID, RTA_TTL_PROPAGATE, + RTA_IP_PROTO, + RTA_SPORT, + RTA_DPORT, + RTA_NH_ID, __RTA_MAX }; @@ -430,6 +454,8 @@ enum { #define RTAX_QUICKACK RTAX_QUICKACK RTAX_CC_ALGO, #define RTAX_CC_ALGO RTAX_CC_ALGO + RTAX_FASTOPEN_NO_COOKIE, +#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE __RTAX_MAX }; @@ -497,7 +523,7 @@ struct ifinfomsg { }; /******************************************************************** - * prefix information + * prefix information ****/ struct prefixmsg { @@ -511,7 +537,7 @@ struct prefixmsg { unsigned char prefix_pad3; }; -enum +enum { PREFIX_UNSPEC, PREFIX_ADDRESS, @@ -538,9 +564,19 @@ struct tcmsg { int tcm_ifindex; __u32 tcm_handle; __u32 tcm_parent; +/* tcm_block_index is used instead of tcm_parent + * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK + */ +#define tcm_block_index tcm_parent __u32 tcm_info; }; +/* For manipulation of filters in shared block, tcm_ifindex is set to + * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index + * which is the block index. + */ +#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) + enum { TCA_UNSPEC, TCA_KIND, @@ -554,6 +590,9 @@ enum { TCA_PAD, TCA_DUMP_INVISIBLE, TCA_CHAIN, + TCA_HW_OFFLOAD, + TCA_INGRESS_BLOCK, + TCA_EGRESS_BLOCK, __TCA_MAX }; @@ -586,6 +625,7 @@ enum { #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) +#ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 #define RTMGRP_NOTIFY 2 @@ -606,6 +646,7 @@ enum { #define RTMGRP_DECnet_ROUTE 0x4000 #define RTMGRP_IPV6_PREFIX 0x20000 +#endif /* RTnetlink multicast groups */ enum rtnetlink_groups { @@ -671,6 +712,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV6_MROUTE_R, #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R + RTNLGRP_NEXTHOP, +#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) @@ -715,4 +758,4 @@ enum { -#endif /* __LINUX_RTNETLINK_H */ +#endif /* _UAPI__LINUX_RTNETLINK_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 8c1e501774..8eb9602170 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_SOCKET_H -#define _LINUX_SOCKET_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_SOCKET_H +#define _UAPI_LINUX_SOCKET_H /* * Desired design of maximum size and alignment (see RFC2553) @@ -18,4 +19,4 @@ struct __kernel_sockaddr_storage { /* _SS_MAXSIZE value minus size of ss_family */ } __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */ -#endif /* _LINUX_SOCKET_H */ +#endif /* _UAPI_LINUX_SOCKET_H */ diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 9b368cc404..d2ec6ff566 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -254,6 +254,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, reason ? reason : "unspecified"); } + circuit->adj_state_changes++; #ifndef FABRICD /* send northbound notification */ isis_notif_adj_state_change(adj, new_state, reason); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 8d008d78bd..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. */ @@ -135,8 +137,6 @@ struct isis_circuit *isis_circuit_new(void) } #endif /* ifndef FABRICD */ - circuit->mtc = mpls_te_circuit_new(); - circuit_mt_init(circuit); QOBJ_REG(circuit, isis_circuit); @@ -266,8 +266,11 @@ void isis_circuit_add_addr(struct isis_circuit *circuit, ipv4->prefix = connected->address->u.prefix4; listnode_add(circuit->ip_addrs, ipv4); - /* Update MPLS TE Local IP address parameter */ - set_circuitparams_local_ipaddr(circuit->mtc, ipv4->prefix); + /* Update Local IP address parameter if MPLS TE is enable */ + if (circuit->ext && IS_MPLS_TE(circuit->ext)) { + circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr; + SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR); + } if (circuit->area) lsp_regenerate_schedule(circuit->area, circuit->is_type, @@ -478,6 +481,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) isis_circuit_add_addr(circuit, conn); + } void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) @@ -521,7 +525,6 @@ void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp) assert(ifp->info == circuit); else ifp->info = circuit; - isis_link_params_update(circuit, ifp); } void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp) @@ -1388,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 */ @@ -1397,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 2371c0b73a..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 { @@ -121,7 +123,7 @@ struct isis_circuit { uint16_t psnp_interval[2]; /* psnp-interval in seconds */ uint8_t metric[2]; uint32_t te_metric[2]; - struct mpls_te_circuit *mtc; /* MPLS-TE parameters */ + struct isis_ext_subtlvs *ext; /* Extended parameters (TE + Adj SID */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *mt_settings; /* IS-IS MT Settings */ @@ -144,6 +146,13 @@ struct isis_circuit { uint32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */ uint32_t rej_adjacencies; /* rejectedAdjacencies */ + /* + * Counters as in ietf-isis@2019-09-09.yang + */ + uint32_t id_len_mismatches; /* id-len-mismatch */ + uint32_t max_area_addr_mismatches; /* max-area-addresses-mismatch */ + uint32_t auth_type_failures; /*authentication-type-fails */ + uint32_t auth_failures; /* authentication-fails */ QOBJ_FIELDS }; diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index bd06286755..37f4dcfabd 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -188,14 +188,10 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag", } /* check if the interface is a loopback and if so set it as passive */ - pthread_rwlock_rdlock(&running_config->lock); - { - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); - } - pthread_rwlock_unlock(&running_config->lock); + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (ifp && if_is_loopback(ifp)) + nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", + NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -262,14 +258,10 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag", } /* check if the interface is a loopback and if so set it as passive */ - pthread_rwlock_rdlock(&running_config->lock); - { - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); - } - pthread_rwlock_unlock(&running_config->lock); + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (ifp && if_is_loopback(ifp)) + nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", + NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -410,26 +402,20 @@ DEFPY(no_is_type, no_is_type_cmd, "Act as both a station router and an area router\n" "Act as an area router only\n") { - const char *value; - - pthread_rwlock_rdlock(&running_config->lock); - { - struct isis_area *area; + const char *value = NULL; + struct isis_area *area; - area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - - /* - * Put the is-type back to defaults: - * - level-1-2 on first area - * - level-1 for the rest - */ - if (area && listgetdata(listhead(isis->area_list)) == area) - value = "level-1-2"; - else - value = NULL; - } - pthread_rwlock_unlock(&running_config->lock); + area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + /* + * Put the is-type back to defaults: + * - level-1-2 on first area + * - level-1 for the rest + */ + if (area && listgetdata(listhead(isis->area_list)) == area) + value = "level-1-2"; + else + value = NULL; nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); @@ -1817,45 +1803,52 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd, "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { - const char *circ_type = NULL; + struct interface *ifp; + struct isis_circuit *circuit; + int is_type; + const char *circ_type; /* * Default value depends on whether the circuit is part of an area, * and the is-type of the area if there is one. So we need to do this * here. */ - pthread_rwlock_rdlock(&running_config->lock); - { - struct interface *ifp; - struct isis_circuit *circuit; + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (!ifp) + goto def_val; - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (!ifp) - goto unlock; + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + goto def_val; - circuit = circuit_scan_by_ifp(ifp); - if (!circuit || circuit->state != C_STATE_UP) - goto unlock; + if (circuit->state == C_STATE_UP) + is_type = circuit->area->is_type; + else + goto def_val; - switch (circuit->area->is_type) { - case IS_LEVEL_1: - circ_type = "level-1"; - break; - case IS_LEVEL_2: - circ_type = "level-2"; - break; - case IS_LEVEL_1_AND_2: - circ_type = "level-1-2"; - break; - } + switch (is_type) { + case IS_LEVEL_1: + circ_type = "level-1"; + break; + case IS_LEVEL_2: + circ_type = "level-2"; + break; + case IS_LEVEL_1_AND_2: + circ_type = "level-1-2"; + break; + default: + return CMD_ERR_NO_MATCH; } -unlock: - pthread_rwlock_unlock(&running_config->lock); - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY, circ_type); return nb_cli_apply_changes(vty, NULL); + +def_val: + nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", + NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); } void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 4b29e6dc7e..061e758831 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -52,9 +52,9 @@ #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" -#include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_tlvs.h" +#include "isisd/isis_te.h" #include "isisd/fabricd.h" #include "isisd/isis_tx_queue.h" @@ -781,8 +781,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, if (!rn->info) continue; struct isis_ext_info *info = rn->info; - struct prefix_ipv6 *p, *src_p; + srcdest_rnode_prefixes(rn, (const struct prefix **)&p, (const struct prefix **)&src_p); @@ -863,6 +863,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) /* Protocols Supported */ if (area->ip_circuits > 0 || area->ipv6_circuits > 0) { struct nlpids nlpids = {.count = 0}; + if (area->ip_circuits > 0) { lsp_debug( "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", @@ -908,10 +909,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag); } - /* IPv4 address and TE router ID TLVs. In case of the first one we don't - * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put - * into - * LSP and this address is same as router id. */ + /* IPv4 address and TE router ID TLVs. + * In case of the first one we don't follow "C" vendor, + * but "J" vendor behavior - one IPv4 address is put + * into LSP. TE router ID will be the same if MPLS-TE + * is not activate or MPLS-TE router-id not specified + */ if (isis->router_id != 0) { struct in_addr id = {.s_addr = isis->router_id}; inet_ntop(AF_INET, &id, buf, sizeof(buf)); @@ -919,11 +922,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag, buf); isis_tlvs_add_ipv4_address(lsp->tlvs, &id); - /* Exactly same data is put into TE router ID TLV, but only if - * new style - * TLV's are in use. */ + /* If new style TLV's are in use, add TE router ID TLV + * Check if MPLS-TE is activate and mpls-te router-id set + * otherwise add exactly same data as for IPv4 address + */ if (area->newmetric) { - + if (IS_MPLS_TE(area->mta) + && area->mta->router_id.s_addr != 0) + id.s_addr = area->mta->router_id.s_addr; lsp_debug( "ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); @@ -1004,6 +1010,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) && circuit->ipv6_non_link->count > 0) { struct listnode *ipnode; struct prefix_ipv6 *ipv6; + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, ipnode, ipv6)) { lsp_debug( @@ -1036,25 +1043,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } - if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface - && HAS_LINK_PARAMS( - circuit->interface)) - subtlv_len = add_te_subtlvs( - subtlvs, - circuit->mtc); - else - subtlv_len = 0; - + if (area->newmetric) tlvs_add_mt_bcast( lsp->tlvs, circuit, - level, ne_id, metric, - subtlvs, subtlv_len); - } + level, ne_id, metric); } } else { lsp_debug( @@ -1079,36 +1071,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface != NULL - && HAS_LINK_PARAMS( - circuit->interface)) - /* Update Local and Remote IP - * address for MPLS TE circuit - * parameters */ - /* NOTE sure that it is the - * pertinent place for that - * updates */ - /* Local IP address could be - * updated in isis_circuit.c - - * isis_circuit_add_addr() */ - /* But, where update remote IP - * address ? in isis_pdu.c - - * process_p2p_hello() ? */ - - /* Add SubTLVs & Adjust real - * size of SubTLVs */ - subtlv_len = add_te_subtlvs( - subtlvs, circuit->mtc); - else - /* Or keep only TE metric with - * no SubTLVs if MPLS_TE is off - */ - subtlv_len = 0; - uint32_t neighbor_metric; if (fabricd_tier(area) == 0) { neighbor_metric = 0xffe; @@ -1117,8 +1079,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } tlvs_add_mt_p2p(lsp->tlvs, circuit, - ne_id, neighbor_metric, - subtlvs, subtlv_len); + ne_id, neighbor_metric); } } else { lsp_debug( @@ -1512,7 +1473,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, } if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (self)", area->area_tag, sysid_print(ne_id), @@ -1554,7 +1515,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", area->area_tag, sysid_print(ne_id), diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 7f49e9d89a..718924daf2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -243,7 +243,7 @@ int main(int argc, char **argv, char **envp) mt_init(); /* create the global 'isis' instance */ - isis_new(1); + isis_new(1, VRF_DEFAULT); isis_zebra_init(master); isis_bfd_init(); diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index f7d4c7170f..36413bac59 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -511,8 +511,8 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level, static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, unsigned int mt_count, uint16_t *mt_set, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric, + struct isis_ext_subtlvs *ext) { for (unsigned int i = 0; i < mt_count; i++) { uint16_t mtid = mt_set[i]; @@ -527,30 +527,27 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, area->area_tag, sysid_print(id), LSP_PSEUDO_ID(id), isis_mtid2str(mtid)); } - isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs, - subtlv_len); + isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, ext); } } void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len) + int level, uint8_t *id, uint32_t metric) { unsigned int mt_count; uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count); tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric, - subtlvs, subtlv_len); + circuit->ext); } void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id, - metric, subtlvs, subtlv_len); + metric, circuit->ext); } void mt_init(void) diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 515b63f50f..b40139c50a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -116,10 +116,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid); void adj_mt_finish(struct isis_adjacency *adj); void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len); + int level, uint8_t *id, uint32_t metric); void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len); + uint8_t *id, uint32_t metric); void mt_init(void); #endif diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index c1b630eb2d..1e21efa7ce 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -49,6 +49,23 @@ #include "lib/vrf.h" /* + * Helper functions. + */ +static const char *isis_yang_adj_state(enum isis_adj_state state) +{ + switch (state) { + case ISIS_ADJ_DOWN: + return "down"; + case ISIS_ADJ_UP: + return "up"; + case ISIS_ADJ_INITIALIZING: + return "init"; + default: + return "failed"; + } +} + +/* * XPath: /frr-isisd:isis/instance */ static int isis_instance_create(enum nb_event event, @@ -1384,7 +1401,7 @@ static int isis_instance_mpls_te_create(enum nb_event event, struct mpls_te_area *new; - zlog_debug("ISIS MPLS-TE: Initialize area %s", + zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering", area->area_tag); new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area)); @@ -1410,12 +1427,12 @@ static int isis_instance_mpls_te_create(enum nb_event event, * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || IS_FLOOD_AS(circuit->mtc->type)) + if (circuit->ext == NULL) continue; - if (!IS_MPLS_TE(circuit->mtc) + if (!IS_EXT_TE(circuit->ext) && HAS_LINK_PARAMS(circuit->interface)) - circuit->mtc->status = enable; + isis_link_params_update(circuit, circuit->interface); else continue; @@ -1446,11 +1463,16 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, /* Flush LSP if circuit engage */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || (circuit->mtc->status == disable)) + if (!IS_EXT_TE(circuit->ext)) continue; - /* disable MPLS_TE Circuit */ - circuit->mtc->status = disable; + /* disable MPLS_TE Circuit keeping SR one's */ + if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID)) + circuit->ext->status = EXT_ADJ_SID; + else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID)) + circuit->ext->status = EXT_LAN_ADJ_SID; + else + circuit->ext->status = 0; /* Re-originate circuit without STD_TE & GMPLS parameters */ if (circuit->area) @@ -1458,6 +1480,9 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, 0); } + zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering", + area->area_tag); + return NB_OK; } @@ -1534,9 +1559,9 @@ static int lib_interface_isis_create(enum nb_event event, /* check if interface mtu is sufficient. If the area has not * been created yet, assume default MTU for the area */ - ifp = nb_running_get_entry(dnode, NULL, true); + ifp = nb_running_get_entry(dnode, NULL, false); /* zebra might not know yet about the MTU - nothing we can do */ - if (ifp->mtu == 0) + if (!ifp || ifp->mtu == 0) break; actual_mtu = if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu; @@ -2296,6 +2321,368 @@ static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify( } /* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency + */ +static const void * +lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj, *adj_next = NULL; + struct list *list; + struct listnode *node, *node_next; + + /* Get first adjacency. */ + if (list_entry == NULL) { + ifp = (struct interface *)parent_list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; + level++) { + adj = listnode_head( + circuit->u.bc.adjdb[level - 1]); + if (adj) + break; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + break; + default: + adj = NULL; + break; + } + + return adj; + } + + /* Get next adjacency. */ + adj = (struct isis_adjacency *)list_entry; + circuit = adj->circuit; + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + list = circuit->u.bc.adjdb[adj->level - 1]; + node = listnode_lookup(list, adj); + node_next = listnextnode(node); + if (node_next) + adj_next = listgetdata(node_next); + else if (adj->level == ISIS_LEVEL1) { + /* + * Once we finish the L1 adjacencies, move to the L2 + * adjacencies list. + */ + list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1]; + adj_next = listnode_head(list); + } + break; + case CIRCUIT_T_P2P: + /* P2P circuits have at most one adjacency. */ + default: + break; + } + + return adj_next; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_enum(xpath, adj->level); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, sysid_print(adj->sysid)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint32(xpath, adj->circuit->circuit_id); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, snpa_print(adj->snpa)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint16(xpath, adj->hold_time); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath, + const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_changes_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->adj_state_changes); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_number_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj; + struct listnode *node; + uint32_t total = 0; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + /* + * TODO: keep track of the number of adjacencies instead of calculating + * it on demand. + */ + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + for (ALL_LIST_ELEMENTS_RO( + circuit->u.bc.adjdb[level - 1], node, adj)) + total++; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + if (adj) + total = 1; + break; + default: + break; + } + + return yang_data_new_uint32(xpath, total); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->init_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_rejects_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->rej_adjacencies); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_id_len_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->id_len_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_type_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_type_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_failures); +} + +/* * NOTIFICATIONS */ static void notif_prep_instance_hdr(const char *xpath, @@ -2537,19 +2924,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj, listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath); - switch (new_state) { - case ISIS_ADJ_DOWN: - data = yang_data_new_string(xpath_arg, "down"); - break; - case ISIS_ADJ_UP: - data = yang_data_new_string(xpath_arg, "up"); - break; - case ISIS_ADJ_INITIALIZING: - data = yang_data_new_string(xpath_arg, "init"); - break; - default: - data = yang_data_new_string(xpath_arg, "failed"); - } + data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state)); listnode_add(arguments, data); if (new_state == ISIS_ADJ_DOWN) { snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath); @@ -3476,6 +3851,102 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency", + .cbs = { + .get_next = lib_interface_isis_adjacencies_adjacency_get_next, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_init_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem, + } + }, + { .xpath = NULL, }, } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 3d16d56016..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 */ @@ -199,13 +199,6 @@ static int process_p2p_hello(struct iih_info *iih) changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, adj); - /* Update MPLS TE Remote IP address parameter if possible */ - if (IS_MPLS_TE(iih->circuit->area->mta) - && IS_MPLS_TE(iih->circuit->mtc) - && adj->ipv4_address_count) - set_circuitparams_rmt_ipaddr(iih->circuit->mtc, - adj->ipv4_addresses[0]); - /* lets take care of the expiry */ THREAD_TIMER_OFF(adj->t_expire); thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, @@ -583,6 +576,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (p2p_hello) { if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn("p2p hello on non p2p circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "p2p hello on non p2p circuit", @@ -593,6 +587,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, } else { if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("lan hello on non broadcast circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "lan hello on non broadcast circuit", @@ -605,6 +600,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_debug( "level %d LAN Hello received over circuit with externalDomain = true", level); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, @@ -621,6 +617,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, circuit->area->area_tag, circuit->interface->name); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Interface level mismatch", raw_pdu); @@ -650,6 +647,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16, circuit->area->area_tag, pdu_name, circuit->interface->name, iih.pdu_len); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Invalid PDU length", raw_pdu); @@ -661,6 +659,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, flog_err(EC_ISIS_PACKET, "Level %d LAN Hello with Circuit Type %d", level, iih.circ_type); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "LAN Hello with wrong IS-level", raw_pdu); @@ -674,6 +673,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), circuit->rcv_stream, &iih.tlvs, &error_log)) { zlog_warn("isis_unpack_tlvs() failed: %s", error_log); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs", raw_pdu); @@ -692,6 +692,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (!iih.tlvs->protocols_supported.count) { zlog_warn("No supported protocols TLV in %s", pdu_name); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "No supported protocols TLV", raw_pdu); @@ -709,11 +710,14 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -722,6 +726,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_warn( "ISIS-Adj (%s): Received IIH with own sysid - discard", circuit->area->area_tag); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Received IIH with our own sysid", raw_pdu); @@ -759,6 +764,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH", circuit->area->area_tag); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Neither IPv4 not IPv6 considered usable", @@ -947,11 +953,14 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, hdr.lsp_id); #ifndef FABRICD /* send northbound notification */ - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1380,12 +1389,15 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1621,6 +1633,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8 ", while the parameter for this IS is %u", id_len, ISIS_SYS_ID_LEN); + circuit->id_len_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_id_len_mismatch(circuit, id_len, raw_pdu); @@ -1673,6 +1686,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8 " while the parameter for this IS is %u", max_area_addrs, isis->max_area_addrs); + circuit->max_area_addr_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_max_area_addr_mismatch(circuit, max_area_addrs, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 636a63e290..05394e0fe4 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -49,8 +49,16 @@ #include "isis_route.h" #include "isis_zebra.h" +DEFINE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family, union g_addr *ip, ifindex_t ifindex); +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip, ifindex_t ifindex) @@ -316,7 +324,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, return route_info; } -static void isis_route_delete(struct route_node *rode, +static void isis_route_delete(struct isis_area *area, struct route_node *rode, struct route_table *table) { struct isis_route_info *rinfo; @@ -343,13 +351,37 @@ static void isis_route_delete(struct route_node *rode, UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug("ISIS-Rte: route delete %s", buff); - isis_zebra_route_update(prefix, src_p, rinfo); + isis_route_update(area, prefix, src_p, rinfo); } isis_route_info_delete(rinfo); rode->info = NULL; route_unlock_node(rode); } +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) +{ + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_add_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + } else { + if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_del_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + } +} + static void _isis_route_verify_table(struct isis_area *area, struct route_table *table, struct route_table **tables) @@ -390,7 +422,7 @@ static void _isis_route_verify_table(struct isis_area *area, buff); } - isis_zebra_route_update(dst_p, src_p, rinfo); + isis_route_update(area, dst_p, src_p, rinfo); if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) continue; @@ -399,7 +431,7 @@ static void _isis_route_verify_table(struct isis_area *area, * directly for * validating => no problems with deleting routes. */ if (!tables) { - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); continue; } @@ -422,7 +454,7 @@ static void _isis_route_verify_table(struct isis_area *area, route_unlock_node(drnode); } - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); } } diff --git a/isisd/isis_route.h b/isisd/isis_route.h index a20a7e038f..2326bb8228 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -44,6 +44,11 @@ struct isis_route_info { struct list *nexthops; }; +DECLARE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + struct isis_route_info *isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p, uint32_t cost, diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 4ea6c2c60d..9871d2bcb9 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -3,8 +3,9 @@ * * This is an implementation of RFC5305 & RFC 7810 * - * Copyright (C) 2014 Orange Labs - * http://www.orange.com + * Author: Olivier Dugeon <olivier.dugeon@orange.com> + * + * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com * * This file is part of GNU Zebra. * @@ -47,6 +48,7 @@ #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" +#include "isisd/isis_adjacency.h" #include "isisd/isisd.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" @@ -56,6 +58,7 @@ #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_te.h" +#include "isisd/isis_zebra.h" const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; @@ -63,424 +66,6 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ -/* Create new MPLS TE Circuit context */ -struct mpls_te_circuit *mpls_te_circuit_new(void) -{ - struct mpls_te_circuit *mtc; - - zlog_debug("ISIS MPLS-TE: Create new MPLS TE Circuit context"); - - mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_circuit)); - - mtc->status = disable; - mtc->type = STD_TE; - mtc->length = 0; - - return mtc; -} - -/* Copy SUB TLVs parameters into a buffer - No space verification are performed - */ -/* Caller must verify before that there is enough free space in the buffer */ -uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc) -{ - uint8_t size, *tlvs = buf; - - zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); - - if (mtc == NULL) { - zlog_debug( - "ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified"); - return 0; - } - - /* Create buffer if not provided */ - if (buf == NULL) { - zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified"); - return 0; - } - - /* TE_SUBTLV_ADMIN_GRP */ - if (SUBTLV_TYPE(mtc->admin_grp) != 0) { - size = SUBTLV_SIZE(&(mtc->admin_grp.header)); - memcpy(tlvs, &(mtc->admin_grp), size); - tlvs += size; - } - - /* TE_SUBTLV_LLRI */ - if (SUBTLV_TYPE(mtc->llri) != 0) { - size = SUBTLV_SIZE(&(mtc->llri.header)); - memcpy(tlvs, &(mtc->llri), size); - tlvs += size; - } - - /* TE_SUBTLV_LCLIF_IPADDR */ - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) { - size = SUBTLV_SIZE(&(mtc->local_ipaddr.header)); - memcpy(tlvs, &(mtc->local_ipaddr), size); - tlvs += size; - } - - /* TE_SUBTLV_RMTIF_IPADDR */ - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) { - size = SUBTLV_SIZE(&(mtc->rmt_ipaddr.header)); - memcpy(tlvs, &(mtc->rmt_ipaddr), size); - tlvs += size; - } - - /* TE_SUBTLV_MAX_BW */ - if (SUBTLV_TYPE(mtc->max_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->max_bw.header)); - memcpy(tlvs, &(mtc->max_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_MAX_RSV_BW */ - if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->max_rsv_bw.header)); - memcpy(tlvs, &(mtc->max_rsv_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_UNRSV_BW */ - if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->unrsv_bw.header)); - memcpy(tlvs, &(mtc->unrsv_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_TE_METRIC */ - if (SUBTLV_TYPE(mtc->te_metric) != 0) { - size = SUBTLV_SIZE(&(mtc->te_metric.header)); - memcpy(tlvs, &(mtc->te_metric), size); - tlvs += size; - } - - /* TE_SUBTLV_AV_DELAY */ - if (SUBTLV_TYPE(mtc->av_delay) != 0) { - size = SUBTLV_SIZE(&(mtc->av_delay.header)); - memcpy(tlvs, &(mtc->av_delay), size); - tlvs += size; - } - - /* TE_SUBTLV_MM_DELAY */ - if (SUBTLV_TYPE(mtc->mm_delay) != 0) { - size = SUBTLV_SIZE(&(mtc->mm_delay.header)); - memcpy(tlvs, &(mtc->mm_delay), size); - tlvs += size; - } - - /* TE_SUBTLV_DELAY_VAR */ - if (SUBTLV_TYPE(mtc->delay_var) != 0) { - size = SUBTLV_SIZE(&(mtc->delay_var.header)); - memcpy(tlvs, &(mtc->delay_var), size); - tlvs += size; - } - - /* TE_SUBTLV_PKT_LOSS */ - if (SUBTLV_TYPE(mtc->pkt_loss) != 0) { - size = SUBTLV_SIZE(&(mtc->pkt_loss.header)); - memcpy(tlvs, &(mtc->pkt_loss), size); - tlvs += size; - } - - /* TE_SUBTLV_RES_BW */ - if (SUBTLV_TYPE(mtc->res_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->res_bw.header)); - memcpy(tlvs, &(mtc->res_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_AVA_BW */ - if (SUBTLV_TYPE(mtc->ava_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->ava_bw.header)); - memcpy(tlvs, &(mtc->ava_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_USE_BW */ - if (SUBTLV_TYPE(mtc->use_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->use_bw.header)); - memcpy(tlvs, &(mtc->use_bw), size); - tlvs += size; - } - - /* Add before this line any other parsing of TLV */ - (void)tlvs; - - /* Update SubTLVs length */ - mtc->length = subtlvs_len(mtc); - - zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length); - - return mtc->length; -} - -/* Compute total Sub-TLVs size */ -uint8_t subtlvs_len(struct mpls_te_circuit *mtc) -{ - int length = 0; - - /* Sanity Check */ - if (mtc == NULL) - return 0; - - /* TE_SUBTLV_ADMIN_GRP */ - if (SUBTLV_TYPE(mtc->admin_grp) != 0) - length += SUBTLV_SIZE(&(mtc->admin_grp.header)); - - /* TE_SUBTLV_LLRI */ - if (SUBTLV_TYPE(mtc->llri) != 0) - length += SUBTLV_SIZE(&mtc->llri.header); - - /* TE_SUBTLV_LCLIF_IPADDR */ - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) - length += SUBTLV_SIZE(&mtc->local_ipaddr.header); - - /* TE_SUBTLV_RMTIF_IPADDR */ - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) - length += SUBTLV_SIZE(&mtc->rmt_ipaddr.header); - - /* TE_SUBTLV_MAX_BW */ - if (SUBTLV_TYPE(mtc->max_bw) != 0) - length += SUBTLV_SIZE(&mtc->max_bw.header); - - /* TE_SUBTLV_MAX_RSV_BW */ - if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) - length += SUBTLV_SIZE(&mtc->max_rsv_bw.header); - - /* TE_SUBTLV_UNRSV_BW */ - if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) - length += SUBTLV_SIZE(&mtc->unrsv_bw.header); - - /* TE_SUBTLV_TE_METRIC */ - if (SUBTLV_TYPE(mtc->te_metric) != 0) - length += SUBTLV_SIZE(&mtc->te_metric.header); - - /* TE_SUBTLV_AV_DELAY */ - if (SUBTLV_TYPE(mtc->av_delay) != 0) - length += SUBTLV_SIZE(&mtc->av_delay.header); - - /* TE_SUBTLV_MM_DELAY */ - if (SUBTLV_TYPE(mtc->mm_delay) != 0) - length += SUBTLV_SIZE(&mtc->mm_delay.header); - - /* TE_SUBTLV_DELAY_VAR */ - if (SUBTLV_TYPE(mtc->delay_var) != 0) - length += SUBTLV_SIZE(&mtc->delay_var.header); - - /* TE_SUBTLV_PKT_LOSS */ - if (SUBTLV_TYPE(mtc->pkt_loss) != 0) - length += SUBTLV_SIZE(&mtc->pkt_loss.header); - - /* TE_SUBTLV_RES_BW */ - if (SUBTLV_TYPE(mtc->res_bw) != 0) - length += SUBTLV_SIZE(&mtc->res_bw.header); - - /* TE_SUBTLV_AVA_BW */ - if (SUBTLV_TYPE(mtc->ava_bw) != 0) - length += SUBTLV_SIZE(&mtc->ava_bw.header); - - /* TE_SUBTLV_USE_BW */ - if (SUBTLV_TYPE(mtc->use_bw) != 0) - length += SUBTLV_SIZE(&mtc->use_bw.header); - - /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */ - if (length > MAX_SUBTLV_SIZE) { - mtc->length = 0; - return 0; - } - - mtc->length = (uint8_t)length; - - return mtc->length; -} - -/* Following are various functions to set MPLS TE parameters */ -static void set_circuitparams_admin_grp(struct mpls_te_circuit *mtc, - uint32_t admingrp) -{ - SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP; - SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE; - mtc->admin_grp.value = htonl(admingrp); - return; -} - -static void __attribute__((unused)) -set_circuitparams_llri(struct mpls_te_circuit *mtc, uint32_t local, - uint32_t remote) -{ - SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI; - SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE; - mtc->llri.local = htonl(local); - mtc->llri.remote = htonl(remote); -} - -void set_circuitparams_local_ipaddr(struct mpls_te_circuit *mtc, - struct in_addr addr) -{ - - SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR; - SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE; - mtc->local_ipaddr.value.s_addr = addr.s_addr; - return; -} - -void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *mtc, - struct in_addr addr) -{ - - SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR; - SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE; - mtc->rmt_ipaddr.value.s_addr = addr.s_addr; - return; -} - -static void set_circuitparams_max_bw(struct mpls_te_circuit *mtc, float fp) -{ - SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW; - SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE; - mtc->max_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_max_rsv_bw(struct mpls_te_circuit *mtc, float fp) -{ - SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW; - SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE; - mtc->max_rsv_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_unrsv_bw(struct mpls_te_circuit *mtc, - int priority, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW; - SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE; - mtc->unrsv_bw.value[priority] = htonf(fp); - return; -} - -static void set_circuitparams_te_metric(struct mpls_te_circuit *mtc, - uint32_t te_metric) -{ - SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC; - SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE; - mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF; - mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF; - mtc->te_metric.value[2] = te_metric & 0xFF; - return; -} - -static void set_circuitparams_inter_as(struct mpls_te_circuit *mtc, - struct in_addr addr, uint32_t as) -{ - - /* Set the Remote ASBR IP address and then the associated AS number */ - SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP; - SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE; - mtc->rip.value.s_addr = addr.s_addr; - - SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS; - SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE; - mtc->ras.value = htonl(as); -} - -static void unset_circuitparams_inter_as(struct mpls_te_circuit *mtc) -{ - - /* Reset the Remote ASBR IP address and then the associated AS number */ - SUBTLV_TYPE(mtc->rip) = 0; - SUBTLV_LEN(mtc->rip) = 0; - mtc->rip.value.s_addr = 0; - - SUBTLV_TYPE(mtc->ras) = 0; - SUBTLV_LEN(mtc->ras) = 0; - mtc->ras.value = 0; -} - -static void set_circuitparams_av_delay(struct mpls_te_circuit *mtc, - uint32_t delay, uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY; - SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE; - tmp = delay & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->av_delay.value = htonl(tmp); - return; -} - -static void set_circuitparams_mm_delay(struct mpls_te_circuit *mtc, - uint32_t low, uint32_t high, - uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY; - SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE; - tmp = low & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->mm_delay.low = htonl(tmp); - mtc->mm_delay.high = htonl(high); - return; -} - -static void set_circuitparams_delay_var(struct mpls_te_circuit *mtc, - uint32_t jitter) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR; - SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE; - mtc->delay_var.value = htonl(jitter & TE_EXT_MASK); - return; -} - -static void set_circuitparams_pkt_loss(struct mpls_te_circuit *mtc, - uint32_t loss, uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS; - SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE; - tmp = loss & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->pkt_loss.value = htonl(tmp); - return; -} - -static void set_circuitparams_res_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW; - SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE; - mtc->res_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_ava_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW; - SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE; - mtc->ava_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_use_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW; - SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE; - mtc->use_bw.value = htonf(fp); - return; -} - /* Main initialization / update function of the MPLS TE Circuit context */ /* Call when interface TE Link parameters are modified */ void isis_link_params_update(struct isis_circuit *circuit, @@ -488,155 +73,222 @@ void isis_link_params_update(struct isis_circuit *circuit, { int i; struct prefix_ipv4 *addr; - struct mpls_te_circuit *mtc; + struct prefix_ipv6 *addr6; + struct isis_ext_subtlvs *ext; + + /* Check if TE is enable or not */ + if (!circuit->area || !IS_MPLS_TE(circuit->area->mta)) + return; /* Sanity Check */ - if ((circuit == NULL) || (ifp == NULL)) + if ((ifp == NULL) || (circuit->state != C_STATE_UP)) return; - zlog_info("MPLS-TE: Initialize circuit parameters for interface %s", - ifp->name); + zlog_debug("TE(%s): Update circuit parameters for interface %s", + circuit->area->area_tag, ifp->name); /* Check if MPLS TE Circuit context has not been already created */ - if (circuit->mtc == NULL) - circuit->mtc = mpls_te_circuit_new(); + if (circuit->ext == NULL) { + circuit->ext = isis_alloc_ext_subtlvs(); + zlog_debug(" |- Allocated new Ext-subTLVs for interface %s", + ifp->name); + } - mtc = circuit->mtc; + ext = circuit->ext; - /* Fulfil MTC TLV from ifp TE Link parameters */ + /* Fulfill Extended subTLVs from interface link parameters */ if (HAS_LINK_PARAMS(ifp)) { - mtc->status = enable; /* STD_TE metrics */ - if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) - set_circuitparams_admin_grp( - mtc, ifp->link_params->admin_grp); - else - SUBTLV_TYPE(mtc->admin_grp) = 0; - - /* If not already set, register local IP addr from ip_addr list - * if it exists */ - if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) { - if (circuit->ip_addrs != NULL - && listcount(circuit->ip_addrs) != 0) { - addr = (struct prefix_ipv4 *)listgetdata( - (struct listnode *)listhead( - circuit->ip_addrs)); - set_circuitparams_local_ipaddr(mtc, - addr->prefix); - } - } - - /* If not already set, try to determine Remote IP addr if - * circuit is P2P */ - if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) - && (circuit->circ_type == CIRCUIT_T_P2P)) { + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) { + ext->adm_group = ifp->link_params->admin_grp; + SET_SUBTLV(ext, EXT_ADM_GRP); + } else + UNSET_SUBTLV(ext, EXT_ADM_GRP); + + /* If known, register local IPv4 addr from ip_addr list */ + if (circuit->ip_addrs != NULL + && listcount(circuit->ip_addrs) != 0) { + addr = (struct prefix_ipv4 *)listgetdata( + (struct listnode *)listhead(circuit->ip_addrs)); + IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix); + SET_SUBTLV(ext, EXT_LOCAL_ADDR); + } else + UNSET_SUBTLV(ext, EXT_LOCAL_ADDR); + + /* Same for Remote IPv4 address */ + if (circuit->circ_type == CIRCUIT_T_P2P) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; + if (adj && adj->adj_state == ISIS_ADJ_UP && adj->ipv4_address_count) { - set_circuitparams_rmt_ipaddr( - mtc, adj->ipv4_addresses[0]); + IPV4_ADDR_COPY(&ext->neigh_addr, + &adj->ipv4_addresses[0]); + SET_SUBTLV(ext, EXT_NEIGH_ADDR); } - } - - if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) - set_circuitparams_max_bw(mtc, ifp->link_params->max_bw); - else - SUBTLV_TYPE(mtc->max_bw) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) - set_circuitparams_max_rsv_bw( - mtc, ifp->link_params->max_rsv_bw); - else - SUBTLV_TYPE(mtc->max_rsv_bw) = 0; + } else + UNSET_SUBTLV(ext, EXT_NEIGH_ADDR); + + /* If known, register local IPv6 addr from ip_addr list */ + if (circuit->ipv6_non_link != NULL + && listcount(circuit->ipv6_non_link) != 0) { + addr6 = (struct prefix_ipv6 *)listgetdata( + (struct listnode *)listhead( + circuit->ipv6_non_link)); + IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix); + SET_SUBTLV(ext, EXT_LOCAL_ADDR6); + } else + UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6); + + /* Same for Remote IPv6 address */ + if (circuit->circ_type == CIRCUIT_T_P2P) { + struct isis_adjacency *adj = circuit->u.p2p.neighbor; - if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + if (adj && adj->adj_state == ISIS_ADJ_UP + && adj->ipv6_address_count) { + IPV6_ADDR_COPY(&ext->neigh_addr6, + &adj->ipv6_addresses[0]); + SET_SUBTLV(ext, EXT_NEIGH_ADDR6); + } + } else + UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6); + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) { + ext->max_bw = ifp->link_params->max_bw; + SET_SUBTLV(ext, EXT_MAX_BW); + } else + UNSET_SUBTLV(ext, EXT_MAX_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) { + ext->max_rsv_bw = ifp->link_params->max_rsv_bw; + SET_SUBTLV(ext, EXT_MAX_RSV_BW); + } else + UNSET_SUBTLV(ext, EXT_MAX_RSV_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) { for (i = 0; i < MAX_CLASS_TYPE; i++) - set_circuitparams_unrsv_bw( - mtc, i, ifp->link_params->unrsv_bw[i]); - else - SUBTLV_TYPE(mtc->unrsv_bw) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) - set_circuitparams_te_metric( - mtc, ifp->link_params->te_metric); - else - SUBTLV_TYPE(mtc->te_metric) = 0; - - /* TE metric Extensions */ - if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) - set_circuitparams_av_delay( - mtc, ifp->link_params->av_delay, 0); - else - SUBTLV_TYPE(mtc->av_delay) = 0; + ext->unrsv_bw[i] = + ifp->link_params->unrsv_bw[i]; + SET_SUBTLV(ext, EXT_UNRSV_BW); + } else + UNSET_SUBTLV(ext, EXT_UNRSV_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) { + ext->te_metric = ifp->link_params->te_metric; + SET_SUBTLV(ext, EXT_TE_METRIC); + } else + UNSET_SUBTLV(ext, EXT_TE_METRIC); + + /* TE metric extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) { + ext->delay = ifp->link_params->av_delay; + SET_SUBTLV(ext, EXT_DELAY); + } else + UNSET_SUBTLV(ext, EXT_DELAY); + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) { + ext->min_delay = ifp->link_params->min_delay; + ext->max_delay = ifp->link_params->max_delay; + SET_SUBTLV(ext, EXT_MM_DELAY); + } else + UNSET_SUBTLV(ext, EXT_MM_DELAY); + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) { + ext->delay_var = ifp->link_params->delay_var; + SET_SUBTLV(ext, EXT_DELAY_VAR); + } else + UNSET_SUBTLV(ext, EXT_DELAY_VAR); + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) { + ext->pkt_loss = ifp->link_params->pkt_loss; + SET_SUBTLV(ext, EXT_PKT_LOSS); + } else + UNSET_SUBTLV(ext, EXT_PKT_LOSS); + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) { + ext->res_bw = ifp->link_params->res_bw; + SET_SUBTLV(ext, EXT_RES_BW); + } else + UNSET_SUBTLV(ext, EXT_RES_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) { + ext->ava_bw = ifp->link_params->ava_bw; + SET_SUBTLV(ext, EXT_AVA_BW); + } else + UNSET_SUBTLV(ext, EXT_AVA_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) { + ext->use_bw = ifp->link_params->use_bw; + SET_SUBTLV(ext, EXT_USE_BW); + } else + UNSET_SUBTLV(ext, EXT_USE_BW); - if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) - set_circuitparams_mm_delay( - mtc, ifp->link_params->min_delay, - ifp->link_params->max_delay, 0); - else - SUBTLV_TYPE(mtc->mm_delay) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) - set_circuitparams_delay_var( - mtc, ifp->link_params->delay_var); - else - SUBTLV_TYPE(mtc->delay_var) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) - set_circuitparams_pkt_loss( - mtc, ifp->link_params->pkt_loss, 0); + /* INTER_AS */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { + ext->remote_as = ifp->link_params->rmt_as; + ext->remote_ip = ifp->link_params->rmt_ip; + SET_SUBTLV(ext, EXT_RMT_AS); + SET_SUBTLV(ext, EXT_RMT_IP); + } else { + /* reset inter-as TE params */ + UNSET_SUBTLV(ext, EXT_RMT_AS); + UNSET_SUBTLV(ext, EXT_RMT_IP); + } + zlog_debug(" |- New MPLS-TE link parameters status 0x%x", + ext->status); + } else { + zlog_debug(" |- Reset Extended subTLVs status 0x%x", + ext->status); + /* Reset TE subTLVs keeping SR one's */ + if (IS_SUBTLV(ext, EXT_ADJ_SID)) + ext->status = EXT_ADJ_SID; + else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID)) + ext->status = EXT_LAN_ADJ_SID; else - SUBTLV_TYPE(mtc->pkt_loss) = 0; + ext->status = 0; + } - if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) - set_circuitparams_res_bw(mtc, ifp->link_params->res_bw); - else - SUBTLV_TYPE(mtc->res_bw) = 0; + return; +} - if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) - set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw); - else - SUBTLV_TYPE(mtc->ava_bw) = 0; +static int isis_link_update_adj_hook(struct isis_adjacency *adj) +{ - if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) - set_circuitparams_use_bw(mtc, ifp->link_params->use_bw); - else - SUBTLV_TYPE(mtc->use_bw) = 0; + struct isis_circuit *circuit = adj->circuit; - /* INTER_AS */ - if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) - set_circuitparams_inter_as(mtc, - ifp->link_params->rmt_ip, - ifp->link_params->rmt_as); - else - /* reset inter-as TE params */ - unset_circuitparams_inter_as(mtc); + /* Update MPLS TE Remote IP address parameter if possible */ + if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext)) + return 0; - /* Compute total length of SUB TLVs */ - mtc->length = subtlvs_len(mtc); + /* IPv4 first */ + if (adj->ipv4_address_count > 0) { + IPV4_ADDR_COPY(&circuit->ext->neigh_addr, + &adj->ipv4_addresses[0]); + SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR); + } - } else - mtc->status = disable; + /* and IPv6 */ + if (adj->ipv6_address_count > 0) { + IPV6_ADDR_COPY(&circuit->ext->neigh_addr6, + &adj->ipv6_addresses[0]); + SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6); + } -/* Finally Update LSP */ -#if 0 - if (circuit->area && IS_MPLS_TE(circuit->area->mta)) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); -#endif - return; + return 0; } -void isis_mpls_te_update(struct interface *ifp) +int isis_mpls_te_update(struct interface *ifp) { struct isis_circuit *circuit; + uint8_t rc = 1; /* Sanity Check */ if (ifp == NULL) - return; + return rc; /* Get circuit context from interface */ - if ((circuit = circuit_scan_by_ifp(ifp)) == NULL) - return; + circuit = circuit_scan_by_ifp(ifp); + if (circuit == NULL) + return rc; /* Update TE TLVs ... */ isis_link_params_update(circuit, ifp); @@ -645,418 +297,11 @@ void isis_mpls_te_update(struct interface *ifp) if (circuit->area && IS_MPLS_TE(circuit->area->mta)) lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return; -} - -/*------------------------------------------------------------------------* - * Followings are vty session control functions. - *------------------------------------------------------------------------*/ - -static uint8_t print_subtlv_admin_grp(struct sbuf *buf, int indent, - struct te_subtlv_admin_grp *tlv) -{ - sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n", - ntohl(tlv->value)); - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_llri(struct sbuf *buf, int indent, - struct te_subtlv_llri *tlv) -{ - sbuf_push(buf, indent, "Link Local ID: %" PRIu32 "\n", - ntohl(tlv->local)); - sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n", - ntohl(tlv->remote)); - - return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); -} - -static uint8_t print_subtlv_local_ipaddr(struct sbuf *buf, int indent, - struct te_subtlv_local_ipaddr *tlv) -{ - sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent, - struct te_subtlv_rmt_ipaddr *tlv) -{ - sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_max_bw(struct sbuf *buf, int indent, - struct te_subtlv_max_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_max_rsv_bw(struct sbuf *buf, int indent, - struct te_subtlv_max_rsv_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", - fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_unrsv_bw(struct sbuf *buf, int indent, - struct te_subtlv_unrsv_bw *tlv) -{ - float fval1, fval2; - int i; - - sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); - - for (i = 0; i < MAX_CLASS_TYPE; i += 2) { - fval1 = ntohf(tlv->value[i]); - fval2 = ntohf(tlv->value[i + 1]); - sbuf_push(buf, indent + 2, - "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", i, - fval1, i + 1, fval2); - } - - return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); -} - -static uint8_t print_subtlv_te_metric(struct sbuf *buf, int indent, - struct te_subtlv_te_metric *tlv) -{ - uint32_t te_metric; - - te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; - sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_ras(struct sbuf *buf, int indent, - struct te_subtlv_ras *tlv) -{ - sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n", - ntohl(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_rip(struct sbuf *buf, int indent, - struct te_subtlv_rip *tlv) -{ - sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); + rc = 0; + return rc; } -static uint8_t print_subtlv_av_delay(struct sbuf *buf, int indent, - struct te_subtlv_av_delay *tlv) -{ - uint32_t delay; - uint32_t A; - - delay = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - - sbuf_push(buf, indent, - "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", - A ? "Anomalous" : "Normal", delay); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_mm_delay(struct sbuf *buf, int indent, - struct te_subtlv_mm_delay *tlv) -{ - uint32_t low, high; - uint32_t A; - - low = (uint32_t)ntohl(tlv->low) & TE_EXT_MASK; - A = (uint32_t)ntohl(tlv->low) & TE_EXT_ANORMAL; - high = (uint32_t)ntohl(tlv->high) & TE_EXT_MASK; - - sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n", - A ? "Anomalous" : "Normal", low, high); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_delay_var(struct sbuf *buf, int indent, - struct te_subtlv_delay_var *tlv) -{ - uint32_t jitter; - - jitter = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - - sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n", - jitter); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_pkt_loss(struct sbuf *buf, int indent, - struct te_subtlv_pkt_loss *tlv) -{ - uint32_t loss; - uint32_t A; - float fval; - - loss = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - fval = (float)(loss * LOSS_PRECISION); - A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - - sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", - A ? "Anomalous" : "Normal", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_res_bw(struct sbuf *buf, int indent, - struct te_subtlv_res_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_ava_bw(struct sbuf *buf, int indent, - struct te_subtlv_ava_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent, - struct te_subtlv_use_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_unknown_tlv(struct sbuf *buf, int indent, - struct subtlv_header *tlvh) -{ - int i, rtn; - uint8_t *v = (uint8_t *)tlvh; - - if (tlvh->length != 0) { - sbuf_push(buf, indent, - "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); - sbuf_push(buf, indent + 2, "Dump: [00]"); - rtn = 1; /* initialize end of line counter */ - for (i = 0; i < tlvh->length; i++) { - sbuf_push(buf, 0, " %#.2x", v[i]); - if (rtn == 8) { - sbuf_push(buf, 0, "\n"); - sbuf_push(buf, indent + 8, "[%.2x]", i + 1); - rtn = 1; - } else - rtn++; - } - sbuf_push(buf, 0, "\n"); - } else { - sbuf_push(buf, indent, - "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); - } - - return SUBTLV_SIZE(tlvh); -} - -/* Main Show function */ -void mpls_te_print_detail(struct sbuf *buf, int indent, - uint8_t *subtlvs, uint8_t subtlv_len) -{ - struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs; - uint16_t sum = 0; - - for (; sum < subtlv_len; - tlvh = (struct subtlv_header *)(subtlvs + sum)) { - if (subtlv_len - sum < SUBTLV_SIZE(tlvh)) { - sbuf_push(buf, indent, "Available data %" PRIu8 " is less than TLV size %u!\n", - subtlv_len - sum, SUBTLV_SIZE(tlvh)); - return; - } - - switch (tlvh->type) { - case TE_SUBTLV_ADMIN_GRP: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Administrative Group!\n"); - return; - } - sum += print_subtlv_admin_grp(buf, indent, - (struct te_subtlv_admin_grp *)tlvh); - break; - case TE_SUBTLV_LLRI: - if (tlvh->length != TE_SUBTLV_LLRI_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Link ID!\n"); - return; - } - sum += print_subtlv_llri(buf, indent, - (struct te_subtlv_llri *)tlvh); - break; - case TE_SUBTLV_LOCAL_IPADDR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Local IP address!\n"); - return; - } - sum += print_subtlv_local_ipaddr(buf, indent, - (struct te_subtlv_local_ipaddr *)tlvh); - break; - case TE_SUBTLV_RMT_IPADDR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote Interface address!\n"); - return; - } - sum += print_subtlv_rmt_ipaddr(buf, indent, - (struct te_subtlv_rmt_ipaddr *)tlvh); - break; - case TE_SUBTLV_MAX_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Bandwidth!\n"); - return; - } - sum += print_subtlv_max_bw(buf, indent, - (struct te_subtlv_max_bw *)tlvh); - break; - case TE_SUBTLV_MAX_RSV_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Reservable Bandwidth!\n"); - return; - } - sum += print_subtlv_max_rsv_bw(buf, indent, - (struct te_subtlv_max_rsv_bw *)tlvh); - break; - case TE_SUBTLV_UNRSV_BW: - if (tlvh->length != TE_SUBTLV_UNRSV_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unreserved Bandwidth!\n"); - return; - } - sum += print_subtlv_unrsv_bw(buf, indent, - (struct te_subtlv_unrsv_bw *)tlvh); - break; - case TE_SUBTLV_TE_METRIC: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Traffic Engineering Metric!\n"); - return; - } - sum += print_subtlv_te_metric(buf, indent, - (struct te_subtlv_te_metric *)tlvh); - break; - case TE_SUBTLV_RAS: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote AS number!\n"); - return; - } - sum += print_subtlv_ras(buf, indent, - (struct te_subtlv_ras *)tlvh); - break; - case TE_SUBTLV_RIP: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote ASBR IP Address!\n"); - return; - } - sum += print_subtlv_rip(buf, indent, - (struct te_subtlv_rip *)tlvh); - break; - case TE_SUBTLV_AV_DELAY: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Average Link Delay!\n"); - return; - } - sum += print_subtlv_av_delay(buf, indent, - (struct te_subtlv_av_delay *)tlvh); - break; - case TE_SUBTLV_MM_DELAY: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Min/Max Link Delay!\n"); - return; - } - sum += print_subtlv_mm_delay(buf, indent, - (struct te_subtlv_mm_delay *)tlvh); - break; - case TE_SUBTLV_DELAY_VAR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Delay Variation!\n"); - return; - } - sum += print_subtlv_delay_var(buf, indent, - (struct te_subtlv_delay_var *)tlvh); - break; - case TE_SUBTLV_PKT_LOSS: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Link Packet Loss!\n"); - return; - } - sum += print_subtlv_pkt_loss(buf, indent, - (struct te_subtlv_pkt_loss *)tlvh); - break; - case TE_SUBTLV_RES_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n"); - return; - } - sum += print_subtlv_res_bw(buf, indent, - (struct te_subtlv_res_bw *)tlvh); - break; - case TE_SUBTLV_AVA_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Available Bandwidth!\n"); - return; - } - sum += print_subtlv_ava_bw(buf, indent, - (struct te_subtlv_ava_bw *)tlvh); - break; - case TE_SUBTLV_USE_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n"); - return; - } - sum += print_subtlv_use_bw(buf, indent, - (struct te_subtlv_use_bw *)tlvh); - break; - default: - sum += print_unknown_tlv(buf, indent, tlvh); - break; - } - } - return; -} - -/*------------------------------------------------------------------------* - * Followings are vty command functions. - *------------------------------------------------------------------------*/ +/* Followings are vty command functions */ #ifndef FABRICD DEFUN (show_isis_mpls_te_router, @@ -1092,45 +337,104 @@ DEFUN (show_isis_mpls_te_router, return CMD_SUCCESS; } -static void show_mpls_te_sub(struct vty *vty, char *name, - struct mpls_te_circuit *mtc) +static void show_ext_sub(struct vty *vty, char *name, + struct isis_ext_subtlvs *ext) { struct sbuf buf; + char ibuf[PREFIX2STR_BUFFER]; sbuf_init(&buf, NULL, 0); - if (mtc->status != enable) + if (!ext || ext->status == EXT_DISABLE) return; vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name); sbuf_reset(&buf); - print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp); - - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) - print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr); - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) - print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr); - - print_subtlv_max_bw(&buf, 4, &mtc->max_bw); - print_subtlv_max_rsv_bw(&buf, 4, &mtc->max_rsv_bw); - print_subtlv_unrsv_bw(&buf, 4, &mtc->unrsv_bw); - print_subtlv_te_metric(&buf, 4, &mtc->te_metric); - - if (IS_INTER_AS(mtc->type)) { - if (SUBTLV_TYPE(mtc->ras) != 0) - print_subtlv_ras(&buf, 4, &mtc->ras); - if (SUBTLV_TYPE(mtc->rip) != 0) - print_subtlv_rip(&buf, 4, &mtc->rip); - } - print_subtlv_av_delay(&buf, 4, &mtc->av_delay); - print_subtlv_mm_delay(&buf, 4, &mtc->mm_delay); - print_subtlv_delay_var(&buf, 4, &mtc->delay_var); - print_subtlv_pkt_loss(&buf, 4, &mtc->pkt_loss); - print_subtlv_res_bw(&buf, 4, &mtc->res_bw); - print_subtlv_ava_bw(&buf, 4, &mtc->ava_bw); - print_subtlv_use_bw(&buf, 4, &mtc->use_bw); + if (IS_SUBTLV(ext, EXT_ADM_GRP)) + sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n", + ext->adm_group); + if (IS_SUBTLV(ext, EXT_LLRI)) { + sbuf_push(&buf, 4, "Link Local ID: %" PRIu32 "\n", + ext->local_llri); + sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n", + ext->remote_llri); + } + if (IS_SUBTLV(ext, EXT_LOCAL_ADDR)) + sbuf_push(&buf, 4, "Local Interface IP Address(es): %s\n", + inet_ntoa(ext->local_addr)); + if (IS_SUBTLV(ext, EXT_NEIGH_ADDR)) + sbuf_push(&buf, 4, "Remote Interface IP Address(es): %s\n", + inet_ntoa(ext->neigh_addr)); + if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6)) + sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &ext->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6)) + sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &ext->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(ext, EXT_MAX_BW)) + sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n", + ext->max_bw); + if (IS_SUBTLV(ext, EXT_MAX_RSV_BW)) + sbuf_push(&buf, 4, + "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + ext->max_rsv_bw); + if (IS_SUBTLV(ext, EXT_UNRSV_BW)) { + sbuf_push(&buf, 4, "Unreserved Bandwidth:\n"); + for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { + sbuf_push(&buf, 4 + 2, + "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + j, ext->unrsv_bw[j], + j + 1, ext->unrsv_bw[j + 1]); + } + } + if (IS_SUBTLV(ext, EXT_TE_METRIC)) + sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n", + ext->te_metric); + if (IS_SUBTLV(ext, EXT_RMT_AS)) + sbuf_push(&buf, 4, + "Inter-AS TE Remote AS number: %" PRIu32 "\n", + ext->remote_as); + if (IS_SUBTLV(ext, EXT_RMT_IP)) + sbuf_push(&buf, 4, + "Inter-AS TE Remote ASBR IP address: %s\n", + inet_ntoa(ext->remote_ip)); + if (IS_SUBTLV(ext, EXT_DELAY)) + sbuf_push(&buf, 4, + "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", + IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal", + ext->delay); + if (IS_SUBTLV(ext, EXT_MM_DELAY)) { + sbuf_push(&buf, 4, "%s Min/Max Link Delay: %" PRIu32 " / %" + PRIu32 " (micro-sec)\n", + IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal", + ext->min_delay & TE_EXT_MASK, + ext->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(ext, EXT_DELAY_VAR)) + sbuf_push(&buf, 4, + "Delay Variation: %" PRIu32 " (micro-sec)\n", + ext->delay_var & TE_EXT_MASK); + if (IS_SUBTLV(ext, EXT_PKT_LOSS)) + sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n", + IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal", + (float)((ext->pkt_loss & TE_EXT_MASK) + * LOSS_PRECISION)); + if (IS_SUBTLV(ext, EXT_RES_BW)) + sbuf_push(&buf, 4, + "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", + ext->res_bw); + if (IS_SUBTLV(ext, EXT_AVA_BW)) + sbuf_push(&buf, 4, + "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", + ext->ava_bw); + if (IS_SUBTLV(ext, EXT_USE_BW)) + sbuf_push(&buf, 4, + "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", + ext->use_bw); vty_multiline(vty, "", "%s", sbuf_buf(&buf)); vty_out(vty, "---------------\n\n"); @@ -1170,8 +474,8 @@ DEFUN (show_isis_mpls_te_interface, for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) - show_mpls_te_sub(vty, circuit->interface->name, - circuit->mtc); + show_ext_sub(vty, circuit->interface->name, + circuit->ext); } } else { /* Interface name is specified. */ @@ -1185,7 +489,7 @@ DEFUN (show_isis_mpls_te_interface, "ISIS is not enabled on circuit %s\n", ifp->name); else - show_mpls_te_sub(vty, ifp->name, circuit->mtc); + show_ext_sub(vty, ifp->name, circuit->ext); } } @@ -1197,6 +501,11 @@ DEFUN (show_isis_mpls_te_interface, void isis_mpls_te_init(void) { + /* Register Circuit and Adjacency hook */ + hook_register(isis_if_new_hook, isis_mpls_te_update); + hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook); + + #ifndef FABRICD /* Register new VTY commands */ install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd); diff --git a/isisd/isis_te.h b/isisd/isis_te.h index beb0c1836f..2a6911d500 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -3,8 +3,9 @@ * * This is an implementation of RFC5305, RFC 5307 and RFC 7810 * - * Copyright (C) 2014 Orange Labs - * http://www.orange.com + * Author: Olivier Dugeon <olivier.dugeon@orange.com> + * + * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com * * This file is part of GNU Zebra. * @@ -50,10 +51,10 @@ * Remote AS number 24 RFC5316 * IPv4 Remote ASBR identifier 25 RFC5316 * + * NOTE: RFC5316 is not fully supported in this version + * only subTLVs decoding is provided */ -/* NOTE: RFC5316 is not yet supported in this version */ - /* Following define the type of TE link regarding the various RFC */ #define STD_TE 0x01 #define GMPLS 0x02 @@ -73,170 +74,9 @@ #define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) /* - * Following section defines subTLV (tag, length, value) structures, - * used for Traffic Engineering. + * Note (since release 7.2), subTLVs definition, serialization + * and de-serialization have mode to isis_tlvs.[c,h] */ -struct subtlv_header { - uint8_t type; /* sub_TLV_XXX type (see above) */ - uint8_t length; /* Value portion only, in byte */ -}; - -#define MAX_SUBTLV_SIZE 256 - -#define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ - -#define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) - -#define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE) - -#define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh)) - -#define SUBTLV_TYPE(stlvh) stlvh.header.type -#define SUBTLV_LEN(stlvh) stlvh.header.length -#define SUBTLV_VAL(stlvh) stlvh.value -#define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE - -#define SUBTLV_DEF_SIZE 4 - -/* Link Sub-TLV: Resource Class/Color - RFC 5305 */ -#define TE_SUBTLV_ADMIN_GRP 3 -struct te_subtlv_admin_grp { - struct subtlv_header header; /* Value length is 4 octets. */ - uint32_t value; /* Admin. group membership. */ -} __attribute__((__packed__)); - -/* Link Local/Remote Identifiers - RFC 5307 */ -#define TE_SUBTLV_LLRI 4 -#define TE_SUBTLV_LLRI_SIZE 8 -struct te_subtlv_llri { - struct subtlv_header header; /* Value length is 8 octets. */ - uint32_t local; /* Link Local Identifier */ - uint32_t remote; /* Link Remote Identifier */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */ -#define TE_SUBTLV_LOCAL_IPADDR 6 -struct te_subtlv_local_ipaddr { - struct subtlv_header header; /* Value length is 4 x N octets. */ - struct in_addr value; /* Local IP address(es). */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */ -#define TE_SUBTLV_RMT_IPADDR 8 -struct te_subtlv_rmt_ipaddr { - struct subtlv_header header; /* Value length is 4 x N octets. */ - struct in_addr value; /* Neighbor's IP address(es). */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */ -#define TE_SUBTLV_MAX_BW 9 -struct te_subtlv_max_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bytes/sec */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */ -#define TE_SUBTLV_MAX_RSV_BW 10 -struct te_subtlv_max_rsv_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bytes/sec */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */ -#define TE_SUBTLV_UNRSV_BW 11 -#define TE_SUBTLV_UNRSV_SIZE 32 -struct te_subtlv_unrsv_bw { - struct subtlv_header header; /* Value length is 32 octets. */ - float value[8]; /* One for each priority level. */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */ -#define TE_SUBTLV_TE_METRIC 18 -#define TE_SUBTLV_TE_METRIC_SIZE 3 -struct te_subtlv_te_metric { - struct subtlv_header header; /* Value length is 4 octets. */ - uint8_t value[3]; /* Link metric for TE purpose. */ -} __attribute__((__packed__)); - -/* Remote AS Number sub-TLV - RFC5316 */ -#define TE_SUBTLV_RAS 24 -struct te_subtlv_ras { - struct subtlv_header header; /* Value length is 4 octets. */ - uint32_t value; /* Remote AS number */ -} __attribute__((__packed__)); - -/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ -#define TE_SUBTLV_RIP 25 -struct te_subtlv_rip { - struct subtlv_header header; /* Value length is 4 octets. */ - struct in_addr value; /* Remote ASBR IP address */ -} __attribute__((__packed__)); - - -/* TE Metric Extensions - RFC 7810 */ -/* Link Sub-TLV: Average Link Delay */ -#define TE_SUBTLV_AV_DELAY 33 -struct te_subtlv_av_delay { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... - 16777215 - with Anomalous Bit (A) as Upper most bit */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Low/High Link Delay */ -#define TE_SUBTLV_MM_DELAY 34 -#define TE_SUBTLV_MM_DELAY_SIZE 8 -struct te_subtlv_mm_delay { - struct subtlv_header header; /* Value length is 8 bytes. */ - uint32_t low; /* low delay in micro-seconds only 24 bits => 0 ... - 16777215 - with Anomalous Bit (A) as Upper most bit */ - uint32_t high; /* high delay in micro-seconds only 24 bits => 0 ... - 16777215 */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ -#define TE_SUBTLV_DELAY_VAR 35 -struct te_subtlv_delay_var { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t value; /* interval in micro-seconds only 24 bits => 0 ... - 16777215 */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ -#define TE_SUBTLV_PKT_LOSS 36 -struct te_subtlv_pkt_loss { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t - value; /* in percentage of total traffic only 24 bits (2^24 - 2) - with Anomalous Bit (A) as Upper most bit */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ -#define TE_SUBTLV_RES_BW 37 -struct te_subtlv_res_bw { - struct subtlv_header header; /* Value length is 4 bytes. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ -#define TE_SUBTLV_AVA_BW 38 -struct te_subtlv_ava_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ -#define TE_SUBTLV_USE_BW 39 -struct te_subtlv_use_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -#define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */ /* Following declaration concerns the MPLS-TE and LINk-TE management */ typedef enum _status_t { disable, enable, learn } status_t; @@ -244,7 +84,10 @@ typedef enum _status_t { disable, enable, learn } status_t; /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; -#define IS_MPLS_TE(m) (m && m->status == enable) +#define IS_EXT_TE(e) (e && e->status != 0 \ + && e->status != EXT_ADJ_SID \ + && e->status != EXT_LAN_ADJ_SID) +#define IS_MPLS_TE(a) (a && a->status == enable) /* Per area MPLS-TE parameters */ struct mpls_te_area { @@ -262,56 +105,9 @@ struct mpls_te_area { struct in_addr router_id; }; -/* Per Circuit MPLS-TE parameters */ -struct mpls_te_circuit { - - /* Status of MPLS-TE on this interface */ - status_t status; - - /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), - * INTER_AS_EMU(RFC5316 emulated) */ - uint8_t type; - - /* Total size of sub_tlvs */ - uint8_t length; - - /* Store subTLV in network byte order. */ - /* RFC5305 */ - struct te_subtlv_admin_grp admin_grp; - /* RFC5307 */ - struct te_subtlv_llri llri; - /* RFC5305 */ - struct te_subtlv_local_ipaddr local_ipaddr; - struct te_subtlv_rmt_ipaddr rmt_ipaddr; - struct te_subtlv_max_bw max_bw; - struct te_subtlv_max_rsv_bw max_rsv_bw; - struct te_subtlv_unrsv_bw unrsv_bw; - struct te_subtlv_te_metric te_metric; - /* RFC5316 */ - struct te_subtlv_ras ras; - struct te_subtlv_rip rip; - /* RFC7810 */ - struct te_subtlv_av_delay av_delay; - struct te_subtlv_mm_delay mm_delay; - struct te_subtlv_delay_var delay_var; - struct te_subtlv_pkt_loss pkt_loss; - struct te_subtlv_res_bw res_bw; - struct te_subtlv_ava_bw ava_bw; - struct te_subtlv_use_bw use_bw; -}; - /* Prototypes. */ void isis_mpls_te_init(void); -struct mpls_te_circuit *mpls_te_circuit_new(void); -struct sbuf; -void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, - uint8_t subtlv_len); -void set_circuitparams_local_ipaddr(struct mpls_te_circuit *, struct in_addr); -void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *, struct in_addr); -uint8_t subtlvs_len(struct mpls_te_circuit *); -uint8_t add_te_subtlvs(uint8_t *, struct mpls_te_circuit *); -uint8_t build_te_subtlvs(uint8_t *, struct isis_circuit *); void isis_link_params_update(struct isis_circuit *, struct interface *); -void isis_mpls_te_update(struct interface *); +int isis_mpls_te_update(struct interface *); #endif /* _ZEBRA_ISIS_MPLS_TE_H */ diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index ee253c7a31..442442152c 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -3,6 +3,8 @@ * * Copyright (C) 2015,2017 Christian Franke * + * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) + * * This file is part of FRR. * * FRR is free software; you can redistribute it and/or modify it @@ -28,6 +30,7 @@ #include "memory.h" #include "stream.h" #include "sbuf.h" +#include "network.h" #include "isisd/isisd.h" #include "isisd/isis_memory.h" @@ -98,7 +101,8 @@ static struct pack_order_entry pack_order[] = { PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach), PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach), PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach), - PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)}; + PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach) +}; /* This is a forward definition. The table is actually initialized * in at the bottom. */ @@ -108,9 +112,683 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; /* Prototypes */ static void append_item(struct isis_item_list *dest, struct isis_item *item); +static void init_item_list(struct isis_item_list *items); -/* Functions for Sub-TLV 3 SR Prefix-SID */ +/* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */ +struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void) +{ + struct isis_ext_subtlvs *ext; + + ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs)); + init_item_list(&ext->adj_sid); + init_item_list(&ext->lan_sid); + + return ext; +} + +/* + * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6. + * A negative value could be used to skip copy of Adjacency SID. + */ +static struct isis_ext_subtlvs * +copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid) +{ + struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv)); + struct isis_adj_sid *adj; + struct isis_lan_adj_sid *lan; + + memcpy(rv, exts, sizeof(struct isis_ext_subtlvs)); + init_item_list(&rv->adj_sid); + init_item_list(&rv->lan_sid); + + UNSET_SUBTLV(rv, EXT_ADJ_SID); + UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID); + + /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */ + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL; + adj = adj->next) { + if ((mtid != -1) + && (((mtid == ISIS_MT_IPV4_UNICAST) + && (adj->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (adj->family != AF_INET6)))) + continue; + + struct isis_adj_sid *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid)); + new->family = adj->family; + new->flags = adj->flags; + new->weight = adj->weight; + new->sid = adj->sid; + append_item(&rv->adj_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_ADJ_SID); + } + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL; + lan = lan->next) { + if ((mtid != -1) + && (((mtid == ISIS_MT_IPV4_UNICAST) + && (lan->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (lan->family != AF_INET6)))) + continue; + + struct isis_lan_adj_sid *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid)); + new->family = lan->family; + new->flags = lan->flags; + new->weight = lan->weight; + memcpy(new->neighbor_id, lan->neighbor_id, 6); + new->sid = lan->sid; + append_item(&rv->lan_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_LAN_ADJ_SID); + } + + return rv; +} + +/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ +static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, + struct sbuf *buf, int indent, + uint16_t mtid) +{ + + char ibuf[PREFIX2STR_BUFFER]; + + /* Standard metrics */ + if (IS_SUBTLV(exts, EXT_ADM_GRP)) + sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n", + exts->adm_group); + if (IS_SUBTLV(exts, EXT_LLRI)) { + sbuf_push(buf, indent, "Link Local ID: %" PRIu32 "\n", + exts->local_llri); + sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n", + exts->remote_llri); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) + sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n", + inet_ntoa(exts->local_addr)); + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) + sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n", + inet_ntoa(exts->neigh_addr)); + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) + sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &exts->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) + sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &exts->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(exts, EXT_MAX_BW)) + sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", + exts->max_bw); + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) + sbuf_push(buf, indent, + "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + exts->max_rsv_bw); + if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { + sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); + for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { + sbuf_push(buf, indent + 2, + "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + j, exts->unrsv_bw[j], + j + 1, exts->unrsv_bw[j + 1]); + } + } + if (IS_SUBTLV(exts, EXT_TE_METRIC)) + sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", + exts->te_metric); + if (IS_SUBTLV(exts, EXT_RMT_AS)) + sbuf_push(buf, indent, + "Inter-AS TE Remote AS number: %" PRIu32 "\n", + exts->remote_as); + if (IS_SUBTLV(exts, EXT_RMT_IP)) + sbuf_push(buf, indent, + "Inter-AS TE Remote ASBR IP address: %s\n", + inet_ntoa(exts->remote_ip)); + /* Extended metrics */ + if (IS_SUBTLV(exts, EXT_DELAY)) + sbuf_push(buf, indent, + "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", + IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal", + exts->delay); + if (IS_SUBTLV(exts, EXT_MM_DELAY)) { + sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" + PRIu32 " (micro-sec)\n", + IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { + sbuf_push(buf, indent, + "Delay Variation: %" PRIu32 " (micro-sec)\n", + exts->delay_var & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) + sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", + IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal", + (float)((exts->pkt_loss & TE_EXT_MASK) + * LOSS_PRECISION)); + if (IS_SUBTLV(exts, EXT_RES_BW)) + sbuf_push(buf, indent, + "Unidir. Residual Bandwidth: %g (Bytes/sec)\n", + exts->res_bw); + if (IS_SUBTLV(exts, EXT_AVA_BW)) + sbuf_push(buf, indent, + "Unidir. Available Bandwidth: %g (Bytes/sec)\n", + exts->ava_bw); + if (IS_SUBTLV(exts, EXT_USE_BW)) + sbuf_push(buf, indent, + "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n", + exts->use_bw); + /* Segment Routing Adjacency */ + if (IS_SUBTLV(exts, EXT_ADJ_SID)) { + struct isis_adj_sid *adj; + + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; + adj = adj->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) + && (adj->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (adj->family != AF_INET6))) + continue; + sbuf_push( + buf, indent, + "Adjacency-SID: %" PRIu32 ", Weight: %" PRIu8 + ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n", + adj->sid, adj->weight, + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0'); + } + } + if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { + struct isis_lan_adj_sid *lan; + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) + && (lan->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (lan->family != AF_INET6))) + continue; + sbuf_push(buf, indent, + "Lan-Adjacency-SID: %" PRIu32 + ", Weight: %" PRIu8 + ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n" + " Neighbor-ID: %s\n", + lan->sid, lan->weight, + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0', + isis_format_id(lan->neighbor_id, 6)); + } + } +} + +static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts) +{ + struct isis_item *item, *next_item; + + /* First, free Adj SID and LAN Adj SID list if needed */ + for (item = exts->adj_sid.head; item; item = next_item) { + next_item = item->next; + XFREE(MTYPE_ISIS_SUBTLV, item); + } + for (item = exts->lan_sid.head; item; item = next_item) { + next_item = item->next; + XFREE(MTYPE_ISIS_SUBTLV, item); + } + XFREE(MTYPE_ISIS_SUBTLV, exts); +} + +static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts, + struct stream *s) +{ + uint8_t size; + + if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) + return 1; + + if (IS_SUBTLV(exts, EXT_ADM_GRP)) { + stream_putc(s, ISIS_SUBTLV_ADMIN_GRP); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->adm_group); + } + if (IS_SUBTLV(exts, EXT_LLRI)) { + stream_putc(s, ISIS_SUBTLV_LLRI); + stream_putc(s, ISIS_SUBTLV_LLRI_SIZE); + stream_putl(s, exts->local_llri); + stream_putl(s, exts->remote_llri); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) { + stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->local_addr.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) { + stream_putc(s, ISIS_SUBTLV_RMT_IPADDR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->neigh_addr.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) { + stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6); + stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE); + stream_put(s, &exts->local_addr6, 16); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) { + stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6); + stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE); + stream_put(s, &exts->neigh_addr6, 16); + } + if (IS_SUBTLV(exts, EXT_MAX_BW)) { + stream_putc(s, ISIS_SUBTLV_MAX_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->max_bw); + } + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) { + stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->max_rsv_bw); + } + if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { + stream_putc(s, ISIS_SUBTLV_UNRSV_BW); + stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE); + for (int j = 0; j < MAX_CLASS_TYPE; j++) + stream_putf(s, exts->unrsv_bw[j]); + } + if (IS_SUBTLV(exts, EXT_TE_METRIC)) { + stream_putc(s, ISIS_SUBTLV_TE_METRIC); + stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE); + stream_put3(s, exts->te_metric); + } + if (IS_SUBTLV(exts, EXT_RMT_AS)) { + stream_putc(s, ISIS_SUBTLV_RAS); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->remote_as); + } + if (IS_SUBTLV(exts, EXT_RMT_IP)) { + stream_putc(s, ISIS_SUBTLV_RIP); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->remote_ip.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_DELAY)) { + stream_putc(s, ISIS_SUBTLV_AV_DELAY); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->delay); + } + if (IS_SUBTLV(exts, EXT_MM_DELAY)) { + stream_putc(s, ISIS_SUBTLV_MM_DELAY); + stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE); + stream_putl(s, exts->min_delay); + stream_putl(s, exts->max_delay); + } + if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { + stream_putc(s, ISIS_SUBTLV_DELAY_VAR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->delay_var); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) { + stream_putc(s, ISIS_SUBTLV_PKT_LOSS); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->pkt_loss); + } + if (IS_SUBTLV(exts, EXT_RES_BW)) { + stream_putc(s, ISIS_SUBTLV_RES_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->res_bw); + } + if (IS_SUBTLV(exts, EXT_AVA_BW)) { + stream_putc(s, ISIS_SUBTLV_AVA_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->ava_bw); + } + if (IS_SUBTLV(exts, EXT_USE_BW)) { + stream_putc(s, ISIS_SUBTLV_USE_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->use_bw); + } + if (IS_SUBTLV(exts, EXT_ADJ_SID)) { + struct isis_adj_sid *adj; + + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; + adj = adj->next) { + stream_putc(s, ISIS_SUBTLV_ADJ_SID); + size = ISIS_SUBTLV_ADJ_SID_SIZE; + if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + size++; + stream_putc(s, size); + stream_putc(s, adj->flags); + stream_putc(s, adj->weight); + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + stream_put3(s, adj->sid); + else + stream_putl(s, adj->sid); + + } + } + if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { + struct isis_lan_adj_sid *lan; + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan; + lan = lan->next) { + stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID); + size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE; + if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + size++; + stream_putc(s, size); + stream_putc(s, lan->flags); + stream_putc(s, lan->weight); + stream_put(s, lan->neighbor_id, 6); + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + stream_put3(s, lan->sid); + else + stream_putl(s, lan->sid); + } + } + + return 0; +} + +static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + uint8_t sum = 0; + uint8_t subtlv_type; + uint8_t subtlv_len; + + struct isis_extended_reach *rv = dest; + struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs(); + + rv->subtlvs = exts; + + /* + * Parse subTLVs until reach subTLV length + * Check that it remains at least 2 bytes: subTLV Type & Length + */ + while (len > sum + 2) { + /* Read SubTLV Type and Length */ + subtlv_type = stream_getc(s); + subtlv_len = stream_getc(s); + if (subtlv_len > len - sum) { + sbuf_push(log, indent, "TLV %" PRIu8 ": Available data %" PRIu8 " is less than TLV size %u !\n", + subtlv_type, len - sum, subtlv_len); + return 1; + } + switch (subtlv_type) { + /* Standard Metric as defined in RFC5305 */ + case ISIS_SUBTLV_ADMIN_GRP: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Administrative Group!\n"); + } else { + exts->adm_group = stream_getl(s); + SET_SUBTLV(exts, EXT_ADM_GRP); + } + break; + case ISIS_SUBTLV_LLRI: + if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Link ID!\n"); + } else { + exts->local_llri = stream_getl(s); + exts->remote_llri = stream_getl(s); + SET_SUBTLV(exts, EXT_LLRI); + } + break; + case ISIS_SUBTLV_LOCAL_IPADDR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Local IP address!\n"); + } else { + stream_get(&exts->local_addr.s_addr, s, 4); + SET_SUBTLV(exts, EXT_LOCAL_ADDR); + } + break; + case ISIS_SUBTLV_RMT_IPADDR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote IP address!\n"); + } else { + stream_get(&exts->neigh_addr.s_addr, s, 4); + SET_SUBTLV(exts, EXT_NEIGH_ADDR); + } + break; + case ISIS_SUBTLV_LOCAL_IPADDR6: + if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Local IPv6 address!\n"); + } else { + stream_get(&exts->local_addr6, s, 16); + SET_SUBTLV(exts, EXT_LOCAL_ADDR6); + } + break; + case ISIS_SUBTLV_RMT_IPADDR6: + if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote IPv6 address!\n"); + } else { + stream_get(&exts->neigh_addr6, s, 16); + SET_SUBTLV(exts, EXT_NEIGH_ADDR6); + } + break; + case ISIS_SUBTLV_MAX_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Maximum Bandwidth!\n"); + } else { + exts->max_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_MAX_BW); + } + break; + case ISIS_SUBTLV_MAX_RSV_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Maximum Reservable Bandwidth!\n"); + } else { + exts->max_rsv_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_MAX_RSV_BW); + } + break; + case ISIS_SUBTLV_UNRSV_BW: + if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unreserved Bandwidth!\n"); + } else { + for (int i = 0; i < MAX_CLASS_TYPE; i++) + exts->unrsv_bw[i] = stream_getf(s); + SET_SUBTLV(exts, EXT_UNRSV_BW); + } + break; + case ISIS_SUBTLV_TE_METRIC: + if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Traffic Engineering Metric!\n"); + } else { + exts->te_metric = stream_get3(s); + SET_SUBTLV(exts, EXT_TE_METRIC); + } + break; + case ISIS_SUBTLV_RAS: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote AS number!\n"); + } else { + exts->remote_as = stream_getl(s); + SET_SUBTLV(exts, EXT_RMT_AS); + } + break; + case ISIS_SUBTLV_RIP: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote ASBR IP Address!\n"); + } else { + stream_get(&exts->remote_ip.s_addr, s, 4); + SET_SUBTLV(exts, EXT_RMT_IP); + } + break; + /* Extended Metrics as defined in RFC 7810 */ + case ISIS_SUBTLV_AV_DELAY: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Average Link Delay!\n"); + } else { + exts->delay = stream_getl(s); + SET_SUBTLV(exts, EXT_DELAY); + } + break; + case ISIS_SUBTLV_MM_DELAY: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Min/Max Link Delay!\n"); + } else { + exts->min_delay = stream_getl(s); + exts->max_delay = stream_getl(s); + SET_SUBTLV(exts, EXT_MM_DELAY); + } + break; + case ISIS_SUBTLV_DELAY_VAR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Delay Variation!\n"); + } else { + exts->delay_var = stream_getl(s); + SET_SUBTLV(exts, EXT_DELAY_VAR); + } + break; + case ISIS_SUBTLV_PKT_LOSS: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Link Packet Loss!\n"); + } else { + exts->pkt_loss = stream_getl(s); + SET_SUBTLV(exts, EXT_PKT_LOSS); + } + break; + case ISIS_SUBTLV_RES_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n"); + } else { + exts->res_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_RES_BW); + } + break; + case ISIS_SUBTLV_AVA_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Available Bandwidth!\n"); + } else { + exts->ava_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_AVA_BW); + } + break; + case ISIS_SUBTLV_USE_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n"); + } else { + exts->use_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_USE_BW); + } + break; + /* Segment Routing Adjacency */ + case ISIS_SUBTLV_ADJ_SID: + if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) { + sbuf_push(log, indent, + "TLV size does not match expected size for Adjacency SID!\n"); + } else { + struct isis_adj_sid *adj; + + adj = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_adj_sid)); + adj->flags = stream_getc(s); + adj->weight = stream_getc(s); + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { + adj->sid = stream_get3(s); + adj->sid &= MPLS_LABEL_VALUE_MASK; + } else { + adj->sid = stream_getl(s); + } + if (mtid == ISIS_MT_IPV4_UNICAST) + adj->family = AF_INET; + if (mtid == ISIS_MT_IPV6_UNICAST) + adj->family = AF_INET6; + append_item(&exts->adj_sid, + (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_ADJ_SID); + } + break; + case ISIS_SUBTLV_LAN_ADJ_SID: + if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) { + sbuf_push(log, indent, + "TLV size does not match expected size for LAN-Adjacency SID!\n"); + } else { + struct isis_lan_adj_sid *lan; + + lan = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_lan_adj_sid)); + lan->flags = stream_getc(s); + lan->weight = stream_getc(s); + stream_get(&(lan->neighbor_id), s, + ISIS_SYS_ID_LEN); + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { + lan->sid = stream_get3(s); + lan->sid &= MPLS_LABEL_VALUE_MASK; + } else { + lan->sid = stream_getl(s); + } + if (mtid == ISIS_MT_IPV4_UNICAST) + lan->family = AF_INET; + if (mtid == ISIS_MT_IPV6_UNICAST) + lan->family = AF_INET6; + append_item(&exts->lan_sid, + (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_LAN_ADJ_SID); + } + break; + default: + /* Skip unknown TLV */ + stream_forward_getp(s, subtlv_len); + break; + } + sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE; + } + + return 0; +} + +/* Functions for Sub-TLV 3 SR Prefix-SID */ static struct isis_item *copy_item_prefix_sid(struct isis_item *i) { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; @@ -127,20 +805,22 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; - sbuf_push(buf, indent, "SR Prefix-SID:\n"); - sbuf_push(buf, indent, " Flags:%s%s%s%s%s%s\n", - sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "", - sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", - sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "", - sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "", - sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", - sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); - sbuf_push(buf, indent, " Algorithm: %" PRIu8 "\n", sid->algorithm); + sbuf_push(buf, indent, "SR Prefix-SID "); if (sid->flags & ISIS_PREFIX_SID_VALUE) { - sbuf_push(buf, indent, "Label: %" PRIu32 "\n", sid->value); + sbuf_push(buf, 0, "Label: %" PRIu32 ", ", sid->value); } else { - sbuf_push(buf, indent, "Index: %" PRIu32 "\n", sid->value); + sbuf_push(buf, 0, "Index: %" PRIu32 ", ", sid->value); } + sbuf_push(buf, 0, "Algorithm: %" PRIu8 ", ", sid->algorithm); + sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n", + sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" + : "", + sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", + sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP", + sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" + : "", + sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", + sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); } static void free_item_prefix_sid(struct isis_item *i) @@ -186,15 +866,17 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, } sid.flags = stream_getc(s); - if ((sid.flags & ISIS_PREFIX_SID_VALUE) - != (sid.flags & ISIS_PREFIX_SID_LOCAL)) { - sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n"); - return 0; + if (!!(sid.flags & ISIS_PREFIX_SID_VALUE) + != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) { + sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n"); + return 1; } sid.algorithm = stream_getc(s); - uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6; + uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) + ? ISIS_SUBTLV_PREFIX_SID_SIZE + : ISIS_SUBTLV_PREFIX_SID_SIZE + 1; if (len != expected_size) { sbuf_push(log, indent, "TLV size differs from expected size. " @@ -205,6 +887,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, if (sid.flags & ISIS_PREFIX_SID_VALUE) { sid.value = stream_get3(s); + sid.value &= MPLS_LABEL_VALUE_MASK; } else { sid.value = stream_getl(s); } @@ -276,7 +959,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, p.prefixlen = stream_getc(s); if (p.prefixlen > 128) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n", p.prefixlen); return 1; } @@ -305,7 +988,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, memcpy(subtlvs->source_prefix, &p, sizeof(p)); return 0; } -static void init_item_list(struct isis_item_list *items); + static struct isis_item *copy_item(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *item); @@ -703,11 +1386,8 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i) memcpy(rv->id, r->id, 7); rv->metric = r->metric; - if (r->subtlvs && r->subtlv_len) { - rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len); - memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len); - rv->subtlv_len = r->subtlv_len; - } + if (r->subtlvs) + rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1); return (struct isis_item *)rv; } @@ -724,28 +1404,37 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); sbuf_push(buf, 0, "\n"); - if (r->subtlv_len && r->subtlvs) - mpls_te_print_detail(buf, indent + 2, r->subtlvs, - r->subtlv_len); + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid); } static void free_item_extended_reach(struct isis_item *i) { struct isis_extended_reach *item = (struct isis_extended_reach *)i; - XFREE(MTYPE_ISIS_TLV, item->subtlvs); + if (item->subtlvs != NULL) + free_item_ext_subtlvs(item->subtlvs); XFREE(MTYPE_ISIS_TLV, item); } static int pack_item_extended_reach(struct isis_item *i, struct stream *s) { struct isis_extended_reach *r = (struct isis_extended_reach *)i; + size_t len; + size_t len_pos; - if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len) + if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) return 1; + stream_put(s, r->id, sizeof(r->id)); stream_put3(s, r->metric); - stream_putc(s, r->subtlv_len); - stream_put(s, r->subtlvs, r->subtlv_len); + len_pos = stream_get_endp(s); + /* Real length will be adjust after adding subTLVs */ + stream_putc(s, 11); + if (r->subtlvs) + pack_item_ext_subtlvs(r->subtlvs, s); + /* Adjust length */ + len = stream_get_endp(s) - len_pos - 1; + stream_putc_at(s, len_pos, len); return 0; } @@ -780,9 +1469,6 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, rv->metric = stream_get3(s); subtlv_len = stream_getc(s); - format_item_extended_reach(mtid, (struct isis_item *)rv, log, - indent + 2); - if ((size_t)len < ((size_t)11) + subtlv_len) { sbuf_push(log, indent, "Not enough data left for subtlv size %" PRIu8 @@ -795,20 +1481,14 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, subtlv_len); if (subtlv_len) { - size_t subtlv_start = stream_get_getp(s); - - if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s, - log, NULL, indent + 4, NULL)) { + if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv, + indent + 4)) { goto out; } - - stream_set_getp(s, subtlv_start); - - rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); - stream_get(rv->subtlvs, s, subtlv_len); - rv->subtlv_len = subtlv_len; } + format_item_extended_reach(mtid, (struct isis_item *)rv, log, + indent + 2); append_item(items, (struct isis_item *)rv); return 0; out: @@ -1257,6 +1937,7 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i) rv->metric = r->metric; rv->down = r->down; rv->prefix = r->prefix; + rv->subtlvs = copy_subtlvs(r->subtlvs); return (struct isis_item *)rv; } @@ -1348,7 +2029,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, rv->prefix.family = AF_INET; rv->prefix.prefixlen = control & 0x3f; if (rv->prefix.prefixlen > 32) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n", rv->prefix.prefixlen); goto out; } @@ -1834,7 +2515,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, rv->prefix.family = AF_INET6; rv->prefix.prefixlen = stream_getc(s); if (rv->prefix.prefixlen > 128) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n", rv->prefix.prefixlen); goto out; } @@ -1848,6 +2529,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, } stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen)); struct in6_addr orig_prefix = rv->prefix.prefix; + apply_mask_ipv6(&rv->prefix); if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix))) sbuf_push(log, indent + 2, @@ -1898,6 +2580,222 @@ out: return 1; } +/* Functions related to TLV 242 Router Capability */ +static struct isis_router_cap *copy_tlv_router_cap( + const struct isis_router_cap *router_cap) +{ + struct isis_router_cap *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + if (!router_cap) + return NULL; + + memcpy(rv, router_cap, sizeof(*rv)); + + return rv; +} + +static void format_tlv_router_cap(const struct isis_router_cap *router_cap, + struct sbuf *buf, int indent) +{ + char addrbuf[INET_ADDRSTRLEN]; + + if (!router_cap) + return; + + /* Router ID and Flags */ + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + sbuf_push(buf, indent, "Router Capability:"); + sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf, + router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0', + router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0'); + + /* SR Global Block */ + if (router_cap->srgb.range_size != 0) + sbuf_push(buf, indent, + " Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n", + IS_SR_IPV4(router_cap->srgb) ? "1" : "0", + IS_SR_IPV6(router_cap->srgb) ? "1" : "0", + router_cap->srgb.lower_bound, + router_cap->srgb.range_size); + + /* SR Algorithms */ + if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { + sbuf_push(buf, indent, " Algorithm: %s", + router_cap->algo[0] == 0 ? "0: SPF" + : "0: Strict SPF"); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) + sbuf_push(buf, indent, " %s", + router_cap->algo[1] == 0 + ? "0: SPF" + : "0: Strict SPF"); + sbuf_push(buf, indent, "\n"); + } + + /* SR Node MSSD */ + if (router_cap->msd != 0) + sbuf_push(buf, indent, " Node MSD: %d\n", router_cap->msd); +} + +static void free_tlv_router_cap(struct isis_router_cap *router_cap) +{ + XFREE(MTYPE_ISIS_TLV, router_cap); +} + +static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, + struct stream *s) +{ + size_t tlv_len = ISIS_ROUTER_CAP_SIZE; + size_t len_pos; + uint8_t nb_algo; + + if (!router_cap) + return 0; + + /* Compute Maximum TLV size */ + tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE + + ISIS_SUBTLV_HDR_SIZE + + ISIS_SUBTLV_ALGORITHM_SIZE + + ISIS_SUBTLV_NODE_MSD_SIZE; + + if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len)) + return 1; + + /* Add Router Capability TLV 242 with Router ID and Flags */ + stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY); + /* Real length will be adjusted later */ + len_pos = stream_get_endp(s); + stream_putc(s, tlv_len); + stream_put_ipv4(s, router_cap->router_id.s_addr); + stream_putc(s, router_cap->flags); + + /* Add SRGB if set */ + if ((router_cap->srgb.range_size != 0) + && (router_cap->srgb.lower_bound != 0)) { + stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE); + stream_putc(s, router_cap->srgb.flags); + stream_put3(s, router_cap->srgb.range_size); + stream_putc(s, ISIS_SUBTLV_SID_LABEL); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE); + stream_put3(s, router_cap->srgb.lower_bound); + + /* Then SR Algorithm if set */ + for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++) + if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET) + break; + if (nb_algo > 0) { + stream_putc(s, ISIS_SUBTLV_ALGORITHM); + stream_putc(s, nb_algo); + for (int i = 0; i < nb_algo; i++) + stream_putc(s, router_cap->algo[i]); + } + /* And finish with MSD if set */ + if (router_cap->msd != 0) { + stream_putc(s, ISIS_SUBTLV_NODE_MSD); + stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE); + stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION); + stream_putc(s, router_cap->msd); + } + } + + /* Adjust TLV length which depends on subTLVs presence */ + tlv_len = stream_get_endp(s) - len_pos - 1; + stream_putc_at(s, len_pos, tlv_len); + + return 0; +} + +static int unpack_tlv_router_cap(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + uint8_t type; + uint8_t length; + uint8_t subtlv_len; + uint8_t sid_len; + + sbuf_push(log, indent, "Unpacking Router Capability TLV...\n"); + if (tlv_len < ISIS_ROUTER_CAP_SIZE) { + sbuf_push(log, indent, "WARNING: Unexpected TLV size\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + if (tlvs->router_cap) { + sbuf_push(log, indent, + "WARNING: Router Capability TLV present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + /* Allocate router cap structure and initialize SR Algorithms */ + tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap)); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET; + + /* Get Router ID and Flags */ + tlvs->router_cap->router_id.s_addr = stream_get_ipv4(s); + tlvs->router_cap->flags = stream_getc(s); + + /* Parse remaining part of the TLV if present */ + subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE; + while (subtlv_len > 2) { + struct isis_router_cap *rc = tlvs->router_cap; + uint8_t msd_type; + + type = stream_getc(s); + length = stream_getc(s); + switch (type) { + case ISIS_SUBTLV_SID_LABEL_RANGE: + rc->srgb.flags = stream_getc(s); + rc->srgb.range_size = stream_get3(s); + /* Skip Type and get Length of SID Label */ + stream_getc(s); + sid_len = stream_getc(s); + if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE) + rc->srgb.lower_bound = stream_get3(s); + else + rc->srgb.lower_bound = stream_getl(s); + + /* SRGB sanity checks. */ + if (rc->srgb.range_size == 0 + || (rc->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX) + || ((rc->srgb.lower_bound + rc->srgb.range_size - 1) + > MPLS_LABEL_UNRESERVED_MAX)) { + sbuf_push(log, indent, "Invalid label range. Reset SRGB\n"); + rc->srgb.lower_bound = 0; + rc->srgb.range_size = 0; + } + break; + case ISIS_SUBTLV_ALGORITHM: + /* Only 2 algorithms are supported: SPF & Strict SPF */ + stream_get(&rc->algo, s, + length > SR_ALGORITHM_COUNT + ? SR_ALGORITHM_COUNT + : length); + if (length > SR_ALGORITHM_COUNT) + stream_forward_getp( + s, length - SR_ALGORITHM_COUNT); + break; + case ISIS_SUBTLV_NODE_MSD: + msd_type = stream_getc(s); + rc->msd = stream_getc(s); + /* Only BMI-MSD type has been defined in RFC 8491 */ + if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION) + rc->msd = 0; + break; + default: + stream_forward_getp(s, length); + break; + } + subtlv_len = subtlv_len - length - 2; + } + return 0; +} + /* Functions related to TLV 10 Authentication */ static struct isis_item *copy_item_auth(struct isis_item *i) { @@ -2318,6 +3216,39 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item) dest->count++; } +static void delete_item(struct isis_item_list *dest, struct isis_item *del) +{ + struct isis_item *item, *prev = NULL, *next; + + /* Sanity Check */ + if ((dest == NULL) || (del == NULL)) + return; + + /* + * TODO: delete is tricky because "dest" is a singly linked list. + * We need to switch a doubly linked list. + */ + for (item = dest->head; item; item = next) { + if (item->next == del) { + prev = item; + break; + } + next = item->next; + } + if (prev) + prev->next = del->next; + if (dest->head == del) + dest->head = del->next; + if ((struct isis_item *)dest->tail == del) { + *dest->tail = prev; + if (prev) + dest->tail = &(*dest->tail)->next; + else + dest->tail = &dest->head; + } + dest->count--; +} + static struct isis_item *last_item(struct isis_item_list *list) { return container_of(list->tail, struct isis_item, next); @@ -2596,6 +3527,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj); + rv->router_cap = copy_tlv_router_cap(tlvs->router_cap); + rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf); return rv; @@ -2631,6 +3564,7 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) format_tlv_dynamic_hostname(tlvs->hostname, buf, indent); format_tlv_te_router_id(tlvs->te_router_id, buf, indent); + format_tlv_router_cap(tlvs->router_cap, buf, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, &tlvs->extended_reach, buf, indent); @@ -2717,6 +3651,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs) free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, &tlvs->mt_ipv6_reach); free_tlv_threeway_adj(tlvs->threeway_adj); + free_tlv_router_cap(tlvs->router_cap); free_tlv_spine_leaf(tlvs->spine_leaf); XFREE(MTYPE_ISIS_TLV, tlvs); @@ -2897,6 +3832,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, fragment_tlvs->hostname = copy_tlv_dynamic_hostname(tlvs->hostname); + rv = pack_tlv_router_cap(tlvs->router_cap, stream); + if (rv) + return rv; + if (fragment_tlvs) { + fragment_tlvs->router_cap = + copy_tlv_router_cap(tlvs->router_cap); + } + rv = pack_tlv_te_router_id(tlvs->te_router_id, stream); if (rv) return rv; @@ -3131,6 +4074,7 @@ ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information"); TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency"); ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address"); ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability"); +TLV_OPS(router_cap, "TLV 242 Router Capability"); ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID"); SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); @@ -3144,21 +4088,22 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_TLV_AUTH] = &tlv_auth_ops, [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops, [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops, - [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops, [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops, [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops, [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops, [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops, [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops, - [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops, [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops, + [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops, - [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops, + [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops, [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, + [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, + [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops, }, [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, [ISIS_CONTEXT_SUBTLV_IP_REACH] = { @@ -3593,6 +4538,18 @@ void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname); } +/* Set Router Capability TLV parameters */ +void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs, + const struct isis_router_cap *cap) +{ + XFREE(MTYPE_ISIS_TLV, tlvs->router_cap); + if (!cap) + return; + + tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap)); + *tlvs->router_cap = *cap; +} + void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, const struct in_addr *id) { @@ -3614,6 +4571,38 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r); } +void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj) +{ + append_item(&exts->adj_sid, (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_ADJ_SID); +} + +void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj) +{ + delete_item(&exts->adj_sid, (struct isis_item *)adj); + XFREE(MTYPE_ISIS_SUBTLV, adj); + if (exts->adj_sid.count == 0) + UNSET_SUBTLV(exts, EXT_ADJ_SID); +} + +void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan) +{ + append_item(&exts->lan_sid, (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_LAN_ADJ_SID); +} + +void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan) +{ + delete_item(&exts->lan_sid, (struct isis_item *)lan); + XFREE(MTYPE_ISIS_SUBTLV, lan); + if (exts->lan_sid.count == 0) + UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID); +} + void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, struct prefix_ipv4 *dest, uint32_t metric) { @@ -3668,17 +4657,14 @@ void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len) + struct isis_ext_subtlvs *exts) { struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); memcpy(r->id, id, sizeof(r->id)); r->metric = metric; - if (subtlvs && subtlv_len) { - r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); - memcpy(r->subtlvs, subtlvs, subtlv_len); - r->subtlv_len = subtlv_len; - } + if (exts) + r->subtlvs = copy_item_ext_subtlvs(exts, mtid); struct isis_item_list *l; if (mtid == ISIS_MT_IPV4_UNICAST) diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 4954d791d8..2948728e2b 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -2,6 +2,8 @@ * IS-IS TLV Serializer/Deserializer * * Copyright (C) 2015,2017 Christian Franke + + * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) * * This file is part of FRR. * @@ -66,14 +68,14 @@ struct isis_lsp_entry { }; struct isis_extended_reach; +struct isis_ext_subtlvs; struct isis_extended_reach { struct isis_extended_reach *next; uint8_t id[7]; uint32_t metric; - uint8_t *subtlvs; - uint8_t subtlv_len; + struct isis_ext_subtlvs *subtlvs; }; struct isis_extended_ip_reach; @@ -130,6 +132,95 @@ struct isis_threeway_adj { uint32_t neighbor_circuit_id; }; +/* + * Segment Routing subTLV's as per + * draft-ietf-isis-segment-routing-extension-25 + */ +#define ISIS_SUBTLV_SRGB_FLAG_I 0x80 +#define ISIS_SUBTLV_SRGB_FLAG_V 0x40 +#define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I) +#define IS_SR_IPV6(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V) + +/* Structure aggregating SRGB info */ +struct isis_srgb { + uint8_t flags; + uint32_t range_size; + uint32_t lower_bound; +}; + +/* Prefix-SID sub-TLVs flags */ +#define ISIS_PREFIX_SID_READVERTISED 0x80 +#define ISIS_PREFIX_SID_NODE 0x40 +#define ISIS_PREFIX_SID_NO_PHP 0x20 +#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10 +#define ISIS_PREFIX_SID_VALUE 0x08 +#define ISIS_PREFIX_SID_LOCAL 0x04 + +struct isis_prefix_sid; +struct isis_prefix_sid { + struct isis_prefix_sid *next; + + uint8_t flags; + uint8_t algorithm; + uint32_t value; +}; + +/* Adj-SID and LAN-Ajd-SID sub-TLVs flags */ +#define EXT_SUBTLV_LINK_ADJ_SID_FFLG 0x80 +#define EXT_SUBTLV_LINK_ADJ_SID_BFLG 0x40 +#define EXT_SUBTLV_LINK_ADJ_SID_VFLG 0x20 +#define EXT_SUBTLV_LINK_ADJ_SID_LFLG 0x10 +#define EXT_SUBTLV_LINK_ADJ_SID_SFLG 0x08 +#define EXT_SUBTLV_LINK_ADJ_SID_PFLG 0x04 + +struct isis_adj_sid; +struct isis_adj_sid { + struct isis_adj_sid *next; + + uint8_t family; + uint8_t flags; + uint8_t weight; + uint32_t sid; +}; + +struct isis_lan_adj_sid; +struct isis_lan_adj_sid { + struct isis_lan_adj_sid *next; + + uint8_t family; + uint8_t flags; + uint8_t weight; + uint8_t neighbor_id[ISIS_SYS_ID_LEN]; + uint32_t sid; +}; + +/* RFC 4971 & RFC 7981 */ +#define ISIS_ROUTER_CAP_FLAG_S 0x01 +#define ISIS_ROUTER_CAP_FLAG_D 0x02 +#define ISIS_ROUTER_CAP_SIZE 5 + +/* Number of supported algorithm for Segment Routing. + * Right now only 2 have been standardized: + * - 0: SPF + * - 1: Strict SPF + */ +#define SR_ALGORITHM_COUNT 2 +#define SR_ALGORITHM_SPF 0 +#define SR_ALGORITHM_STRICT_SPF 1 +#define SR_ALGORITHM_UNSET 255 + +struct isis_router_cap { + struct in_addr router_id; + uint8_t flags; + + /* draft-ietf-segment-routing-extensions-25 */ + struct isis_srgb srgb; + uint8_t algo[SR_ALGORITHM_COUNT]; + /* RFC 8491 */ +#define MSD_TYPE_BASE_MPLS_IMPOSITION 0x01 + uint8_t msd; +}; + struct isis_item; struct isis_item { struct isis_item *next; @@ -233,26 +324,10 @@ struct isis_tlvs { struct isis_item_list ipv6_reach; struct isis_mt_item_list mt_ipv6_reach; struct isis_threeway_adj *threeway_adj; + struct isis_router_cap *router_cap; struct isis_spine_leaf *spine_leaf; }; -#define ISIS_PREFIX_SID_READVERTISED 0x80 -#define ISIS_PREFIX_SID_NODE 0x40 -#define ISIS_PREFIX_SID_NO_PHP 0x20 -#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10 -#define ISIS_PREFIX_SID_VALUE 0x08 -#define ISIS_PREFIX_SID_LOCAL 0x04 - -struct isis_prefix_sid; -struct isis_prefix_sid { - struct isis_prefix_sid *next; - - uint8_t flags; - uint8_t algorithm; - - uint32_t value; -}; - enum isis_tlv_context { ISIS_CONTEXT_LSP, ISIS_CONTEXT_SUBTLV_NE_REACH, @@ -266,11 +341,12 @@ struct isis_subtlvs { /* draft-baker-ipv6-isis-dst-src-routing-06 */ struct prefix_ipv6 *source_prefix; - /* draft-ietf-isis-segment-routing-extensions-16 */ + /* draft-ietf-isis-segment-routing-extensions-25 */ struct isis_item_list prefix_sids; }; enum isis_tlv_type { + /* TLVs code point */ ISIS_TLV_AREA_ADDRESSES = 1, ISIS_TLV_OLDSTYLE_REACH = 2, ISIS_TLV_LAN_NEIGHBORS = 6, @@ -295,10 +371,149 @@ enum isis_tlv_type { ISIS_TLV_IPV6_REACH = 236, ISIS_TLV_MT_IPV6_REACH = 237, ISIS_TLV_THREE_WAY_ADJ = 240, + ISIS_TLV_ROUTER_CAPABILITY = 242, ISIS_TLV_MAX = 256, + /* subTLVs code point */ + ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22, + + /* RFC 5305 & RFC 6119 */ + ISIS_SUBTLV_ADMIN_GRP = 3, + ISIS_SUBTLV_LOCAL_IPADDR = 6, + ISIS_SUBTLV_RMT_IPADDR = 8, + ISIS_SUBTLV_MAX_BW = 9, + ISIS_SUBTLV_MAX_RSV_BW = 10, + ISIS_SUBTLV_UNRSV_BW = 11, + ISIS_SUBTLV_LOCAL_IPADDR6 = 12, + ISIS_SUBTLV_RMT_IPADDR6 = 13, + ISIS_SUBTLV_TE_METRIC = 18, + + /* RFC 5307 */ + ISIS_SUBTLV_LLRI = 4, + + /* RFC 5316 */ + ISIS_SUBTLV_RAS = 24, + ISIS_SUBTLV_RIP = 25, + + /* draft-isis-segment-routing-extension-25 */ + ISIS_SUBTLV_SID_LABEL = 1, + ISIS_SUBTLV_SID_LABEL_RANGE = 2, + ISIS_SUBTLV_ALGORITHM = 19, + ISIS_SUBTLV_NODE_MSD = 23, ISIS_SUBTLV_PREFIX_SID = 3, - ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22 + ISIS_SUBTLV_ADJ_SID = 31, + ISIS_SUBTLV_LAN_ADJ_SID = 32, + + /* RFC 7810 */ + ISIS_SUBTLV_AV_DELAY = 33, + ISIS_SUBTLV_MM_DELAY = 34, + ISIS_SUBTLV_DELAY_VAR = 35, + ISIS_SUBTLV_PKT_LOSS = 36, + ISIS_SUBTLV_RES_BW = 37, + ISIS_SUBTLV_AVA_BW = 38, + ISIS_SUBTLV_USE_BW = 39, + + ISIS_SUBTLV_MAX = 40 +}; + +/* subTLVs size for TE and SR */ +enum ext_subtlv_size { + ISIS_SUBTLV_LLRI_SIZE = 8, + + ISIS_SUBTLV_UNRSV_BW_SIZE = 32, + ISIS_SUBTLV_TE_METRIC_SIZE = 3, + ISIS_SUBTLV_IPV6_ADDR_SIZE = 16, + + /* draft-isis-segment-routing-extension-25 */ + ISIS_SUBTLV_SID_LABEL_SIZE = 3, + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9, + ISIS_SUBTLV_ALGORITHM_SIZE = 4, + ISIS_SUBTLV_NODE_MSD_SIZE = 2, + ISIS_SUBTLV_ADJ_SID_SIZE = 5, + ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11, + ISIS_SUBTLV_PREFIX_SID_SIZE = 5, + + ISIS_SUBTLV_MM_DELAY_SIZE = 8, + + ISIS_SUBTLV_HDR_SIZE = 2, + ISIS_SUBTLV_DEF_SIZE = 4, + + ISIS_SUBTLV_MAX_SIZE = 180 +}; + +/* Macros to manage the optional presence of EXT subTLVs */ +#define SET_SUBTLV(s, t) ((s->status) |= (t)) +#define UNSET_SUBTLV(s, t) ((s->status) &= ~(t)) +#define IS_SUBTLV(s, t) (s->status & t) + +#define EXT_DISABLE 0x000000 +#define EXT_ADM_GRP 0x000001 +#define EXT_LLRI 0x000002 +#define EXT_LOCAL_ADDR 0x000004 +#define EXT_NEIGH_ADDR 0x000008 +#define EXT_LOCAL_ADDR6 0x000010 +#define EXT_NEIGH_ADDR6 0x000020 +#define EXT_MAX_BW 0x000040 +#define EXT_MAX_RSV_BW 0x000080 +#define EXT_UNRSV_BW 0x000100 +#define EXT_TE_METRIC 0x000200 +#define EXT_RMT_AS 0x000400 +#define EXT_RMT_IP 0x000800 +#define EXT_ADJ_SID 0x001000 +#define EXT_LAN_ADJ_SID 0x002000 +#define EXT_DELAY 0x004000 +#define EXT_MM_DELAY 0x008000 +#define EXT_DELAY_VAR 0x010000 +#define EXT_PKT_LOSS 0x020000 +#define EXT_RES_BW 0x040000 +#define EXT_AVA_BW 0x080000 +#define EXT_USE_BW 0x100000 + +/* + * This structure groups all Extended IS Reachability subTLVs. + * + * Each bit of the status field indicates if a subTLVs is valid or not. + * SubTLVs values use following units: + * - Bandwidth in bytes/sec following IEEE format, + * - Delay in micro-seconds with only 24 bits significant + * - Packet Loss in percentage of total traffic with only 24 bits (2^24 - 2) + * + * For Delay and packet Loss, upper bit (A) indicates if the value is + * normal (0) or anomalous (1). + */ +#define IS_ANORMAL(v) (v & 0x80000000) + +struct isis_ext_subtlvs { + + uint32_t status; + + uint32_t adm_group; /* Resource Class/Color - RFC 5305 */ + /* Link Local/Remote Identifiers - RFC 5307 */ + uint32_t local_llri; + uint32_t remote_llri; + struct in_addr local_addr; /* Local IP Address - RFC 5305 */ + struct in_addr neigh_addr; /* Neighbor IP Address - RFC 5305 */ + struct in6_addr local_addr6; /* Local IPv6 Address - RFC 6119 */ + struct in6_addr neigh_addr6; /* Neighbor IPv6 Address - RFC 6119 */ + float max_bw; /* Maximum Bandwidth - RFC 5305 */ + float max_rsv_bw; /* Maximum Reservable Bandwidth - RFC 5305 */ + float unrsv_bw[8]; /* Unreserved Bandwidth - RFC 5305 */ + uint32_t te_metric; /* Traffic Engineering Metric - RFC 5305 */ + uint32_t remote_as; /* Remote AS Number sub-TLV - RFC5316 */ + struct in_addr remote_ip; /* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ + + uint32_t delay; /* Average Link Delay - RFC 8570 */ + uint32_t min_delay; /* Low Link Delay - RFC 8570 */ + uint32_t max_delay; /* High Link Delay - RFC 8570 */ + uint32_t delay_var; /* Link Delay Variation i.e. Jitter - RFC 8570 */ + uint32_t pkt_loss; /* Unidirectional Link Packet Loss - RFC 8570 */ + float res_bw; /* Unidirectional Residual Bandwidth - RFC 8570 */ + float ava_bw; /* Unidirectional Available Bandwidth - RFC 8570 */ + float use_bw; /* Unidirectional Utilized Bandwidth - RFC 8570 */ + + /* Segment Routing Adjacency & LAN Adjacency Segment ID */ + struct isis_item_list adj_sid; + struct isis_item_list lan_sid; }; #define IS_COMPAT_MT_TLV(tlv_type) \ @@ -329,7 +544,6 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size); #define ISIS_MT_AT_MASK 0x4000 #endif - void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd); void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs, struct list *addresses); @@ -359,6 +573,8 @@ void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id, struct isis_lsp **last_lsp); void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, const char *hostname); +void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs, + const struct isis_router_cap *cap); void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, const struct in_addr *id); void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, @@ -371,11 +587,21 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid, struct prefix_ipv6 *dest, struct prefix_ipv6 *src, uint32_t metric); +struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void); +void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj); +void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj); +void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan); +void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan); + void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, uint8_t metric); void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len); + struct isis_ext_subtlvs *subtlvs); const char *isis_threeway_state_name(enum isis_threeway_state state); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index e8481a558b..bdf6869f5c 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -72,77 +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); - - 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; @@ -219,9 +148,9 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS) return 0; } -static void isis_zebra_route_add_route(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) +void isis_zebra_route_add_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -229,7 +158,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix, struct listnode *node; int count = 0; - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + if (zclient->sock < 0) return; memset(&api, 0, sizeof(api)); @@ -292,17 +221,15 @@ static void isis_zebra_route_add_route(struct prefix *prefix, api.nexthop_num = count; zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); - SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } -static void isis_zebra_route_del_route(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) +void isis_zebra_route_del_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) { struct zapi_route api; - if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + if (zclient->sock < 0) return; memset(&api, 0, sizeof(api)); @@ -316,20 +243,6 @@ static void isis_zebra_route_del_route(struct prefix *prefix, } zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); -} - -void isis_zebra_route_update(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) -{ - if (zclient->sock < 0) - return; - - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) - isis_zebra_route_add_route(prefix, src_p, route_info); - else - isis_zebra_route_del_route(prefix, src_p, route_info); } static int isis_zebra_read(ZAPI_CALLBACK_ARGS) @@ -400,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 20c10d0b23..d00f348c8e 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -29,9 +29,12 @@ void isis_zebra_stop(void); struct isis_route_info; -void isis_zebra_route_update(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info); +void isis_zebra_route_add_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); +void isis_zebra_route_del_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); int isis_distribute_list_update(int routetype); void isis_zebra_redistribute_set(afi_t afi, int type); void isis_zebra_redistribute_unset(afi_t afi, int type); diff --git a/isisd/isisd.c b/isisd/isisd.c index 67f557ab50..029a9e0688 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -75,12 +75,13 @@ int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); -void isis_new(unsigned long process_id) +void isis_new(unsigned long process_id, vrf_id_t vrf_id) { isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); /* * Default values */ + isis->vrf_id = vrf_id; isis->max_area_addrs = 3; isis->process_id = process_id; isis->router_id = 0; diff --git a/isisd/isisd.h b/isisd/isisd.h index 393b1d67c7..f825b6ecb4 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -58,11 +58,11 @@ extern struct zebra_privs_t isisd_privs; /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ -/* #define EXTREME_DICT_DEBUG */ struct fabricd; struct isis { + vrf_id_t vrf_id; unsigned long process_id; int sysid_set; uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ @@ -190,7 +190,7 @@ struct isis_area { DECLARE_QOBJ_TYPE(isis_area) void isis_init(void); -void isis_new(unsigned long); +void isis_new(unsigned long process_id, vrf_id_t vrf_id); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup(const char *); int isis_area_get(struct vty *vty, const char *area_tag); diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 7f2e396a7f..b234e3ebe3 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -249,7 +249,7 @@ l2vpn_pw_init(struct l2vpn_pw *pw) l2vpn_pw_fec(pw, &fec); lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, - 0, (void *)pw); + 0, 0, (void *)pw); lde_kernel_update(&fec); } @@ -260,7 +260,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw) struct zapi_pw zpw; l2vpn_pw_fec(pw, &fec); - lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); + lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0); lde_kernel_update(&fec); pw2zpw(pw, &zpw); @@ -433,7 +433,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) if (pw == NULL) return; - fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0); + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0); if (fnh == NULL) return; @@ -482,7 +482,7 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) } fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, - 0, 0); + 0, 0, 0); if (fnh == NULL) continue; diff --git a/ldpd/lde.c b/ldpd/lde.c index ac680b47a9..006d27f6ab 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -520,7 +520,8 @@ lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: lde_kernel_insert(&fec, kr->af, &kr->nexthop, - kr->ifindex, kr->priority, + kr->ifindex, kr->route_type, + kr->route_instance, kr->flags & F_CONNECTED, NULL); break; case IMSG_NETWORK_UPDATE: @@ -747,7 +748,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); @@ -761,7 +763,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); @@ -798,7 +801,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); @@ -812,7 +816,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); diff --git a/ldpd/lde.h b/ldpd/lde.h index 0a7d0a58fe..ce466c16b9 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -108,7 +108,8 @@ struct fec_nh { union ldpd_addr nexthop; ifindex_t ifindex; uint32_t remote_label; - uint8_t priority; + uint8_t route_type; + unsigned short route_instance; uint8_t flags; }; #define F_FEC_NH_NEW 0x01 @@ -193,11 +194,11 @@ void rt_dump(pid_t); void fec_snap(struct lde_nbr *); void fec_tree_clear(void); struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); void lde_kernel_insert(struct fec *, int, union ldpd_addr *, - ifindex_t, uint8_t, int, void *); + ifindex_t, uint8_t, unsigned short, int, void *); void lde_kernel_remove(struct fec *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); void lde_kernel_update(struct fec *); void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_request(struct map *, struct lde_nbr *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 0957a5455e..eb1a6d9434 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -31,7 +31,7 @@ static int lde_nbr_is_nexthop(struct fec_node *, static void fec_free(void *); static struct fec_node *fec_add(struct fec *fec); static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); static void fec_nh_del(struct fec_nh *); RB_GENERATE(fec_tree, fec, entry, fec_compare) @@ -275,7 +275,7 @@ fec_add(struct fec *fec) struct fec_nh * fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_nh *fnh; @@ -283,7 +283,8 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, if (fnh->af == af && ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 && fnh->ifindex == ifindex && - fnh->priority == priority) + fnh->route_type == route_type && + fnh->route_instance == route_instance) return (fnh); return (NULL); @@ -291,7 +292,7 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, static struct fec_nh * fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_nh *fnh; @@ -303,7 +304,8 @@ fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, fnh->nexthop = *nexthop; fnh->ifindex = ifindex; fnh->remote_label = NO_LABEL; - fnh->priority = priority; + fnh->route_type = route_type; + fnh->route_instance = route_instance; LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); return (fnh); @@ -318,7 +320,8 @@ fec_nh_del(struct fec_nh *fnh) void lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority, int connected, void *data) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance, + int connected, void *data) { struct fec_node *fn; struct fec_nh *fnh; @@ -329,9 +332,10 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, if (data) fn->data = data; - fnh = fec_nh_find(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); if (fnh == NULL) - fnh = fec_nh_add(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type, + route_instance); fnh->flags |= F_FEC_NH_NEW; if (connected) fnh->flags |= F_FEC_NH_CONNECTED; @@ -339,7 +343,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, void lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_node *fn; struct fec_nh *fnh; @@ -348,7 +352,7 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, if (fn == NULL) /* route lost */ return; - fnh = fec_nh_find(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); if (fnh == NULL) /* route lost */ return; diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 35a7d944d3..4df1fc0304 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -37,11 +37,8 @@ static void ifp2kif(struct interface *, struct kif *); static void ifc2kaddr(struct interface *, struct connected *, struct kaddr *); -static int zebra_send_mpls_labels(int, struct kroute *); +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); @@ -106,9 +103,10 @@ pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) } static int -zebra_send_mpls_labels(int cmd, struct kroute *kr) +ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr) { - struct stream *s; + struct zapi_labels zl = {}; + struct zapi_nexthop_label *znh; if (kr->local_label < MPLS_LABEL_RESERVED_MAX || kr->remote_label == NO_LABEL) @@ -120,48 +118,65 @@ zebra_send_mpls_labels(int cmd, struct kroute *kr) log_label(kr->local_label), log_label(kr->remote_label), (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete"); - /* Reset stream. */ - s = zclient->obuf; - stream_reset(s); + zl.type = ZEBRA_LSP_LDP; + zl.local_label = kr->local_label; - zclient_create_header(s, cmd, VRF_DEFAULT); - stream_putc(s, ZEBRA_LSP_LDP); - stream_putl(s, kr->af); + /* Set prefix. */ + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.family = kr->af; switch (kr->af) { case AF_INET: - stream_put_in_addr(s, &kr->prefix.v4); - stream_putc(s, kr->prefixlen); - stream_put_in_addr(s, &kr->nexthop.v4); + zl.route.prefix.u.prefix4 = kr->prefix.v4; break; case AF_INET6: - stream_write(s, (uint8_t *)&kr->prefix.v6, 16); - stream_putc(s, kr->prefixlen); - stream_write(s, (uint8_t *)&kr->nexthop.v6, 16); + zl.route.prefix.u.prefix6 = kr->prefix.v6; break; default: - fatalx("kr_change: unknown af"); + fatalx("ldp_zebra_send_mpls_labels: unknown af"); } - stream_putl(s, kr->ifindex); - stream_putc(s, kr->priority); - stream_putl(s, kr->local_label); - stream_putl(s, kr->remote_label); + zl.route.prefix.prefixlen = kr->prefixlen; + zl.route.type = kr->route_type; + zl.route.instance = kr->route_instance; - /* Put length at the first point of the stream. */ - stream_putw_at(s, 0, stream_get_endp(s)); + /* Set nexthop. */ + zl.nexthop_num = 1; + znh = &zl.nexthops[0]; + switch (kr->af) { + case AF_INET: + znh->family = AF_INET; + znh->address.ipv4 = kr->nexthop.v4; + if (kr->ifindex) + znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + znh->type = NEXTHOP_TYPE_IPV4; + break; + case AF_INET6: + znh->family = AF_INET6; + znh->address.ipv6 = kr->nexthop.v6; + if (kr->ifindex) + znh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + else + znh->type = NEXTHOP_TYPE_IPV6; + break; + default: + break; + } + znh->ifindex = kr->ifindex; + znh->label = kr->remote_label; - return (zclient_send_message(zclient)); + return zebra_send_mpls_labels(zclient, cmd, &zl); } int kr_change(struct kroute *kr) { - return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr)); + return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr)); } int kr_delete(struct kroute *kr) { - return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr)); + return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr)); } int @@ -246,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)); @@ -286,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); @@ -324,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) { @@ -407,7 +411,8 @@ ldp_zebra_read_route(ZAPI_CALLBACK_ARGS) break; } kr.prefixlen = api.prefix.prefixlen; - kr.priority = api.distance; + kr.route_type = api.type; + kr.route_instance = api.instance; switch (api.type) { case ZEBRA_ROUTE_CONNECT: @@ -516,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); @@ -523,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; diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 9113505581..bd7562e5ad 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -543,7 +543,8 @@ struct kroute { uint32_t local_label; uint32_t remote_label; unsigned short ifindex; - uint8_t priority; + uint8_t route_type; + uint8_t route_instance; uint16_t flags; }; diff --git a/lib/command.c b/lib/command.c index de28a726b0..04f2bd95a0 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1061,8 +1061,10 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, vty->num_cfg_changes = 0; memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes)); - /* Regenerate candidate configuration. */ - if (frr_get_cli_mode() == FRR_CLI_CLASSIC) + /* Regenerate candidate configuration if necessary. */ + if (frr_get_cli_mode() == FRR_CLI_CLASSIC + && running_config->version + > vty->candidate_config->version) nb_config_replace(vty->candidate_config, running_config, true); } @@ -1716,16 +1718,12 @@ static int vty_write_config(struct vty *vty) vty_out(vty, "frr defaults %s\n", DFLT_NAME); vty_out(vty, "!\n"); - pthread_rwlock_rdlock(&running_config->lock); - { - for (i = 0; i < vector_active(cmdvec); i++) - if ((node = vector_slot(cmdvec, i)) && node->func - && (node->vtysh || vty->type != VTY_SHELL)) { - if ((*node->func)(vty)) - vty_out(vty, "!\n"); - } - } - pthread_rwlock_unlock(&running_config->lock); + for (i = 0; i < vector_active(cmdvec); i++) + if ((node = vector_slot(cmdvec, i)) && node->func + && (node->vtysh || vty->type != VTY_SHELL)) { + if ((*node->func)(vty)) + vty_out(vty, "!\n"); + } if (vty->type == VTY_TERM) { vty_out(vty, "end\n"); diff --git a/lib/command.h b/lib/command.h index 137d3748ae..d5dc129c72 100644 --- a/lib/command.h +++ b/lib/command.h @@ -412,7 +412,7 @@ struct cmd_node { #define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n" #define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n" -/* Dameons lists */ +/* Daemons lists */ #define DAEMONS_STR \ "For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\n" #define DAEMONS_LIST \ diff --git a/lib/command_match.c b/lib/command_match.c index 26d763849d..0195aebc17 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -724,7 +724,12 @@ static enum match_type match_ipv4(const char *str) return no_match; memcpy(buf, sp, str - sp); - if (atoi(buf) > 255) + + int v = atoi(buf); + + if (v > 255) + return no_match; + if (v > 0 && buf[0] == '0') return no_match; nums++; @@ -775,7 +780,12 @@ static enum match_type match_ipv4_prefix(const char *str) return no_match; memcpy(buf, sp, str - sp); - if (atoi(buf) > 255) + + int v = atoi(buf); + + if (v > 255) + return no_match; + if (v > 0 && buf[0] == '0') return no_match; if (dots == 3) { diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 21dfc9256f..5c71fac10a 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -35,6 +35,9 @@ DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives") static void *fpt_run(void *arg); static int fpt_halt(struct frr_pthread *fpt, void **res); +/* misc sigs */ +static void frr_pthread_destroy_nolock(struct frr_pthread *fpt); + /* default frr_pthread attributes */ struct frr_pthread_attr frr_pthread_attr_default = { .start = fpt_run, @@ -51,13 +54,22 @@ void frr_pthread_init(void) { frr_with_mutex(&frr_pthread_list_mtx) { frr_pthread_list = list_new(); - frr_pthread_list->del = (void (*)(void *))&frr_pthread_destroy; } } void frr_pthread_finish(void) { + frr_pthread_stop_all(); + frr_with_mutex(&frr_pthread_list_mtx) { + struct listnode *n, *nn; + struct frr_pthread *fpt; + + for (ALL_LIST_ELEMENTS(frr_pthread_list, n, nn, fpt)) { + listnode_delete(frr_pthread_list, fpt); + frr_pthread_destroy_nolock(fpt); + } + list_delete(&frr_pthread_list); } } @@ -97,10 +109,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr, return fpt; } -void frr_pthread_destroy(struct frr_pthread *fpt) +static void frr_pthread_destroy_nolock(struct frr_pthread *fpt) { thread_master_free(fpt->master); - pthread_mutex_destroy(&fpt->mtx); pthread_mutex_destroy(fpt->running_cond_mtx); pthread_cond_destroy(fpt->running_cond); @@ -110,6 +121,15 @@ void frr_pthread_destroy(struct frr_pthread *fpt) XFREE(MTYPE_FRR_PTHREAD, fpt); } +void frr_pthread_destroy(struct frr_pthread *fpt) +{ + frr_with_mutex(&frr_pthread_list_mtx) { + listnode_delete(frr_pthread_list, fpt); + } + + frr_pthread_destroy_nolock(fpt); +} + int frr_pthread_set_name(struct frr_pthread *fpt) { int ret = 0; @@ -183,8 +203,11 @@ void frr_pthread_stop_all(void) frr_with_mutex(&frr_pthread_list_mtx) { struct listnode *n; struct frr_pthread *fpt; - for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt)) - frr_pthread_stop(fpt, NULL); + for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt)) { + if (atomic_load_explicit(&fpt->running, + memory_order_relaxed)) + frr_pthread_stop(fpt, NULL); + } } } @@ -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); @@ -207,21 +242,18 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) if (yang_module_find("frr-interface")) { struct lyd_node *if_dnode; - pthread_rwlock_wrlock(&running_config->lock); - { - if_dnode = yang_dnode_get( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf", - ifp->name, old_vrf->name); - if (if_dnode) { - yang_dnode_change_leaf(if_dnode, vrf->name); - running_config->version++; - } + if_dnode = yang_dnode_get( + running_config->dnode, + "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf", + ifp->name, old_vrf->name); + if (if_dnode) { + yang_dnode_change_leaf(if_dnode, vrf->name); + running_config->version++; } - pthread_rwlock_unlock(&running_config->lock); } } + /* Delete interface structure. */ void if_delete_retain(struct interface *ifp) { @@ -1199,7 +1231,7 @@ void if_link_params_free(struct interface *ifp) */ DEFPY_NOSH (interface, interface_cmd, - "interface IFNAME [vrf NAME$vrfname]", + "interface IFNAME [vrf NAME$vrf_name]", "Select an interface to configure\n" "Interface's name\n" VRF_CMD_HELP_STR) @@ -1209,8 +1241,8 @@ DEFPY_NOSH (interface, struct interface *ifp; int ret; - if (!vrfname) - vrfname = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; /* * This command requires special handling to maintain backward @@ -1219,7 +1251,7 @@ DEFPY_NOSH (interface, * interface is found, then a new one should be created on the default * VRF. */ - VRF_GET_ID(vrf_id, vrfname, false); + VRF_GET_ID(vrf_id, vrf_name, false); ifp = if_lookup_by_name_all_vrf(ifname); if (ifp && ifp->vrf_id != vrf_id) { struct vrf *vrf; @@ -1230,24 +1262,24 @@ DEFPY_NOSH (interface, */ if (vrf_id != VRF_DEFAULT) { vty_out(vty, "%% interface %s not in %s vrf\n", ifname, - vrfname); + vrf_name); return CMD_WARNING_CONFIG_FAILED; } /* * Special case 2: a VRF name was *not* specified, and the found * interface is associated to a VRF other than the default one. - * Update vrf_id and vrfname to account for that. + * Update vrf_id and vrf_name to account for that. */ vrf = vrf_lookup_by_id(ifp->vrf_id); assert(vrf); vrf_id = ifp->vrf_id; - vrfname = vrf->name; + vrf_name = vrf->name; } snprintf(xpath_list, sizeof(xpath_list), "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname, - vrfname); + vrf_name); nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); ret = nb_cli_apply_changes(vty, xpath_list); @@ -1270,20 +1302,20 @@ DEFPY_NOSH (interface, DEFPY (no_interface, no_interface_cmd, - "no interface IFNAME [vrf NAME$vrfname]", + "no interface IFNAME [vrf NAME$vrf_name]", NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n" VRF_CMD_HELP_STR) { - if (!vrfname) - vrfname = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifname, vrfname); + ifname, vrf_name); } static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, @@ -1370,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 ------- */ /* @@ -1426,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; } @@ -1453,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; } @@ -1461,6 +1508,60 @@ static int lib_interface_destroy(enum nb_event event, } /* + * XPath: /frr-interface:lib/interface + */ +static const void *lib_interface_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct vrf *vrf; + struct interface *pif = (struct interface *)list_entry; + + if (list_entry == NULL) { + vrf = RB_MIN(vrf_name_head, &vrfs_by_name); + assert(vrf); + pif = RB_MIN(if_name_head, &vrf->ifaces_by_name); + } else { + vrf = vrf_lookup_by_id(pif->vrf_id); + pif = RB_NEXT(if_name_head, pif); + /* if no more interfaces, switch to next vrf */ + while (pif == NULL) { + vrf = RB_NEXT(vrf_name_head, vrf); + if (!vrf) + return NULL; + pif = RB_MIN(if_name_head, &vrf->ifaces_by_name); + } + } + + return pif; +} + +static int lib_interface_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + const struct interface *ifp = list_entry; + + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + assert(vrf); + + keys->num = 2; + strlcpy(keys->key[0], ifp->name, sizeof(keys->key[0])); + strlcpy(keys->key[1], vrf->name, sizeof(keys->key[1])); + + return NB_OK; +} + +static const void *lib_interface_lookup_entry(const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + const char *ifname = keys->key[0]; + const char *vrfname = keys->key[1]; + struct vrf *vrf = vrf_lookup_by_name(vrfname); + + return if_lookup_by_name(ifname, vrf->vrf_id); +} + +/* * XPath: /frr-interface:lib/interface/description */ static int lib_interface_description_modify(enum nb_event event, @@ -1505,6 +1606,9 @@ const struct frr_yang_module_info frr_interface_info = { .create = lib_interface_create, .destroy = lib_interface_destroy, .cli_show = cli_show_interface, + .get_next = lib_interface_get_next, + .get_keys = lib_interface_get_keys, + .lookup_entry = lib_interface_lookup_entry, }, }, { @@ -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/libfrr.c b/lib/libfrr.c index 4301dc20ad..d4aa1f899a 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -42,6 +42,7 @@ #include "northbound_db.h" #include "debug.h" #include "frrcu.h" +#include "frr_pthread.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) DEFINE_KOOH(frr_early_fini, (), ()) @@ -681,6 +682,8 @@ struct thread_master *frr_init(void) memory_init(); log_filter_cmd_init(); + frr_pthread_init(); + log_ref_init(); log_ref_vty_init(); lib_error_init(); @@ -865,12 +868,7 @@ static int frr_config_read_in(struct thread *t) /* * Update the shared candidate after reading the startup configuration. */ - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_replace(vty_shared_candidate_config, running_config, - true); - } - pthread_rwlock_unlock(&running_config->lock); + nb_config_replace(vty_shared_candidate_config, running_config, true); return 0; } @@ -1076,6 +1074,7 @@ void frr_fini(void) db_close(); #endif log_ref_fini(); + frr_pthread_finish(); zprivs_terminate(di->privs); /* signal_init -> nothing needed */ thread_master_free(master); @@ -1041,6 +1041,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS), DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD), DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE), + DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE), DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS), DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT), DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC), diff --git a/lib/mpls.h b/lib/mpls.h index d7b56c47bd..635ecc77a1 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -47,6 +47,7 @@ extern "C" { #define MPLS_LABEL_OAM_ALERT 14 /* [RFC3429] */ #define MPLS_LABEL_EXTENSION 15 /* [RFC7274] */ #define MPLS_LABEL_MAX 1048575 +#define MPLS_LABEL_VALUE_MASK 0x000FFFFF #define MPLS_LABEL_NONE 0xFFFFFFFF /* for internal use only */ /* Minimum and maximum label values */ @@ -125,7 +126,7 @@ enum lsp_types_t { ZEBRA_LSP_STATIC = 1, /* Static LSP. */ ZEBRA_LSP_LDP = 2, /* LDP LSP. */ ZEBRA_LSP_BGP = 3, /* BGP LSP. */ - ZEBRA_LSP_SR = 4, /* Segment Routing LSP. */ + ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */ ZEBRA_LSP_SHARP = 5, /* Identifier for test protocol */ }; diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index abe2096cec..9564321d38 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -475,7 +475,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ |INTERFACE$intf\ >\ - [nexthop-vrf NAME$name]", + [nexthop-vrf NAME$vrf_name]", NO_STR "Specify one of the nexthops in this ECMP group\n" "v4 Address\n" @@ -490,7 +490,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, struct nexthop *nh; bool legal; - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name); + legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name); if (nhop.type == NEXTHOP_TYPE_IPV6 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -502,7 +502,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nh = nexthop_exists(&nhgc->nhg, &nhop); if (no) { - nexthop_group_unsave_nhop(nhgc, name, addr, intf); + nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf); if (nh) { _nexthop_del(&nhgc->nhg, nh); @@ -520,7 +520,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, _nexthop_add(&nhgc->nhg.nexthop, nh); } - nexthop_group_save_nhop(nhgc, name, addr, intf); + nexthop_group_save_nhop(nhgc, vrf_name, addr, intf); if (legal && nhg_hooks.add_nexthop) nhg_hooks.add_nexthop(nhgc, nh); diff --git a/lib/northbound.c b/lib/northbound.c index a814f23e14..1b332fb1e8 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -64,6 +64,9 @@ static bool transaction_in_progress; static int nb_callback_configuration(const enum nb_event event, struct nb_config_change *change); +static void nb_log_callback(const enum nb_event event, + enum nb_operation operation, const char *xpath, + const char *value); static struct nb_transaction *nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, enum nb_client client, @@ -180,7 +183,18 @@ static int nb_node_validate_cb(const struct nb_node *nb_node, valid = nb_operation_is_valid(operation, nb_node->snode); - if (!valid && callback_implemented) + /* + * Add an exception for operational data callbacks. A rw list usually + * doesn't need any associated operational data callbacks. But if this + * rw list is augmented by another module which adds state nodes under + * it, then this list will need to have the 'get_next()', 'get_keys()' + * and 'lookup_entry()' callbacks. As such, never log a warning when + * these callbacks are implemented when they are not needed, since this + * depends on context (e.g. some daemons might augment "frr-interface" + * while others don't). + */ + if (!valid && callback_implemented && operation != NB_OP_GET_NEXT + && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY) flog_warn(EC_LIB_NB_CB_UNNEEDED, "unneeded '%s' callback for '%s'", nb_operation_name(operation), nb_node->xpath); @@ -211,6 +225,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) !!nb_node->cbs.destroy, false); error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move, false); + error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE, + !!nb_node->cbs.pre_validate, true); error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH, !!nb_node->cbs.apply_finish, true); error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM, @@ -265,7 +281,6 @@ struct nb_config *nb_config_new(struct lyd_node *dnode) else config->dnode = yang_dnode_new(ly_native_ctx, true); config->version = 0; - pthread_rwlock_init(&config->lock, NULL); return config; } @@ -274,7 +289,6 @@ void nb_config_free(struct nb_config *config) { if (config->dnode) yang_dnode_free(config->dnode); - pthread_rwlock_destroy(&config->lock); XFREE(MTYPE_NB_CONFIG, config); } @@ -285,7 +299,6 @@ struct nb_config *nb_config_dup(const struct nb_config *config) dup = XCALLOC(MTYPE_NB_CONFIG, sizeof(*dup)); dup->dnode = yang_dnode_dup(config->dnode); dup->version = config->version; - pthread_rwlock_init(&dup->lock, NULL); return dup; } @@ -335,21 +348,23 @@ static inline int nb_config_cb_compare(const struct nb_config_cb *a, return 1; /* - * Use XPath as a tie-breaker. This will naturally sort parent nodes - * before their children. + * Preserve the order of the configuration changes as told by libyang. */ - return strcmp(a->xpath, b->xpath); + return a->seq - b->seq; } RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare); static void nb_config_diff_add_change(struct nb_config_cbs *changes, enum nb_operation operation, + uint32_t *seq, const struct lyd_node *dnode) { struct nb_config_change *change; change = XCALLOC(MTYPE_TMP, sizeof(*change)); change->cb.operation = operation; + change->cb.seq = *seq; + *seq = *seq + 1; change->cb.nb_node = dnode->schema->priv; yang_dnode_get_path(dnode, change->cb.xpath, sizeof(change->cb.xpath)); change->cb.dnode = dnode; @@ -374,7 +389,7 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes) * configurations. Given a new subtree, calculate all new YANG data nodes, * excluding default leafs and leaf-lists. This is a recursive function. */ -static void nb_config_diff_created(const struct lyd_node *dnode, +static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq, struct nb_config_cbs *changes) { enum nb_operation operation; @@ -393,16 +408,17 @@ static void nb_config_diff_created(const struct lyd_node *dnode, else return; - nb_config_diff_add_change(changes, operation, dnode); + nb_config_diff_add_change(changes, operation, seq, dnode); break; case LYS_CONTAINER: case LYS_LIST: if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) - nb_config_diff_add_change(changes, NB_OP_CREATE, dnode); + nb_config_diff_add_change(changes, NB_OP_CREATE, seq, + dnode); /* Process child nodes recursively. */ LY_TREE_FOR (dnode->child, child) { - nb_config_diff_created(child, changes); + nb_config_diff_created(child, seq, changes); } break; default: @@ -410,11 +426,11 @@ static void nb_config_diff_created(const struct lyd_node *dnode, } } -static void nb_config_diff_deleted(const struct lyd_node *dnode, +static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq, struct nb_config_cbs *changes) { if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema)) - nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode); + nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode); else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) { struct lyd_node *child; @@ -425,7 +441,7 @@ static void nb_config_diff_deleted(const struct lyd_node *dnode, * when applicable (i.e. optional nodes). */ LY_TREE_FOR (dnode->child, child) { - nb_config_diff_deleted(child, changes); + nb_config_diff_deleted(child, seq, changes); } } } @@ -436,6 +452,7 @@ static void nb_config_diff(const struct nb_config *config1, struct nb_config_cbs *changes) { struct lyd_difflist *diff; + uint32_t seq = 0; diff = lyd_diff(config1->dnode, config2->dnode, LYD_DIFFOPT_WITHDEFAULTS); @@ -450,15 +467,16 @@ static void nb_config_diff(const struct nb_config *config1, switch (type) { case LYD_DIFF_CREATED: dnode = diff->second[i]; - nb_config_diff_created(dnode, changes); + nb_config_diff_created(dnode, &seq, changes); break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - nb_config_diff_deleted(dnode, changes); + nb_config_diff_deleted(dnode, &seq, changes); break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; - nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode); + nb_config_diff_add_change(changes, NB_OP_MODIFY, &seq, + dnode); break; case LYD_DIFF_MOVEDAFTER1: case LYD_DIFF_MOVEDAFTER2: @@ -535,28 +553,17 @@ int nb_candidate_edit(struct nb_config *candidate, bool nb_candidate_needs_update(const struct nb_config *candidate) { - bool ret = false; - - pthread_rwlock_rdlock(&running_config->lock); - { - if (candidate->version < running_config->version) - ret = true; - } - pthread_rwlock_unlock(&running_config->lock); + if (candidate->version < running_config->version) + return true; - return ret; + return false; } int nb_candidate_update(struct nb_config *candidate) { struct nb_config *updated_config; - pthread_rwlock_rdlock(&running_config->lock); - { - updated_config = nb_config_dup(running_config); - } - pthread_rwlock_unlock(&running_config->lock); - + updated_config = nb_config_dup(running_config); if (nb_config_merge(updated_config, candidate, true) != NB_OK) return NB_ERR; @@ -583,14 +590,45 @@ static int nb_candidate_validate_yang(struct nb_config *candidate) } /* Perform code-level validation using the northbound callbacks. */ -static int nb_candidate_validate_changes(struct nb_config *candidate, - struct nb_config_cbs *changes) +static int nb_candidate_validate_code(struct nb_config *candidate, + struct nb_config_cbs *changes) { struct nb_config_cb *cb; + struct lyd_node *root, *next, *child; + int ret; + + /* First validate the candidate as a whole. */ + LY_TREE_FOR (candidate->dnode, root) { + LY_TREE_DFS_BEGIN (root, next, child) { + struct nb_node *nb_node; + + nb_node = child->schema->priv; + if (!nb_node->cbs.pre_validate) + goto next; + + if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, + DEBUG_MODE_ALL)) { + char xpath[XPATH_MAXLEN]; + + yang_dnode_get_path(child, xpath, + sizeof(xpath)); + nb_log_callback(NB_EV_VALIDATE, + NB_OP_PRE_VALIDATE, xpath, + NULL); + } + + ret = (*nb_node->cbs.pre_validate)(child); + if (ret != NB_OK) + return NB_ERR_VALIDATION; + next: + LY_TREE_DFS_END(root, next, child); + } + } + + /* Now validate the configuration changes. */ RB_FOREACH (cb, nb_config_cbs, changes) { struct nb_config_change *change = (struct nb_config_change *)cb; - int ret; ret = nb_callback_configuration(NB_EV_VALIDATE, change); if (ret != NB_OK) @@ -609,13 +647,9 @@ int nb_candidate_validate(struct nb_config *candidate) return NB_ERR_VALIDATION; RB_INIT(nb_config_cbs, &changes); - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_diff(running_config, candidate, &changes); - ret = nb_candidate_validate_changes(candidate, &changes); - nb_config_diff_del_changes(&changes); - } - pthread_rwlock_unlock(&running_config->lock); + nb_config_diff(running_config, candidate, &changes); + ret = nb_candidate_validate_code(candidate, &changes); + nb_config_diff_del_changes(&changes); return ret; } @@ -635,36 +669,26 @@ int nb_candidate_commit_prepare(struct nb_config *candidate, } RB_INIT(nb_config_cbs, &changes); - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_diff(running_config, candidate, &changes); - if (RB_EMPTY(nb_config_cbs, &changes)) { - pthread_rwlock_unlock(&running_config->lock); - return NB_ERR_NO_CHANGES; - } + nb_config_diff(running_config, candidate, &changes); + if (RB_EMPTY(nb_config_cbs, &changes)) + return NB_ERR_NO_CHANGES; - if (nb_candidate_validate_changes(candidate, &changes) - != NB_OK) { - flog_warn( - EC_LIB_NB_CANDIDATE_INVALID, - "%s: failed to validate candidate configuration", - __func__); - nb_config_diff_del_changes(&changes); - pthread_rwlock_unlock(&running_config->lock); - return NB_ERR_VALIDATION; - } + if (nb_candidate_validate_code(candidate, &changes) != NB_OK) { + flog_warn(EC_LIB_NB_CANDIDATE_INVALID, + "%s: failed to validate candidate configuration", + __func__); + nb_config_diff_del_changes(&changes); + return NB_ERR_VALIDATION; + } - *transaction = nb_transaction_new(candidate, &changes, client, - user, comment); - if (*transaction == NULL) { - flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED, - "%s: failed to create transaction", __func__); - nb_config_diff_del_changes(&changes); - pthread_rwlock_unlock(&running_config->lock); - return NB_ERR_LOCKED; - } + *transaction = + nb_transaction_new(candidate, &changes, client, user, comment); + if (*transaction == NULL) { + flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED, + "%s: failed to create transaction", __func__); + nb_config_diff_del_changes(&changes); + return NB_ERR_LOCKED; } - pthread_rwlock_unlock(&running_config->lock); return nb_transaction_process(NB_EV_PREPARE, *transaction); } @@ -683,11 +707,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction, /* Replace running by candidate. */ transaction->config->version++; - pthread_rwlock_wrlock(&running_config->lock); - { - nb_config_replace(running_config, transaction->config, true); - } - pthread_rwlock_unlock(&running_config->lock); + nb_config_replace(running_config, transaction->config, true); /* Record transaction. */ if (save_transaction @@ -961,52 +981,40 @@ static int nb_transaction_process(enum nb_event event, { struct nb_config_cb *cb; - /* - * Need to lock the running configuration since transaction->changes - * can contain pointers to data nodes from the running configuration. - */ - pthread_rwlock_rdlock(&running_config->lock); - { - RB_FOREACH (cb, nb_config_cbs, &transaction->changes) { - struct nb_config_change *change = - (struct nb_config_change *)cb; - int ret; + RB_FOREACH (cb, nb_config_cbs, &transaction->changes) { + struct nb_config_change *change = (struct nb_config_change *)cb; + int ret; + /* + * Only try to release resources that were allocated + * successfully. + */ + if (event == NB_EV_ABORT && change->prepare_ok == false) + break; + + /* Call the appropriate callback. */ + ret = nb_callback_configuration(event, change); + switch (event) { + case NB_EV_PREPARE: + if (ret != NB_OK) + return ret; + change->prepare_ok = true; + break; + case NB_EV_ABORT: + case NB_EV_APPLY: /* - * Only try to release resources that were allocated - * successfully. + * At this point it's not possible to reject the + * transaction anymore, so any failure here can lead to + * inconsistencies and should be treated as a bug. + * Operations prone to errors, like validations and + * resource allocations, should be performed during the + * 'prepare' phase. */ - if (event == NB_EV_ABORT && change->prepare_ok == false) - break; - - /* Call the appropriate callback. */ - ret = nb_callback_configuration(event, change); - switch (event) { - case NB_EV_PREPARE: - if (ret != NB_OK) { - pthread_rwlock_unlock( - &running_config->lock); - return ret; - } - change->prepare_ok = true; - break; - case NB_EV_ABORT: - case NB_EV_APPLY: - /* - * At this point it's not possible to reject the - * transaction anymore, so any failure here can - * lead to inconsistencies and should be treated - * as a bug. Operations prone to errors, like - * validations and resource allocations, should - * be performed during the 'prepare' phase. - */ - break; - default: - break; - } + break; + default: + break; } } - pthread_rwlock_unlock(&running_config->lock); return NB_OK; } @@ -1310,9 +1318,27 @@ static int nb_oper_data_iter_node(const struct lys_node *snode, /* Update XPath. */ strlcpy(xpath, xpath_parent, sizeof(xpath)); - if (!first && snode->nodetype != LYS_USES) - snprintf(xpath + strlen(xpath), sizeof(xpath) - strlen(xpath), - "/%s", snode->name); + if (!first && snode->nodetype != LYS_USES) { + struct lys_node *parent; + + /* Get the real parent. */ + parent = snode->parent; + while (parent && parent->nodetype == LYS_USES) + parent = parent->parent; + + /* + * When necessary, include the namespace of the augmenting + * module. + */ + if (parent && parent->nodetype == LYS_AUGMENT) + snprintf(xpath + strlen(xpath), + sizeof(xpath) - strlen(xpath), "/%s:%s", + snode->module->name, snode->name); + else + snprintf(xpath + strlen(xpath), + sizeof(xpath) - strlen(xpath), "/%s", + snode->name); + } nb_node = snode->priv; switch (snode->nodetype) { @@ -1550,6 +1576,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; + case NB_OP_PRE_VALIDATE: case NB_OP_APPLY_FINISH: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -1768,6 +1795,8 @@ const char *nb_operation_name(enum nb_operation operation) return "destroy"; case NB_OP_MOVE: return "move"; + case NB_OP_PRE_VALIDATE: + return "pre_validate"; case NB_OP_APPLY_FINISH: return "apply_finish"; case NB_OP_GET_ELEM: diff --git a/lib/northbound.h b/lib/northbound.h index ce79d907f9..fbd7771db7 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -72,6 +72,7 @@ enum nb_operation { NB_OP_MODIFY, NB_OP_DESTROY, NB_OP_MOVE, + NB_OP_PRE_VALIDATE, NB_OP_APPLY_FINISH, NB_OP_GET_ELEM, NB_OP_GET_NEXT, @@ -199,6 +200,19 @@ struct nb_callbacks { /* * Optional configuration callback. * + * This callback can be used to validate subsections of the + * configuration being committed before validating the configuration + * changes themselves. It's useful to perform more complex validations + * that depend on the relationship between multiple nodes. + * + * dnode + * libyang data node associated with the 'pre_validate' callback. + */ + int (*pre_validate)(const struct lyd_node *dnode); + + /* + * Optional configuration callback. + * * The 'apply_finish' callbacks are called after all other callbacks * during the apply phase (NB_EV_APPLY). These callbacks are called only * under one of the following two cases: @@ -435,25 +449,15 @@ enum nb_client { /* Northbound configuration. */ struct nb_config { - /* Configuration data. */ struct lyd_node *dnode; - - /* Configuration version. */ uint32_t version; - - /* - * Lock protecting this structure. The use of this lock is always - * necessary when reading or modifying the global running configuration. - * For candidate configurations, use of this lock is optional depending - * on the threading scheme of the northbound plugin. - */ - pthread_rwlock_t lock; }; /* Northbound configuration callback. */ struct nb_config_cb { RB_ENTRY(nb_config_cb) entry; enum nb_operation operation; + uint32_t seq; char xpath[XPATH_MAXLEN]; const struct nb_node *nb_node; const struct lyd_node *dnode; diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 884c01a457..a15fe3d1c9 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -193,13 +193,8 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) "Please check the logs for more details.\n"); /* Regenerate candidate for consistency. */ - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_replace(vty->candidate_config, - running_config, true); - } - pthread_rwlock_unlock(&running_config->lock); - + nb_config_replace(vty->candidate_config, running_config, + true); return CMD_WARNING_CONFIG_FAILED; } } @@ -307,12 +302,7 @@ static int nb_cli_commit(struct vty *vty, bool force, /* "confirm" parameter. */ if (confirmed_timeout) { - pthread_rwlock_rdlock(&running_config->lock); - { - vty->confirmed_commit_rollback = - nb_config_dup(running_config); - } - pthread_rwlock_unlock(&running_config->lock); + vty->confirmed_commit_rollback = nb_config_dup(running_config); vty->t_confirmed_commit_timeout = NULL; thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty, @@ -326,13 +316,8 @@ static int nb_cli_commit(struct vty *vty, bool force, /* Map northbound return code to CLI return code. */ switch (ret) { case NB_OK: - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_replace(vty->candidate_config_base, - running_config, true); - } - pthread_rwlock_unlock(&running_config->lock); - + nb_config_replace(vty->candidate_config_base, running_config, + true); vty_out(vty, "%% Configuration committed successfully (Transaction ID #%u).\n\n", transaction_id); @@ -729,12 +714,7 @@ DEFPY (config_update, return CMD_WARNING; } - pthread_rwlock_rdlock(&running_config->lock); - { - nb_config_replace(vty->candidate_config_base, running_config, - true); - } - pthread_rwlock_unlock(&running_config->lock); + nb_config_replace(vty->candidate_config_base, running_config, true); vty_out(vty, "%% Candidate configuration updated successfully.\n\n"); @@ -834,12 +814,8 @@ DEFPY (show_config_running, } } - pthread_rwlock_rdlock(&running_config->lock); - { - nb_cli_show_config(vty, running_config, format, translator, - !!with_defaults); - } - pthread_rwlock_unlock(&running_config->lock); + nb_cli_show_config(vty, running_config, format, translator, + !!with_defaults); return CMD_SUCCESS; } @@ -953,68 +929,57 @@ DEFPY (show_config_compare, struct nb_config *config2, *config_transaction2 = NULL; int ret = CMD_WARNING; - /* - * For simplicity, lock the running configuration regardless if it's - * going to be used or not. - */ - pthread_rwlock_rdlock(&running_config->lock); - { - if (c1_candidate) - config1 = vty->candidate_config; - else if (c1_running) - config1 = running_config; - else { - config_transaction1 = nb_db_transaction_load(c1_tid); - if (!config_transaction1) { - vty_out(vty, - "%% Transaction %u does not exist\n\n", - (unsigned int)c1_tid); - goto exit; - } - config1 = config_transaction1; + if (c1_candidate) + config1 = vty->candidate_config; + else if (c1_running) + config1 = running_config; + else { + config_transaction1 = nb_db_transaction_load(c1_tid); + if (!config_transaction1) { + vty_out(vty, "%% Transaction %u does not exist\n\n", + (unsigned int)c1_tid); + goto exit; } + config1 = config_transaction1; + } - if (c2_candidate) - config2 = vty->candidate_config; - else if (c2_running) - config2 = running_config; - else { - config_transaction2 = nb_db_transaction_load(c2_tid); - if (!config_transaction2) { - vty_out(vty, - "%% Transaction %u does not exist\n\n", - (unsigned int)c2_tid); - goto exit; - } - config2 = config_transaction2; + if (c2_candidate) + config2 = vty->candidate_config; + else if (c2_running) + config2 = running_config; + else { + config_transaction2 = nb_db_transaction_load(c2_tid); + if (!config_transaction2) { + vty_out(vty, "%% Transaction %u does not exist\n\n", + (unsigned int)c2_tid); + goto exit; } + config2 = config_transaction2; + } - if (json) - format = NB_CFG_FMT_JSON; - else if (xml) - format = NB_CFG_FMT_XML; - else - format = NB_CFG_FMT_CMDS; + if (json) + format = NB_CFG_FMT_JSON; + else if (xml) + format = NB_CFG_FMT_XML; + else + format = NB_CFG_FMT_CMDS; - if (translator_family) { - translator = yang_translator_find(translator_family); - if (!translator) { - vty_out(vty, - "%% Module translator \"%s\" not found\n", - translator_family); - goto exit; - } + if (translator_family) { + translator = yang_translator_find(translator_family); + if (!translator) { + vty_out(vty, "%% Module translator \"%s\" not found\n", + translator_family); + goto exit; } - - ret = nb_cli_show_config_compare(vty, config1, config2, format, - translator); - exit: - if (config_transaction1) - nb_config_free(config_transaction1); - if (config_transaction2) - nb_config_free(config_transaction2); } - pthread_rwlock_unlock(&running_config->lock); + + ret = nb_cli_show_config_compare(vty, config1, config2, format, + translator); +exit: + if (config_transaction1) + nb_config_free(config_transaction1); + if (config_transaction2) + nb_config_free(config_transaction2); return ret; } diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index e9669fc7e1..2fc3c81cf2 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -289,11 +289,7 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) struct cdb_iter_args iter_args; int ret; - pthread_rwlock_rdlock(&running_config->lock); - { - candidate = nb_config_dup(running_config); - } - pthread_rwlock_unlock(&running_config->lock); + candidate = nb_config_dup(running_config); /* Iterate over all configuration changes. */ iter_args.candidate = candidate; diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index a55da23dd1..218cae4e74 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -18,6 +18,8 @@ // #include <zebra.h> +#include <grpcpp/grpcpp.h> +#include "grpc/frr-northbound.grpc.pb.h" #include "log.h" #include "libfrr.h" @@ -32,9 +34,6 @@ #include <memory> #include <string> -#include <grpcpp/grpcpp.h> -#include "grpc/frr-northbound.grpc.pb.h" - #define GRPC_DEFAULT_PORT 50051 /* @@ -702,15 +701,10 @@ class NorthboundImpl final : public frr::Northbound::Service { struct lyd_node *dnode; - pthread_rwlock_rdlock(&running_config->lock); - { - dnode = yang_dnode_get(running_config->dnode, - path.empty() ? NULL - : path.c_str()); - if (dnode) - dnode = yang_dnode_dup(dnode); - } - pthread_rwlock_unlock(&running_config->lock); + dnode = yang_dnode_get(running_config->dnode, + path.empty() ? NULL : path.c_str()); + if (dnode) + dnode = yang_dnode_dup(dnode); return dnode; } @@ -817,11 +811,7 @@ class NorthboundImpl final : public frr::Northbound::Service struct candidate *candidate = &_candidates[candidate_id]; candidate->id = candidate_id; - pthread_rwlock_rdlock(&running_config->lock); - { - candidate->config = nb_config_dup(running_config); - } - pthread_rwlock_unlock(&running_config->lock); + candidate->config = nb_config_dup(running_config); candidate->transaction = NULL; return candidate; diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 77183282ba..b94c939763 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -256,11 +256,7 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session, return ret; } - pthread_rwlock_rdlock(&running_config->lock); - { - candidate = nb_config_dup(running_config); - } - pthread_rwlock_unlock(&running_config->lock); + candidate = nb_config_dup(running_config); while ((ret = sr_get_change_next(session, it, &sr_op, &sr_old_val, &sr_new_val)) diff --git a/lib/prefix.c b/lib/prefix.c index 35b679ab90..aa6661d7fb 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -773,8 +773,18 @@ int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2) if (i) return i; - return numcmp(pp1[offset] & maskbit[shift], - pp2[offset] & maskbit[shift]); + /* + * At this point offset was the same, if we have shift + * that means we still have data to compare, if shift is + * 0 then we are at the end of the data structure + * and should just return, as that we will be accessing + * memory beyond the end of the party zone + */ + if (shift) + return numcmp(pp1[offset] & maskbit[shift], + pp2[offset] & maskbit[shift]); + + return 0; } /* 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/routemap.c b/lib/routemap.c index fc15183bf9..580d898448 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -478,11 +478,6 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, ret = route_map_add_match(index, command, arg, type); switch (ret) { - case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - break; case RMAP_RULE_MISSING: vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; @@ -493,7 +488,7 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; break; - case RMAP_DUPLICATE_RULE: + case RMAP_COMPILE_SUCCESS: /* * Nothing to do here move along */ @@ -526,7 +521,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); } - ret = route_map_delete_match(index, command, dep_name); + ret = route_map_delete_match(index, command, dep_name, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); @@ -539,10 +534,6 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ @@ -573,7 +564,6 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: break; } @@ -598,7 +588,6 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: break; } @@ -1410,6 +1399,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, struct route_map_rule_cmd *cmd; void *compile; int8_t delete_rmap_event_type = 0; + const char *rule_key; /* First lookup rule for add match statement. */ cmd = route_map_lookup_match(match_name); @@ -1423,6 +1413,12 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, return RMAP_COMPILE_ERROR; } else compile = NULL; + /* use the compiled results if applicable */ + if (compile && cmd->func_get_rmap_rule_key) + rule_key = (*cmd->func_get_rmap_rule_key) + (compile); + else + rule_key = match_arg; /* If argument is completely same ignore it. */ for (rule = index->match_list.head; rule; rule = next) { @@ -1436,7 +1432,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, if (cmd->func_free) (*cmd->func_free)(compile); - return RMAP_DUPLICATE_RULE; + return RMAP_COMPILE_SUCCESS; } /* Remove the dependency of the route-map on the rule @@ -1447,7 +1443,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, get_route_map_delete_event(type); route_map_upd8_dependency( delete_rmap_event_type, - rule->rule_str, + rule_key, index->map->name); } @@ -1473,6 +1469,8 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } + if (type != RMAP_EVENT_MATCH_ADDED) + route_map_upd8_dependency(type, rule_key, index->map->name); return RMAP_COMPILE_SUCCESS; } @@ -1480,10 +1478,12 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, /* Delete specified route match rule. */ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, const char *match_name, - const char *match_arg) + const char *match_arg, + route_map_event_t type) { struct route_map_rule *rule; struct route_map_rule_cmd *cmd; + const char *rule_key; cmd = route_map_lookup_match(match_name); if (cmd == NULL) @@ -1492,7 +1492,6 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, for (rule = index->match_list.head; rule; rule = rule->next) if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0 || match_arg == NULL)) { - route_map_rule_delete(&index->match_list, rule); /* Execute event hook. */ if (route_map_master.event_hook) { (*route_map_master.event_hook)(index->map->name); @@ -1500,6 +1499,17 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, index->map->name, RMAP_EVENT_CALL_ADDED); } + if (cmd->func_get_rmap_rule_key) + rule_key = (*cmd->func_get_rmap_rule_key) + (rule->value); + else + rule_key = match_arg; + + if (type != RMAP_EVENT_MATCH_DELETED && rule_key) + route_map_upd8_dependency(type, rule_key, + index->map->name); + + route_map_rule_delete(&index->match_list, rule); return RMAP_COMPILE_SUCCESS; } /* Can't find matched rule. */ diff --git a/lib/routemap.h b/lib/routemap.h index 40525987e9..e6eccd4b29 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -123,6 +123,9 @@ struct route_map_rule_cmd { /* Free allocated value by func_compile (). */ void (*func_free)(void *); + + /** To get the rule key after Compilation **/ + void *(*func_get_rmap_rule_key)(void *val); }; /* Route map apply error. */ @@ -135,8 +138,6 @@ enum rmap_compile_rets { /* Route map rule can't compile */ RMAP_COMPILE_ERROR, - /* Route map rule is duplicate */ - RMAP_DUPLICATE_RULE }; /* Route map rule list. */ @@ -228,7 +229,8 @@ extern enum rmap_compile_rets route_map_add_match(struct route_map_index *index, /* Delete specified route match rule. */ extern enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, - const char *match_name, const char *match_arg); + const char *match_name, const char *match_arg, + route_map_event_t type); extern const char *route_map_get_match_arg(struct route_map_index *index, const char *match_name); diff --git a/lib/systemd.c b/lib/systemd.c index 8a2a5eeac3..44db48d006 100644 --- a/lib/systemd.c +++ b/lib/systemd.c @@ -86,6 +86,7 @@ static int systemd_get_watchdog_time(int the_process) void systemd_send_stopping(void) { + systemd_send_information("STATUS="); systemd_send_information("STOPPING=1"); } @@ -116,3 +117,11 @@ void systemd_send_started(struct thread_master *m, int the_process) if (wsecs != 0) thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL); } + +void systemd_send_status(const char *status) +{ + char buffer[1024]; + + snprintf(buffer, sizeof(buffer), "STATUS=%s", status); + systemd_send_information(buffer); +} diff --git a/lib/systemd.h b/lib/systemd.h index 6e43df527d..1f730720ce 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -42,6 +42,11 @@ void systemd_send_stopping(void); */ void systemd_send_started(struct thread_master *master, int the_process); +/* + * status - A status string to send to systemd + */ +void systemd_send_status(const char *status); + #ifdef __cplusplus } #endif 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; @@ -199,9 +199,14 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) /* Set name */ if (name && vrf->name[0] != '\0' && strcmp(name, vrf->name)) { + /* update the vrf name */ RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf); + strlcpy(vrf->data.l.netns_name, + name, NS_NAMSIZ); strlcpy(vrf->name, name, sizeof(vrf->name)); RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); + if (vrf->vrf_id == VRF_DEFAULT) + vrf_set_default_name(vrf->name, false); } else if (name && vrf->name[0] == '\0') { strlcpy(vrf->name, name, sizeof(vrf->name)); RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); @@ -467,6 +472,14 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { .varname = "vrf", .completions = vrf_autocomplete, }, + { + .varname = "vrf_name", + .completions = vrf_autocomplete, + }, + { + .varname = "nexthop_vrf", + .completions = vrf_autocomplete, + }, {.completions = NULL}, }; @@ -870,7 +883,8 @@ void vrf_set_default_name(const char *default_name, bool force) def_vrf->vrf_id); return; } - + if (strmatch(vrf_default_name, default_name)) + return; snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name); if (def_vrf) { if (force) @@ -2582,22 +2582,17 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive) vty->private_config = private_config; vty->xpath_index = 0; - pthread_rwlock_rdlock(&running_config->lock); - { - if (private_config) { - vty->candidate_config = nb_config_dup(running_config); + if (private_config) { + vty->candidate_config = nb_config_dup(running_config); + vty->candidate_config_base = nb_config_dup(running_config); + vty_out(vty, + "Warning: uncommitted changes will be discarded on exit.\n\n"); + } else { + vty->candidate_config = vty_shared_candidate_config; + if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) vty->candidate_config_base = nb_config_dup(running_config); - vty_out(vty, - "Warning: uncommitted changes will be discarded on exit.\n\n"); - } else { - vty->candidate_config = vty_shared_candidate_config; - if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) - vty->candidate_config_base = - nb_config_dup(running_config); - } } - pthread_rwlock_unlock(&running_config->lock); return CMD_SUCCESS; } diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index 0558383823..50225f35a0 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -782,6 +782,60 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, } /* + * Derived type: IP prefix. + */ +void yang_str2prefix(const char *value, union prefixptr prefix) +{ + (void)str2prefix(value, prefix.p); + apply_mask(prefix.p); +} + +struct yang_data *yang_data_new_prefix(const char *xpath, + union prefixconstptr prefix) +{ + char value_str[PREFIX2STR_BUFFER]; + + (void)prefix2str(prefix.p, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_prefix(union prefixptr prefix, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_node_leaf_list *dleaf; + + assert(dnode); + if (xpath_fmt) { + va_list ap; + char xpath[XPATH_MAXLEN]; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + dnode = yang_dnode_get(dnode, xpath); + YANG_DNODE_GET_ASSERT(dnode, xpath); + } + + dleaf = (const struct lyd_node_leaf_list *)dnode; + assert(dleaf->value_type == LY_TYPE_STRING); + (void)str2prefix(dleaf->value_str, prefix.p); +} + +void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2prefix(value, var); +} + +/* * Derived type: ipv4. */ void yang_str2ipv4(const char *value, struct in_addr *addr) @@ -1000,3 +1054,56 @@ void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt, ...) value = yang_get_default_value(xpath); yang_str2ipv6p(value, var); } + +/* + * Derived type: ip. + */ +void yang_str2ip(const char *value, struct ipaddr *ip) +{ + (void)str2ipaddr(value, ip); +} + +struct yang_data *yang_data_new_ip(const char *xpath, const struct ipaddr *addr) +{ + size_t sz = IS_IPADDR_V4(addr) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; + char value_str[sz]; + + ipaddr2str(addr, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_node_leaf_list *dleaf; + + assert(dnode); + if (xpath_fmt) { + va_list ap; + char xpath[XPATH_MAXLEN]; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + dnode = yang_dnode_get(dnode, xpath); + YANG_DNODE_GET_ASSERT(dnode, xpath); + } + + dleaf = (const struct lyd_node_leaf_list *)dnode; + assert(dleaf->value_type == LY_TYPE_STRING); + (void)str2ipaddr(dleaf->value_str, addr); +} + +void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ip(value, var); +} diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h index 5203a033ad..1a30ff3686 100644 --- a/lib/yang_wrappers.h +++ b/lib/yang_wrappers.h @@ -114,6 +114,16 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...); extern void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, ...); +/* ip prefix */ +extern void yang_str2prefix(const char *value, union prefixptr prefix); +extern struct yang_data *yang_data_new_prefix(const char *xpath, + union prefixconstptr prefix); +extern void yang_dnode_get_prefix(union prefixptr prefix, + const struct lyd_node *dnode, + const char *xpath_fmt, ...); +extern void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, + ...); + /* ipv4 */ extern void yang_str2ipv4(const char *value, struct in_addr *addr); extern struct yang_data *yang_data_new_ipv4(const char *xpath, @@ -154,4 +164,12 @@ extern void yang_dnode_get_ipv6p(union prefixptr prefix, extern void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt, ...); +/* ip */ +extern void yang_str2ip(const char *value, struct ipaddr *addr); +extern struct yang_data *yang_data_new_ip(const char *xpath, + const struct ipaddr *addr); +extern void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode, + const char *xpath_fmt, ...); +extern void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...); + #endif /* _FRR_NORTHBOUND_WRAPPERS_H_ */ diff --git a/lib/zclient.c b/lib/zclient.c index dad0ffa945..5e23a5cc33 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; @@ -2451,6 +2495,143 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start, return zclient_send_message(zclient); } +int zebra_send_mpls_labels(struct zclient *zclient, int cmd, + struct zapi_labels *zl) +{ + if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0) + return -1; + return zclient_send_message(zclient); +} + +int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) +{ + struct zapi_nexthop_label *znh; + + stream_reset(s); + + zclient_create_header(s, cmd, VRF_DEFAULT); + stream_putc(s, zl->message); + stream_putc(s, zl->type); + stream_putl(s, zl->local_label); + + if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) { + stream_putw(s, zl->route.prefix.family); + stream_put_prefix(s, &zl->route.prefix); + stream_putc(s, zl->route.type); + stream_putw(s, zl->route.instance); + } + + if (zl->nexthop_num > MULTIPATH_NUM) { + flog_err( + EC_LIB_ZAPI_ENCODE, + "%s: label %u: can't encode %u nexthops (maximum is %u)", + __func__, zl->local_label, zl->nexthop_num, + MULTIPATH_NUM); + return -1; + } + stream_putw(s, zl->nexthop_num); + + for (int i = 0; i < zl->nexthop_num; i++) { + znh = &zl->nexthops[i]; + + stream_putc(s, znh->type); + stream_putw(s, znh->family); + switch (znh->family) { + case AF_INET: + stream_put_in_addr(s, &znh->address.ipv4); + break; + case AF_INET6: + stream_write(s, (uint8_t *)&znh->address.ipv6, 16); + break; + default: + break; + } + stream_putl(s, znh->ifindex); + stream_putl(s, znh->label); + } + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + +int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) +{ + struct zapi_nexthop_label *znh; + + memset(zl, 0, sizeof(*zl)); + + /* Get data. */ + STREAM_GETC(s, zl->message); + STREAM_GETC(s, zl->type); + STREAM_GETL(s, zl->local_label); + + if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) { + size_t psize; + + STREAM_GETW(s, zl->route.prefix.family); + STREAM_GETC(s, zl->route.prefix.prefixlen); + + psize = PSIZE(zl->route.prefix.prefixlen); + switch (zl->route.prefix.family) { + case AF_INET: + if (zl->route.prefix.prefixlen > IPV4_MAX_BITLEN) { + zlog_debug( + "%s: Specified prefix length %d is greater than a v4 address can support", + __PRETTY_FUNCTION__, + zl->route.prefix.prefixlen); + return -1; + } + STREAM_GET(&zl->route.prefix.u.prefix4.s_addr, s, + psize); + break; + case AF_INET6: + if (zl->route.prefix.prefixlen > IPV6_MAX_BITLEN) { + zlog_debug( + "%s: Specified prefix length %d is greater than a v6 address can support", + __PRETTY_FUNCTION__, + zl->route.prefix.prefixlen); + return -1; + } + STREAM_GET(&zl->route.prefix.u.prefix6, s, psize); + break; + default: + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: Specified family %u is not v4 or v6", + __PRETTY_FUNCTION__, zl->route.prefix.family); + return -1; + } + + STREAM_GETC(s, zl->route.type); + STREAM_GETW(s, zl->route.instance); + } + + STREAM_GETW(s, zl->nexthop_num); + for (int i = 0; i < zl->nexthop_num; i++) { + znh = &zl->nexthops[i]; + + STREAM_GETC(s, znh->type); + STREAM_GETW(s, znh->family); + switch (znh->family) { + case AF_INET: + STREAM_GET(&znh->address.ipv4.s_addr, s, + IPV4_MAX_BYTELEN); + break; + case AF_INET6: + STREAM_GET(&znh->address.ipv6, s, 16); + break; + default: + break; + } + STREAM_GETL(s, znh->ifindex); + STREAM_GETL(s, znh->label); + } + + return 0; +stream_failure: + return -1; +} int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) { @@ -2709,14 +2890,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) @@ -2744,14 +2921,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 f7c579a4d6..71ebabbf75 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -126,6 +126,7 @@ typedef enum { ZEBRA_INTERFACE_LINK_PARAMS, ZEBRA_MPLS_LABELS_ADD, ZEBRA_MPLS_LABELS_DELETE, + ZEBRA_MPLS_LABELS_REPLACE, ZEBRA_IPMR_ROUTE_STATS, ZEBRA_LABEL_MANAGER_CONNECT, ZEBRA_LABEL_MANAGER_CONNECT_ASYNC, @@ -244,10 +245,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); @@ -403,6 +400,28 @@ struct zapi_route { uint32_t tableid; }; +struct zapi_nexthop_label { + enum nexthop_types_t type; + int family; + union g_addr address; + ifindex_t ifindex; + mpls_label_t label; +}; + +struct zapi_labels { + uint8_t message; +#define ZAPI_LABELS_FTN 0x01 + enum lsp_types_t type; + mpls_label_t local_label; + struct { + struct prefix prefix; + uint8_t type; + unsigned short instance; + } route; + uint16_t nexthop_num; + struct zapi_nexthop_label nexthops[MULTIPATH_NUM]; +}; + struct zapi_pw { char ifname[IF_NAMESIZE]; ifindex_t ifindex; @@ -602,7 +621,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); @@ -611,7 +629,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, @@ -633,6 +650,12 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd, + struct zapi_labels *zl); +extern int zapi_labels_encode(struct stream *s, int cmd, + struct zapi_labels *zl); +extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl); + extern int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw); extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw); 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_asbr.c b/ospf6d/ospf6_asbr.c index 4d1c085081..7914412e87 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1593,7 +1593,6 @@ static int route_map_command_status(struct vty *vty, enum rmap_compile_rets ret) return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: break; } diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 692c84ad08..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) @@ -355,8 +356,6 @@ void ospf6_interface_state_update(struct interface *ifp) oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) return; - if (oi->area == NULL) - return; if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) return; @@ -683,6 +682,9 @@ int interface_up(struct thread *thread) oi = (struct ospf6_interface *)THREAD_ARG(thread); assert(oi && oi->interface); + if (!oi->type_cfg) + oi->type = ospf6_default_iftype(oi->interface); + /* * Remove old pointer. If this thread wasn't a timer this * operation won't make a difference, because it is already NULL. @@ -774,8 +776,7 @@ int interface_up(struct thread *thread) } /* decide next interface state */ - if ((if_is_pointopoint(oi->interface)) - || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi); } else if (oi->priority == 0) ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi); @@ -880,6 +881,19 @@ int interface_down(struct thread *thread) } +static const char *ospf6_iftype_str(uint8_t iftype) +{ + switch (iftype) { + case OSPF_IFTYPE_LOOPBACK: + return "LOOPBACK"; + case OSPF_IFTYPE_BROADCAST: + return "BROADCAST"; + case OSPF_IFTYPE_POINTOPOINT: + return "POINTOPOINT"; + } + return "UNKNOWN"; +} + /* show specified interface structure */ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) { @@ -888,23 +902,16 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) struct prefix *p; struct listnode *i; char strbuf[PREFIX2STR_BUFFER], drouter[32], bdrouter[32]; - const char *type; + uint8_t default_iftype; struct timeval res, now; char duration[32]; struct ospf6_lsa *lsa; - /* check physical interface type */ - if (if_is_loopback(ifp)) - type = "LOOPBACK"; - else if (if_is_broadcast(ifp)) - type = "BROADCAST"; - else if (if_is_pointopoint(ifp)) - type = "POINTOPOINT"; - else - type = "UNKNOWN"; + default_iftype = ospf6_default_iftype(ifp); vty_out(vty, "%s is %s, type %s\n", ifp->name, - (if_is_operative(ifp) ? "up" : "down"), type); + (if_is_operative(ifp) ? "up" : "down"), + ospf6_iftype_str(default_iftype)); vty_out(vty, " Interface ID: %d\n", ifp->ifindex); if (ifp->info == NULL) { @@ -913,6 +920,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) } else oi = (struct ospf6_interface *)ifp->info; + if (if_is_operative(ifp) && oi->type != default_iftype) + vty_out(vty, " Operating as type %s\n", + ospf6_iftype_str(oi->type)); + vty_out(vty, " Internet Address:\n"); for (ALL_LIST_ELEMENTS_RO(ifp->connected, i, c)) { @@ -1809,6 +1820,8 @@ DEFUN (ipv6_ospf6_network, } assert(oi); + oi->type_cfg = true; + if (strncmp(argv[idx_network]->arg, "b", 1) == 0) { if (oi->type == OSPF_IFTYPE_BROADCAST) return CMD_SUCCESS; @@ -1849,6 +1862,8 @@ DEFUN (no_ipv6_ospf6_network, return CMD_SUCCESS; } + oi->type_cfg = false; + type = ospf6_default_iftype(ifp); if (oi->type == type) { return CMD_SUCCESS; @@ -1916,13 +1931,10 @@ static int config_write_ospf6_interface(struct vty *vty) if (oi->mtu_ignore) vty_out(vty, " ipv6 ospf6 mtu-ignore\n"); - if (oi->type != ospf6_default_iftype(ifp)) { - if (oi->type == OSPF_IFTYPE_POINTOPOINT) - vty_out(vty, - " ipv6 ospf6 network point-to-point\n"); - else if (oi->type == OSPF_IFTYPE_BROADCAST) - vty_out(vty, " ipv6 ospf6 network broadcast\n"); - } + if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT) + vty_out(vty, " ipv6 ospf6 network point-to-point\n"); + else if (oi->type_cfg && oi->type == OSPF_IFTYPE_BROADCAST) + vty_out(vty, " ipv6 ospf6 network broadcast\n"); ospf6_bfd_write_config(vty, oi); @@ -1935,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_interface.h b/ospf6d/ospf6_interface.h index e0c39a29b4..53a8910f4d 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -55,6 +55,7 @@ struct ospf6_interface { /* Network Type */ uint8_t type; + bool type_cfg; /* Router Priority */ uint8_t priority; diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index b551dbdfa6..0a9f1c6f7c 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -298,13 +298,17 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend, void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; if (lsdb == NULL) return; - for (ALL_LSDB(lsdb, lsa)) + for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_lsdb_remove(lsa, lsdb); + } } void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa) @@ -319,9 +323,12 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa) int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb) { int reschedule = 0; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; - for (ALL_LSDB(lsdb, lsa)) { + for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); if (!OSPF6_LSA_IS_MAXAGE(lsa)) continue; if (lsa->retrans_count != 0) { diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 4acb5e3b2e..da42a24252 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1866,7 +1866,8 @@ int ospf6_dbdesc_send(struct thread *thread) int ospf6_dbdesc_send_newone(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; unsigned int size = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -1876,7 +1877,10 @@ int ospf6_dbdesc_send_newone(struct thread *thread) structure) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc); - for (ALL_LSDB(on->summary_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->summary_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); if (size + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock(lsa); @@ -2019,7 +2023,8 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); on->thread_send_lsupdate = (struct thread *)NULL; @@ -2044,7 +2049,9 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ - for (ALL_LSDB(on->lsupdate_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->lsupdate_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header)) > ospf6_packet_max(on->ospf6_if)) { @@ -2074,7 +2081,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) p += OSPF6_LSA_SIZE(lsa->header); lsa_cnt++; - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, on->lsupdate_list); } @@ -2202,7 +2209,8 @@ int ospf6_lsupdate_send_interface(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; oi = (struct ospf6_interface *)THREAD_ARG(thread); oi->thread_send_lsupdate = (struct thread *)NULL; @@ -2228,7 +2236,9 @@ int ospf6_lsupdate_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); lsa_cnt = 0; - for (ALL_LSDB(oi->lsupdate_list, lsa)) { + for (iterend = ospf6_lsdb_head(oi->lsupdate_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header))) > ospf6_packet_max(oi)) { @@ -2263,7 +2273,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread) p += OSPF6_LSA_SIZE(lsa->header); lsa_cnt++; - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, oi->lsupdate_list); } @@ -2289,7 +2299,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) struct ospf6_neighbor *on; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; int lsa_cnt = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -2312,7 +2323,9 @@ int ospf6_lsack_send_neighbor(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(on->lsack_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->lsack_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { @@ -2340,7 +2353,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header)); p += sizeof(struct ospf6_lsa_header); - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, on->lsack_list); lsa_cnt++; } @@ -2367,7 +2380,8 @@ int ospf6_lsack_send_interface(struct thread *thread) struct ospf6_interface *oi; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; int lsa_cnt = 0; oi = (struct ospf6_interface *)THREAD_ARG(thread); @@ -2391,7 +2405,9 @@ int ospf6_lsack_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(oi->lsack_list, lsa)) { + for (iterend = ospf6_lsdb_head(oi->lsack_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(oi)) { @@ -2409,7 +2425,7 @@ int ospf6_lsack_send_interface(struct thread *thread) memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header)); p += sizeof(struct ospf6_lsa_header); - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, oi->lsack_list); lsa_cnt++; } diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 46dc621ae7..4318db5225 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -112,11 +112,15 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -287,7 +291,8 @@ int twoway_received(struct thread *thread) int negotiation_done(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -301,7 +306,10 @@ int negotiation_done(struct thread *thread) /* clear ls-list */ ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -495,7 +503,8 @@ int seqnumber_mismatch(struct thread *thread) int bad_lsreq(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -514,7 +523,10 @@ int bad_lsreq(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -532,7 +544,8 @@ int bad_lsreq(struct thread *thread) int oneway_received(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -549,7 +562,9 @@ int oneway_received(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -618,7 +633,7 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on) snprintf(deadtime, sizeof(deadtime), "%02ld:%02ld:%02ld", h, m, s); /* Neighbor State */ - if (if_is_pointopoint(on->ospf6_if->interface)) + if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT) snprintf(nstate, sizeof(nstate), "PointToPoint"); else { if (on->router_id == on->drouter) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index fc7c6177d7..1ba89f3bd6 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -1130,9 +1130,9 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(ntohl(oi->area->area_id)); break; case OSPFv3IFTYPE: - if (if_is_broadcast(oi->interface)) + if (oi->type == OSPF_IFTYPE_BROADCAST) return SNMP_INTEGER(1); - else if (if_is_pointopoint(oi->interface)) + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) return SNMP_INTEGER(3); else break; /* Unknown, don't put anything */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 40c6123810..95dafff84e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -136,7 +136,7 @@ static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) ospf6_abr_originate_summary(route); } -static struct ospf6 *ospf6_create(void) +static struct ospf6 *ospf6_create(vrf_id_t vrf_id) { struct ospf6 *o; @@ -144,6 +144,7 @@ static struct ospf6 *ospf6_create(void) /* initialize */ monotime(&o->starttime); + o->vrf_id = vrf_id; o->area_list = list_new(); o->area_list->cmp = ospf6_area_cmp; o->lsdb = ospf6_lsdb_create(o); @@ -325,7 +326,7 @@ DEFUN_NOSH (router_ospf6, OSPF6_STR) { if (ospf6 == NULL) { - ospf6 = ospf6_create(); + ospf6 = ospf6_create(VRF_DEFAULT); if (ospf6->router_id == 0) ospf6_router_id_update(); } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 381027dcff..ba41fca65b 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -31,6 +31,9 @@ struct ospf6_master { /* OSPFv3 top level data structure */ struct ospf6 { + /* The relevant vrf_id */ + vrf_id_t vrf_id; + /* my router id */ uint32_t router_id; 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_main.c b/ospfd/ospf_main.c index 36bb8d49b5..bee7bbb21d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -216,16 +216,6 @@ int main(int argc, char **argv) /* OSPF errors init */ ospf_error_init(); - /* Need to initialize the default ospf structure, so the interface mode - commands can be duly processed if they are received before 'router - ospf', - when quagga(ospfd) is restarted */ - if (!ospf_get_instance(instance)) { - flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s", - strerror(errno)); - exit(1); - } - frr_config_fork(); frr_run(master); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 5a29c1fb07..a508ae657f 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1362,11 +1362,12 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, case NSM_Down: case NSM_Attempt: case NSM_TwoWay: - flog_warn( - EC_OSPF_PACKET, - "Packet[DD]: Neighbor %s state is %s, packet discarded.", - inet_ntoa(nbr->router_id), - lookup_msg(ospf_nsm_state_msg, nbr->state, NULL)); + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "Packet[DD]: Neighbor %s state is %s, packet discarded.", + inet_ntoa(nbr->router_id), + lookup_msg(ospf_nsm_state_msg, nbr->state, + NULL)); break; case NSM_Init: OSPF_NSM_EVENT_EXECUTE(nbr, NSM_TwoWayReceived); diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 6947393a60..ff2039bec8 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -608,26 +608,8 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp) /* Send MPLS Label entry to Zebra for installation or deletion */ static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) { - struct stream *s; - - /* Reset stream. */ - s = zclient->obuf; - stream_reset(s); - - zclient_create_header(s, cmd, VRF_DEFAULT); - stream_putc(s, ZEBRA_LSP_SR); - /* OSPF Segment Routing currently support only IPv4 */ - stream_putl(s, nhlfe.prefv4.family); - stream_put_in_addr(s, &nhlfe.prefv4.prefix); - stream_putc(s, nhlfe.prefv4.prefixlen); - stream_put_in_addr(s, &nhlfe.nexthop); - stream_putl(s, nhlfe.ifindex); - stream_putc(s, OSPF_SR_PRIORITY_DEFAULT); - stream_putl(s, nhlfe.label_in); - stream_putl(s, nhlfe.label_out); - - /* Put length at the first point of the stream. */ - stream_putw_at(s, 0, stream_get_endp(s)); + struct zapi_labels zl = {}; + struct zapi_nexthop_label *znh; if (IS_DEBUG_OSPF_SR) zlog_debug(" |- %s LSP %u/%u for %s/%u via %u", @@ -636,70 +618,39 @@ static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) inet_ntoa(nhlfe.prefv4.prefix), nhlfe.prefv4.prefixlen, nhlfe.ifindex); - return zclient_send_message(zclient); -} - -/* Request zebra to install/remove FEC in FIB */ -static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe) -{ - struct zapi_route api; - struct zapi_nexthop *api_nh; - - /* Support only IPv4 */ - if (nhlfe.prefv4.family != AF_INET) - return -1; - - memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_OSPF; - api.safi = SAFI_UNICAST; - memcpy(&api.prefix, &nhlfe.prefv4, sizeof(struct prefix_ipv4)); - - if (cmd == ZEBRA_ROUTE_ADD) { - /* Metric value. */ - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = OSPF_SR_DEFAULT_METRIC; - /* Nexthop */ - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api_nh = &api.nexthops[0]; - IPV4_ADDR_COPY(&api_nh->gate.ipv4, &nhlfe.nexthop); - api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - api_nh->ifindex = nhlfe.ifindex; - /* MPLS labels */ - SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - api_nh->labels[0] = nhlfe.label_out; - api_nh->label_num = 1; - api_nh->vrf_id = VRF_DEFAULT; - api.nexthop_num = 1; - } - - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- %s FEC %u for %s/%u via %u", - cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete", - nhlfe.label_out, inet_ntoa(nhlfe.prefv4.prefix), - nhlfe.prefv4.prefixlen, nhlfe.ifindex); - - return zclient_route_send(cmd, zclient, &api); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = nhlfe.label_in; + + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.family = nhlfe.prefv4.family; + zl.route.prefix.prefixlen = nhlfe.prefv4.prefixlen; + zl.route.prefix.u.prefix4 = nhlfe.prefv4.prefix; + zl.route.type = ZEBRA_ROUTE_OSPF; + zl.route.instance = 0; + + zl.nexthop_num = 1; + znh = &zl.nexthops[0]; + znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + znh->family = AF_INET; + znh->address.ipv4 = nhlfe.nexthop; + znh->ifindex = nhlfe.ifindex; + znh->label = nhlfe.label_out; + + return zebra_send_mpls_labels(zclient, cmd, &zl); } /* Add new NHLFE entry for SID */ static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe) { - if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) { + if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe); - if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL) - ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_ADD, nhlfe); - } } /* Remove NHLFE entry for SID */ static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe) { - if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) { + if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe); - if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL) - ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_DELETE, nhlfe); - } } /* Update NHLFE entry for SID */ diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index 4d3f5f441a..df923e970f 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -27,9 +27,6 @@ #ifndef _FRR_OSPF_SR_H #define _FRR_OSPF_SR_H -/* Default Route priority for OSPF Segment Routing */ -#define OSPF_SR_PRIORITY_DEFAULT 10 - /* macros and constants for segment routing */ #define SET_RANGE_SIZE_MASK 0xffffff00 #define GET_RANGE_SIZE_MASK 0x00ffffff diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8fa91f500c..d11c34f243 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -10661,7 +10661,7 @@ static void ospf_interface_clear(struct interface *ifp) DEFUN (clear_ip_ospf_interface, clear_ip_ospf_interface_cmd, - "clear ip ospf [vrf <NAME>] interface [IFNAME]", + "clear ip ospf [vrf NAME] interface [IFNAME]", CLEAR_STR IP_STR "OSPF information\n" 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 e48a5b4d36..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) @@ -2158,7 +2159,7 @@ static int ospf_vrf_disable(struct vrf *vrf) void ospf_vrf_init(void) { vrf_init(ospf_vrf_new, ospf_vrf_enable, ospf_vrf_disable, - ospf_vrf_delete, NULL); + ospf_vrf_delete, ospf_vrf_enable); } void ospf_vrf_terminate(void) 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_nht.c b/pbrd/pbr_nht.c index 57e8cf5742..67a1fe2ffe 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -267,7 +267,9 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_map_check_nh_group_change(nhgc->name); - if (nhop->type == NEXTHOP_TYPE_IFINDEX) { + if (nhop->type == NEXTHOP_TYPE_IFINDEX + || (nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + && IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6))) { struct interface *ifp; ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); @@ -682,29 +684,124 @@ struct pbr_nht_individual { uint32_t valid; }; -static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, - void *data) +static bool +pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, + const struct pbr_nht_individual *pnhi) { - struct pbr_nexthop_cache *pnhc = b->data; - struct pbr_nht_individual *pnhi = data; - char buf[PREFIX_STRLEN]; - bool old_valid; + bool is_valid = pnhc->valid; - old_valid = pnhc->valid; + if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */ + goto done; switch (pnhi->nhr->prefix.family) { case AF_INET: if (pnhc->nexthop->gate.ipv4.s_addr - == pnhi->nhr->prefix.u.prefix4.s_addr) - pnhc->valid = !!pnhi->nhr->nexthop_num; + != pnhi->nhr->prefix.u.prefix4.s_addr) + goto done; /* Unrelated change */ break; case AF_INET6: if (memcmp(&pnhc->nexthop->gate.ipv6, &pnhi->nhr->prefix.u.prefix6, 16) - == 0) - pnhc->valid = !!pnhi->nhr->nexthop_num; + != 0) + goto done; /* Unrelated change */ + break; + } + + if (!pnhi->nhr->nexthop_num) { + is_valid = false; + goto done; + } + + if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + + /* GATEWAY_IFINDEX type shouldn't resolve to group */ + if (pnhi->nhr->nexthop_num > 1) { + is_valid = false; + goto done; + } + + /* If whatever we resolved to wasn't on the interface we + * specified. (i.e. not a connected route), its invalid. + */ + if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) { + is_valid = false; + goto done; + } + } + + is_valid = true; + +done: + pnhc->valid = is_valid; + + return pnhc->valid; +} + +static bool pbr_nht_individual_nexthop_interface_update( + struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi) +{ + bool is_valid = pnhc->valid; + + if (!pnhi->ifp) /* It doesn't care about non-interface updates */ + goto done; + + if (pnhc->nexthop->ifindex + != pnhi->ifp->ifindex) /* Un-related interface */ + goto done; + + is_valid = !!if_is_up(pnhi->ifp); + +done: + pnhc->valid = is_valid; + + return pnhc->valid; +} + +/* Given this update either from interface or nexthop tracking, re-validate this + * nexthop. + * + * If the update is un-related, the subroutines shoud just return their cached + * valid state. + */ +static void +pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, + const struct pbr_nht_individual *pnhi) +{ + assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */ + + switch (pnhc->nexthop->type) { + case NEXTHOP_TYPE_IFINDEX: + pbr_nht_individual_nexthop_interface_update(pnhc, pnhi); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) { + pbr_nht_individual_nexthop_interface_update(pnhc, pnhi); + break; + } + /* Intentional fall thru */ + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + pbr_nht_individual_nexthop_gw_update(pnhc, pnhi); + break; + case NEXTHOP_TYPE_BLACKHOLE: + pnhc->valid = true; break; } +} + +static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + char buf[PREFIX_STRLEN]; + bool old_valid; + + old_valid = pnhc->valid; + + pbr_nht_individual_nexthop_update(pnhc, pnhi); DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid, @@ -736,7 +833,7 @@ pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg, static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; - struct pbr_nht_individual pnhi; + struct pbr_nht_individual pnhi = {}; struct nexthop_group nhg = {}; bool old_valid; @@ -778,9 +875,7 @@ pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b, old_valid = pnhc->valid; - if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX - && pnhc->nexthop->ifindex == pnhi->ifp->ifindex) - pnhc->valid = !!if_is_up(pnhi->ifp); + pbr_nht_individual_nexthop_update(pnhc, pnhi); DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name, old_valid, pnhc->valid); @@ -793,7 +888,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; - struct pbr_nht_individual pnhi; + struct pbr_nht_individual pnhi = {}; bool old_valid; old_valid = pnhgc->valid; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 5e7addc9d2..069b3e6c9b 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -254,7 +254,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ |INTERFACE$intf\ >\ - [nexthop-vrf NAME$name]", + [nexthop-vrf NAME$vrf_name]", NO_STR "Set for the PBR-MAP\n" "Specify one of the nexthops in this map\n" @@ -276,13 +276,13 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, return CMD_WARNING_CONFIG_FAILED; } - if (name) - vrf = vrf_lookup_by_name(name); + if (vrf_name) + vrf = vrf_lookup_by_name(vrf_name); else vrf = vrf_lookup_by_id(VRF_DEFAULT); if (!vrf) { - vty_out(vty, "Specified: %s is non-existent\n", name); + vty_out(vty, "Specified: %s is non-existent\n", vrf_name); return CMD_WARNING_CONFIG_FAILED; } @@ -363,7 +363,9 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, pbr_map_check(pbrms); } - if (nhop.type == NEXTHOP_TYPE_IFINDEX) { + if (nhop.type == NEXTHOP_TYPE_IFINDEX + || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX + && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) { struct interface *ifp; ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index d74d0fcd23..39e92467ab 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; @@ -482,6 +450,12 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg) p.family = AF_INET6; memcpy(&p.u.prefix6, &nhop->gate.ipv6, 16); p.prefixlen = 128; + if (IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6)) + /* + * Don't bother tracking link locals, just track their + * interface state. + */ + return; break; } 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_assert.c b/pimd/pim_assert.c index 3aa2a92241..53ab22754c 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -259,11 +259,11 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, curr += offset; curr_size -= offset; - if (curr_size != 8) { + if (curr_size < 8) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: preference/metric size is not 8: size=%d from %s on interface %s", + "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s", __PRETTY_FUNCTION__, curr_size, src_str, ifp->name); return -3; } 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_join.c b/pimd/pim_join.c index 5e1a4f0c5e..686475fefe 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -62,7 +62,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); - zlog_warn( + zlog_debug( "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, pim_str_sg_dump(sg), !!(source_flags & PIM_RPT_BIT_MASK), @@ -94,11 +94,8 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, sizeof(received_rp)); pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4, local_rp, sizeof(local_rp)); - if (PIM_DEBUG_PIM_TRACE) - zlog_warn( - "%s: Specified RP(%s) in join is different than our configured RP(%s)", - __PRETTY_FUNCTION__, received_rp, - local_rp); + zlog_warn("%s: Specified RP(%s) in join is different than our configured RP(%s)", + __PRETTY_FUNCTION__, received_rp, local_rp); return; } @@ -122,7 +119,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); - zlog_warn( + zlog_debug( "%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, pim_str_sg_dump(sg), source_flags & PIM_RPT_BIT_MASK, @@ -185,15 +182,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, Check upstream address family */ if (msg_upstream_addr.family != AF_INET) { - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); - zlog_warn( - "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", - __PRETTY_FUNCTION__, msg_upstream_addr.family, - src_str, ifp->name); - } + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", + __PRETTY_FUNCTION__, msg_upstream_addr.family, + src_str, ifp->name); return -2; } @@ -270,7 +263,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, upstream_str, sizeof(upstream_str)); pim_inet4_dump("<grp?>", sg.grp, group_str, sizeof(group_str)); - zlog_warn( + zlog_debug( "%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s", __PRETTY_FUNCTION__, upstream_str, group_str, msg_num_joined_sources, msg_num_pruned_sources, diff --git a/pimd/pim_main.c b/pimd/pim_main.c index c57151b900..4090ce7f93 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -128,6 +128,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(); pim_mlag_init(); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index f7f4b54aea..a235ed0569 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -611,7 +611,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str, sizeof(ip_dst_str)); - zlog_warn( + zlog_debug( "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s", __PRETTY_FUNCTION__, pim->vrf->name, ifp->name, igmp, ip_src_str, ip_dst_str); @@ -643,7 +643,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, sizeof(src_str)); pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str)); - zlog_warn( + zlog_debug( "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d", __PRETTY_FUNCTION__, igmpmsgtype2str[msg->im_msgtype], @@ -698,12 +698,9 @@ static int mroute_read(struct thread *t) if (errno == EWOULDBLOCK || errno == EAGAIN) break; - if (PIM_DEBUG_MROUTE) - zlog_warn( - "%s: failure reading rd=%d: fd=%d: errno=%d: %s", - __PRETTY_FUNCTION__, rd, - pim->mroute_socket, errno, - safe_strerror(errno)); + zlog_warn("%s: failure reading rd=%d: fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, rd, pim->mroute_socket, + errno, safe_strerror(errno)); goto done; } @@ -1085,18 +1082,14 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) pim_zlookup_sg_statistics(c_oil); if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) { - if (PIM_DEBUG_MROUTE) { - struct prefix_sg sg; + struct prefix_sg sg; - sg.src = c_oil->oil.mfcc_origin; - sg.grp = c_oil->oil.mfcc_mcastgrp; + sg.src = c_oil->oil.mfcc_origin; + sg.grp = c_oil->oil.mfcc_mcastgrp; - zlog_warn( - "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s", - (unsigned long)SIOCGETSGCNT, - pim_str_sg_dump(&sg), errno, - safe_strerror(errno)); - } + zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s", + (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg), + errno, safe_strerror(errno)); return; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 12b28ed9af..cd2d306f3d 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -574,6 +574,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, ip->ip_id = htons(++ip_id); ip->ip_hl = 5; ip->ip_v = 4; + ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; ip->ip_p = PIM_IP_PROTO_PIM; ip->ip_src = src; ip->ip_dst = dst; diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 82255cd3b0..7f03e18389 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -255,6 +255,12 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, } } + /* Set Tx socket DSCP byte */ + if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s", + fd, safe_strerror(errno)); + } + return fd; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 073943c695..b517b998e3 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -64,218 +64,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; @@ -794,10 +582,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; @@ -1184,12 +968,6 @@ void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; - int input_iface_vif_index = 0; - struct pim_instance *pim; - struct pim_interface *pim_ifp; - - pim_ifp = ch->interface->info; - pim = pim_ifp->pim; if (PIM_DEBUG_PIM_TRACE) { char source_str[INET_ADDRSTRLEN]; @@ -1207,55 +985,6 @@ void pim_forward_start(struct pim_ifchannel *ch) inet_ntoa(up->upstream_addr)); } - /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, - as part of mroute_del called by pim_forward_stop. - */ - if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) { - struct prefix src, grp; - - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = up->sg.src; - - if (pim_ecmp_nexthop_lookup(pim, &up->rpf.source_nexthop, &src, - &grp, 0)) - input_iface_vif_index = pim_if_find_vifindex_by_ifindex( - pim, up->rpf.source_nexthop.interface->ifindex); - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_PIM_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", up->sg.src, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - pim_channel_oil_change_iif(pim, up->channel_oil, - MAXVIFS, - __PRETTY_FUNCTION__); - } - - else - pim_channel_oil_change_iif(pim, up->channel_oil, - input_iface_vif_index, - __PRETTY_FUNCTION__); - - if (PIM_DEBUG_TRACE) { - struct interface *in_intf = pim_if_find_by_vif_index( - pim, input_iface_vif_index); - zlog_debug( - "%s: Update channel_oil IIF %s VIFI %d entry %s ", - __PRETTY_FUNCTION__, - in_intf ? in_intf->name : "Unknown", - input_iface_vif_index, up->sg_str); - } - } - if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) mask = PIM_OIF_FLAG_PROTO_IGMP; @@ -1305,3 +1034,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/qpb/subdir.am b/qpb/subdir.am index 75a733f8fc..1864ba7369 100644 --- a/qpb/subdir.am +++ b/qpb/subdir.am @@ -10,9 +10,12 @@ qpb_libfrr_pb_la_SOURCES = \ qpb/qpb.c \ qpb/qpb_allocator.c \ # end + +if HAVE_PROTOBUF nodist_qpb_libfrr_pb_la_SOURCES = \ qpb/qpb.pb-c.c \ # end +endif noinst_HEADERS += \ qpb/linear_allocator.h \ diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index fa0a6d8a0a..b3f9ac7630 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -656,6 +656,9 @@ fi %files pythontools +%{_sbindir}/generate_support_bundle.py +%{_sbindir}/generate_support_bundle.pyc +%{_sbindir}/generate_support_bundle.pyo %{_sbindir}/frr-reload.py %{_sbindir}/frr-reload.pyc %{_sbindir}/frr-reload.pyo 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/ripd/ripd.c b/ripd/ripd.c index ad373aebdf..1b5a582cb1 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3641,6 +3641,37 @@ static int rip_vrf_enable(struct vrf *vrf) int socket; rip = rip_lookup_by_vrf_name(vrf->name); + if (!rip) { + char *old_vrf_name = NULL; + + rip = (struct rip *)vrf->info; + if (!rip) + return 0; + /* update vrf name */ + if (rip->vrf_name) + old_vrf_name = rip->vrf_name; + rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name); + /* + * HACK: Change the RIP VRF in the running configuration directly, + * bypassing the northbound layer. This is necessary to avoid deleting + * the RIP and readding it in the new VRF, which would have + * several implications. + */ + if (yang_module_find("frr-ripd") && old_vrf_name) { + struct lyd_node *rip_dnode; + + rip_dnode = yang_dnode_get( + running_config->dnode, + "/frr-ripd:ripd/instance[vrf='%s']/vrf", + old_vrf_name); + if (rip_dnode) { + yang_dnode_change_leaf(rip_dnode, vrf->name); + running_config->version++; + } + } + if (old_vrf_name) + XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name); + } if (!rip || rip->enabled) return 0; @@ -3682,7 +3713,7 @@ static int rip_vrf_disable(struct vrf *vrf) void rip_vrf_init(void) { vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete, - NULL); + rip_vrf_enable); } void rip_vrf_terminate(void) 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 49f7dda646..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); @@ -2776,7 +2776,39 @@ static int ripng_vrf_enable(struct vrf *vrf) int socket; ripng = ripng_lookup_by_vrf_name(vrf->name); - if (!ripng || ripng->enabled) + if (!ripng) { + char *old_vrf_name = NULL; + + ripng = (struct ripng *)vrf->info; + if (!ripng) + return 0; + /* update vrf name */ + if (ripng->vrf_name) + old_vrf_name = ripng->vrf_name; + ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name); + /* + * HACK: Change the RIPng VRF in the running configuration directly, + * bypassing the northbound layer. This is necessary to avoid deleting + * the RIPng and readding it in the new VRF, which would have + * several implications. + */ + if (yang_module_find("frr-ripngd") && old_vrf_name) { + struct lyd_node *ripng_dnode; + + ripng_dnode = yang_dnode_get( + running_config->dnode, + "/frr-ripngd:ripngd/instance[vrf='%s']/vrf", + old_vrf_name); + if (ripng_dnode) { + yang_dnode_change_leaf(ripng_dnode, vrf->name); + running_config->version++; + } + } + if (old_vrf_name) + XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name); + } + + if (ripng->enabled) return 0; if (IS_RIPNG_DEBUG_EVENT) @@ -2784,13 +2816,11 @@ static int ripng_vrf_enable(struct vrf *vrf) vrf->vrf_id); /* Activate the VRF RIPng instance. */ - if (!ripng->enabled) { - socket = ripng_make_socket(vrf); - if (socket < 0) - return -1; + socket = ripng_make_socket(vrf); + if (socket < 0) + return -1; - ripng_instance_enable(ripng, vrf, socket); - } + ripng_instance_enable(ripng, vrf, socket); return 0; } @@ -2817,7 +2847,7 @@ static int ripng_vrf_disable(struct vrf *vrf) void ripng_vrf_init(void) { vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable, - ripng_vrf_delete, NULL); + ripng_vrf_delete, ripng_vrf_enable); } void ripng_vrf_terminate(void) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 60cfb2e486..486ccf6bfe 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,7 +39,7 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", + "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -54,12 +54,12 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, struct prefix p; bool type_import; - if (!name) - name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -83,7 +83,7 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", + "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -98,12 +98,12 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, struct prefix p; bool type_import; - if (!name) - name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -162,7 +162,7 @@ DEFPY (install_routes_data_dump, DEFPY (install_routes, install_routes_cmd, - "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" @@ -209,13 +209,13 @@ DEFPY (install_routes, } sg.r.orig_prefix = prefix; - if (!name) - name = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -252,7 +252,7 @@ DEFPY (install_routes, } DEFPY(vrf_label, vrf_label_cmd, - "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$name label (0-100000)$label", + "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label", "Sharp Routing Protocol\n" "Give a vrf a label\n" "Pop and forward for IPv4\n" @@ -264,10 +264,10 @@ DEFPY(vrf_label, vrf_label_cmd, struct vrf *vrf; afi_t afi = (ipv4) ? AFI_IP : AFI_IP6; - if (strcmp(name, "default") == 0) + if (strcmp(vrf_name, "default") == 0) vrf = vrf_lookup_by_id(VRF_DEFAULT); else - vrf = vrf_lookup_by_name(name); + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "Unable to find vrf you silly head"); @@ -283,7 +283,7 @@ DEFPY(vrf_label, vrf_label_cmd, DEFPY (remove_routes, remove_routes_cmd, - "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", + "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", "Sharp Routing Protocol\n" "Remove some routes\n" "Routes to remove\n" @@ -314,10 +314,10 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } - vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name ? name : VRF_DEFAULT_NAME); + vrf_name ? vrf_name : VRF_DEFAULT_NAME); return CMD_WARNING; } 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_routes.c b/staticd/static_routes.c index 34f58a98e2..a8a5ca523a 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -100,7 +100,8 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4)) || (afi == AFI_IP6 && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!strcmp(ifname ? ifname : "", si->ifname))) { + && (!strcmp(ifname ? ifname : "", si->ifname)) + && nh_svrf->vrf->vrf_id == si->nh_vrf_id) { if ((distance == si->distance) && (tag == si->tag) && (table_id == si->table_id) && !memcmp(&si->snh_label, snh_label, diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 9dd25fbdd1..abb64aad3f 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -27,6 +27,7 @@ #include "static_memory.h" #include "static_vrf.h" #include "static_routes.h" +#include "static_zebra.h" #include "static_vty.h" static void zebra_stable_node_cleanup(struct route_table *table, @@ -76,6 +77,8 @@ static int static_vrf_new(struct vrf *vrf) static int static_vrf_enable(struct vrf *vrf) { + static_zebra_vrf_register(vrf); + static_fixup_vrf_ids(vrf->info); /* @@ -89,6 +92,7 @@ static int static_vrf_enable(struct vrf *vrf) static int static_vrf_disable(struct vrf *vrf) { + static_zebra_vrf_unregister(vrf); return 0; } diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 3a9e4e8fa4..f926e1d9cd 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -35,7 +35,6 @@ #ifndef VTYSH_EXTRACT_PL #include "staticd/static_vty_clippy.c" #endif - static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty, const char *vrf_name) { @@ -479,6 +478,23 @@ static int static_route_leak( return CMD_WARNING_CONFIG_FAILED; } gatep = &gate; + + if (afi == AFI_IP && !negate) { + if (if_lookup_exact_address(&gatep->ipv4, AF_INET, + svrf->vrf->vrf_id)) + if (vty) + vty_out(vty, + "%% Warning!! Local connected address is configured as Gateway IP(%s)\n", + gate_str); + } else if (afi == AFI_IP6 && !negate) { + if (if_lookup_exact_address(&gatep->ipv6, AF_INET6, + svrf->vrf->vrf_id)) + if (vty) + vty_out(vty, + "%% Warning!! Local connected address is configured as Gateway IPv6(%s)\n", + gate_str); + } + } if (gate_str == NULL && ifname == NULL) diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 27605da63f..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; + if (if_is_vrf(ifp)) { + struct static_vrf *svrf = static_vrf_lookup_by_id(ifp->vrf_id); - 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); - - 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; } @@ -200,6 +158,25 @@ struct static_nht_data { uint8_t nh_num; }; +/* API to check whether the configured nexthop address is + * one of its local connected address or not. + */ +static bool +static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family) +{ + if (family == AF_INET) { + if (if_lookup_exact_address(&addr->u.prefix4, + AF_INET, + vrfid)) + return true; + } else if (family == AF_INET6) { + if (if_lookup_exact_address(&addr->u.prefix6, + AF_INET6, + vrfid)) + return true; + } + return false; +} static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) { struct static_nht_data *nhtd, lookup; @@ -214,6 +191,12 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) if (nhr.prefix.family == AF_INET6) afi = AFI_IP6; + if (nhr.type == ZEBRA_ROUTE_CONNECT) { + if (static_nexthop_is_local(vrf_id, &nhr.prefix, + nhr.prefix.family)) + nhr.nexthop_num = 0; + } + memset(&lookup, 0, sizeof(lookup)); lookup.nh = &nhr.prefix; lookup.nh_vrf_id = vrf_id; @@ -479,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; @@ -501,3 +484,17 @@ void static_zebra_init(void) static_nht_hash_cmp, "Static Nexthop Tracking hash"); } + +void static_zebra_vrf_register(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_reg_requests(zclient, vrf->vrf_id); +} + +void static_zebra_vrf_unregister(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_dereg_requests(zclient, vrf->vrf_id); +} diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index 15f5410b81..962dc3908f 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -28,4 +28,7 @@ extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, vrf_id_t vrf_id, safi_t safi, bool install); extern void static_zebra_init(void); +extern void static_zebra_vrf_register(struct vrf *vrf); +extern void static_zebra_vrf_unregister(struct vrf *vrf); + #endif diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index b2612892f9..b5db36703a 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1379,6 +1379,7 @@ int main(void) i = 0; + frr_pthread_init(); bgp_pthreads_init(); bgp_pth_ka->running = true; diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 968f9ac445..db1cf0611d 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -916,6 +916,7 @@ int main(void) vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); + frr_pthread_init(); bgp_pthreads_init(); bgp_pth_ka->running = true; diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 8e1b62ac15..e5d3030ed1 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1391,6 +1391,7 @@ static void bgp_startup(void) bgp_master_init(master); bgp_option_set(BGP_OPT_NO_LISTEN); vrf_init(NULL, NULL, NULL, NULL, NULL); + frr_pthread_init(); bgp_init(0); bgp_pthreads_run(); } diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex 6f8bc2218e..46e45e5ee0 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz 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/Dockerfile b/tests/topotests/Dockerfile index 4602688782..fc6d6df530 100644 --- a/tests/topotests/Dockerfile +++ b/tests/topotests/Dockerfile @@ -19,6 +19,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \ libpython-dev \ libreadline-dev \ libc-ares-dev \ + libcap-dev \ man \ mininet \ pkg-config \ diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref index 0a20231371..a7d6fe11a6 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -15,6 +15,7 @@ S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX S>* 4.5.6.13/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.14/32 [1/0] unreachable (blackhole), XX:XX:XX +S 4.5.6.15/32 [255/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref index 6e3e9c87c1..d5bc16a2bf 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref @@ -20,9 +20,10 @@ C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX -S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX +S>* 4:5::6:12/128 [1/0] is directly connected, r1-eth0, XX:XX:XX +S 4:5::6:15/128 [255/0] via fc00::2, r1-eth0, XX:XX:XX S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf index c621593ef7..85c8676964 100644 --- a/tests/topotests/all-protocol-startup/r1/zebra.conf +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -20,7 +20,12 @@ ip route 4.5.6.11/32 192.168.0.2 r1-eth0 ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0 # Create ifname routes ip route 4.5.6.12/32 r1-eth0 -ipv6 route 4:5::6:12/32 r1-eth0 +ipv6 route 4:5::6:12/128 r1-eth0 +# Create a route that has a large admin distance +# an admin distance of 255 should be accepted +# by zebra but not installed. +ip route 4.5.6.15/32 192.168.0.2 255 +ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255 ! interface r1-eth0 description to sw0 - no routing protocol diff --git a/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json index 50797f130a..34f11c0a29 100755 --- a/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json +++ b/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json @@ -564,6 +564,16 @@ "ipv6": "auto" } }, + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + }, "bgp": { "local_as": "300", "address_family": { @@ -620,38 +630,198 @@ "neighbor": { "r2": { "dest_link": { - "r3-link1": {}, - "r3-link2": {}, - "r3-link3": {}, - "r3-link4": {}, - "r3-link5": {}, - "r3-link6": {}, - "r3-link7": {}, - "r3-link8": {}, - "r3-link9": {}, - "r3-link10": {}, - "r3-link11": {}, - "r3-link12": {}, - "r3-link13": {}, - "r3-link14": {}, - "r3-link15": {}, - "r3-link16": {}, - "r3-link17": {}, - "r3-link18": {}, - "r3-link19": {}, - "r3-link20": {}, - "r3-link21": {}, - "r3-link22": {}, - "r3-link23": {}, - "r3-link24": {}, - "r3-link25": {}, - "r3-link26": {}, - "r3-link27": {}, - "r3-link28": {}, - "r3-link29": {}, - "r3-link30": {}, - "r3-link31": {}, - "r3-link32": {} + "r3-link1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link2": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link3": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link4": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link5": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link6": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link7": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link8": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link9": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link10": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link11": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link12": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link13": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link14": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link15": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link16": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link17": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link18": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link19": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link20": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link21": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link22": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link23": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link24": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link25": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link26": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link27": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link28": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link29": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link30": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link31": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link32": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } } } } diff --git a/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json index 9010b8c273..9eea9073c7 100755 --- a/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json +++ b/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json @@ -574,6 +574,16 @@ "ipv6": "auto" } }, + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + }, "bgp": { "local_as": "100", "address_family": { @@ -630,38 +640,198 @@ "neighbor": { "r2": { "dest_link": { - "r3-link1": {}, - "r3-link2": {}, - "r3-link3": {}, - "r3-link4": {}, - "r3-link5": {}, - "r3-link6": {}, - "r3-link7": {}, - "r3-link8": {}, - "r3-link9": {}, - "r3-link10": {}, - "r3-link11": {}, - "r3-link12": {}, - "r3-link13": {}, - "r3-link14": {}, - "r3-link15": {}, - "r3-link16": {}, - "r3-link17": {}, - "r3-link18": {}, - "r3-link19": {}, - "r3-link20": {}, - "r3-link21": {}, - "r3-link22": {}, - "r3-link23": {}, - "r3-link24": {}, - "r3-link25": {}, - "r3-link26": {}, - "r3-link27": {}, - "r3-link28": {}, - "r3-link29": {}, - "r3-link30": {}, - "r3-link31": {}, - "r3-link32": {} + "r3-link1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link2": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link3": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link4": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link5": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link6": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link7": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link8": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link9": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link10": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link11": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link12": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link13": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link14": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link15": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link16": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link17": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link18": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link19": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link20": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link21": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link22": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link23": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link24": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link25": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link26": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link27": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link28": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link29": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link30": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link31": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + }, + "r3-link32": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } } } } 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/bgp_aggregate-address_route-map/__init__.py b/tests/topotests/bgp_aggregate-address_route-map/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/__init__.py diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf new file mode 100644 index 0000000000..ef34817bb1 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + address-family ipv4 unicast + redistribute connected + aggregate-address 172.16.255.0/24 route-map aggr-rmap + exit-address-family +! +route-map aggr-rmap permit 10 + set metric 123 +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf new file mode 100644 index 0000000000..0a283c06d5 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf new file mode 100644 index 0000000000..73d4d0aeea --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + exit-address-family +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py new file mode 100644 index 0000000000..d6753e9b23 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +# +# bgp_aggregate-address_route-map.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# 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 NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_aggregate-address_route-map.py: + +Test if works the following commands: +router bgp 65031 + address-family ipv4 unicast + aggregate-address 192.168.255.0/24 route-map aggr-rmap + +route-map aggr-rmap permit 10 + set metric 123 +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + '192.168.255.1': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 3 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_aggregate_address_has_metric(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json")) + expected = { + 'paths': [ + { + 'med': 123 + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) + + test_func = functools.partial(_bgp_aggregate_address_has_metric, router) + success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, 'Failed to see applied metric for aggregated prefix in "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 149a420a32..547a5949a3 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -11,16 +11,17 @@ for rtr in l3mdev_rtrs: rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: - luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP,LOWER_UP','pass','VRF cust1 up') - luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4: .*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') + luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP','pass','VRF cust1 intf up') + luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4.*UP','pass','VRF cust1 IP intf up') + luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'192.168','pass','VRF cust1 IP config') luCommand(rtr, 'ip route show vrf {}-cust1'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust1 interface route') -luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up') -luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') +luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP','pass','VRF cust2 up') +luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP.* 192.168','pass','VRF cust1 IP config') luCommand(rtr, 'ip route show vrf r4-cust2'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust2 interface route') rtrs = ['ce1', 'ce2', 'ce3'] for rtr in rtrs: luCommand(rtr, 'ip route show','192.168...0/24 dev ce.-eth0','pass','CE interface route') luCommand(rtr,'ping 192.168.1.1 -c 1',' 0. packet loss','wait','CE->PE ping') -luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up') +luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP','pass','VRF cust2 up') luCommand('ce4', 'ip route show vrf ce4-cust2','192.168...0/24 dev ce.-eth0','pass','CE interface route') luCommand('ce4','ping 192.168.2.1 -c 1 -I ce4-cust2',' 0. packet loss','wait','CE4->PE4 ping') diff --git a/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf new file mode 100644 index 0000000000..29a119c291 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf @@ -0,0 +1,8 @@ +hostname spine1 +router bgp 99 + neighbor 192.168.2.1 remote-as internal + neighbor 192.168.4.2 remote-as internal + address-family ipv4 uni + redistribute connected + neighbor 192.168.2.1 route-reflector-client + neighbor 192.168.4.2 route-reflector-client diff --git a/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref new file mode 100644 index 0000000000..552e96ddb9 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref @@ -0,0 +1,162 @@ +{ + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.2.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"spine1-eth0", + "active":true + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"spine1-eth0", + "active":true + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.4.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"spine1-eth1", + "active":true + } + ] + } + ], + "192.168.4.0\/24":[ + { + "prefix":"192.168.4.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"spine1-eth1", + "active":true + } + ] + } + ], + "192.168.5.0\/24":[ + { + "prefix":"192.168.5.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.2.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"spine1-eth0", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.4.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"spine1-eth1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf b/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf new file mode 100644 index 0000000000..6d8f0952d3 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf @@ -0,0 +1 @@ +hostname spine1 diff --git a/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf new file mode 100644 index 0000000000..ea25462d53 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf @@ -0,0 +1,9 @@ +hostname spine1 +ip forwarding +ipv6 forwarding + +int spine1-eth0 + ip addr 192.168.2.3/24 + +int spine1-eth1 + ip addr 192.168.4.3/24 diff --git a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf new file mode 100644 index 0000000000..a865b388ac --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf @@ -0,0 +1,8 @@ +hostname spine2 +router bgp 99 + neighbor 192.168.5.1 remote-as internal + neighbor 192.168.6.2 remote-as internal + address-family ipv4 uni + redistribute connected + neighbor 192.168.5.1 route-reflector-client + neighbor 192.168.6.2 route-reflector-client diff --git a/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref new file mode 100644 index 0000000000..c428a8832f --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref @@ -0,0 +1,162 @@ +{ + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.5.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"spine2-eth0", + "active":true + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.5.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"spine2-eth0", + "active":true + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.6.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"spine2-eth1", + "active":true + } + ] + } + ], + "192.168.4.0\/24":[ + { + "prefix":"192.168.4.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.6.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"spine2-eth1", + "active":true + } + ] + } + ], + "192.168.5.0\/24":[ + { + "prefix":"192.168.5.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"spine2-eth0", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"spine2-eth1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf b/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf new file mode 100644 index 0000000000..3ee14d262c --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf @@ -0,0 +1 @@ +hostname spine2 diff --git a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf new file mode 100644 index 0000000000..a06681fbc4 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf @@ -0,0 +1,9 @@ +hostname spine2 +ip forwarding +ipv6 forwarding + +int spine2-eth0 + ip addr 192.168.5.4/24 + +int spine2-eth1 + ip addr 192.168.6.4/24 diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py new file mode 100755 index 0000000000..c28394a7a7 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python + +# +# test_bgp_rr_ibgp_topo1.py +# +# Copyright (c) 2019 by +# Cumulus Networks, Inc. +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_rr_ibgp_topo1.py: Testing IBGP with RR and no IGP + + + In a leaf/spine topology with only IBGP connections, where + the same network is being redistributed at multiple points + in the network ( say a redistribute connected at both leaf and spines ) + we end up in a state where zebra gets very confused. + + eva# show ip route + Codes: K - kernel route, C - connected, S - static, R - RIP, + O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, + F - PBR, f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + C>* 192.168.1.0/24 is directly connected, tor1-eth0, 00:00:30 + C>* 192.168.2.0/24 is directly connected, tor1-eth1, 00:00:30 + B 192.168.3.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25 + via 192.168.6.2 inactive, 00:00:25 + B>* 192.168.4.0/24 [200/0] via 192.168.2.3, tor1-eth1, 00:00:25 + * via 192.168.6.2 inactive, 00:00:25 + C>* 192.168.5.0/24 is directly connected, tor1-eth2, 00:00:30 + B>* 192.168.6.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25 + * via 192.168.5.4, tor1-eth2, 00:00:25 + + Effectively we have ibgp routes recursing through ibgp routes + and there is no metric to discern whom to listen to. + + This draft: + https://tools.ietf.org/html/draft-ietf-idr-bgp-optimal-route-reflection-19 + + appears to address this issue. From looking at both cisco and arista + deployments they are handling this issue by having the route reflector + prefer the localy learned routes over from their clients. + + Add this topology, in a broken state, so that when we do fix this issue + it is a simple matter of touching this topology up and re-adding it + to the normal daily builds. I also wanted to add this topology + since it is in a state of `doneness` and I wanted to move onto + my normal day job without having to remember about this test. + + This topology is not configured to be run as part of the normal + topotests. + +""" + +import os +import re +import sys +import pytest +import json + +# 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, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "BGP_RR_IBGP Topology 1" + + def build(self, **_opts): + "Build function" + + tgen = get_topogen(self) + + tgen.add_router('tor1') + tgen.add_router('tor2') + tgen.add_router('spine1') + tgen.add_router('spine2') + + # First switch is for a dummy interface (for local network) + # on tor1 + # 192.168.1.0/24 + switch = tgen.add_switch('sw1') + switch.add_link(tgen.gears['tor1']) + + # 192.168.2.0/24 - tor1 <-> spine1 connection + switch = tgen.add_switch('sw2') + switch.add_link(tgen.gears['tor1']) + switch.add_link(tgen.gears['spine1']) + + # 3rd switch is for a dummy interface (for local netwokr) + # 192.168.3.0/24 - tor2 + switch = tgen.add_switch('sw3') + switch.add_link(tgen.gears['tor2']) + + # 192.168.4.0/24 - tor2 <-> spine1 connection + switch = tgen.add_switch('sw4') + switch.add_link(tgen.gears['tor2']) + switch.add_link(tgen.gears['spine1']) + + # 192.168.5.0/24 - tor1 <-> spine2 connection + switch = tgen.add_switch('sw5') + switch.add_link(tgen.gears['tor1']) + switch.add_link(tgen.gears['spine2']) + + # 192.168.6.0/24 - tor2 <-> spine2 connection + switch = tgen.add_switch('sw6') + switch.add_link(tgen.gears['tor2']) + switch.add_link(tgen.gears['spine2']) + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + "Setup topology" + tgen = Topogen(NetworkTopo, module.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_converge_protocols(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + topotest.sleep(5, 'Waiting for BGP_RR_IBGP convergence') + + +def test_bgp_rr_ibgp_routes(): + "Test Route Reflection" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Verify BGP_RR_IBGP Status + logger.info("Verifying BGP_RR_IBGP routes") + +def test_zebra_ipv4_routingTable(): + "Test 'show ip route'" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + failures = 0 + router_list = tgen.routers().values() + for router in router_list: + output = router.vtysh_cmd('show ip route json', isjson=True) + refTableFile = '{}/{}/show_ip_route.json_ref'.format(CWD, router.name) + expected = json.loads(open(refTableFile).read()) + + assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name) + assert topotest.json_cmp(output, expected) is None, assertmsg + +def test_shutdown_check_stderr(): + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Verifying unexpected STDERR output from daemons") + + router_list = tgen.routers().values() + for router in router_list: + router.stop() + + log = tgen.net[router.name].getStdErr('bgpd') + if log: + logger.error('BGPd StdErr Log:' + log) + log = tgen.net[router.name].getStdErr('zebra') + if log: + logger.error('Zebra StdErr Log:' + log) + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + +# +# Auxiliary Functions +# diff --git a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf new file mode 100644 index 0000000000..44a78dffd7 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf @@ -0,0 +1,5 @@ +hostname tor1 +router bgp 99 + neighbor 192.168.2.3 remote-as internal + neighbor 192.168.5.4 remote-as internal + redistribute connected diff --git a/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref new file mode 100644 index 0000000000..223dcebbca --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref @@ -0,0 +1,169 @@ +{ + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"tor1-eth0", + "active":true + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"tor1-eth1", + "active":true + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"bgp", + "distance":200, + "metric":0, + "table":254, + "internalStatus":0, + "internalFlags":5, + "internalNextHopNum":2, + "internalNextHopActiveNum":0, + "nexthops":[ + { + "flags":0, + "ip":"192.168.4.2", + "afi":"ipv4" + }, + { + "flags":0, + "ip":"192.168.6.2", + "afi":"ipv4" + } + ] + } + ], + "192.168.4.0\/24":[ + { + "prefix":"192.168.4.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.2.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"tor1-eth1", + "active":true + }, + { + "flags":0, + "ip":"192.168.6.2", + "afi":"ipv4" + } + ] + } + ], + "192.168.5.0\/24":[ + { + "prefix":"192.168.5.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"tor1-eth2", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":0, + "ip":"192.168.4.2", + "afi":"ipv4" + }, + { + "flags":3, + "fib":true, + "ip":"192.168.5.4", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"tor1-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf b/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf new file mode 100644 index 0000000000..bb8d510b01 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf @@ -0,0 +1 @@ +hostname tor1 diff --git a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf new file mode 100644 index 0000000000..f2fa713507 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf @@ -0,0 +1,12 @@ +hostname tor1 +ip forwarding +ipv6 forwarding + +int tor1-eth0 + ip addr 192.168.1.1/24 + +int tor1-eth1 + ip addr 192.168.2.1/24 + +int tor1-eth2 + ip addr 192.168.5.1/24 diff --git a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf new file mode 100644 index 0000000000..5ef1de260e --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf @@ -0,0 +1,5 @@ +hostname tor2 +router bgp 99 + neighbor 192.168.4.3 remote-as internal + neighbor 192.168.6.4 remote-as internal + redistribute connected diff --git a/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref new file mode 100644 index 0000000000..5f041b8c62 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref @@ -0,0 +1,169 @@ +{ + "192.168.1.0\/24":[ + { + "prefix":"192.168.1.0\/24", + "protocol":"bgp", + "distance":200, + "metric":0, + "table":254, + "internalStatus":0, + "internalFlags":5, + "internalNextHopNum":2, + "internalNextHopActiveNum":0, + "nexthops":[ + { + "flags":0, + "ip":"192.168.2.1", + "afi":"ipv4" + }, + { + "flags":0, + "ip":"192.168.5.1", + "afi":"ipv4" + } + ] + } + ], + "192.168.2.0\/24":[ + { + "prefix":"192.168.2.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"192.168.4.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"tor2-eth1", + "active":true + }, + { + "flags":0, + "ip":"192.168.5.1", + "afi":"ipv4" + } + ] + } + ], + "192.168.3.0\/24":[ + { + "prefix":"192.168.3.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"tor2-eth0", + "active":true + } + ] + } + ], + "192.168.4.0\/24":[ + { + "prefix":"192.168.4.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"tor2-eth1", + "active":true + } + ] + } + ], + "192.168.5.0\/24":[ + { + "prefix":"192.168.5.0\/24", + "protocol":"bgp", + "selected":true, + "destSelected":true, + "distance":200, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":13, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":0, + "ip":"192.168.2.1", + "afi":"ipv4" + }, + { + "flags":3, + "fib":true, + "ip":"192.168.6.4", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"tor2-eth2", + "active":true + } + ] + } + ], + "192.168.6.0\/24":[ + { + "prefix":"192.168.6.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"tor2-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf b/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf new file mode 100644 index 0000000000..03098e75d9 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf @@ -0,0 +1 @@ +hostname tor2 diff --git a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf new file mode 100644 index 0000000000..3318cbb196 --- /dev/null +++ b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf @@ -0,0 +1,13 @@ +hostname tor2 +ip forwarding +ipv6 forwarding + +int tor2-eth0 + ip addr 192.168.3.2/24 + +int tor2-eth1 + ip addr 192.168.4.2/24 + + +int tor2-eth2 + ip addr 192.168.6.2/24 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/ldp-topo1/r1/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 deleted file mode 100644 index f244122f1a..0000000000 --- a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 +++ /dev/null @@ -1,5 +0,0 @@ -xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 deleted file mode 100644 index ff99ff9866..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O 1.1.1.1/32 [110/0] is directly connected, lo -O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 -O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx -O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx -O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 -O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index ff72a1c0b7..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,42 +0,0 @@ -1.1.1.1/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.2.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 38522e162e..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -Local LDP Identifier: 1.1.1.1:0 -Discovery Sources: - Interfaces: - r1-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index 0fb15d2da7..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r1-eth0 ACTIVE xx:xx:xx 5/15 1 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index 3df98bfae5..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,8 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref index 61cb9eec82..7e24359af3 100644 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref @@ -1,8 +1,8 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 implicit-null - XX LDP 10.0.1.2 implicit-null - XX LDP 10.0.1.2 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 implicit-null + XX LDP 10.0.1.2 implicit-null + XX LDP 10.0.1.2 implicit-null + diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 deleted file mode 100644 index 912a082019..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 +++ /dev/null @@ -1,8 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null deleted file mode 100644 index 912a082019..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,8 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 deleted file mode 100644 index eaec2f16b9..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0 -O 2.2.2.2/32 [110/0] is directly connected, lo -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1 -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1 -O 10.0.1.0/24 [110/10] is directly connected, r2-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r2-eth1 -O 10.0.3.0/24 [110/10] is directly connected, r2-eth2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index 54ee39080a..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,56 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index b1bebd7c46..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,12 +0,0 @@ -Local LDP Identifier: 2.2.2.2:0 -Discovery Sources: - Interfaces: - r2-eth0: xmit/recv - LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 - Hold time: 15 sec - r2-eth1: xmit/recv - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index f9fc98408c..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,3 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1 -ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index a70e2f48c6..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,26 +0,0 @@ -Peer LDP Identifier: 1.1.1.1:0 - TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref index 46420ccd11..df05a6b31a 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref @@ -1,7 +1,7 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 implicit-null - XX LDP 10.0.2.3 implicit-null - XX LDP 10.0.2.4 implicit-null - XX LDP 10.0.3.3 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.1.1 implicit-null + XX LDP 10.0.2.3 implicit-null + XX LDP 10.0.2.4 implicit-null + XX LDP 10.0.3.3 implicit-null + diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 deleted file mode 100644 index ba244e76ec..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 3 - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null deleted file mode 100644 index ba244e76ec..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,7 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 3 - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 deleted file mode 100644 index c8a29400b2..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 -O 3.3.3.3/32 [110/0] is directly connected, lo -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r3-eth0 -O 10.0.3.0/24 [110/10] is directly connected, r3-eth1 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index e04d2b7e4a..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,49 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 5e299fff9c..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ -Local LDP Identifier: 3.3.3.3:0 -Discovery Sources: - Interfaces: - r3-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index 243811e3a9..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r3-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index ee1983ac29..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,17 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref index c367f240f4..3978895613 100644 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref @@ -1,10 +1,10 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.4 implicit-null - XX LDP 10.0.3.2 XX - XX LDP 10.0.3.2 implicit-null - XX LDP 10.0.3.2 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.4 implicit-null + XX LDP 10.0.3.2 XX + XX LDP 10.0.3.2 implicit-null + XX LDP 10.0.3.2 implicit-null + diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 deleted file mode 100644 index 9198969bd5..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 +++ /dev/null @@ -1,10 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null deleted file mode 100644 index 9198969bd5..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,10 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 deleted file mode 100644 index df2a2b585f..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 -O 4.4.4.4/32 [110/0] is directly connected, lo -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r4-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index 3d55805d7c..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,49 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 imp-null -4.4.4.4/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 3ebddd606a..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ -Local LDP Identifier: 4.4.4.4:0 -Discovery Sources: - Interfaces: - r4-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index dd57656f15..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r4-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index fb0e7d7dfa..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,17 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref index 9f86cd67cc..174dcebd4d 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref @@ -1,9 +1,9 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.3 implicit-null - XX LDP 10.0.2.3 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.3 implicit-null + XX LDP 10.0.2.3 implicit-null + diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 deleted file mode 100644 index b8cf5a2702..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null deleted file mode 100644 index b8cf5a2702..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,9 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 409a5f54c8..f02f4c4e21 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -77,12 +77,6 @@ from lib import topotest fatal_error = "" -# Expected version of CLI Output - Appendix to filename -# empty string = current, latest output (default) -# "-1" ... "-NNN" previous versions (incrementing with each version) -cli_version = "" - - ##################################################### ## ## Network Topology Definition @@ -164,7 +158,6 @@ def teardown_module(module): def test_router_running(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -179,35 +172,12 @@ def test_router_running(): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error - # Detect CLI Version - # At this time, there are only 2 possible outputs, so simple check - output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() - - # Check if old or new format of CLI Output. Default is to current format - # - # Old (v1) output looks like this: - # Local LDP Identifier: 1.1.1.1:0 - # Discovery Sources: - # Interfaces: - # r1-eth0: xmit/recv - # LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - # Hold time: 15 sec - # Targeted Hellos: - # - # Current (v0) output looks like this: - # AF ID Type Source Holdtime - # ipv4 2.2.2.2 Link r1-eth0 15 - pattern = re.compile("^Local LDP Identifier.*") - if pattern.match(output): - cli_version = "-1" - # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) def test_mpls_interfaces(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -220,7 +190,7 @@ def test_mpls_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -263,7 +233,6 @@ def test_mpls_interfaces(): def test_mpls_ldp_neighbor_establish(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -279,22 +248,22 @@ def test_mpls_ldp_neighbor_establish(): # Look for any node not yet converged for i in range(1, 5): established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() - if cli_version != "-1": - # On current version, we need to make sure they all turn to OPERATIONAL on all lines - # - lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1) - # Check all lines to be either table header (starting with ^AF or show OPERATIONAL) - header = r'^AF.*' - operational = r'^ip.*OPERATIONAL.*' - found_operational = 0 - for j in range(1, len(lines)): - if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])): - established = "" # Empty string shows NOT established - if re.search(operational, lines[j]): - found_operational += 1 - if found_operational < 1: - # Need at least one operational neighbor + + # On current version, we need to make sure they all turn to OPERATIONAL on all lines + # + lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1) + # Check all lines to be either table header (starting with ^AF or show OPERATIONAL) + header = r'^AF.*' + operational = r'^ip.*OPERATIONAL.*' + found_operational = 0 + for j in range(1, len(lines)): + if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])): established = "" # Empty string shows NOT established + if re.search(operational, lines[j]): + found_operational += 1 + if found_operational < 1: + # Need at least one operational neighbor + established = "" # Empty string shows NOT established if not established: print('Waiting for r%s' %i) sys.stdout.flush() @@ -326,7 +295,6 @@ def test_mpls_ldp_neighbor_establish(): def test_mpls_ldp_discovery(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -339,7 +307,7 @@ def test_mpls_ldp_discovery(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref' if os.path.isfile(refTableFile): # Actual output from router actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() @@ -381,7 +349,6 @@ def test_mpls_ldp_discovery(): def test_mpls_ldp_neighbor(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -394,7 +361,7 @@ def test_mpls_ldp_neighbor(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -405,17 +372,8 @@ def test_mpls_ldp_neighbor(): actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() # Mask out changing parts in output - if cli_version == "-1": - # Mask out Timer in Uptime - actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual) - # Mask out Port numbers in TCP connection - actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+", - r"TCP connection: \1:xxx - \2:xxx", actual) - else: - # Current Version - # - # Mask out Timer in Uptime - actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual) + # Mask out Timer in Uptime + actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -446,7 +404,6 @@ def test_mpls_ldp_neighbor(): def test_mpls_ldp_binding(): global fatal_error global net - global cli_version # Skip this test for now until proper sorting of the output # is implemented @@ -463,7 +420,7 @@ def test_mpls_ldp_binding(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_binding.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -474,16 +431,9 @@ def test_mpls_ldp_binding(): actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip() # Mask out changing parts in output - if cli_version == "-1": - # Mask out label - actual = re.sub(r"label: [0-9]+", "label: xxx", actual) - actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual) - else: - # Current Version - # - # Mask out label - actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) - actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + # Mask out label + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -527,7 +477,6 @@ def test_mpls_ldp_binding(): def test_zebra_ipv4_routingTable(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -540,7 +489,7 @@ def test_zebra_ipv4_routingTable(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_ipv4_route.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -562,9 +511,6 @@ def test_zebra_ipv4_routingTable(): # now fix newlines of expected (make them all the same) expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) - # Add missing comma before label (for old version) - actual = re.sub(r"([0-9]) label ", r"\1, label ", actual) - # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -594,7 +540,6 @@ def test_zebra_ipv4_routingTable(): def test_mpls_table(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -607,23 +552,16 @@ def test_mpls_table(): print("******************************************\n") failures = 0 - version = cli_version - if (version == ""): - # check for new output without implicit-null - output = net['r1'].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip() - if 'LDP 10.0.1.2 3' in output: - version = "-no-impl-null" - for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, version) + refTableFile = '%s/r%s/show_mpls_table.ref' if os.path.isfile(refTableFile): # Read expected result from file - expected = open(refTableFile).read().rstrip() + expected = open(refTableFile).read() # Fix newlines (make them all the same) expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) # Actual output from router - actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip() + actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null') # Fix inconsistent Label numbers at beginning of line actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual) @@ -672,7 +610,6 @@ def test_mpls_table(): def test_linux_mpls_routes(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref deleted file mode 100644 index fb193265be..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,31 +0,0 @@ -{ - "neighbors":[ - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} - diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index 7c4d0ab58c..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 2270c3fdde..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "2.2.2.2":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref deleted file mode 100644 index 1376579757..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index a982c1cbd3..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 18ffbc2f8a..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref deleted file mode 100644 index 41de304b2b..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index d7e0e42405..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - } - ], - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index b0669742ab..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - }, - "2.2.2.2":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index 0948c2e41b..ce651c50cd 100755 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -144,9 +144,6 @@ def setup_module(mod): ) tgen.start_router() - for router in router_list.values(): - if router.has_version('<', '3'): - tgen.set_error('unsupported version') def teardown_module(mod): "Teardown the pytest environment" @@ -180,30 +177,8 @@ def test_ospf_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - # Old output (before FRR PR1383) didn't show a list of neighbors. - # Check for dict object and compare to old output if this is the case - tgen = get_topogen() - router = tgen.gears['r1'] - output = router.vtysh_cmd("show ip ospf neighbor json", isjson=True) - - # We could have either old format (without "neighbors" and direct list - # of IP's or new format from PR1659 with "neighbors". - # Trying old formats first and fall back to new format - # - # New format: neighbors have dict instead of list of dicts (PR1723). - if output.has_key('neighbors'): - if isinstance(output['neighbors'], dict): - reffile = "show_ip_ospf_neighbor.json" - else: - reffile = "show_ip_ospf_neighbor.ref" - else: - if isinstance(output["2.2.2.2"], dict): - reffile = "show_ip_ospf_neighbor.ref-old-nolist" - else: - reffile = "show_ip_ospf_neighbor.ref-no-neigh" - for rname in ['r1', 'r2', 'r3']: - router_compare_json_output(rname, "show ip ospf neighbor json", reffile) + router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json") def test_rib(): logger.info("Test: verify RIB") diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index c47dddb8d4..41d6a326cf 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -445,10 +445,10 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type, bgp_data = input_dict[router]["bgp"]["address_family"] neigh_data = bgp_data[addr_type]["unicast"]["neighbor"] - for name, peer_dict in deepcopy(neigh_data).iteritems(): + for peer_name, peer_dict in deepcopy(neigh_data).iteritems(): for dest_link, peer in peer_dict["dest_link"].iteritems(): deactivate = None - nh_details = topo[name] + nh_details = topo[peer_name] # Loopback interface if "source_link" in peer and peer["source_link"] == "lo": for destRouterLink, data in sorted(nh_details["links"]. @@ -864,7 +864,7 @@ def clear_bgp_and_verify(tgen, topo, router): peer_uptime_before_clear_bgp = {} # Verifying BGP convergence before bgp clear command - for retry in range(1, 11): + for retry in range(31): sleeptime = 3 # Waiting for BGP to converge logger.info("Waiting for %s sec for BGP to converge on router" @@ -944,7 +944,7 @@ def clear_bgp_and_verify(tgen, topo, router): peer_uptime_after_clear_bgp = {} # Verifying BGP convergence after bgp clear command - for retry in range(11): + for retry in range(31): sleeptime = 3 # Waiting for BGP to converge logger.info("Waiting for %s sec for BGP to converge on router" @@ -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..c413bf45c7 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 @@ -34,11 +35,7 @@ import ConfigParser import traceback import socket import ipaddr -import re -from lib import topotest - -from functools import partial from lib.topolog import logger, logger_config from lib.topogen import TopoRouter from lib.topotest import interface_set_status @@ -208,6 +205,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 +545,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] @@ -736,62 +732,6 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0): return _retry -def disable_v6_link_local(tgen, router, intf_name=None): - """ - Disables ipv6 link local addresses for a particular interface or - all interfaces - - * `tgen`: tgen onject - * `router` : router for which hightest interface should be - calculated - * `intf_name` : Interface name for which v6 link local needs to - be disabled - """ - - router_list = tgen.routers() - for rname, rnode in router_list.iteritems(): - if rname != router: - continue - - linklocal = [] - - ifaces = router_list[router].run('ip -6 address') - - # Fix newlines (make them all the same) - ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() - - interface = None - ll_per_if_count = 0 - for line in ifaces: - # Interface name - m = re.search('[0-9]+: ([^:]+)[@if0-9:]+ <', line) - if m: - interface = m.group(1).split("@")[0] - ll_per_if_count = 0 - - # Interface ip - m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+' - ':[0-9a-f]+[/0-9]*) scope link', line) - if m: - local = m.group(1) - ll_per_if_count += 1 - if ll_per_if_count > 1: - linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] - else: - linklocal += [[interface, local]] - - if len(linklocal[0]) > 1: - link_local_dict = {item[0]: item[1] for item in linklocal} - - for lname, laddr in link_local_dict.items(): - - if intf_name is not None and lname != intf_name: - continue - - cmd = "ip addr del {} dev {}".format(laddr, lname) - router_list[router].run(cmd) - - ############################################# # These APIs, will used by testcase ############################################# @@ -821,8 +761,6 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_name = destRouterLink else: interface_name = data["interface"] - if "ipv6" in data: - disable_v6_link_local(tgen, c_router, interface_name) interface_data.append("interface {}".format( str(interface_name) )) @@ -893,6 +831,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 +857,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 +1056,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 +1096,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 +1130,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 +1173,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 +1220,86 @@ 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( 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 +1314,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 +1326,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 +1352,172 @@ 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 + """ + + 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) + + ############################################# # Verification APIs ############################################# @@ -1625,5 +1819,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/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json index 254c137acd..6b1fe76b6e 100644 --- a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json @@ -4,7 +4,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -17,7 +17,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -30,7 +30,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8300, "distance":150, "installed":true, @@ -43,7 +43,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8400, "distance":150, "installed":true, @@ -56,7 +56,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -69,7 +69,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json index 0d73a409ed..79965d280a 100644 --- a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json @@ -4,7 +4,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":20100, "distance":150, "installed":true, @@ -17,7 +17,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -30,7 +30,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":10400, "distance":150, "installed":true, @@ -43,7 +43,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -56,7 +56,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -69,7 +69,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -82,7 +82,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -95,7 +95,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -108,7 +108,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json index b15f90afd1..ceb2f7a0e5 100644 --- a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json @@ -4,7 +4,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8100, "distance":150, "installed":true, @@ -17,7 +17,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -30,7 +30,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8400, "distance":150, "installed":true, @@ -43,7 +43,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -56,7 +56,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, diff --git a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json index d1238517f5..d7f54b224d 100644 --- a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json @@ -4,7 +4,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8100, "distance":150, "installed":true, @@ -17,7 +17,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -30,7 +30,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":8300, "distance":150, "installed":true, @@ -43,7 +43,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -56,7 +56,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, @@ -69,7 +69,7 @@ "installed":true, "nexthops":[ { - "type":"SR", + "type":"SR (OSPF)", "outLabel":3, "distance":150, "installed":true, diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index ade5bfd501..62c825341f 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,6 @@ # Skip pytests example directory [pytest] -norecursedirs = .git example-test example-topojson-test lib docker +norecursedirs = .git example-test example-topojson-test lib docker bgp_rr_ibgp [topogen] # Default configuration values diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index d52824ff07..8845df5fc7 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -28,6 +28,7 @@ show bgp ipv6 update-groups advertised-routes show bgp ipv6 update-groups packet-queue show bgp ipv6 update-groups statistics show ip bgp statistics +show bgp martian next-hop show bgp evpn route CMD_LIST_END @@ -37,14 +38,17 @@ PROC_NAME:zebra CMD_LIST_START show zebra show zebra client summary -show ip route - +show ip zebra route dump json +show ipv6 zebra route dump json +show ip nht vrf all show route-map show memory -show interface +show interface vrf all show vrf +show zebra fpm stats show error all show work-queues +show debugging hashtable show running-config show thread cpu show thread poll diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py index 118ca113a5..c9ca9c3d0d 100644..100755 --- a/tools/generate_support_bundle.py +++ b/tools/generate_support_bundle.py @@ -1,3 +1,5 @@ +#!/usr/bin/python + ######################################################## ### Python Script to generate the FRR support bundle ### ######################################################## diff --git a/tools/subdir.am b/tools/subdir.am index 7713bb1ade..c637db6eb1 100644 --- a/tools/subdir.am +++ b/tools/subdir.am @@ -16,6 +16,7 @@ sbin_SCRIPTS += \ \ tools/frrcommon.sh \ tools/frrinit.sh \ + tools/generate_support_bundle.py \ tools/watchfrr.sh \ # end @@ -35,6 +36,7 @@ EXTRA_DIST += \ tools/frr-reload \ tools/frr-reload.py \ tools/frr.service \ + tools/generate_support_bundle.py \ tools/multiple-bgpd.sh \ tools/rrcheck.pl \ tools/rrlookup.pl \ 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/vtysh/vtysh.c b/vtysh/vtysh.c index a762e9555c..08126f6885 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2422,6 +2422,53 @@ DEFUN (vtysh_show_error_code, return CMD_SUCCESS; } +/* Northbound. */ +DEFUN (show_yang_operational_data, + show_yang_operational_data_cmd, + "show yang operational-data XPATH$xpath\ + [{\ + format <json$json|xml$xml>\ + |translate WORD$translator_family\ + }]" DAEMONS_LIST, + SHOW_STR + "YANG information\n" + "Show YANG operational data\n" + "XPath expression specifying the YANG data path\n" + "Set the output format\n" + "JavaScript Object Notation\n" + "Extensible Markup Language\n" + "Translate operational data\n" + "YANG module translator\n" + DAEMONS_STR) +{ + int idx_protocol = argc - 1; + char *fcmd = argv_concat(argv, argc - 1, 0); + int ret = vtysh_client_execute_name(argv[idx_protocol]->text, fcmd); + XFREE(MTYPE_TMP, fcmd); + return ret; +} + +DEFUNSH(VTYSH_ALL, debug_nb, + debug_nb_cmd, + "[no] debug northbound\ + [<\ + callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ + |notifications$notifications\ + |events$events\ + >]", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Callbacks\n" + "Configuration\n" + "State\n" + "RPC\n" + "Notifications\n" + "Events\n") +{ + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2548,10 +2595,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd, } DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, - "no log facility [FACILITY]", NO_STR + "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]", + NO_STR "Logging control\n" "Reset syslog facility to default (daemon)\n" - "Syslog facility\n") + LOG_FACILITY_DESC) { return CMD_SUCCESS; } @@ -4017,6 +4065,11 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd); install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd); + /* northbound */ + install_element(VIEW_NODE, &show_yang_operational_data_cmd); + install_element(ENABLE_NODE, &debug_nb_cmd); + install_element(CONFIG_NODE, &debug_nb_cmd); + /* misc lib show commands */ install_element(VIEW_NODE, &vtysh_show_memory_cmd); install_element(VIEW_NODE, &vtysh_show_modules_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 3ec2eb239d..e56c6fbf4e 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -406,7 +406,9 @@ void vtysh_config_parse_line(void *arg, const char *line) == 0 || strncmp(line, "frr", strlen("frr")) == 0 || strncmp(line, "agentx", strlen("agentx")) == 0 - || strncmp(line, "no log", strlen("no log")) == 0) + || strncmp(line, "no log", strlen("no log")) == 0 + || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0 + || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0) config_add_line_uniq(config_top, line); else config_add_line(config_top, line); diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index c27491e55c..30f606c202 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -19,3 +19,6 @@ watchfrr_watchfrr_SOURCES = \ watchfrr/watchfrr_errors.c \ watchfrr/watchfrr_vty.c \ # end + +watchfrr/watchfrr_vty_clippy.c: $(CLIPPY_DEPS) +watchfrr/watchfrr_vty.$(OBJEXT): watchfrr/watchfrr_vty_clippy.c diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index c17d381730..ea59655824 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -159,6 +159,15 @@ struct daemon { struct thread *t_write; struct daemon *next; struct restart_info restart; + + /* + * For a given daemon, if we've turned on ignore timeouts + * ignore the timeout value and assume everything is ok + * This is for daemon debugging w/ gdb after we have started + * FRR and realize we have something that needs to be looked + * at + */ + bool ignore_timeout; }; #define OPTION_MINRESTART 2000 @@ -191,6 +200,25 @@ static void phase_check(void); static void restart_done(struct daemon *dmn); static const char *progname; + +void watchfrr_set_ignore_daemon(struct vty *vty, const char *dname, bool ignore) +{ + struct daemon *dmn; + + for (dmn = gs.daemons; dmn; dmn = dmn->next) { + if (strncmp(dmn->name, dname, strlen(dmn->name)) == 0) + break; + } + + if (dmn) { + dmn->ignore_timeout = ignore; + vty_out(vty, "%s switching to %s\n", dmn->name, + ignore ? "ignore" : "watch"); + } else + vty_out(vty, "%s is not configured for running at the moment", + dname); +} + static void printhelp(FILE *target) { fprintf(target, @@ -432,12 +460,20 @@ static int run_job(struct restart_info *restart, const char *cmdtype, return -1; } +#if defined HAVE_SYSTEMD + char buffer[512]; + + snprintf(buffer, sizeof(buffer), "restarting %s", restart->name); + systemd_send_status(buffer); +#endif + /* Note: time_elapsed test must come before the force test, since we need to make sure that delay is initialized for use below in updating the restart interval. */ if ((time_elapsed(&delay, &restart->time)->tv_sec < restart->interval) && !force) { + if (gs.loglevel > LOG_DEBUG + 1) zlog_debug( "postponing %s %s: " @@ -462,6 +498,9 @@ static int run_job(struct restart_info *restart, const char *cmdtype, restart->pid = 0; } +#if defined HAVE_SYSTEMD + systemd_send_status("FRR Operational"); +#endif /* Calculate the new restart interval. */ if (update_interval) { if (delay.tv_sec > 2 * gs.max_restart_interval) @@ -533,7 +572,9 @@ static int wakeup_init(struct thread *t_wakeup) static void restart_done(struct daemon *dmn) { if (dmn->state != DAEMON_DOWN) { - zlog_warn("wtf?"); + zlog_warn( + "Daemon: %s: is in %s state but expected it to be in DAEMON_DOWN state", + dmn->name, state_str[dmn->state]); return; } if (dmn->t_wakeup) @@ -677,6 +718,7 @@ static void daemon_send_ready(int exitcode) fclose(fp); #if defined HAVE_SYSTEMD systemd_send_started(master, 0); + systemd_send_status("FRR Operational"); #endif sent = 1; } @@ -961,6 +1003,8 @@ static int wakeup_no_answer(struct thread *t_wakeup) dmn->t_wakeup = NULL; dmn->state = DAEMON_UNRESPONSIVE; + if (dmn->ignore_timeout) + return 0; flog_err(EC_WATCHFRR_CONNECTION, "%s state -> unresponsive : no response yet to ping " "sent %ld seconds ago", @@ -1014,7 +1058,8 @@ void watchfrr_status(struct vty *vty) (long)gs.restart.pid); for (dmn = gs.daemons; dmn; dmn = dmn->next) { - vty_out(vty, " %-20s %s\n", dmn->name, state_str[dmn->state]); + vty_out(vty, " %-20s %s%s", dmn->name, state_str[dmn->state], + dmn->ignore_timeout ? "/Ignoring Timeout\n" : "\n"); if (dmn->restart.pid) vty_out(vty, " restart running, pid %ld\n", (long)dmn->restart.pid); diff --git a/watchfrr/watchfrr.h b/watchfrr/watchfrr.h index c5f54769bd..ba6e94960f 100644 --- a/watchfrr/watchfrr.h +++ b/watchfrr/watchfrr.h @@ -41,4 +41,6 @@ extern void watchfrr_status(struct vty *vty); */ extern bool check_all_up(void); +extern void watchfrr_set_ignore_daemon(struct vty *vty, const char *dname, + bool ignore); #endif /* FRR_WATCHFRR_H */ diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c index 9b844d67f2..c06cb89382 100644 --- a/watchfrr/watchfrr_vty.c +++ b/watchfrr/watchfrr_vty.c @@ -134,6 +134,23 @@ DEFUN (show_watchfrr, return CMD_SUCCESS; } +#ifndef VTYSH_EXTRACT_PL +#include "watchfrr/watchfrr_vty_clippy.c" +#endif + +DEFPY (watchfrr_ignore_daemon, + watchfrr_ignore_daemon_cmd, + "[no] watchfrr ignore DAEMON$dname", + NO_STR + "Watchfrr Specific sub-command\n" + "Ignore a specified daemon when it does not respond to echo request\n" + "The daemon to ignore\n") +{ + watchfrr_set_ignore_daemon(vty, dname, no ? false : true ); + + return CMD_SUCCESS; +} + void integrated_write_sigchld(int status) { uint8_t reply[4] = {0, 0, 0, CMD_WARNING}; @@ -168,6 +185,9 @@ void watchfrr_vty_init(void) integrated_write_pid = -1; install_element(ENABLE_NODE, &config_write_integrated_cmd); install_element(ENABLE_NODE, &show_debugging_watchfrr_cmd); + + install_element(ENABLE_NODE, &watchfrr_ignore_daemon_cmd); + install_element(CONFIG_NODE, &show_debugging_watchfrr_cmd); install_element(VIEW_NODE, &show_watchfrr_cmd); } diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index 853d823880..0c62954570 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -23,6 +23,11 @@ module frr-eigrpd { description "This module defines a model for managing FRR eigrpd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2019-06-19 { description "Initial revision."; reference @@ -94,9 +99,7 @@ module frr-eigrpd { leaf-list passive-interface { description "List of suppressed interfaces"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; } leaf active-time { diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index d3cc66dfaa..4f7f3beebd 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -11,6 +11,10 @@ module frr-interface { description "This module defines a model for managing FRR interfaces."; + revision 2019-09-09 { + description + "Added interface-ref typedef"; + } revision 2018-03-28 { description "Initial revision."; @@ -43,4 +47,13 @@ module frr-interface { } } } + + typedef interface-ref { + type leafref { + require-instance false; + path "/frr-interface:lib/frr-interface:interface/frr-interface:name"; + } + description + "Reference to an interface"; + } } diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 9180b0c5f3..faa880eff4 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -27,6 +27,11 @@ module frr-isisd { description "This module defines a model for managing FRR isisd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2018-07-26 { description "Initial revision."; @@ -56,6 +61,13 @@ module frr-isisd { "This type defines IS-IS level of an object."; } + typedef extended-circuit-id { + type uint32; + description + "This type defines the extended circuit ID + associated with an interface."; + } + typedef network-type { type enumeration { enum "unknown" { @@ -90,6 +102,20 @@ module frr-isisd { pattern, An example LSP ID is 0143.0438.AeF0.02-01"; } + typedef snpa { + type string { + length "0 .. 20"; + } + description + "This type defines the Subnetwork Point + of Attachment (SNPA) format. + The SNPA should be encoded according to the rules + specified for the particular type of subnetwork + being used. As an example, for an ethernet subnetwork, + the SNPA is encoded as a MAC address like + '00aa.bbcc.ddee'."; + } + typedef system-id { type string { pattern "[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}"; @@ -270,6 +296,399 @@ module frr-isisd { } } + grouping interface-config { + description "Interface configuration grouping"; + + leaf area-tag { + type string; + mandatory true; + description + "Area-tag associated to this circuit."; + } + + leaf ipv4-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv4 traffic over this circuit."; + } + + leaf ipv6-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv6 traffic over this circuit."; + } + + leaf circuit-type { + type level; + default "level-1-2"; + description + "IS-type of this circuit."; + } + + leaf bfd-monitoring { + type boolean; + default false; + description "Monitor IS-IS peers on this circuit."; + } + + container csnp-interval { + description + "Complete Sequence Number PDU (CSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-2"; + } + } + + container psnp-interval { + description + "Partial Sequence Number PDU (PSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PCNSP interval for level-2"; + } + } + + container hello { + description + "Parameters related to IS-IS hello PDUs."; + leaf padding { + type boolean; + default "true"; + description + "Add padding to IS-IS hello PDUs."; + } + + container interval { + description + "Interval between consecutive hello messages."; + leaf level-1 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-1; interval will depend on multiplier."; + } + + leaf level-2 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-2; interval will depend on multiplier."; + } + } + + container multiplier { + description + "Multiplier for the hello messages holding time."; + leaf level-1 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + + leaf level-2 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + } + } + + container metric { + description + "Default metric for this IS-IS circuit."; + leaf level-1 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-1 metric for this IS-IS circuit."; + } + + leaf level-2 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-2 metric for this IS-IS circuit."; + } + } + + container priority { + description + "Priority for Designated Router election."; + leaf level-1 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-1 priority for this IS-IS circuit."; + } + + leaf level-2 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-2 priority for this IS-IS circuit."; + } + } + + leaf network-type { + type network-type; + default "broadcast"; + must "(. = \"point-to-point\") or (. = \"broadcast\")"; + description + "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; + } + + leaf passive { + type boolean; + default "false"; + description + "Interface is in passive mode."; + } + + container password { + presence "Present if a password is set for this IS interface."; + uses isis-password; + } + + leaf disable-three-way-handshake { + type boolean; + default "false"; + description + "Disables three-way handshake when creating new adjacencies."; + } + + container multi-topology { + description + "IS-IS topologies configured on this circuit."; + leaf ipv4-unicast { + type boolean; + default "true"; + description + "IPv4 unicast topology."; + } + + leaf ipv4-multicast { + type boolean; + default "true"; + description + "IPv4 multicast topology."; + } + + leaf ipv4-management { + type boolean; + default "true"; + description + "IPv4 management topology."; + } + + leaf ipv6-unicast { + type boolean; + default "true"; + description + "IPv6 unicast topology."; + } + + leaf ipv6-multicast { + type boolean; + default "true"; + description + "IPv6 multicast topology."; + } + + leaf ipv6-management { + type boolean; + default "true"; + description + "IPv6 management topology."; + } + + leaf ipv6-dstsrc { + type boolean; + default "true"; + description + "IPv6 destination-source topology."; + } + } + } + + grouping adjacency-state { + container adjacencies { + config false; + list adjacency { + leaf neighbor-sys-type { + type level; + description + "Level capability of neighboring system"; + } + leaf neighbor-sysid { + type system-id; + description + "The system-id of the neighbor"; + } + leaf neighbor-extended-circuit-id { + type extended-circuit-id; + description + "Circuit ID of the neighbor"; + } + leaf neighbor-snpa { + type snpa; + description + "SNPA of the neighbor"; + } + leaf hold-timer { + type uint16; + units seconds; + description + "The holding time in seconds for this + adjacency. This value is based on + received hello PDUs and the elapsed + time since receipt."; + } + leaf neighbor-priority { + type uint8 { + range "0 .. 127"; + } + description + "Priority of the neighboring IS for becoming + the DIS."; + } + leaf state { + type adj-state-type; + description + "This leaf describes the state of the interface."; + } + + description + "List of operational adjacencies."; + } + description + "This container lists the adjacencies of + the local node."; + } + description + "Adjacency state"; + } + + grouping event-counters { + container event-counters { + config false; + leaf adjacency-changes { + type uint32; + description + "The number of times an adjacency state change has + occurred on this interface."; + } + leaf adjacency-number { + type uint32; + description + "The number of adjacencies on this interface."; + } + leaf init-fails { + type uint32; + description + "The number of times initialization of this + interface has failed. This counts events such + as PPP NCP failures. Failures to form an + adjacency are counted by adjacency-rejects."; + } + leaf adjacency-rejects { + type uint32; + description + "The number of times an adjacency has been + rejected on this interface."; + } + leaf id-len-mismatch { + type uint32; + description + "The number of times an IS-IS PDU with an ID + field length different from that for this + system has been received on this interface."; + } + leaf max-area-addresses-mismatch { + type uint32; + description + "The number of times an IS-IS PDU has been + received on this interface with the + max area address field differing from that of + this system."; + } + leaf authentication-type-fails { + type uint32; + description + "Number of authentication type mismatches."; + } + leaf authentication-fails { + type uint32; + description + "Number of authentication key failures."; + } + description "IS-IS interface event counters."; + } + description + "Grouping for IS-IS interface event counters"; + } + + grouping interface-state { + description + "IS-IS interface operational state."; + uses adjacency-state; + uses event-counters; + } + grouping notification-instance-hdr { description "Instance specific IS-IS notification data grouping"; @@ -296,7 +715,7 @@ module frr-isisd { description "Interface specific IS-IS notification data grouping"; leaf interface-name { - type string; + type frr-interface:interface-ref; description "IS-IS interface name"; } @@ -308,7 +727,7 @@ module frr-isisd { } leaf extended-circuit-id { - type uint32; + type extended-circuit-id; description "Eextended circuit-id of the interface."; } @@ -728,270 +1147,8 @@ module frr-isisd { presence "Present if an IS-IS circuit is defined for this interface."; description "IS-IS interface parameters."; - leaf area-tag { - type string; - mandatory true; - description - "Area-tag associated to this circuit."; - } - - leaf ipv4-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv4 traffic over this circuit."; - } - - leaf ipv6-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv6 traffic over this circuit."; - } - - leaf circuit-type { - type level; - default "level-1-2"; - description - "IS-type of this circuit."; - } - - leaf bfd-monitoring { - type boolean; - default false; - description "Monitor IS-IS peers on this circuit."; - } - - container csnp-interval { - description - "Complete Sequence Number PDU (CSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-2"; - } - } - - container psnp-interval { - description - "Partial Sequence Number PDU (PSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PCNSP interval for level-2"; - } - } - - container hello { - description - "Parameters related to IS-IS hello PDUs."; - leaf padding { - type boolean; - default "true"; - description - "Add padding to IS-IS hello PDUs."; - } - - container interval { - description - "Interval between consecutive hello messages."; - leaf level-1 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-1; interval will depend on multiplier."; - } - - leaf level-2 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-2; interval will depend on multiplier."; - } - } - - container multiplier { - description - "Multiplier for the hello messages holding time."; - leaf level-1 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - - leaf level-2 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - } - } - - container metric { - description - "Default metric for this IS-IS circuit."; - leaf level-1 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-1 metric for this IS-IS circuit."; - } - - leaf level-2 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-2 metric for this IS-IS circuit."; - } - } - - container priority { - description - "Priority for Designated Router election."; - leaf level-1 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-1 priority for this IS-IS circuit."; - } - - leaf level-2 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-2 priority for this IS-IS circuit."; - } - } - - leaf network-type { - type network-type; - default "broadcast"; - must "(. = \"point-to-point\") or (. = \"broadcast\")"; - description - "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; - } - - leaf passive { - type boolean; - default "false"; - description - "Interface is in passive mode."; - } - - container password { - presence "Present if a password is set for this IS interface."; - uses isis-password; - } - - leaf disable-three-way-handshake { - type boolean; - default "false"; - description - "Disables three-way handshake when creating new adjacencies."; - } - - container multi-topology { - description - "IS-IS topologies configured on this circuit."; - leaf ipv4-unicast { - type boolean; - default "true"; - description - "IPv4 unicast topology."; - } - - leaf ipv4-multicast { - type boolean; - default "true"; - description - "IPv4 multicast topology."; - } - - leaf ipv4-management { - type boolean; - default "true"; - description - "IPv4 management topology."; - } - - leaf ipv6-unicast { - type boolean; - default "true"; - description - "IPv6 unicast topology."; - } - - leaf ipv6-multicast { - type boolean; - default "true"; - description - "IPv6 multicast topology."; - } - - leaf ipv6-management { - type boolean; - default "true"; - description - "IPv6 management topology."; - } - - leaf ipv6-dstsrc { - type boolean; - default "true"; - description - "IPv6 destination-source topology."; - } - } + uses interface-config; + uses interface-state; } } diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang new file mode 100644 index 0000000000..00ba02a3c3 --- /dev/null +++ b/yang/frr-nexthop.yang @@ -0,0 +1,200 @@ +module frr-nexthop { + yang-version 1.1; + namespace "http://frrouting.org/yang/nexthop"; + prefix frr-nexthop; + + import ietf-inet-types { + prefix inet; + } + + import ietf-routing-types { + prefix rt-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines a model for managing FRR nexthop information."; + + revision 2019-08-15 { + description + "Initial revision."; + } + + typedef gateway-address { + type inet:ip-address; + } + + typedef nexthop-type { + type enumeration { + enum "ifindex" { + value 1; + description + "Specific interface."; + } + enum "ip4" { + value 2; + description + "IPv4 address."; + } + enum "ip4-ifindex" { + value 3; + description + "IPv4 address and interface."; + } + enum "ip6" { + value 4; + description + "IPv6 address."; + } + enum "ip6-ifindex" { + value 5; + description + "IPv6 address and interface."; + } + enum "blackhole" { + value 6; + description + "Unreachable or prohibited."; + } + } + description + "Nexthop types."; + } + + typedef blackhole-type { + type enumeration { + enum "unspec" { + value 0; + description + "Generic unreachable."; + } + enum "null" { + value 1; + description + "Null type."; + } + enum "reject" { + value 2; + description + "ICMP unreachable."; + } + enum "prohibited" { + value 3; + description + "ICMP admin-prohibited."; + } + } + default "null"; + description + "Nexthop blackhole types."; + } + + /* + * Nexthop object + */ + grouping frr-nexthop { + leaf nh-type { + type nexthop-type; + mandatory true; + description + "The nexthop type."; + } + + leaf gateway { + type gateway-address; + description + "The nexthop gateway address."; + } + + leaf vrf { + type string; + description + "The nexthop vrf name, if different from the route."; + } + + leaf interface { + type string; + description + "The nexthop egress interface."; + } + + leaf bh-type { + type blackhole-type; + description + "A blackhole sub-type, if the nexthop is a blackhole type."; + } + + leaf flags { + type uint32; + description + "The nexthop's raw flags value."; + } + + leaf is-duplicate { + type empty; + description + "Duplicate nexthop; will be ignored."; + } + leaf is-recursive { + type empty; + description + "Nexthop must be resolved through another gateway."; + } + leaf is-onlink { + type empty; + description + "Nexthop is directly connected."; + } + leaf is-active { + type empty; + description + "Nexthop is active."; + } + + uses rt-types:mpls-label-stack { + description + "Nexthop's MPLS label stack."; + } + + leaf mtu { + type uint32; + description + "The nexthop's specific MTU."; + } + + } // End of nexthop + + /* + * Nexthop-group container + */ + grouping frr-nexthop-group { + description + "A nexthop-group, represented as a list of nexthop objects."; + + leaf name { + type string; + description + "The nexthop-group name."; + } + + list entry { + key "id"; + description + "A list of nexthop objects."; + leaf id { + type uint32; + description + "Identifies a nexthop within a nexthop group; the entries + are ordered by id value, and the value has no other meaning."; + } + + uses frr-nexthop; + + } + } // End of frr-nexthop-group + +} diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 07690793f0..94a9ebf3e1 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -24,6 +24,11 @@ module frr-ripd { description "This module defines a model for managing FRR ripd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2017-12-06 { description "Initial revision."; @@ -113,9 +118,7 @@ module frr-ripd { "Enable RIP on the specified IP network."; } leaf-list interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "Enable RIP on the specified interface."; } @@ -124,7 +127,15 @@ module frr-ripd { description "Offset-list to modify route metric."; leaf interface { - type string; + type union { + type frr-interface:interface-ref; + type enumeration { + enum '*' { + description + "Match all interfaces."; + } + } + } description "Interface to match. Use '*' to match all interfaces."; } @@ -168,18 +179,14 @@ module frr-ripd { } leaf-list passive-interface { when "../passive-default = 'false'"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIP packets is disabled."; } leaf-list non-passive-interface { when "../passive-default = 'true'"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIP packets is enabled."; diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index b341b438a4..831758af86 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -24,6 +24,11 @@ module frr-ripngd { description "This module defines a model for managing FRR ripngd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2018-11-27 { description "Initial revision."; @@ -71,9 +76,7 @@ module frr-ripngd { "Enable RIPng on the specified IPv6 network."; } leaf-list interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "Enable RIPng on the specified interface."; } @@ -82,7 +85,15 @@ module frr-ripngd { description "Offset-list to modify route metric."; leaf interface { - type string; + type union { + type frr-interface:interface-ref; + type enumeration { + enum '*' { + description + "Match all interfaces."; + } + } + } description "Interface to match. Use '*' to match all interfaces."; } @@ -118,9 +129,7 @@ module frr-ripngd { } } leaf-list passive-interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIPng packets is disabled."; diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang new file mode 100644 index 0000000000..b5ca5c9a40 --- /dev/null +++ b/yang/frr-zebra.yang @@ -0,0 +1,1788 @@ +module frr-zebra { + yang-version 1.1; + namespace "http://frrouting.org/yang/zebra"; + prefix frr-zebra; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import frr-route-types { + prefix frr-route-types; + } + + import ietf-routing-types { + prefix rt-types; + } + + import frr-nexthop { + prefix frr-nh; + } + + import frr-interface { + prefix frr-interface; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines a model for managing the FRR zebra daemon."; + + revision 2019-06-01 { + description + "Initial revision."; + } + + typedef unix-timestamp { + type uint32; + units "seconds"; + description + "An absolute time in seconds since the unix epoch."; + } + + /* + * Multicast RPF mode configurable type + */ + typedef mcast-rpf-lookup-mode { + type enumeration { + enum "none" { + value 0; + description + "No mode set."; + } + enum "mrib-only" { + value 1; + description + "Lookup in unicast RIB only."; + } + enum "urib-only" { + value 2; + description + "Lookup in multicast RIB only."; + } + enum "mrib-then-urib" { + value 3; + description + "Try multicast RIB first, fall back to unicast RIB."; + } + enum "lower-distance" { + value 4; + description + "Lookup both unicast and mcast, use entry with lower distance."; + } + enum "longer-prefix" { + value 5; + description + "Lookup both unicast and mcast, use entry with longer prefix."; + } + } + description + "Multicast RPF lookup behavior"; + } + + /* + * Common route data, shared by v4 and v6 routes. + */ + grouping route-common { + description + "Common information about a route."; + + leaf vrf { + type string; + description + "The route's vrf name."; + } + + leaf distance { + type uint8; + description + "Admin distance based on routing protocol."; + } + leaf metric { + type uint32; + description + "Route metric value."; + } + leaf tag { + type uint32 { + range "1..4294967295"; + } + description + "Route tag value."; + } + + leaf is-selected { + type empty; + description + "Route is the selected or preferred route for the prefix."; + } + leaf is-installed { + type empty; + description + "Route is installed in the FIB."; + } + leaf is-failed { + type empty; + description + "Route installation in FIB has failed."; + } + leaf is-queued { + type empty; + description + "Route has a pending FIB operation that has not completed."; + } + + leaf internal-flags { + type int32; + description + "Internal flags for the route."; + } + leaf internal-status { + type int32; + description + "Internal status for the route."; + } + + leaf uptime { + type uint32; + units "seconds"; + description + "Uptime for the route."; + } + + container nexthop-group { + description + "Nexthop information for the route."; + + uses frr-nh:frr-nexthop-group; + } + + } // End of route-common + + /* + * IPv4 Route object. + */ + grouping ip4-route { + description + "An IPv4 route."; + + leaf prefix { + type inet:ipv4-prefix; + description + "IP address (in the form A.B.C.D) and prefix length, + separated by the slash (/) character. The range of + values for the prefix-length is 0 to 32."; + } + leaf "protocol" { + type frr-route-types:frr-route-types-v4; + description + "The protocol owning the route."; + } + + uses route-common; + + } // End of ip4-route + + /* + * IPv6 Route object. + */ + grouping ip6-route { + description + "An IPv6 route."; + + leaf prefix { + type inet:ipv6-prefix; + description + "The route's IPv6 prefix."; + } + leaf "protocol" { + type frr-route-types:frr-route-types-v6; + description + "The protocol owning the route."; + } + + uses route-common; + + } // End of ip6-route + + /* + * VxLAN Network Identifier type + */ + typedef vni-id-type { + type uint32 { + range "0..16777215"; + } + description + "A VxLAN network identifier value."; + } + + typedef vni-vtep-flood-type { + type enumeration { + enum "head-end-repl" { + value 0; + description + "Head-end replication."; + } + enum "disabled" { + value 1; + description + "Flooding disabled."; + } + enum pim-sm { + value 2; + description + "Multicast PIM-SM."; + } + } + } + + /* + * Information about EVPN VNIs + */ + grouping vni-information { + choice type-choice { + case l2 { + leaf is-layer2 { + type empty; + description + "Information about an L2 VNI."; + } + leaf vtep-count { + type uint32; + description + "Number of VTEPs."; + } + } + case l3 { + leaf is-layer3 { + type empty; + description + "Information about an L3 VNI."; + } + } + } + leaf vni-id { + type vni-id-type; + description + "The VNI identifier."; + } + leaf vxlan-ifname { + type frr-interface:interface-ref; + description + "The VxLAN interface name."; + } + leaf mac-count { + type uint32; + description + "Number of valid MACs."; + } + leaf neighbor-count { + type uint32; + description + "Number of neighbors."; + } + leaf vrf { + type string; + description + "The tenant VRF."; + } + leaf local-vtep-addr { + type inet:ipv4-address; + description + "The local VTEP IP address."; + } + } + + /* + * Detailed EVPN VNI information for L2. + */ + grouping vni-l2-detail { + leaf if-index { + type uint32; + description + "The VxLAN ifindex."; + } + leaf advertise-gw { + type empty; + description + "The gateway MAC-IP is being advertised."; + } + leaf mcase-group { + type rt-types:ipv4-multicast-group-address; + description + "The VNI multicast group for BUM traffic."; + } + list remote-vtep-list { + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + leaf vtep-flood { + type vni-vtep-flood-type; + } + } + } + + /* + * Detailed EVPN VNI information for L3. + */ + grouping vni-l3-detail { + leaf svi-interface { + type string; + description + "The SVI interface."; + } + leaf is-up { + type empty; + description + "The state is active."; + } + leaf prefix-only { + type empty; + description + "Prefix routes only"; + } + leaf router-mac { + type yang:mac-address; + description + "The VNI Router MAC address."; + } + list vni-list { + description + "A list of the associated L2 VNIs."; + leaf vni-id { + type vni-id-type; + description + "An L2 VNI identifier."; + } + } + } + + /* + * Debug options + */ + grouping zebra-debugs { + leaf debug-events { + type boolean; + description "Debug ZAPI events."; + } + leaf debug-zapi-send { + type boolean; + description "Debug ZAPI messages sent."; + } + leaf debug-zapi-recv { + type boolean; + description "Debug ZAPI messages received."; + } + leaf debug-zapi-detail { + type boolean; + description "Debug ZAPI details."; + } + leaf debug-kernel { + type boolean; + description "Debug kernel events."; + } + leaf debug-kernel-msg-send { + type boolean; + description "Debug kernel messages sent."; + } + leaf debug-kernel-msg-recv { + type boolean; + description "Debug kernel messages received."; + } + leaf debug-rib { + type boolean; + description "Debug RIB processing."; + } + leaf debug-rib-detail { + type boolean; + description "Debug RIB processing details."; + } + leaf debug-fpm { + type boolean; + description "Debug the FIB Push Interface subsystem."; + } + leaf debug-nht { + type boolean; + description "Debug Nexthop-tracking."; + } + leaf debug-nht-detail { + type boolean; + description "Debug Nexthop-tracking details."; + } + leaf debug-mpls { + type boolean; + description "Debug MPLS."; + } + leaf debug-vxlan { + type boolean; + description "Debug VxLAN."; + } + leaf debug-pw { + type boolean; + description "Debug pseudowires."; + } + leaf debug-dplane { + type boolean; + description "Debug the dataplane subsystem."; + } + leaf debug-dplane-detail { + type boolean; + description "Debug dataplane subsystem details."; + } + leaf debug-mlag { + type boolean; + description "Debug MLAG."; + } + } + + /* + * Main zebra container + */ + container zebra { + description + "Data model for the Zebra daemon."; + + leaf mcast-rpf-lookup { + type frr-zebra:mcast-rpf-lookup-mode; + default "mrib-then-urib"; + description + "Multicast RPF lookup behavior."; + } + + leaf ip-forwarding { + type boolean; + description + "IP forwarding status."; + } + + leaf ipv6-forwarding { + type enumeration { + enum "unknown" { + value -1; + description + "Unknown state."; + } + enum "off" { + value 0; + description + "IPv6 forwarding disabled."; + } + enum "on" { + value 1; + description + "IPv6 forwarding enabled."; + } + } + description + "IPv6 forwarding status."; + } + + leaf workqueue-hold-timer { + type uint32 { + range "0..10000"; + } + units "milliseconds"; + default "10"; + description + "Work-queue processing hold timer, in milliseconds."; + } + + leaf zapi-packets { + type uint32 { + range "1..10000"; + } + default "1000"; + description + "Number of ZAPI packets to process before relinquishing + the main thread."; + } + + container import-kernel-table { + description + "Parameters to use when importing IPv4 routes from a non-main kernel + routing table."; + + leaf table-id { + type uint32 { + range "1..252"; + } + description + "The kernel table id."; + } + leaf distance { + type uint32 { + range "1..255"; + } + default "15"; + description + "The admin distance to use for imported routes."; + } + leaf route-map { + type string; + description + "A route-map to filter imported routes."; + } + } + + leaf allow-external-route-update { + type empty; + description + "Allow FRR-controlled routes to be overwritten by external processes"; + } + + leaf dplane-queue-limit { + type uint32 { + range "0..10000"; + } + default "200"; + description + "Limit on the number of updates queued to the dataplane subsystem."; + } + + list vrf-vni-mapping { + description + "EVPN VNI mapping corresponding to a VRF."; + key "vrf-id"; + leaf vrf-id { + type uint32; + description + "The identifier for a VRF."; + } + leaf vni-id { + type vni-id-type; + description + "The VNI id to map to the VRF."; + } + leaf prefix-only { + type empty; + description + "Prefix routes only."; + } + } + + /* + * Debug options + */ + container debugs { + uses zebra-debugs; + } /* End of debugs */ + + /* + * End of configuration attributes + */ + + /* + * Operational data. + */ + container state { + config false; + description + "Operational data."; + + } // End of operational / state container + + } // End of zebra container + + /* + * RPCs + */ + rpc get-route-information { + description + "Retrieve IPv4 or IPv6 unicast routes."; + + input { + + choice ip-type { + case v4 { + leaf ipv4 { + type empty; + mandatory true; + description + "Retrieve IPv4 routes."; + } + leaf prefix-v4 { + type inet:ipv4-prefix; + description + "Retrieve routes matching a specific prefix."; + } + leaf supernets-only { + type empty; + description + "Skip routes that are subnets of classful prefix sizes."; + } + } + case v6 { + leaf ipv6 { + type empty; + mandatory true; + description + "Retrieve IPv6 routes."; + } + leaf prefix-v6 { + type inet:ipv6-prefix; + description + "Retrieve routes matching a specific prefix."; + } + } + } + + choice vrf-choice { + case single { + leaf vrf { + type string; + description + "Retrieve routes in a non-default vrf."; + } + } + case all { + leaf all-vrfs { + type empty; + description + "Retrieve routes from all vrfs."; + } + } + } + + leaf fib-routes { + type empty; + description + "Retrieve FIB routes rather than RIB routes."; + } + + leaf table-id { + type uint32 { + range "1..4294967295"; + } + description + "Routing table id to retrieve."; + } + + leaf protocol { + type frr-route-types:frr-route-types-v4; + description + "Retrieve routes from a specific protocol daemon."; + } + leaf ospf-instance { + type uint32 { + range "1..65535"; + } + must '../protocol = "ospf"'; + description + "Retrieve routes from a specific OSPF instance."; + } + + choice detail { + case det { + leaf include-detail { + type empty; + description + "Include detailed information."; + } + } + case summ { + leaf summary { + type empty; + description + "Include summary information only."; + } + } + } + } // End of input + + output { + choice route-list { + case v4 { + container routes-v4 { + description + "IPv4 route information."; + list route { + uses ip4-route; + } + } + } + case v6 { + container routes-v6 { + description + "IPv6 route information."; + list route { + uses ip6-route; + } + } + } + } + } // End of output + + } // End get-route-information + + rpc get-v6-mroute-info { + description + "Retrieve IPv6 multicast routes."; + + input { + choice vrf-choice { + case single { + leaf vrf { + type string; + description + "Retrieve routes in a non-default vrf."; + } + } + case all { + leaf all-vrfs { + type empty; + description + "Retrieve routes from all vrfs."; + } + } + } + } + + output { + container routes { + description + "IPv6 mcast route information."; + list route { + uses ip6-route; + } + } + } + + }// End get-v6-mroute-info + + + rpc get-vrf-info { + description + "Retrieve VRF information; the default VRF is elided."; + + // Note: no input clause. + + output { + list vrf-list { + leaf name { + type string; + description + "The VRF name"; + } + leaf is-user-config { + type empty; + description + "The VRF was configured by an admin."; + } + leaf vrf-id { + type uint32; + description + "The VRF id."; + } + choice vrf-type { + case inactive { + leaf is-inactive { + type empty; + description + "The VRF is inactive."; + } + } + case netns { + leaf netns-name { + type string; + description + "The net namespace name associated with the VRF."; + } + } + case table { + leaf table-id { + type uint32; + description + "The table-id associated with the VRF."; + } + } + } + } + } + } // End get-vrf-info + + rpc get-vrf-vni-info { + description + "Retrieve mappings between EVPN VNI and VRF."; + + // Note: no input clause. + + output { + list vrf-vni-list { + leaf vrf-name { + type string; + description + "The VRF name."; + } + leaf vni-id { + type vni-id-type; + description + "The EVPN VNI."; + } + leaf vxlan-if-name { + type frr-interface:interface-ref; + description + "The VxLAN interface name."; + } + leaf svi-if-name { + type frr-interface:interface-ref; + description + "The SVI interface name."; + } + leaf router-mac-addr { + type yang:mac-address; + description + "Router MAC address."; + } + leaf is-up { + type empty; + description + "The state is active."; + } + } + } + } // End get-vrf-vni-info + + rpc get-evpn-info { + description + "Retrieve global information about EVPN."; + + // Note: No input clause. + + output { + leaf l2vni-count { + type uint32; + description + "Number of L2 VNIs."; + } + leaf l3vni-count { + type uint32; + description + "Number of L3 VNIs."; + } + leaf advertise-gateway { + type empty; + description + "Advertise the gateway MAC-IP."; + } + leaf advertise-svi { + type empty; + description + "Advertise SVI MAC-IP."; + } + leaf dup-detect { + type empty; + description + "Duplicate address detection is enabled."; + } + leaf dad-max-moves { + type uint32; + description + "Maximum moves allowed before address is considered duplicate."; + } + leaf dad-timeout { + type uint32; + units "seconds"; + description + "Duplicate address detection timeout."; + } + leaf dad-freeze { + type empty; + description + "Duplicate address detection freeze enabled."; + } + + choice dad-freeze-choice { + case freeze-permanent { + leaf dad-freeze-perm { + type empty; + description + "Duplicate address detection freeze is permanent."; + } + } + case freeze-time { + leaf dad-freeze-time { + type uint32; + units "seconds"; + description + "Duplicate address detection freeze timer."; + } + } + } + } + } // End get-evpn-info + + rpc get-vni-info { + // If no vni is specified, retrieve global list. + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + } + } + leaf detailed-info { + type empty; + description + "Retrieve detailed information."; + } + } + + output { + list vni-list { + description + "Information about EVPN VNI objects."; + + uses vni-information; + + choice detail-choice { + case l2 { + description + "Detailed L2 information."; + uses vni-l2-detail; + } + case l3 { + description + "Detailed L3 information."; + uses vni-l3-detail; + } + } + } + } + } // End get-vni-info + + rpc get-evpn-vni-rmac { + description + "Retrieve information about VxLAN VNI RMACs."; + + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + leaf vni-rmac { + type yang:mac-address; + description + "A single RMAC address."; + } + } + } + } + + output { + list rmac-info-list { + leaf rmac { + type yang:mac-address; + description + "The RMAC address."; + } + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + leaf refcount { + type uint32; + description + "The refcount of the RMAC."; + } + list prefix-list { + leaf prefix-item { + type inet:ip-prefix; + description + "IP prefixes associated with the RMAC."; + } + } + } + } + } // End get-evpn-vni-rmac + + rpc get-evpn-vni-nexthops { + description + "Retrieve information about EVPN nexthops."; + + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + leaf vni-ipaddr { + type inet:ip-address; + description + "A single host IP address (v4 or v6)."; + } + } + } + } + + output { + list nh-info-list { + leaf ip-addr { + type inet:ip-address; + description + "The nexthop IP address."; + } + leaf mac-addr { + type yang:mac-address; + description + "The nexthop MAC address."; + } + leaf refcount { + type uint32; + description + "The refcount of the RMAC."; + } + list prefix-list { + leaf prefix-item { + type inet:ip-prefix; + description + "IP prefixes associated with the RMAC."; + } + } + } + } + } // End get-evpn-vni-vteps + + rpc clear-evpn-dup-addr { + description + "Clear duplicate address detection state for one or all VNIs."; + input { + choice clear-dup-choice { + case all-case { + leaf all-vnis { + type empty; + description + "Clear all VNIs."; + } + } + case single-case { + leaf vni-id { + type vni-id-type; + description + "Clear state for a single EVPN VNI."; + } + choice ip-mac-choice { + description + "Clear state for a specific MAC or IP address."; + case ip-case { + leaf vni-ipaddr { + type inet:ip-address; + description + "A specific IP address (v4 or v6)."; + } + } + case mac-case { + leaf mac-addr { + type yang:mac-address; + description + "A specific MAC address."; + } + } + } + } + } + } + } // End clear-evpn-dup-addr + + rpc get-evpn-macs { + description + "Retrieve information about EVPN MAC addresses."; + input { + choice all-choice { + default "all-vni"; + + case all-vni { + leaf all-vnis { + type empty; + description + "Retrieve information for all VNIs."; + } + choice all-choices { + case detail-case { + leaf all-detail { + type empty; + description + "Include detailed results."; + } + } + case vtep-case { + leaf all-vtep-addr { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case dup-case { + leaf all-dup { + type empty; + description + "Show duplicate addresses."; + } + } + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information for a single VNI."; + } + choice single-choices { + case detail-case { + leaf single-detail { + type empty; + description + "Include detailed results."; + } + } + case mac-case { + leaf single-mac { + type yang:mac-address; + description + "A specific MAC address."; + } + } + case vtep-case { + leaf single-vtep { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case dup-case { + leaf single-dup { + type empty; + description + "Show duplicate addresses."; + } + } + } + } + } + } // End of input section + + output { + list mac-list { + leaf mac-addr { + type yang:mac-address; + description + "The MAC address."; + } + leaf vni { + type vni-id-type; + description + "The VNI value."; + } + leaf local-sequence { + type uint32; + description + "Local sequence number."; + } + leaf remote-sequence { + type uint32; + description + "Remote sequence number."; + } + leaf dad-count { + type uint32; + description + "Duplicate detection counter."; + } + leaf is-duplicate { + type empty; + description + "Duplicate MAC detected."; + } + leaf dup-detect-time { + type unix-timestamp; + description + "If a duplicate, the detection time."; + } + container dup-detect-started { + leaf dup-detect-start { + type unix-timestamp; + description + "Duplicate detection process start time."; + } + leaf dup-count { + type uint32; + description + "Duplicate detection count."; + } + } + + leaf is-auto { + type empty; + description + "This is an Auto MAC."; + } + leaf is-sticky { + type empty; + description + "This is a sticky MAC."; + } + leaf is-default-gw { + type empty; + description + "This is a default-gateway MAC."; + } + leaf is-remote-gw { + type empty; + description + "This is a remote-gateway MAC."; + } + list neighbor-list { + leaf neighbor-addr { + type inet:ip-address; + description + "Neighbor address."; + } + leaf is-active { + type empty; + description + "Neighbor is active."; + } + } + + leaf mac-count { + type uint32; + description + "Number of MACs (local and remote)."; + } + choice local-rem-choice { + case local-case { + leaf intf { + type frr-interface:interface-ref; + description + "The local interface name."; + } + leaf vlan { + type uint32; + description + "A VLAN id."; + } + } + case remote-case { + leaf vtep-addr { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + } + } + } + } + } // End get-evpn-macs + + rpc get-evpn-arp-cache { + description + "Retrieve information about EVPN neighbor cache entries."; + input { + choice all-choice { + default "all-vni"; + + case all-vni { + leaf all-vnis { + type empty; + description + "Retrieve information for all VNIs."; + } + choice all-choices { + case detail-case { + leaf all-detail { + type empty; + description + "Include detailed results."; + } + } + case dup-case { + leaf all-dup { + type empty; + description + "Show duplicates."; + } + } + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information for a single VNI."; + } + choice single-choices { + case vtep-case { + leaf single-vtep { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case neighbor-case { + leaf neighbor-addr { + type inet:ip-address; + description + "A single neighbor address."; + } + } + case dup-case { + leaf single-dup { + type empty; + description + "Show duplicates."; + } + } + } + } + } + } // End input section + + output { + list vni-list { + container vni-container { + description + "Information for one VNI."; + leaf vni-id { + type vni-id-type; + description + "The VNI id."; + } + list neigh-list { + description + "Information about a VNI's neighbor cache."; + + leaf mac-addr { + type yang:mac-address; + description + "A neighbor MAC address."; + } + leaf ip-addr { + type inet:ip-address; + description + "A neighbor IP address."; + } + leaf state-active { + type empty; + description + "Indicates whether the entry is active."; + } + + choice local-remote-choice { + case local-case { + leaf is-local { + type empty; + description + "The entry is local."; + } + } + case remote-case { + leaf is-remote { + type empty; + description + "The entry is remote."; + } + } + } + + leaf is-dup { + type empty; + description + "The entry is a detected duplicate."; + } + leaf is-default-gw { + type empty; + description + "The entry is a default gateway."; + } + leaf is-router { + type empty; + description + "The entry is a router."; + } + leaf local-sequence { + type uint32; + description + "The local sequence number."; + } + leaf remote-sequence { + type uint32; + description + "The remote sequence number."; + } + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP address."; + } + } + } + } + } + } // End get-evpn-arp-cache + + rpc get-pbr-ipset { + input { + leaf name { + type string; + description + "An optional specific IPset name."; + } + } + + output { + list ipset-list { + leaf name { + type string; + description + "The IPset name."; + } + leaf ipset-type { + type enumeration { + enum "net-net" { + value 1; + description + ""; + } + enum "net-port-net" { + value 2; + description + ""; + } + enum "net-port" { + value 3; + description + ""; + } + enum "net" { + value 4; + description + ""; + } + } + } + leaf src-prefix { + type inet:ip-prefix; + description + ""; + } + leaf dest-prefix { + type inet:ip-prefix; + description + ""; + } + leaf src-port { + type inet:port-number; + description + ""; + } + leaf dest-port { + type inet:port-number; + description + ""; + } + + choice proto-choice { + description + "Filter UDP/TCP only, or a specific protocol number."; + case udp-tcp-case { + leaf is-udp-tcp { + type empty; + description + "Filter TCP/UDP ports only."; + } + } + case proto-case { + leaf proto { + type uint32; + description + "Filter a specific protocol number."; + } + } + } + container icmp-info { + description + "Additional information for ICMP filters."; + leaf type-min { + type uint8; + description + ""; + } + leaf type-max { + type uint8; + description + ""; + } + leaf code-min { + type uint8; + description + ""; + } + leaf code-max { + type uint8; + description + ""; + } + } + container ipset-stats { + leaf is-unique { + type empty; + description + ""; + } + leaf packet-counter { + type uint64; + description + ""; + } + leaf bytes-counter { + type uint64; + description + ""; + } + } + } + } + } // End get-pbr-ipset + + rpc get-pbr-iptable { + input { + leaf name { + type string; + description + "An optional single IPtable name."; + } + } + + output { + list iptable-list { + leaf name { + type string; + description + "The IPtable name."; + } + leaf unique-val { + type uint32; + description + ""; + } + choice action-choice { + description "The table action."; + case drop-case { + leaf action-drop { + type empty; + description ""; + } + } + case redirect-case { + leaf action-redirect { + type empty; + description ""; + } + } + } + leaf min-packet { + type uint32; + description + ""; + } + leaf max-packet { + type uint32; + description + ""; + } + leaf lookup-src-port { + type empty; + description + ""; + } + leaf lookup-dst-port { + type empty; + description + ""; + } + leaf tcp-flags { + type uint16; + description + ""; + } + leaf tcp-flags-mask { + type uint16; + description + ""; + } + leaf protocol-val { + type uint32; + description "An IP protocol number."; + } + container dscp-info { + leaf dscp-value { + type uint32; + description + "A DSCP value to match."; + } + leaf invert-match { + type empty; + description + "If set, exclude the specified value"; + } + } + container fragment-info { + leaf fragment-val { + type uint32; + description "An IP fragment value."; + } + leaf invert-match { + type empty; + description + "If set, exclude the specified value."; + } + } + container iptable-stats { + leaf packet-counter { + type uint64; + description + ""; + } + leaf bytes-counter { + type uint64; + description + ""; + } + } + container rule-info { + description + "Information about a rule, for redirect tables."; + leaf table-id { + type uint32; + description + "The rule table id."; + } + leaf table-fwmark { + type uint32; + description + "The firewall mark for the rule."; + } + } + } + } + } // End get-pbr-iptable + + /* + * Handy 'all-at-once' api to retrieve debugs + */ + rpc get-debugs { + output { + uses zebra-debugs; + } + } // End get-debugs + + augment "/frr-interface:lib/frr-interface:interface" { + description + "Extends interface model with Zebra-related parameters."; + container zebra { + list ip4-addr-list { + description + "IPv4 prefixes for an interface."; + key "ip4-prefix"; + leaf ip4-prefix { + type inet:ipv4-prefix; + description + "IPv4 address prefix."; + } + leaf ip4-peer { + type inet:ipv4-prefix; + description + "Peer prefix, for peer-to-peer interfaces."; + } + leaf label { + type string; + description + "Optional string label for the address."; + } + } + list ip6-addr-list { + description + "IPv6 prefixes for an interface."; + key "ip6-prefix"; + leaf ip6-prefix { + type inet:ipv6-prefix; + description + "IPv6 address prefix."; + } + leaf label { + type string; + description + "Optional string label for the address."; + } + } + + leaf multicast { + type boolean; + description + "Multicast flag for the interface."; + } + leaf link-detect { + type boolean; + description + "Link-detection for the interface."; + } + leaf shutdown { + type boolean; + description + "Interface admin status."; + } + leaf bandwidth { + type uint32 { + range "1..100000"; + } + description + "Link bandwidth informational parameter, in megabits."; + } + + // TODO -- link-params for (experimental/partial TE use in IGP extensions) + + } + } // End interface model augmentation + +} diff --git a/yang/libyang_plugins/frr_user_types.c b/yang/libyang_plugins/frr_user_types.c index 4814f5bc1d..48cdceccf4 100644 --- a/yang/libyang_plugins/frr_user_types.c +++ b/yang/libyang_plugins/frr_user_types.c @@ -20,6 +20,7 @@ #include <zebra.h> #include "prefix.h" +#include "ipaddr.h" #include <libyang/user_types.h> @@ -53,6 +54,21 @@ static int ipv6_address_store_clb(const char *type_name, const char *value_str, return 0; } +static int ip_address_store_clb(const char *type_name, const char *value_str, + lyd_val *value, char **err_msg) +{ + value->ptr = malloc(sizeof(struct ipaddr)); + if (!value->ptr) + return 1; + + if (str2ipaddr(value_str, value->ptr)) { + free(value->ptr); + return 1; + } + + return 0; +} + static int ipv4_prefix_store_clb(const char *type_name, const char *value_str, lyd_val *value, char **err_msg) { @@ -83,6 +99,21 @@ static int ipv6_prefix_store_clb(const char *type_name, const char *value_str, return 0; } +static int ip_prefix_store_clb(const char *type_name, const char *value_str, + lyd_val *value, char **err_msg) +{ + value->ptr = malloc(sizeof(struct prefix)); + if (!value->ptr) + return 1; + + if (str2prefix(value_str, value->ptr) == 0) { + free(value->ptr); + return 1; + } + + return 0; +} + struct lytype_plugin_list frr_user_types[] = { {"ietf-inet-types", "2013-07-15", "ipv4-address", ipv4_address_store_clb, free}, @@ -92,9 +123,13 @@ struct lytype_plugin_list frr_user_types[] = { ipv6_address_store_clb, free}, {"ietf-inet-types", "2013-07-15", "ipv6-address-no-zone", ipv6_address_store_clb, free}, + {"ietf-inet-types", "2013-07-15", "ip-address", ip_address_store_clb, + free}, {"ietf-inet-types", "2013-07-15", "ipv4-prefix", ipv4_prefix_store_clb, free}, {"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb, free}, + {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb, + free}, {NULL, NULL, NULL, NULL, NULL} /* terminating item */ }; diff --git a/zebra/connected.c b/zebra/connected.c index 6b92945c63..87cf8c8f20 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -385,7 +385,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) return; break; default: - zlog_info("Unknown AFI: %s", afi2str(afi)); + zlog_warn("Unknown AFI: %s", afi2str(afi)); break; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index c71b95f753..35cb3a6f5f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -365,7 +365,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, } } -static int get_iflink_speed(struct interface *interface) +static int get_iflink_speed(struct interface *interface, int *error) { struct ifreq ifdata; struct ethtool_cmd ecmd; @@ -373,6 +373,8 @@ static int get_iflink_speed(struct interface *interface) int rc; const char *ifname = interface->name; + if (error) + *error = 0; /* initialize struct */ memset(&ifdata, 0, sizeof(ifdata)); @@ -393,6 +395,9 @@ static int get_iflink_speed(struct interface *interface) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Failure to read interface %s speed: %d %s", ifname, errno, safe_strerror(errno)); + /* no vrf socket creation may probably mean vrf issue */ + if (error) + *error = -1; return 0; } /* Get the current link state for the interface */ @@ -404,6 +409,9 @@ static int get_iflink_speed(struct interface *interface) zlog_debug( "IOCTL failure to read interface %s speed: %d %s", ifname, errno, safe_strerror(errno)); + /* no device means interface unreachable */ + if (errno == ENODEV && error) + *error = -1; ecmd.speed_hi = 0; ecmd.speed = 0; } @@ -413,9 +421,9 @@ static int get_iflink_speed(struct interface *interface) return (ecmd.speed_hi << 16) | ecmd.speed; } -uint32_t kernel_get_speed(struct interface *ifp) +uint32_t kernel_get_speed(struct interface *ifp, int *error) { - return get_iflink_speed(ifp); + return get_iflink_speed(ifp, error); } static int netlink_extract_bridge_info(struct rtattr *link_data, @@ -696,7 +704,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; - ifp->speed = get_iflink_speed(ifp); + ifp->speed = get_iflink_speed(ifp, NULL); ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; /* Set zebra interface type */ @@ -1032,7 +1040,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { - zlog_debug("%s: NULL address", __func__); + zlog_debug("%s: Local Interface Address is NULL for %s", + __func__, ifp->name); return -1; } @@ -1376,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) { @@ -1402,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 6486c01430..ef03cf87f6 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -70,10 +70,19 @@ static int if_zebra_speed_update(struct thread *thread) struct zebra_if *zif = ifp->info; uint32_t new_speed; bool changed = false; + int error = 0; zif->speed_update = NULL; - new_speed = kernel_get_speed(ifp); + new_speed = kernel_get_speed(ifp, &error); + + /* error may indicate vrf not available or + * interfaces not available. + * note that loopback & virtual interfaces can return 0 as speed + */ + if (error < 0) + return 1; + if (new_speed != ifp->speed) { zlog_info("%s: %s old speed: %u new speed: %u", __PRETTY_FUNCTION__, ifp->name, ifp->speed, @@ -261,8 +270,10 @@ struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns, for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) { ifp = (struct interface *)rn->info; - if (ifp && strcmp(ifp->name, ifname) == 0) + if (ifp && strcmp(ifp->name, ifname) == 0) { + route_unlock_node(rn); return (ifp); + } } return NULL; @@ -767,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 */ @@ -1556,7 +1574,7 @@ struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1}; #endif /* Show all interfaces to vty. */ DEFPY(show_interface, show_interface_cmd, - "show interface [vrf NAME$name] [brief$brief]", + "show interface [vrf NAME$vrf_name] [brief$brief]", SHOW_STR "Interface status and configuration\n" VRF_CMD_HELP_STR @@ -1568,8 +1586,8 @@ DEFPY(show_interface, show_interface_cmd, interface_update_stats(); - if (name) - VRF_GET_ID(vrf_id, name, false); + if (vrf_name) + VRF_GET_ID(vrf_id, vrf_name, false); /* All interface print. */ vrf = vrf_lookup_by_id(vrf_id); @@ -2034,13 +2052,13 @@ DEFUN (link_params_enable, /* This command could be issue at startup, when activate MPLS TE */ /* on a new interface or after a ON / OFF / ON toggle */ /* In all case, TE parameters are reset to their default factory */ - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: enable TE link parameters on interface %s", ifp->name); if (!if_link_params_get(ifp)) { - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: failed to init TE link parameters %s", ifp->name); @@ -2063,8 +2081,9 @@ DEFUN (no_link_params_enable, { VTY_DECLVAR_CONTEXT(interface, ifp); - zlog_debug("MPLS-TE: disable TE link parameters on interface %s", - ifp->name); + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) + zlog_debug("MPLS-TE: disable TE link parameters on interface %s", + ifp->name); if_link_params_free(ifp); @@ -3195,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/main.c b/zebra/main.c index 657d1247e9..f0225ac5e6 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -36,7 +36,6 @@ #include "vrf.h" #include "libfrr.h" #include "routemap.h" -#include "frr_pthread.h" #include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" @@ -143,6 +142,9 @@ static void sigint(void) zlog_notice("Terminating on signal"); + atomic_store_explicit(&zrouter.in_shutdown, true, + memory_order_relaxed); + frr_early_fini(); zebra_dplane_pre_finish(); @@ -375,9 +377,6 @@ int main(int argc, char **argv) zrouter.master = frr_init(); - /* Initialize pthread library */ - frr_pthread_init(); - /* Zebra related initialize. */ zebra_router_init(); zserv_init(); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 1ae2ba92b0..0dc9de0c59 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -119,7 +119,7 @@ static void zebra_redistribute(struct zserv *client, int type, srcdest_rnode_prefixes(rn, &dst_p, &src_p); - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_RIB) zlog_debug( "%s: client %s %s(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", __func__, @@ -149,7 +149,8 @@ static void zebra_redistribute(struct zserv *client, int type, /* Either advertise a route for redistribution to registered clients or */ /* withdraw redistribution if add cannot be done for client */ void redistribute_update(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re, struct route_entry *prev_re) + const struct route_entry *re, + const struct route_entry *prev_re) { struct listnode *node, *nnode; struct zserv *client; @@ -200,7 +201,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, send_redistribute = 1; if (send_redistribute) { - if (IS_ZEBRA_DEBUG_EVENT) { + if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( "%s: client %s %s(%u), type=%d, distance=%d, metric=%d", __func__, @@ -226,54 +227,102 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, } } +/* + * During a route delete, where 'new_re' is NULL, redist a delete to all + * clients registered for the type of 'old_re'. + * During a route update, redist a delete to any clients who will not see + * an update when the new route is installed. There are cases when a client + * may have seen a redist for 'old_re', but will not see + * the redist for 'new_re'. + */ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re) + const struct route_entry *old_re, + const struct route_entry *new_re) { struct listnode *node, *nnode; struct zserv *client; - char buf[INET6_ADDRSTRLEN]; int afi; + char buf[PREFIX_STRLEN]; + vrf_id_t vrfid; + + if (old_re) + vrfid = old_re->vrf_id; + else if (new_re) + vrfid = new_re->vrf_id; + else + return; if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug("%u:%s/%d: Redist delete re %p (%s)", - re->vrf_id, buf, p->prefixlen, re, - zebra_route_string(re->type)); + zlog_debug( + "%u:%s: Redist del: re %p (%s), new re %p (%s)", + vrfid, prefix2str(p, buf, sizeof(buf)), + old_re, + old_re ? zebra_route_string(old_re->type) : "None", + new_re, + new_re ? zebra_route_string(new_re->type) : "None"); } /* Add DISTANCE_INFINITY check. */ - if (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) { flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, "%s: Unknown AFI/SAFI prefix received\n", - __FUNCTION__); + __func__); return; } + /* Skip invalid (e.g. linklocal) prefix */ if (!zebra_check_addr(p)) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("Redist delete filter prefix %s", - prefix2str(p, buf, sizeof(buf))); + if (IS_ZEBRA_DEBUG_RIB) { + zlog_debug( + "%u:%s: Redist del old: skipping invalid prefix", + vrfid, prefix2str(p, buf, sizeof(buf))); + } return; } for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if ((is_default_prefix(p) - && vrf_bitmap_check(client->redist_default[afi], - re->vrf_id)) - || vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], - re->vrf_id) - || (re->instance - && redist_check_instance( - &client->mi_redist[afi][re->type], - re->instance)) - || vrf_bitmap_check(client->redist[afi][re->type], - re->vrf_id)) { + if (new_re) { + /* Skip this client if it will receive an update for the + * 'new' re + */ + if (is_default_prefix(p) + && vrf_bitmap_check(client->redist_default[afi], + new_re->vrf_id)) + continue; + else if (vrf_bitmap_check( + client->redist[afi][ZEBRA_ROUTE_ALL], + new_re->vrf_id)) + continue; + else if (new_re->instance + && redist_check_instance( + &client->mi_redist[afi][new_re->type], + new_re->instance)) + continue; + else if (vrf_bitmap_check( + client->redist[afi][new_re->type], + new_re->vrf_id)) + continue; + } + + /* Send a delete for the 'old' re to any subscribed client. */ + if (old_re + && (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, re); + client, p, src_p, old_re); } } } diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 30ff6bcd09..2685458f96 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -42,11 +42,19 @@ extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS); extern void redistribute_update(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re, - struct route_entry *prev_re); -extern void redistribute_delete(const struct prefix *p, - const struct prefix *src_p, - struct route_entry *re); + const struct route_entry *re, + const struct route_entry *prev_re); +/* + * During a route delete, where 'new_re' is NULL, redist a delete to all + * clients registered for the type of 'old_re'. + * During a route update, redist a delete to any clients who will not see + * an update when the new route is installed. There are cases when a client + * may have seen a redist for 'old_re', but will not see + * the redist for 'new_re'. + */ +void redistribute_delete(const struct prefix *p, const struct prefix *src_p, + const struct route_entry *old_re, + const struct route_entry *new_re); extern void zebra_interface_up_update(struct interface *); extern void zebra_interface_down_update(struct interface *); diff --git a/zebra/rt.h b/zebra/rt.h index 59b42fed18..f311a6b9d3 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -66,7 +66,7 @@ extern int kernel_interface_set_master(struct interface *master, extern int mpls_kernel_init(void); -extern uint32_t kernel_get_speed(struct interface *ifp); +extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); /* diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5edcf9bb8a..43e44cad16 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1440,6 +1440,7 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1460,6 +1461,8 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); @@ -1930,6 +1933,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1950,6 +1954,8 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6); req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); @@ -2297,6 +2303,7 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, static enum zebra_dplane_result netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2304,13 +2311,7 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) } req; int ret; int dst_alen; - struct zebra_if *zif; - struct interface *br_if; - struct zebra_if *br_zif; int vid_present = 0; - char vid_buf[20]; - struct zebra_ns *zns; - struct interface *ifp; int cmd; struct in_addr vtep_ip; vlanid_t vid; @@ -2320,42 +2321,6 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) else cmd = RTM_DELNEIGH; - /* Locate zebra ns and interface objects from context data */ - zns = zebra_ns_lookup(dplane_ctx_get_ns(ctx)->ns_id); - if (zns == NULL) { - /* Nothing to be done */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - zebra ns unknown", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - dplane_ctx_get_ifname(ctx), - dplane_ctx_get_ifindex(ctx)); - - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ifp = if_lookup_by_index_per_ns(zns, dplane_ctx_get_ifindex(ctx)); - if (ifp == NULL) { - /* Nothing to be done */ - /* Nothing to be done */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - interface unknown", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - dplane_ctx_get_ifname(ctx), - dplane_ctx_get_ifindex(ctx)); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - vid = dplane_ctx_mac_get_vlan(ctx); - - zif = ifp->info; - if ((br_if = zif->brslave_info.br_if) == NULL) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - ifp->name, ifp->ifindex); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); @@ -2372,26 +2337,35 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) else req.ndm.ndm_flags |= NTF_EXT_LEARNED; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, dplane_ctx_mac_get_addr(ctx), 6); - req.ndm.ndm_ifindex = ifp->ifindex; + req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); dst_alen = 4; // TODO: hardcoded vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx)); addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen); - br_zif = (struct zebra_if *)br_if->info; - if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) { + vid = dplane_ctx_mac_get_vlan(ctx); + + if (vid > 0) { addattr16(&req.n, sizeof(req), NDA_VLAN, vid); vid_present = 1; - sprintf(vid_buf, " VLAN %u", vid); } - addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + addattr32(&req.n, sizeof(req), NDA_MASTER, + dplane_ctx_mac_get_br_ifindex(ctx)); if (IS_ZEBRA_DEBUG_KERNEL) { char ipbuf[PREFIX_STRLEN]; char buf[ETHER_ADDR_STRLEN]; char dst_buf[PREFIX_STRLEN + 10]; + char vid_buf[20]; + + if (vid_present) + snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid); + else + vid_buf[0] = '\0'; inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf)); snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf); @@ -2399,8 +2373,9 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s", nl_msg_type_to_str(cmd), - nl_family_to_str(req.ndm.ndm_family), ifp->name, - ifp->ifindex, vid_present ? vid_buf : "", + nl_family_to_str(req.ndm.ndm_family), + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx), vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", buf, dst_buf); } @@ -2782,6 +2757,7 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2816,6 +2792,8 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_type = RTN_UNICAST; req.ndm.ndm_flags = flags; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); if (mac) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index dc0f29bdbc..981ef7a889 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -396,7 +396,7 @@ extern int kernel_interface_set_master(struct interface *master, return 0; } -uint32_t kernel_get_speed(struct interface *ifp) +uint32_t kernel_get_speed(struct interface *ifp, int *error) { return ifp->speed; } 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/rule_netlink.c b/zebra/rule_netlink.c index 8cc5b52b34..711c4e0877 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -54,6 +54,7 @@ */ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) { + uint8_t protocol = RTPROT_ZEBRA; int family; int bytelen; struct { @@ -78,6 +79,9 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) req.frh.family = family; req.frh.action = FR_ACT_TO_TBL; + addattr_l(&req.n, sizeof(req), + FRA_PROTOCOL, &protocol, sizeof(protocol)); + /* rule's pref # */ addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 6c9fff03ef..5820032902 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -516,7 +516,8 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) int zsend_redistribute_route(int cmd, struct zserv *client, const struct prefix *p, - const struct prefix *src_p, struct route_entry *re) + const struct prefix *src_p, + const struct route_entry *re) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -1424,7 +1425,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re->flags = api.flags; re->uptime = monotime(NULL); re->vrf_id = vrf_id; - if (api.tableid && vrf_id == VRF_DEFAULT) + if (api.tableid) re->table = api.tableid; else re->table = zvrf->table_id; @@ -1623,7 +1624,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; - if (api.vrf_id == VRF_DEFAULT && api.tableid != 0) + if (api.tableid) table_id = api.tableid; else table_id = zvrf->table_id; @@ -1749,88 +1750,146 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); } -static void zread_mpls_labels(ZAPI_HANDLER_ARGS) +/* + * Handle request to create an MPLS LSP. + * + * A single message can fully specify an LSP with multiple nexthops. + * + * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is + * updated to use the received label(s). + */ +static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) { struct stream *s; - enum lsp_types_t type; - struct prefix prefix; - enum nexthop_types_t gtype; - union g_addr gate; - ifindex_t ifindex; - mpls_label_t in_label, out_label; - uint8_t distance; + struct zapi_labels zl; /* Get input stream. */ s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); + return; + } - /* Get data. */ - STREAM_GETC(s, type); - STREAM_GETL(s, prefix.family); - switch (prefix.family) { - case AF_INET: - STREAM_GET(&prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); - STREAM_GETC(s, prefix.prefixlen); - if (prefix.prefixlen > IPV4_MAX_BITLEN) { - zlog_debug( - "%s: Specified prefix length %d is greater than a v4 address can support", - __PRETTY_FUNCTION__, prefix.prefixlen); - return; - } - STREAM_GET(&gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN); - break; - case AF_INET6: - STREAM_GET(&prefix.u.prefix6, s, 16); - STREAM_GETC(s, prefix.prefixlen); - if (prefix.prefixlen > IPV6_MAX_BITLEN) { - zlog_debug( - "%s: Specified prefix length %d is greater than a v6 address can support", - __PRETTY_FUNCTION__, prefix.prefixlen); - return; - } - STREAM_GET(&gate.ipv6, s, 16); - break; - default: - zlog_debug("%s: Specified AF %d is not supported for this call", - __PRETTY_FUNCTION__, prefix.family); + if (!mpls_enabled) return; + + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + znh->type, &znh->address, znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, + znh->type, &znh->address, znh->ifindex, + zl.route.type, zl.route.instance, + znh->label); } - STREAM_GETL(s, ifindex); - STREAM_GETC(s, distance); - STREAM_GETL(s, in_label); - STREAM_GETL(s, out_label); +} - switch (prefix.family) { - case AF_INET: - if (ifindex) - gtype = NEXTHOP_TYPE_IPV4_IFINDEX; - else - gtype = NEXTHOP_TYPE_IPV4; - break; - case AF_INET6: - if (ifindex) - gtype = NEXTHOP_TYPE_IPV6_IFINDEX; - else - gtype = NEXTHOP_TYPE_IPV6; - break; - default: +/* + * Handle request to delete an MPLS LSP. + * + * An LSP is identified by its type and local label. When the received message + * doesn't contain any nexthop, the whole LSP is deleted. Otherwise, only the + * listed LSP nexthops (aka NHLFEs) are deleted. + * + * When the optional ZAPI_LABELS_FTN flag is set, the labels of the specified + * FEC (route) nexthops are deleted. + */ +static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_labels zl; + + /* Get input stream. */ + s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); return; } if (!mpls_enabled) return; - if (hdr->command == ZEBRA_MPLS_LABELS_ADD) { - mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, - ifindex); - mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, - distance, out_label); - } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) { - mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); - mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, - distance, out_label); + if (zl.nexthop_num > 0) { + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_uninstall(zvrf, zl.type, zl.local_label, + znh->type, &znh->address, + znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_update(0, zvrf, zl.type, + &zl.route.prefix, znh->type, + &znh->address, znh->ifindex, + zl.route.type, + zl.route.instance, znh->label); + } + } else { + mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix, + zl.route.type, zl.route.instance); + } +} + +/* + * Handle request to add an MPLS LSP or change an existing one. + * + * A single message can fully specify an LSP with multiple nexthops. + * + * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is + * updated to use the received label(s). + * + * NOTE: zebra will use route replace semantics (make-before-break) to update + * the LSP in the forwarding plane if that's supported by the underlying + * platform. + */ +static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_labels zl; + + /* Get input stream. */ + s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); + return; + } + + if (!mpls_enabled) + return; + + mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label); + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix, + zl.route.type, zl.route.instance); + + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + znh->type, &znh->address, znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) { + mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, + znh->type, &znh->address, znh->ifindex, + zl.route.type, zl.route.instance, + znh->label); + } } -stream_failure: - return; } /* Send response to a table manager connect request to client */ @@ -2455,8 +2514,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_INTERFACE_ENABLE_RADV] = NULL, [ZEBRA_INTERFACE_DISABLE_RADV] = NULL, #endif - [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels, - [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels, + [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add, + [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete, + [ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace, [ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats, [ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request, [ZEBRA_LABEL_MANAGER_CONNECT_ASYNC] = zread_label_manager_request, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 884edfef04..996a255ff4 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -65,7 +65,8 @@ extern int zsend_interface_update(int cmd, struct zserv *client, extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct prefix *p, const struct prefix *src_p, - struct route_entry *re); + const struct route_entry *re); + extern int zsend_router_id_update(struct zserv *zclient, struct prefix *p, vrf_id_t vrf_id); extern int zsend_interface_vrf_update(struct zserv *zclient, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 2bf541617c..bf343e06e5 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -152,6 +152,7 @@ struct dplane_intf_info { */ struct dplane_mac_info { vlanid_t vid; + ifindex_t br_ifindex; struct ethaddr mac; struct in_addr vtep_ip; bool is_sticky; @@ -377,6 +378,7 @@ static enum zebra_dplane_result intf_addr_update_internal( enum dplane_op_e op); static enum zebra_dplane_result mac_update_internal( enum dplane_op_e op, const struct interface *ifp, + const struct interface *br_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, bool sticky); static enum zebra_dplane_result neigh_update_internal( @@ -1272,6 +1274,12 @@ const struct in_addr *dplane_ctx_mac_get_vtep_ip( return &(ctx->u.macinfo.vtep_ip); } +ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.macinfo.br_ifindex; +} + /* Accessors for neighbor information */ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( const struct zebra_dplane_ctx *ctx) @@ -2134,6 +2142,7 @@ static enum zebra_dplane_result intf_addr_update_internal( * Enqueue vxlan/evpn mac add (or update). */ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, @@ -2142,8 +2151,8 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, enum zebra_dplane_result result; /* Use common helper api */ - result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, vid, - mac, vtep_ip, sticky); + result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, + vid, mac, vtep_ip, sticky); return result; } @@ -2151,6 +2160,7 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, * Enqueue vxlan/evpn mac delete. */ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip) @@ -2158,8 +2168,8 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, enum zebra_dplane_result result; /* Use common helper api */ - result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, vid, mac, - vtep_ip, false); + result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, + vid, mac, vtep_ip, false); return result; } @@ -2169,6 +2179,7 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, static enum zebra_dplane_result mac_update_internal(enum dplane_op_e op, const struct interface *ifp, + const struct interface *br_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, @@ -2204,6 +2215,7 @@ mac_update_internal(enum dplane_op_e op, /* Init the mac-specific data area */ memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo)); + ctx->u.macinfo.br_ifindex = br_ifp->ifindex; ctx->u.macinfo.vtep_ip = vtep_ip; ctx->u.macinfo.mac = *mac; ctx->u.macinfo.vid = vid; @@ -2499,6 +2511,18 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed) } /* + * Helper for 'show run' etc. + */ +int dplane_config_write_helper(struct vty *vty) +{ + if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED) + vty_out(vty, "zebra dplane limit %u\n", + zdplane_info.dg_max_queued_updates); + + return 0; +} + +/* * Provider registration */ int dplane_provider_register(const char *name, diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 31f0fc98b3..be945632c1 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -328,6 +328,7 @@ const struct ethaddr *dplane_ctx_mac_get_addr( const struct zebra_dplane_ctx *ctx); const struct in_addr *dplane_ctx_mac_get_vtep_ip( const struct zebra_dplane_ctx *ctx); +ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx); /* Accessors for neighbor information */ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( @@ -402,12 +403,14 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp, * Enqueue evpn mac operations for the dataplane. */ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, bool sticky); enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip); @@ -452,6 +455,7 @@ uint32_t dplane_get_in_queue_len(void); */ int dplane_show_helper(struct vty *vty, bool detailed); int dplane_show_provs_helper(struct vty *vty, bool detailed); +int dplane_config_write_helper(struct vty *vty); /* * Dataplane providers: modules that process or consume dataplane events. diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 4144c0afe0..5d88d4eeb4 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -711,7 +711,6 @@ static void zfpm_connection_down(const char *detail) * Start thread to clean up state after the connection goes down. */ assert(!zfpm_g->t_conn_down); - zfpm_debug("Starting conn_down thread"); zfpm_rnodes_iter_init(&zfpm_g->t_conn_down_state.iter); zfpm_g->t_conn_down = NULL; thread_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, @@ -806,8 +805,6 @@ static int zfpm_read_cb(struct thread *thread) goto done; } - zfpm_debug("Read out a full fpm message"); - /* * Just throw it away for now. */ @@ -1249,7 +1246,7 @@ static int zfpm_connect_cb(struct thread *t) sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - zfpm_debug("Failed to create socket for connect(): %s", + zlog_err("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; return 0; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 5214f1f22d..8088ec1bfe 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -34,6 +34,7 @@ #include "routemap.h" #include "stream.h" #include "nexthop.h" +#include "termtable.h" #include "lib/json.h" #include "zebra/rib.h" @@ -124,6 +125,9 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, static int snhlfe_del(zebra_snhlfe_t *snhlfe); static int snhlfe_del_all(zebra_slsp_t *slsp); static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); +static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt); +static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, + int afi, enum lsp_types_t lsp_type); /* Static functions */ @@ -1111,6 +1115,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size) inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size); break; case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size); break; case NEXTHOP_TYPE_IFINDEX: @@ -2294,6 +2299,42 @@ static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client) return 0; } +struct lsp_uninstall_args { + struct hash *lsp_table; + enum lsp_types_t type; +}; + +/* + * Cleanup MPLS labels registered by this client. + */ +static int zebra_mpls_cleanup_zclient_labels(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + struct lsp_uninstall_args args; + + zvrf = vrf->info; + if (!zvrf) + continue; + + /* Cleanup LSPs. */ + args.lsp_table = zvrf->lsp_table; + args.type = lsp_type_from_re_type(client->proto); + hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type, + &args); + + /* Cleanup FTNs. */ + mpls_ftn_uninstall_all(zvrf, AFI_IP, + lsp_type_from_re_type(client->proto)); + mpls_ftn_uninstall_all(zvrf, AFI_IP6, + lsp_type_from_re_type(client->proto)); + } + + return 0; +} + /* * Return FEC (if any) to which this label is bound. * Note: Only works for per-prefix binding and when the label is not @@ -2542,8 +2583,8 @@ static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, */ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct prefix *prefix, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, uint8_t distance, - mpls_label_t out_label) + union g_addr *gate, ifindex_t ifindex, uint8_t route_type, + unsigned short route_instance, mpls_label_t out_label) { struct route_table *table; struct route_node *rn; @@ -2562,7 +2603,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, RNODE_FOREACH_RE (rn, re) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) continue; - if (re->distance == distance) + if (re->type == route_type && re->instance == route_instance) break; } @@ -2617,6 +2658,42 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, return 0; } +int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + unsigned short route_instance) +{ + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + struct nexthop *nexthop; + + /* Lookup table. */ + table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, + zvrf_id(zvrf)); + if (!table) + return -1; + + /* Lookup existing route */ + rn = route_node_get(table, prefix); + RNODE_FOREACH_RE (rn, re) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + if (re->type == route_type && re->instance == route_instance) + break; + } + if (re == NULL) + return -1; + + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) + nexthop_del_labels(nexthop); + + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + rib_queue_add(rn); + + return 0; +} + /* * Install/update a NHLFE for an LSP in the forwarding table. This may be * a new LSP entry or a new NHLFE for an existing in-label or an update of @@ -2749,12 +2826,34 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, return 0; } +int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* If entry is not present, exit. */ + tmp_ile.in_label = in_label; + lsp = hash_lookup(lsp_table, &tmp_ile); + if (!lsp) + return 0; + + return mpls_lsp_uninstall_all(lsp_table, lsp, type); +} + /* - * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. + * Uninstall all NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) +static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt) { + struct lsp_uninstall_args *args = ctxt; zebra_lsp_t *lsp; struct hash *lsp_table; @@ -2762,17 +2861,19 @@ void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) if (!lsp->nhlfe_list) return; - lsp_table = ctxt; + lsp_table = args->lsp_table; if (!lsp_table) return; - mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP); + mpls_lsp_uninstall_all(lsp_table, lsp, args->type); } /* - * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. + * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and + * LSP type. */ -void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) +static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, + int afi, enum lsp_types_t lsp_type) { struct route_table *table; struct route_node *rn; @@ -2790,7 +2891,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) RNODE_FOREACH_RE (rn, re) { for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { - if (nexthop->nh_label_type != ZEBRA_LSP_LDP) + if (nexthop->nh_label_type != lsp_type) continue; nexthop_del_labels(nexthop); @@ -3047,7 +3148,6 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, json_object *json = NULL; zebra_lsp_t *lsp = NULL; zebra_nhlfe_t *nhlfe = NULL; - struct nexthop *nexthop = NULL; struct listnode *node = NULL; struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp); @@ -3063,15 +3163,23 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } else { - vty_out(vty, " Inbound Outbound\n"); - vty_out(vty, " Label Type Nexthop Label\n"); - vty_out(vty, "-------- ------- --------------- --------\n"); + struct ttable *tt; + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) { for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { - vty_out(vty, "%8d %7s ", lsp->ile.in_label, - nhlfe_type2str(nhlfe->type)); + struct nexthop *nexthop; + const char *out_label_str; + char nh_buf[NEXTHOP_STRLEN]; + nexthop = nhlfe->nexthop; switch (nexthop->type) { @@ -3081,45 +3189,47 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, zns = zebra_ns_lookup(NS_DEFAULT); ifp = if_lookup_by_index_per_ns( - zns, - nexthop->ifindex); - if (ifp) - vty_out(vty, "%15s", ifp->name); - else - vty_out(vty, "%15s", "Null"); - + zns, nexthop->ifindex); + snprintf(nh_buf, sizeof(nh_buf), "%s", + ifp ? ifp->name : "Null"); break; } case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, "%15s", - inet_ntoa(nexthop->gate.ipv4)); + inet_ntop(AF_INET, &nexthop->gate.ipv4, + nh_buf, sizeof(nh_buf)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, "%15s", - inet_ntop(AF_INET6, - &nexthop->gate.ipv6, - buf, BUFSIZ)); + inet_ntop(AF_INET6, &nexthop->gate.ipv6, + nh_buf, sizeof(nh_buf)); break; default: break; } if (nexthop->type != NEXTHOP_TYPE_IFINDEX) - vty_out(vty, " %8s\n", - mpls_label2str( - nexthop->nh_label - ->num_labels, - &nexthop->nh_label - ->label[0], - buf, BUFSIZ, 1)); + out_label_str = mpls_label2str( + nexthop->nh_label->num_labels, + &nexthop->nh_label->label[0], + buf, BUFSIZ, 1); else - vty_out(vty, "\n"); + out_label_str = "-"; + + ttable_add_row(tt, "%u|%s|%s|%s", + lsp->ile.in_label, + nhlfe_type2str(nhlfe->type), + nh_buf, out_label_str); } } - vty_out(vty, "\n"); + /* Dump the generated table. */ + if (tt->nrows > 1) { + char *table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } + ttable_del(tt); } list_delete(&lsp_list); @@ -3289,4 +3399,5 @@ void zebra_mpls_init(void) mpls_enabled = 1; hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); + hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels); } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index d983221cb5..157f43ca98 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -269,8 +269,15 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, */ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct prefix *prefix, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, uint8_t distance, - mpls_label_t out_label); + union g_addr *gate, ifindex_t ifindex, uint8_t route_type, + unsigned short route_instance, mpls_label_t out_label); + +/* + * Uninstall all NHLFEs bound to a single FEC. + */ +int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + unsigned short route_instance); /* * Install/update a NHLFE for an LSP in the forwarding table. This may be @@ -291,15 +298,10 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, union g_addr *gate, ifindex_t ifindex); /* - * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. - * If no other NHLFEs exist, the entry would be deleted. - */ -void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); - -/* - * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. + * Uninstall all NHLFEs for a particular LSP forwarding entry. */ -void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi); +int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label); /* * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry. @@ -426,7 +428,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type) return (route_distance(ZEBRA_ROUTE_BGP)); case ZEBRA_LSP_NONE: case ZEBRA_LSP_SHARP: - case ZEBRA_LSP_SR: + case ZEBRA_LSP_OSPF_SR: return 150; } @@ -448,8 +450,12 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type) switch (re_type) { case ZEBRA_ROUTE_STATIC: return ZEBRA_LSP_STATIC; + case ZEBRA_ROUTE_LDP: + return ZEBRA_LSP_LDP; case ZEBRA_ROUTE_BGP: return ZEBRA_LSP_BGP; + case ZEBRA_ROUTE_OSPF: + return ZEBRA_LSP_OSPF_SR; case ZEBRA_ROUTE_SHARP: return ZEBRA_LSP_SHARP; default: @@ -469,7 +475,7 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type) return ZEBRA_ROUTE_LDP; case ZEBRA_LSP_BGP: return ZEBRA_ROUTE_BGP; - case ZEBRA_LSP_SR: + case ZEBRA_LSP_OSPF_SR: return ZEBRA_ROUTE_OSPF; case ZEBRA_LSP_NONE: return ZEBRA_ROUTE_KERNEL; @@ -496,8 +502,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type) return "LDP"; case ZEBRA_LSP_BGP: return "BGP"; - case ZEBRA_LSP_SR: - return "SR"; + case ZEBRA_LSP_OSPF_SR: + return "SR (OSPF)"; case ZEBRA_LSP_SHARP: return "SHARP"; case ZEBRA_LSP_NONE: diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ee2956d3ea..35df02a19a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -122,6 +122,33 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, _nexthop_add(&nexthop->resolved, resolved_hop); } +/* Checks if nexthop we are trying to resolve to is valid */ +static bool nexthop_valid_resolve(const struct nexthop *nexthop, + const struct nexthop *resolved) +{ + /* Can't resolve to a recursive nexthop */ + if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE)) + return false; + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* If the nexthop we are resolving to does not match the + * ifindex for the nexthop the route wanted, its not valid. + */ + if (nexthop->ifindex != resolved->ifindex) + return false; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + break; + } + + return true; +} + /* * Given a nexthop we need to properly recursively resolve * the route. As such, do a table lookup to find and match @@ -287,8 +314,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_RECURSIVE)) + if (!nexthop_valid_resolve(nexthop, newhop)) continue; SET_FLAG(nexthop->flags, @@ -308,8 +334,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_RECURSIVE)) + if (!nexthop_valid_resolve(nexthop, newhop)) continue; SET_FLAG(nexthop->flags, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 157c67fa62..4a726b3e07 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -691,7 +691,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) srcdest_rnode_prefixes(rn, &p, &src_p); - redistribute_delete(p, src_p, re); + redistribute_delete(p, src_p, re, NULL); UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); } } @@ -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; } @@ -1248,8 +1252,17 @@ static void rib_process(struct route_node *rn) SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED); if (old_selected) { - if (!new_selected) - redistribute_delete(p, src_p, old_selected); + /* + * If we're removing the old entry, we should tell + * redist subscribers about that *if* they aren't + * going to see a redist for the new entry. + */ + if (!new_selected || CHECK_FLAG(old_selected->status, + ROUTE_ENTRY_REMOVED)) + redistribute_delete(p, src_p, + old_selected, + new_selected); + if (old_selected != new_selected) UNSET_FLAG(old_selected->flags, ZEBRA_FLAG_SELECTED); @@ -1547,7 +1560,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, changed_p = true; UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - break; + + /* Keep checking nexthops */ + continue; } if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) { @@ -1983,6 +1998,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) * not-installed; or not-installed to installed. */ if (start_count > 0 && end_count > 0) { + if (debug_p) + zlog_debug("%u:%s applied nexthop changes from dplane notification", + dplane_ctx_get_vrf(ctx), dest_str); /* Changed nexthops - update kernel/others */ dplane_route_notif_update(rn, re, @@ -2026,7 +2044,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx); /* Redistribute, lsp, and nht update */ - redistribute_delete(dest_pfx, src_pfx, re); + redistribute_delete(dest_pfx, src_pfx, re, NULL); zebra_rib_evaluate_rn_nexthops( rn, zebra_router_get_next_sequence()); @@ -2088,14 +2106,6 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) return 1; } - -/* - * Perform next-hop tracking processing after RIB updates. - */ -static void do_nht_processing(void) -{ -} - /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and * data @@ -3198,6 +3208,7 @@ static int rib_process_dplane_results(struct thread *thread) { struct zebra_dplane_ctx *ctx; struct dplane_ctx_q ctxlist; + bool shut_p = false; /* Dequeue a list of completed updates with one lock/unlock cycle */ @@ -3217,6 +3228,21 @@ static int rib_process_dplane_results(struct thread *thread) if (ctx == NULL) break; + /* If zebra is shutting down, avoid processing results, + * just drain the results queue. + */ + shut_p = atomic_load_explicit(&zrouter.in_shutdown, + memory_order_relaxed); + if (shut_p) { + while (ctx) { + dplane_ctx_fini(&ctx); + + ctx = dplane_ctx_dequeue(&ctxlist); + } + + continue; + } + while (ctx) { switch (dplane_ctx_get_op(ctx)) { case DPLANE_OP_ROUTE_INSTALL: @@ -3294,9 +3320,6 @@ static int rib_process_dplane_results(struct thread *thread) } while (1); - /* Check for nexthop tracking processing after finishing with results */ - do_nht_processing(); - return 0; } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 666ebb70e8..5df5d94f4b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -337,7 +337,7 @@ static void addr2hostprefix(int af, const union g_addr *addr, break; default: memset(prefix, 0, sizeof(*prefix)); - zlog_debug("%s: unknown address family %d", __func__, af); + zlog_warn("%s: unknown address family %d", __func__, af); break; } } @@ -916,7 +916,8 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, table = get_rnh_table(vrfid, afi, type); if (!table) { - zlog_debug("print_rnhs: rnh table not found"); + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("print_rnhs: rnh table not found"); return; } @@ -1198,13 +1199,6 @@ static int zebra_client_cleanup_rnh(struct zserv *client) RNH_IMPORT_CHECK_TYPE); zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, RNH_IMPORT_CHECK_TYPE); - if (client->proto == ZEBRA_ROUTE_LDP) { - hash_iterate(zvrf->lsp_table, - mpls_ldp_lsp_uninstall_all, - zvrf->lsp_table); - mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP); - mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP6); - } } } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 88d2091394..364f5755d8 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -78,11 +78,6 @@ static int zebra_route_match_add(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ @@ -116,7 +111,7 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); } - ret = route_map_delete_match(index, command, arg); + ret = route_map_delete_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% Zebra Can't find rule.\n"); @@ -127,10 +122,6 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index a12e34a495..1f80561986 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -104,6 +104,8 @@ struct zebra_mlag_info { }; struct zebra_router { + atomic_bool in_shutdown; + /* Thread master */ struct thread_master *master; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 72d0b6866d..f425c0e49e 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -92,7 +92,7 @@ static int zebra_vrf_new(struct vrf *vrf) struct zebra_vrf *zvrf; if (IS_ZEBRA_DEBUG_EVENT) - zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id); + zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id); zvrf = zebra_vrf_alloc(); vrf->info = zvrf; @@ -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"); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 38de01e228..5ce9d3f293 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -394,6 +394,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + struct vrf *vrf = NULL; rib_dest_t *dest = rib_dest_from_rnode(rn); struct nexthop_group *nhg; @@ -422,9 +423,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "instance", re->instance); - if (re->vrf_id) + if (re->vrf_id) { json_object_int_add(json_route, "vrfId", re->vrf_id); + vrf = vrf_lookup_by_id(re->vrf_id); + json_object_string_add(json_route, "vrfName", + vrf->name); + } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); @@ -565,9 +570,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if ((nexthop->vrf_id != re->vrf_id) && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { - struct vrf *vrf = - vrf_lookup_by_id(nexthop->vrf_id); - + vrf = vrf_lookup_by_id(nexthop->vrf_id); json_object_string_add(json_nexthop, "vrf", vrf->name); } @@ -1384,35 +1387,37 @@ DEFPY (show_route_detail, DEFPY (show_route_summary, show_route_summary_cmd, - "show\ - <\ - ip$ipv4 route [vrf <NAME$vrf_name|all$vrf_all>]\ - summary [prefix$prefix]\ - |ipv6$ipv6 route [vrf <NAME$vrf_name|all$vrf_all>]\ - summary [prefix$prefix]\ - >", + "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] \ + summary [table (1-4294967295)$table_id] [prefix$prefix]", SHOW_STR IP_STR - "IP routing table\n" - VRF_FULL_CMD_HELP_STR - "Summary of all routes\n" - "Prefix routes\n" IP6_STR "IP routing table\n" VRF_FULL_CMD_HELP_STR "Summary of all routes\n" + "Table to display summary for\n" + "The table number\n" "Prefix routes\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct route_table *table; + if (table_id == 0) + table_id = RT_TABLE_MAIN; + if (vrf_all) { struct vrf *vrf; struct zebra_vrf *zvrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if ((zvrf = vrf->info) == NULL - || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL) + if ((zvrf = vrf->info) == NULL) + continue; + + table = zebra_vrf_table_with_table_id(afi, + SAFI_UNICAST, + zvrf->vrf->vrf_id, + table_id); + if (!table) continue; if (prefix) @@ -1426,7 +1431,9 @@ DEFPY (show_route_summary, if (vrf_name) VRF_GET_ID(vrf_id, vrf_name, false); - table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); + table = zebra_vrf_table_with_table_id(afi, + SAFI_UNICAST, + vrf_id, table_id); if (!table) return CMD_SUCCESS; @@ -2651,6 +2658,10 @@ static int config_write_protocol(struct vty *vty) == MCAST_MIX_DISTANCE ? "lower-distance" : "longer-prefix"); + + /* Include dataplane info */ + dplane_config_write_helper(vty); + return 1; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index bb8b61e7e3..2417b505ad 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2553,8 +2553,9 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) return 0; if (!zvni->vxlan_if) { - zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); return -1; } @@ -2843,9 +2844,12 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, /* mac entry should be present */ mac = zvni_mac_lookup(zvni, &n->emac); if (!mac) { - zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", - prefix_mac2str(&n->emac, buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", + prefix_mac2str(&n->emac, + buf1, sizeof(buf1)), + ipaddr2str(ip, buf2, sizeof(buf2)), + zvni->vni); return -1; } @@ -3736,10 +3740,12 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) */ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + const struct zebra_if *zif, *br_zif; + const struct zebra_l2info_vxlan *vxl; bool sticky; enum zebra_dplane_result res; + const struct interface *br_ifp; + vlanid_t vid; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -3747,13 +3753,25 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) zif = zvni->vxlan_if->info; if (!zif) return -1; + + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; sticky = !!CHECK_FLAG(mac->flags, (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); - res = dplane_mac_add(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, - mac->fwd_info.r_vtep_ip, sticky); + br_zif = (const struct zebra_if *)(br_ifp->info); + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_add(zvni->vxlan_if, br_ifp, vid, + &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -3765,30 +3783,44 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) */ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + const struct zebra_if *zif, *br_zif; + const struct zebra_l2info_vxlan *vxl; struct in_addr vtep_ip; - struct interface *ifp; + const struct interface *ifp, *br_ifp; + vlanid_t vid; enum zebra_dplane_result res; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; if (!zvni->vxlan_if) { - zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); return -1; } zif = zvni->vxlan_if->info; if (!zif) return -1; + + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; + br_zif = (const struct zebra_if *)br_ifp->info; + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + ifp = zvni->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - res = dplane_mac_del(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); + res = dplane_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -4491,9 +4523,11 @@ static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) */ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; + const struct zebra_if *zif = NULL, *br_zif = NULL; + const struct zebra_l2info_vxlan *vxl = NULL; + const struct interface *br_ifp; enum zebra_dplane_result res; + vlanid_t vid; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) @@ -4503,9 +4537,20 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) if (!zif) return -1; + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; - res = dplane_mac_add(zl3vni->vxlan_if, vxl->access_vlan, + br_zif = (const struct zebra_if *)br_ifp->info; + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_add(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; @@ -4519,8 +4564,10 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { char buf[ETHER_ADDR_STRLEN]; - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; + const struct zebra_if *zif = NULL, *br_zif; + const struct zebra_l2info_vxlan *vxl = NULL; + const struct interface *br_ifp; + vlanid_t vid; enum zebra_dplane_result res; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) @@ -4528,10 +4575,12 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) return 0; if (!zl3vni->vxlan_if) { - zlog_debug( - "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", - prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), - zl3vni->vni, zl3vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", + prefix_mac2str(&zrmac->macaddr, + buf, sizeof(buf)), + zl3vni->vni, zl3vni); return -1; } @@ -4539,9 +4588,19 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) if (!zif) return -1; + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; - res = dplane_mac_del(zl3vni->vxlan_if, vxl->access_vlan, + br_zif = (const struct zebra_if *)br_ifp->info; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_del(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; @@ -9094,6 +9153,11 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) if (zvni->advertise_svi_macip == advertise) return; + /* Store flag even though SVI is not present. + * Once SVI comes up triggers self MAC-IP route add. + */ + zvni->advertise_svi_macip = advertise; + ifp = zvni->vxlan_if; if (!ifp) return; @@ -9105,20 +9169,17 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) return; zl2_info = zif->l2info.vxl; - vlan_if = zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); if (!vlan_if) return; if (advertise) { - zvni->advertise_svi_macip = advertise; /* Add primary SVI MAC-IP */ zvni_add_macip_for_intf(vlan_if, zvni); } else { - /* Del primary MAC-IP */ + /* Del primary SVI MAC-IP */ zvni_del_macip_for_intf(vlan_if, zvni); - zvni->advertise_svi_macip = advertise; } } |
