diff options
65 files changed, 2292 insertions, 1564 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..feb9827ce1 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,59 @@ 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); + + pthread_rwlock_wrlock(&running_config->lock); + { + 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++; + } + pthread_rwlock_unlock(&running_config->lock); + } + } + 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..248bbca8cf 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -519,8 +519,7 @@ unsigned int attrhash_key_make(const void *p) MIX(attr->mp_nexthop_len); key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); - MIX(attr->nh_ifindex); - MIX(attr->nh_lla_ifindex); + MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance); return key; } @@ -562,7 +561,8 @@ bool attrhash_cmp(const void *p1, const void *p2) &attr2->originator_id) && overlay_index_same(attr1, attr2) && attr1->nh_ifindex == attr2->nh_ifindex - && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex) + && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex + && attr1->distance == attr2->distance) return true; } @@ -1685,8 +1685,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, #define BGP_MP_REACH_MIN_SIZE 5 #define LEN_LEFT (length - (stream_get_getp(s) - start)) if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) { - zlog_info("%s: %s sent invalid length, %lu", __func__, - peer->host, (unsigned long)length); + zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI", + __func__, peer->host, (unsigned long)length); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1702,7 +1702,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, */ if (bgp_debug_update(peer, NULL, NULL, 0)) zlog_debug( - "%s: MP_REACH received AFI %s or SAFI %s is unrecognized", + "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI", peer->host, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); return BGP_ATTR_PARSE_ERROR; @@ -1713,7 +1713,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, if (LEN_LEFT < attr->mp_nexthop_len) { zlog_info( - "%s: %s, MP nexthop length, %u, goes past end of attribute", + "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1722,7 +1722,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, switch (attr->mp_nexthop_len) { case 0: if (safi != SAFI_FLOWSPEC) { - zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", + zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1754,7 +1754,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1771,7 +1771,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1789,7 +1789,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, if (bgp_debug_update(peer, NULL, NULL, 1)) zlog_debug( - "%s rcvd nexthops %s, %s -- ignoring non-LL value", + "%s sent next-hops %s and %s. Ignoring non-LL value", peer->host, inet_ntop(AF_INET6, &attr->mp_nexthop_global, @@ -1801,21 +1801,21 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } if (!peer->nexthop.ifp) { - zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing", + zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex; break; default: - zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", + zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI", __func__, peer->host, attr->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!LEN_LEFT) { - zlog_info("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, - peer->host); + zlog_info("%s: %s sent SNPA which couldn't be read", + __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } @@ -1831,12 +1831,13 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, /* must have nrli_len, what is left of the attribute */ nlri_len = LEN_LEFT; if (nlri_len > STREAM_READABLE(s)) { - zlog_info("%s: (%s) Failed to read NLRI", __func__, peer->host); + zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read", + __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!nlri_len) { - zlog_info("%s: (%s) No Reachability, Treating as a EOR marker", + zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker", __func__, peer->host); mp_update->afi = afi; @@ -2043,8 +2044,8 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ length -= 4; if (tlv_length != length) { - zlog_info("%s: tlv_length(%d) != length(%d)", __func__, - tlv_length, length); + zlog_info("%s: tlv_length(%d) != length(%d)", + __func__, tlv_length, length); } } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 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_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_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 962f0b3375..05974bb2ba 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -11877,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 da702ec857..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, @@ -3076,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. */ @@ -3114,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"); @@ -3125,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 */ @@ -4064,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, @@ -5119,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); @@ -5172,6 +5226,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd); install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd); install_element(RMAP_NODE, &set_local_pref_cmd); + install_element(RMAP_NODE, &set_distance_cmd); + install_element(RMAP_NODE, &no_set_distance_cmd); install_element(RMAP_NODE, &no_set_local_pref_cmd); install_element(RMAP_NODE, &set_weight_cmd); install_element(RMAP_NODE, &set_label_index_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 2cfd65896c..352e3b87e8 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1420,7 +1420,6 @@ DEFUN (match_rpki, vty_out(vty, "%% BGP Argument is malformed.\n"); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Intentionally doing nothing here */ @@ -1443,7 +1442,8 @@ DEFUN (no_match_rpki, VTY_DECLVAR_CONTEXT(route_map_index, index); enum rmap_compile_rets ret; - ret = route_map_delete_match(index, "rpki", argv[3]->arg); + ret = route_map_delete_match(index, "rpki", argv[3]->arg, + RMAP_EVENT_MATCH_DELETED); if (ret) { switch (ret) { case RMAP_RULE_MISSING: @@ -1453,7 +1453,6 @@ DEFUN (no_match_rpki, vty_out(vty, "%% BGP Argument is malformed.\n"); break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Nothing to do here */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5b31fbb3a8..e815334bfc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2053,7 +2053,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info( + zlog_debug( "peer(s) are now active for labeled-unicast, allocate MPLS labels"); bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1; @@ -2156,7 +2156,7 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) && !bgp_afi_safi_peer_exists(bgp, afi, safi)) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info( + zlog_debug( "peer(s) are no longer active for labeled-unicast, deallocate MPLS labels"); bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0; @@ -7931,8 +7931,6 @@ static void bgp_pthreads_init(void) assert(!bgp_pth_io); assert(!bgp_pth_ka); - frr_pthread_init(); - struct frr_pthread_attr io = { .start = frr_pthread_attr_default.start, .stop = frr_pthread_attr_default.stop, @@ -7958,7 +7956,6 @@ void bgp_pthreads_run(void) void bgp_pthreads_finish(void) { frr_pthread_stop_all(); - frr_pthread_finish(); } void bgp_init(unsigned short instance) diff --git a/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/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/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index d78588644f..e7a7cc56aa 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -148,7 +148,6 @@ static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * Intentionally not handling these cases */ @@ -165,7 +164,7 @@ static int eigrp_route_match_delete(struct vty *vty, { enum rmap_compile_rets ret; - ret = route_map_delete_match(index, command, arg); + ret = route_map_delete_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: vty_out(vty, "%% Can't find rule.\n"); @@ -176,7 +175,6 @@ static int eigrp_route_match_delete(struct vty *vty, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally ignored */ @@ -211,7 +209,6 @@ static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index, } break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally left blank here */ @@ -239,7 +236,6 @@ static int eigrp_route_set_delete(struct vty *vty, return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: /* * These cases intentionally not handled */ diff --git a/fpm/subdir.am b/fpm/subdir.am index a0fa3d274f..a645ca2b03 100644 --- a/fpm/subdir.am +++ b/fpm/subdir.am @@ -12,9 +12,13 @@ fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm_pb.c \ # end +if FPM +if HAVE_PROTOBUF nodist_fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm.pb-c.c \ # end +endif +endif CLEANFILES += \ fpm/fpm.pb-c.c \ diff --git a/grpc/subdir.am b/grpc/subdir.am index 3fb163fccf..048e12a024 100644 --- a/grpc/subdir.am +++ b/grpc/subdir.am @@ -5,10 +5,12 @@ endif grpc_libfrrgrpc_pb_la_LDFLAGS = -version-info 0:0:0 grpc_libfrrgrpc_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(GRPC_CXXFLAGS) +if GRPC nodist_grpc_libfrrgrpc_pb_la_SOURCES = \ grpc/frr-northbound.pb.cc \ grpc/frr-northbound.grpc.pb.cc \ # end +endif CLEANFILES += \ grpc/frr-northbound.pb.cc \ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 8d008d78bd..5da8e6ee9e 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -135,8 +135,6 @@ struct isis_circuit *isis_circuit_new(void) } #endif /* ifndef FABRICD */ - circuit->mtc = mpls_te_circuit_new(); - circuit_mt_init(circuit); QOBJ_REG(circuit, isis_circuit); @@ -266,8 +264,11 @@ void isis_circuit_add_addr(struct isis_circuit *circuit, ipv4->prefix = connected->address->u.prefix4; listnode_add(circuit->ip_addrs, ipv4); - /* Update MPLS TE Local IP address parameter */ - set_circuitparams_local_ipaddr(circuit->mtc, ipv4->prefix); + /* Update Local IP address parameter if MPLS TE is enable */ + if (circuit->ext && IS_MPLS_TE(circuit->ext)) { + circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr; + SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR); + } if (circuit->area) lsp_regenerate_schedule(circuit->area, circuit->is_type, @@ -478,6 +479,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) isis_circuit_add_addr(circuit, conn); + } void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) @@ -521,7 +523,6 @@ void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp) assert(ifp->info == circuit); else ifp->info = circuit; - isis_link_params_update(circuit, ifp); } void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp) diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 2371c0b73a..e3541644aa 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -121,7 +121,7 @@ struct isis_circuit { uint16_t psnp_interval[2]; /* psnp-interval in seconds */ uint8_t metric[2]; uint32_t te_metric[2]; - struct mpls_te_circuit *mtc; /* MPLS-TE parameters */ + struct isis_ext_subtlvs *ext; /* Extended parameters (TE + Adj SID */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *mt_settings; /* IS-IS MT Settings */ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 4b29e6dc7e..061e758831 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -52,9 +52,9 @@ #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" -#include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_tlvs.h" +#include "isisd/isis_te.h" #include "isisd/fabricd.h" #include "isisd/isis_tx_queue.h" @@ -781,8 +781,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, if (!rn->info) continue; struct isis_ext_info *info = rn->info; - struct prefix_ipv6 *p, *src_p; + srcdest_rnode_prefixes(rn, (const struct prefix **)&p, (const struct prefix **)&src_p); @@ -863,6 +863,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) /* Protocols Supported */ if (area->ip_circuits > 0 || area->ipv6_circuits > 0) { struct nlpids nlpids = {.count = 0}; + if (area->ip_circuits > 0) { lsp_debug( "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", @@ -908,10 +909,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag); } - /* IPv4 address and TE router ID TLVs. In case of the first one we don't - * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put - * into - * LSP and this address is same as router id. */ + /* IPv4 address and TE router ID TLVs. + * In case of the first one we don't follow "C" vendor, + * but "J" vendor behavior - one IPv4 address is put + * into LSP. TE router ID will be the same if MPLS-TE + * is not activate or MPLS-TE router-id not specified + */ if (isis->router_id != 0) { struct in_addr id = {.s_addr = isis->router_id}; inet_ntop(AF_INET, &id, buf, sizeof(buf)); @@ -919,11 +922,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag, buf); isis_tlvs_add_ipv4_address(lsp->tlvs, &id); - /* Exactly same data is put into TE router ID TLV, but only if - * new style - * TLV's are in use. */ + /* If new style TLV's are in use, add TE router ID TLV + * Check if MPLS-TE is activate and mpls-te router-id set + * otherwise add exactly same data as for IPv4 address + */ if (area->newmetric) { - + if (IS_MPLS_TE(area->mta) + && area->mta->router_id.s_addr != 0) + id.s_addr = area->mta->router_id.s_addr; lsp_debug( "ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); @@ -1004,6 +1010,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) && circuit->ipv6_non_link->count > 0) { struct listnode *ipnode; struct prefix_ipv6 *ipv6; + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, ipnode, ipv6)) { lsp_debug( @@ -1036,25 +1043,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } - if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface - && HAS_LINK_PARAMS( - circuit->interface)) - subtlv_len = add_te_subtlvs( - subtlvs, - circuit->mtc); - else - subtlv_len = 0; - + if (area->newmetric) tlvs_add_mt_bcast( lsp->tlvs, circuit, - level, ne_id, metric, - subtlvs, subtlv_len); - } + level, ne_id, metric); } } else { lsp_debug( @@ -1079,36 +1071,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) lsp->tlvs, ne_id, metric); } if (area->newmetric) { - uint8_t subtlvs[256]; - uint8_t subtlv_len; - - if (IS_MPLS_TE(area->mta) - && circuit->interface != NULL - && HAS_LINK_PARAMS( - circuit->interface)) - /* Update Local and Remote IP - * address for MPLS TE circuit - * parameters */ - /* NOTE sure that it is the - * pertinent place for that - * updates */ - /* Local IP address could be - * updated in isis_circuit.c - - * isis_circuit_add_addr() */ - /* But, where update remote IP - * address ? in isis_pdu.c - - * process_p2p_hello() ? */ - - /* Add SubTLVs & Adjust real - * size of SubTLVs */ - subtlv_len = add_te_subtlvs( - subtlvs, circuit->mtc); - else - /* Or keep only TE metric with - * no SubTLVs if MPLS_TE is off - */ - subtlv_len = 0; - uint32_t neighbor_metric; if (fabricd_tier(area) == 0) { neighbor_metric = 0xffe; @@ -1117,8 +1079,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } tlvs_add_mt_p2p(lsp->tlvs, circuit, - ne_id, neighbor_metric, - subtlvs, subtlv_len); + ne_id, neighbor_metric); } } else { lsp_debug( @@ -1512,7 +1473,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, } if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (self)", area->area_tag, sysid_print(ne_id), @@ -1554,7 +1515,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, if (circuit->area->newmetric) { isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, - ne_id, 0, NULL, 0); + ne_id, 0, circuit->ext); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", area->area_tag, sysid_print(ne_id), diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index f7d4c7170f..36413bac59 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -511,8 +511,8 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level, static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, unsigned int mt_count, uint16_t *mt_set, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric, + struct isis_ext_subtlvs *ext) { for (unsigned int i = 0; i < mt_count; i++) { uint16_t mtid = mt_set[i]; @@ -527,30 +527,27 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, area->area_tag, sysid_print(id), LSP_PSEUDO_ID(id), isis_mtid2str(mtid)); } - isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs, - subtlv_len); + isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, ext); } } void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len) + int level, uint8_t *id, uint32_t metric) { unsigned int mt_count; uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count); tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric, - subtlvs, subtlv_len); + circuit->ext); } void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len) + uint8_t *id, uint32_t metric) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id, - metric, subtlvs, subtlv_len); + metric, circuit->ext); } void mt_init(void) diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 515b63f50f..b40139c50a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -116,10 +116,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid); void adj_mt_finish(struct isis_adjacency *adj); void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - int level, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len); + int level, uint8_t *id, uint32_t metric); void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, - uint8_t *id, uint32_t metric, uint8_t *subtlvs, - uint8_t subtlv_len); + uint8_t *id, uint32_t metric); void mt_init(void); #endif diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index c1b630eb2d..bd61918697 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -1384,7 +1384,7 @@ static int isis_instance_mpls_te_create(enum nb_event event, struct mpls_te_area *new; - zlog_debug("ISIS MPLS-TE: Initialize area %s", + zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering", area->area_tag); new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area)); @@ -1410,12 +1410,12 @@ static int isis_instance_mpls_te_create(enum nb_event event, * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || IS_FLOOD_AS(circuit->mtc->type)) + if (circuit->ext == NULL) continue; - if (!IS_MPLS_TE(circuit->mtc) + if (!IS_EXT_TE(circuit->ext) && HAS_LINK_PARAMS(circuit->interface)) - circuit->mtc->status = enable; + isis_link_params_update(circuit, circuit->interface); else continue; @@ -1446,11 +1446,16 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, /* Flush LSP if circuit engage */ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { - if (circuit->mtc == NULL || (circuit->mtc->status == disable)) + if (!IS_EXT_TE(circuit->ext)) continue; - /* disable MPLS_TE Circuit */ - circuit->mtc->status = disable; + /* disable MPLS_TE Circuit keeping SR one's */ + if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID)) + circuit->ext->status = EXT_ADJ_SID; + else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID)) + circuit->ext->status = EXT_LAN_ADJ_SID; + else + circuit->ext->status = 0; /* Re-originate circuit without STD_TE & GMPLS parameters */ if (circuit->area) @@ -1458,6 +1463,9 @@ static int isis_instance_mpls_te_destroy(enum nb_event event, 0); } + zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering", + area->area_tag); + return NB_OK; } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 3d16d56016..ecfce392ff 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -199,13 +199,6 @@ static int process_p2p_hello(struct iih_info *iih) changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, adj); - /* Update MPLS TE Remote IP address parameter if possible */ - if (IS_MPLS_TE(iih->circuit->area->mta) - && IS_MPLS_TE(iih->circuit->mtc) - && adj->ipv4_address_count) - set_circuitparams_rmt_ipaddr(iih->circuit->mtc, - adj->ipv4_addresses[0]); - /* lets take care of the expiry */ THREAD_TIMER_OFF(adj->t_expire); thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 636a63e290..05394e0fe4 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -49,8 +49,16 @@ #include "isis_route.h" #include "isis_zebra.h" +DEFINE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family, union g_addr *ip, ifindex_t ifindex); +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip, ifindex_t ifindex) @@ -316,7 +324,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, return route_info; } -static void isis_route_delete(struct route_node *rode, +static void isis_route_delete(struct isis_area *area, struct route_node *rode, struct route_table *table) { struct isis_route_info *rinfo; @@ -343,13 +351,37 @@ static void isis_route_delete(struct route_node *rode, UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug("ISIS-Rte: route delete %s", buff); - isis_zebra_route_update(prefix, src_p, rinfo); + isis_route_update(area, prefix, src_p, rinfo); } isis_route_info_delete(rinfo); rode->info = NULL; route_unlock_node(rode); } +static void isis_route_update(struct isis_area *area, struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) +{ + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_add_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + } else { + if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + + isis_zebra_route_del_route(prefix, src_p, route_info); + hook_call(isis_route_update_hook, area, prefix, route_info); + + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + } +} + static void _isis_route_verify_table(struct isis_area *area, struct route_table *table, struct route_table **tables) @@ -390,7 +422,7 @@ static void _isis_route_verify_table(struct isis_area *area, buff); } - isis_zebra_route_update(dst_p, src_p, rinfo); + isis_route_update(area, dst_p, src_p, rinfo); if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) continue; @@ -399,7 +431,7 @@ static void _isis_route_verify_table(struct isis_area *area, * directly for * validating => no problems with deleting routes. */ if (!tables) { - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); continue; } @@ -422,7 +454,7 @@ static void _isis_route_verify_table(struct isis_area *area, route_unlock_node(drnode); } - isis_route_delete(rnode, table); + isis_route_delete(area, rnode, table); } } diff --git a/isisd/isis_route.h b/isisd/isis_route.h index a20a7e038f..2326bb8228 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -44,6 +44,11 @@ struct isis_route_info { struct list *nexthops; }; +DECLARE_HOOK(isis_route_update_hook, + (struct isis_area * area, struct prefix *prefix, + struct isis_route_info *route_info), + (area, prefix, route_info)) + struct isis_route_info *isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p, uint32_t cost, diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 4ea6c2c60d..44fa45d02b 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -3,8 +3,9 @@ * * This is an implementation of RFC5305 & RFC 7810 * - * Copyright (C) 2014 Orange Labs - * http://www.orange.com + * Author: Olivier Dugeon <olivier.dugeon@orange.com> + * + * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com * * This file is part of GNU Zebra. * @@ -47,6 +48,7 @@ #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" +#include "isisd/isis_adjacency.h" #include "isisd/isisd.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" @@ -56,6 +58,7 @@ #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_te.h" +#include "isisd/isis_zebra.h" const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; @@ -63,424 +66,6 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ -/* Create new MPLS TE Circuit context */ -struct mpls_te_circuit *mpls_te_circuit_new(void) -{ - struct mpls_te_circuit *mtc; - - zlog_debug("ISIS MPLS-TE: Create new MPLS TE Circuit context"); - - mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_circuit)); - - mtc->status = disable; - mtc->type = STD_TE; - mtc->length = 0; - - return mtc; -} - -/* Copy SUB TLVs parameters into a buffer - No space verification are performed - */ -/* Caller must verify before that there is enough free space in the buffer */ -uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc) -{ - uint8_t size, *tlvs = buf; - - zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); - - if (mtc == NULL) { - zlog_debug( - "ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified"); - return 0; - } - - /* Create buffer if not provided */ - if (buf == NULL) { - zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified"); - return 0; - } - - /* TE_SUBTLV_ADMIN_GRP */ - if (SUBTLV_TYPE(mtc->admin_grp) != 0) { - size = SUBTLV_SIZE(&(mtc->admin_grp.header)); - memcpy(tlvs, &(mtc->admin_grp), size); - tlvs += size; - } - - /* TE_SUBTLV_LLRI */ - if (SUBTLV_TYPE(mtc->llri) != 0) { - size = SUBTLV_SIZE(&(mtc->llri.header)); - memcpy(tlvs, &(mtc->llri), size); - tlvs += size; - } - - /* TE_SUBTLV_LCLIF_IPADDR */ - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) { - size = SUBTLV_SIZE(&(mtc->local_ipaddr.header)); - memcpy(tlvs, &(mtc->local_ipaddr), size); - tlvs += size; - } - - /* TE_SUBTLV_RMTIF_IPADDR */ - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) { - size = SUBTLV_SIZE(&(mtc->rmt_ipaddr.header)); - memcpy(tlvs, &(mtc->rmt_ipaddr), size); - tlvs += size; - } - - /* TE_SUBTLV_MAX_BW */ - if (SUBTLV_TYPE(mtc->max_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->max_bw.header)); - memcpy(tlvs, &(mtc->max_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_MAX_RSV_BW */ - if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->max_rsv_bw.header)); - memcpy(tlvs, &(mtc->max_rsv_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_UNRSV_BW */ - if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->unrsv_bw.header)); - memcpy(tlvs, &(mtc->unrsv_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_TE_METRIC */ - if (SUBTLV_TYPE(mtc->te_metric) != 0) { - size = SUBTLV_SIZE(&(mtc->te_metric.header)); - memcpy(tlvs, &(mtc->te_metric), size); - tlvs += size; - } - - /* TE_SUBTLV_AV_DELAY */ - if (SUBTLV_TYPE(mtc->av_delay) != 0) { - size = SUBTLV_SIZE(&(mtc->av_delay.header)); - memcpy(tlvs, &(mtc->av_delay), size); - tlvs += size; - } - - /* TE_SUBTLV_MM_DELAY */ - if (SUBTLV_TYPE(mtc->mm_delay) != 0) { - size = SUBTLV_SIZE(&(mtc->mm_delay.header)); - memcpy(tlvs, &(mtc->mm_delay), size); - tlvs += size; - } - - /* TE_SUBTLV_DELAY_VAR */ - if (SUBTLV_TYPE(mtc->delay_var) != 0) { - size = SUBTLV_SIZE(&(mtc->delay_var.header)); - memcpy(tlvs, &(mtc->delay_var), size); - tlvs += size; - } - - /* TE_SUBTLV_PKT_LOSS */ - if (SUBTLV_TYPE(mtc->pkt_loss) != 0) { - size = SUBTLV_SIZE(&(mtc->pkt_loss.header)); - memcpy(tlvs, &(mtc->pkt_loss), size); - tlvs += size; - } - - /* TE_SUBTLV_RES_BW */ - if (SUBTLV_TYPE(mtc->res_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->res_bw.header)); - memcpy(tlvs, &(mtc->res_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_AVA_BW */ - if (SUBTLV_TYPE(mtc->ava_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->ava_bw.header)); - memcpy(tlvs, &(mtc->ava_bw), size); - tlvs += size; - } - - /* TE_SUBTLV_USE_BW */ - if (SUBTLV_TYPE(mtc->use_bw) != 0) { - size = SUBTLV_SIZE(&(mtc->use_bw.header)); - memcpy(tlvs, &(mtc->use_bw), size); - tlvs += size; - } - - /* Add before this line any other parsing of TLV */ - (void)tlvs; - - /* Update SubTLVs length */ - mtc->length = subtlvs_len(mtc); - - zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length); - - return mtc->length; -} - -/* Compute total Sub-TLVs size */ -uint8_t subtlvs_len(struct mpls_te_circuit *mtc) -{ - int length = 0; - - /* Sanity Check */ - if (mtc == NULL) - return 0; - - /* TE_SUBTLV_ADMIN_GRP */ - if (SUBTLV_TYPE(mtc->admin_grp) != 0) - length += SUBTLV_SIZE(&(mtc->admin_grp.header)); - - /* TE_SUBTLV_LLRI */ - if (SUBTLV_TYPE(mtc->llri) != 0) - length += SUBTLV_SIZE(&mtc->llri.header); - - /* TE_SUBTLV_LCLIF_IPADDR */ - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) - length += SUBTLV_SIZE(&mtc->local_ipaddr.header); - - /* TE_SUBTLV_RMTIF_IPADDR */ - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) - length += SUBTLV_SIZE(&mtc->rmt_ipaddr.header); - - /* TE_SUBTLV_MAX_BW */ - if (SUBTLV_TYPE(mtc->max_bw) != 0) - length += SUBTLV_SIZE(&mtc->max_bw.header); - - /* TE_SUBTLV_MAX_RSV_BW */ - if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) - length += SUBTLV_SIZE(&mtc->max_rsv_bw.header); - - /* TE_SUBTLV_UNRSV_BW */ - if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) - length += SUBTLV_SIZE(&mtc->unrsv_bw.header); - - /* TE_SUBTLV_TE_METRIC */ - if (SUBTLV_TYPE(mtc->te_metric) != 0) - length += SUBTLV_SIZE(&mtc->te_metric.header); - - /* TE_SUBTLV_AV_DELAY */ - if (SUBTLV_TYPE(mtc->av_delay) != 0) - length += SUBTLV_SIZE(&mtc->av_delay.header); - - /* TE_SUBTLV_MM_DELAY */ - if (SUBTLV_TYPE(mtc->mm_delay) != 0) - length += SUBTLV_SIZE(&mtc->mm_delay.header); - - /* TE_SUBTLV_DELAY_VAR */ - if (SUBTLV_TYPE(mtc->delay_var) != 0) - length += SUBTLV_SIZE(&mtc->delay_var.header); - - /* TE_SUBTLV_PKT_LOSS */ - if (SUBTLV_TYPE(mtc->pkt_loss) != 0) - length += SUBTLV_SIZE(&mtc->pkt_loss.header); - - /* TE_SUBTLV_RES_BW */ - if (SUBTLV_TYPE(mtc->res_bw) != 0) - length += SUBTLV_SIZE(&mtc->res_bw.header); - - /* TE_SUBTLV_AVA_BW */ - if (SUBTLV_TYPE(mtc->ava_bw) != 0) - length += SUBTLV_SIZE(&mtc->ava_bw.header); - - /* TE_SUBTLV_USE_BW */ - if (SUBTLV_TYPE(mtc->use_bw) != 0) - length += SUBTLV_SIZE(&mtc->use_bw.header); - - /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */ - if (length > MAX_SUBTLV_SIZE) { - mtc->length = 0; - return 0; - } - - mtc->length = (uint8_t)length; - - return mtc->length; -} - -/* Following are various functions to set MPLS TE parameters */ -static void set_circuitparams_admin_grp(struct mpls_te_circuit *mtc, - uint32_t admingrp) -{ - SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP; - SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE; - mtc->admin_grp.value = htonl(admingrp); - return; -} - -static void __attribute__((unused)) -set_circuitparams_llri(struct mpls_te_circuit *mtc, uint32_t local, - uint32_t remote) -{ - SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI; - SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE; - mtc->llri.local = htonl(local); - mtc->llri.remote = htonl(remote); -} - -void set_circuitparams_local_ipaddr(struct mpls_te_circuit *mtc, - struct in_addr addr) -{ - - SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR; - SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE; - mtc->local_ipaddr.value.s_addr = addr.s_addr; - return; -} - -void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *mtc, - struct in_addr addr) -{ - - SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR; - SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE; - mtc->rmt_ipaddr.value.s_addr = addr.s_addr; - return; -} - -static void set_circuitparams_max_bw(struct mpls_te_circuit *mtc, float fp) -{ - SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW; - SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE; - mtc->max_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_max_rsv_bw(struct mpls_te_circuit *mtc, float fp) -{ - SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW; - SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE; - mtc->max_rsv_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_unrsv_bw(struct mpls_te_circuit *mtc, - int priority, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW; - SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE; - mtc->unrsv_bw.value[priority] = htonf(fp); - return; -} - -static void set_circuitparams_te_metric(struct mpls_te_circuit *mtc, - uint32_t te_metric) -{ - SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC; - SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE; - mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF; - mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF; - mtc->te_metric.value[2] = te_metric & 0xFF; - return; -} - -static void set_circuitparams_inter_as(struct mpls_te_circuit *mtc, - struct in_addr addr, uint32_t as) -{ - - /* Set the Remote ASBR IP address and then the associated AS number */ - SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP; - SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE; - mtc->rip.value.s_addr = addr.s_addr; - - SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS; - SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE; - mtc->ras.value = htonl(as); -} - -static void unset_circuitparams_inter_as(struct mpls_te_circuit *mtc) -{ - - /* Reset the Remote ASBR IP address and then the associated AS number */ - SUBTLV_TYPE(mtc->rip) = 0; - SUBTLV_LEN(mtc->rip) = 0; - mtc->rip.value.s_addr = 0; - - SUBTLV_TYPE(mtc->ras) = 0; - SUBTLV_LEN(mtc->ras) = 0; - mtc->ras.value = 0; -} - -static void set_circuitparams_av_delay(struct mpls_te_circuit *mtc, - uint32_t delay, uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY; - SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE; - tmp = delay & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->av_delay.value = htonl(tmp); - return; -} - -static void set_circuitparams_mm_delay(struct mpls_te_circuit *mtc, - uint32_t low, uint32_t high, - uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY; - SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE; - tmp = low & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->mm_delay.low = htonl(tmp); - mtc->mm_delay.high = htonl(high); - return; -} - -static void set_circuitparams_delay_var(struct mpls_te_circuit *mtc, - uint32_t jitter) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR; - SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE; - mtc->delay_var.value = htonl(jitter & TE_EXT_MASK); - return; -} - -static void set_circuitparams_pkt_loss(struct mpls_te_circuit *mtc, - uint32_t loss, uint8_t anormal) -{ - uint32_t tmp; - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS; - SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE; - tmp = loss & TE_EXT_MASK; - if (anormal) - tmp |= TE_EXT_ANORMAL; - mtc->pkt_loss.value = htonl(tmp); - return; -} - -static void set_circuitparams_res_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW; - SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE; - mtc->res_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_ava_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW; - SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE; - mtc->ava_bw.value = htonf(fp); - return; -} - -static void set_circuitparams_use_bw(struct mpls_te_circuit *mtc, float fp) -{ - /* Note that TLV-length field is the size of array. */ - SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW; - SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE; - mtc->use_bw.value = htonf(fp); - return; -} - /* Main initialization / update function of the MPLS TE Circuit context */ /* Call when interface TE Link parameters are modified */ void isis_link_params_update(struct isis_circuit *circuit, @@ -488,155 +73,223 @@ void isis_link_params_update(struct isis_circuit *circuit, { int i; struct prefix_ipv4 *addr; - struct mpls_te_circuit *mtc; + struct prefix_ipv6 *addr6; + struct isis_ext_subtlvs *ext; + + /* Check if TE is enable or not */ + if (!circuit->area || !IS_MPLS_TE(circuit->area->mta)) + return; /* Sanity Check */ - if ((circuit == NULL) || (ifp == NULL)) + if ((circuit == NULL) || (ifp == NULL) + || (circuit->state != C_STATE_UP)) return; - zlog_info("MPLS-TE: Initialize circuit parameters for interface %s", - ifp->name); + zlog_debug("TE(%s): Update circuit parameters for interface %s", + circuit->area->area_tag, ifp->name); /* Check if MPLS TE Circuit context has not been already created */ - if (circuit->mtc == NULL) - circuit->mtc = mpls_te_circuit_new(); + if (circuit->ext == NULL) { + circuit->ext = isis_alloc_ext_subtlvs(); + zlog_debug(" |- Allocated new Ext-subTLVs for interface %s", + ifp->name); + } - mtc = circuit->mtc; + ext = circuit->ext; - /* Fulfil MTC TLV from ifp TE Link parameters */ + /* Fulfill Extended subTLVs from interface link parameters */ if (HAS_LINK_PARAMS(ifp)) { - mtc->status = enable; /* STD_TE metrics */ - if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) - set_circuitparams_admin_grp( - mtc, ifp->link_params->admin_grp); - else - SUBTLV_TYPE(mtc->admin_grp) = 0; - - /* If not already set, register local IP addr from ip_addr list - * if it exists */ - if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) { - if (circuit->ip_addrs != NULL - && listcount(circuit->ip_addrs) != 0) { - addr = (struct prefix_ipv4 *)listgetdata( - (struct listnode *)listhead( - circuit->ip_addrs)); - set_circuitparams_local_ipaddr(mtc, - addr->prefix); - } - } - - /* If not already set, try to determine Remote IP addr if - * circuit is P2P */ - if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) - && (circuit->circ_type == CIRCUIT_T_P2P)) { + if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) { + ext->adm_group = ifp->link_params->admin_grp; + SET_SUBTLV(ext, EXT_ADM_GRP); + } else + UNSET_SUBTLV(ext, EXT_ADM_GRP); + + /* If known, register local IPv4 addr from ip_addr list */ + if (circuit->ip_addrs != NULL + && listcount(circuit->ip_addrs) != 0) { + addr = (struct prefix_ipv4 *)listgetdata( + (struct listnode *)listhead(circuit->ip_addrs)); + IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix); + SET_SUBTLV(ext, EXT_LOCAL_ADDR); + } else + UNSET_SUBTLV(ext, EXT_LOCAL_ADDR); + + /* Same for Remote IPv4 address */ + if (circuit->circ_type == CIRCUIT_T_P2P) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; + if (adj && adj->adj_state == ISIS_ADJ_UP && adj->ipv4_address_count) { - set_circuitparams_rmt_ipaddr( - mtc, adj->ipv4_addresses[0]); + IPV4_ADDR_COPY(&ext->neigh_addr, + &adj->ipv4_addresses[0]); + SET_SUBTLV(ext, EXT_NEIGH_ADDR); } - } - - if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) - set_circuitparams_max_bw(mtc, ifp->link_params->max_bw); - else - SUBTLV_TYPE(mtc->max_bw) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) - set_circuitparams_max_rsv_bw( - mtc, ifp->link_params->max_rsv_bw); - else - SUBTLV_TYPE(mtc->max_rsv_bw) = 0; + } else + UNSET_SUBTLV(ext, EXT_NEIGH_ADDR); + + /* If known, register local IPv6 addr from ip_addr list */ + if (circuit->ipv6_non_link != NULL + && listcount(circuit->ipv6_non_link) != 0) { + addr6 = (struct prefix_ipv6 *)listgetdata( + (struct listnode *)listhead( + circuit->ipv6_non_link)); + IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix); + SET_SUBTLV(ext, EXT_LOCAL_ADDR6); + } else + UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6); + + /* Same for Remote IPv6 address */ + if (circuit->circ_type == CIRCUIT_T_P2P) { + struct isis_adjacency *adj = circuit->u.p2p.neighbor; - if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) + if (adj && adj->adj_state == ISIS_ADJ_UP + && adj->ipv6_address_count) { + IPV6_ADDR_COPY(&ext->neigh_addr6, + &adj->ipv6_addresses[0]); + SET_SUBTLV(ext, EXT_NEIGH_ADDR6); + } + } else + UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6); + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) { + ext->max_bw = ifp->link_params->max_bw; + SET_SUBTLV(ext, EXT_MAX_BW); + } else + UNSET_SUBTLV(ext, EXT_MAX_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) { + ext->max_rsv_bw = ifp->link_params->max_rsv_bw; + SET_SUBTLV(ext, EXT_MAX_RSV_BW); + } else + UNSET_SUBTLV(ext, EXT_MAX_RSV_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) { for (i = 0; i < MAX_CLASS_TYPE; i++) - set_circuitparams_unrsv_bw( - mtc, i, ifp->link_params->unrsv_bw[i]); - else - SUBTLV_TYPE(mtc->unrsv_bw) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) - set_circuitparams_te_metric( - mtc, ifp->link_params->te_metric); - else - SUBTLV_TYPE(mtc->te_metric) = 0; - - /* TE metric Extensions */ - if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) - set_circuitparams_av_delay( - mtc, ifp->link_params->av_delay, 0); - else - SUBTLV_TYPE(mtc->av_delay) = 0; + ext->unrsv_bw[i] = + ifp->link_params->unrsv_bw[i]; + SET_SUBTLV(ext, EXT_UNRSV_BW); + } else + UNSET_SUBTLV(ext, EXT_UNRSV_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) { + ext->te_metric = ifp->link_params->te_metric; + SET_SUBTLV(ext, EXT_TE_METRIC); + } else + UNSET_SUBTLV(ext, EXT_TE_METRIC); + + /* TE metric extensions */ + if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) { + ext->delay = ifp->link_params->av_delay; + SET_SUBTLV(ext, EXT_DELAY); + } else + UNSET_SUBTLV(ext, EXT_DELAY); + + if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) { + ext->min_delay = ifp->link_params->min_delay; + ext->max_delay = ifp->link_params->max_delay; + SET_SUBTLV(ext, EXT_MM_DELAY); + } else + UNSET_SUBTLV(ext, EXT_MM_DELAY); + + if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) { + ext->delay_var = ifp->link_params->delay_var; + SET_SUBTLV(ext, EXT_DELAY_VAR); + } else + UNSET_SUBTLV(ext, EXT_DELAY_VAR); + + if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) { + ext->pkt_loss = ifp->link_params->pkt_loss; + SET_SUBTLV(ext, EXT_PKT_LOSS); + } else + UNSET_SUBTLV(ext, EXT_PKT_LOSS); + + if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) { + ext->res_bw = ifp->link_params->res_bw; + SET_SUBTLV(ext, EXT_RES_BW); + } else + UNSET_SUBTLV(ext, EXT_RES_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) { + ext->ava_bw = ifp->link_params->ava_bw; + SET_SUBTLV(ext, EXT_AVA_BW); + } else + UNSET_SUBTLV(ext, EXT_AVA_BW); + + if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) { + ext->use_bw = ifp->link_params->use_bw; + SET_SUBTLV(ext, EXT_USE_BW); + } else + UNSET_SUBTLV(ext, EXT_USE_BW); - if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) - set_circuitparams_mm_delay( - mtc, ifp->link_params->min_delay, - ifp->link_params->max_delay, 0); - else - SUBTLV_TYPE(mtc->mm_delay) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) - set_circuitparams_delay_var( - mtc, ifp->link_params->delay_var); - else - SUBTLV_TYPE(mtc->delay_var) = 0; - - if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) - set_circuitparams_pkt_loss( - mtc, ifp->link_params->pkt_loss, 0); + /* INTER_AS */ + if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { + ext->remote_as = ifp->link_params->rmt_as; + ext->remote_ip = ifp->link_params->rmt_ip; + SET_SUBTLV(ext, EXT_RMT_AS); + SET_SUBTLV(ext, EXT_RMT_IP); + } else { + /* reset inter-as TE params */ + UNSET_SUBTLV(ext, EXT_RMT_AS); + UNSET_SUBTLV(ext, EXT_RMT_IP); + } + zlog_debug(" |- New MPLS-TE link parameters status 0x%x", + ext->status); + } else { + zlog_debug(" |- Reset Extended subTLVs status 0x%x", + ext->status); + /* Reset TE subTLVs keeping SR one's */ + if (IS_SUBTLV(ext, EXT_ADJ_SID)) + ext->status = EXT_ADJ_SID; + else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID)) + ext->status = EXT_LAN_ADJ_SID; else - SUBTLV_TYPE(mtc->pkt_loss) = 0; + ext->status = 0; + } - if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) - set_circuitparams_res_bw(mtc, ifp->link_params->res_bw); - else - SUBTLV_TYPE(mtc->res_bw) = 0; + return; +} - if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) - set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw); - else - SUBTLV_TYPE(mtc->ava_bw) = 0; +static int isis_link_update_adj_hook(struct isis_adjacency *adj) +{ - if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) - set_circuitparams_use_bw(mtc, ifp->link_params->use_bw); - else - SUBTLV_TYPE(mtc->use_bw) = 0; + struct isis_circuit *circuit = adj->circuit; - /* INTER_AS */ - if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) - set_circuitparams_inter_as(mtc, - ifp->link_params->rmt_ip, - ifp->link_params->rmt_as); - else - /* reset inter-as TE params */ - unset_circuitparams_inter_as(mtc); + /* Update MPLS TE Remote IP address parameter if possible */ + if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext)) + return 0; - /* Compute total length of SUB TLVs */ - mtc->length = subtlvs_len(mtc); + /* IPv4 first */ + if (adj->ipv4_address_count > 0) { + IPV4_ADDR_COPY(&circuit->ext->neigh_addr, + &adj->ipv4_addresses[0]); + SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR); + } - } else - mtc->status = disable; + /* and IPv6 */ + if (adj->ipv6_address_count > 0) { + IPV6_ADDR_COPY(&circuit->ext->neigh_addr6, + &adj->ipv6_addresses[0]); + SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6); + } -/* Finally Update LSP */ -#if 0 - if (circuit->area && IS_MPLS_TE(circuit->area->mta)) - lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); -#endif - return; + return 0; } -void isis_mpls_te_update(struct interface *ifp) +int isis_mpls_te_update(struct interface *ifp) { struct isis_circuit *circuit; + uint8_t rc = 1; /* Sanity Check */ if (ifp == NULL) - return; + return rc; /* Get circuit context from interface */ - if ((circuit = circuit_scan_by_ifp(ifp)) == NULL) - return; + circuit = circuit_scan_by_ifp(ifp); + if (circuit == NULL) + return rc; /* Update TE TLVs ... */ isis_link_params_update(circuit, ifp); @@ -645,418 +298,11 @@ void isis_mpls_te_update(struct interface *ifp) if (circuit->area && IS_MPLS_TE(circuit->area->mta)) lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - return; -} - -/*------------------------------------------------------------------------* - * Followings are vty session control functions. - *------------------------------------------------------------------------*/ - -static uint8_t print_subtlv_admin_grp(struct sbuf *buf, int indent, - struct te_subtlv_admin_grp *tlv) -{ - sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n", - ntohl(tlv->value)); - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_llri(struct sbuf *buf, int indent, - struct te_subtlv_llri *tlv) -{ - sbuf_push(buf, indent, "Link Local ID: %" PRIu32 "\n", - ntohl(tlv->local)); - sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n", - ntohl(tlv->remote)); - - return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); -} - -static uint8_t print_subtlv_local_ipaddr(struct sbuf *buf, int indent, - struct te_subtlv_local_ipaddr *tlv) -{ - sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent, - struct te_subtlv_rmt_ipaddr *tlv) -{ - sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_max_bw(struct sbuf *buf, int indent, - struct te_subtlv_max_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_max_rsv_bw(struct sbuf *buf, int indent, - struct te_subtlv_max_rsv_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", - fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_unrsv_bw(struct sbuf *buf, int indent, - struct te_subtlv_unrsv_bw *tlv) -{ - float fval1, fval2; - int i; - - sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); - - for (i = 0; i < MAX_CLASS_TYPE; i += 2) { - fval1 = ntohf(tlv->value[i]); - fval2 = ntohf(tlv->value[i + 1]); - sbuf_push(buf, indent + 2, - "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", i, - fval1, i + 1, fval2); - } - - return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); -} - -static uint8_t print_subtlv_te_metric(struct sbuf *buf, int indent, - struct te_subtlv_te_metric *tlv) -{ - uint32_t te_metric; - - te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; - sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_ras(struct sbuf *buf, int indent, - struct te_subtlv_ras *tlv) -{ - sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n", - ntohl(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_rip(struct sbuf *buf, int indent, - struct te_subtlv_rip *tlv) -{ - sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n", - inet_ntoa(tlv->value)); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); + rc = 0; + return rc; } -static uint8_t print_subtlv_av_delay(struct sbuf *buf, int indent, - struct te_subtlv_av_delay *tlv) -{ - uint32_t delay; - uint32_t A; - - delay = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - - sbuf_push(buf, indent, - "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", - A ? "Anomalous" : "Normal", delay); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_mm_delay(struct sbuf *buf, int indent, - struct te_subtlv_mm_delay *tlv) -{ - uint32_t low, high; - uint32_t A; - - low = (uint32_t)ntohl(tlv->low) & TE_EXT_MASK; - A = (uint32_t)ntohl(tlv->low) & TE_EXT_ANORMAL; - high = (uint32_t)ntohl(tlv->high) & TE_EXT_MASK; - - sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n", - A ? "Anomalous" : "Normal", low, high); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_delay_var(struct sbuf *buf, int indent, - struct te_subtlv_delay_var *tlv) -{ - uint32_t jitter; - - jitter = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - - sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n", - jitter); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_pkt_loss(struct sbuf *buf, int indent, - struct te_subtlv_pkt_loss *tlv) -{ - uint32_t loss; - uint32_t A; - float fval; - - loss = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK; - fval = (float)(loss * LOSS_PRECISION); - A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - - sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", - A ? "Anomalous" : "Normal", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_res_bw(struct sbuf *buf, int indent, - struct te_subtlv_res_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_ava_bw(struct sbuf *buf, int indent, - struct te_subtlv_ava_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent, - struct te_subtlv_use_bw *tlv) -{ - float fval; - - fval = ntohf(tlv->value); - - sbuf_push(buf, indent, - "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", fval); - - return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); -} - -static uint8_t print_unknown_tlv(struct sbuf *buf, int indent, - struct subtlv_header *tlvh) -{ - int i, rtn; - uint8_t *v = (uint8_t *)tlvh; - - if (tlvh->length != 0) { - sbuf_push(buf, indent, - "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); - sbuf_push(buf, indent + 2, "Dump: [00]"); - rtn = 1; /* initialize end of line counter */ - for (i = 0; i < tlvh->length; i++) { - sbuf_push(buf, 0, " %#.2x", v[i]); - if (rtn == 8) { - sbuf_push(buf, 0, "\n"); - sbuf_push(buf, indent + 8, "[%.2x]", i + 1); - rtn = 1; - } else - rtn++; - } - sbuf_push(buf, 0, "\n"); - } else { - sbuf_push(buf, indent, - "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); - } - - return SUBTLV_SIZE(tlvh); -} - -/* Main Show function */ -void mpls_te_print_detail(struct sbuf *buf, int indent, - uint8_t *subtlvs, uint8_t subtlv_len) -{ - struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs; - uint16_t sum = 0; - - for (; sum < subtlv_len; - tlvh = (struct subtlv_header *)(subtlvs + sum)) { - if (subtlv_len - sum < SUBTLV_SIZE(tlvh)) { - sbuf_push(buf, indent, "Available data %" PRIu8 " is less than TLV size %u!\n", - subtlv_len - sum, SUBTLV_SIZE(tlvh)); - return; - } - - switch (tlvh->type) { - case TE_SUBTLV_ADMIN_GRP: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Administrative Group!\n"); - return; - } - sum += print_subtlv_admin_grp(buf, indent, - (struct te_subtlv_admin_grp *)tlvh); - break; - case TE_SUBTLV_LLRI: - if (tlvh->length != TE_SUBTLV_LLRI_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Link ID!\n"); - return; - } - sum += print_subtlv_llri(buf, indent, - (struct te_subtlv_llri *)tlvh); - break; - case TE_SUBTLV_LOCAL_IPADDR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Local IP address!\n"); - return; - } - sum += print_subtlv_local_ipaddr(buf, indent, - (struct te_subtlv_local_ipaddr *)tlvh); - break; - case TE_SUBTLV_RMT_IPADDR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote Interface address!\n"); - return; - } - sum += print_subtlv_rmt_ipaddr(buf, indent, - (struct te_subtlv_rmt_ipaddr *)tlvh); - break; - case TE_SUBTLV_MAX_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Bandwidth!\n"); - return; - } - sum += print_subtlv_max_bw(buf, indent, - (struct te_subtlv_max_bw *)tlvh); - break; - case TE_SUBTLV_MAX_RSV_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Reservable Bandwidth!\n"); - return; - } - sum += print_subtlv_max_rsv_bw(buf, indent, - (struct te_subtlv_max_rsv_bw *)tlvh); - break; - case TE_SUBTLV_UNRSV_BW: - if (tlvh->length != TE_SUBTLV_UNRSV_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unreserved Bandwidth!\n"); - return; - } - sum += print_subtlv_unrsv_bw(buf, indent, - (struct te_subtlv_unrsv_bw *)tlvh); - break; - case TE_SUBTLV_TE_METRIC: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Traffic Engineering Metric!\n"); - return; - } - sum += print_subtlv_te_metric(buf, indent, - (struct te_subtlv_te_metric *)tlvh); - break; - case TE_SUBTLV_RAS: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote AS number!\n"); - return; - } - sum += print_subtlv_ras(buf, indent, - (struct te_subtlv_ras *)tlvh); - break; - case TE_SUBTLV_RIP: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Remote ASBR IP Address!\n"); - return; - } - sum += print_subtlv_rip(buf, indent, - (struct te_subtlv_rip *)tlvh); - break; - case TE_SUBTLV_AV_DELAY: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Average Link Delay!\n"); - return; - } - sum += print_subtlv_av_delay(buf, indent, - (struct te_subtlv_av_delay *)tlvh); - break; - case TE_SUBTLV_MM_DELAY: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Min/Max Link Delay!\n"); - return; - } - sum += print_subtlv_mm_delay(buf, indent, - (struct te_subtlv_mm_delay *)tlvh); - break; - case TE_SUBTLV_DELAY_VAR: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Delay Variation!\n"); - return; - } - sum += print_subtlv_delay_var(buf, indent, - (struct te_subtlv_delay_var *)tlvh); - break; - case TE_SUBTLV_PKT_LOSS: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Link Packet Loss!\n"); - return; - } - sum += print_subtlv_pkt_loss(buf, indent, - (struct te_subtlv_pkt_loss *)tlvh); - break; - case TE_SUBTLV_RES_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n"); - return; - } - sum += print_subtlv_res_bw(buf, indent, - (struct te_subtlv_res_bw *)tlvh); - break; - case TE_SUBTLV_AVA_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Available Bandwidth!\n"); - return; - } - sum += print_subtlv_ava_bw(buf, indent, - (struct te_subtlv_ava_bw *)tlvh); - break; - case TE_SUBTLV_USE_BW: - if (tlvh->length != SUBTLV_DEF_SIZE) { - sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n"); - return; - } - sum += print_subtlv_use_bw(buf, indent, - (struct te_subtlv_use_bw *)tlvh); - break; - default: - sum += print_unknown_tlv(buf, indent, tlvh); - break; - } - } - return; -} - -/*------------------------------------------------------------------------* - * Followings are vty command functions. - *------------------------------------------------------------------------*/ +/* Followings are vty command functions */ #ifndef FABRICD DEFUN (show_isis_mpls_te_router, @@ -1092,45 +338,104 @@ DEFUN (show_isis_mpls_te_router, return CMD_SUCCESS; } -static void show_mpls_te_sub(struct vty *vty, char *name, - struct mpls_te_circuit *mtc) +static void show_ext_sub(struct vty *vty, char *name, + struct isis_ext_subtlvs *ext) { struct sbuf buf; + char ibuf[PREFIX2STR_BUFFER]; sbuf_init(&buf, NULL, 0); - if (mtc->status != enable) + if (!ext || ext->status == EXT_DISABLE) return; vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name); sbuf_reset(&buf); - print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp); - - if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) - print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr); - if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) - print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr); - - print_subtlv_max_bw(&buf, 4, &mtc->max_bw); - print_subtlv_max_rsv_bw(&buf, 4, &mtc->max_rsv_bw); - print_subtlv_unrsv_bw(&buf, 4, &mtc->unrsv_bw); - print_subtlv_te_metric(&buf, 4, &mtc->te_metric); - - if (IS_INTER_AS(mtc->type)) { - if (SUBTLV_TYPE(mtc->ras) != 0) - print_subtlv_ras(&buf, 4, &mtc->ras); - if (SUBTLV_TYPE(mtc->rip) != 0) - print_subtlv_rip(&buf, 4, &mtc->rip); - } - print_subtlv_av_delay(&buf, 4, &mtc->av_delay); - print_subtlv_mm_delay(&buf, 4, &mtc->mm_delay); - print_subtlv_delay_var(&buf, 4, &mtc->delay_var); - print_subtlv_pkt_loss(&buf, 4, &mtc->pkt_loss); - print_subtlv_res_bw(&buf, 4, &mtc->res_bw); - print_subtlv_ava_bw(&buf, 4, &mtc->ava_bw); - print_subtlv_use_bw(&buf, 4, &mtc->use_bw); + if (IS_SUBTLV(ext, EXT_ADM_GRP)) + sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n", + ext->adm_group); + if (IS_SUBTLV(ext, EXT_LLRI)) { + sbuf_push(&buf, 4, "Link Local ID: %" PRIu32 "\n", + ext->local_llri); + sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n", + ext->remote_llri); + } + if (IS_SUBTLV(ext, EXT_LOCAL_ADDR)) + sbuf_push(&buf, 4, "Local Interface IP Address(es): %s\n", + inet_ntoa(ext->local_addr)); + if (IS_SUBTLV(ext, EXT_NEIGH_ADDR)) + sbuf_push(&buf, 4, "Remote Interface IP Address(es): %s\n", + inet_ntoa(ext->neigh_addr)); + if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6)) + sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &ext->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6)) + sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &ext->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(ext, EXT_MAX_BW)) + sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n", + ext->max_bw); + if (IS_SUBTLV(ext, EXT_MAX_RSV_BW)) + sbuf_push(&buf, 4, + "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + ext->max_rsv_bw); + if (IS_SUBTLV(ext, EXT_UNRSV_BW)) { + sbuf_push(&buf, 4, "Unreserved Bandwidth:\n"); + for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { + sbuf_push(&buf, 4 + 2, + "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + j, ext->unrsv_bw[j], + j + 1, ext->unrsv_bw[j + 1]); + } + } + if (IS_SUBTLV(ext, EXT_TE_METRIC)) + sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n", + ext->te_metric); + if (IS_SUBTLV(ext, EXT_RMT_AS)) + sbuf_push(&buf, 4, + "Inter-AS TE Remote AS number: %" PRIu32 "\n", + ext->remote_as); + if (IS_SUBTLV(ext, EXT_RMT_IP)) + sbuf_push(&buf, 4, + "Inter-AS TE Remote ASBR IP address: %s\n", + inet_ntoa(ext->remote_ip)); + if (IS_SUBTLV(ext, EXT_DELAY)) + sbuf_push(&buf, 4, + "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", + IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal", + ext->delay); + if (IS_SUBTLV(ext, EXT_MM_DELAY)) { + sbuf_push(&buf, 4, "%s Min/Max Link Delay: %" PRIu32 " / %" + PRIu32 " (micro-sec)\n", + IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal", + ext->min_delay & TE_EXT_MASK, + ext->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(ext, EXT_DELAY_VAR)) + sbuf_push(&buf, 4, + "Delay Variation: %" PRIu32 " (micro-sec)\n", + ext->delay_var & TE_EXT_MASK); + if (IS_SUBTLV(ext, EXT_PKT_LOSS)) + sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n", + IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal", + (float)((ext->pkt_loss & TE_EXT_MASK) + * LOSS_PRECISION)); + if (IS_SUBTLV(ext, EXT_RES_BW)) + sbuf_push(&buf, 4, + "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", + ext->res_bw); + if (IS_SUBTLV(ext, EXT_AVA_BW)) + sbuf_push(&buf, 4, + "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", + ext->ava_bw); + if (IS_SUBTLV(ext, EXT_USE_BW)) + sbuf_push(&buf, 4, + "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", + ext->use_bw); vty_multiline(vty, "", "%s", sbuf_buf(&buf)); vty_out(vty, "---------------\n\n"); @@ -1170,8 +475,8 @@ DEFUN (show_isis_mpls_te_interface, for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) - show_mpls_te_sub(vty, circuit->interface->name, - circuit->mtc); + show_ext_sub(vty, circuit->interface->name, + circuit->ext); } } else { /* Interface name is specified. */ @@ -1185,7 +490,7 @@ DEFUN (show_isis_mpls_te_interface, "ISIS is not enabled on circuit %s\n", ifp->name); else - show_mpls_te_sub(vty, ifp->name, circuit->mtc); + show_ext_sub(vty, ifp->name, circuit->ext); } } @@ -1197,6 +502,11 @@ DEFUN (show_isis_mpls_te_interface, void isis_mpls_te_init(void) { + /* Register Circuit and Adjacency hook */ + hook_register(isis_if_new_hook, isis_mpls_te_update); + hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook); + + #ifndef FABRICD /* Register new VTY commands */ install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd); diff --git a/isisd/isis_te.h b/isisd/isis_te.h index beb0c1836f..2a6911d500 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -3,8 +3,9 @@ * * This is an implementation of RFC5305, RFC 5307 and RFC 7810 * - * Copyright (C) 2014 Orange Labs - * http://www.orange.com + * Author: Olivier Dugeon <olivier.dugeon@orange.com> + * + * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com * * This file is part of GNU Zebra. * @@ -50,10 +51,10 @@ * Remote AS number 24 RFC5316 * IPv4 Remote ASBR identifier 25 RFC5316 * + * NOTE: RFC5316 is not fully supported in this version + * only subTLVs decoding is provided */ -/* NOTE: RFC5316 is not yet supported in this version */ - /* Following define the type of TE link regarding the various RFC */ #define STD_TE 0x01 #define GMPLS 0x02 @@ -73,170 +74,9 @@ #define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) /* - * Following section defines subTLV (tag, length, value) structures, - * used for Traffic Engineering. + * Note (since release 7.2), subTLVs definition, serialization + * and de-serialization have mode to isis_tlvs.[c,h] */ -struct subtlv_header { - uint8_t type; /* sub_TLV_XXX type (see above) */ - uint8_t length; /* Value portion only, in byte */ -}; - -#define MAX_SUBTLV_SIZE 256 - -#define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ - -#define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) - -#define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE) - -#define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh)) - -#define SUBTLV_TYPE(stlvh) stlvh.header.type -#define SUBTLV_LEN(stlvh) stlvh.header.length -#define SUBTLV_VAL(stlvh) stlvh.value -#define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE - -#define SUBTLV_DEF_SIZE 4 - -/* Link Sub-TLV: Resource Class/Color - RFC 5305 */ -#define TE_SUBTLV_ADMIN_GRP 3 -struct te_subtlv_admin_grp { - struct subtlv_header header; /* Value length is 4 octets. */ - uint32_t value; /* Admin. group membership. */ -} __attribute__((__packed__)); - -/* Link Local/Remote Identifiers - RFC 5307 */ -#define TE_SUBTLV_LLRI 4 -#define TE_SUBTLV_LLRI_SIZE 8 -struct te_subtlv_llri { - struct subtlv_header header; /* Value length is 8 octets. */ - uint32_t local; /* Link Local Identifier */ - uint32_t remote; /* Link Remote Identifier */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */ -#define TE_SUBTLV_LOCAL_IPADDR 6 -struct te_subtlv_local_ipaddr { - struct subtlv_header header; /* Value length is 4 x N octets. */ - struct in_addr value; /* Local IP address(es). */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */ -#define TE_SUBTLV_RMT_IPADDR 8 -struct te_subtlv_rmt_ipaddr { - struct subtlv_header header; /* Value length is 4 x N octets. */ - struct in_addr value; /* Neighbor's IP address(es). */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */ -#define TE_SUBTLV_MAX_BW 9 -struct te_subtlv_max_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bytes/sec */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */ -#define TE_SUBTLV_MAX_RSV_BW 10 -struct te_subtlv_max_rsv_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bytes/sec */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */ -#define TE_SUBTLV_UNRSV_BW 11 -#define TE_SUBTLV_UNRSV_SIZE 32 -struct te_subtlv_unrsv_bw { - struct subtlv_header header; /* Value length is 32 octets. */ - float value[8]; /* One for each priority level. */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */ -#define TE_SUBTLV_TE_METRIC 18 -#define TE_SUBTLV_TE_METRIC_SIZE 3 -struct te_subtlv_te_metric { - struct subtlv_header header; /* Value length is 4 octets. */ - uint8_t value[3]; /* Link metric for TE purpose. */ -} __attribute__((__packed__)); - -/* Remote AS Number sub-TLV - RFC5316 */ -#define TE_SUBTLV_RAS 24 -struct te_subtlv_ras { - struct subtlv_header header; /* Value length is 4 octets. */ - uint32_t value; /* Remote AS number */ -} __attribute__((__packed__)); - -/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ -#define TE_SUBTLV_RIP 25 -struct te_subtlv_rip { - struct subtlv_header header; /* Value length is 4 octets. */ - struct in_addr value; /* Remote ASBR IP address */ -} __attribute__((__packed__)); - - -/* TE Metric Extensions - RFC 7810 */ -/* Link Sub-TLV: Average Link Delay */ -#define TE_SUBTLV_AV_DELAY 33 -struct te_subtlv_av_delay { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... - 16777215 - with Anomalous Bit (A) as Upper most bit */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Low/High Link Delay */ -#define TE_SUBTLV_MM_DELAY 34 -#define TE_SUBTLV_MM_DELAY_SIZE 8 -struct te_subtlv_mm_delay { - struct subtlv_header header; /* Value length is 8 bytes. */ - uint32_t low; /* low delay in micro-seconds only 24 bits => 0 ... - 16777215 - with Anomalous Bit (A) as Upper most bit */ - uint32_t high; /* high delay in micro-seconds only 24 bits => 0 ... - 16777215 */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Link Delay Variation i.e. Jitter */ -#define TE_SUBTLV_DELAY_VAR 35 -struct te_subtlv_delay_var { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t value; /* interval in micro-seconds only 24 bits => 0 ... - 16777215 */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ -#define TE_SUBTLV_PKT_LOSS 36 -struct te_subtlv_pkt_loss { - struct subtlv_header header; /* Value length is 4 bytes. */ - uint32_t - value; /* in percentage of total traffic only 24 bits (2^24 - 2) - with Anomalous Bit (A) as Upper most bit */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ -#define TE_SUBTLV_RES_BW 37 -struct te_subtlv_res_bw { - struct subtlv_header header; /* Value length is 4 bytes. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ -#define TE_SUBTLV_AVA_BW 38 -struct te_subtlv_ava_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ -#define TE_SUBTLV_USE_BW 39 -struct te_subtlv_use_bw { - struct subtlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ -} __attribute__((__packed__)); - -#define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */ /* Following declaration concerns the MPLS-TE and LINk-TE management */ typedef enum _status_t { disable, enable, learn } status_t; @@ -244,7 +84,10 @@ typedef enum _status_t { disable, enable, learn } status_t; /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; -#define IS_MPLS_TE(m) (m && m->status == enable) +#define IS_EXT_TE(e) (e && e->status != 0 \ + && e->status != EXT_ADJ_SID \ + && e->status != EXT_LAN_ADJ_SID) +#define IS_MPLS_TE(a) (a && a->status == enable) /* Per area MPLS-TE parameters */ struct mpls_te_area { @@ -262,56 +105,9 @@ struct mpls_te_area { struct in_addr router_id; }; -/* Per Circuit MPLS-TE parameters */ -struct mpls_te_circuit { - - /* Status of MPLS-TE on this interface */ - status_t status; - - /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), - * INTER_AS_EMU(RFC5316 emulated) */ - uint8_t type; - - /* Total size of sub_tlvs */ - uint8_t length; - - /* Store subTLV in network byte order. */ - /* RFC5305 */ - struct te_subtlv_admin_grp admin_grp; - /* RFC5307 */ - struct te_subtlv_llri llri; - /* RFC5305 */ - struct te_subtlv_local_ipaddr local_ipaddr; - struct te_subtlv_rmt_ipaddr rmt_ipaddr; - struct te_subtlv_max_bw max_bw; - struct te_subtlv_max_rsv_bw max_rsv_bw; - struct te_subtlv_unrsv_bw unrsv_bw; - struct te_subtlv_te_metric te_metric; - /* RFC5316 */ - struct te_subtlv_ras ras; - struct te_subtlv_rip rip; - /* RFC7810 */ - struct te_subtlv_av_delay av_delay; - struct te_subtlv_mm_delay mm_delay; - struct te_subtlv_delay_var delay_var; - struct te_subtlv_pkt_loss pkt_loss; - struct te_subtlv_res_bw res_bw; - struct te_subtlv_ava_bw ava_bw; - struct te_subtlv_use_bw use_bw; -}; - /* Prototypes. */ void isis_mpls_te_init(void); -struct mpls_te_circuit *mpls_te_circuit_new(void); -struct sbuf; -void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, - uint8_t subtlv_len); -void set_circuitparams_local_ipaddr(struct mpls_te_circuit *, struct in_addr); -void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *, struct in_addr); -uint8_t subtlvs_len(struct mpls_te_circuit *); -uint8_t add_te_subtlvs(uint8_t *, struct mpls_te_circuit *); -uint8_t build_te_subtlvs(uint8_t *, struct isis_circuit *); void isis_link_params_update(struct isis_circuit *, struct interface *); -void isis_mpls_te_update(struct interface *); +int isis_mpls_te_update(struct interface *); #endif /* _ZEBRA_ISIS_MPLS_TE_H */ diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index ee253c7a31..442442152c 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -3,6 +3,8 @@ * * Copyright (C) 2015,2017 Christian Franke * + * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) + * * This file is part of FRR. * * FRR is free software; you can redistribute it and/or modify it @@ -28,6 +30,7 @@ #include "memory.h" #include "stream.h" #include "sbuf.h" +#include "network.h" #include "isisd/isisd.h" #include "isisd/isis_memory.h" @@ -98,7 +101,8 @@ static struct pack_order_entry pack_order[] = { PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach), PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach), PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach), - PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)}; + PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach) +}; /* This is a forward definition. The table is actually initialized * in at the bottom. */ @@ -108,9 +112,683 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; /* Prototypes */ static void append_item(struct isis_item_list *dest, struct isis_item *item); +static void init_item_list(struct isis_item_list *items); -/* Functions for Sub-TLV 3 SR Prefix-SID */ +/* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */ +struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void) +{ + struct isis_ext_subtlvs *ext; + + ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs)); + init_item_list(&ext->adj_sid); + init_item_list(&ext->lan_sid); + + return ext; +} + +/* + * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6. + * A negative value could be used to skip copy of Adjacency SID. + */ +static struct isis_ext_subtlvs * +copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid) +{ + struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv)); + struct isis_adj_sid *adj; + struct isis_lan_adj_sid *lan; + + memcpy(rv, exts, sizeof(struct isis_ext_subtlvs)); + init_item_list(&rv->adj_sid); + init_item_list(&rv->lan_sid); + + UNSET_SUBTLV(rv, EXT_ADJ_SID); + UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID); + + /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */ + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL; + adj = adj->next) { + if ((mtid != -1) + && (((mtid == ISIS_MT_IPV4_UNICAST) + && (adj->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (adj->family != AF_INET6)))) + continue; + + struct isis_adj_sid *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid)); + new->family = adj->family; + new->flags = adj->flags; + new->weight = adj->weight; + new->sid = adj->sid; + append_item(&rv->adj_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_ADJ_SID); + } + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL; + lan = lan->next) { + if ((mtid != -1) + && (((mtid == ISIS_MT_IPV4_UNICAST) + && (lan->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (lan->family != AF_INET6)))) + continue; + + struct isis_lan_adj_sid *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid)); + new->family = lan->family; + new->flags = lan->flags; + new->weight = lan->weight; + memcpy(new->neighbor_id, lan->neighbor_id, 6); + new->sid = lan->sid; + append_item(&rv->lan_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_LAN_ADJ_SID); + } + + return rv; +} + +/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ +static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, + struct sbuf *buf, int indent, + uint16_t mtid) +{ + + char ibuf[PREFIX2STR_BUFFER]; + + /* Standard metrics */ + if (IS_SUBTLV(exts, EXT_ADM_GRP)) + sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n", + exts->adm_group); + if (IS_SUBTLV(exts, EXT_LLRI)) { + sbuf_push(buf, indent, "Link Local ID: %" PRIu32 "\n", + exts->local_llri); + sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n", + exts->remote_llri); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) + sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n", + inet_ntoa(exts->local_addr)); + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) + sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n", + inet_ntoa(exts->neigh_addr)); + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) + sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &exts->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) + sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n", + inet_ntop(AF_INET6, &exts->local_addr6, ibuf, + PREFIX2STR_BUFFER)); + if (IS_SUBTLV(exts, EXT_MAX_BW)) + sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", + exts->max_bw); + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) + sbuf_push(buf, indent, + "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + exts->max_rsv_bw); + if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { + sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); + for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { + sbuf_push(buf, indent + 2, + "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + j, exts->unrsv_bw[j], + j + 1, exts->unrsv_bw[j + 1]); + } + } + if (IS_SUBTLV(exts, EXT_TE_METRIC)) + sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", + exts->te_metric); + if (IS_SUBTLV(exts, EXT_RMT_AS)) + sbuf_push(buf, indent, + "Inter-AS TE Remote AS number: %" PRIu32 "\n", + exts->remote_as); + if (IS_SUBTLV(exts, EXT_RMT_IP)) + sbuf_push(buf, indent, + "Inter-AS TE Remote ASBR IP address: %s\n", + inet_ntoa(exts->remote_ip)); + /* Extended metrics */ + if (IS_SUBTLV(exts, EXT_DELAY)) + sbuf_push(buf, indent, + "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", + IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal", + exts->delay); + if (IS_SUBTLV(exts, EXT_MM_DELAY)) { + sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" + PRIu32 " (micro-sec)\n", + IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { + sbuf_push(buf, indent, + "Delay Variation: %" PRIu32 " (micro-sec)\n", + exts->delay_var & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) + sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", + IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal", + (float)((exts->pkt_loss & TE_EXT_MASK) + * LOSS_PRECISION)); + if (IS_SUBTLV(exts, EXT_RES_BW)) + sbuf_push(buf, indent, + "Unidir. Residual Bandwidth: %g (Bytes/sec)\n", + exts->res_bw); + if (IS_SUBTLV(exts, EXT_AVA_BW)) + sbuf_push(buf, indent, + "Unidir. Available Bandwidth: %g (Bytes/sec)\n", + exts->ava_bw); + if (IS_SUBTLV(exts, EXT_USE_BW)) + sbuf_push(buf, indent, + "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n", + exts->use_bw); + /* Segment Routing Adjacency */ + if (IS_SUBTLV(exts, EXT_ADJ_SID)) { + struct isis_adj_sid *adj; + + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; + adj = adj->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) + && (adj->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (adj->family != AF_INET6))) + continue; + sbuf_push( + buf, indent, + "Adjacency-SID: %" PRIu32 ", Weight: %" PRIu8 + ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n", + adj->sid, adj->weight, + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0'); + } + } + if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { + struct isis_lan_adj_sid *lan; + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) + && (lan->family != AF_INET)) + || ((mtid == ISIS_MT_IPV6_UNICAST) + && (lan->family != AF_INET6))) + continue; + sbuf_push(buf, indent, + "Lan-Adjacency-SID: %" PRIu32 + ", Weight: %" PRIu8 + ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n" + " Neighbor-ID: %s\n", + lan->sid, lan->weight, + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0', + isis_format_id(lan->neighbor_id, 6)); + } + } +} + +static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts) +{ + struct isis_item *item, *next_item; + + /* First, free Adj SID and LAN Adj SID list if needed */ + for (item = exts->adj_sid.head; item; item = next_item) { + next_item = item->next; + XFREE(MTYPE_ISIS_SUBTLV, item); + } + for (item = exts->lan_sid.head; item; item = next_item) { + next_item = item->next; + XFREE(MTYPE_ISIS_SUBTLV, item); + } + XFREE(MTYPE_ISIS_SUBTLV, exts); +} + +static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts, + struct stream *s) +{ + uint8_t size; + + if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) + return 1; + + if (IS_SUBTLV(exts, EXT_ADM_GRP)) { + stream_putc(s, ISIS_SUBTLV_ADMIN_GRP); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->adm_group); + } + if (IS_SUBTLV(exts, EXT_LLRI)) { + stream_putc(s, ISIS_SUBTLV_LLRI); + stream_putc(s, ISIS_SUBTLV_LLRI_SIZE); + stream_putl(s, exts->local_llri); + stream_putl(s, exts->remote_llri); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) { + stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->local_addr.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) { + stream_putc(s, ISIS_SUBTLV_RMT_IPADDR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->neigh_addr.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) { + stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6); + stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE); + stream_put(s, &exts->local_addr6, 16); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) { + stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6); + stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE); + stream_put(s, &exts->neigh_addr6, 16); + } + if (IS_SUBTLV(exts, EXT_MAX_BW)) { + stream_putc(s, ISIS_SUBTLV_MAX_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->max_bw); + } + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) { + stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->max_rsv_bw); + } + if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { + stream_putc(s, ISIS_SUBTLV_UNRSV_BW); + stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE); + for (int j = 0; j < MAX_CLASS_TYPE; j++) + stream_putf(s, exts->unrsv_bw[j]); + } + if (IS_SUBTLV(exts, EXT_TE_METRIC)) { + stream_putc(s, ISIS_SUBTLV_TE_METRIC); + stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE); + stream_put3(s, exts->te_metric); + } + if (IS_SUBTLV(exts, EXT_RMT_AS)) { + stream_putc(s, ISIS_SUBTLV_RAS); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->remote_as); + } + if (IS_SUBTLV(exts, EXT_RMT_IP)) { + stream_putc(s, ISIS_SUBTLV_RIP); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_put(s, &exts->remote_ip.s_addr, 4); + } + if (IS_SUBTLV(exts, EXT_DELAY)) { + stream_putc(s, ISIS_SUBTLV_AV_DELAY); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->delay); + } + if (IS_SUBTLV(exts, EXT_MM_DELAY)) { + stream_putc(s, ISIS_SUBTLV_MM_DELAY); + stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE); + stream_putl(s, exts->min_delay); + stream_putl(s, exts->max_delay); + } + if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { + stream_putc(s, ISIS_SUBTLV_DELAY_VAR); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->delay_var); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) { + stream_putc(s, ISIS_SUBTLV_PKT_LOSS); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putl(s, exts->pkt_loss); + } + if (IS_SUBTLV(exts, EXT_RES_BW)) { + stream_putc(s, ISIS_SUBTLV_RES_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->res_bw); + } + if (IS_SUBTLV(exts, EXT_AVA_BW)) { + stream_putc(s, ISIS_SUBTLV_AVA_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->ava_bw); + } + if (IS_SUBTLV(exts, EXT_USE_BW)) { + stream_putc(s, ISIS_SUBTLV_USE_BW); + stream_putc(s, ISIS_SUBTLV_DEF_SIZE); + stream_putf(s, exts->use_bw); + } + if (IS_SUBTLV(exts, EXT_ADJ_SID)) { + struct isis_adj_sid *adj; + + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; + adj = adj->next) { + stream_putc(s, ISIS_SUBTLV_ADJ_SID); + size = ISIS_SUBTLV_ADJ_SID_SIZE; + if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + size++; + stream_putc(s, size); + stream_putc(s, adj->flags); + stream_putc(s, adj->weight); + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + stream_put3(s, adj->sid); + else + stream_putl(s, adj->sid); + + } + } + if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { + struct isis_lan_adj_sid *lan; + + for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan; + lan = lan->next) { + stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID); + size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE; + if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + size++; + stream_putc(s, size); + stream_putc(s, lan->flags); + stream_putc(s, lan->weight); + stream_put(s, lan->neighbor_id, 6); + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + stream_put3(s, lan->sid); + else + stream_putl(s, lan->sid); + } + } + + return 0; +} + +static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + uint8_t sum = 0; + uint8_t subtlv_type; + uint8_t subtlv_len; + + struct isis_extended_reach *rv = dest; + struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs(); + + rv->subtlvs = exts; + + /* + * Parse subTLVs until reach subTLV length + * Check that it remains at least 2 bytes: subTLV Type & Length + */ + while (len > sum + 2) { + /* Read SubTLV Type and Length */ + subtlv_type = stream_getc(s); + subtlv_len = stream_getc(s); + if (subtlv_len > len - sum) { + sbuf_push(log, indent, "TLV %" PRIu8 ": Available data %" PRIu8 " is less than TLV size %u !\n", + subtlv_type, len - sum, subtlv_len); + return 1; + } + switch (subtlv_type) { + /* Standard Metric as defined in RFC5305 */ + case ISIS_SUBTLV_ADMIN_GRP: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Administrative Group!\n"); + } else { + exts->adm_group = stream_getl(s); + SET_SUBTLV(exts, EXT_ADM_GRP); + } + break; + case ISIS_SUBTLV_LLRI: + if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Link ID!\n"); + } else { + exts->local_llri = stream_getl(s); + exts->remote_llri = stream_getl(s); + SET_SUBTLV(exts, EXT_LLRI); + } + break; + case ISIS_SUBTLV_LOCAL_IPADDR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Local IP address!\n"); + } else { + stream_get(&exts->local_addr.s_addr, s, 4); + SET_SUBTLV(exts, EXT_LOCAL_ADDR); + } + break; + case ISIS_SUBTLV_RMT_IPADDR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote IP address!\n"); + } else { + stream_get(&exts->neigh_addr.s_addr, s, 4); + SET_SUBTLV(exts, EXT_NEIGH_ADDR); + } + break; + case ISIS_SUBTLV_LOCAL_IPADDR6: + if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Local IPv6 address!\n"); + } else { + stream_get(&exts->local_addr6, s, 16); + SET_SUBTLV(exts, EXT_LOCAL_ADDR6); + } + break; + case ISIS_SUBTLV_RMT_IPADDR6: + if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote IPv6 address!\n"); + } else { + stream_get(&exts->neigh_addr6, s, 16); + SET_SUBTLV(exts, EXT_NEIGH_ADDR6); + } + break; + case ISIS_SUBTLV_MAX_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Maximum Bandwidth!\n"); + } else { + exts->max_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_MAX_BW); + } + break; + case ISIS_SUBTLV_MAX_RSV_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Maximum Reservable Bandwidth!\n"); + } else { + exts->max_rsv_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_MAX_RSV_BW); + } + break; + case ISIS_SUBTLV_UNRSV_BW: + if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unreserved Bandwidth!\n"); + } else { + for (int i = 0; i < MAX_CLASS_TYPE; i++) + exts->unrsv_bw[i] = stream_getf(s); + SET_SUBTLV(exts, EXT_UNRSV_BW); + } + break; + case ISIS_SUBTLV_TE_METRIC: + if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Traffic Engineering Metric!\n"); + } else { + exts->te_metric = stream_get3(s); + SET_SUBTLV(exts, EXT_TE_METRIC); + } + break; + case ISIS_SUBTLV_RAS: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote AS number!\n"); + } else { + exts->remote_as = stream_getl(s); + SET_SUBTLV(exts, EXT_RMT_AS); + } + break; + case ISIS_SUBTLV_RIP: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Remote ASBR IP Address!\n"); + } else { + stream_get(&exts->remote_ip.s_addr, s, 4); + SET_SUBTLV(exts, EXT_RMT_IP); + } + break; + /* Extended Metrics as defined in RFC 7810 */ + case ISIS_SUBTLV_AV_DELAY: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Average Link Delay!\n"); + } else { + exts->delay = stream_getl(s); + SET_SUBTLV(exts, EXT_DELAY); + } + break; + case ISIS_SUBTLV_MM_DELAY: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Min/Max Link Delay!\n"); + } else { + exts->min_delay = stream_getl(s); + exts->max_delay = stream_getl(s); + SET_SUBTLV(exts, EXT_MM_DELAY); + } + break; + case ISIS_SUBTLV_DELAY_VAR: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Delay Variation!\n"); + } else { + exts->delay_var = stream_getl(s); + SET_SUBTLV(exts, EXT_DELAY_VAR); + } + break; + case ISIS_SUBTLV_PKT_LOSS: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Link Packet Loss!\n"); + } else { + exts->pkt_loss = stream_getl(s); + SET_SUBTLV(exts, EXT_PKT_LOSS); + } + break; + case ISIS_SUBTLV_RES_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n"); + } else { + exts->res_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_RES_BW); + } + break; + case ISIS_SUBTLV_AVA_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Available Bandwidth!\n"); + } else { + exts->ava_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_AVA_BW); + } + break; + case ISIS_SUBTLV_USE_BW: + if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + sbuf_push(log, indent, + "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n"); + } else { + exts->use_bw = stream_getf(s); + SET_SUBTLV(exts, EXT_USE_BW); + } + break; + /* Segment Routing Adjacency */ + case ISIS_SUBTLV_ADJ_SID: + if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) { + sbuf_push(log, indent, + "TLV size does not match expected size for Adjacency SID!\n"); + } else { + struct isis_adj_sid *adj; + + adj = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_adj_sid)); + adj->flags = stream_getc(s); + adj->weight = stream_getc(s); + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { + adj->sid = stream_get3(s); + adj->sid &= MPLS_LABEL_VALUE_MASK; + } else { + adj->sid = stream_getl(s); + } + if (mtid == ISIS_MT_IPV4_UNICAST) + adj->family = AF_INET; + if (mtid == ISIS_MT_IPV6_UNICAST) + adj->family = AF_INET6; + append_item(&exts->adj_sid, + (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_ADJ_SID); + } + break; + case ISIS_SUBTLV_LAN_ADJ_SID: + if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) { + sbuf_push(log, indent, + "TLV size does not match expected size for LAN-Adjacency SID!\n"); + } else { + struct isis_lan_adj_sid *lan; + + lan = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_lan_adj_sid)); + lan->flags = stream_getc(s); + lan->weight = stream_getc(s); + stream_get(&(lan->neighbor_id), s, + ISIS_SYS_ID_LEN); + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { + lan->sid = stream_get3(s); + lan->sid &= MPLS_LABEL_VALUE_MASK; + } else { + lan->sid = stream_getl(s); + } + if (mtid == ISIS_MT_IPV4_UNICAST) + lan->family = AF_INET; + if (mtid == ISIS_MT_IPV6_UNICAST) + lan->family = AF_INET6; + append_item(&exts->lan_sid, + (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_LAN_ADJ_SID); + } + break; + default: + /* Skip unknown TLV */ + stream_forward_getp(s, subtlv_len); + break; + } + sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE; + } + + return 0; +} + +/* Functions for Sub-TLV 3 SR Prefix-SID */ static struct isis_item *copy_item_prefix_sid(struct isis_item *i) { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; @@ -127,20 +805,22 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; - sbuf_push(buf, indent, "SR Prefix-SID:\n"); - sbuf_push(buf, indent, " Flags:%s%s%s%s%s%s\n", - sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "", - sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", - sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "", - sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "", - sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", - sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); - sbuf_push(buf, indent, " Algorithm: %" PRIu8 "\n", sid->algorithm); + sbuf_push(buf, indent, "SR Prefix-SID "); if (sid->flags & ISIS_PREFIX_SID_VALUE) { - sbuf_push(buf, indent, "Label: %" PRIu32 "\n", sid->value); + sbuf_push(buf, 0, "Label: %" PRIu32 ", ", sid->value); } else { - sbuf_push(buf, indent, "Index: %" PRIu32 "\n", sid->value); + sbuf_push(buf, 0, "Index: %" PRIu32 ", ", sid->value); } + sbuf_push(buf, 0, "Algorithm: %" PRIu8 ", ", sid->algorithm); + sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n", + sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" + : "", + sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", + sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP", + sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" + : "", + sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", + sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); } static void free_item_prefix_sid(struct isis_item *i) @@ -186,15 +866,17 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, } sid.flags = stream_getc(s); - if ((sid.flags & ISIS_PREFIX_SID_VALUE) - != (sid.flags & ISIS_PREFIX_SID_LOCAL)) { - sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n"); - return 0; + if (!!(sid.flags & ISIS_PREFIX_SID_VALUE) + != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) { + sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n"); + return 1; } sid.algorithm = stream_getc(s); - uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6; + uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) + ? ISIS_SUBTLV_PREFIX_SID_SIZE + : ISIS_SUBTLV_PREFIX_SID_SIZE + 1; if (len != expected_size) { sbuf_push(log, indent, "TLV size differs from expected size. " @@ -205,6 +887,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, if (sid.flags & ISIS_PREFIX_SID_VALUE) { sid.value = stream_get3(s); + sid.value &= MPLS_LABEL_VALUE_MASK; } else { sid.value = stream_getl(s); } @@ -276,7 +959,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, p.prefixlen = stream_getc(s); if (p.prefixlen > 128) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n", p.prefixlen); return 1; } @@ -305,7 +988,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, memcpy(subtlvs->source_prefix, &p, sizeof(p)); return 0; } -static void init_item_list(struct isis_item_list *items); + static struct isis_item *copy_item(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *item); @@ -703,11 +1386,8 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i) memcpy(rv->id, r->id, 7); rv->metric = r->metric; - if (r->subtlvs && r->subtlv_len) { - rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len); - memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len); - rv->subtlv_len = r->subtlv_len; - } + if (r->subtlvs) + rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1); return (struct isis_item *)rv; } @@ -724,28 +1404,37 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); sbuf_push(buf, 0, "\n"); - if (r->subtlv_len && r->subtlvs) - mpls_te_print_detail(buf, indent + 2, r->subtlvs, - r->subtlv_len); + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid); } static void free_item_extended_reach(struct isis_item *i) { struct isis_extended_reach *item = (struct isis_extended_reach *)i; - XFREE(MTYPE_ISIS_TLV, item->subtlvs); + if (item->subtlvs != NULL) + free_item_ext_subtlvs(item->subtlvs); XFREE(MTYPE_ISIS_TLV, item); } static int pack_item_extended_reach(struct isis_item *i, struct stream *s) { struct isis_extended_reach *r = (struct isis_extended_reach *)i; + size_t len; + size_t len_pos; - if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len) + if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) return 1; + stream_put(s, r->id, sizeof(r->id)); stream_put3(s, r->metric); - stream_putc(s, r->subtlv_len); - stream_put(s, r->subtlvs, r->subtlv_len); + len_pos = stream_get_endp(s); + /* Real length will be adjust after adding subTLVs */ + stream_putc(s, 11); + if (r->subtlvs) + pack_item_ext_subtlvs(r->subtlvs, s); + /* Adjust length */ + len = stream_get_endp(s) - len_pos - 1; + stream_putc_at(s, len_pos, len); return 0; } @@ -780,9 +1469,6 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, rv->metric = stream_get3(s); subtlv_len = stream_getc(s); - format_item_extended_reach(mtid, (struct isis_item *)rv, log, - indent + 2); - if ((size_t)len < ((size_t)11) + subtlv_len) { sbuf_push(log, indent, "Not enough data left for subtlv size %" PRIu8 @@ -795,20 +1481,14 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, subtlv_len); if (subtlv_len) { - size_t subtlv_start = stream_get_getp(s); - - if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s, - log, NULL, indent + 4, NULL)) { + if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv, + indent + 4)) { goto out; } - - stream_set_getp(s, subtlv_start); - - rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); - stream_get(rv->subtlvs, s, subtlv_len); - rv->subtlv_len = subtlv_len; } + format_item_extended_reach(mtid, (struct isis_item *)rv, log, + indent + 2); append_item(items, (struct isis_item *)rv); return 0; out: @@ -1257,6 +1937,7 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i) rv->metric = r->metric; rv->down = r->down; rv->prefix = r->prefix; + rv->subtlvs = copy_subtlvs(r->subtlvs); return (struct isis_item *)rv; } @@ -1348,7 +2029,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, rv->prefix.family = AF_INET; rv->prefix.prefixlen = control & 0x3f; if (rv->prefix.prefixlen > 32) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n", rv->prefix.prefixlen); goto out; } @@ -1834,7 +2515,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, rv->prefix.family = AF_INET6; rv->prefix.prefixlen = stream_getc(s); if (rv->prefix.prefixlen > 128) { - sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n", rv->prefix.prefixlen); goto out; } @@ -1848,6 +2529,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, } stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen)); struct in6_addr orig_prefix = rv->prefix.prefix; + apply_mask_ipv6(&rv->prefix); if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix))) sbuf_push(log, indent + 2, @@ -1898,6 +2580,222 @@ out: return 1; } +/* Functions related to TLV 242 Router Capability */ +static struct isis_router_cap *copy_tlv_router_cap( + const struct isis_router_cap *router_cap) +{ + struct isis_router_cap *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + if (!router_cap) + return NULL; + + memcpy(rv, router_cap, sizeof(*rv)); + + return rv; +} + +static void format_tlv_router_cap(const struct isis_router_cap *router_cap, + struct sbuf *buf, int indent) +{ + char addrbuf[INET_ADDRSTRLEN]; + + if (!router_cap) + return; + + /* Router ID and Flags */ + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + sbuf_push(buf, indent, "Router Capability:"); + sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf, + router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0', + router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0'); + + /* SR Global Block */ + if (router_cap->srgb.range_size != 0) + sbuf_push(buf, indent, + " Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n", + IS_SR_IPV4(router_cap->srgb) ? "1" : "0", + IS_SR_IPV6(router_cap->srgb) ? "1" : "0", + router_cap->srgb.lower_bound, + router_cap->srgb.range_size); + + /* SR Algorithms */ + if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { + sbuf_push(buf, indent, " Algorithm: %s", + router_cap->algo[0] == 0 ? "0: SPF" + : "0: Strict SPF"); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) + sbuf_push(buf, indent, " %s", + router_cap->algo[1] == 0 + ? "0: SPF" + : "0: Strict SPF"); + sbuf_push(buf, indent, "\n"); + } + + /* SR Node MSSD */ + if (router_cap->msd != 0) + sbuf_push(buf, indent, " Node MSD: %d\n", router_cap->msd); +} + +static void free_tlv_router_cap(struct isis_router_cap *router_cap) +{ + XFREE(MTYPE_ISIS_TLV, router_cap); +} + +static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, + struct stream *s) +{ + size_t tlv_len = ISIS_ROUTER_CAP_SIZE; + size_t len_pos; + uint8_t nb_algo; + + if (!router_cap) + return 0; + + /* Compute Maximum TLV size */ + tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE + + ISIS_SUBTLV_HDR_SIZE + + ISIS_SUBTLV_ALGORITHM_SIZE + + ISIS_SUBTLV_NODE_MSD_SIZE; + + if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len)) + return 1; + + /* Add Router Capability TLV 242 with Router ID and Flags */ + stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY); + /* Real length will be adjusted later */ + len_pos = stream_get_endp(s); + stream_putc(s, tlv_len); + stream_put_ipv4(s, router_cap->router_id.s_addr); + stream_putc(s, router_cap->flags); + + /* Add SRGB if set */ + if ((router_cap->srgb.range_size != 0) + && (router_cap->srgb.lower_bound != 0)) { + stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE); + stream_putc(s, router_cap->srgb.flags); + stream_put3(s, router_cap->srgb.range_size); + stream_putc(s, ISIS_SUBTLV_SID_LABEL); + stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE); + stream_put3(s, router_cap->srgb.lower_bound); + + /* Then SR Algorithm if set */ + for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++) + if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET) + break; + if (nb_algo > 0) { + stream_putc(s, ISIS_SUBTLV_ALGORITHM); + stream_putc(s, nb_algo); + for (int i = 0; i < nb_algo; i++) + stream_putc(s, router_cap->algo[i]); + } + /* And finish with MSD if set */ + if (router_cap->msd != 0) { + stream_putc(s, ISIS_SUBTLV_NODE_MSD); + stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE); + stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION); + stream_putc(s, router_cap->msd); + } + } + + /* Adjust TLV length which depends on subTLVs presence */ + tlv_len = stream_get_endp(s) - len_pos - 1; + stream_putc_at(s, len_pos, tlv_len); + + return 0; +} + +static int unpack_tlv_router_cap(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + uint8_t type; + uint8_t length; + uint8_t subtlv_len; + uint8_t sid_len; + + sbuf_push(log, indent, "Unpacking Router Capability TLV...\n"); + if (tlv_len < ISIS_ROUTER_CAP_SIZE) { + sbuf_push(log, indent, "WARNING: Unexpected TLV size\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + if (tlvs->router_cap) { + sbuf_push(log, indent, + "WARNING: Router Capability TLV present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + /* Allocate router cap structure and initialize SR Algorithms */ + tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap)); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET; + + /* Get Router ID and Flags */ + tlvs->router_cap->router_id.s_addr = stream_get_ipv4(s); + tlvs->router_cap->flags = stream_getc(s); + + /* Parse remaining part of the TLV if present */ + subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE; + while (subtlv_len > 2) { + struct isis_router_cap *rc = tlvs->router_cap; + uint8_t msd_type; + + type = stream_getc(s); + length = stream_getc(s); + switch (type) { + case ISIS_SUBTLV_SID_LABEL_RANGE: + rc->srgb.flags = stream_getc(s); + rc->srgb.range_size = stream_get3(s); + /* Skip Type and get Length of SID Label */ + stream_getc(s); + sid_len = stream_getc(s); + if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE) + rc->srgb.lower_bound = stream_get3(s); + else + rc->srgb.lower_bound = stream_getl(s); + + /* SRGB sanity checks. */ + if (rc->srgb.range_size == 0 + || (rc->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX) + || ((rc->srgb.lower_bound + rc->srgb.range_size - 1) + > MPLS_LABEL_UNRESERVED_MAX)) { + sbuf_push(log, indent, "Invalid label range. Reset SRGB\n"); + rc->srgb.lower_bound = 0; + rc->srgb.range_size = 0; + } + break; + case ISIS_SUBTLV_ALGORITHM: + /* Only 2 algorithms are supported: SPF & Strict SPF */ + stream_get(&rc->algo, s, + length > SR_ALGORITHM_COUNT + ? SR_ALGORITHM_COUNT + : length); + if (length > SR_ALGORITHM_COUNT) + stream_forward_getp( + s, length - SR_ALGORITHM_COUNT); + break; + case ISIS_SUBTLV_NODE_MSD: + msd_type = stream_getc(s); + rc->msd = stream_getc(s); + /* Only BMI-MSD type has been defined in RFC 8491 */ + if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION) + rc->msd = 0; + break; + default: + stream_forward_getp(s, length); + break; + } + subtlv_len = subtlv_len - length - 2; + } + return 0; +} + /* Functions related to TLV 10 Authentication */ static struct isis_item *copy_item_auth(struct isis_item *i) { @@ -2318,6 +3216,39 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item) dest->count++; } +static void delete_item(struct isis_item_list *dest, struct isis_item *del) +{ + struct isis_item *item, *prev = NULL, *next; + + /* Sanity Check */ + if ((dest == NULL) || (del == NULL)) + return; + + /* + * TODO: delete is tricky because "dest" is a singly linked list. + * We need to switch a doubly linked list. + */ + for (item = dest->head; item; item = next) { + if (item->next == del) { + prev = item; + break; + } + next = item->next; + } + if (prev) + prev->next = del->next; + if (dest->head == del) + dest->head = del->next; + if ((struct isis_item *)dest->tail == del) { + *dest->tail = prev; + if (prev) + dest->tail = &(*dest->tail)->next; + else + dest->tail = &dest->head; + } + dest->count--; +} + static struct isis_item *last_item(struct isis_item_list *list) { return container_of(list->tail, struct isis_item, next); @@ -2596,6 +3527,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj); + rv->router_cap = copy_tlv_router_cap(tlvs->router_cap); + rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf); return rv; @@ -2631,6 +3564,7 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) format_tlv_dynamic_hostname(tlvs->hostname, buf, indent); format_tlv_te_router_id(tlvs->te_router_id, buf, indent); + format_tlv_router_cap(tlvs->router_cap, buf, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, &tlvs->extended_reach, buf, indent); @@ -2717,6 +3651,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs) free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, &tlvs->mt_ipv6_reach); free_tlv_threeway_adj(tlvs->threeway_adj); + free_tlv_router_cap(tlvs->router_cap); free_tlv_spine_leaf(tlvs->spine_leaf); XFREE(MTYPE_ISIS_TLV, tlvs); @@ -2897,6 +3832,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, fragment_tlvs->hostname = copy_tlv_dynamic_hostname(tlvs->hostname); + rv = pack_tlv_router_cap(tlvs->router_cap, stream); + if (rv) + return rv; + if (fragment_tlvs) { + fragment_tlvs->router_cap = + copy_tlv_router_cap(tlvs->router_cap); + } + rv = pack_tlv_te_router_id(tlvs->te_router_id, stream); if (rv) return rv; @@ -3131,6 +4074,7 @@ ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information"); TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency"); ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address"); ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability"); +TLV_OPS(router_cap, "TLV 242 Router Capability"); ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID"); SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); @@ -3144,21 +4088,22 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_TLV_AUTH] = &tlv_auth_ops, [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops, [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops, - [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops, [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops, [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops, [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops, [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops, [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops, - [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops, [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops, + [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops, - [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops, + [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops, [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, + [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, + [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops, }, [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, [ISIS_CONTEXT_SUBTLV_IP_REACH] = { @@ -3593,6 +4538,18 @@ void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname); } +/* Set Router Capability TLV parameters */ +void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs, + const struct isis_router_cap *cap) +{ + XFREE(MTYPE_ISIS_TLV, tlvs->router_cap); + if (!cap) + return; + + tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap)); + *tlvs->router_cap = *cap; +} + void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, const struct in_addr *id) { @@ -3614,6 +4571,38 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r); } +void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj) +{ + append_item(&exts->adj_sid, (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_ADJ_SID); +} + +void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj) +{ + delete_item(&exts->adj_sid, (struct isis_item *)adj); + XFREE(MTYPE_ISIS_SUBTLV, adj); + if (exts->adj_sid.count == 0) + UNSET_SUBTLV(exts, EXT_ADJ_SID); +} + +void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan) +{ + append_item(&exts->lan_sid, (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_LAN_ADJ_SID); +} + +void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan) +{ + delete_item(&exts->lan_sid, (struct isis_item *)lan); + XFREE(MTYPE_ISIS_SUBTLV, lan); + if (exts->lan_sid.count == 0) + UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID); +} + void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, struct prefix_ipv4 *dest, uint32_t metric) { @@ -3668,17 +4657,14 @@ void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len) + struct isis_ext_subtlvs *exts) { struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); memcpy(r->id, id, sizeof(r->id)); r->metric = metric; - if (subtlvs && subtlv_len) { - r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); - memcpy(r->subtlvs, subtlvs, subtlv_len); - r->subtlv_len = subtlv_len; - } + if (exts) + r->subtlvs = copy_item_ext_subtlvs(exts, mtid); struct isis_item_list *l; if (mtid == ISIS_MT_IPV4_UNICAST) diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 4954d791d8..2948728e2b 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -2,6 +2,8 @@ * IS-IS TLV Serializer/Deserializer * * Copyright (C) 2015,2017 Christian Franke + + * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) * * This file is part of FRR. * @@ -66,14 +68,14 @@ struct isis_lsp_entry { }; struct isis_extended_reach; +struct isis_ext_subtlvs; struct isis_extended_reach { struct isis_extended_reach *next; uint8_t id[7]; uint32_t metric; - uint8_t *subtlvs; - uint8_t subtlv_len; + struct isis_ext_subtlvs *subtlvs; }; struct isis_extended_ip_reach; @@ -130,6 +132,95 @@ struct isis_threeway_adj { uint32_t neighbor_circuit_id; }; +/* + * Segment Routing subTLV's as per + * draft-ietf-isis-segment-routing-extension-25 + */ +#define ISIS_SUBTLV_SRGB_FLAG_I 0x80 +#define ISIS_SUBTLV_SRGB_FLAG_V 0x40 +#define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I) +#define IS_SR_IPV6(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V) + +/* Structure aggregating SRGB info */ +struct isis_srgb { + uint8_t flags; + uint32_t range_size; + uint32_t lower_bound; +}; + +/* Prefix-SID sub-TLVs flags */ +#define ISIS_PREFIX_SID_READVERTISED 0x80 +#define ISIS_PREFIX_SID_NODE 0x40 +#define ISIS_PREFIX_SID_NO_PHP 0x20 +#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10 +#define ISIS_PREFIX_SID_VALUE 0x08 +#define ISIS_PREFIX_SID_LOCAL 0x04 + +struct isis_prefix_sid; +struct isis_prefix_sid { + struct isis_prefix_sid *next; + + uint8_t flags; + uint8_t algorithm; + uint32_t value; +}; + +/* Adj-SID and LAN-Ajd-SID sub-TLVs flags */ +#define EXT_SUBTLV_LINK_ADJ_SID_FFLG 0x80 +#define EXT_SUBTLV_LINK_ADJ_SID_BFLG 0x40 +#define EXT_SUBTLV_LINK_ADJ_SID_VFLG 0x20 +#define EXT_SUBTLV_LINK_ADJ_SID_LFLG 0x10 +#define EXT_SUBTLV_LINK_ADJ_SID_SFLG 0x08 +#define EXT_SUBTLV_LINK_ADJ_SID_PFLG 0x04 + +struct isis_adj_sid; +struct isis_adj_sid { + struct isis_adj_sid *next; + + uint8_t family; + uint8_t flags; + uint8_t weight; + uint32_t sid; +}; + +struct isis_lan_adj_sid; +struct isis_lan_adj_sid { + struct isis_lan_adj_sid *next; + + uint8_t family; + uint8_t flags; + uint8_t weight; + uint8_t neighbor_id[ISIS_SYS_ID_LEN]; + uint32_t sid; +}; + +/* RFC 4971 & RFC 7981 */ +#define ISIS_ROUTER_CAP_FLAG_S 0x01 +#define ISIS_ROUTER_CAP_FLAG_D 0x02 +#define ISIS_ROUTER_CAP_SIZE 5 + +/* Number of supported algorithm for Segment Routing. + * Right now only 2 have been standardized: + * - 0: SPF + * - 1: Strict SPF + */ +#define SR_ALGORITHM_COUNT 2 +#define SR_ALGORITHM_SPF 0 +#define SR_ALGORITHM_STRICT_SPF 1 +#define SR_ALGORITHM_UNSET 255 + +struct isis_router_cap { + struct in_addr router_id; + uint8_t flags; + + /* draft-ietf-segment-routing-extensions-25 */ + struct isis_srgb srgb; + uint8_t algo[SR_ALGORITHM_COUNT]; + /* RFC 8491 */ +#define MSD_TYPE_BASE_MPLS_IMPOSITION 0x01 + uint8_t msd; +}; + struct isis_item; struct isis_item { struct isis_item *next; @@ -233,26 +324,10 @@ struct isis_tlvs { struct isis_item_list ipv6_reach; struct isis_mt_item_list mt_ipv6_reach; struct isis_threeway_adj *threeway_adj; + struct isis_router_cap *router_cap; struct isis_spine_leaf *spine_leaf; }; -#define ISIS_PREFIX_SID_READVERTISED 0x80 -#define ISIS_PREFIX_SID_NODE 0x40 -#define ISIS_PREFIX_SID_NO_PHP 0x20 -#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10 -#define ISIS_PREFIX_SID_VALUE 0x08 -#define ISIS_PREFIX_SID_LOCAL 0x04 - -struct isis_prefix_sid; -struct isis_prefix_sid { - struct isis_prefix_sid *next; - - uint8_t flags; - uint8_t algorithm; - - uint32_t value; -}; - enum isis_tlv_context { ISIS_CONTEXT_LSP, ISIS_CONTEXT_SUBTLV_NE_REACH, @@ -266,11 +341,12 @@ struct isis_subtlvs { /* draft-baker-ipv6-isis-dst-src-routing-06 */ struct prefix_ipv6 *source_prefix; - /* draft-ietf-isis-segment-routing-extensions-16 */ + /* draft-ietf-isis-segment-routing-extensions-25 */ struct isis_item_list prefix_sids; }; enum isis_tlv_type { + /* TLVs code point */ ISIS_TLV_AREA_ADDRESSES = 1, ISIS_TLV_OLDSTYLE_REACH = 2, ISIS_TLV_LAN_NEIGHBORS = 6, @@ -295,10 +371,149 @@ enum isis_tlv_type { ISIS_TLV_IPV6_REACH = 236, ISIS_TLV_MT_IPV6_REACH = 237, ISIS_TLV_THREE_WAY_ADJ = 240, + ISIS_TLV_ROUTER_CAPABILITY = 242, ISIS_TLV_MAX = 256, + /* subTLVs code point */ + ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22, + + /* RFC 5305 & RFC 6119 */ + ISIS_SUBTLV_ADMIN_GRP = 3, + ISIS_SUBTLV_LOCAL_IPADDR = 6, + ISIS_SUBTLV_RMT_IPADDR = 8, + ISIS_SUBTLV_MAX_BW = 9, + ISIS_SUBTLV_MAX_RSV_BW = 10, + ISIS_SUBTLV_UNRSV_BW = 11, + ISIS_SUBTLV_LOCAL_IPADDR6 = 12, + ISIS_SUBTLV_RMT_IPADDR6 = 13, + ISIS_SUBTLV_TE_METRIC = 18, + + /* RFC 5307 */ + ISIS_SUBTLV_LLRI = 4, + + /* RFC 5316 */ + ISIS_SUBTLV_RAS = 24, + ISIS_SUBTLV_RIP = 25, + + /* draft-isis-segment-routing-extension-25 */ + ISIS_SUBTLV_SID_LABEL = 1, + ISIS_SUBTLV_SID_LABEL_RANGE = 2, + ISIS_SUBTLV_ALGORITHM = 19, + ISIS_SUBTLV_NODE_MSD = 23, ISIS_SUBTLV_PREFIX_SID = 3, - ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22 + ISIS_SUBTLV_ADJ_SID = 31, + ISIS_SUBTLV_LAN_ADJ_SID = 32, + + /* RFC 7810 */ + ISIS_SUBTLV_AV_DELAY = 33, + ISIS_SUBTLV_MM_DELAY = 34, + ISIS_SUBTLV_DELAY_VAR = 35, + ISIS_SUBTLV_PKT_LOSS = 36, + ISIS_SUBTLV_RES_BW = 37, + ISIS_SUBTLV_AVA_BW = 38, + ISIS_SUBTLV_USE_BW = 39, + + ISIS_SUBTLV_MAX = 40 +}; + +/* subTLVs size for TE and SR */ +enum ext_subtlv_size { + ISIS_SUBTLV_LLRI_SIZE = 8, + + ISIS_SUBTLV_UNRSV_BW_SIZE = 32, + ISIS_SUBTLV_TE_METRIC_SIZE = 3, + ISIS_SUBTLV_IPV6_ADDR_SIZE = 16, + + /* draft-isis-segment-routing-extension-25 */ + ISIS_SUBTLV_SID_LABEL_SIZE = 3, + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9, + ISIS_SUBTLV_ALGORITHM_SIZE = 4, + ISIS_SUBTLV_NODE_MSD_SIZE = 2, + ISIS_SUBTLV_ADJ_SID_SIZE = 5, + ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11, + ISIS_SUBTLV_PREFIX_SID_SIZE = 5, + + ISIS_SUBTLV_MM_DELAY_SIZE = 8, + + ISIS_SUBTLV_HDR_SIZE = 2, + ISIS_SUBTLV_DEF_SIZE = 4, + + ISIS_SUBTLV_MAX_SIZE = 180 +}; + +/* Macros to manage the optional presence of EXT subTLVs */ +#define SET_SUBTLV(s, t) ((s->status) |= (t)) +#define UNSET_SUBTLV(s, t) ((s->status) &= ~(t)) +#define IS_SUBTLV(s, t) (s->status & t) + +#define EXT_DISABLE 0x000000 +#define EXT_ADM_GRP 0x000001 +#define EXT_LLRI 0x000002 +#define EXT_LOCAL_ADDR 0x000004 +#define EXT_NEIGH_ADDR 0x000008 +#define EXT_LOCAL_ADDR6 0x000010 +#define EXT_NEIGH_ADDR6 0x000020 +#define EXT_MAX_BW 0x000040 +#define EXT_MAX_RSV_BW 0x000080 +#define EXT_UNRSV_BW 0x000100 +#define EXT_TE_METRIC 0x000200 +#define EXT_RMT_AS 0x000400 +#define EXT_RMT_IP 0x000800 +#define EXT_ADJ_SID 0x001000 +#define EXT_LAN_ADJ_SID 0x002000 +#define EXT_DELAY 0x004000 +#define EXT_MM_DELAY 0x008000 +#define EXT_DELAY_VAR 0x010000 +#define EXT_PKT_LOSS 0x020000 +#define EXT_RES_BW 0x040000 +#define EXT_AVA_BW 0x080000 +#define EXT_USE_BW 0x100000 + +/* + * This structure groups all Extended IS Reachability subTLVs. + * + * Each bit of the status field indicates if a subTLVs is valid or not. + * SubTLVs values use following units: + * - Bandwidth in bytes/sec following IEEE format, + * - Delay in micro-seconds with only 24 bits significant + * - Packet Loss in percentage of total traffic with only 24 bits (2^24 - 2) + * + * For Delay and packet Loss, upper bit (A) indicates if the value is + * normal (0) or anomalous (1). + */ +#define IS_ANORMAL(v) (v & 0x80000000) + +struct isis_ext_subtlvs { + + uint32_t status; + + uint32_t adm_group; /* Resource Class/Color - RFC 5305 */ + /* Link Local/Remote Identifiers - RFC 5307 */ + uint32_t local_llri; + uint32_t remote_llri; + struct in_addr local_addr; /* Local IP Address - RFC 5305 */ + struct in_addr neigh_addr; /* Neighbor IP Address - RFC 5305 */ + struct in6_addr local_addr6; /* Local IPv6 Address - RFC 6119 */ + struct in6_addr neigh_addr6; /* Neighbor IPv6 Address - RFC 6119 */ + float max_bw; /* Maximum Bandwidth - RFC 5305 */ + float max_rsv_bw; /* Maximum Reservable Bandwidth - RFC 5305 */ + float unrsv_bw[8]; /* Unreserved Bandwidth - RFC 5305 */ + uint32_t te_metric; /* Traffic Engineering Metric - RFC 5305 */ + uint32_t remote_as; /* Remote AS Number sub-TLV - RFC5316 */ + struct in_addr remote_ip; /* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ + + uint32_t delay; /* Average Link Delay - RFC 8570 */ + uint32_t min_delay; /* Low Link Delay - RFC 8570 */ + uint32_t max_delay; /* High Link Delay - RFC 8570 */ + uint32_t delay_var; /* Link Delay Variation i.e. Jitter - RFC 8570 */ + uint32_t pkt_loss; /* Unidirectional Link Packet Loss - RFC 8570 */ + float res_bw; /* Unidirectional Residual Bandwidth - RFC 8570 */ + float ava_bw; /* Unidirectional Available Bandwidth - RFC 8570 */ + float use_bw; /* Unidirectional Utilized Bandwidth - RFC 8570 */ + + /* Segment Routing Adjacency & LAN Adjacency Segment ID */ + struct isis_item_list adj_sid; + struct isis_item_list lan_sid; }; #define IS_COMPAT_MT_TLV(tlv_type) \ @@ -329,7 +544,6 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size); #define ISIS_MT_AT_MASK 0x4000 #endif - void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd); void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs, struct list *addresses); @@ -359,6 +573,8 @@ void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id, struct isis_lsp **last_lsp); void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, const char *hostname); +void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs, + const struct isis_router_cap *cap); void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, const struct in_addr *id); void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, @@ -371,11 +587,21 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid, struct prefix_ipv6 *dest, struct prefix_ipv6 *src, uint32_t metric); +struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void); +void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj); +void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_adj_sid *adj); +void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan); +void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts, + struct isis_lan_adj_sid *lan); + void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, uint8_t metric); void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, uint8_t *id, uint32_t metric, - uint8_t *subtlvs, uint8_t subtlv_len); + struct isis_ext_subtlvs *subtlvs); const char *isis_threeway_state_name(enum isis_threeway_state state); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index e8481a558b..39a2f6ef35 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -53,6 +53,8 @@ struct zclient *zclient = NULL; +DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) + /* Router-id update message from zebra. */ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) { @@ -82,6 +84,8 @@ static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS) isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); + hook_call(isis_if_new_hook, ifp); + return 0; } @@ -219,9 +223,9 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS) return 0; } -static void isis_zebra_route_add_route(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) +void isis_zebra_route_add_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -229,7 +233,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix, struct listnode *node; int count = 0; - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + if (zclient->sock < 0) return; memset(&api, 0, sizeof(api)); @@ -292,17 +296,15 @@ static void isis_zebra_route_add_route(struct prefix *prefix, api.nexthop_num = count; zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); - SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } -static void isis_zebra_route_del_route(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) +void isis_zebra_route_del_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info) { struct zapi_route api; - if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + if (zclient->sock < 0) return; memset(&api, 0, sizeof(api)); @@ -316,20 +318,6 @@ static void isis_zebra_route_del_route(struct prefix *prefix, } zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); -} - -void isis_zebra_route_update(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info) -{ - if (zclient->sock < 0) - return; - - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) - isis_zebra_route_add_route(prefix, src_p, route_info); - else - isis_zebra_route_del_route(prefix, src_p, route_info); } static int isis_zebra_read(ZAPI_CALLBACK_ARGS) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 20c10d0b23..83a32108eb 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -24,14 +24,19 @@ extern struct zclient *zclient; +DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); + void isis_zebra_init(struct thread_master *); void isis_zebra_stop(void); struct isis_route_info; -void isis_zebra_route_update(struct prefix *prefix, - struct prefix_ipv6 *src_p, - struct isis_route_info *route_info); +void isis_zebra_route_add_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); +void isis_zebra_route_del_route(struct prefix *prefix, + struct prefix_ipv6 *src_p, + struct isis_route_info *route_info); int isis_distribute_list_update(int routetype); void isis_zebra_redistribute_set(afi_t afi, int type); void isis_zebra_redistribute_unset(afi_t afi, int type); diff --git a/isisd/isisd.h b/isisd/isisd.h index 393b1d67c7..308f018c19 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -58,7 +58,6 @@ extern struct zebra_privs_t isisd_privs; /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ -/* #define EXTREME_DICT_DEBUG */ struct fabricd; diff --git a/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); + } } } diff --git a/lib/libfrr.c b/lib/libfrr.c index 4301dc20ad..478fe4e205 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(); @@ -1076,6 +1079,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); diff --git a/lib/mpls.h b/lib/mpls.h index 472ee9bc46..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 */ 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) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 4d1c085081..7914412e87 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1593,7 +1593,6 @@ static int route_map_command_status(struct vty *vty, enum rmap_compile_rets ret) return CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: - case RMAP_DUPLICATE_RULE: break; } diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 36bb8d49b5..bee7bbb21d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -216,16 +216,6 @@ int main(int argc, char **argv) /* OSPF errors init */ ospf_error_init(); - /* Need to initialize the default ospf structure, so the interface mode - commands can be duly processed if they are received before 'router - ospf', - when quagga(ospfd) is restarted */ - if (!ospf_get_instance(instance)) { - flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s", - strerror(errno)); - exit(1); - } - frr_config_fork(); frr_run(master); diff --git a/ospfd/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/ripd/ripd.c b/ripd/ripd.c index ad373aebdf..cd2ddb1eba 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3641,6 +3641,41 @@ 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; + + pthread_rwlock_wrlock(&running_config->lock); + { + 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++; + } + } + pthread_rwlock_unlock(&running_config->lock); + } + if (old_vrf_name) + XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name); + } if (!rip || rip->enabled) return 0; @@ -3682,7 +3717,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..120f46f0da 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2776,7 +2776,43 @@ 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; + + pthread_rwlock_wrlock(&running_config->lock); + { + 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++; + } + } + pthread_rwlock_unlock(&running_config->lock); + } + if (old_vrf_name) + XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name); + } + + if (ripng->enabled) return 0; if (IS_RIPNG_DEBUG_EVENT) @@ -2784,13 +2820,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 +2851,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/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/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/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/zebra_rib.c b/zebra/zebra_rib.c index 157c67fa62..d8fb9ae3cf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2088,14 +2088,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 +3286,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_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 */ |
