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.
/* 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);
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;
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)
return NULL;
return bfd->vrf->info;
}
+
+void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
+{
+ if (!vrf || !bs)
+ return;
+ /* update key */
+ hash_release(bfd_key_hash, bs);
+ /*
+ * HACK: Change the BFD VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the BFD and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) {
+ struct lyd_node *bfd_dnode;
+ char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
+ char addr_buf[INET6_ADDRSTRLEN];
+ int slen;
+
+ /* build xpath */
+ if (bs->key.mhop) {
+ inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf));
+ snprintf(xpath_srcaddr, sizeof(xpath_srcaddr), "[source-addr='%s']",
+ addr_buf);
+ } else
+ xpath_srcaddr[0] = 0;
+ inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf));
+ slen = snprintf(xpath, sizeof(xpath),
+ "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
+ bs->key.mhop ? "multi-hop" : "single-hop", xpath_srcaddr,
+ addr_buf);
+ if (bs->key.ifname[0])
+ slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+ "[interface='%s']", bs->key.ifname);
+ else
+ slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+ "[interface='']");
+ snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf",
+ bs->key.vrfname);
+
+ bfd_dnode = yang_dnode_get(running_config->dnode, xpath,
+ bs->key.vrfname);
+ if (bfd_dnode) {
+ yang_dnode_change_leaf(bfd_dnode, vrf->name);
+ running_config->version++;
+ }
+ }
+ memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname));
+ strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname));
+ hash_get(bfd_key_hash, bs, hash_alloc_intern);
+}
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);
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;
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);
/* 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] &&
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;
}
&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;
}
struct community *community,
struct ecommunity *ecommunity,
struct lcommunity *lcommunity,
- int as_set, uint8_t atomic_aggregate)
+ struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate,
+ struct prefix *p)
{
struct attr attr;
struct attr *new;
+ int ret;
memset(&attr, 0, sizeof(struct attr));
attr.label = MPLS_INVALID_LABEL;
attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
- if (!as_set || atomic_aggregate)
+ if (!aggregate->as_set || atomic_aggregate)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
attr.label_index = BGP_INVALID_LABEL_INDEX;
attr.label = MPLS_INVALID_LABEL;
- new = bgp_attr_intern(&attr);
+ /* Apply route-map */
+ if (aggregate->rmap.name) {
+ struct attr attr_tmp = attr;
+ struct bgp_path_info rmap_path;
+
+ memset(&rmap_path, 0, sizeof(struct bgp_path_info));
+ rmap_path.peer = bgp->peer_self;
+ rmap_path.attr = &attr_tmp;
+
+ SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
+
+ ret = route_map_apply(aggregate->rmap.map, p, RMAP_BGP,
+ &rmap_path);
+
+ bgp->peer_self->rmap_type = 0;
+
+ if (ret == RMAP_DENYMATCH) {
+ /* Free uninterned attribute. */
+ bgp_attr_flush(&attr_tmp);
+
+ /* Unintern original. */
+ aspath_unintern(&attr.aspath);
+ return NULL;
+ }
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr_tmp);
+
+ new = bgp_attr_intern(&attr_tmp);
+ } else {
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr);
+
+ new = bgp_attr_intern(&attr);
+ }
aspath_unintern(&new->aspath);
return new;
#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;
}
*/
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;
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;
}
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;
}
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;
}
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;
}
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,
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;
}
/* 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;
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);
}
}
/* EVPN local router-mac */
struct ethaddr rmac;
+
+ /* Distance as applied by Route map */
+ uint8_t distance;
};
/* rmap_change_flags definition */
struct community *community,
struct ecommunity *ecommunity,
struct lcommunity *lcommunity,
- int as_set,
- uint8_t atomic_aggregate);
+ struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate,
+ struct prefix *p);
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct bpacket_attr_vec_arr *vecarr,
#define BMP_STR "BGP Monitoring Protocol\n"
#ifndef VTYSH_EXTRACT_PL
-#include "bgp_bmp_clippy.c"
+#include "bgpd/bgp_bmp_clippy.c"
#endif
DEFPY_NOSH(bmp_targets_main,
for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn))
bgpevpn_unlink_from_l3vni(vpn);
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
+
/* Delete the instance if it was autocreated */
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
bgp_delete(bgp_vrf);
/* 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;
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 =
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". */
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)
static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
- static_attr.mp_nexthop_len = 4;
+ static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
break;
case AF_INET6:
static_attr.mp_nexthop_global = nexthop->u.prefix6;
- static_attr.mp_nexthop_len = 16;
+ static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
break;
default:
*/
static_attr.mp_nexthop_global_in =
static_attr.nexthop;
- static_attr.mp_nexthop_len = 4;
+ static_attr.mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV4;
/*
* XXX Leave static_attr.nexthop
* intact for NHT
&& !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
static_attr.mp_nexthop_global_in.s_addr =
static_attr.nexthop.s_addr;
- static_attr.mp_nexthop_len = 4;
+ static_attr.mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV4;
static_attr.flag |=
ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
}
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);
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);
/* 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
/* 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 *);
static void bgp_aggregate_free(struct bgp_aggregate *aggregate)
{
+ XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+ route_map_counter_decrement(aggregate->rmap.map);
XFREE(MTYPE_BGP_AGGREGATE, aggregate);
}
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_path_info *pi, *orig, *new;
+ struct attr *attr;
table = bgp->rib[afi][safi];
if (pi)
bgp_path_info_delete(rn, pi);
+ attr = bgp_attr_aggregate_intern(
+ bgp, origin, aspath, community, ecommunity, lcommunity,
+ aggregate, atomic_aggregate, p);
+
+ if (!attr) {
+ bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
+ return;
+ }
+
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0,
- bgp->peer_self,
- bgp_attr_aggregate_intern(bgp, origin, aspath,
- community, ecommunity,
- lcommunity,
- aggregate->as_set,
- atomic_aggregate),
- rn);
+ bgp->peer_self, attr, rn);
+
SET_FLAG(new->flags, BGP_PATH_VALID);
bgp_path_info_add(rn, new);
}
/* Update an aggregate as routes are added/removed from the BGP table */
-static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
+void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
afi_t afi, safi_t safi,
struct bgp_aggregate *aggregate)
{
aggregate);
}
-static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
safi_t safi, struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
}
static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
- safi_t safi, uint8_t summary_only, uint8_t as_set)
+ safi_t safi, const char *rmap, uint8_t summary_only,
+ uint8_t as_set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
/* Old configuration check. */
rn = bgp_node_get(bgp->aggregate[afi][safi], &p);
+ aggregate = bgp_node_get_bgp_aggregate_info(rn);
- if (bgp_node_has_bgp_path_info_data(rn)) {
+ if (aggregate) {
vty_out(vty, "There is already same aggregate network.\n");
/* try to remove the old entry */
ret = bgp_aggregate_unset(vty, prefix_str, afi, safi);
aggregate->summary_only = summary_only;
aggregate->as_set = as_set;
aggregate->safi = safi;
+
+ if (rmap) {
+ XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+ route_map_counter_decrement(aggregate->rmap.map);
+ aggregate->rmap.name =
+ XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+ aggregate->rmap.map = route_map_lookup_by_name(rmap);
+ route_map_counter_increment(aggregate->rmap.map);
+ }
bgp_node_set_bgp_aggregate_info(rn, aggregate);
/* Aggregate address insert into BGP routing table. */
DEFUN (aggregate_address,
aggregate_address_cmd,
- "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D/M", &idx);
char *prefix = argv[idx]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
idx = 0;
? AGGREGATE_SUMMARY_ONLY
: 0;
+ idx = 0;
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty),
- summary_only, as_set);
+ rmap, summary_only, as_set);
}
DEFUN (aggregate_address_mask,
aggregate_address_mask_cmd,
- "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate address\n"
"Aggregate mask\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D", &idx);
char *prefix = argv[idx]->arg;
char *mask = argv[idx + 1]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
idx = 0;
? AGGREGATE_SUMMARY_ONLY
: 0;
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
char prefix_str[BUFSIZ];
int ret = netmask_str2prefix_str(prefix, mask, prefix_str);
}
return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
- summary_only, as_set);
+ rmap, summary_only, as_set);
}
DEFUN (no_aggregate_address,
DEFUN (ipv6_aggregate_address,
ipv6_aggregate_address_cmd,
- "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "X:X::X:X/M", &idx);
char *prefix = argv[idx]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
int sum_only = argv_find(argv, argc, "summary-only", &idx)
? AGGREGATE_SUMMARY_ONLY
: 0;
- return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only,
- as_set);
+
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
+ return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap,
+ sum_only, as_set);
}
DEFUN (no_ipv6_aggregate_address,
/* We display both LL & GL if both have been
* received */
- if ((attr->mp_nexthop_len == 32)
+ if ((attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
|| (path->peer->conf_if)) {
json_nexthop_ll = json_object_new_object();
json_object_string_add(
} else {
/* Display LL if LL/Global both in table unless
* prefer-global is set */
- if (((attr->mp_nexthop_len == 32)
+ if (((attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
&& !attr->mp_nexthop_prefer_global)
|| (path->peer->conf_if)) {
if (path->peer->conf_if) {
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);
if (bgp_aggregate->summary_only)
vty_out(vty, " summary-only");
+ if (bgp_aggregate->rmap.name)
+ vty_out(vty, " route-map %s", bgp_aggregate->rmap.name);
+
vty_out(vty, "\n");
}
}
#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 */
uint8_t as_set;
/* Route-map for aggregated route. */
- struct route_map *map;
+ struct {
+ char *name;
+ struct route_map *map;
+ } rmap;
/* Suppress-count. */
unsigned long count;
extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t,
safi_t);
+extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate);
+extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate);
extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi);
/* If su='0.0.0.0' (command 'match peer local'), and it's a
NETWORK,
- REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH
+ REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route
+ => return RMAP_MATCH
*/
if (sockunion_same(su, &su_def)) {
int ret;
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_NETWORK)
|| CHECK_FLAG(peer->rmap_type,
PEER_RMAP_TYPE_REDISTRIBUTE)
+ || CHECK_FLAG(peer->rmap_type,
+ PEER_RMAP_TYPE_AGGREGATE)
|| CHECK_FLAG(peer->rmap_type,
PEER_RMAP_TYPE_DEFAULT))
ret = RMAP_MATCH;
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
/* 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. */
"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. */
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,
/* Set next hop value and length in attribute. */
if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) {
path->attr->mp_nexthop_local = peer_address;
- if (path->attr->mp_nexthop_len != 32)
- path->attr->mp_nexthop_len = 32;
+ if (path->attr->mp_nexthop_len
+ != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+ path->attr->mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
} else {
path->attr->mp_nexthop_global = peer_address;
if (path->attr->mp_nexthop_len == 0)
- path->attr->mp_nexthop_len = 16;
+ path->attr->mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV6_GLOBAL;
}
} else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
/* Set next hop value. */
path->attr->mp_nexthop_global_in = *address;
- path->attr->mp_nexthop_len = 4;
+ path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
}
return RMAP_OKAY;
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.
*/
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");
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
*/
struct peer *peer;
struct bgp_node *bn;
struct bgp_static *bgp_static;
+ struct bgp_aggregate *aggregate;
struct listnode *node, *nnode;
struct route_map *map;
char buf[INET6_ADDRSTRLEN];
safi);
}
}
+
+ /* For aggregate-address route-map updates. */
+ for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn;
+ bn = bgp_route_next(bn)) {
+ aggregate = bgp_node_get_bgp_aggregate_info(bn);
+ if (!aggregate)
+ continue;
+
+ if (!aggregate->rmap.name
+ || (strcmp(rmap_name, aggregate->rmap.name) != 0))
+ continue;
+
+ if (!aggregate->rmap.map)
+ route_map_counter_increment(map);
+
+ aggregate->rmap.map = map;
+
+ if (route_update) {
+ if (bgp_debug_zebra(&bn->p))
+ zlog_debug(
+ "Processing route_map %s update on aggregate-address route %s",
+ rmap_name,
+ inet_ntop(bn->p.family,
+ &bn->p.u.prefix, buf,
+ INET6_ADDRSTRLEN));
+ bgp_aggregate_route(bgp, &bn->p, afi, safi,
+ aggregate);
+ }
+ }
}
/* For redistribute route-map updates. */
"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,
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);
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);
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
*/
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:
vty_out(vty, "%% BGP Argument is malformed.\n");
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
/*
* Nothing to do here
*/
&& !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;
&& !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;
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,
void bgp_pthreads_finish(void)
{
frr_pthread_stop_all();
- frr_pthread_finish();
}
void bgp_init(unsigned short instance)
#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */
#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */
#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */
+#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */
/* peer specific BFD information */
struct bfd_info *bfd_info;
attr.nexthop.s_addr = nexthop->addr.v4.s_addr;
attr.mp_nexthop_global_in = nexthop->addr.v4;
- attr.mp_nexthop_len = 4;
+ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
break;
case AF_INET6:
attr.mp_nexthop_global = nexthop->addr.v6;
- attr.mp_nexthop_len = 16;
+ attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
break;
default:
switch (use_nexthop->family) {
case AF_INET:
new->nexthop = use_nexthop->u.prefix4;
- new->mp_nexthop_len = 4; /* bytes */
+ new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
break;
case AF_INET6:
new->mp_nexthop_global = use_nexthop->u.prefix6;
- new->mp_nexthop_len = 16; /* bytes */
+ new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
break;
default:
switch (use_nexthop->family) {
case AF_INET:
new->nexthop = use_nexthop->u.prefix4;
- new->mp_nexthop_len = 4; /* bytes */
+ new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
break;
case AF_INET6:
new->mp_nexthop_global = use_nexthop->u.prefix6;
- new->mp_nexthop_len = 16; /* bytes */
+ new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
break;
default:
usr/lib/frr/frr-reload.py
+usr/lib/frr/generate_support_bundle.py
dh_auto_install
sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/frr-reload.py
+ sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/generate_support_bundle.py
# let dh_systemd_* and dh_installinit do their thing automatically
ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),)
This command specifies an aggregate address.
+.. index:: aggregate-address A.B.C.D/M route-map NAME
+.. clicmd:: aggregate-address A.B.C.D/M route-map NAME
+
+ Apply a route-map for an aggregated prefix.
+
.. index:: aggregate-address A.B.C.D/M as-set
.. clicmd:: aggregate-address A.B.C.D/M as-set
.. index:: no aggregate-address A.B.C.D/M
.. clicmd:: no aggregate-address A.B.C.D/M
-
+
This command removes an aggregate address.
- This configuration example setup the aggregate-address under
+ This configuration example setup the aggregate-address under
ipv4 address-family.
.. code-block:: frr
aggregate-address 10.0.0.0/8
aggregate-address 20.0.0.0/8 as-set
aggregate-address 40.0.0.0/8 summary-only
+ aggregate-address 50.0.0.0/8 route-map aggr-rmap
exit-address-family
This command specifies an aggregate address.
+.. index:: aggregate-address X:X::X:X/M route-map NAME
+.. clicmd:: aggregate-address X:X::X:X/M route-map NAME
+
+ Apply a route-map for an aggregated prefix.
+
.. index:: aggregate-address X:X::X:X/M as-set
.. clicmd:: aggregate-address X:X::X:X/M as-set
This command removes an aggregate address.
- This configuration example setup the aggregate-address under
- ipv4 address-family.
+ This configuration example setup the aggregate-address under
+ ipv6 address-family.
.. code-block:: frr
router bgp 1
address-family ipv6 unicast
aggregate-address 10::0/64
- aggregate-address 20::0/64 as-set
- aggregate-address 40::0/64 summary-only
+ aggregate-address 20::0/64 as-set
+ aggregate-address 40::0/64 summary-only
+ aggregate-address 50::0/64 route-map aggr-rmap
exit-address-family
.. _bgp-redistribute-to-bgp:
Displaying Routes by Large Community Attribute
----------------------------------------------
-The following commands allow displaying routes based on their
+The following commands allow displaying routes based on their
large community attribute.
.. index:: show [ip] bgp <ipv4|ipv6> large-community
These commands display BGP routes which have the large community attribute.
attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that
- large community are displayed. When `exact-match` is specified, it display
- only routes that have an exact match. When `json` is specified, it display
+ large community are displayed. When `exact-match` is specified, it display
+ only routes that have an exact match. When `json` is specified, it display
routes in json format.
.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD
.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json
These commands display BGP routes for the address family specified that
- match the specified large community list. When `exact-match` is specified,
- it displays only routes that have an exact match. When `json` is specified,
+ match the specified large community list. When `exact-match` is specified,
+ it displays only routes that have an exact match. When `json` is specified,
it display routes in json format.
.. _bgp-display-routes-by-as-path:
vnc
vrrp
bmp
+ watchfrr
########
Appendix
link-state messages. From this collection of LSAs in the LSDB, each router can
then calculate the shortest path to any other router, based on some common
metric, by using an algorithm such as
-`Edsger Djikstra's <http://www.cs.utexas.edu/users/EWD/>`_
+`Edsger Dijkstra's <http://www.cs.utexas.edu/users/EWD/>`_
:abbr:`SPF (Shortest Path First)` algorithm.
.. index:: Link-state routing protocol advantages
.. clicmd:: ip pim sm
Tell pim that we would like to use this interface to form pim neighbors
- over. Please note we will *not* accept igmp reports over this interface with
- this command.
+ over. Please note that this command does not enable the reception of IGMP
+ reports on the interface. Refer to the next `ip igmp` command for IGMP
+ management.
.. index:: ip igmp
.. clicmd:: ip igmp
Tell pim to receive IGMP reports and Query on this interface. The default
- version is v3. This command is useful on the LHR.
+ version is v3. This command is useful on a LHR.
.. index:: ip igmp join A.B.C.D A.B.C.D
.. clicmd:: ip igmp join A.B.C.D A.B.C.D
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
doc/user/zebra.rst \
doc/user/bfd.rst \
doc/user/flowspec.rst \
+ doc/user/watchfrr.rst \
# end
EXTRA_DIST += \
--- /dev/null
+.. _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.
.. _zebra-vrf:
+Administrative Distance
+=======================
+
+Administrative distance allows FRR to make decisions about what routes
+should be installed in the rib based upon the originating protocol.
+The lowest Admin Distance is the route selected. This is purely a
+subjective decision about ordering and care has been taken to choose
+the same distances that other routing suites have choosen.
+
++------------+-----------+
+| Protocol | Distance |
++------------+-----------+
+| System | 0 |
++------------+-----------+
+| Kernel | 0 |
++------------+-----------+
+| Connect | 0 |
++------------+-----------+
+| Static | 1 |
++------------+-----------+
+| NHRP | 10 |
++------------+-----------+
+| EBGP | 20 |
++------------+-----------+
+| EIGRP | 90 |
++------------+-----------+
+| BABEL | 100 |
++------------+-----------+
+| OSPF | 110 |
++------------+-----------+
+| ISIS | 115 |
++------------+-----------+
+| OPENFABRIC | 115 |
++------------+-----------+
+| RIP | 120 |
++------------+-----------+
+| Table | 150 |
++------------+-----------+
+| SHARP | 150 |
++------------+-----------+
+| IBGP | 200 |
++------------+-----------+
+| PBR | 200 |
++------------+-----------+
+
+An admin distance of 255 indicates to Zebra that the route should not be
+installed into the Data Plane. Additionally routes with an admin distance
+of 255 will not be redistributed.
+
+Zebra does treat Kernel routes as special case for the purposes of Admin
+Distance. Upon learning about a route that is not originated by FRR
+we read the metric value as a uint32_t. The top byte of the value
+is interpreted as the Administrative Distance and the low three bytes
+are read in as the metric. This special case is to facilitate VRF
+default routes.
+
Virtual Routing and Forwarding
==============================
This command will dump the routing tables within the vrf scope. If `vrf all`
is executed, all routing tables will be dumped.
+.. index:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix]
+.. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix]
+
+ This command will dump a summary output of the specified VRF and TABLENO
+ combination. If neither VRF or TABLENO is specified FRR defaults to
+ the default vrf and default table. If prefix is specified dump the
+ number of prefix routes.
+
By using the :option:`-n` option, the *Linux network namespace* will be mapped
over the *Zebra* VRF. One nice feature that is possible by handling *Linux
network namespace* is the ability to name default VRF. At startup, *Zebra*
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
/*
* Intentionally not handling these cases
*/
{
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");
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
/*
* These cases intentionally ignored
*/
}
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
/*
* These cases intentionally left blank here
*/
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
/*
* These cases intentionally not handled
*/
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 \
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 \
}
#endif /* ifndef FABRICD */
- circuit->mtc = mpls_te_circuit_new();
-
circuit_mt_init(circuit);
QOBJ_REG(circuit, isis_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,
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)
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)
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 */
}
/* check if the interface is a loopback and if so set it as passive */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp && if_is_loopback(ifp))
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
- NB_OP_MODIFY, "true");
- }
- pthread_rwlock_unlock(&running_config->lock);
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp && if_is_loopback(ifp))
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+ NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
}
/* check if the interface is a loopback and if so set it as passive */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp && if_is_loopback(ifp))
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
- NB_OP_MODIFY, "true");
- }
- pthread_rwlock_unlock(&running_config->lock);
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp && if_is_loopback(ifp))
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+ NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
"Act as both a station router and an area router\n"
"Act as an area router only\n")
{
- const char *value;
-
- pthread_rwlock_rdlock(&running_config->lock);
- {
- struct isis_area *area;
+ const char *value = NULL;
+ struct isis_area *area;
- area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-
- /*
- * Put the is-type back to defaults:
- * - level-1-2 on first area
- * - level-1 for the rest
- */
- if (area && listgetdata(listhead(isis->area_list)) == area)
- value = "level-1-2";
- else
- value = NULL;
- }
- pthread_rwlock_unlock(&running_config->lock);
+ area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ /*
+ * Put the is-type back to defaults:
+ * - level-1-2 on first area
+ * - level-1 for the rest
+ */
+ if (area && listgetdata(listhead(isis->area_list)) == area)
+ value = "level-1-2";
+ else
+ value = NULL;
nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
- const char *circ_type = NULL;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ int is_type;
+ const char *circ_type;
/*
* Default value depends on whether the circuit is part of an area,
* and the is-type of the area if there is one. So we need to do this
* here.
*/
- pthread_rwlock_rdlock(&running_config->lock);
- {
- struct interface *ifp;
- struct isis_circuit *circuit;
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (!ifp)
+ goto def_val;
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (!ifp)
- goto unlock;
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ goto def_val;
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit || circuit->state != C_STATE_UP)
- goto unlock;
+ if (circuit->state == C_STATE_UP)
+ is_type = circuit->area->is_type;
+ else
+ goto def_val;
- switch (circuit->area->is_type) {
- case IS_LEVEL_1:
- circ_type = "level-1";
- break;
- case IS_LEVEL_2:
- circ_type = "level-2";
- break;
- case IS_LEVEL_1_AND_2:
- circ_type = "level-1-2";
- break;
- }
+ switch (is_type) {
+ case IS_LEVEL_1:
+ circ_type = "level-1";
+ break;
+ case IS_LEVEL_2:
+ circ_type = "level-2";
+ break;
+ case IS_LEVEL_1_AND_2:
+ circ_type = "level-1-2";
+ break;
+ default:
+ return CMD_ERR_NO_MATCH;
}
-unlock:
- pthread_rwlock_unlock(&running_config->lock);
-
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
NB_OP_MODIFY, circ_type);
return nb_cli_apply_changes(vty, NULL);
+
+def_val:
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
+ NB_OP_MODIFY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
#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"
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);
/* 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",
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));
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);
&& 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(
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(
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;
}
tlvs_add_mt_p2p(lsp->tlvs, circuit,
- ne_id, neighbor_metric,
- subtlvs, subtlv_len);
+ ne_id, neighbor_metric);
}
} else {
lsp_debug(
}
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),
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),
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];
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)
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
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));
* 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;
/* 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)
0);
}
+ zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
+ area->area_tag);
+
return NB_OK;
}
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,
#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)
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;
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)
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;
* directly for
* validating => no problems with deleting routes. */
if (!tables) {
- isis_route_delete(rnode, table);
+ isis_route_delete(area, rnode, table);
continue;
}
route_unlock_node(drnode);
}
- isis_route_delete(rnode, table);
+ isis_route_delete(area, rnode, table);
}
}
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,
*
* 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.
*
#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"
#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"};
* 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,
{
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);
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,
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");
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. */
"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);
}
}
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);
*
* 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.
*
* 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
#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;
/* 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 {
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 */
*
* 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
#include "memory.h"
#include "stream.h"
#include "sbuf.h"
+#include "network.h"
#include "isisd/isisd.h"
#include "isisd/isis_memory.h"
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. */
/* 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;
{
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)
}
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. "
if (sid.flags & ISIS_PREFIX_SID_VALUE) {
sid.value = stream_get3(s);
+ sid.value &= MPLS_LABEL_VALUE_MASK;
} else {
sid.value = stream_getl(s);
}
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;
}
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);
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;
}
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;
}
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
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:
rv->metric = r->metric;
rv->down = r->down;
rv->prefix = r->prefix;
+ rv->subtlvs = copy_subtlvs(r->subtlvs);
return (struct isis_item *)rv;
}
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;
}
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;
}
}
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,
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)
{
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);
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;
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);
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);
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;
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");
[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] = {
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)
{
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)
{
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)
* 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.
*
};
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;
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;
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,
/* 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,
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) \
#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);
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,
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);
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)
{
isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
ifp);
+ hook_call(isis_if_new_hook, ifp);
+
return 0;
}
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;
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));
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));
}
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)
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);
/* uncomment if you are a developer in bug hunt */
/* #define EXTREME_DEBUG */
-/* #define EXTREME_DICT_DEBUG */
struct fabricd;
l2vpn_pw_fec(pw, &fec);
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
- 0, (void *)pw);
+ 0, 0, (void *)pw);
lde_kernel_update(&fec);
}
struct zapi_pw zpw;
l2vpn_pw_fec(pw, &fec);
- lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
+ lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0);
lde_kernel_update(&fec);
pw2zpw(pw, &zpw);
if (pw == NULL)
return;
- fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0);
+ fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0);
if (fnh == NULL)
return;
}
fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
- 0, 0);
+ 0, 0, 0);
if (fnh == NULL)
continue;
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
lde_kernel_insert(&fec, kr->af, &kr->nexthop,
- kr->ifindex, kr->priority,
+ kr->ifindex, kr->route_type,
+ kr->route_instance,
kr->flags & F_CONNECTED, NULL);
break;
case IMSG_NETWORK_UPDATE:
kr.ifindex = fnh->ifindex;
kr.local_label = fn->local_label;
kr.remote_label = fnh->remote_label;
- kr.priority = fnh->priority;
+ kr.route_type = fnh->route_type;
+ kr.route_instance = fnh->route_instance;
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr));
kr.ifindex = fnh->ifindex;
kr.local_label = fn->local_label;
kr.remote_label = fnh->remote_label;
- kr.priority = fnh->priority;
+ kr.route_type = fnh->route_type;
+ kr.route_instance = fnh->route_instance;
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr));
kr.ifindex = fnh->ifindex;
kr.local_label = fn->local_label;
kr.remote_label = fnh->remote_label;
- kr.priority = fnh->priority;
+ kr.route_type = fnh->route_type;
+ kr.route_instance = fnh->route_instance;
lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
sizeof(kr));
kr.ifindex = fnh->ifindex;
kr.local_label = fn->local_label;
kr.remote_label = fnh->remote_label;
- kr.priority = fnh->priority;
+ kr.route_type = fnh->route_type;
+ kr.route_instance = fnh->route_instance;
lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
sizeof(kr));
union ldpd_addr nexthop;
ifindex_t ifindex;
uint32_t remote_label;
- uint8_t priority;
+ uint8_t route_type;
+ unsigned short route_instance;
uint8_t flags;
};
#define F_FEC_NH_NEW 0x01
void fec_snap(struct lde_nbr *);
void fec_tree_clear(void);
struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *,
- ifindex_t, uint8_t);
+ ifindex_t, uint8_t, unsigned short);
void lde_kernel_insert(struct fec *, int, union ldpd_addr *,
- ifindex_t, uint8_t, int, void *);
+ ifindex_t, uint8_t, unsigned short, int, void *);
void lde_kernel_remove(struct fec *, int, union ldpd_addr *,
- ifindex_t, uint8_t);
+ ifindex_t, uint8_t, unsigned short);
void lde_kernel_update(struct fec *);
void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(struct map *, struct lde_nbr *);
static void fec_free(void *);
static struct fec_node *fec_add(struct fec *fec);
static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *,
- ifindex_t, uint8_t);
+ ifindex_t, uint8_t, unsigned short);
static void fec_nh_del(struct fec_nh *);
RB_GENERATE(fec_tree, fec, entry, fec_compare)
struct fec_nh *
fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
- ifindex_t ifindex, uint8_t priority)
+ ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
{
struct fec_nh *fnh;
if (fnh->af == af &&
ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 &&
fnh->ifindex == ifindex &&
- fnh->priority == priority)
+ fnh->route_type == route_type &&
+ fnh->route_instance == route_instance)
return (fnh);
return (NULL);
static struct fec_nh *
fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
- ifindex_t ifindex, uint8_t priority)
+ ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
{
struct fec_nh *fnh;
fnh->nexthop = *nexthop;
fnh->ifindex = ifindex;
fnh->remote_label = NO_LABEL;
- fnh->priority = priority;
+ fnh->route_type = route_type;
+ fnh->route_instance = route_instance;
LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
return (fnh);
void
lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
- ifindex_t ifindex, uint8_t priority, int connected, void *data)
+ ifindex_t ifindex, uint8_t route_type, unsigned short route_instance,
+ int connected, void *data)
{
struct fec_node *fn;
struct fec_nh *fnh;
if (data)
fn->data = data;
- fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+ fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
if (fnh == NULL)
- fnh = fec_nh_add(fn, af, nexthop, ifindex, priority);
+ fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
+ route_instance);
fnh->flags |= F_FEC_NH_NEW;
if (connected)
fnh->flags |= F_FEC_NH_CONNECTED;
void
lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
- ifindex_t ifindex, uint8_t priority)
+ ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
{
struct fec_node *fn;
struct fec_nh *fnh;
if (fn == NULL)
/* route lost */
return;
- fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+ fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
if (fnh == NULL)
/* route lost */
return;
static void ifp2kif(struct interface *, struct kif *);
static void ifc2kaddr(struct interface *, struct connected *,
struct kaddr *);
-static int zebra_send_mpls_labels(int, struct kroute *);
+static int ldp_zebra_send_mpls_labels(int, struct kroute *);
static int ldp_router_id_update(ZAPI_CALLBACK_ARGS);
static int ldp_interface_add(ZAPI_CALLBACK_ARGS);
static int ldp_interface_delete(ZAPI_CALLBACK_ARGS);
}
static int
-zebra_send_mpls_labels(int cmd, struct kroute *kr)
+ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
{
- struct stream *s;
+ struct zapi_labels zl = {};
+ struct zapi_nexthop_label *znh;
if (kr->local_label < MPLS_LABEL_RESERVED_MAX ||
kr->remote_label == NO_LABEL)
log_label(kr->local_label), log_label(kr->remote_label),
(cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete");
- /* Reset stream. */
- s = zclient->obuf;
- stream_reset(s);
+ zl.type = ZEBRA_LSP_LDP;
+ zl.local_label = kr->local_label;
- zclient_create_header(s, cmd, VRF_DEFAULT);
- stream_putc(s, ZEBRA_LSP_LDP);
- stream_putl(s, kr->af);
+ /* Set prefix. */
+ SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+ zl.route.prefix.family = kr->af;
switch (kr->af) {
case AF_INET:
- stream_put_in_addr(s, &kr->prefix.v4);
- stream_putc(s, kr->prefixlen);
- stream_put_in_addr(s, &kr->nexthop.v4);
+ zl.route.prefix.u.prefix4 = kr->prefix.v4;
break;
case AF_INET6:
- stream_write(s, (uint8_t *)&kr->prefix.v6, 16);
- stream_putc(s, kr->prefixlen);
- stream_write(s, (uint8_t *)&kr->nexthop.v6, 16);
+ zl.route.prefix.u.prefix6 = kr->prefix.v6;
break;
default:
- fatalx("kr_change: unknown af");
+ fatalx("ldp_zebra_send_mpls_labels: unknown af");
}
- stream_putl(s, kr->ifindex);
- stream_putc(s, kr->priority);
- stream_putl(s, kr->local_label);
- stream_putl(s, kr->remote_label);
+ zl.route.prefix.prefixlen = kr->prefixlen;
+ zl.route.type = kr->route_type;
+ zl.route.instance = kr->route_instance;
- /* Put length at the first point of the stream. */
- stream_putw_at(s, 0, stream_get_endp(s));
+ /* Set nexthop. */
+ zl.nexthop_num = 1;
+ znh = &zl.nexthops[0];
+ switch (kr->af) {
+ case AF_INET:
+ znh->family = AF_INET;
+ znh->address.ipv4 = kr->nexthop.v4;
+ if (kr->ifindex)
+ znh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ else
+ znh->type = NEXTHOP_TYPE_IPV4;
+ break;
+ case AF_INET6:
+ znh->family = AF_INET6;
+ znh->address.ipv6 = kr->nexthop.v6;
+ if (kr->ifindex)
+ znh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else
+ znh->type = NEXTHOP_TYPE_IPV6;
+ break;
+ default:
+ break;
+ }
+ znh->ifindex = kr->ifindex;
+ znh->label = kr->remote_label;
- return (zclient_send_message(zclient));
+ return zebra_send_mpls_labels(zclient, cmd, &zl);
}
int
kr_change(struct kroute *kr)
{
- return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
+ return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
}
int
kr_delete(struct kroute *kr)
{
- return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
+ return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
}
int
break;
}
kr.prefixlen = api.prefix.prefixlen;
- kr.priority = api.distance;
+ kr.route_type = api.type;
+ kr.route_instance = api.instance;
switch (api.type) {
case ZEBRA_ROUTE_CONNECT:
uint32_t local_label;
uint32_t remote_label;
unsigned short ifindex;
- uint8_t priority;
+ uint8_t route_type;
+ uint8_t route_instance;
uint16_t flags;
};
vty_out(vty, "frr defaults %s\n", DFLT_NAME);
vty_out(vty, "!\n");
- pthread_rwlock_rdlock(&running_config->lock);
- {
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((node = vector_slot(cmdvec, i)) && node->func
- && (node->vtysh || vty->type != VTY_SHELL)) {
- if ((*node->func)(vty))
- vty_out(vty, "!\n");
- }
- }
- pthread_rwlock_unlock(&running_config->lock);
+ for (i = 0; i < vector_active(cmdvec); i++)
+ if ((node = vector_slot(cmdvec, i)) && node->func
+ && (node->vtysh || vty->type != VTY_SHELL)) {
+ if ((*node->func)(vty))
+ vty_out(vty, "!\n");
+ }
if (vty->type == VTY_TERM) {
vty_out(vty, "end\n");
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,
{
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);
}
}
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);
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;
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);
+ }
}
}
if (yang_module_find("frr-interface")) {
struct lyd_node *if_dnode;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- if_dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
- ifp->name, old_vrf->name);
- if (if_dnode) {
- yang_dnode_change_leaf(if_dnode, vrf->name);
- running_config->version++;
- }
+ if_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
+ ifp->name, old_vrf->name);
+ if (if_dnode) {
+ yang_dnode_change_leaf(if_dnode, vrf->name);
+ running_config->version++;
}
- pthread_rwlock_unlock(&running_config->lock);
}
}
+
/* Delete interface structure. */
void if_delete_retain(struct interface *ifp)
{
return NB_OK;
}
+/*
+ * XPath: /frr-interface:lib/interface
+ */
+static const void *lib_interface_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct vrf *vrf;
+ struct interface *pif = (struct interface *)list_entry;
+
+ if (list_entry == NULL) {
+ vrf = RB_MIN(vrf_name_head, &vrfs_by_name);
+ assert(vrf);
+ pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+ } else {
+ vrf = vrf_lookup_by_id(pif->vrf_id);
+ pif = RB_NEXT(if_name_head, pif);
+ /* if no more interfaces, switch to next vrf */
+ while (pif == NULL) {
+ vrf = RB_NEXT(vrf_name_head, vrf);
+ if (!vrf)
+ return NULL;
+ pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+ }
+ }
+
+ return pif;
+}
+
+static int lib_interface_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct interface *ifp = list_entry;
+
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ assert(vrf);
+
+ keys->num = 2;
+ strlcpy(keys->key[0], ifp->name, sizeof(keys->key[0]));
+ strlcpy(keys->key[1], vrf->name, sizeof(keys->key[1]));
+
+ return NB_OK;
+}
+
+static const void *lib_interface_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *ifname = keys->key[0];
+ const char *vrfname = keys->key[1];
+ struct vrf *vrf = vrf_lookup_by_name(vrfname);
+
+ return if_lookup_by_name(ifname, vrf->vrf_id);
+}
+
/*
* XPath: /frr-interface:lib/interface/description
*/
.create = lib_interface_create,
.destroy = lib_interface_destroy,
.cli_show = cli_show_interface,
+ .get_next = lib_interface_get_next,
+ .get_keys = lib_interface_get_keys,
+ .lookup_entry = lib_interface_lookup_entry,
},
},
{
#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, (), ())
memory_init();
log_filter_cmd_init();
+ frr_pthread_init();
+
log_ref_init();
log_ref_vty_init();
lib_error_init();
/*
* Update the shared candidate after reading the startup configuration.
*/
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty_shared_candidate_config, running_config,
- true);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_replace(vty_shared_candidate_config, running_config, true);
return 0;
}
db_close();
#endif
log_ref_fini();
+ frr_pthread_finish();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
thread_master_free(master);
DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS),
DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD),
DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE),
+ DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE),
DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
#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 */
ZEBRA_LSP_STATIC = 1, /* Static LSP. */
ZEBRA_LSP_LDP = 2, /* LDP LSP. */
ZEBRA_LSP_BGP = 3, /* BGP LSP. */
- ZEBRA_LSP_SR = 4, /* Segment Routing LSP. */
+ ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */
ZEBRA_LSP_SHARP = 5, /* Identifier for test protocol */
};
static int nb_callback_configuration(const enum nb_event event,
struct nb_config_change *change);
+static void nb_log_callback(const enum nb_event event,
+ enum nb_operation operation, const char *xpath,
+ const char *value);
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
struct nb_config_cbs *changes,
enum nb_client client,
valid = nb_operation_is_valid(operation, nb_node->snode);
- if (!valid && callback_implemented)
+ /*
+ * Add an exception for operational data callbacks. A rw list usually
+ * doesn't need any associated operational data callbacks. But if this
+ * rw list is augmented by another module which adds state nodes under
+ * it, then this list will need to have the 'get_next()', 'get_keys()'
+ * and 'lookup_entry()' callbacks. As such, never log a warning when
+ * these callbacks are implemented when they are not needed, since this
+ * depends on context (e.g. some daemons might augment "frr-interface"
+ * while others don't).
+ */
+ if (!valid && callback_implemented && operation != NB_OP_GET_NEXT
+ && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY)
flog_warn(EC_LIB_NB_CB_UNNEEDED,
"unneeded '%s' callback for '%s'",
nb_operation_name(operation), nb_node->xpath);
!!nb_node->cbs.destroy, false);
error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move,
false);
+ error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE,
+ !!nb_node->cbs.pre_validate, true);
error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH,
!!nb_node->cbs.apply_finish, true);
error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM,
else
config->dnode = yang_dnode_new(ly_native_ctx, true);
config->version = 0;
- pthread_rwlock_init(&config->lock, NULL);
return config;
}
{
if (config->dnode)
yang_dnode_free(config->dnode);
- pthread_rwlock_destroy(&config->lock);
XFREE(MTYPE_NB_CONFIG, config);
}
dup = XCALLOC(MTYPE_NB_CONFIG, sizeof(*dup));
dup->dnode = yang_dnode_dup(config->dnode);
dup->version = config->version;
- pthread_rwlock_init(&dup->lock, NULL);
return dup;
}
return 1;
/*
- * Use XPath as a tie-breaker. This will naturally sort parent nodes
- * before their children.
+ * Preserve the order of the configuration changes as told by libyang.
*/
- return strcmp(a->xpath, b->xpath);
+ return a->seq - b->seq;
}
RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare);
static void nb_config_diff_add_change(struct nb_config_cbs *changes,
enum nb_operation operation,
+ uint32_t *seq,
const struct lyd_node *dnode)
{
struct nb_config_change *change;
change = XCALLOC(MTYPE_TMP, sizeof(*change));
change->cb.operation = operation;
+ change->cb.seq = *seq;
+ *seq = *seq + 1;
change->cb.nb_node = dnode->schema->priv;
yang_dnode_get_path(dnode, change->cb.xpath, sizeof(change->cb.xpath));
change->cb.dnode = dnode;
* configurations. Given a new subtree, calculate all new YANG data nodes,
* excluding default leafs and leaf-lists. This is a recursive function.
*/
-static void nb_config_diff_created(const struct lyd_node *dnode,
+static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
enum nb_operation operation;
else
return;
- nb_config_diff_add_change(changes, operation, dnode);
+ nb_config_diff_add_change(changes, operation, seq, dnode);
break;
case LYS_CONTAINER:
case LYS_LIST:
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
+ nb_config_diff_add_change(changes, NB_OP_CREATE, seq,
+ dnode);
/* Process child nodes recursively. */
LY_TREE_FOR (dnode->child, child) {
- nb_config_diff_created(child, changes);
+ nb_config_diff_created(child, seq, changes);
}
break;
default:
}
}
-static void nb_config_diff_deleted(const struct lyd_node *dnode,
+static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
+ nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
struct lyd_node *child;
* when applicable (i.e. optional nodes).
*/
LY_TREE_FOR (dnode->child, child) {
- nb_config_diff_deleted(child, changes);
+ nb_config_diff_deleted(child, seq, changes);
}
}
}
struct nb_config_cbs *changes)
{
struct lyd_difflist *diff;
+ uint32_t seq = 0;
diff = lyd_diff(config1->dnode, config2->dnode,
LYD_DIFFOPT_WITHDEFAULTS);
switch (type) {
case LYD_DIFF_CREATED:
dnode = diff->second[i];
- nb_config_diff_created(dnode, changes);
+ nb_config_diff_created(dnode, &seq, changes);
break;
case LYD_DIFF_DELETED:
dnode = diff->first[i];
- nb_config_diff_deleted(dnode, changes);
+ nb_config_diff_deleted(dnode, &seq, changes);
break;
case LYD_DIFF_CHANGED:
dnode = diff->second[i];
- nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
+ nb_config_diff_add_change(changes, NB_OP_MODIFY, &seq,
+ dnode);
break;
case LYD_DIFF_MOVEDAFTER1:
case LYD_DIFF_MOVEDAFTER2:
bool nb_candidate_needs_update(const struct nb_config *candidate)
{
- bool ret = false;
-
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (candidate->version < running_config->version)
- ret = true;
- }
- pthread_rwlock_unlock(&running_config->lock);
+ if (candidate->version < running_config->version)
+ return true;
- return ret;
+ return false;
}
int nb_candidate_update(struct nb_config *candidate)
{
struct nb_config *updated_config;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- updated_config = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ updated_config = nb_config_dup(running_config);
if (nb_config_merge(updated_config, candidate, true) != NB_OK)
return NB_ERR;
}
/* Perform code-level validation using the northbound callbacks. */
-static int nb_candidate_validate_changes(struct nb_config *candidate,
- struct nb_config_cbs *changes)
+static int nb_candidate_validate_code(struct nb_config *candidate,
+ struct nb_config_cbs *changes)
{
struct nb_config_cb *cb;
+ struct lyd_node *root, *next, *child;
+ int ret;
+
+ /* First validate the candidate as a whole. */
+ LY_TREE_FOR (candidate->dnode, root) {
+ LY_TREE_DFS_BEGIN (root, next, child) {
+ struct nb_node *nb_node;
+
+ nb_node = child->schema->priv;
+ if (!nb_node->cbs.pre_validate)
+ goto next;
+
+ if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config,
+ DEBUG_MODE_ALL)) {
+ char xpath[XPATH_MAXLEN];
+
+ yang_dnode_get_path(child, xpath,
+ sizeof(xpath));
+ nb_log_callback(NB_EV_VALIDATE,
+ NB_OP_PRE_VALIDATE, xpath,
+ NULL);
+ }
+
+ ret = (*nb_node->cbs.pre_validate)(child);
+ if (ret != NB_OK)
+ return NB_ERR_VALIDATION;
+ next:
+ LY_TREE_DFS_END(root, next, child);
+ }
+ }
+
+ /* Now validate the configuration changes. */
RB_FOREACH (cb, nb_config_cbs, changes) {
struct nb_config_change *change = (struct nb_config_change *)cb;
- int ret;
ret = nb_callback_configuration(NB_EV_VALIDATE, change);
if (ret != NB_OK)
return NB_ERR_VALIDATION;
RB_INIT(nb_config_cbs, &changes);
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_diff(running_config, candidate, &changes);
- ret = nb_candidate_validate_changes(candidate, &changes);
- nb_config_diff_del_changes(&changes);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_diff(running_config, candidate, &changes);
+ ret = nb_candidate_validate_code(candidate, &changes);
+ nb_config_diff_del_changes(&changes);
return ret;
}
}
RB_INIT(nb_config_cbs, &changes);
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_diff(running_config, candidate, &changes);
- if (RB_EMPTY(nb_config_cbs, &changes)) {
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_NO_CHANGES;
- }
+ nb_config_diff(running_config, candidate, &changes);
+ if (RB_EMPTY(nb_config_cbs, &changes))
+ return NB_ERR_NO_CHANGES;
- if (nb_candidate_validate_changes(candidate, &changes)
- != NB_OK) {
- flog_warn(
- EC_LIB_NB_CANDIDATE_INVALID,
- "%s: failed to validate candidate configuration",
- __func__);
- nb_config_diff_del_changes(&changes);
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_VALIDATION;
- }
+ if (nb_candidate_validate_code(candidate, &changes) != NB_OK) {
+ flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
+ "%s: failed to validate candidate configuration",
+ __func__);
+ nb_config_diff_del_changes(&changes);
+ return NB_ERR_VALIDATION;
+ }
- *transaction = nb_transaction_new(candidate, &changes, client,
- user, comment);
- if (*transaction == NULL) {
- flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
- "%s: failed to create transaction", __func__);
- nb_config_diff_del_changes(&changes);
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_LOCKED;
- }
+ *transaction =
+ nb_transaction_new(candidate, &changes, client, user, comment);
+ if (*transaction == NULL) {
+ flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
+ "%s: failed to create transaction", __func__);
+ nb_config_diff_del_changes(&changes);
+ return NB_ERR_LOCKED;
}
- pthread_rwlock_unlock(&running_config->lock);
return nb_transaction_process(NB_EV_PREPARE, *transaction);
}
/* Replace running by candidate. */
transaction->config->version++;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- nb_config_replace(running_config, transaction->config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_replace(running_config, transaction->config, true);
/* Record transaction. */
if (save_transaction
{
struct nb_config_cb *cb;
- /*
- * Need to lock the running configuration since transaction->changes
- * can contain pointers to data nodes from the running configuration.
- */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
- struct nb_config_change *change =
- (struct nb_config_change *)cb;
- int ret;
+ RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
+ struct nb_config_change *change = (struct nb_config_change *)cb;
+ int ret;
+ /*
+ * Only try to release resources that were allocated
+ * successfully.
+ */
+ if (event == NB_EV_ABORT && change->prepare_ok == false)
+ break;
+
+ /* Call the appropriate callback. */
+ ret = nb_callback_configuration(event, change);
+ switch (event) {
+ case NB_EV_PREPARE:
+ if (ret != NB_OK)
+ return ret;
+ change->prepare_ok = true;
+ break;
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
/*
- * Only try to release resources that were allocated
- * successfully.
+ * At this point it's not possible to reject the
+ * transaction anymore, so any failure here can lead to
+ * inconsistencies and should be treated as a bug.
+ * Operations prone to errors, like validations and
+ * resource allocations, should be performed during the
+ * 'prepare' phase.
*/
- if (event == NB_EV_ABORT && change->prepare_ok == false)
- break;
-
- /* Call the appropriate callback. */
- ret = nb_callback_configuration(event, change);
- switch (event) {
- case NB_EV_PREPARE:
- if (ret != NB_OK) {
- pthread_rwlock_unlock(
- &running_config->lock);
- return ret;
- }
- change->prepare_ok = true;
- break;
- case NB_EV_ABORT:
- case NB_EV_APPLY:
- /*
- * At this point it's not possible to reject the
- * transaction anymore, so any failure here can
- * lead to inconsistencies and should be treated
- * as a bug. Operations prone to errors, like
- * validations and resource allocations, should
- * be performed during the 'prepare' phase.
- */
- break;
- default:
- break;
- }
+ break;
+ default:
+ break;
}
}
- pthread_rwlock_unlock(&running_config->lock);
return NB_OK;
}
/* Update XPath. */
strlcpy(xpath, xpath_parent, sizeof(xpath));
- if (!first && snode->nodetype != LYS_USES)
- snprintf(xpath + strlen(xpath), sizeof(xpath) - strlen(xpath),
- "/%s", snode->name);
+ if (!first && snode->nodetype != LYS_USES) {
+ struct lys_node *parent;
+
+ /* Get the real parent. */
+ parent = snode->parent;
+ while (parent && parent->nodetype == LYS_USES)
+ parent = parent->parent;
+
+ /*
+ * When necessary, include the namespace of the augmenting
+ * module.
+ */
+ if (parent && parent->nodetype == LYS_AUGMENT)
+ snprintf(xpath + strlen(xpath),
+ sizeof(xpath) - strlen(xpath), "/%s:%s",
+ snode->module->name, snode->name);
+ else
+ snprintf(xpath + strlen(xpath),
+ sizeof(xpath) - strlen(xpath), "/%s",
+ snode->name);
+ }
nb_node = snode->priv;
switch (snode->nodetype) {
return false;
}
return true;
+ case NB_OP_PRE_VALIDATE:
case NB_OP_APPLY_FINISH:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
return "destroy";
case NB_OP_MOVE:
return "move";
+ case NB_OP_PRE_VALIDATE:
+ return "pre_validate";
case NB_OP_APPLY_FINISH:
return "apply_finish";
case NB_OP_GET_ELEM:
NB_OP_MODIFY,
NB_OP_DESTROY,
NB_OP_MOVE,
+ NB_OP_PRE_VALIDATE,
NB_OP_APPLY_FINISH,
NB_OP_GET_ELEM,
NB_OP_GET_NEXT,
*/
int (*move)(enum nb_event event, const struct lyd_node *dnode);
+ /*
+ * Optional configuration callback.
+ *
+ * This callback can be used to validate subsections of the
+ * configuration being committed before validating the configuration
+ * changes themselves. It's useful to perform more complex validations
+ * that depend on the relationship between multiple nodes.
+ *
+ * dnode
+ * libyang data node associated with the 'pre_validate' callback.
+ */
+ int (*pre_validate)(const struct lyd_node *dnode);
+
/*
* Optional configuration callback.
*
/* Northbound configuration. */
struct nb_config {
- /* Configuration data. */
struct lyd_node *dnode;
-
- /* Configuration version. */
uint32_t version;
-
- /*
- * Lock protecting this structure. The use of this lock is always
- * necessary when reading or modifying the global running configuration.
- * For candidate configurations, use of this lock is optional depending
- * on the threading scheme of the northbound plugin.
- */
- pthread_rwlock_t lock;
};
/* Northbound configuration callback. */
struct nb_config_cb {
RB_ENTRY(nb_config_cb) entry;
enum nb_operation operation;
+ uint32_t seq;
char xpath[XPATH_MAXLEN];
const struct nb_node *nb_node;
const struct lyd_node *dnode;
"Please check the logs for more details.\n");
/* Regenerate candidate for consistency. */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config,
- running_config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ nb_config_replace(vty->candidate_config, running_config,
+ true);
return CMD_WARNING_CONFIG_FAILED;
}
}
/* "confirm" parameter. */
if (confirmed_timeout) {
- pthread_rwlock_rdlock(&running_config->lock);
- {
- vty->confirmed_commit_rollback =
- nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ vty->confirmed_commit_rollback = nb_config_dup(running_config);
vty->t_confirmed_commit_timeout = NULL;
thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
/* Map northbound return code to CLI return code. */
switch (ret) {
case NB_OK:
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config_base,
- running_config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ nb_config_replace(vty->candidate_config_base, running_config,
+ true);
vty_out(vty,
"%% Configuration committed successfully (Transaction ID #%u).\n\n",
transaction_id);
return CMD_WARNING;
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config_base, running_config,
- true);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_replace(vty->candidate_config_base, running_config, true);
vty_out(vty, "%% Candidate configuration updated successfully.\n\n");
}
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_cli_show_config(vty, running_config, format, translator,
- !!with_defaults);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_cli_show_config(vty, running_config, format, translator,
+ !!with_defaults);
return CMD_SUCCESS;
}
struct nb_config *config2, *config_transaction2 = NULL;
int ret = CMD_WARNING;
- /*
- * For simplicity, lock the running configuration regardless if it's
- * going to be used or not.
- */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (c1_candidate)
- config1 = vty->candidate_config;
- else if (c1_running)
- config1 = running_config;
- else {
- config_transaction1 = nb_db_transaction_load(c1_tid);
- if (!config_transaction1) {
- vty_out(vty,
- "%% Transaction %u does not exist\n\n",
- (unsigned int)c1_tid);
- goto exit;
- }
- config1 = config_transaction1;
+ if (c1_candidate)
+ config1 = vty->candidate_config;
+ else if (c1_running)
+ config1 = running_config;
+ else {
+ config_transaction1 = nb_db_transaction_load(c1_tid);
+ if (!config_transaction1) {
+ vty_out(vty, "%% Transaction %u does not exist\n\n",
+ (unsigned int)c1_tid);
+ goto exit;
}
+ config1 = config_transaction1;
+ }
- if (c2_candidate)
- config2 = vty->candidate_config;
- else if (c2_running)
- config2 = running_config;
- else {
- config_transaction2 = nb_db_transaction_load(c2_tid);
- if (!config_transaction2) {
- vty_out(vty,
- "%% Transaction %u does not exist\n\n",
- (unsigned int)c2_tid);
- goto exit;
- }
- config2 = config_transaction2;
+ if (c2_candidate)
+ config2 = vty->candidate_config;
+ else if (c2_running)
+ config2 = running_config;
+ else {
+ config_transaction2 = nb_db_transaction_load(c2_tid);
+ if (!config_transaction2) {
+ vty_out(vty, "%% Transaction %u does not exist\n\n",
+ (unsigned int)c2_tid);
+ goto exit;
}
+ config2 = config_transaction2;
+ }
- if (json)
- format = NB_CFG_FMT_JSON;
- else if (xml)
- format = NB_CFG_FMT_XML;
- else
- format = NB_CFG_FMT_CMDS;
+ if (json)
+ format = NB_CFG_FMT_JSON;
+ else if (xml)
+ format = NB_CFG_FMT_XML;
+ else
+ format = NB_CFG_FMT_CMDS;
- if (translator_family) {
- translator = yang_translator_find(translator_family);
- if (!translator) {
- vty_out(vty,
- "%% Module translator \"%s\" not found\n",
- translator_family);
- goto exit;
- }
+ if (translator_family) {
+ translator = yang_translator_find(translator_family);
+ if (!translator) {
+ vty_out(vty, "%% Module translator \"%s\" not found\n",
+ translator_family);
+ goto exit;
}
-
- ret = nb_cli_show_config_compare(vty, config1, config2, format,
- translator);
- exit:
- if (config_transaction1)
- nb_config_free(config_transaction1);
- if (config_transaction2)
- nb_config_free(config_transaction2);
}
- pthread_rwlock_unlock(&running_config->lock);
+
+ ret = nb_cli_show_config_compare(vty, config1, config2, format,
+ translator);
+exit:
+ if (config_transaction1)
+ nb_config_free(config_transaction1);
+ if (config_transaction2)
+ nb_config_free(config_transaction2);
return ret;
}
struct cdb_iter_args iter_args;
int ret;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate = nb_config_dup(running_config);
/* Iterate over all configuration changes. */
iter_args.candidate = candidate;
{
struct lyd_node *dnode;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- dnode = yang_dnode_get(running_config->dnode,
- path.empty() ? NULL
- : path.c_str());
- if (dnode)
- dnode = yang_dnode_dup(dnode);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ dnode = yang_dnode_get(running_config->dnode,
+ path.empty() ? NULL : path.c_str());
+ if (dnode)
+ dnode = yang_dnode_dup(dnode);
return dnode;
}
struct candidate *candidate = &_candidates[candidate_id];
candidate->id = candidate_id;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate->config = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate->config = nb_config_dup(running_config);
candidate->transaction = NULL;
return candidate;
return ret;
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate = nb_config_dup(running_config);
while ((ret = sr_get_change_next(session, it, &sr_op, &sr_old_val,
&sr_new_val))
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;
frr_protonameinst);
return CMD_WARNING_CONFIG_FAILED;
break;
- case RMAP_DUPLICATE_RULE:
+ case RMAP_COMPILE_SUCCESS:
/*
* Nothing to do here move along
*/
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);
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
*/
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
break;
}
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
break;
}
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);
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) {
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
get_route_map_delete_event(type);
route_map_upd8_dependency(
delete_rmap_event_type,
- rule->rule_str,
+ rule_key,
index->map->name);
}
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;
}
/* 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)
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);
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. */
/* 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. */
/* Route map rule can't compile */
RMAP_COMPILE_ERROR,
- /* Route map rule is duplicate */
- RMAP_DUPLICATE_RULE
};
/* Route map rule list. */
/* 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);
/* 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);
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)
vty->private_config = private_config;
vty->xpath_index = 0;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (private_config) {
- vty->candidate_config = nb_config_dup(running_config);
+ if (private_config) {
+ vty->candidate_config = nb_config_dup(running_config);
+ vty->candidate_config_base = nb_config_dup(running_config);
+ vty_out(vty,
+ "Warning: uncommitted changes will be discarded on exit.\n\n");
+ } else {
+ vty->candidate_config = vty_shared_candidate_config;
+ if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
vty->candidate_config_base =
nb_config_dup(running_config);
- vty_out(vty,
- "Warning: uncommitted changes will be discarded on exit.\n\n");
- } else {
- vty->candidate_config = vty_shared_candidate_config;
- if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
- vty->candidate_config_base =
- nb_config_dup(running_config);
- }
}
- pthread_rwlock_unlock(&running_config->lock);
return CMD_SUCCESS;
}
xpath);
}
+/*
+ * Derived type: IP prefix.
+ */
+void yang_str2prefix(const char *value, union prefixptr prefix)
+{
+ (void)str2prefix(value, prefix.p);
+ apply_mask(prefix.p);
+}
+
+struct yang_data *yang_data_new_prefix(const char *xpath,
+ union prefixconstptr prefix)
+{
+ char value_str[PREFIX2STR_BUFFER];
+
+ (void)prefix2str(prefix.p, value_str, sizeof(value_str));
+ return yang_data_new(xpath, value_str);
+}
+
+void yang_dnode_get_prefix(union prefixptr prefix, const struct lyd_node *dnode,
+ const char *xpath_fmt, ...)
+{
+ const struct lyd_node_leaf_list *dleaf;
+
+ assert(dnode);
+ if (xpath_fmt) {
+ va_list ap;
+ char xpath[XPATH_MAXLEN];
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+ dnode = yang_dnode_get(dnode, xpath);
+ YANG_DNODE_GET_ASSERT(dnode, xpath);
+ }
+
+ dleaf = (const struct lyd_node_leaf_list *)dnode;
+ assert(dleaf->value_type == LY_TYPE_STRING);
+ (void)str2prefix(dleaf->value_str, prefix.p);
+}
+
+void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...)
+{
+ char xpath[XPATH_MAXLEN];
+ const char *value;
+ va_list ap;
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+
+ value = yang_get_default_value(xpath);
+ yang_str2prefix(value, var);
+}
+
/*
* Derived type: ipv4.
*/
value = yang_get_default_value(xpath);
yang_str2ipv6p(value, var);
}
+
+/*
+ * Derived type: ip.
+ */
+void yang_str2ip(const char *value, struct ipaddr *ip)
+{
+ (void)str2ipaddr(value, ip);
+}
+
+struct yang_data *yang_data_new_ip(const char *xpath, const struct ipaddr *addr)
+{
+ size_t sz = IS_IPADDR_V4(addr) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+ char value_str[sz];
+
+ ipaddr2str(addr, value_str, sizeof(value_str));
+ return yang_data_new(xpath, value_str);
+}
+
+void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode,
+ const char *xpath_fmt, ...)
+{
+ const struct lyd_node_leaf_list *dleaf;
+
+ assert(dnode);
+ if (xpath_fmt) {
+ va_list ap;
+ char xpath[XPATH_MAXLEN];
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+ dnode = yang_dnode_get(dnode, xpath);
+ YANG_DNODE_GET_ASSERT(dnode, xpath);
+ }
+
+ dleaf = (const struct lyd_node_leaf_list *)dnode;
+ assert(dleaf->value_type == LY_TYPE_STRING);
+ (void)str2ipaddr(dleaf->value_str, addr);
+}
+
+void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...)
+{
+ char xpath[XPATH_MAXLEN];
+ const char *value;
+ va_list ap;
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+
+ value = yang_get_default_value(xpath);
+ yang_str2ip(value, var);
+}
extern void yang_get_default_string_buf(char *buf, size_t size,
const char *xpath_fmt, ...);
+/* ip prefix */
+extern void yang_str2prefix(const char *value, union prefixptr prefix);
+extern struct yang_data *yang_data_new_prefix(const char *xpath,
+ union prefixconstptr prefix);
+extern void yang_dnode_get_prefix(union prefixptr prefix,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
+extern void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt,
+ ...);
+
/* ipv4 */
extern void yang_str2ipv4(const char *value, struct in_addr *addr);
extern struct yang_data *yang_data_new_ipv4(const char *xpath,
extern void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt,
...);
+/* ip */
+extern void yang_str2ip(const char *value, struct ipaddr *addr);
+extern struct yang_data *yang_data_new_ip(const char *xpath,
+ const struct ipaddr *addr);
+extern void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
+extern void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...);
+
#endif /* _FRR_NORTHBOUND_WRAPPERS_H_ */
return zclient_send_message(zclient);
}
+int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
+ struct zapi_labels *zl)
+{
+ if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0)
+ return -1;
+ return zclient_send_message(zclient);
+}
+
+int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
+{
+ struct zapi_nexthop_label *znh;
+
+ stream_reset(s);
+
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+ stream_putc(s, zl->message);
+ stream_putc(s, zl->type);
+ stream_putl(s, zl->local_label);
+
+ if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+ stream_putw(s, zl->route.prefix.family);
+ stream_put_prefix(s, &zl->route.prefix);
+ stream_putc(s, zl->route.type);
+ stream_putw(s, zl->route.instance);
+ }
+
+ if (zl->nexthop_num > MULTIPATH_NUM) {
+ flog_err(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: label %u: can't encode %u nexthops (maximum is %u)",
+ __func__, zl->local_label, zl->nexthop_num,
+ MULTIPATH_NUM);
+ return -1;
+ }
+ stream_putw(s, zl->nexthop_num);
+
+ for (int i = 0; i < zl->nexthop_num; i++) {
+ znh = &zl->nexthops[i];
+
+ stream_putc(s, znh->type);
+ stream_putw(s, znh->family);
+ switch (znh->family) {
+ case AF_INET:
+ stream_put_in_addr(s, &znh->address.ipv4);
+ break;
+ case AF_INET6:
+ stream_write(s, (uint8_t *)&znh->address.ipv6, 16);
+ break;
+ default:
+ break;
+ }
+ stream_putl(s, znh->ifindex);
+ stream_putl(s, znh->label);
+ }
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
+{
+ struct zapi_nexthop_label *znh;
+
+ memset(zl, 0, sizeof(*zl));
+
+ /* Get data. */
+ STREAM_GETC(s, zl->message);
+ STREAM_GETC(s, zl->type);
+ STREAM_GETL(s, zl->local_label);
+
+ if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+ size_t psize;
+
+ STREAM_GETW(s, zl->route.prefix.family);
+ STREAM_GETC(s, zl->route.prefix.prefixlen);
+
+ psize = PSIZE(zl->route.prefix.prefixlen);
+ switch (zl->route.prefix.family) {
+ case AF_INET:
+ if (zl->route.prefix.prefixlen > IPV4_MAX_BITLEN) {
+ zlog_debug(
+ "%s: Specified prefix length %d is greater than a v4 address can support",
+ __PRETTY_FUNCTION__,
+ zl->route.prefix.prefixlen);
+ return -1;
+ }
+ STREAM_GET(&zl->route.prefix.u.prefix4.s_addr, s,
+ psize);
+ break;
+ case AF_INET6:
+ if (zl->route.prefix.prefixlen > IPV6_MAX_BITLEN) {
+ zlog_debug(
+ "%s: Specified prefix length %d is greater than a v6 address can support",
+ __PRETTY_FUNCTION__,
+ zl->route.prefix.prefixlen);
+ return -1;
+ }
+ STREAM_GET(&zl->route.prefix.u.prefix6, s, psize);
+ break;
+ default:
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: Specified family %u is not v4 or v6",
+ __PRETTY_FUNCTION__, zl->route.prefix.family);
+ return -1;
+ }
+
+ STREAM_GETC(s, zl->route.type);
+ STREAM_GETW(s, zl->route.instance);
+ }
+
+ STREAM_GETW(s, zl->nexthop_num);
+ for (int i = 0; i < zl->nexthop_num; i++) {
+ znh = &zl->nexthops[i];
+
+ STREAM_GETC(s, znh->type);
+ STREAM_GETW(s, znh->family);
+ switch (znh->family) {
+ case AF_INET:
+ STREAM_GET(&znh->address.ipv4.s_addr, s,
+ IPV4_MAX_BYTELEN);
+ break;
+ case AF_INET6:
+ STREAM_GET(&znh->address.ipv6, s, 16);
+ break;
+ default:
+ break;
+ }
+ STREAM_GETL(s, znh->ifindex);
+ STREAM_GETL(s, znh->label);
+ }
+
+ return 0;
+stream_failure:
+ return -1;
+}
int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
{
ZEBRA_INTERFACE_LINK_PARAMS,
ZEBRA_MPLS_LABELS_ADD,
ZEBRA_MPLS_LABELS_DELETE,
+ ZEBRA_MPLS_LABELS_REPLACE,
ZEBRA_IPMR_ROUTE_STATS,
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_LABEL_MANAGER_CONNECT_ASYNC,
uint32_t tableid;
};
+struct zapi_nexthop_label {
+ enum nexthop_types_t type;
+ int family;
+ union g_addr address;
+ ifindex_t ifindex;
+ mpls_label_t label;
+};
+
+struct zapi_labels {
+ uint8_t message;
+#define ZAPI_LABELS_FTN 0x01
+ enum lsp_types_t type;
+ mpls_label_t local_label;
+ struct {
+ struct prefix prefix;
+ uint8_t type;
+ unsigned short instance;
+ } route;
+ uint16_t nexthop_num;
+ struct zapi_nexthop_label nexthops[MULTIPATH_NUM];
+};
+
struct zapi_pw {
char ifname[IF_NAMESIZE];
ifindex_t ifindex;
extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
uint32_t end);
+extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
+ struct zapi_labels *zl);
+extern int zapi_labels_encode(struct stream *s, int cmd,
+ struct zapi_labels *zl);
+extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
+
extern int zebra_send_pw(struct zclient *zclient, int command,
struct zapi_pw *pw);
extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw);
return CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
- case RMAP_DUPLICATE_RULE:
break;
}
/* 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);
/* Send MPLS Label entry to Zebra for installation or deletion */
static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe)
{
- struct stream *s;
-
- /* Reset stream. */
- s = zclient->obuf;
- stream_reset(s);
-
- zclient_create_header(s, cmd, VRF_DEFAULT);
- stream_putc(s, ZEBRA_LSP_SR);
- /* OSPF Segment Routing currently support only IPv4 */
- stream_putl(s, nhlfe.prefv4.family);
- stream_put_in_addr(s, &nhlfe.prefv4.prefix);
- stream_putc(s, nhlfe.prefv4.prefixlen);
- stream_put_in_addr(s, &nhlfe.nexthop);
- stream_putl(s, nhlfe.ifindex);
- stream_putc(s, OSPF_SR_PRIORITY_DEFAULT);
- stream_putl(s, nhlfe.label_in);
- stream_putl(s, nhlfe.label_out);
-
- /* Put length at the first point of the stream. */
- stream_putw_at(s, 0, stream_get_endp(s));
+ struct zapi_labels zl = {};
+ struct zapi_nexthop_label *znh;
if (IS_DEBUG_OSPF_SR)
zlog_debug(" |- %s LSP %u/%u for %s/%u via %u",
inet_ntoa(nhlfe.prefv4.prefix),
nhlfe.prefv4.prefixlen, nhlfe.ifindex);
- return zclient_send_message(zclient);
-}
-
-/* Request zebra to install/remove FEC in FIB */
-static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
-{
- struct zapi_route api;
- struct zapi_nexthop *api_nh;
-
- /* Support only IPv4 */
- if (nhlfe.prefv4.family != AF_INET)
- return -1;
-
- memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_OSPF;
- api.safi = SAFI_UNICAST;
- memcpy(&api.prefix, &nhlfe.prefv4, sizeof(struct prefix_ipv4));
-
- if (cmd == ZEBRA_ROUTE_ADD) {
- /* Metric value. */
- SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
- api.metric = OSPF_SR_DEFAULT_METRIC;
- /* Nexthop */
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api_nh = &api.nexthops[0];
- IPV4_ADDR_COPY(&api_nh->gate.ipv4, &nhlfe.nexthop);
- api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
- api_nh->ifindex = nhlfe.ifindex;
- /* MPLS labels */
- SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
- api_nh->labels[0] = nhlfe.label_out;
- api_nh->label_num = 1;
- api_nh->vrf_id = VRF_DEFAULT;
- api.nexthop_num = 1;
- }
-
- if (IS_DEBUG_OSPF_SR)
- zlog_debug(" |- %s FEC %u for %s/%u via %u",
- cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete",
- nhlfe.label_out, inet_ntoa(nhlfe.prefv4.prefix),
- nhlfe.prefv4.prefixlen, nhlfe.ifindex);
-
- return zclient_route_send(cmd, zclient, &api);
+ zl.type = ZEBRA_LSP_OSPF_SR;
+ zl.local_label = nhlfe.label_in;
+
+ SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+ zl.route.prefix.family = nhlfe.prefv4.family;
+ zl.route.prefix.prefixlen = nhlfe.prefv4.prefixlen;
+ zl.route.prefix.u.prefix4 = nhlfe.prefv4.prefix;
+ zl.route.type = ZEBRA_ROUTE_OSPF;
+ zl.route.instance = 0;
+
+ zl.nexthop_num = 1;
+ znh = &zl.nexthops[0];
+ znh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ znh->family = AF_INET;
+ znh->address.ipv4 = nhlfe.nexthop;
+ znh->ifindex = nhlfe.ifindex;
+ znh->label = nhlfe.label_out;
+
+ return zebra_send_mpls_labels(zclient, cmd, &zl);
}
/* Add new NHLFE entry for SID */
static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe)
{
- if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+ if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0))
ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe);
- if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
- ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_ADD, nhlfe);
- }
}
/* Remove NHLFE entry for SID */
static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe)
{
- if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+ if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0))
ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
- if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
- ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_DELETE, nhlfe);
- }
}
/* Update NHLFE entry for SID */
#ifndef _FRR_OSPF_SR_H
#define _FRR_OSPF_SR_H
-/* Default Route priority for OSPF Segment Routing */
-#define OSPF_SR_PRIORITY_DEFAULT 10
-
/* macros and constants for segment routing */
#define SET_RANGE_SIZE_MASK 0xffffff00
#define GET_RANGE_SIZE_MASK 0x00ffffff
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)
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,
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;
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);
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;
curr += offset;
curr_size -= offset;
- if (curr_size != 8) {
+ if (curr_size < 8) {
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn(
- "%s: preference/metric size is not 8: size=%d from %s on interface %s",
+ "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s",
__PRETTY_FUNCTION__, curr_size, src_str, ifp->name);
return -3;
}
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 \
%files pythontools
+%{_sbindir}/generate_support_bundle.py
+%{_sbindir}/generate_support_bundle.pyc
+%{_sbindir}/generate_support_bundle.pyo
%{_sbindir}/frr-reload.py
%{_sbindir}/frr-reload.pyc
%{_sbindir}/frr-reload.pyo
int socket;
rip = rip_lookup_by_vrf_name(vrf->name);
+ if (!rip) {
+ char *old_vrf_name = NULL;
+
+ rip = (struct rip *)vrf->info;
+ if (!rip)
+ return 0;
+ /* update vrf name */
+ if (rip->vrf_name)
+ old_vrf_name = rip->vrf_name;
+ rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name);
+ /*
+ * HACK: Change the RIP VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the RIP and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-ripd") && old_vrf_name) {
+ struct lyd_node *rip_dnode;
+
+ rip_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripd:ripd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (rip_dnode) {
+ yang_dnode_change_leaf(rip_dnode, vrf->name);
+ running_config->version++;
+ }
+ }
+ if (old_vrf_name)
+ XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
+ }
if (!rip || rip->enabled)
return 0;
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)
int socket;
ripng = ripng_lookup_by_vrf_name(vrf->name);
- if (!ripng || ripng->enabled)
+ if (!ripng) {
+ char *old_vrf_name = NULL;
+
+ ripng = (struct ripng *)vrf->info;
+ if (!ripng)
+ return 0;
+ /* update vrf name */
+ if (ripng->vrf_name)
+ old_vrf_name = ripng->vrf_name;
+ ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name);
+ /*
+ * HACK: Change the RIPng VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the RIPng and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-ripngd") && old_vrf_name) {
+ struct lyd_node *ripng_dnode;
+
+ ripng_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (ripng_dnode) {
+ yang_dnode_change_leaf(ripng_dnode, vrf->name);
+ running_config->version++;
+ }
+ }
+ if (old_vrf_name)
+ XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
+ }
+
+ if (ripng->enabled)
return 0;
if (IS_RIPNG_DEBUG_EVENT)
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;
}
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)
&& IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
|| (afi == AFI_IP6
&& IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
- && (!strcmp(ifname ? ifname : "", si->ifname))) {
+ && (!strcmp(ifname ? ifname : "", si->ifname))
+ && nh_svrf->vrf->vrf_id == si->nh_vrf_id) {
if ((distance == si->distance) && (tag == si->tag)
&& (table_id == si->table_id)
&& !memcmp(&si->snh_label, snh_label,
#ifndef VTYSH_EXTRACT_PL
#include "staticd/static_vty_clippy.c"
#endif
-
static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
const char *vrf_name)
{
return CMD_WARNING_CONFIG_FAILED;
}
gatep = &gate;
+
+ if (afi == AFI_IP && !negate) {
+ if (if_lookup_exact_address(&gatep->ipv4, AF_INET,
+ svrf->vrf->vrf_id))
+ if (vty)
+ vty_out(vty,
+ "%% Warning!! Local connected address is configured as Gateway IP(%s)\n",
+ gate_str);
+ } else if (afi == AFI_IP6 && !negate) {
+ if (if_lookup_exact_address(&gatep->ipv6, AF_INET6,
+ svrf->vrf->vrf_id))
+ if (vty)
+ vty_out(vty,
+ "%% Warning!! Local connected address is configured as Gateway IPv6(%s)\n",
+ gate_str);
+ }
+
}
if (gate_str == NULL && ifname == NULL)
uint8_t nh_num;
};
+/* API to check whether the configured nexthop address is
+ * one of its local connected address or not.
+ */
+static bool
+static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family)
+{
+ if (family == AF_INET) {
+ if (if_lookup_exact_address(&addr->u.prefix4,
+ AF_INET,
+ vrfid))
+ return true;
+ } else if (family == AF_INET6) {
+ if (if_lookup_exact_address(&addr->u.prefix6,
+ AF_INET6,
+ vrfid))
+ return true;
+ }
+ return false;
+}
static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
{
struct static_nht_data *nhtd, lookup;
if (nhr.prefix.family == AF_INET6)
afi = AFI_IP6;
+ if (nhr.type == ZEBRA_ROUTE_CONNECT) {
+ if (static_nexthop_is_local(vrf_id, &nhr.prefix,
+ nhr.prefix.family))
+ nhr.nexthop_num = 0;
+ }
+
memset(&lookup, 0, sizeof(lookup));
lookup.nh = &nhr.prefix;
lookup.nh_vrf_id = vrf_id;
i = 0;
+ frr_pthread_init();
bgp_pthreads_init();
bgp_pth_ka->running = true;
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;
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();
}
S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
S>* 4.5.6.13/32 [1/0] unreachable (blackhole), XX:XX:XX
S>* 4.5.6.14/32 [1/0] unreachable (blackhole), XX:XX:XX
+S 4.5.6.15/32 [255/0] via 192.168.0.2, r1-eth0, XX:XX:XX
S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX
S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX
S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX
C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX
C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX
O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX
-S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
+S>* 4:5::6:12/128 [1/0] is directly connected, r1-eth0, XX:XX:XX
+S 4:5::6:15/128 [255/0] via fc00::2, r1-eth0, XX:XX:XX
S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX
S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX
S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX
ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0
# Create ifname routes
ip route 4.5.6.12/32 r1-eth0
-ipv6 route 4:5::6:12/32 r1-eth0
+ipv6 route 4:5::6:12/128 r1-eth0
+# Create a route that has a large admin distance
+# an admin distance of 255 should be accepted
+# by zebra but not installed.
+ip route 4.5.6.15/32 192.168.0.2 255
+ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255
!
interface r1-eth0
description to sw0 - no routing protocol
--- /dev/null
+router bgp 65000
+ neighbor 192.168.255.2 remote-as 65001
+ address-family ipv4 unicast
+ redistribute connected
+ aggregate-address 172.16.255.0/24 route-map aggr-rmap
+ exit-address-family
+!
+route-map aggr-rmap permit 10
+ set metric 123
+!
--- /dev/null
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
--- /dev/null
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65000
+ exit-address-family
+!
--- /dev/null
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# bgp_aggregate-address_route-map.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_aggregate-address_route-map.py:
+
+Test if works the following commands:
+router bgp 65031
+ address-family ipv4 unicast
+ aggregate-address 192.168.255.0/24 route-map aggr-rmap
+
+route-map aggr-rmap permit 10
+ set metric 123
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_bgp_maximum_prefix_invalid():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears['r2']
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ '192.168.255.1': {
+ 'bgpState': 'Established',
+ 'addressFamilyInfo': {
+ 'ipv4Unicast': {
+ 'acceptedPrefixCounter': 3
+ }
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_aggregate_address_has_metric(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json"))
+ expected = {
+ 'paths': [
+ {
+ 'med': 123
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, 'Failed to see bgp convergence in "{}"'.format(router)
+
+ test_func = functools.partial(_bgp_aggregate_address_has_metric, router)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, 'Failed to see applied metric for aggregated prefix in "{}"'.format(router)
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+++ /dev/null
-xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
+++ /dev/null
-O 1.1.1.1/32 [110/0] is directly connected, lo
-O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0
-O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx
-O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx
-O 10.0.1.0/24 [110/10] is directly connected, r1-eth0
-O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0
-O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0
+++ /dev/null
-1.1.1.1/32
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
-2.2.2.2/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
-3.3.3.3/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
-4.4.4.4/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
-10.0.1.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
-10.0.2.0/24
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
-10.0.3.0/24
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
+++ /dev/null
-Local LDP Identifier: 1.1.1.1:0
-Discovery Sources:
- Interfaces:
- r1-eth0: xmit/recv
- LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
- Hold time: 15 sec
- Targeted Hellos:
+++ /dev/null
-AF Interface State Uptime Hello Timers ac
-ipv4 r1-eth0 ACTIVE xx:xx:xx 5/15 1
+++ /dev/null
-Peer LDP Identifier: 2.2.2.2:0
- TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r1-eth0
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.2 XX
- XX LDP 10.0.1.2 XX
- XX LDP 10.0.1.2 implicit-null
- XX LDP 10.0.1.2 implicit-null
- XX LDP 10.0.1.2 implicit-null
+ Inbound Label Type Nexthop Outbound Label
+ -----------------------------------------------
+ XX LDP 10.0.1.2 XX
+ XX LDP 10.0.1.2 XX
+ XX LDP 10.0.1.2 implicit-null
+ XX LDP 10.0.1.2 implicit-null
+ XX LDP 10.0.1.2 implicit-null
+
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 XX
- XX LDP 10.0.1.2 XX
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 3
- XX LDP 10.0.1.2 XX
- XX LDP 10.0.1.2 XX
+++ /dev/null
-O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0
-O 2.2.2.2/32 [110/0] is directly connected, lo
-O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1
-O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1
-O 10.0.1.0/24 [110/10] is directly connected, r2-eth0
-O 10.0.2.0/24 [110/10] is directly connected, r2-eth1
-O 10.0.3.0/24 [110/10] is directly connected, r2-eth2
+++ /dev/null
-1.1.1.1/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 imp-null
- 3.3.3.3 xxx
- 4.4.4.4 xxx
-2.2.2.2/32
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 xxx
- 3.3.3.3 xxx
- 4.4.4.4 xxx
-3.3.3.3/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 xxx
- 3.3.3.3 imp-null
- 4.4.4.4 xxx
-4.4.4.4/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 xxx
- 3.3.3.3 xxx
- 4.4.4.4 imp-null
-10.0.1.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 imp-null
- 3.3.3.3 xxx
- 4.4.4.4 xxx
-10.0.2.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 xxx
- 3.3.3.3 imp-null
- 4.4.4.4 imp-null
-10.0.3.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 1.1.1.1 xxx
- 3.3.3.3 imp-null
- 4.4.4.4 xxx
+++ /dev/null
-Local LDP Identifier: 2.2.2.2:0
-Discovery Sources:
- Interfaces:
- r2-eth0: xmit/recv
- LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1
- Hold time: 15 sec
- r2-eth1: xmit/recv
- LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3
- Hold time: 15 sec
- LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4
- Hold time: 15 sec
- Targeted Hellos:
+++ /dev/null
-AF Interface State Uptime Hello Timers ac
-ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1
-ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2
+++ /dev/null
-Peer LDP Identifier: 1.1.1.1:0
- TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r2-eth0
-
-Peer LDP Identifier: 3.3.3.3:0
- TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r2-eth1
-
-Peer LDP Identifier: 4.4.4.4:0
- TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r2-eth1
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.1 implicit-null
- XX LDP 10.0.2.3 implicit-null
- XX LDP 10.0.2.4 implicit-null
- XX LDP 10.0.3.3 implicit-null
+ Inbound Label Type Nexthop Outbound Label
+ -----------------------------------------------
+ XX LDP 10.0.1.1 implicit-null
+ XX LDP 10.0.2.3 implicit-null
+ XX LDP 10.0.2.4 implicit-null
+ XX LDP 10.0.3.3 implicit-null
+
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.1 3
- XX LDP 10.0.2.3 3
- XX LDP 10.0.2.4 3
- XX LDP 10.0.3.3 3
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.1.1 3
- XX LDP 10.0.2.3 3
- XX LDP 10.0.2.4 3
- XX LDP 10.0.3.3 3
+++ /dev/null
-O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx
-O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0
-O 3.3.3.3/32 [110/0] is directly connected, lo
-O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0
-O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0
-O 10.0.2.0/24 [110/10] is directly connected, r3-eth0
-O 10.0.3.0/24 [110/10] is directly connected, r3-eth1
+++ /dev/null
-1.1.1.1/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 4.4.4.4 xxx
-2.2.2.2/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 4.4.4.4 xxx
-3.3.3.3/32
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 4.4.4.4 xxx
-4.4.4.4/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 4.4.4.4 imp-null
-10.0.1.0/24
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 4.4.4.4 xxx
-10.0.2.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 4.4.4.4 imp-null
-10.0.3.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 4.4.4.4 xxx
+++ /dev/null
-Local LDP Identifier: 3.3.3.3:0
-Discovery Sources:
- Interfaces:
- r3-eth0: xmit/recv
- LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
- Hold time: 15 sec
- LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4
- Hold time: 15 sec
- Targeted Hellos:
+++ /dev/null
-AF Interface State Uptime Hello Timers ac
-ipv4 r3-eth0 ACTIVE xx:xx:xx 5/15 2
+++ /dev/null
-Peer LDP Identifier: 2.2.2.2:0
- TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r3-eth0
-
-Peer LDP Identifier: 4.4.4.4:0
- TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r3-eth0
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.2 implicit-null
- XX LDP 10.0.2.2 implicit-null
- XX LDP 10.0.2.4 implicit-null
- XX LDP 10.0.3.2 XX
- XX LDP 10.0.3.2 implicit-null
- XX LDP 10.0.3.2 implicit-null
+ Inbound Label Type Nexthop Outbound Label
+ -----------------------------------------------
+ XX LDP 10.0.2.2 XX
+ XX LDP 10.0.2.2 implicit-null
+ XX LDP 10.0.2.2 implicit-null
+ XX LDP 10.0.2.4 implicit-null
+ XX LDP 10.0.3.2 XX
+ XX LDP 10.0.3.2 implicit-null
+ XX LDP 10.0.3.2 implicit-null
+
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.4 3
- XX LDP 10.0.3.2 3
- XX LDP 10.0.3.2 3
- XX LDP 10.0.3.2 XX
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.4 3
- XX LDP 10.0.3.2 3
- XX LDP 10.0.3.2 3
- XX LDP 10.0.3.2 XX
+++ /dev/null
-O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx
-O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0
-O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0
-O 4.4.4.4/32 [110/0] is directly connected, lo
-O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0
-O 10.0.2.0/24 [110/10] is directly connected, r4-eth0
-O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0
+++ /dev/null
-1.1.1.1/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 3.3.3.3 xxx
-2.2.2.2/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 3.3.3.3 xxx
-3.3.3.3/32
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 3.3.3.3 imp-null
-4.4.4.4/32
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 xxx
- 3.3.3.3 xxx
-10.0.1.0/24
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 3.3.3.3 xxx
-10.0.2.0/24
- Local binding: label: imp-null
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 3.3.3.3 imp-null
-10.0.3.0/24
- Local binding: label: xxx
- Remote bindings:
- Peer Label
- ----------------- ---------
- 2.2.2.2 imp-null
- 3.3.3.3 imp-null
+++ /dev/null
-Local LDP Identifier: 4.4.4.4:0
-Discovery Sources:
- Interfaces:
- r4-eth0: xmit/recv
- LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
- Hold time: 15 sec
- LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3
- Hold time: 15 sec
- Targeted Hellos:
+++ /dev/null
-AF Interface State Uptime Hello Timers ac
-ipv4 r4-eth0 ACTIVE xx:xx:xx 5/15 2
+++ /dev/null
-Peer LDP Identifier: 2.2.2.2:0
- TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r4-eth0
-
-Peer LDP Identifier: 3.3.3.3:0
- TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx
- Session Holdtime: 180 sec
- State: OPERATIONAL; Downstream-Unsolicited
- Up time: xx:xx:xx
- LDP Discovery Sources:
- IPv4:
- Interface: r4-eth0
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.2 implicit-null
- XX LDP 10.0.2.2 implicit-null
- XX LDP 10.0.2.2 implicit-null
- XX LDP 10.0.2.3 implicit-null
- XX LDP 10.0.2.3 implicit-null
+ Inbound Label Type Nexthop Outbound Label
+ -----------------------------------------------
+ XX LDP 10.0.2.2 XX
+ XX LDP 10.0.2.2 implicit-null
+ XX LDP 10.0.2.2 implicit-null
+ XX LDP 10.0.2.2 implicit-null
+ XX LDP 10.0.2.3 implicit-null
+ XX LDP 10.0.2.3 implicit-null
+
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.3 3
- XX LDP 10.0.2.3 3
+++ /dev/null
- Inbound Outbound
- Label Type Nexthop Label
--------- ------- --------------- --------
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 3
- XX LDP 10.0.2.2 XX
- XX LDP 10.0.2.3 3
- XX LDP 10.0.2.3 3
fatal_error = ""
-# Expected version of CLI Output - Appendix to filename
-# empty string = current, latest output (default)
-# "-1" ... "-NNN" previous versions (incrementing with each version)
-cli_version = ""
-
-
#####################################################
##
## Network Topology Definition
def test_router_running():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
fatal_error = net['r%s' % i].checkRouterRunning()
assert fatal_error == "", fatal_error
- # Detect CLI Version
- # At this time, there are only 2 possible outputs, so simple check
- output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
-
- # Check if old or new format of CLI Output. Default is to current format
- #
- # Old (v1) output looks like this:
- # Local LDP Identifier: 1.1.1.1:0
- # Discovery Sources:
- # Interfaces:
- # r1-eth0: xmit/recv
- # LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
- # Hold time: 15 sec
- # Targeted Hellos:
- #
- # Current (v0) output looks like this:
- # AF ID Type Source Holdtime
- # ipv4 2.2.2.2 Link r1-eth0 15
- pattern = re.compile("^Local LDP Identifier.*")
- if pattern.match(output):
- cli_version = "-1"
-
# For debugging after starting FRR/Quagga daemons, uncomment the next line
# CLI(net)
def test_mpls_interfaces():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
print("******************************************\n")
failures = 0
for i in range(1, 5):
- refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version)
+ refTableFile = '%s/r%s/show_mpls_ldp_interface.ref'
if os.path.isfile(refTableFile):
# Read expected result from file
expected = open(refTableFile).read().rstrip()
def test_mpls_ldp_neighbor_establish():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
# Look for any node not yet converged
for i in range(1, 5):
established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
- if cli_version != "-1":
- # On current version, we need to make sure they all turn to OPERATIONAL on all lines
- #
- lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
- # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
- header = r'^AF.*'
- operational = r'^ip.*OPERATIONAL.*'
- found_operational = 0
- for j in range(1, len(lines)):
- if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
- established = "" # Empty string shows NOT established
- if re.search(operational, lines[j]):
- found_operational += 1
- if found_operational < 1:
- # Need at least one operational neighbor
+
+ # On current version, we need to make sure they all turn to OPERATIONAL on all lines
+ #
+ lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
+ # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
+ header = r'^AF.*'
+ operational = r'^ip.*OPERATIONAL.*'
+ found_operational = 0
+ for j in range(1, len(lines)):
+ if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
established = "" # Empty string shows NOT established
+ if re.search(operational, lines[j]):
+ found_operational += 1
+ if found_operational < 1:
+ # Need at least one operational neighbor
+ established = "" # Empty string shows NOT established
if not established:
print('Waiting for r%s' %i)
sys.stdout.flush()
def test_mpls_ldp_discovery():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
print("******************************************\n")
failures = 0
for i in range(1, 5):
- refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version)
+ refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref'
if os.path.isfile(refTableFile):
# Actual output from router
actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
def test_mpls_ldp_neighbor():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
print("******************************************\n")
failures = 0
for i in range(1, 5):
- refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version)
+ refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref'
if os.path.isfile(refTableFile):
# Read expected result from file
expected = open(refTableFile).read().rstrip()
actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
# Mask out changing parts in output
- if cli_version == "-1":
- # Mask out Timer in Uptime
- actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual)
- # Mask out Port numbers in TCP connection
- actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+",
- r"TCP connection: \1:xxx - \2:xxx", actual)
- else:
- # Current Version
- #
- # Mask out Timer in Uptime
- actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual)
+ # Mask out Timer in Uptime
+ actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual)
# Fix newlines (make them all the same)
actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
def test_mpls_ldp_binding():
global fatal_error
global net
- global cli_version
# Skip this test for now until proper sorting of the output
# is implemented
print("******************************************\n")
failures = 0
for i in range(1, 5):
- refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version)
+ refTableFile = '%s/r%s/show_mpls_ldp_binding.ref'
if os.path.isfile(refTableFile):
# Read expected result from file
expected = open(refTableFile).read().rstrip()
actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip()
# Mask out changing parts in output
- if cli_version == "-1":
- # Mask out label
- actual = re.sub(r"label: [0-9]+", "label: xxx", actual)
- actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual)
- else:
- # Current Version
- #
- # Mask out label
- actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
- actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
+ # Mask out label
+ actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
+ actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
# Fix newlines (make them all the same)
actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
def test_zebra_ipv4_routingTable():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
print("******************************************\n")
failures = 0
for i in range(1, 5):
- refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version)
+ refTableFile = '%s/r%s/show_ipv4_route.ref'
if os.path.isfile(refTableFile):
# Read expected result from file
expected = open(refTableFile).read().rstrip()
# now fix newlines of expected (make them all the same)
expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
- # Add missing comma before label (for old version)
- actual = re.sub(r"([0-9]) label ", r"\1, label ", actual)
-
# Fix newlines (make them all the same)
actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
def test_mpls_table():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
print("******************************************\n")
failures = 0
- version = cli_version
- if (version == ""):
- # check for new output without implicit-null
- output = net['r1'].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
- if 'LDP 10.0.1.2 3' in output:
- version = "-no-impl-null"
-
for i in range(1, 5):
- refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, version)
+ refTableFile = '%s/r%s/show_mpls_table.ref'
if os.path.isfile(refTableFile):
# Read expected result from file
- expected = open(refTableFile).read().rstrip()
+ expected = open(refTableFile).read()
# Fix newlines (make them all the same)
expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
# Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
+ actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null')
# Fix inconsistent Label numbers at beginning of line
actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual)
def test_linux_mpls_routes():
global fatal_error
global net
- global cli_version
# Skip if previous fatal error condition is raised
if (fatal_error != ""):
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8300,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8400,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":20100,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":10400,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8100,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8400,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8100,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":8300,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
"installed":true,
"nexthops":[
{
- "type":"SR",
+ "type":"SR (OSPF)",
"outLabel":3,
"distance":150,
"installed":true,
# Skip pytests example directory
[pytest]
-norecursedirs = .git example-test example-topojson-test lib docker
+norecursedirs = .git example-test example-topojson-test lib docker bgp-ecmp-topo2
[topogen]
# Default configuration values
show bgp ipv6 update-groups packet-queue
show bgp ipv6 update-groups statistics
show ip bgp statistics
+show bgp martian next-hop
show bgp evpn route
CMD_LIST_END
CMD_LIST_START
show zebra
show zebra client summary
-show ip route
-
+show ip zebra route dump json
+show ipv6 zebra route dump json
+show ip nht vrf all
show route-map
show memory
-show interface
+show interface vrf all
show vrf
+show zebra fpm stats
show error all
show work-queues
+show debugging hashtable
show running-config
show thread cpu
show thread poll
+#!/usr/bin/python
+
########################################################
### Python Script to generate the FRR support bundle ###
########################################################
\
tools/frrcommon.sh \
tools/frrinit.sh \
+ tools/generate_support_bundle.py \
tools/watchfrr.sh \
# end
tools/frr-reload \
tools/frr-reload.py \
tools/frr.service \
+ tools/generate_support_bundle.py \
tools/multiple-bgpd.sh \
tools/rrcheck.pl \
tools/rrlookup.pl \
== 0
|| strncmp(line, "frr", strlen("frr")) == 0
|| strncmp(line, "agentx", strlen("agentx")) == 0
- || strncmp(line, "no log", strlen("no log")) == 0)
+ || strncmp(line, "no log", strlen("no log")) == 0
+ || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
+ || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
config_add_line_uniq(config_top, line);
else
config_add_line(config_top, line);
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
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
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,
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)
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",
(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);
*/
extern bool check_all_up(void);
+extern void watchfrr_set_ignore_daemon(struct vty *vty, const char *dname,
+ bool ignore);
#endif /* FRR_WATCHFRR_H */
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};
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);
}
description
"This module defines a model for managing FRR eigrpd daemon.";
+ revision 2019-09-09 {
+ description
+ "Changed interface references to use
+ frr-interface:interface-ref typedef";
+ }
revision 2019-06-19 {
description "Initial revision.";
reference
leaf-list passive-interface {
description "List of suppressed interfaces";
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
}
leaf active-time {
description
"This module defines a model for managing FRR interfaces.";
+ revision 2019-09-09 {
+ description
+ "Added interface-ref typedef";
+ }
revision 2018-03-28 {
description
"Initial revision.";
}
}
}
+
+ typedef interface-ref {
+ type leafref {
+ require-instance false;
+ path "/frr-interface:lib/frr-interface:interface/frr-interface:name";
+ }
+ description
+ "Reference to an interface";
+ }
}
description
"This module defines a model for managing FRR isisd daemon.";
+ revision 2019-09-09 {
+ description
+ "Changed interface references to use
+ frr-interface:interface-ref typedef";
+ }
revision 2018-07-26 {
description
"Initial revision.";
description
"Interface specific IS-IS notification data grouping";
leaf interface-name {
- type string;
+ type frr-interface:interface-ref;
description
"IS-IS interface name";
}
description
"This module defines a model for managing FRR ripd daemon.";
+ revision 2019-09-09 {
+ description
+ "Changed interface references to use
+ frr-interface:interface-ref typedef";
+ }
revision 2017-12-06 {
description
"Initial revision.";
"Enable RIP on the specified IP network.";
}
leaf-list interface {
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
description
"Enable RIP on the specified interface.";
}
description
"Offset-list to modify route metric.";
leaf interface {
- type string;
+ type union {
+ type frr-interface:interface-ref;
+ type enumeration {
+ enum '*' {
+ description
+ "Match all interfaces.";
+ }
+ }
+ }
description
"Interface to match. Use '*' to match all interfaces.";
}
}
leaf-list passive-interface {
when "../passive-default = 'false'";
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is disabled.";
}
leaf-list non-passive-interface {
when "../passive-default = 'true'";
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is enabled.";
description
"This module defines a model for managing FRR ripngd daemon.";
+ revision 2019-09-09 {
+ description
+ "Changed interface references to use
+ frr-interface:interface-ref typedef";
+ }
revision 2018-11-27 {
description
"Initial revision.";
"Enable RIPng on the specified IPv6 network.";
}
leaf-list interface {
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
description
"Enable RIPng on the specified interface.";
}
description
"Offset-list to modify route metric.";
leaf interface {
- type string;
+ type union {
+ type frr-interface:interface-ref;
+ type enumeration {
+ enum '*' {
+ description
+ "Match all interfaces.";
+ }
+ }
+ }
description
"Interface to match. Use '*' to match all interfaces.";
}
}
}
leaf-list passive-interface {
- type string {
- length "1..16";
- }
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIPng packets
is disabled.";
#include <zebra.h>
#include "prefix.h"
+#include "ipaddr.h"
#include <libyang/user_types.h>
return 0;
}
+static int ip_address_store_clb(const char *type_name, const char *value_str,
+ lyd_val *value, char **err_msg)
+{
+ value->ptr = malloc(sizeof(struct ipaddr));
+ if (!value->ptr)
+ return 1;
+
+ if (str2ipaddr(value_str, value->ptr)) {
+ free(value->ptr);
+ return 1;
+ }
+
+ return 0;
+}
+
static int ipv4_prefix_store_clb(const char *type_name, const char *value_str,
lyd_val *value, char **err_msg)
{
return 0;
}
+static int ip_prefix_store_clb(const char *type_name, const char *value_str,
+ lyd_val *value, char **err_msg)
+{
+ value->ptr = malloc(sizeof(struct prefix));
+ if (!value->ptr)
+ return 1;
+
+ if (str2prefix(value_str, value->ptr) == 0) {
+ free(value->ptr);
+ return 1;
+ }
+
+ return 0;
+}
+
struct lytype_plugin_list frr_user_types[] = {
{"ietf-inet-types", "2013-07-15", "ipv4-address",
ipv4_address_store_clb, free},
ipv6_address_store_clb, free},
{"ietf-inet-types", "2013-07-15", "ipv6-address-no-zone",
ipv6_address_store_clb, free},
+ {"ietf-inet-types", "2013-07-15", "ip-address", ip_address_store_clb,
+ free},
{"ietf-inet-types", "2013-07-15", "ipv4-prefix", ipv4_prefix_store_clb,
free},
{"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb,
free},
+ {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb,
+ free},
{NULL, NULL, NULL, NULL, NULL} /* terminating item */
};
#include "vrf.h"
#include "libfrr.h"
#include "routemap.h"
-#include "frr_pthread.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h"
zrouter.master = frr_init();
- /* Initialize pthread library */
- frr_pthread_init();
-
/* Zebra related initialize. */
zebra_router_init();
zserv_init();
vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf));
}
-static void zread_mpls_labels(ZAPI_HANDLER_ARGS)
+/*
+ * Handle request to create an MPLS LSP.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ */
+static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS)
{
struct stream *s;
- enum lsp_types_t type;
- struct prefix prefix;
- enum nexthop_types_t gtype;
- union g_addr gate;
- ifindex_t ifindex;
- mpls_label_t in_label, out_label;
- uint8_t distance;
+ struct zapi_labels zl;
/* Get input stream. */
s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
+ return;
+ }
- /* Get data. */
- STREAM_GETC(s, type);
- STREAM_GETL(s, prefix.family);
- switch (prefix.family) {
- case AF_INET:
- STREAM_GET(&prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
- STREAM_GETC(s, prefix.prefixlen);
- if (prefix.prefixlen > IPV4_MAX_BITLEN) {
- zlog_debug(
- "%s: Specified prefix length %d is greater than a v4 address can support",
- __PRETTY_FUNCTION__, prefix.prefixlen);
- return;
- }
- STREAM_GET(&gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN);
- break;
- case AF_INET6:
- STREAM_GET(&prefix.u.prefix6, s, 16);
- STREAM_GETC(s, prefix.prefixlen);
- if (prefix.prefixlen > IPV6_MAX_BITLEN) {
- zlog_debug(
- "%s: Specified prefix length %d is greater than a v6 address can support",
- __PRETTY_FUNCTION__, prefix.prefixlen);
- return;
- }
- STREAM_GET(&gate.ipv6, s, 16);
- break;
- default:
- zlog_debug("%s: Specified AF %d is not supported for this call",
- __PRETTY_FUNCTION__, prefix.family);
+ if (!mpls_enabled)
return;
+
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+ znh->type, &znh->address, znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+ znh->type, &znh->address, znh->ifindex,
+ zl.route.type, zl.route.instance,
+ znh->label);
}
- STREAM_GETL(s, ifindex);
- STREAM_GETC(s, distance);
- STREAM_GETL(s, in_label);
- STREAM_GETL(s, out_label);
+}
- switch (prefix.family) {
- case AF_INET:
- if (ifindex)
- gtype = NEXTHOP_TYPE_IPV4_IFINDEX;
- else
- gtype = NEXTHOP_TYPE_IPV4;
- break;
- case AF_INET6:
- if (ifindex)
- gtype = NEXTHOP_TYPE_IPV6_IFINDEX;
- else
- gtype = NEXTHOP_TYPE_IPV6;
- break;
- default:
+/*
+ * Handle request to delete an MPLS LSP.
+ *
+ * An LSP is identified by its type and local label. When the received message
+ * doesn't contain any nexthop, the whole LSP is deleted. Otherwise, only the
+ * listed LSP nexthops (aka NHLFEs) are deleted.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the labels of the specified
+ * FEC (route) nexthops are deleted.
+ */
+static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_labels zl;
+
+ /* Get input stream. */
+ s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
return;
}
if (!mpls_enabled)
return;
- if (hdr->command == ZEBRA_MPLS_LABELS_ADD) {
- mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
- ifindex);
- mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
- distance, out_label);
- } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) {
- mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
- mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
- distance, out_label);
+ if (zl.nexthop_num > 0) {
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_uninstall(zvrf, zl.type, zl.local_label,
+ znh->type, &znh->address,
+ znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_update(0, zvrf, zl.type,
+ &zl.route.prefix, znh->type,
+ &znh->address, znh->ifindex,
+ zl.route.type,
+ zl.route.instance, znh->label);
+ }
+ } else {
+ mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+ zl.route.type, zl.route.instance);
+ }
+}
+
+/*
+ * Handle request to add an MPLS LSP or change an existing one.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ *
+ * NOTE: zebra will use route replace semantics (make-before-break) to update
+ * the LSP in the forwarding plane if that's supported by the underlying
+ * platform.
+ */
+static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_labels zl;
+
+ /* Get input stream. */
+ s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+
+ if (!mpls_enabled)
+ return;
+
+ mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+ zl.route.type, zl.route.instance);
+
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+ znh->type, &znh->address, znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) {
+ mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+ znh->type, &znh->address, znh->ifindex,
+ zl.route.type, zl.route.instance,
+ znh->label);
+ }
}
-stream_failure:
- return;
}
/* Send response to a table manager connect request to client */
[ZEBRA_INTERFACE_ENABLE_RADV] = NULL,
[ZEBRA_INTERFACE_DISABLE_RADV] = NULL,
#endif
- [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels,
- [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels,
+ [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,
+ [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete,
+ [ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace,
[ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats,
[ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request,
[ZEBRA_LABEL_MANAGER_CONNECT_ASYNC] = zread_label_manager_request,
#include "routemap.h"
#include "stream.h"
#include "nexthop.h"
+#include "termtable.h"
#include "lib/json.h"
#include "zebra/rib.h"
static int snhlfe_del(zebra_snhlfe_t *snhlfe);
static int snhlfe_del_all(zebra_slsp_t *slsp);
static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size);
+static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
+static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
+ int afi, enum lsp_types_t lsp_type);
/* Static functions */
inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
break;
case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
break;
case NEXTHOP_TYPE_IFINDEX:
return 0;
}
+struct lsp_uninstall_args {
+ struct hash *lsp_table;
+ enum lsp_types_t type;
+};
+
+/*
+ * Cleanup MPLS labels registered by this client.
+ */
+static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
+{
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ struct lsp_uninstall_args args;
+
+ zvrf = vrf->info;
+ if (!zvrf)
+ continue;
+
+ /* Cleanup LSPs. */
+ args.lsp_table = zvrf->lsp_table;
+ args.type = lsp_type_from_re_type(client->proto);
+ hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
+ &args);
+
+ /* Cleanup FTNs. */
+ mpls_ftn_uninstall_all(zvrf, AFI_IP,
+ lsp_type_from_re_type(client->proto));
+ mpls_ftn_uninstall_all(zvrf, AFI_IP6,
+ lsp_type_from_re_type(client->proto));
+ }
+
+ return 0;
+}
+
/*
* Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not
*/
int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct prefix *prefix, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex, uint8_t distance,
- mpls_label_t out_label)
+ union g_addr *gate, ifindex_t ifindex, uint8_t route_type,
+ unsigned short route_instance, mpls_label_t out_label)
{
struct route_table *table;
struct route_node *rn;
RNODE_FOREACH_RE (rn, re) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
- if (re->distance == distance)
+ if (re->type == route_type && re->instance == route_instance)
break;
}
return 0;
}
+int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, uint8_t route_type,
+ unsigned short route_instance)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct route_entry *re;
+ struct nexthop *nexthop;
+
+ /* Lookup table. */
+ table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
+ zvrf_id(zvrf));
+ if (!table)
+ return -1;
+
+ /* Lookup existing route */
+ rn = route_node_get(table, prefix);
+ RNODE_FOREACH_RE (rn, re) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+ continue;
+ if (re->type == route_type && re->instance == route_instance)
+ break;
+ }
+ if (re == NULL)
+ return -1;
+
+ for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
+ nexthop_del_labels(nexthop);
+
+ SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+ SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+ rib_queue_add(rn);
+
+ return 0;
+}
+
/*
* Install/update a NHLFE for an LSP in the forwarding table. This may be
* a new LSP entry or a new NHLFE for an existing in-label or an update of
return 0;
}
+int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = in_label;
+ lsp = hash_lookup(lsp_table, &tmp_ile);
+ if (!lsp)
+ return 0;
+
+ return mpls_lsp_uninstall_all(lsp_table, lsp, type);
+}
+
/*
- * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
+ * Uninstall all NHLFEs for a particular LSP forwarding entry.
* If no other NHLFEs exist, the entry would be deleted.
*/
-void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
+static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
{
+ struct lsp_uninstall_args *args = ctxt;
zebra_lsp_t *lsp;
struct hash *lsp_table;
if (!lsp->nhlfe_list)
return;
- lsp_table = ctxt;
+ lsp_table = args->lsp_table;
if (!lsp_table)
return;
- mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
+ mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
}
/*
- * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
+ * LSP type.
*/
-void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
+static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
+ int afi, enum lsp_types_t lsp_type)
{
struct route_table *table;
struct route_node *rn;
RNODE_FOREACH_RE (rn, re) {
for (nexthop = re->ng.nexthop; nexthop;
nexthop = nexthop->next) {
- if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
+ if (nexthop->nh_label_type != lsp_type)
continue;
nexthop_del_labels(nexthop);
json_object *json = NULL;
zebra_lsp_t *lsp = NULL;
zebra_nhlfe_t *nhlfe = NULL;
- struct nexthop *nexthop = NULL;
struct listnode *node = NULL;
struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
- vty_out(vty, " Inbound Outbound\n");
- vty_out(vty, " Label Type Nexthop Label\n");
- vty_out(vty, "-------- ------- --------------- --------\n");
+ struct ttable *tt;
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
for (nhlfe = lsp->nhlfe_list; nhlfe;
nhlfe = nhlfe->next) {
- vty_out(vty, "%8d %7s ", lsp->ile.in_label,
- nhlfe_type2str(nhlfe->type));
+ struct nexthop *nexthop;
+ const char *out_label_str;
+ char nh_buf[NEXTHOP_STRLEN];
+
nexthop = nhlfe->nexthop;
switch (nexthop->type) {
zns = zebra_ns_lookup(NS_DEFAULT);
ifp = if_lookup_by_index_per_ns(
- zns,
- nexthop->ifindex);
- if (ifp)
- vty_out(vty, "%15s", ifp->name);
- else
- vty_out(vty, "%15s", "Null");
-
+ zns, nexthop->ifindex);
+ snprintf(nh_buf, sizeof(nh_buf), "%s",
+ ifp ? ifp->name : "Null");
break;
}
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, "%15s",
- inet_ntoa(nexthop->gate.ipv4));
+ inet_ntop(AF_INET, &nexthop->gate.ipv4,
+ nh_buf, sizeof(nh_buf));
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, "%15s",
- inet_ntop(AF_INET6,
- &nexthop->gate.ipv6,
- buf, BUFSIZ));
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+ nh_buf, sizeof(nh_buf));
break;
default:
break;
}
if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
- vty_out(vty, " %8s\n",
- mpls_label2str(
- nexthop->nh_label
- ->num_labels,
- &nexthop->nh_label
- ->label[0],
- buf, BUFSIZ, 1));
+ out_label_str = mpls_label2str(
+ nexthop->nh_label->num_labels,
+ &nexthop->nh_label->label[0],
+ buf, BUFSIZ, 1);
else
- vty_out(vty, "\n");
+ out_label_str = "-";
+
+ ttable_add_row(tt, "%u|%s|%s|%s",
+ lsp->ile.in_label,
+ nhlfe_type2str(nhlfe->type),
+ nh_buf, out_label_str);
}
}
- vty_out(vty, "\n");
+ /* Dump the generated table. */
+ if (tt->nrows > 1) {
+ char *table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ }
+ ttable_del(tt);
}
list_delete(&lsp_list);
mpls_enabled = 1;
hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
+ hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
}
*/
int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct prefix *prefix, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex, uint8_t distance,
- mpls_label_t out_label);
+ union g_addr *gate, ifindex_t ifindex, uint8_t route_type,
+ unsigned short route_instance, mpls_label_t out_label);
+
+/*
+ * Uninstall all NHLFEs bound to a single FEC.
+ */
+int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, uint8_t route_type,
+ unsigned short route_instance);
/*
* Install/update a NHLFE for an LSP in the forwarding table. This may be
union g_addr *gate, ifindex_t ifindex);
/*
- * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
- * If no other NHLFEs exist, the entry would be deleted.
- */
-void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt);
-
-/*
- * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ * Uninstall all NHLFEs for a particular LSP forwarding entry.
*/
-void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi);
+int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label);
/*
* Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry.
return (route_distance(ZEBRA_ROUTE_BGP));
case ZEBRA_LSP_NONE:
case ZEBRA_LSP_SHARP:
- case ZEBRA_LSP_SR:
+ case ZEBRA_LSP_OSPF_SR:
return 150;
}
switch (re_type) {
case ZEBRA_ROUTE_STATIC:
return ZEBRA_LSP_STATIC;
+ case ZEBRA_ROUTE_LDP:
+ return ZEBRA_LSP_LDP;
case ZEBRA_ROUTE_BGP:
return ZEBRA_LSP_BGP;
+ case ZEBRA_ROUTE_OSPF:
+ return ZEBRA_LSP_OSPF_SR;
case ZEBRA_ROUTE_SHARP:
return ZEBRA_LSP_SHARP;
default:
return ZEBRA_ROUTE_LDP;
case ZEBRA_LSP_BGP:
return ZEBRA_ROUTE_BGP;
- case ZEBRA_LSP_SR:
+ case ZEBRA_LSP_OSPF_SR:
return ZEBRA_ROUTE_OSPF;
case ZEBRA_LSP_NONE:
return ZEBRA_ROUTE_KERNEL;
return "LDP";
case ZEBRA_LSP_BGP:
return "BGP";
- case ZEBRA_LSP_SR:
- return "SR";
+ case ZEBRA_LSP_OSPF_SR:
+ return "SR (OSPF)";
case ZEBRA_LSP_SHARP:
return "SHARP";
case ZEBRA_LSP_NONE:
_nexthop_add(&nexthop->resolved, resolved_hop);
}
+/* Checks if nexthop we are trying to resolve to is valid */
+static bool nexthop_valid_resolve(const struct nexthop *nexthop,
+ const struct nexthop *resolved)
+{
+ /* Can't resolve to a recursive nexthop */
+ if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
+ return false;
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ /* If the nexthop we are resolving to does not match the
+ * ifindex for the nexthop the route wanted, its not valid.
+ */
+ if (nexthop->ifindex != resolved->ifindex)
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ }
+
+ return true;
+}
+
/*
* Given a nexthop we need to properly recursively resolve
* the route. As such, do a table lookup to find and match
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_RECURSIVE))
+ if (!nexthop_valid_resolve(nexthop, newhop))
continue;
SET_FLAG(nexthop->flags,
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_RECURSIVE))
+ if (!nexthop_valid_resolve(nexthop, newhop))
continue;
SET_FLAG(nexthop->flags,
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
} while (1);
- /* Check for nexthop tracking processing after finishing with results */
- do_nht_processing();
-
return 0;
}
RNH_IMPORT_CHECK_TYPE);
zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client,
RNH_IMPORT_CHECK_TYPE);
- if (client->proto == ZEBRA_ROUTE_LDP) {
- hash_iterate(zvrf->lsp_table,
- mpls_ldp_lsp_uninstall_all,
- zvrf->lsp_table);
- mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP);
- mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP6);
- }
}
}
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
*/
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");
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
*/
DEFPY (show_route_summary,
show_route_summary_cmd,
- "show\
- <\
- ip$ipv4 route [vrf <NAME$vrf_name|all$vrf_all>]\
- summary [prefix$prefix]\
- |ipv6$ipv6 route [vrf <NAME$vrf_name|all$vrf_all>]\
- summary [prefix$prefix]\
- >",
+ "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] \
+ summary [table (1-4294967295)$table_id] [prefix$prefix]",
SHOW_STR
IP_STR
- "IP routing table\n"
- VRF_FULL_CMD_HELP_STR
- "Summary of all routes\n"
- "Prefix routes\n"
IP6_STR
"IP routing table\n"
VRF_FULL_CMD_HELP_STR
"Summary of all routes\n"
+ "Table to display summary for\n"
+ "The table number\n"
"Prefix routes\n")
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
struct route_table *table;
+ if (table_id == 0)
+ table_id = RT_TABLE_MAIN;
+
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- if ((zvrf = vrf->info) == NULL
- || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL)
+ if ((zvrf = vrf->info) == NULL)
+ continue;
+
+ table = zebra_vrf_table_with_table_id(afi,
+ SAFI_UNICAST,
+ zvrf->vrf->vrf_id,
+ table_id);
+ if (!table)
continue;
if (prefix)
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
- table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
+ table = zebra_vrf_table_with_table_id(afi,
+ SAFI_UNICAST,
+ vrf_id, table_id);
if (!table)
return CMD_SUCCESS;