diff options
169 files changed, 4057 insertions, 2828 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/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..5663ce54cb 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -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..ae6d04e77d 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] && diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e21c84355e..248bbca8cf 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -519,8 +519,7 @@ 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); return key; } @@ -562,7 +561,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 +724,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 +781,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 +792,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; @@ -1647,8 +1685,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 +1702,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 +1713,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 +1722,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 +1754,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 +1771,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 +1789,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 +1801,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 +1831,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 +2044,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..cfa428a796 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -206,6 +206,9 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; + + /* Distance as applied by Route map */ + uint8_t distance; }; /* rmap_change_flags definition */ @@ -272,8 +275,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 3af373b562..551102151e 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1767,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, diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 6c77f18f33..50fef00a96 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5668,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); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 79c873e601..0be8becbab 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1324,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; 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_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..c81abd643f 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -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..05974bb2ba 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5704,6 +5704,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 +5756,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 +5794,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 +5828,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) { @@ -5982,7 +5989,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; @@ -6426,7 +6433,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 +6459,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 +6477,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 +6496,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 +6517,33 @@ 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; + char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; idx = 0; @@ -6522,6 +6551,10 @@ DEFUN (aggregate_address_mask, ? AGGREGATE_SUMMARY_ONLY : 0; + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + char prefix_str[BUFSIZ]; int ret = netmask_str2prefix_str(prefix, mask, prefix_str); @@ -6531,7 +6564,7 @@ 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, @@ -6581,17 +6614,20 @@ 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; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6599,8 +6635,13 @@ 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); + + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + + return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap, + sum_only, as_set); } DEFUN (no_ipv6_aggregate_address, @@ -7228,7 +7269,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 +7302,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) { @@ -11834,6 +11877,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 +12513,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..a5286cea69 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -269,7 +269,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 +278,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 +1210,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 +1300,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 +1700,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. */ @@ -2728,10 +2772,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 +2895,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 +2968,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 +3115,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 +3148,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 +3159,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 +3284,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 +3368,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. */ @@ -4028,6 +4094,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, @@ -5083,6 +5172,7 @@ void bgp_route_map_init(void) 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); @@ -5136,6 +5226,8 @@ void bgp_route_map_init(void) 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..352e3b87e8 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1420,7 +1420,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 +1442,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 +1453,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/bgpd.c b/bgpd/bgpd.c index 5b31fbb3a8..e815334bfc 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; @@ -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 e9b07bc403..9d45d96987 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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; 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/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/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/user/bgp.rst b/doc/user/bgp.rst index 7883d0e4c6..7b3cdf2c4b 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -685,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 @@ -699,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 @@ -713,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 @@ -726,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 @@ -744,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: @@ -2321,7 +2333,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 @@ -2338,8 +2350,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 @@ -2352,8 +2364,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: 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 76a9364cf9..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 -`Edsger 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..e36783d176 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 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/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..b7283d83de 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* 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/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/isisd/isis_circuit.c b/isisd/isis_circuit.c index 8d008d78bd..5da8e6ee9e 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -135,8 +135,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 +264,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 +479,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 +523,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) diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 2371c0b73a..e3541644aa 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -121,7 +121,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 */ 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_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..bd61918697 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -1384,7 +1384,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 +1410,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 +1446,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 +1463,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; } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 3d16d56016..ecfce392ff 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -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, 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..44fa45d02b 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,223 @@ 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 ((circuit == NULL) || (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 +298,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 +338,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 +475,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 +490,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 +502,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..39a2f6ef35 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -53,6 +53,8 @@ struct zclient *zclient = NULL; +DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) + /* Router-id update message from zebra. */ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) { @@ -82,6 +84,8 @@ static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS) isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); + hook_call(isis_if_new_hook, ifp); + return 0; } @@ -219,9 +223,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 +233,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 +296,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 +318,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) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 20c10d0b23..83a32108eb 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -24,14 +24,19 @@ extern struct zclient *zclient; +DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); + void isis_zebra_init(struct thread_master *); void isis_zebra_stop(void); 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.h b/isisd/isisd.h index 393b1d67c7..308f018c19 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -58,7 +58,6 @@ 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; 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..884ae159be 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -37,7 +37,7 @@ 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); @@ -106,9 +106,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 +121,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 @@ -407,7 +425,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: 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 eecca2a5f5..04f2bd95a0 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1718,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/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); + } } } @@ -207,21 +207,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) { @@ -1461,6 +1458,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 +1556,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, }, }, { 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/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..1d6317b005 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -702,15 +702,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 +812,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/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); @@ -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); @@ -870,7 +875,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 f809704f86..92a495ac61 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2451,6 +2451,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) { diff --git a/lib/zclient.h b/lib/zclient.h index 81e454d192..eb3c97b111 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, @@ -395,6 +396,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; @@ -625,6 +648,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/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/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_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/ospfd.c b/ospfd/ospfd.c index e48a5b4d36..f4de255877 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -2158,7 +2158,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_nht.c b/pbrd/pbr_nht.c index 57e8cf5742..359f869c42 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -682,29 +682,119 @@ 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_IPV4_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_IPV4: + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + 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 +826,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 +868,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 +881,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/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/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/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/ripngd.c b/ripngd/ripngd.c index 49f7dda646..ef4e474737 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -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/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_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..1965c2968e 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -200,6 +200,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 +233,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; 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/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_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/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/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..b65f93856f 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-ecmp-topo2 [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/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..a6a910a1db 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, @@ -533,7 +561,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) @@ -961,6 +991,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 +1046,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..3313dc2f20 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."; @@ -296,7 +301,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"; } 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/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/main.c b/zebra/main.c index 657d1247e9..99607c0d78 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" @@ -375,9 +374,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/zapi_msg.c b/zebra/zapi_msg.c index 0e7dc5ce9b..ffdc4dc512 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1750,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 */ @@ -2456,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/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 ff4bfb10f7..5428b6eaef 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2097,14 +2097,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 @@ -3303,9 +3295,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..bcaf1b5204 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1198,13 +1198,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_vty.c b/zebra/zebra_vty.c index 38de01e228..7984481093 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1384,35 +1384,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 +1428,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; |
