diff options
192 files changed, 4924 insertions, 3355 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 ab9dc3092a..a7cd3fee88 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; } @@ -1305,14 +1305,20 @@ bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr) if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) || IPV4_CLASS_DE(nexthop_h)) && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { + uint8_t data[7]; /* type(2) + length(1) + nhop(4) */ char buf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, INET_ADDRSTRLEN); flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); + data[0] = BGP_ATTR_FLAG_TRANS; + data[1] = BGP_ATTR_NEXT_HOP; + data[2] = BGP_ATTR_NHLEN_IPV4; + memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4); + bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, + data, 7); return BGP_ATTR_PARSE_ERROR; } @@ -1685,8 +1691,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; } @@ -1702,7 +1708,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; @@ -1713,7 +1719,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; } @@ -1722,7 +1728,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; } @@ -1754,7 +1760,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; } @@ -1771,7 +1777,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; } @@ -1789,7 +1795,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, @@ -1801,21 +1807,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; } @@ -1831,12 +1837,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; @@ -2043,8 +2050,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 f1a871fe43..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 */ 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_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 5eeab36742..05974bb2ba 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7269,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( @@ -7301,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) { @@ -11875,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); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index ba4e32c23d..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 */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b1f1819b6b..a5286cea69 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1210,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 @@ -1284,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. */ @@ -1683,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. */ @@ -2731,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, @@ -2856,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)) { @@ -2926,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; @@ -3073,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. */ @@ -3111,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"); @@ -3122,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 */ @@ -4061,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, @@ -5116,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); @@ -5169,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/bgp_updgrp.c b/bgpd/bgp_updgrp.c index de7b05bdd9..4b6af935e0 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -570,8 +570,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; if (filter->map[RMAP_OUT].name) - vty_out(vty, " Outgoing route map: %s%s\n", - filter->map[RMAP_OUT].map ? "X" : "", + vty_out(vty, " Outgoing route map: %s\n", filter->map[RMAP_OUT].name); vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv); if (updgrp->conf->change_local_as) @@ -613,6 +612,9 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) subgrp->peer_refreshes_combined); vty_out(vty, " Merge checks triggered: %u\n", subgrp->merge_checks_triggered); + vty_out(vty, " Coalesce Time: %u%s\n", + (UPDGRP_INST(subgrp->update_group))->coalesce_time, + subgrp->t_coalesce ? "(Running)" : ""); vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version); vty_out(vty, " Packet queue length: %d\n", bpacket_queue_length(SUBGRP_PKTQ(subgrp))); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 21f1dff60d..5c1483a768 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -324,8 +324,9 @@ static int subgroup_coalesce_timer(struct thread *thread) subgrp = THREAD_ARG(thread); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) zlog_debug("u%" PRIu64 ":s%" PRIu64 - " announcing routes upon coalesce timer expiry", - (SUBGRP_UPDGRP(subgrp))->id, subgrp->id); + " announcing routes upon coalesce timer expiry(%u ms)", + (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, + subgrp->v_coalesce), subgrp->t_coalesce = NULL; subgrp->v_coalesce = 0; subgroup_announce_route(subgrp); diff --git a/bgpd/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/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/configure.ac b/configure.ac index be3a9c763d..88f1c4f627 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.60]) -AC_INIT([frr], [7.2-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" 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 7b3cdf2c4b..8edd19026d 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2396,6 +2396,23 @@ Displaying Routes by AS Path Print a summary of neighbor connections for the specified AFI/SAFI combination. +Displaying Update Group Information +----------------------------------- + +..index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue] +..clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue] + + Display Information about each individual update-group being used. + If SUBGROUP-ID is specified only display about that particular group. If + advertise-queue is specified the list of routes that need to be sent + to the peers in the update-group is displayed, advertised-routes means + the list of routes we have sent to the peers in the update-group and + packet-queue specifies the list of packets in the queue to be sent. + +..index:: show bgp update-groups statistics +..clicmd:: show bgp update-groups statistics + + Display Information about update-group events in FRR. .. _bgp-route-reflector: diff --git a/doc/user/index.rst b/doc/user/index.rst index 6c3b14e062..416c51f13b 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -58,6 +58,7 @@ Protocols vnc vrrp bmp + watchfrr ######## Appendix diff --git a/doc/user/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 b7283d83de..5d2cfbc337 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -663,19 +663,30 @@ kernel. .. clicmd:: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can - be **any** or one of + be: - - system, - - kernel, + - any, + - babel, + - bgp, - connected, - - static, - - rip, - - ripng, + - eigrp, + - isis, + - kernel, + - nhrp, + - openfabric, - ospf, - ospf6, - - isis, - - bgp, - - hsls. + - rip, + - sharp, + - static, + - ripng, + - table, + - vnc. + + If you choose any as the option that will cause all protocols that are sending + routes to zebra. You can specify a :dfn:`ip protocol PROTOCOL route-map ROUTEMAP` + on a per vrf basis, by entering this command under vrf mode for the vrf you + want to apply the route-map against. .. index:: set src ADDRESS .. clicmd:: set src ADDRESS 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/include/linux/fib_rules.h b/include/linux/fib_rules.h index bc6688012c..232df14e12 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_FIB_RULES_H #define __LINUX_FIB_RULES_H @@ -22,13 +23,23 @@ struct fib_rule_hdr { __u8 tos; __u8 table; - __u8 res1; /* reserved */ + __u8 res1; /* reserved */ __u8 res2; /* reserved */ __u8 action; __u32 flags; }; +struct fib_rule_uid_range { + __u32 start; + __u32 end; +}; + +struct fib_rule_port_range { + __u16 start; + __u16 end; +}; + enum { FRA_UNSPEC, FRA_DST, /* destination address */ @@ -43,7 +54,7 @@ enum { FRA_UNUSED5, FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ - FRA_UNUSED6, + FRA_TUN_ID, FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, /* Extended table id */ @@ -51,6 +62,11 @@ enum { FRA_OIFNAME, FRA_PAD, FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ + FRA_UID_RANGE, /* UID range */ + FRA_PROTOCOL, /* Originator of the rule */ + FRA_IP_PROTO, /* ip proto */ + FRA_SPORT_RANGE, /* sport */ + FRA_DPORT_RANGE, /* dport */ __FRA_MAX }; diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index a924606f36..dfcf3ce009 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -34,6 +34,7 @@ enum { IFA_MULTICAST, IFA_FLAGS, IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + IFA_TARGET_NETNSID, __IFA_MAX, }; @@ -63,7 +64,9 @@ struct ifa_cacheinfo { }; /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif #endif diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 156f4434ca..fb79481cb2 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Linux ethernet bridge * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_IF_BRIDGE_H -#define _LINUX_IF_BRIDGE_H +#ifndef _UAPI_LINUX_IF_BRIDGE_H +#define _UAPI_LINUX_IF_BRIDGE_H #include <linux/types.h> #include <linux/if_ether.h> @@ -96,7 +97,7 @@ struct __fdb_entry { __u32 ageing_timer_value; __u8 port_hi; __u8 pad0; - __u16 unused; + __u16 vlan; }; /* Bridge Flags */ @@ -236,6 +237,7 @@ struct br_mdb_entry { #define MDB_PERMANENT 1 __u8 state; #define MDB_FLAGS_OFFLOAD (1 << 0) +#define MDB_FLAGS_FAST_LEAVE (1 << 1) __u8 flags; __u16 vid; struct { @@ -291,4 +293,4 @@ struct br_mcast_stats { __u64 mcast_bytes[BR_MCAST_DIR_SIZE]; __u64 mcast_packets[BR_MCAST_DIR_SIZE]; }; -#endif /* _LINUX_IF_BRIDGE_H */ +#endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 1f97d0560b..22a45914a2 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_IF_LINK_H -#define _LINUX_IF_LINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_IF_LINK_H +#define _UAPI_LINUX_IF_LINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -158,6 +159,14 @@ enum { IFLA_PAD, IFLA_XDP, IFLA_EVENT, + IFLA_NEW_NETNSID, + IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, + IFLA_NEW_IFINDEX, + IFLA_MIN_MTU, + IFLA_MAX_MTU, __IFLA_MAX }; @@ -165,8 +174,10 @@ enum { #define IFLA_MAX (__IFLA_MAX - 1) /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif enum { IFLA_INET_UNSPEC, @@ -276,6 +287,7 @@ enum { IFLA_BR_MCAST_STATS_ENABLED, IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, __IFLA_BR_MAX, }; @@ -323,6 +335,14 @@ enum { IFLA_BRPORT_MCAST_TO_UCAST, IFLA_BRPORT_VLAN_TUNNEL, IFLA_BRPORT_BCAST_FLOOD, + IFLA_BRPORT_GROUP_FWD_MASK, + IFLA_BRPORT_NEIGH_SUPPRESS, + IFLA_BRPORT_ISOLATED, + IFLA_BRPORT_BACKUP_PORT, + IFLA_BRPORT_PEER_LINK = 60, /* MLAG peer link */ + IFLA_BRPORT_DUAL_LINK, /* MLAG Dual Connected link */ + IFLA_BRPORT_GROUP_FWD_MASKHI, + IFLA_BRPORT_DUAL_LINK_READY, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -448,6 +468,16 @@ enum { #define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + enum macsec_validation_type { MACSEC_VALIDATE_DISABLED = 0, MACSEC_VALIDATE_CHECK = 1, @@ -460,6 +490,7 @@ enum macsec_validation_type { enum { IFLA_IPVLAN_UNSPEC, IFLA_IPVLAN_MODE, + IFLA_IPVLAN_FLAGS, __IFLA_IPVLAN_MAX }; @@ -472,6 +503,9 @@ enum ipvlan_mode { IPVLAN_MODE_MAX }; +#define IPVLAN_F_PRIVATE 0x01 +#define IPVLAN_F_VEPA 0x02 + /* VXLAN section */ enum { IFLA_VXLAN_UNSPEC, @@ -502,6 +536,7 @@ enum { IFLA_VXLAN_COLLECT_METADATA, IFLA_VXLAN_LABEL, IFLA_VXLAN_GPE, + IFLA_VXLAN_TTL_INHERIT, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -585,6 +620,8 @@ enum { IFLA_BOND_AD_USER_PORT_KEY, IFLA_BOND_AD_ACTOR_SYSTEM, IFLA_BOND_TLB_DYNAMIC_LB, + IFLA_BOND_CL_START = 60, + IFLA_BOND_AD_LACP_BYPASS = IFLA_BOND_CL_START, __IFLA_BOND_MAX, }; @@ -612,6 +649,9 @@ enum { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + + IFLA_BOND_SLAVE_CL_START = 50, + IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START, __IFLA_BOND_SLAVE_MAX, }; @@ -721,6 +761,8 @@ enum { IFLA_VF_STATS_BROADCAST, IFLA_VF_STATS_MULTICAST, IFLA_VF_STATS_PAD, + IFLA_VF_STATS_RX_DROPPED, + IFLA_VF_STATS_TX_DROPPED, __IFLA_VF_STATS_MAX, }; @@ -872,6 +914,7 @@ enum { enum { LINK_XSTATS_TYPE_UNSPEC, LINK_XSTATS_TYPE_BRIDGE, + LINK_XSTATS_TYPE_BOND, __LINK_XSTATS_TYPE_MAX }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) @@ -902,6 +945,7 @@ enum { XDP_ATTACHED_DRV, XDP_ATTACHED_SKB, XDP_ATTACHED_HW, + XDP_ATTACHED_MULTI, }; enum { @@ -910,6 +954,9 @@ enum { IFLA_XDP_ATTACHED, IFLA_XDP_FLAGS, IFLA_XDP_PROG_ID, + IFLA_XDP_DRV_PROG_ID, + IFLA_XDP_SKB_PROG_ID, + IFLA_XDP_HW_PROG_ID, __IFLA_XDP_MAX, }; @@ -925,4 +972,43 @@ enum { IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */ }; -#endif /* _LINUX_IF_LINK_H */ +/* tun section */ + +enum { + IFLA_TUN_UNSPEC, + IFLA_TUN_OWNER, + IFLA_TUN_GROUP, + IFLA_TUN_TYPE, + IFLA_TUN_PI, + IFLA_TUN_VNET_HDR, + IFLA_TUN_PERSIST, + IFLA_TUN_MULTI_QUEUE, + IFLA_TUN_NUM_QUEUES, + IFLA_TUN_NUM_DISABLED_QUEUES, + __IFLA_TUN_MAX, +}; + +#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) + +/* rmnet section */ + +#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0) +#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1) +#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2) +#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3) + +enum { + IFLA_RMNET_UNSPEC, + IFLA_RMNET_MUX_ID, + IFLA_RMNET_FLAGS, + __IFLA_RMNET_MAX, +}; + +#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1) + +struct ifla_rmnet_flags { + __u32 flags; + __u32 mask; +}; + +#endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h index 3298426271..de696ca12f 100644 --- a/include/linux/lwtunnel.h +++ b/include/linux/lwtunnel.h @@ -1,5 +1,6 @@ -#ifndef _LWTUNNEL_H_ -#define _LWTUNNEL_H_ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LWTUNNEL_H_ +#define _UAPI_LWTUNNEL_H_ #include <linux/types.h> @@ -67,4 +68,4 @@ enum { #define LWT_BPF_MAX_HEADROOM 256 -#endif /* _LWTUNNEL_H_ */ +#endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h index 1a0e57b45a..521f2e605f 100644 --- a/include/linux/mpls_iptunnel.h +++ b/include/linux/mpls_iptunnel.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * mpls tunnel api * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_MPLS_IPTUNNEL_H -#define _LINUX_MPLS_IPTUNNEL_H +#ifndef _UAPI_LINUX_MPLS_IPTUNNEL_H +#define _UAPI_LINUX_MPLS_IPTUNNEL_H /* MPLS tunnel attributes * [RTA_ENCAP] = { @@ -27,4 +28,4 @@ enum { }; #define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) -#endif /* _LINUX_MPLS_IPTUNNEL_H */ +#endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */ diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h index 3199d28980..cd144e3099 100644 --- a/include/linux/neighbour.h +++ b/include/linux/neighbour.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_NEIGHBOUR_H #define __LINUX_NEIGHBOUR_H @@ -27,6 +28,7 @@ enum { NDA_MASTER, NDA_LINK_NETNSID, NDA_SRC_VNI, + NDA_PROTOCOL, /* Originator of entry */ __NDA_MAX }; @@ -42,6 +44,7 @@ enum { #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_EXT_LEARNED 0x10 #define NTF_OFFLOADED 0x20 +#define NTF_STICKY 0x40 #define NTF_ROUTER 0x80 /* diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h index 9a92b7e14a..0187c74d88 100644 --- a/include/linux/net_namespace.h +++ b/include/linux/net_namespace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* Copyright (c) 2015 6WIND S.A. * Author: Nicolas Dichtel <nicolas.dichtel@6wind.com> * @@ -5,8 +6,8 @@ * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. */ -#ifndef _LINUX_NET_NAMESPACE_H_ -#define _LINUX_NET_NAMESPACE_H_ +#ifndef _UAPI_LINUX_NET_NAMESPACE_H_ +#define _UAPI_LINUX_NET_NAMESPACE_H_ /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ enum { @@ -20,4 +21,4 @@ enum { #define NETNSA_MAX (__NETNSA_MAX - 1) -#endif /* _LINUX_NET_NAMESPACE_H_ */ +#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 0b2c29bd08..0a4d733177 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef __LINUX_NETLINK_H -#define __LINUX_NETLINK_H +#ifndef _UAPI__LINUX_NETLINK_H +#define _UAPI__LINUX_NETLINK_H #include <linux/kernel.h> #include <linux/socket.h> /* for __kernel_sa_family_t */ @@ -147,12 +147,15 @@ enum nlmsgerr_attrs { #define NETLINK_PKTINFO 3 #define NETLINK_BROADCAST_ERROR 4 #define NETLINK_NO_ENOBUFS 5 +#ifndef __KERNEL__ #define NETLINK_RX_RING 6 #define NETLINK_TX_RING 7 +#endif #define NETLINK_LISTEN_ALL_NSID 8 #define NETLINK_LIST_MEMBERSHIPS 9 #define NETLINK_CAP_ACK 10 #define NETLINK_EXT_ACK 11 +#define NETLINK_GET_STRICT_CHK 12 struct nl_pktinfo { __u32 group; @@ -175,6 +178,7 @@ struct nl_mmap_hdr { __u32 nm_gid; }; +#ifndef __KERNEL__ enum nl_mmap_status { NL_MMAP_STATUS_UNUSED, NL_MMAP_STATUS_RESERVED, @@ -186,6 +190,7 @@ enum nl_mmap_status { #define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO #define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) #define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) +#endif #define NET_MAJOR 36 /* Major 36 is reserved for networking */ @@ -244,4 +249,4 @@ struct nla_bitfield32 { __u32 selector; }; -#endif /* __LINUX_NETLINK_H */ +#endif /* _UAPI__LINUX_NETLINK_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 813e9e0767..ce2a623abb 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -1,5 +1,6 @@ -#ifndef __LINUX_RTNETLINK_H -#define __LINUX_RTNETLINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI__LINUX_RTNETLINK_H +#define _UAPI__LINUX_RTNETLINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -149,6 +150,20 @@ enum { RTM_NEWCACHEREPORT = 96, #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + RTM_NEWCHAIN = 100, +#define RTM_NEWCHAIN RTM_NEWCHAIN + RTM_DELCHAIN, +#define RTM_DELCHAIN RTM_DELCHAIN + RTM_GETCHAIN, +#define RTM_GETCHAIN RTM_GETCHAIN + + RTM_NEWNEXTHOP = 104, +#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP + RTM_DELNEXTHOP, +#define RTM_DELNEXTHOP RTM_DELNEXTHOP + RTM_GETNEXTHOP, +#define RTM_GETNEXTHOP RTM_GETNEXTHOP + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -253,6 +268,11 @@ enum { #define RTPROT_DHCP 16 /* DHCP client */ #define RTPROT_MROUTED 17 /* Multicast daemon */ #define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_BGP 186 /* BGP Routes */ +#define RTPROT_ISIS 187 /* ISIS Routes */ +#define RTPROT_OSPF 188 /* OSPF Routes */ +#define RTPROT_RIP 189 /* RIP Routes */ +#define RTPROT_EIGRP 192 /* EIGRP Routes */ /* rtm_scope @@ -326,6 +346,10 @@ enum rtattr_type_t { RTA_PAD, RTA_UID, RTA_TTL_PROPAGATE, + RTA_IP_PROTO, + RTA_SPORT, + RTA_DPORT, + RTA_NH_ID, __RTA_MAX }; @@ -430,6 +454,8 @@ enum { #define RTAX_QUICKACK RTAX_QUICKACK RTAX_CC_ALGO, #define RTAX_CC_ALGO RTAX_CC_ALGO + RTAX_FASTOPEN_NO_COOKIE, +#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE __RTAX_MAX }; @@ -538,9 +564,19 @@ struct tcmsg { int tcm_ifindex; __u32 tcm_handle; __u32 tcm_parent; +/* tcm_block_index is used instead of tcm_parent + * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK + */ +#define tcm_block_index tcm_parent __u32 tcm_info; }; +/* For manipulation of filters in shared block, tcm_ifindex is set to + * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index + * which is the block index. + */ +#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) + enum { TCA_UNSPEC, TCA_KIND, @@ -554,6 +590,9 @@ enum { TCA_PAD, TCA_DUMP_INVISIBLE, TCA_CHAIN, + TCA_HW_OFFLOAD, + TCA_INGRESS_BLOCK, + TCA_EGRESS_BLOCK, __TCA_MAX }; @@ -586,6 +625,7 @@ enum { #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) +#ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 #define RTMGRP_NOTIFY 2 @@ -606,6 +646,7 @@ enum { #define RTMGRP_DECnet_ROUTE 0x4000 #define RTMGRP_IPV6_PREFIX 0x20000 +#endif /* RTnetlink multicast groups */ enum rtnetlink_groups { @@ -671,6 +712,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV6_MROUTE_R, #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R + RTNLGRP_NEXTHOP, +#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) @@ -715,4 +758,4 @@ enum { -#endif /* __LINUX_RTNETLINK_H */ +#endif /* _UAPI__LINUX_RTNETLINK_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 8c1e501774..8eb9602170 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_SOCKET_H -#define _LINUX_SOCKET_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_SOCKET_H +#define _UAPI_LINUX_SOCKET_H /* * Desired design of maximum size and alignment (see RFC2553) @@ -18,4 +19,4 @@ struct __kernel_sockaddr_storage { /* _SS_MAXSIZE value minus size of ss_family */ } __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */ -#endif /* _LINUX_SOCKET_H */ +#endif /* _UAPI_LINUX_SOCKET_H */ diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 9b368cc404..d2ec6ff566 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -254,6 +254,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, reason ? reason : "unspecified"); } + circuit->adj_state_changes++; #ifndef FABRICD /* send northbound notification */ isis_notif_adj_state_change(adj, new_state, reason); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 8d008d78bd..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..b77c8ce352 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 */ @@ -144,6 +144,13 @@ struct isis_circuit { uint32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */ uint32_t rej_adjacencies; /* rejectedAdjacencies */ + /* + * Counters as in ietf-isis@2019-09-09.yang + */ + uint32_t id_len_mismatches; /* id-len-mismatch */ + uint32_t max_area_addr_mismatches; /* max-area-addresses-mismatch */ + uint32_t auth_type_failures; /*authentication-type-fails */ + uint32_t auth_failures; /* authentication-fails */ QOBJ_FIELDS }; diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index bd06286755..37f4dcfabd 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -188,14 +188,10 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag", } /* check if the interface is a loopback and if so set it as passive */ - pthread_rwlock_rdlock(&running_config->lock); - { - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); - } - pthread_rwlock_unlock(&running_config->lock); + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (ifp && if_is_loopback(ifp)) + nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", + NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -262,14 +258,10 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag", } /* check if the interface is a loopback and if so set it as passive */ - pthread_rwlock_rdlock(&running_config->lock); - { - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); - } - pthread_rwlock_unlock(&running_config->lock); + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (ifp && if_is_loopback(ifp)) + nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", + NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -410,26 +402,20 @@ DEFPY(no_is_type, no_is_type_cmd, "Act as both a station router and an area router\n" "Act as an area router only\n") { - const char *value; - - pthread_rwlock_rdlock(&running_config->lock); - { - struct isis_area *area; + const char *value = NULL; + struct isis_area *area; - area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - - /* - * Put the is-type back to defaults: - * - level-1-2 on first area - * - level-1 for the rest - */ - if (area && listgetdata(listhead(isis->area_list)) == area) - value = "level-1-2"; - else - value = NULL; - } - pthread_rwlock_unlock(&running_config->lock); + area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + /* + * Put the is-type back to defaults: + * - level-1-2 on first area + * - level-1 for the rest + */ + if (area && listgetdata(listhead(isis->area_list)) == area) + value = "level-1-2"; + else + value = NULL; nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); @@ -1817,45 +1803,52 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd, "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { - const char *circ_type = NULL; + struct interface *ifp; + struct isis_circuit *circuit; + int is_type; + const char *circ_type; /* * Default value depends on whether the circuit is part of an area, * and the is-type of the area if there is one. So we need to do this * here. */ - pthread_rwlock_rdlock(&running_config->lock); - { - struct interface *ifp; - struct isis_circuit *circuit; + ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); + if (!ifp) + goto def_val; - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (!ifp) - goto unlock; + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + goto def_val; - circuit = circuit_scan_by_ifp(ifp); - if (!circuit || circuit->state != C_STATE_UP) - goto unlock; + if (circuit->state == C_STATE_UP) + is_type = circuit->area->is_type; + else + goto def_val; - switch (circuit->area->is_type) { - case IS_LEVEL_1: - circ_type = "level-1"; - break; - case IS_LEVEL_2: - circ_type = "level-2"; - break; - case IS_LEVEL_1_AND_2: - circ_type = "level-1-2"; - break; - } + switch (is_type) { + case IS_LEVEL_1: + circ_type = "level-1"; + break; + case IS_LEVEL_2: + circ_type = "level-2"; + break; + case IS_LEVEL_1_AND_2: + circ_type = "level-1-2"; + break; + default: + return CMD_ERR_NO_MATCH; } -unlock: - pthread_rwlock_unlock(&running_config->lock); - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY, circ_type); return nb_cli_apply_changes(vty, NULL); + +def_val: + nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", + NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); } void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 4b29e6dc7e..061e758831 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -52,9 +52,9 @@ #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" -#include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_tlvs.h" +#include "isisd/isis_te.h" #include "isisd/fabricd.h" #include "isisd/isis_tx_queue.h" @@ -781,8 +781,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, if (!rn->info) continue; struct isis_ext_info *info = rn->info; - struct prefix_ipv6 *p, *src_p; + srcdest_rnode_prefixes(rn, (const struct prefix **)&p, (const struct prefix **)&src_p); @@ -863,6 +863,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) /* Protocols Supported */ if (area->ip_circuits > 0 || area->ipv6_circuits > 0) { struct nlpids nlpids = {.count = 0}; + if (area->ip_circuits > 0) { lsp_debug( "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", @@ -908,10 +909,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag); } - /* IPv4 address and TE router ID TLVs. In case of the first one we don't - * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put - * into - * LSP and this address is same as router id. */ + /* IPv4 address and TE router ID TLVs. + * In case of the first one we don't follow "C" vendor, + * but "J" vendor behavior - one IPv4 address is put + * into LSP. TE router ID will be the same if MPLS-TE + * is not activate or MPLS-TE router-id not specified + */ if (isis->router_id != 0) { struct in_addr id = {.s_addr = isis->router_id}; inet_ntop(AF_INET, &id, buf, sizeof(buf)); @@ -919,11 +922,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag, buf); isis_tlvs_add_ipv4_address(lsp->tlvs, &id); - /* Exactly same data is put into TE router ID TLV, but only if - * new style - * TLV's are in use. */ + /* If new style TLV's are in use, add TE router ID TLV + * Check if MPLS-TE is activate and mpls-te router-id set + * otherwise add exactly same data as for IPv4 address + */ if (area->newmetric) { - + if (IS_MPLS_TE(area->mta) + && area->mta->router_id.s_addr != 0) + id.s_addr = area->mta->router_id.s_addr; lsp_debug( "ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); @@ -1004,6 +1010,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) && circuit->ipv6_non_link->count > 0) { struct listnode *ipnode; struct prefix_ipv6 *ipv6; + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, ipnode, ipv6)) { lsp_debug( @@ -1036,25 +1043,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } - if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface - && HAS_LINK_PARAMS( - circuit->interface)) - subtlv_len = add_te_subtlvs( - subtlvs, - circuit->mtc); - else - subtlv_len = 0; - + if (area->newmetric) tlvs_add_mt_bcast( lsp->tlvs, circuit, - level, ne_id, metric, - subtlvs, subtlv_len); - } + level, ne_id, metric); } } else { lsp_debug( @@ -1079,36 +1071,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface != NULL - && HAS_LINK_PARAMS( - circuit->interface)) - /* Update Local and Remote IP - * address for MPLS TE circuit - * parameters */ - /* NOTE sure that it is the - * pertinent place for that - * updates */ - /* Local IP address could be - * updated in isis_circuit.c - - * isis_circuit_add_addr() */ - /* But, where update remote IP - * address ? in isis_pdu.c - - * process_p2p_hello() ? */ - - /* Add SubTLVs & Adjust real - * size of SubTLVs */ - subtlv_len = add_te_subtlvs( - subtlvs, circuit->mtc); - else - /* Or keep only TE metric with - * no SubTLVs if MPLS_TE is off - */ - subtlv_len = 0; - uint32_t neighbor_metric; if (fabricd_tier(area) == 0) { neighbor_metric = 0xffe; @@ -1117,8 +1079,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } tlvs_add_mt_p2p(lsp->tlvs, circuit, - ne_id, neighbor_metric, - subtlvs, subtlv_len); + ne_id, neighbor_metric); } } else { lsp_debug( @@ -1512,7 +1473,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, } if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (self)", area->area_tag, sysid_print(ne_id), @@ -1554,7 +1515,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", area->area_tag, sysid_print(ne_id), diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 7f49e9d89a..718924daf2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -243,7 +243,7 @@ int main(int argc, char **argv, char **envp) mt_init(); /* create the global 'isis' instance */ - isis_new(1); + isis_new(1, VRF_DEFAULT); isis_zebra_init(master); isis_bfd_init(); diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index f7d4c7170f..36413bac59 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -511,8 +511,8 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level, static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, unsigned int mt_count, uint16_t *mt_set, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric, + struct isis_ext_subtlvs *ext) { for (unsigned int i = 0; i < mt_count; i++) { uint16_t mtid = mt_set[i]; @@ -527,30 +527,27 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, area->area_tag, sysid_print(id), LSP_PSEUDO_ID(id), isis_mtid2str(mtid)); } - isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs, - subtlv_len); + isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, ext); } } void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len) + int level, uint8_t *id, uint32_t metric) { unsigned int mt_count; uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count); tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric, - subtlvs, subtlv_len); + circuit->ext); } void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id, - metric, subtlvs, subtlv_len); + metric, circuit->ext); } void mt_init(void) diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 515b63f50f..b40139c50a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -116,10 +116,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid); void adj_mt_finish(struct isis_adjacency *adj); void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len); + int level, uint8_t *id, uint32_t metric); void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len); + uint8_t *id, uint32_t metric); void mt_init(void); #endif diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index c1b630eb2d..ccd4cfbd1c 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -49,6 +49,23 @@ #include "lib/vrf.h" /* + * Helper functions. + */ +static const char *isis_yang_adj_state(enum isis_adj_state state) +{ + switch (state) { + case ISIS_ADJ_DOWN: + return "down"; + case ISIS_ADJ_UP: + return "up"; + case ISIS_ADJ_INITIALIZING: + return "init"; + default: + return "failed"; + } +} + +/* * XPath: /frr-isisd:isis/instance */ static int isis_instance_create(enum nb_event event, @@ -1384,7 +1401,7 @@ static int isis_instance_mpls_te_create(enum nb_event event, struct mpls_te_area *new; - zlog_debug("ISIS MPLS-TE: Initialize area %s", + zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering", area->area_tag); new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area)); @@ -1410,12 +1427,12 @@ static int isis_instance_mpls_te_create(enum nb_event event, * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || IS_FLOOD_AS(circuit->mtc->type)) + if (circuit->ext == NULL) continue; - if (!IS_MPLS_TE(circuit->mtc) + if (!IS_EXT_TE(circuit->ext) && HAS_LINK_PARAMS(circuit->interface)) - circuit->mtc->status = enable; + isis_link_params_update(circuit, circuit->interface); else continue; @@ -1446,11 +1463,16 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, /* Flush LSP if circuit engage */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || (circuit->mtc->status == disable)) + if (!IS_EXT_TE(circuit->ext)) continue; - /* disable MPLS_TE Circuit */ - circuit->mtc->status = disable; + /* disable MPLS_TE Circuit keeping SR one's */ + if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID)) + circuit->ext->status = EXT_ADJ_SID; + else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID)) + circuit->ext->status = EXT_LAN_ADJ_SID; + else + circuit->ext->status = 0; /* Re-originate circuit without STD_TE & GMPLS parameters */ if (circuit->area) @@ -1458,6 +1480,9 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, 0); } + zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering", + area->area_tag); + return NB_OK; } @@ -2296,6 +2321,368 @@ static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify( } /* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency + */ +static const void * +lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj, *adj_next = NULL; + struct list *list; + struct listnode *node, *node_next; + + /* Get first adjacency. */ + if (list_entry == NULL) { + ifp = (struct interface *)parent_list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; + level++) { + adj = listnode_head( + circuit->u.bc.adjdb[level - 1]); + if (adj) + break; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + break; + default: + adj = NULL; + break; + } + + return adj; + } + + /* Get next adjacency. */ + adj = (struct isis_adjacency *)list_entry; + circuit = adj->circuit; + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + list = circuit->u.bc.adjdb[adj->level - 1]; + node = listnode_lookup(list, adj); + node_next = listnextnode(node); + if (node_next) + adj_next = listgetdata(node_next); + else if (adj->level == ISIS_LEVEL1) { + /* + * Once we finish the L1 adjacencies, move to the L2 + * adjacencies list. + */ + list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1]; + adj_next = listnode_head(list); + } + break; + case CIRCUIT_T_P2P: + /* P2P circuits have at most one adjacency. */ + default: + break; + } + + return adj_next; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_enum(xpath, adj->level); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, sysid_print(adj->sysid)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint32(xpath, adj->circuit->circuit_id); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, snpa_print(adj->snpa)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint16(xpath, adj->hold_time); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath, + const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_changes_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->adj_state_changes); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_number_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj; + struct listnode *node; + uint32_t total = 0; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + /* + * TODO: keep track of the number of adjacencies instead of calculating + * it on demand. + */ + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + for (ALL_LIST_ELEMENTS_RO( + circuit->u.bc.adjdb[level - 1], node, adj)) + total++; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + if (adj) + total = 1; + break; + default: + break; + } + + return yang_data_new_uint32(xpath, total); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->init_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_rejects_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->rej_adjacencies); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_id_len_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->id_len_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_type_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_type_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_failures); +} + +/* * NOTIFICATIONS */ static void notif_prep_instance_hdr(const char *xpath, @@ -2537,19 +2924,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj, listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath); - switch (new_state) { - case ISIS_ADJ_DOWN: - data = yang_data_new_string(xpath_arg, "down"); - break; - case ISIS_ADJ_UP: - data = yang_data_new_string(xpath_arg, "up"); - break; - case ISIS_ADJ_INITIALIZING: - data = yang_data_new_string(xpath_arg, "init"); - break; - default: - data = yang_data_new_string(xpath_arg, "failed"); - } + data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state)); listnode_add(arguments, data); if (new_state == ISIS_ADJ_DOWN) { snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath); @@ -3476,6 +3851,102 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency", + .cbs = { + .get_next = lib_interface_isis_adjacencies_adjacency_get_next, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_init_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem, + } + }, + { .xpath = NULL, }, } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 3d16d56016..46b013ddd0 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, @@ -583,6 +576,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (p2p_hello) { if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn("p2p hello on non p2p circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "p2p hello on non p2p circuit", @@ -593,6 +587,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, } else { if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("lan hello on non broadcast circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "lan hello on non broadcast circuit", @@ -605,6 +600,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_debug( "level %d LAN Hello received over circuit with externalDomain = true", level); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, @@ -621,6 +617,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, circuit->area->area_tag, circuit->interface->name); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Interface level mismatch", raw_pdu); @@ -650,6 +647,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16, circuit->area->area_tag, pdu_name, circuit->interface->name, iih.pdu_len); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Invalid PDU length", raw_pdu); @@ -661,6 +659,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, flog_err(EC_ISIS_PACKET, "Level %d LAN Hello with Circuit Type %d", level, iih.circ_type); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "LAN Hello with wrong IS-level", raw_pdu); @@ -674,6 +673,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), circuit->rcv_stream, &iih.tlvs, &error_log)) { zlog_warn("isis_unpack_tlvs() failed: %s", error_log); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs", raw_pdu); @@ -692,6 +692,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (!iih.tlvs->protocols_supported.count) { zlog_warn("No supported protocols TLV in %s", pdu_name); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "No supported protocols TLV", raw_pdu); @@ -709,11 +710,14 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -722,6 +726,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_warn( "ISIS-Adj (%s): Received IIH with own sysid - discard", circuit->area->area_tag); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Received IIH with our own sysid", raw_pdu); @@ -759,6 +764,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH", circuit->area->area_tag); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Neither IPv4 not IPv6 considered usable", @@ -947,11 +953,14 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, hdr.lsp_id); #ifndef FABRICD /* send northbound notification */ - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1380,12 +1389,15 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1621,6 +1633,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8 ", while the parameter for this IS is %u", id_len, ISIS_SYS_ID_LEN); + circuit->id_len_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_id_len_mismatch(circuit, id_len, raw_pdu); @@ -1673,6 +1686,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8 " while the parameter for this IS is %u", max_area_addrs, isis->max_area_addrs); + circuit->max_area_addr_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_max_area_addr_mismatch(circuit, max_area_addrs, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 636a63e290..05394e0fe4 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -49,8 +49,16 @@ #include "isis_route.h" #include "isis_zebra.h" +DEFINE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family, union g_addr *ip, ifindex_t ifindex); +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip, ifindex_t ifindex) @@ -316,7 +324,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, return route_info; } -static void isis_route_delete(struct route_node *rode, +static void isis_route_delete(struct isis_area *area, struct route_node *rode, struct route_table *table) { struct isis_route_info *rinfo; @@ -343,13 +351,37 @@ static void isis_route_delete(struct route_node *rode, UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug("ISIS-Rte: route delete %s", buff); - isis_zebra_route_update(prefix, src_p, rinfo); + isis_route_update(area, prefix, src_p, rinfo); } isis_route_info_delete(rinfo); rode->info = NULL; route_unlock_node(rode); } +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) +{ + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_add_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + } else { + if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_del_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + } +} + static void _isis_route_verify_table(struct isis_area *area, struct route_table *table, struct route_table **tables) @@ -390,7 +422,7 @@ static void _isis_route_verify_table(struct isis_area *area, buff); } - isis_zebra_route_update(dst_p, src_p, rinfo); + isis_route_update(area, dst_p, src_p, rinfo); if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) continue; @@ -399,7 +431,7 @@ static void _isis_route_verify_table(struct isis_area *area, * directly for * validating => no problems with deleting routes. */ if (!tables) { - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); continue; } @@ -422,7 +454,7 @@ static void _isis_route_verify_table(struct isis_area *area, route_unlock_node(drnode); } - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); } } diff --git a/isisd/isis_route.h b/isisd/isis_route.h index a20a7e038f..2326bb8228 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -44,6 +44,11 @@ struct isis_route_info { struct list *nexthops; }; +DECLARE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + struct isis_route_info *isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p, uint32_t cost, diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 4ea6c2c60d..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.c b/isisd/isisd.c index 67f557ab50..029a9e0688 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -75,12 +75,13 @@ int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); -void isis_new(unsigned long process_id) +void isis_new(unsigned long process_id, vrf_id_t vrf_id) { isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); /* * Default values */ + isis->vrf_id = vrf_id; isis->max_area_addrs = 3; isis->process_id = process_id; isis->router_id = 0; diff --git a/isisd/isisd.h b/isisd/isisd.h index 393b1d67c7..f825b6ecb4 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -58,11 +58,11 @@ extern struct zebra_privs_t isisd_privs; /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ -/* #define EXTREME_DICT_DEBUG */ struct fabricd; struct isis { + vrf_id_t vrf_id; unsigned long process_id; int sysid_set; uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ @@ -190,7 +190,7 @@ struct isis_area { DECLARE_QOBJ_TYPE(isis_area) void isis_init(void); -void isis_new(unsigned long); +void isis_new(unsigned long process_id, vrf_id_t vrf_id); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup(const char *); int isis_area_get(struct vty *vty, const char *area_tag); diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 7f2e396a7f..b234e3ebe3 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -249,7 +249,7 @@ l2vpn_pw_init(struct l2vpn_pw *pw) l2vpn_pw_fec(pw, &fec); lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, - 0, (void *)pw); + 0, 0, (void *)pw); lde_kernel_update(&fec); } @@ -260,7 +260,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw) struct zapi_pw zpw; l2vpn_pw_fec(pw, &fec); - lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); + lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0); lde_kernel_update(&fec); pw2zpw(pw, &zpw); @@ -433,7 +433,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) if (pw == NULL) return; - fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0); + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0); if (fnh == NULL) return; @@ -482,7 +482,7 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) } fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, - 0, 0); + 0, 0, 0); if (fnh == NULL) continue; diff --git a/ldpd/lde.c b/ldpd/lde.c index ac680b47a9..006d27f6ab 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -520,7 +520,8 @@ lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: lde_kernel_insert(&fec, kr->af, &kr->nexthop, - kr->ifindex, kr->priority, + kr->ifindex, kr->route_type, + kr->route_instance, kr->flags & F_CONNECTED, NULL); break; case IMSG_NETWORK_UPDATE: @@ -747,7 +748,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); @@ -761,7 +763,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); @@ -798,7 +801,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); @@ -812,7 +816,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.ifindex = fnh->ifindex; kr.local_label = fn->local_label; kr.remote_label = fnh->remote_label; - kr.priority = fnh->priority; + kr.route_type = fnh->route_type; + kr.route_instance = fnh->route_instance; lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); diff --git a/ldpd/lde.h b/ldpd/lde.h index 0a7d0a58fe..ce466c16b9 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -108,7 +108,8 @@ struct fec_nh { union ldpd_addr nexthop; ifindex_t ifindex; uint32_t remote_label; - uint8_t priority; + uint8_t route_type; + unsigned short route_instance; uint8_t flags; }; #define F_FEC_NH_NEW 0x01 @@ -193,11 +194,11 @@ void rt_dump(pid_t); void fec_snap(struct lde_nbr *); void fec_tree_clear(void); struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); void lde_kernel_insert(struct fec *, int, union ldpd_addr *, - ifindex_t, uint8_t, int, void *); + ifindex_t, uint8_t, unsigned short, int, void *); void lde_kernel_remove(struct fec *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); void lde_kernel_update(struct fec *); void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_request(struct map *, struct lde_nbr *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 0957a5455e..eb1a6d9434 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -31,7 +31,7 @@ static int lde_nbr_is_nexthop(struct fec_node *, static void fec_free(void *); static struct fec_node *fec_add(struct fec *fec); static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *, - ifindex_t, uint8_t); + ifindex_t, uint8_t, unsigned short); static void fec_nh_del(struct fec_nh *); RB_GENERATE(fec_tree, fec, entry, fec_compare) @@ -275,7 +275,7 @@ fec_add(struct fec *fec) struct fec_nh * fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_nh *fnh; @@ -283,7 +283,8 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, if (fnh->af == af && ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 && fnh->ifindex == ifindex && - fnh->priority == priority) + fnh->route_type == route_type && + fnh->route_instance == route_instance) return (fnh); return (NULL); @@ -291,7 +292,7 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, static struct fec_nh * fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_nh *fnh; @@ -303,7 +304,8 @@ fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, fnh->nexthop = *nexthop; fnh->ifindex = ifindex; fnh->remote_label = NO_LABEL; - fnh->priority = priority; + fnh->route_type = route_type; + fnh->route_instance = route_instance; LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); return (fnh); @@ -318,7 +320,8 @@ fec_nh_del(struct fec_nh *fnh) void lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority, int connected, void *data) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance, + int connected, void *data) { struct fec_node *fn; struct fec_nh *fnh; @@ -329,9 +332,10 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, if (data) fn->data = data; - fnh = fec_nh_find(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); if (fnh == NULL) - fnh = fec_nh_add(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type, + route_instance); fnh->flags |= F_FEC_NH_NEW; if (connected) fnh->flags |= F_FEC_NH_CONNECTED; @@ -339,7 +343,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, void lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, - ifindex_t ifindex, uint8_t priority) + ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) { struct fec_node *fn; struct fec_nh *fnh; @@ -348,7 +352,7 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, if (fn == NULL) /* route lost */ return; - fnh = fec_nh_find(fn, af, nexthop, ifindex, priority); + fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); if (fnh == NULL) /* route lost */ return; diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 35a7d944d3..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/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 40c6123810..95dafff84e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -136,7 +136,7 @@ static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) ospf6_abr_originate_summary(route); } -static struct ospf6 *ospf6_create(void) +static struct ospf6 *ospf6_create(vrf_id_t vrf_id) { struct ospf6 *o; @@ -144,6 +144,7 @@ static struct ospf6 *ospf6_create(void) /* initialize */ monotime(&o->starttime); + o->vrf_id = vrf_id; o->area_list = list_new(); o->area_list->cmp = ospf6_area_cmp; o->lsdb = ospf6_lsdb_create(o); @@ -325,7 +326,7 @@ DEFUN_NOSH (router_ospf6, OSPF6_STR) { if (ospf6 == NULL) { - ospf6 = ospf6_create(); + ospf6 = ospf6_create(VRF_DEFAULT); if (ospf6->router_id == 0) ospf6_router_id_update(); } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 381027dcff..ba41fca65b 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -31,6 +31,9 @@ struct ospf6_master { /* OSPFv3 top level data structure */ struct ospf6 { + /* The relevant vrf_id */ + vrf_id_t vrf_id; + /* my router id */ uint32_t router_id; diff --git a/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/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_vrf.c b/staticd/static_vrf.c index 9dd25fbdd1..abb64aad3f 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -27,6 +27,7 @@ #include "static_memory.h" #include "static_vrf.h" #include "static_routes.h" +#include "static_zebra.h" #include "static_vty.h" static void zebra_stable_node_cleanup(struct route_table *table, @@ -76,6 +77,8 @@ static int static_vrf_new(struct vrf *vrf) static int static_vrf_enable(struct vrf *vrf) { + static_zebra_vrf_register(vrf); + static_fixup_vrf_ids(vrf->info); /* @@ -89,6 +92,7 @@ static int static_vrf_enable(struct vrf *vrf) static int static_vrf_disable(struct vrf *vrf) { + static_zebra_vrf_unregister(vrf); return 0; } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 1965c2968e..2944cdad32 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -526,3 +526,17 @@ void static_zebra_init(void) static_nht_hash_cmp, "Static Nexthop Tracking hash"); } + +void static_zebra_vrf_register(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_reg_requests(zclient, vrf->vrf_id); +} + +void static_zebra_vrf_unregister(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_dereg_requests(zclient, vrf->vrf_id); +} diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index 15f5410b81..962dc3908f 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -28,4 +28,7 @@ extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, vrf_id_t vrf_id, safi_t safi, bool install); extern void static_zebra_init(void); +extern void static_zebra_vrf_register(struct vrf *vrf); +extern void static_zebra_vrf_unregister(struct vrf *vrf); + #endif diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index b2612892f9..b5db36703a 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1379,6 +1379,7 @@ int main(void) i = 0; + frr_pthread_init(); bgp_pthreads_init(); bgp_pth_ka->running = true; diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 968f9ac445..db1cf0611d 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -916,6 +916,7 @@ int main(void) vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); + frr_pthread_init(); bgp_pthreads_init(); bgp_pth_ka->running = true; diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 8e1b62ac15..e5d3030ed1 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1391,6 +1391,7 @@ static void bgp_startup(void) bgp_master_init(master); bgp_option_set(BGP_OPT_NO_LISTEN); vrf_init(NULL, NULL, NULL, NULL, NULL); + frr_pthread_init(); bgp_init(0); bgp_pthreads_run(); } diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex 6f8bc2218e..46e45e5ee0 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/tests/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 index bee5115323..d6753e9b23 100644 --- 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 @@ -39,6 +39,7 @@ 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, '../')) @@ -88,21 +89,42 @@ def test_bgp_maximum_prefix_invalid(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + router = tgen.gears['r2'] + def _bgp_converge(router): - while True: - output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) - if output['192.168.255.1']['bgpState'] == 'Established': - if output['192.168.255.1']['addressFamilyInfo']['ipv4Unicast']['acceptedPrefixCounter'] == 3: - return True + 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(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.0/24 json")) - if output['paths'][0]['med'] == 123: - return True - return False + 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) - if _bgp_converge('r2'): - assert _bgp_aggregate_address_has_metric('r2') == True + assert result is None, 'Failed to see applied metric for aggregated prefix in "{}"'.format(router) if __name__ == '__main__': args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 deleted file mode 100644 index f244122f1a..0000000000 --- a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 +++ /dev/null @@ -1,5 +0,0 @@ -xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx -xx via inet 10.0.1.2 dev r1-eth0 proto xx diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 deleted file mode 100644 index ff99ff9866..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O 1.1.1.1/32 [110/0] is directly connected, lo -O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 -O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx -O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx -O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 -O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index ff72a1c0b7..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,42 +0,0 @@ -1.1.1.1/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.2.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 38522e162e..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -Local LDP Identifier: 1.1.1.1:0 -Discovery Sources: - Interfaces: - r1-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index 0fb15d2da7..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r1-eth0 ACTIVE xx:xx:xx 5/15 1 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index 3df98bfae5..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,8 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref index 61cb9eec82..7e24359af3 100644 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref @@ -1,8 +1,8 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 implicit-null - XX LDP 10.0.1.2 implicit-null - XX LDP 10.0.1.2 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 implicit-null + XX LDP 10.0.1.2 implicit-null + XX LDP 10.0.1.2 implicit-null + diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 deleted file mode 100644 index 912a082019..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 +++ /dev/null @@ -1,8 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null deleted file mode 100644 index 912a082019..0000000000 --- a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,8 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 3 - XX LDP 10.0.1.2 XX - XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 deleted file mode 100644 index eaec2f16b9..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0 -O 2.2.2.2/32 [110/0] is directly connected, lo -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1 -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1 -O 10.0.1.0/24 [110/10] is directly connected, r2-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r2-eth1 -O 10.0.3.0/24 [110/10] is directly connected, r2-eth2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index 54ee39080a..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,56 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index b1bebd7c46..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,12 +0,0 @@ -Local LDP Identifier: 2.2.2.2:0 -Discovery Sources: - Interfaces: - r2-eth0: xmit/recv - LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 - Hold time: 15 sec - r2-eth1: xmit/recv - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index f9fc98408c..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,3 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1 -ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index a70e2f48c6..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,26 +0,0 @@ -Peer LDP Identifier: 1.1.1.1:0 - TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref index 46420ccd11..df05a6b31a 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref @@ -1,7 +1,7 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 implicit-null - XX LDP 10.0.2.3 implicit-null - XX LDP 10.0.2.4 implicit-null - XX LDP 10.0.3.3 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.1.1 implicit-null + XX LDP 10.0.2.3 implicit-null + XX LDP 10.0.2.4 implicit-null + XX LDP 10.0.3.3 implicit-null + diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 deleted file mode 100644 index ba244e76ec..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 3 - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null deleted file mode 100644 index ba244e76ec..0000000000 --- a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,7 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.1.1 3 - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 deleted file mode 100644 index c8a29400b2..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 -O 3.3.3.3/32 [110/0] is directly connected, lo -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r3-eth0 -O 10.0.3.0/24 [110/10] is directly connected, r3-eth1 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index e04d2b7e4a..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,49 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 5e299fff9c..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ -Local LDP Identifier: 3.3.3.3:0 -Discovery Sources: - Interfaces: - r3-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index 243811e3a9..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r3-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index ee1983ac29..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,17 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref index c367f240f4..3978895613 100644 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref @@ -1,10 +1,10 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.4 implicit-null - XX LDP 10.0.3.2 XX - XX LDP 10.0.3.2 implicit-null - XX LDP 10.0.3.2 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.4 implicit-null + XX LDP 10.0.3.2 XX + XX LDP 10.0.3.2 implicit-null + XX LDP 10.0.3.2 implicit-null + diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 deleted file mode 100644 index 9198969bd5..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 +++ /dev/null @@ -1,10 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null deleted file mode 100644 index 9198969bd5..0000000000 --- a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,10 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.4 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 3 - XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 deleted file mode 100644 index df2a2b585f..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 +++ /dev/null @@ -1,7 +0,0 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 -O 4.4.4.4/32 [110/0] is directly connected, lo -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0 -O 10.0.2.0/24 [110/10] is directly connected, r4-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 deleted file mode 100644 index 3d55805d7c..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 +++ /dev/null @@ -1,49 +0,0 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 imp-null -4.4.4.4/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 deleted file mode 100644 index 3ebddd606a..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ -Local LDP Identifier: 4.4.4.4:0 -Discovery Sources: - Interfaces: - r4-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 deleted file mode 100644 index dd57656f15..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 +++ /dev/null @@ -1,2 +0,0 @@ -AF Interface State Uptime Hello Timers ac -ipv4 r4-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 deleted file mode 100644 index fb0e7d7dfa..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 +++ /dev/null @@ -1,17 +0,0 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref index 9f86cd67cc..174dcebd4d 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref @@ -1,9 +1,9 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.2 implicit-null - XX LDP 10.0.2.3 implicit-null - XX LDP 10.0.2.3 implicit-null + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------- + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.2 implicit-null + XX LDP 10.0.2.3 implicit-null + XX LDP 10.0.2.3 implicit-null + diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 deleted file mode 100644 index b8cf5a2702..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 +++ /dev/null @@ -1,9 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null deleted file mode 100644 index b8cf5a2702..0000000000 --- a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null +++ /dev/null @@ -1,9 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 3 - XX LDP 10.0.2.2 XX - XX LDP 10.0.2.3 3 - XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 409a5f54c8..f02f4c4e21 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -77,12 +77,6 @@ from lib import topotest fatal_error = "" -# Expected version of CLI Output - Appendix to filename -# empty string = current, latest output (default) -# "-1" ... "-NNN" previous versions (incrementing with each version) -cli_version = "" - - ##################################################### ## ## Network Topology Definition @@ -164,7 +158,6 @@ def teardown_module(module): def test_router_running(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -179,35 +172,12 @@ def test_router_running(): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error - # Detect CLI Version - # At this time, there are only 2 possible outputs, so simple check - output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() - - # Check if old or new format of CLI Output. Default is to current format - # - # Old (v1) output looks like this: - # Local LDP Identifier: 1.1.1.1:0 - # Discovery Sources: - # Interfaces: - # r1-eth0: xmit/recv - # LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - # Hold time: 15 sec - # Targeted Hellos: - # - # Current (v0) output looks like this: - # AF ID Type Source Holdtime - # ipv4 2.2.2.2 Link r1-eth0 15 - pattern = re.compile("^Local LDP Identifier.*") - if pattern.match(output): - cli_version = "-1" - # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) def test_mpls_interfaces(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -220,7 +190,7 @@ def test_mpls_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -263,7 +233,6 @@ def test_mpls_interfaces(): def test_mpls_ldp_neighbor_establish(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -279,22 +248,22 @@ def test_mpls_ldp_neighbor_establish(): # Look for any node not yet converged for i in range(1, 5): established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() - if cli_version != "-1": - # On current version, we need to make sure they all turn to OPERATIONAL on all lines - # - lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1) - # Check all lines to be either table header (starting with ^AF or show OPERATIONAL) - header = r'^AF.*' - operational = r'^ip.*OPERATIONAL.*' - found_operational = 0 - for j in range(1, len(lines)): - if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])): - established = "" # Empty string shows NOT established - if re.search(operational, lines[j]): - found_operational += 1 - if found_operational < 1: - # Need at least one operational neighbor + + # On current version, we need to make sure they all turn to OPERATIONAL on all lines + # + lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1) + # Check all lines to be either table header (starting with ^AF or show OPERATIONAL) + header = r'^AF.*' + operational = r'^ip.*OPERATIONAL.*' + found_operational = 0 + for j in range(1, len(lines)): + if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])): established = "" # Empty string shows NOT established + if re.search(operational, lines[j]): + found_operational += 1 + if found_operational < 1: + # Need at least one operational neighbor + established = "" # Empty string shows NOT established if not established: print('Waiting for r%s' %i) sys.stdout.flush() @@ -326,7 +295,6 @@ def test_mpls_ldp_neighbor_establish(): def test_mpls_ldp_discovery(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -339,7 +307,7 @@ def test_mpls_ldp_discovery(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref' if os.path.isfile(refTableFile): # Actual output from router actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() @@ -381,7 +349,6 @@ def test_mpls_ldp_discovery(): def test_mpls_ldp_neighbor(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -394,7 +361,7 @@ def test_mpls_ldp_neighbor(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -405,17 +372,8 @@ def test_mpls_ldp_neighbor(): actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() # Mask out changing parts in output - if cli_version == "-1": - # Mask out Timer in Uptime - actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual) - # Mask out Port numbers in TCP connection - actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+", - r"TCP connection: \1:xxx - \2:xxx", actual) - else: - # Current Version - # - # Mask out Timer in Uptime - actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual) + # Mask out Timer in Uptime + actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -446,7 +404,6 @@ def test_mpls_ldp_neighbor(): def test_mpls_ldp_binding(): global fatal_error global net - global cli_version # Skip this test for now until proper sorting of the output # is implemented @@ -463,7 +420,7 @@ def test_mpls_ldp_binding(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_mpls_ldp_binding.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -474,16 +431,9 @@ def test_mpls_ldp_binding(): actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip() # Mask out changing parts in output - if cli_version == "-1": - # Mask out label - actual = re.sub(r"label: [0-9]+", "label: xxx", actual) - actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual) - else: - # Current Version - # - # Mask out label - actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) - actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + # Mask out label + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -527,7 +477,6 @@ def test_mpls_ldp_binding(): def test_zebra_ipv4_routingTable(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -540,7 +489,7 @@ def test_zebra_ipv4_routingTable(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version) + refTableFile = '%s/r%s/show_ipv4_route.ref' if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -562,9 +511,6 @@ def test_zebra_ipv4_routingTable(): # now fix newlines of expected (make them all the same) expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) - # Add missing comma before label (for old version) - actual = re.sub(r"([0-9]) label ", r"\1, label ", actual) - # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -594,7 +540,6 @@ def test_zebra_ipv4_routingTable(): def test_mpls_table(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -607,23 +552,16 @@ def test_mpls_table(): print("******************************************\n") failures = 0 - version = cli_version - if (version == ""): - # check for new output without implicit-null - output = net['r1'].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip() - if 'LDP 10.0.1.2 3' in output: - version = "-no-impl-null" - for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, version) + refTableFile = '%s/r%s/show_mpls_table.ref' if os.path.isfile(refTableFile): # Read expected result from file - expected = open(refTableFile).read().rstrip() + expected = open(refTableFile).read() # Fix newlines (make them all the same) expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) # Actual output from router - actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip() + actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null') # Fix inconsistent Label numbers at beginning of line actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual) @@ -672,7 +610,6 @@ def test_mpls_table(): def test_linux_mpls_routes(): global fatal_error global net - global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref deleted file mode 100644 index fb193265be..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,31 +0,0 @@ -{ - "neighbors":[ - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} - diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index 7c4d0ab58c..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 2270c3fdde..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "2.2.2.2":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref deleted file mode 100644 index 1376579757..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index a982c1cbd3..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 18ffbc2f8a..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref deleted file mode 100644 index 41de304b2b..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index d7e0e42405..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - } - ], - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index b0669742ab..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - }, - "2.2.2.2":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index 0948c2e41b..ce651c50cd 100755 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -144,9 +144,6 @@ def setup_module(mod): ) tgen.start_router() - for router in router_list.values(): - if router.has_version('<', '3'): - tgen.set_error('unsupported version') def teardown_module(mod): "Teardown the pytest environment" @@ -180,30 +177,8 @@ def test_ospf_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - # Old output (before FRR PR1383) didn't show a list of neighbors. - # Check for dict object and compare to old output if this is the case - tgen = get_topogen() - router = tgen.gears['r1'] - output = router.vtysh_cmd("show ip ospf neighbor json", isjson=True) - - # We could have either old format (without "neighbors" and direct list - # of IP's or new format from PR1659 with "neighbors". - # Trying old formats first and fall back to new format - # - # New format: neighbors have dict instead of list of dicts (PR1723). - if output.has_key('neighbors'): - if isinstance(output['neighbors'], dict): - reffile = "show_ip_ospf_neighbor.json" - else: - reffile = "show_ip_ospf_neighbor.ref" - else: - if isinstance(output["2.2.2.2"], dict): - reffile = "show_ip_ospf_neighbor.ref-old-nolist" - else: - reffile = "show_ip_ospf_neighbor.ref-no-neigh" - for rname in ['r1', 'r2', 'r3']: - router_compare_json_output(rname, "show ip ospf neighbor json", reffile) + router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json") def test_rib(): logger.info("Test: verify RIB") diff --git a/tests/topotests/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.c b/vtysh/vtysh.c index a762e9555c..08126f6885 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2422,6 +2422,53 @@ DEFUN (vtysh_show_error_code, return CMD_SUCCESS; } +/* Northbound. */ +DEFUN (show_yang_operational_data, + show_yang_operational_data_cmd, + "show yang operational-data XPATH$xpath\ + [{\ + format <json$json|xml$xml>\ + |translate WORD$translator_family\ + }]" DAEMONS_LIST, + SHOW_STR + "YANG information\n" + "Show YANG operational data\n" + "XPath expression specifying the YANG data path\n" + "Set the output format\n" + "JavaScript Object Notation\n" + "Extensible Markup Language\n" + "Translate operational data\n" + "YANG module translator\n" + DAEMONS_STR) +{ + int idx_protocol = argc - 1; + char *fcmd = argv_concat(argv, argc - 1, 0); + int ret = vtysh_client_execute_name(argv[idx_protocol]->text, fcmd); + XFREE(MTYPE_TMP, fcmd); + return ret; +} + +DEFUNSH(VTYSH_ALL, debug_nb, + debug_nb_cmd, + "[no] debug northbound\ + [<\ + callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ + |notifications$notifications\ + |events$events\ + >]", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Callbacks\n" + "Configuration\n" + "State\n" + "RPC\n" + "Notifications\n" + "Events\n") +{ + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2548,10 +2595,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd, } DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, - "no log facility [FACILITY]", NO_STR + "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]", + NO_STR "Logging control\n" "Reset syslog facility to default (daemon)\n" - "Syslog facility\n") + LOG_FACILITY_DESC) { return CMD_SUCCESS; } @@ -4017,6 +4065,11 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd); install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd); + /* northbound */ + install_element(VIEW_NODE, &show_yang_operational_data_cmd); + install_element(ENABLE_NODE, &debug_nb_cmd); + install_element(CONFIG_NODE, &debug_nb_cmd); + /* misc lib show commands */ install_element(VIEW_NODE, &vtysh_show_memory_cmd); install_element(VIEW_NODE, &vtysh_show_modules_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 3ec2eb239d..e56c6fbf4e 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -406,7 +406,9 @@ void vtysh_config_parse_line(void *arg, const char *line) == 0 || strncmp(line, "frr", strlen("frr")) == 0 || strncmp(line, "agentx", strlen("agentx")) == 0 - || strncmp(line, "no log", strlen("no log")) == 0) + || strncmp(line, "no log", strlen("no log")) == 0 + || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0 + || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0) config_add_line_uniq(config_top, line); else config_add_line(config_top, line); diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index c27491e55c..30f606c202 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -19,3 +19,6 @@ watchfrr_watchfrr_SOURCES = \ watchfrr/watchfrr_errors.c \ watchfrr/watchfrr_vty.c \ # end + +watchfrr/watchfrr_vty_clippy.c: $(CLIPPY_DEPS) +watchfrr/watchfrr_vty.$(OBJEXT): watchfrr/watchfrr_vty_clippy.c diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index c17d381730..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-isisd.yang b/yang/frr-isisd.yang index 3313dc2f20..faa880eff4 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -61,6 +61,13 @@ module frr-isisd { "This type defines IS-IS level of an object."; } + typedef extended-circuit-id { + type uint32; + description + "This type defines the extended circuit ID + associated with an interface."; + } + typedef network-type { type enumeration { enum "unknown" { @@ -95,6 +102,20 @@ module frr-isisd { pattern, An example LSP ID is 0143.0438.AeF0.02-01"; } + typedef snpa { + type string { + length "0 .. 20"; + } + description + "This type defines the Subnetwork Point + of Attachment (SNPA) format. + The SNPA should be encoded according to the rules + specified for the particular type of subnetwork + being used. As an example, for an ethernet subnetwork, + the SNPA is encoded as a MAC address like + '00aa.bbcc.ddee'."; + } + typedef system-id { type string { pattern "[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}"; @@ -275,6 +296,399 @@ module frr-isisd { } } + grouping interface-config { + description "Interface configuration grouping"; + + leaf area-tag { + type string; + mandatory true; + description + "Area-tag associated to this circuit."; + } + + leaf ipv4-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv4 traffic over this circuit."; + } + + leaf ipv6-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv6 traffic over this circuit."; + } + + leaf circuit-type { + type level; + default "level-1-2"; + description + "IS-type of this circuit."; + } + + leaf bfd-monitoring { + type boolean; + default false; + description "Monitor IS-IS peers on this circuit."; + } + + container csnp-interval { + description + "Complete Sequence Number PDU (CSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-2"; + } + } + + container psnp-interval { + description + "Partial Sequence Number PDU (PSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PCNSP interval for level-2"; + } + } + + container hello { + description + "Parameters related to IS-IS hello PDUs."; + leaf padding { + type boolean; + default "true"; + description + "Add padding to IS-IS hello PDUs."; + } + + container interval { + description + "Interval between consecutive hello messages."; + leaf level-1 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-1; interval will depend on multiplier."; + } + + leaf level-2 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-2; interval will depend on multiplier."; + } + } + + container multiplier { + description + "Multiplier for the hello messages holding time."; + leaf level-1 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + + leaf level-2 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + } + } + + container metric { + description + "Default metric for this IS-IS circuit."; + leaf level-1 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-1 metric for this IS-IS circuit."; + } + + leaf level-2 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-2 metric for this IS-IS circuit."; + } + } + + container priority { + description + "Priority for Designated Router election."; + leaf level-1 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-1 priority for this IS-IS circuit."; + } + + leaf level-2 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-2 priority for this IS-IS circuit."; + } + } + + leaf network-type { + type network-type; + default "broadcast"; + must "(. = \"point-to-point\") or (. = \"broadcast\")"; + description + "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; + } + + leaf passive { + type boolean; + default "false"; + description + "Interface is in passive mode."; + } + + container password { + presence "Present if a password is set for this IS interface."; + uses isis-password; + } + + leaf disable-three-way-handshake { + type boolean; + default "false"; + description + "Disables three-way handshake when creating new adjacencies."; + } + + container multi-topology { + description + "IS-IS topologies configured on this circuit."; + leaf ipv4-unicast { + type boolean; + default "true"; + description + "IPv4 unicast topology."; + } + + leaf ipv4-multicast { + type boolean; + default "true"; + description + "IPv4 multicast topology."; + } + + leaf ipv4-management { + type boolean; + default "true"; + description + "IPv4 management topology."; + } + + leaf ipv6-unicast { + type boolean; + default "true"; + description + "IPv6 unicast topology."; + } + + leaf ipv6-multicast { + type boolean; + default "true"; + description + "IPv6 multicast topology."; + } + + leaf ipv6-management { + type boolean; + default "true"; + description + "IPv6 management topology."; + } + + leaf ipv6-dstsrc { + type boolean; + default "true"; + description + "IPv6 destination-source topology."; + } + } + } + + grouping adjacency-state { + container adjacencies { + config false; + list adjacency { + leaf neighbor-sys-type { + type level; + description + "Level capability of neighboring system"; + } + leaf neighbor-sysid { + type system-id; + description + "The system-id of the neighbor"; + } + leaf neighbor-extended-circuit-id { + type extended-circuit-id; + description + "Circuit ID of the neighbor"; + } + leaf neighbor-snpa { + type snpa; + description + "SNPA of the neighbor"; + } + leaf hold-timer { + type uint16; + units seconds; + description + "The holding time in seconds for this + adjacency. This value is based on + received hello PDUs and the elapsed + time since receipt."; + } + leaf neighbor-priority { + type uint8 { + range "0 .. 127"; + } + description + "Priority of the neighboring IS for becoming + the DIS."; + } + leaf state { + type adj-state-type; + description + "This leaf describes the state of the interface."; + } + + description + "List of operational adjacencies."; + } + description + "This container lists the adjacencies of + the local node."; + } + description + "Adjacency state"; + } + + grouping event-counters { + container event-counters { + config false; + leaf adjacency-changes { + type uint32; + description + "The number of times an adjacency state change has + occurred on this interface."; + } + leaf adjacency-number { + type uint32; + description + "The number of adjacencies on this interface."; + } + leaf init-fails { + type uint32; + description + "The number of times initialization of this + interface has failed. This counts events such + as PPP NCP failures. Failures to form an + adjacency are counted by adjacency-rejects."; + } + leaf adjacency-rejects { + type uint32; + description + "The number of times an adjacency has been + rejected on this interface."; + } + leaf id-len-mismatch { + type uint32; + description + "The number of times an IS-IS PDU with an ID + field length different from that for this + system has been received on this interface."; + } + leaf max-area-addresses-mismatch { + type uint32; + description + "The number of times an IS-IS PDU has been + received on this interface with the + max area address field differing from that of + this system."; + } + leaf authentication-type-fails { + type uint32; + description + "Number of authentication type mismatches."; + } + leaf authentication-fails { + type uint32; + description + "Number of authentication key failures."; + } + description "IS-IS interface event counters."; + } + description + "Grouping for IS-IS interface event counters"; + } + + grouping interface-state { + description + "IS-IS interface operational state."; + uses adjacency-state; + uses event-counters; + } + grouping notification-instance-hdr { description "Instance specific IS-IS notification data grouping"; @@ -313,7 +727,7 @@ module frr-isisd { } leaf extended-circuit-id { - type uint32; + type extended-circuit-id; description "Eextended circuit-id of the interface."; } @@ -733,270 +1147,8 @@ module frr-isisd { presence "Present if an IS-IS circuit is defined for this interface."; description "IS-IS interface parameters."; - leaf area-tag { - type string; - mandatory true; - description - "Area-tag associated to this circuit."; - } - - leaf ipv4-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv4 traffic over this circuit."; - } - - leaf ipv6-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv6 traffic over this circuit."; - } - - leaf circuit-type { - type level; - default "level-1-2"; - description - "IS-type of this circuit."; - } - - leaf bfd-monitoring { - type boolean; - default false; - description "Monitor IS-IS peers on this circuit."; - } - - container csnp-interval { - description - "Complete Sequence Number PDU (CSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-2"; - } - } - - container psnp-interval { - description - "Partial Sequence Number PDU (PSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PCNSP interval for level-2"; - } - } - - container hello { - description - "Parameters related to IS-IS hello PDUs."; - leaf padding { - type boolean; - default "true"; - description - "Add padding to IS-IS hello PDUs."; - } - - container interval { - description - "Interval between consecutive hello messages."; - leaf level-1 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-1; interval will depend on multiplier."; - } - - leaf level-2 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-2; interval will depend on multiplier."; - } - } - - container multiplier { - description - "Multiplier for the hello messages holding time."; - leaf level-1 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - - leaf level-2 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - } - } - - container metric { - description - "Default metric for this IS-IS circuit."; - leaf level-1 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-1 metric for this IS-IS circuit."; - } - - leaf level-2 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-2 metric for this IS-IS circuit."; - } - } - - container priority { - description - "Priority for Designated Router election."; - leaf level-1 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-1 priority for this IS-IS circuit."; - } - - leaf level-2 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-2 priority for this IS-IS circuit."; - } - } - - leaf network-type { - type network-type; - default "broadcast"; - must "(. = \"point-to-point\") or (. = \"broadcast\")"; - description - "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; - } - - leaf passive { - type boolean; - default "false"; - description - "Interface is in passive mode."; - } - - container password { - presence "Present if a password is set for this IS interface."; - uses isis-password; - } - - leaf disable-three-way-handshake { - type boolean; - default "false"; - description - "Disables three-way handshake when creating new adjacencies."; - } - - container multi-topology { - description - "IS-IS topologies configured on this circuit."; - leaf ipv4-unicast { - type boolean; - default "true"; - description - "IPv4 unicast topology."; - } - - leaf ipv4-multicast { - type boolean; - default "true"; - description - "IPv4 multicast topology."; - } - - leaf ipv4-management { - type boolean; - default "true"; - description - "IPv4 management topology."; - } - - leaf ipv6-unicast { - type boolean; - default "true"; - description - "IPv6 unicast topology."; - } - - leaf ipv6-multicast { - type boolean; - default "true"; - description - "IPv6 multicast topology."; - } - - leaf ipv6-management { - type boolean; - default "true"; - description - "IPv6 management topology."; - } - - leaf ipv6-dstsrc { - type boolean; - default "true"; - description - "IPv6 destination-source topology."; - } - } + uses interface-config; + uses interface-state; } } diff --git a/yang/libyang_plugins/frr_user_types.c b/yang/libyang_plugins/frr_user_types.c index 4814f5bc1d..48cdceccf4 100644 --- a/yang/libyang_plugins/frr_user_types.c +++ b/yang/libyang_plugins/frr_user_types.c @@ -20,6 +20,7 @@ #include <zebra.h> #include "prefix.h" +#include "ipaddr.h" #include <libyang/user_types.h> @@ -53,6 +54,21 @@ static int ipv6_address_store_clb(const char *type_name, const char *value_str, return 0; } +static int ip_address_store_clb(const char *type_name, const char *value_str, + lyd_val *value, char **err_msg) +{ + value->ptr = malloc(sizeof(struct ipaddr)); + if (!value->ptr) + return 1; + + if (str2ipaddr(value_str, value->ptr)) { + free(value->ptr); + return 1; + } + + return 0; +} + static int ipv4_prefix_store_clb(const char *type_name, const char *value_str, lyd_val *value, char **err_msg) { @@ -83,6 +99,21 @@ static int ipv6_prefix_store_clb(const char *type_name, const char *value_str, return 0; } +static int ip_prefix_store_clb(const char *type_name, const char *value_str, + lyd_val *value, char **err_msg) +{ + value->ptr = malloc(sizeof(struct prefix)); + if (!value->ptr) + return 1; + + if (str2prefix(value_str, value->ptr) == 0) { + free(value->ptr); + return 1; + } + + return 0; +} + struct lytype_plugin_list frr_user_types[] = { {"ietf-inet-types", "2013-07-15", "ipv4-address", ipv4_address_store_clb, free}, @@ -92,9 +123,13 @@ struct lytype_plugin_list frr_user_types[] = { ipv6_address_store_clb, free}, {"ietf-inet-types", "2013-07-15", "ipv6-address-no-zone", ipv6_address_store_clb, free}, + {"ietf-inet-types", "2013-07-15", "ip-address", ip_address_store_clb, + free}, {"ietf-inet-types", "2013-07-15", "ipv4-prefix", ipv4_prefix_store_clb, free}, {"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb, free}, + {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb, + free}, {NULL, NULL, NULL, NULL, NULL} /* terminating item */ }; diff --git a/zebra/connected.c b/zebra/connected.c index 6b92945c63..87cf8c8f20 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -385,7 +385,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) return; break; default: - zlog_info("Unknown AFI: %s", afi2str(afi)); + zlog_warn("Unknown AFI: %s", afi2str(afi)); break; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index c71b95f753..08fa77923d 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1032,7 +1032,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { - zlog_debug("%s: NULL address", __func__); + zlog_debug("%s: Local Interface Address is NULL for %s", + __func__, ifp->name); return -1; } diff --git a/zebra/interface.c b/zebra/interface.c index 6486c01430..bb808e1852 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -2034,13 +2034,13 @@ DEFUN (link_params_enable, /* This command could be issue at startup, when activate MPLS TE */ /* on a new interface or after a ON / OFF / ON toggle */ /* In all case, TE parameters are reset to their default factory */ - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: enable TE link parameters on interface %s", ifp->name); if (!if_link_params_get(ifp)) { - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: failed to init TE link parameters %s", ifp->name); @@ -2063,8 +2063,9 @@ DEFUN (no_link_params_enable, { VTY_DECLVAR_CONTEXT(interface, ifp); - zlog_debug("MPLS-TE: disable TE link parameters on interface %s", - ifp->name); + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) + zlog_debug("MPLS-TE: disable TE link parameters on interface %s", + ifp->name); if_link_params_free(ifp); 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/redistribute.c b/zebra/redistribute.c index 1ae2ba92b0..227226b5f9 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -119,7 +119,7 @@ static void zebra_redistribute(struct zserv *client, int type, srcdest_rnode_prefixes(rn, &dst_p, &src_p); - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_RIB) zlog_debug( "%s: client %s %s(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", __func__, @@ -149,7 +149,8 @@ static void zebra_redistribute(struct zserv *client, int type, /* Either advertise a route for redistribution to registered clients or */ /* withdraw redistribution if add cannot be done for client */ void redistribute_update(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re, struct route_entry *prev_re) + const struct route_entry *re, + const struct route_entry *prev_re) { struct listnode *node, *nnode; struct zserv *client; @@ -200,7 +201,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, send_redistribute = 1; if (send_redistribute) { - if (IS_ZEBRA_DEBUG_EVENT) { + if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( "%s: client %s %s(%u), type=%d, distance=%d, metric=%d", __func__, @@ -226,54 +227,99 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, } } +/* + * During a route delete, where 'new_re' is NULL, redist a delete to all + * clients registered for the type of 'old_re'. + * During a route update, redist a delete to any clients who will not see + * an update when the new route is installed. There are cases when a client + * may have seen a redist for 'old_re', but will not see + * the redist for 'new_re'. + */ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re) + const struct route_entry *old_re, + const struct route_entry *new_re) { struct listnode *node, *nnode; struct zserv *client; - char buf[INET6_ADDRSTRLEN]; int afi; + char buf[PREFIX_STRLEN]; + vrf_id_t vrfid; + + if (old_re) + vrfid = old_re->vrf_id; + else if (new_re) + vrfid = new_re->vrf_id; + else + return; if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug("%u:%s/%d: Redist delete re %p (%s)", - re->vrf_id, buf, p->prefixlen, re, - zebra_route_string(re->type)); + zlog_debug( + "%u:%s: Redist del: re %p (%s), new re %p (%s)", + vrfid, prefix2str(p, buf, sizeof(buf)), + old_re, + old_re ? zebra_route_string(old_re->type) : "None", + new_re, + new_re ? zebra_route_string(new_re->type) : "None"); } /* Add DISTANCE_INFINITY check. */ - if (re->distance == DISTANCE_INFINITY) + if (old_re && (old_re->distance == DISTANCE_INFINITY)) return; afi = family2afi(p->family); if (!afi) { flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, "%s: Unknown AFI/SAFI prefix received\n", - __FUNCTION__); + __func__); return; } + /* Skip invalid (e.g. linklocal) prefix */ if (!zebra_check_addr(p)) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("Redist delete filter prefix %s", - prefix2str(p, buf, sizeof(buf))); + if (IS_ZEBRA_DEBUG_RIB) { + zlog_debug( + "%u:%s: Redist del old: skipping invalid prefix", + vrfid, prefix2str(p, buf, sizeof(buf))); + } return; } for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if ((is_default_prefix(p) - && vrf_bitmap_check(client->redist_default[afi], - re->vrf_id)) - || vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], - re->vrf_id) - || (re->instance - && redist_check_instance( - &client->mi_redist[afi][re->type], - re->instance)) - || vrf_bitmap_check(client->redist[afi][re->type], - re->vrf_id)) { + if (new_re) { + /* Skip this client if it will receive an update for the + * 'new' re + */ + if (is_default_prefix(p) + && vrf_bitmap_check(client->redist_default[afi], + new_re->vrf_id)) + continue; + else if (vrf_bitmap_check( + client->redist[afi][ZEBRA_ROUTE_ALL], + new_re->vrf_id)) + continue; + else if (new_re->instance + && redist_check_instance( + &client->mi_redist[afi][new_re->type], + new_re->instance)) + continue; + else if (vrf_bitmap_check( + client->redist[afi][new_re->type], + new_re->vrf_id)) + continue; + } + + /* Send a delete for the 'old' re to any subscribed client. */ + if (old_re + && ((old_re->instance + && redist_check_instance( + &client->mi_redist[afi] + [old_re->type], + old_re->instance)) + || vrf_bitmap_check( + client->redist[afi][old_re->type], + old_re->vrf_id))) { zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, p, src_p, re); + client, p, src_p, old_re); } } } diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 30ff6bcd09..2685458f96 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -42,11 +42,19 @@ extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS); extern void redistribute_update(const struct prefix *p, const struct prefix *src_p, - struct route_entry *re, - struct route_entry *prev_re); -extern void redistribute_delete(const struct prefix *p, - const struct prefix *src_p, - struct route_entry *re); + const struct route_entry *re, + const struct route_entry *prev_re); +/* + * During a route delete, where 'new_re' is NULL, redist a delete to all + * clients registered for the type of 'old_re'. + * During a route update, redist a delete to any clients who will not see + * an update when the new route is installed. There are cases when a client + * may have seen a redist for 'old_re', but will not see + * the redist for 'new_re'. + */ +void redistribute_delete(const struct prefix *p, const struct prefix *src_p, + const struct route_entry *old_re, + const struct route_entry *new_re); extern void zebra_interface_up_update(struct interface *); extern void zebra_interface_down_update(struct interface *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 91a3024038..43e44cad16 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1440,6 +1440,7 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1460,6 +1461,8 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); @@ -1930,6 +1933,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1950,6 +1954,8 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6); req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); @@ -2297,6 +2303,7 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, static enum zebra_dplane_result netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2330,6 +2337,8 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) else req.ndm.ndm_flags |= NTF_EXT_LEARNED; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, dplane_ctx_mac_get_addr(ctx), 6); req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); @@ -2748,6 +2757,7 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2782,6 +2792,8 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_type = RTN_UNICAST; req.ndm.ndm_flags = flags; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); if (mac) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 8cc5b52b34..711c4e0877 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -54,6 +54,7 @@ */ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) { + uint8_t protocol = RTPROT_ZEBRA; int family; int bytelen; struct { @@ -78,6 +79,9 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) req.frh.family = family; req.frh.action = FR_ACT_TO_TBL; + addattr_l(&req.n, sizeof(req), + FRA_PROTOCOL, &protocol, sizeof(protocol)); + /* rule's pref # */ addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index fa6a2f62ec..ffdc4dc512 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -516,7 +516,8 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) int zsend_redistribute_route(int cmd, struct zserv *client, const struct prefix *p, - const struct prefix *src_p, struct route_entry *re) + const struct prefix *src_p, + const struct route_entry *re) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -1749,88 +1750,146 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); } -static void zread_mpls_labels(ZAPI_HANDLER_ARGS) +/* + * Handle request to create an MPLS LSP. + * + * A single message can fully specify an LSP with multiple nexthops. + * + * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is + * updated to use the received label(s). + */ +static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) { struct stream *s; - enum lsp_types_t type; - struct prefix prefix; - enum nexthop_types_t gtype; - union g_addr gate; - ifindex_t ifindex; - mpls_label_t in_label, out_label; - uint8_t distance; + struct zapi_labels zl; /* Get input stream. */ s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); + return; + } - /* Get data. */ - STREAM_GETC(s, type); - STREAM_GETL(s, prefix.family); - switch (prefix.family) { - case AF_INET: - STREAM_GET(&prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); - STREAM_GETC(s, prefix.prefixlen); - if (prefix.prefixlen > IPV4_MAX_BITLEN) { - zlog_debug( - "%s: Specified prefix length %d is greater than a v4 address can support", - __PRETTY_FUNCTION__, prefix.prefixlen); - return; - } - STREAM_GET(&gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN); - break; - case AF_INET6: - STREAM_GET(&prefix.u.prefix6, s, 16); - STREAM_GETC(s, prefix.prefixlen); - if (prefix.prefixlen > IPV6_MAX_BITLEN) { - zlog_debug( - "%s: Specified prefix length %d is greater than a v6 address can support", - __PRETTY_FUNCTION__, prefix.prefixlen); - return; - } - STREAM_GET(&gate.ipv6, s, 16); - break; - default: - zlog_debug("%s: Specified AF %d is not supported for this call", - __PRETTY_FUNCTION__, prefix.family); + if (!mpls_enabled) return; + + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + znh->type, &znh->address, znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, + znh->type, &znh->address, znh->ifindex, + zl.route.type, zl.route.instance, + znh->label); } - STREAM_GETL(s, ifindex); - STREAM_GETC(s, distance); - STREAM_GETL(s, in_label); - STREAM_GETL(s, out_label); +} - switch (prefix.family) { - case AF_INET: - if (ifindex) - gtype = NEXTHOP_TYPE_IPV4_IFINDEX; - else - gtype = NEXTHOP_TYPE_IPV4; - break; - case AF_INET6: - if (ifindex) - gtype = NEXTHOP_TYPE_IPV6_IFINDEX; - else - gtype = NEXTHOP_TYPE_IPV6; - break; - default: +/* + * Handle request to delete an MPLS LSP. + * + * An LSP is identified by its type and local label. When the received message + * doesn't contain any nexthop, the whole LSP is deleted. Otherwise, only the + * listed LSP nexthops (aka NHLFEs) are deleted. + * + * When the optional ZAPI_LABELS_FTN flag is set, the labels of the specified + * FEC (route) nexthops are deleted. + */ +static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_labels zl; + + /* Get input stream. */ + s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); return; } if (!mpls_enabled) return; - if (hdr->command == ZEBRA_MPLS_LABELS_ADD) { - mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, - ifindex); - mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, - distance, out_label); - } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) { - mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); - mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, - distance, out_label); + if (zl.nexthop_num > 0) { + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_uninstall(zvrf, zl.type, zl.local_label, + znh->type, &znh->address, + znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_update(0, zvrf, zl.type, + &zl.route.prefix, znh->type, + &znh->address, znh->ifindex, + zl.route.type, + zl.route.instance, znh->label); + } + } else { + mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix, + zl.route.type, zl.route.instance); + } +} + +/* + * Handle request to add an MPLS LSP or change an existing one. + * + * A single message can fully specify an LSP with multiple nexthops. + * + * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is + * updated to use the received label(s). + * + * NOTE: zebra will use route replace semantics (make-before-break) to update + * the LSP in the forwarding plane if that's supported by the underlying + * platform. + */ +static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_labels zl; + + /* Get input stream. */ + s = msg; + if (zapi_labels_decode(s, &zl) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_labels sent", + __PRETTY_FUNCTION__); + return; + } + + if (!mpls_enabled) + return; + + mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label); + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) + mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix, + zl.route.type, zl.route.instance); + + for (int i = 0; i < zl.nexthop_num; i++) { + struct zapi_nexthop_label *znh; + + znh = &zl.nexthops[i]; + mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + znh->type, &znh->address, znh->ifindex); + + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) { + mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, + znh->type, &znh->address, znh->ifindex, + zl.route.type, zl.route.instance, + znh->label); + } } -stream_failure: - return; } /* Send response to a table manager connect request to client */ @@ -2455,8 +2514,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_INTERFACE_ENABLE_RADV] = NULL, [ZEBRA_INTERFACE_DISABLE_RADV] = NULL, #endif - [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels, - [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels, + [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add, + [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete, + [ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace, [ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats, [ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request, [ZEBRA_LABEL_MANAGER_CONNECT_ASYNC] = zread_label_manager_request, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 884edfef04..996a255ff4 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -65,7 +65,8 @@ extern int zsend_interface_update(int cmd, struct zserv *client, extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct prefix *p, const struct prefix *src_p, - struct route_entry *re); + const struct route_entry *re); + extern int zsend_router_id_update(struct zserv *zclient, struct prefix *p, vrf_id_t vrf_id); extern int zsend_interface_vrf_update(struct zserv *zclient, diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 4144c0afe0..5d88d4eeb4 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -711,7 +711,6 @@ static void zfpm_connection_down(const char *detail) * Start thread to clean up state after the connection goes down. */ assert(!zfpm_g->t_conn_down); - zfpm_debug("Starting conn_down thread"); zfpm_rnodes_iter_init(&zfpm_g->t_conn_down_state.iter); zfpm_g->t_conn_down = NULL; thread_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, @@ -806,8 +805,6 @@ static int zfpm_read_cb(struct thread *thread) goto done; } - zfpm_debug("Read out a full fpm message"); - /* * Just throw it away for now. */ @@ -1249,7 +1246,7 @@ static int zfpm_connect_cb(struct thread *t) sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - zfpm_debug("Failed to create socket for connect(): %s", + zlog_err("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; return 0; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 5214f1f22d..8088ec1bfe 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -34,6 +34,7 @@ #include "routemap.h" #include "stream.h" #include "nexthop.h" +#include "termtable.h" #include "lib/json.h" #include "zebra/rib.h" @@ -124,6 +125,9 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, static int snhlfe_del(zebra_snhlfe_t *snhlfe); static int snhlfe_del_all(zebra_slsp_t *slsp); static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); +static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt); +static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, + int afi, enum lsp_types_t lsp_type); /* Static functions */ @@ -1111,6 +1115,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size) inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size); break; case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size); break; case NEXTHOP_TYPE_IFINDEX: @@ -2294,6 +2299,42 @@ static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client) return 0; } +struct lsp_uninstall_args { + struct hash *lsp_table; + enum lsp_types_t type; +}; + +/* + * Cleanup MPLS labels registered by this client. + */ +static int zebra_mpls_cleanup_zclient_labels(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + struct lsp_uninstall_args args; + + zvrf = vrf->info; + if (!zvrf) + continue; + + /* Cleanup LSPs. */ + args.lsp_table = zvrf->lsp_table; + args.type = lsp_type_from_re_type(client->proto); + hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type, + &args); + + /* Cleanup FTNs. */ + mpls_ftn_uninstall_all(zvrf, AFI_IP, + lsp_type_from_re_type(client->proto)); + mpls_ftn_uninstall_all(zvrf, AFI_IP6, + lsp_type_from_re_type(client->proto)); + } + + return 0; +} + /* * Return FEC (if any) to which this label is bound. * Note: Only works for per-prefix binding and when the label is not @@ -2542,8 +2583,8 @@ static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, */ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct prefix *prefix, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, uint8_t distance, - mpls_label_t out_label) + union g_addr *gate, ifindex_t ifindex, uint8_t route_type, + unsigned short route_instance, mpls_label_t out_label) { struct route_table *table; struct route_node *rn; @@ -2562,7 +2603,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, RNODE_FOREACH_RE (rn, re) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) continue; - if (re->distance == distance) + if (re->type == route_type && re->instance == route_instance) break; } @@ -2617,6 +2658,42 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, return 0; } +int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + unsigned short route_instance) +{ + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + struct nexthop *nexthop; + + /* Lookup table. */ + table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, + zvrf_id(zvrf)); + if (!table) + return -1; + + /* Lookup existing route */ + rn = route_node_get(table, prefix); + RNODE_FOREACH_RE (rn, re) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + if (re->type == route_type && re->instance == route_instance) + break; + } + if (re == NULL) + return -1; + + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) + nexthop_del_labels(nexthop); + + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + rib_queue_add(rn); + + return 0; +} + /* * Install/update a NHLFE for an LSP in the forwarding table. This may be * a new LSP entry or a new NHLFE for an existing in-label or an update of @@ -2749,12 +2826,34 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, return 0; } +int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* If entry is not present, exit. */ + tmp_ile.in_label = in_label; + lsp = hash_lookup(lsp_table, &tmp_ile); + if (!lsp) + return 0; + + return mpls_lsp_uninstall_all(lsp_table, lsp, type); +} + /* - * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. + * Uninstall all NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) +static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt) { + struct lsp_uninstall_args *args = ctxt; zebra_lsp_t *lsp; struct hash *lsp_table; @@ -2762,17 +2861,19 @@ void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) if (!lsp->nhlfe_list) return; - lsp_table = ctxt; + lsp_table = args->lsp_table; if (!lsp_table) return; - mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP); + mpls_lsp_uninstall_all(lsp_table, lsp, args->type); } /* - * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. + * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and + * LSP type. */ -void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) +static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, + int afi, enum lsp_types_t lsp_type) { struct route_table *table; struct route_node *rn; @@ -2790,7 +2891,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) RNODE_FOREACH_RE (rn, re) { for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { - if (nexthop->nh_label_type != ZEBRA_LSP_LDP) + if (nexthop->nh_label_type != lsp_type) continue; nexthop_del_labels(nexthop); @@ -3047,7 +3148,6 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, json_object *json = NULL; zebra_lsp_t *lsp = NULL; zebra_nhlfe_t *nhlfe = NULL; - struct nexthop *nexthop = NULL; struct listnode *node = NULL; struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp); @@ -3063,15 +3163,23 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } else { - vty_out(vty, " Inbound Outbound\n"); - vty_out(vty, " Label Type Nexthop Label\n"); - vty_out(vty, "-------- ------- --------------- --------\n"); + struct ttable *tt; + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) { for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { - vty_out(vty, "%8d %7s ", lsp->ile.in_label, - nhlfe_type2str(nhlfe->type)); + struct nexthop *nexthop; + const char *out_label_str; + char nh_buf[NEXTHOP_STRLEN]; + nexthop = nhlfe->nexthop; switch (nexthop->type) { @@ -3081,45 +3189,47 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, zns = zebra_ns_lookup(NS_DEFAULT); ifp = if_lookup_by_index_per_ns( - zns, - nexthop->ifindex); - if (ifp) - vty_out(vty, "%15s", ifp->name); - else - vty_out(vty, "%15s", "Null"); - + zns, nexthop->ifindex); + snprintf(nh_buf, sizeof(nh_buf), "%s", + ifp ? ifp->name : "Null"); break; } case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, "%15s", - inet_ntoa(nexthop->gate.ipv4)); + inet_ntop(AF_INET, &nexthop->gate.ipv4, + nh_buf, sizeof(nh_buf)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, "%15s", - inet_ntop(AF_INET6, - &nexthop->gate.ipv6, - buf, BUFSIZ)); + inet_ntop(AF_INET6, &nexthop->gate.ipv6, + nh_buf, sizeof(nh_buf)); break; default: break; } if (nexthop->type != NEXTHOP_TYPE_IFINDEX) - vty_out(vty, " %8s\n", - mpls_label2str( - nexthop->nh_label - ->num_labels, - &nexthop->nh_label - ->label[0], - buf, BUFSIZ, 1)); + out_label_str = mpls_label2str( + nexthop->nh_label->num_labels, + &nexthop->nh_label->label[0], + buf, BUFSIZ, 1); else - vty_out(vty, "\n"); + out_label_str = "-"; + + ttable_add_row(tt, "%u|%s|%s|%s", + lsp->ile.in_label, + nhlfe_type2str(nhlfe->type), + nh_buf, out_label_str); } } - vty_out(vty, "\n"); + /* Dump the generated table. */ + if (tt->nrows > 1) { + char *table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } + ttable_del(tt); } list_delete(&lsp_list); @@ -3289,4 +3399,5 @@ void zebra_mpls_init(void) mpls_enabled = 1; hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); + hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels); } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index d983221cb5..157f43ca98 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -269,8 +269,15 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, */ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct prefix *prefix, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, uint8_t distance, - mpls_label_t out_label); + union g_addr *gate, ifindex_t ifindex, uint8_t route_type, + unsigned short route_instance, mpls_label_t out_label); + +/* + * Uninstall all NHLFEs bound to a single FEC. + */ +int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + unsigned short route_instance); /* * Install/update a NHLFE for an LSP in the forwarding table. This may be @@ -291,15 +298,10 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, union g_addr *gate, ifindex_t ifindex); /* - * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. - * If no other NHLFEs exist, the entry would be deleted. - */ -void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); - -/* - * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. + * Uninstall all NHLFEs for a particular LSP forwarding entry. */ -void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi); +int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label); /* * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry. @@ -426,7 +428,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type) return (route_distance(ZEBRA_ROUTE_BGP)); case ZEBRA_LSP_NONE: case ZEBRA_LSP_SHARP: - case ZEBRA_LSP_SR: + case ZEBRA_LSP_OSPF_SR: return 150; } @@ -448,8 +450,12 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type) switch (re_type) { case ZEBRA_ROUTE_STATIC: return ZEBRA_LSP_STATIC; + case ZEBRA_ROUTE_LDP: + return ZEBRA_LSP_LDP; case ZEBRA_ROUTE_BGP: return ZEBRA_LSP_BGP; + case ZEBRA_ROUTE_OSPF: + return ZEBRA_LSP_OSPF_SR; case ZEBRA_ROUTE_SHARP: return ZEBRA_LSP_SHARP; default: @@ -469,7 +475,7 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type) return ZEBRA_ROUTE_LDP; case ZEBRA_LSP_BGP: return ZEBRA_ROUTE_BGP; - case ZEBRA_LSP_SR: + case ZEBRA_LSP_OSPF_SR: return ZEBRA_ROUTE_OSPF; case ZEBRA_LSP_NONE: return ZEBRA_ROUTE_KERNEL; @@ -496,8 +502,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type) return "LDP"; case ZEBRA_LSP_BGP: return "BGP"; - case ZEBRA_LSP_SR: - return "SR"; + case ZEBRA_LSP_OSPF_SR: + return "SR (OSPF)"; case ZEBRA_LSP_SHARP: return "SHARP"; case ZEBRA_LSP_NONE: diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 157c67fa62..5428b6eaef 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -691,7 +691,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) srcdest_rnode_prefixes(rn, &p, &src_p); - redistribute_delete(p, src_p, re); + redistribute_delete(p, src_p, re, NULL); UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); } } @@ -1248,8 +1248,17 @@ static void rib_process(struct route_node *rn) SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED); if (old_selected) { - if (!new_selected) - redistribute_delete(p, src_p, old_selected); + /* + * If we're removing the old entry, we should tell + * redist subscribers about that *if* they aren't + * going to see a redist for the new entry. + */ + if (!new_selected || CHECK_FLAG(old_selected->status, + ROUTE_ENTRY_REMOVED)) + redistribute_delete(p, src_p, + old_selected, + new_selected); + if (old_selected != new_selected) UNSET_FLAG(old_selected->flags, ZEBRA_FLAG_SELECTED); @@ -2026,7 +2035,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx); /* Redistribute, lsp, and nht update */ - redistribute_delete(dest_pfx, src_pfx, re); + redistribute_delete(dest_pfx, src_pfx, re, NULL); zebra_rib_evaluate_rn_nexthops( rn, zebra_router_get_next_sequence()); @@ -2088,14 +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 @@ -3294,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..5df5d94f4b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -337,7 +337,7 @@ static void addr2hostprefix(int af, const union g_addr *addr, break; default: memset(prefix, 0, sizeof(*prefix)); - zlog_debug("%s: unknown address family %d", __func__, af); + zlog_warn("%s: unknown address family %d", __func__, af); break; } } @@ -916,7 +916,8 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, table = get_rnh_table(vrfid, afi, type); if (!table) { - zlog_debug("print_rnhs: rnh table not found"); + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("print_rnhs: rnh table not found"); return; } @@ -1198,13 +1199,6 @@ static int zebra_client_cleanup_rnh(struct zserv *client) RNH_IMPORT_CHECK_TYPE); zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, RNH_IMPORT_CHECK_TYPE); - if (client->proto == ZEBRA_ROUTE_LDP) { - hash_iterate(zvrf->lsp_table, - mpls_ldp_lsp_uninstall_all, - zvrf->lsp_table); - mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP); - mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP6); - } } } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 88d2091394..364f5755d8 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -78,11 +78,6 @@ static int zebra_route_match_add(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_ADDED) { - route_map_upd8_dependency(type, arg, index->map->name); - } - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ @@ -116,7 +111,7 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); } - ret = route_map_delete_match(index, command, arg); + ret = route_map_delete_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% Zebra Can't find rule.\n"); @@ -127,10 +122,6 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - if (type != RMAP_EVENT_MATCH_DELETED && dep_name) - route_map_upd8_dependency(type, dep_name, rmap_name); - break; - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 72d0b6866d..4f1868311c 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -92,7 +92,7 @@ static int zebra_vrf_new(struct vrf *vrf) struct zebra_vrf *zvrf; if (IS_ZEBRA_DEBUG_EVENT) - zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id); + zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id); zvrf = zebra_vrf_alloc(); vrf->info = zvrf; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7984481093..15f0398ca4 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -394,6 +394,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + struct vrf *vrf = NULL; rib_dest_t *dest = rib_dest_from_rnode(rn); struct nexthop_group *nhg; @@ -422,9 +423,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "instance", re->instance); - if (re->vrf_id) + if (re->vrf_id) { json_object_int_add(json_route, "vrfId", re->vrf_id); + vrf = vrf_lookup_by_id(re->vrf_id); + json_object_string_add(json_route, "vrfName", + vrf->name); + } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); @@ -565,9 +570,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if ((nexthop->vrf_id != re->vrf_id) && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { - struct vrf *vrf = - vrf_lookup_by_id(nexthop->vrf_id); - + vrf = vrf_lookup_by_id(nexthop->vrf_id); json_object_string_add(json_nexthop, "vrf", vrf->name); } |
