diff options
59 files changed, 3200 insertions, 1282 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ef8537f039..485495924a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5376,10 +5376,10 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) bgp_attr_get_community( pi->attr), COMMUNITY_NO_LLGR)) - break; + continue; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) - break; + continue; /* * If this is VRF leaked route @@ -5409,9 +5409,9 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) !community_include( bgp_attr_get_community(pi->attr), COMMUNITY_NO_LLGR)) - break; + continue; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) - break; + continue; if (safi == SAFI_UNICAST && (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF || @@ -14161,7 +14161,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, struct bgp *bgp = NULL; int idx = 0; bool uj = use_json(argc, argv); - uint16_t show_flags = 0; + uint16_t show_flags = BGP_SHOW_OPT_DETAIL; if (uj) { argc--; diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 857462a601..c724b938d1 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -369,7 +369,7 @@ static void bgpd_sync_callback(struct thread *thread) thread_add_read(bm->master, bgpd_sync_callback, NULL, socket, &t_rpki); if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(socket, &rec, sizeof(struct pfx_record) != -1)) + while (read(socket, &rec, sizeof(struct pfx_record)) != -1) ; atomic_store_explicit(&rtr_update_overflow, 0, diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index f7d42d8200..d2859670dd 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -272,7 +272,7 @@ ISIS interface Showing ISIS information ======================== -.. clicmd:: show isis summary +.. clicmd:: show isis [vrf <NAME|all>] summary [json] Show summary information about ISIS. @@ -280,17 +280,17 @@ Showing ISIS information Show information about ISIS node. -.. clicmd:: show isis interface [detail] [IFNAME] +.. clicmd:: show isis [vrf <NAME|all>] interface [detail] [IFNAME] [json] Show state and configuration of ISIS specified interface, or all interfaces if no interface is given with or without details. -.. clicmd:: show isis neighbor [detail] [SYSTEMID] +.. clicmd:: show isis [vrf <NAME|all>] neighbor [detail] [SYSTEMID] [json] Show state and information of ISIS specified neighbor, or all neighbors if no system id is given with or without details. -.. clicmd:: show isis database [detail] [LSPID] +.. clicmd:: show isis [vrf <NAME|all>] database [detail] [LSPID] [json] Show the ISIS database globally, for a specific LSP id without or with details. diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 15c6088b7a..221e9c6fe2 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -29,7 +29,7 @@ Besides the common invocation options (:ref:`common-invocation-options`), the Zebra, when started, will read in routes. Those routes that Zebra identifies that it was the originator of will be swept in TIME seconds. If no time is specified then we will sweep those routes immediately. - Under the *BSD's, there is no way to properly store the originating + Under the \*BSD's, there is no way to properly store the originating route and the route types in this case will show up as a static route with an admin distance of 255. diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 06909c4306..2729dce382 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -464,6 +464,220 @@ void isis_adj_expire(struct thread *thread) } /* + * show isis neighbor [detail] json + */ +void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json, + char detail) +{ + json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, + *ipv6_non_link_json, *topo_json, *dis_flaps_json, + *area_addr_json, *adj_sid_json; + time_t now; + struct isis_dynhn *dyn; + int level; + char buf[256]; + + json_object_string_add(json, "adj", isis_adj_name(adj)); + + if (detail == ISIS_UI_LEVEL_BRIEF) { + if (adj->circuit) + json_object_string_add(json, "interface", + adj->circuit->interface->name); + else + json_object_string_add(json, "interface", + "NULL circuit!"); + json_object_int_add(json, "level", adj->level); + json_object_string_add(json, "state", + adj_state2string(adj->adj_state)); + now = time(NULL); + if (adj->last_upd) { + if (adj->last_upd + adj->hold_time < now) + json_object_string_add(json, "last-upd", + "expiring"); + else + json_object_string_add( + json, "expires-in", + time2string(adj->last_upd + + adj->hold_time - now)); + } + json_object_string_add(json, "snpa", snpa_print(adj->snpa)); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + struct sr_adjacency *sra; + struct listnode *anode; + + level = adj->level; + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + if (adj->circuit) + json_object_string_add(iface_json, "name", + adj->circuit->interface->name); + else + json_object_string_add(iface_json, "name", + "null-circuit"); + json_object_int_add(json, "level", adj->level); + json_object_string_add(iface_json, "state", + adj_state2string(adj->adj_state)); + now = time(NULL); + if (adj->last_upd) { + if (adj->last_upd + adj->hold_time < now) + json_object_string_add(iface_json, "last-upd", + "expiring"); + else + json_object_string_add( + json, "expires-in", + time2string(adj->last_upd + + adj->hold_time - now)); + } else + json_object_string_add(json, "expires-in", + time2string(adj->hold_time)); + json_object_int_add(iface_json, "adj-flaps", adj->flaps); + json_object_string_add(iface_json, "last-ago", + time2string(now - adj->last_flap)); + json_object_string_add(iface_json, "circuit-type", + circuit_t2string(adj->circuit_t)); + json_object_string_add(iface_json, "speaks", + nlpid2string(&adj->nlpids)); + if (adj->mt_count != 1 || + adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) { + topo_json = json_object_new_object(); + json_object_object_add(iface_json, "topologies", + topo_json); + for (unsigned int i = 0; i < adj->mt_count; i++) { + snprintfrr(buf, sizeof(buf), "topo-%d", i); + json_object_string_add( + topo_json, buf, + isis_mtid2str(adj->mt_set[i])); + } + } + json_object_string_add(iface_json, "snpa", + snpa_print(adj->snpa)); + if (adj->circuit && + (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { + dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid); + if (dyn) { + snprintfrr(buf, sizeof(buf), "%s-%02x", + dyn->hostname, + adj->lanid[ISIS_SYS_ID_LEN]); + json_object_string_add(iface_json, "lan-id", + buf); + } else { + snprintfrr(buf, sizeof(buf), "%s-%02x", + sysid_print(adj->lanid), + adj->lanid[ISIS_SYS_ID_LEN]); + json_object_string_add(iface_json, "lan-id", + buf); + } + + json_object_int_add(iface_json, "lan-prio", + adj->prio[adj->level - 1]); + + dis_flaps_json = json_object_new_object(); + json_object_object_add(iface_json, "dis-flaps", + dis_flaps_json); + json_object_string_add( + dis_flaps_json, "dis-record", + isis_disflag2string( + adj->dis_record[ISIS_LEVELS + level - 1] + .dis)); + json_object_int_add(dis_flaps_json, "last", + adj->dischanges[level - 1]); + json_object_string_add( + dis_flaps_json, "ago", + time2string(now - (adj->dis_record[ISIS_LEVELS + + level - 1] + .last_dis_change))); + } + + if (adj->area_address_count) { + area_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "area-address", + area_addr_json); + for (unsigned int i = 0; i < adj->area_address_count; + i++) { + json_object_string_add( + area_addr_json, "isonet", + isonet_print(adj->area_addresses[i] + .area_addr, + adj->area_addresses[i] + .addr_len)); + } + } + if (adj->ipv4_address_count) { + ipv4_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv4-address", + ipv4_addr_json); + for (unsigned int i = 0; i < adj->ipv4_address_count; + i++){ + inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf, + sizeof(buf)); + json_object_string_add(ipv4_addr_json, "ipv4", buf); + } + } + if (adj->ll_ipv6_count) { + ipv6_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-link-local", + ipv6_link_json); + for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf, + sizeof(buf)); + json_object_string_add(ipv6_link_json, "ipv6", + buf); + } + } + if (adj->global_ipv6_count) { + ipv6_non_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-global", + ipv6_non_link_json); + for (unsigned int i = 0; i < adj->global_ipv6_count; + i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i], + buf, sizeof(buf)); + json_object_string_add(ipv6_non_link_json, + "ipv6", buf); + } + } + + adj_sid_json = json_object_new_object(); + json_object_object_add(iface_json, "adj-sid", adj_sid_json); + for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) { + const char *adj_type; + const char *backup; + uint32_t sid; + + switch (sra->adj->circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + adj_type = "LAN Adjacency-SID"; + sid = sra->u.ladj_sid->sid; + break; + case CIRCUIT_T_P2P: + adj_type = "Adjacency-SID"; + sid = sra->u.adj_sid->sid; + break; + default: + continue; + } + backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)" + : ""; + + json_object_string_add(adj_sid_json, "nexthop", + (sra->nexthop.family == AF_INET) + ? "IPv4" + : "IPv6"); + json_object_string_add(adj_sid_json, "adj-type", + adj_type); + json_object_string_add(adj_sid_json, "is-backup", + backup); + json_object_int_add(adj_sid_json, "sid", sid); + } + } + return; +} + +/* * show isis neighbor [detail] */ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 4d84c5ca4d..7467a619cb 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -144,6 +144,8 @@ const char *isis_adj_yang_state(enum isis_adj_state state); void isis_adj_expire(struct thread *thread); void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, char detail); +void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json, + char detail); void isis_adj_build_neigh_list(struct list *adjdb, struct list *list); void isis_adj_build_up_list(struct list *adjdb, struct list *list); int isis_adj_usage2levels(enum isis_adj_usage usage); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 1b0447226d..da75f196ba 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -933,6 +933,151 @@ void circuit_update_nlpids(struct isis_circuit *circuit) return; } +void isis_circuit_print_json(struct isis_circuit *circuit, + struct json_object *json, char detail) +{ + int level; + json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, + *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json, + *level_json; + char buf_prx[INET6_BUFSIZ]; + char buf[255]; + + snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id); + if (detail == ISIS_UI_LEVEL_BRIEF) { + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + json_object_string_add(iface_json, "name", + circuit->interface->name); + json_object_string_add(iface_json, "circuit-id", buf); + json_object_string_add(iface_json, "state", + circuit_state2string(circuit->state)); + json_object_string_add(iface_json, "type", + circuit_type2string(circuit->circ_type)); + json_object_string_add(iface_json, "level", + circuit_t2string(circuit->is_type)); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + struct listnode *node; + struct prefix *ip_addr; + + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + json_object_string_add(iface_json, "name", + circuit->interface->name); + json_object_string_add(iface_json, "state", + circuit_state2string(circuit->state)); + if (circuit->is_passive) + json_object_string_add(iface_json, "is-passive", + "passive"); + else + json_object_string_add(iface_json, "is-passive", + "active"); + json_object_string_add(iface_json, "circuit-id", buf); + json_object_string_add(iface_json, "type", + circuit_type2string(circuit->circ_type)); + json_object_string_add(iface_json, "level", + circuit_t2string(circuit->is_type)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + json_object_string_add(iface_json, "snpa", + snpa_print(circuit->u.bc.snpa)); + + + levels_json = json_object_new_array(); + json_object_object_add(iface_json, "levels", levels_json); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((circuit->is_type & level) == 0) + continue; + level_json = json_object_new_object(); + json_object_string_add(level_json, "level", + circuit_t2string(level)); + if (circuit->area->newmetric) + json_object_int_add(level_json, "metric", + circuit->te_metric[0]); + else + json_object_int_add(level_json, "metric", + circuit->metric[0]); + if (!circuit->is_passive) { + json_object_int_add(level_json, + "active-neighbors", + circuit->upadjcount[0]); + json_object_int_add(level_json, + "hello-interval", + circuit->hello_interval[0]); + hold_json = json_object_new_object(); + json_object_object_add(level_json, "holddown", + hold_json); + json_object_int_add( + hold_json, "count", + circuit->hello_multiplier[0]); + json_object_string_add( + hold_json, "pad", + (circuit->pad_hellos ? "yes" : "no")); + json_object_int_add(level_json, "cnsp-interval", + circuit->csnp_interval[0]); + json_object_int_add(level_json, "psnp-interval", + circuit->psnp_interval[0]); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + lan_prio_json = + json_object_new_object(); + json_object_object_add(level_json, + "lan", + lan_prio_json); + json_object_int_add( + lan_prio_json, "priority", + circuit->priority[0]); + json_object_string_add( + lan_prio_json, "is-dis", + (circuit->u.bc.is_dr[0] + ? "yes" + : "no")); + } + } + json_object_array_add(levels_json, level_json); + } + + if (circuit->ip_addrs && listcount(circuit->ip_addrs) > 0) { + ipv4_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "ip-prefix", + ipv4_addr_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv4_addr_json, "ip", + buf_prx); + } + } + if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) { + ipv6_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-link-locals", + ipv6_link_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv6_link_json, "ipv6", + buf_prx); + } + } + if (circuit->ipv6_non_link && + listcount(circuit->ipv6_non_link) > 0) { + ipv6_non_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-prefixes", + ipv6_non_link_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv6_non_link_json, + "ipv6", buf_prx); + } + } + } + return; +} + void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, char detail) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 7465780848..5ff0390c26 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -206,6 +206,8 @@ void isis_circuit_down(struct isis_circuit *); void circuit_update_nlpids(struct isis_circuit *circuit); void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, char detail); +void isis_circuit_print_json(struct isis_circuit *circuit, + struct json_object *json, char detail); size_t isis_circuit_pdu_size(struct isis_circuit *circuit); void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 463d26f6c7..eb7e9e725e 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -733,8 +733,48 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size) } /* this function prints the lsp on show isis database */ -void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis) +void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object *json, + char dynhost, struct isis *isis) +{ + if (json) { + return lsp_print_json(lsp, json, dynhost, isis); + } else { + return lsp_print_vty(lsp, vty, dynhost, isis); + } +} + +void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, + char dynhost, struct isis *isis) +{ + char LSPid[255]; + char age_out[8]; + char b[200]; + json_object *own_json; + char buf[256]; + + lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis); + own_json = json_object_new_object(); + json_object_object_add(json, "lsp", own_json); + json_object_string_add(own_json, "id", LSPid); + json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " "); + json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len); + snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno); + json_object_string_add(json, "seq-number", buf); + snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum); + json_object_string_add(json, "chksum", buf); + if (lsp->hdr.rem_lifetime == 0) { + snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out); + age_out[7] = '\0'; + json_object_string_add(json, "holdtime", age_out); + } else { + json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime); + } + json_object_string_add( + json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); +} + +void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, + char dynhost, struct isis *isis) { char LSPid[255]; char age_out[8]; @@ -754,30 +794,40 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); } -void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis) +void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, + struct isis *isis) { - lsp_print(lsp, vty, dynhost, isis); - if (lsp->tlvs) - vty_multiline(vty, " ", "%s", isis_format_tlvs(lsp->tlvs)); - vty_out(vty, "\n"); + if (json) { + lsp_print_json(lsp, json, dynhost, isis); + if (lsp->tlvs) { + isis_format_tlvs(lsp->tlvs, json); + } + } else { + lsp_print_vty(lsp, vty, dynhost, isis); + if (lsp->tlvs) + vty_multiline(vty, " ", "%s", + isis_format_tlvs(lsp->tlvs, NULL)); + vty_out(vty, "\n"); + } } /* print all the lsps info in the local lspdb */ -int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail, - char dynhost, struct isis *isis) +int lsp_print_all(struct vty *vty, struct json_object *json, + struct lspdb_head *head, char detail, char dynhost, + struct isis *isis) { struct isis_lsp *lsp; int lsp_count = 0; if (detail == ISIS_UI_LEVEL_BRIEF) { frr_each (lspdb, head, lsp) { - lsp_print(lsp, vty, dynhost, isis); + lsp_print_common(lsp, vty, json, dynhost, isis); lsp_count++; } } else if (detail == ISIS_UI_LEVEL_DETAIL) { frr_each (lspdb, head, lsp) { - lsp_print_detail(lsp, vty, dynhost, isis); + lsp_print_detail(lsp, vty, json, dynhost, isis); lsp_count++; } } @@ -1264,7 +1314,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) if (!fragments) { zlog_warn("BUG: could not fragment own LSP:"); log_multiline(LOG_WARNING, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); isis_free_tlvs(tlvs); return; } diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index f42d702b37..b13b2a35e6 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -120,12 +120,19 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno); void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost, char frag, struct isis *isis); -void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis); -void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost, +void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, struct isis *isis); -int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail, - char dynhost, struct isis *isis); +void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, char dynhost, + struct isis *isis); +void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, + char dynhost, struct isis *isis); +void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, + struct isis *isis); +int lsp_print_all(struct vty *vty, struct json_object *json, + struct lspdb_head *head, char detail, char dynhost, + struct isis *isis); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 517c9ec5aa..1a54d47f3c 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -2209,7 +2209,7 @@ int send_csnp(struct isis_circuit *circuit, int level) circuit->interface->name, stream_get_endp(circuit->snd_stream)); log_multiline(LOG_DEBUG, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); if (IS_DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), @@ -2368,7 +2368,7 @@ static int send_psnp(int level, struct isis_circuit *circuit) circuit->interface->name, stream_get_endp(circuit->snd_stream)); log_multiline(LOG_DEBUG, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); if (IS_DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 04b5cf1a67..d5b02f3881 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2683,3 +2683,15 @@ void isis_spf_print(struct isis_spftree *spftree, struct vty *vty) vty_out(vty, " run count : %u\n", spftree->runcount); } +void isis_spf_print_json(struct isis_spftree *spftree, struct json_object *json) +{ + char uptime[MONOTIME_STRLEN]; + time_t cur; + cur = time(NULL); + cur -= spftree->last_run_timestamp; + frrtime_to_interval(cur, uptime, sizeof(uptime)); + json_object_string_add(json, "last-run-elapsed", uptime); + json_object_int_add(json, "last-run-duration-usec", + spftree->last_run_duration); + json_object_int_add(json, "last-run-count", spftree->runcount); +} diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 5b3aa59379..815db7b226 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -75,6 +75,8 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, bool prefix_sid, bool backup); void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); +void isis_spf_print_json(struct isis_spftree *spftree, + struct json_object *json); void isis_run_spf(struct isis_spftree *spftree); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, uint8_t *sysid, diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index f1aae7caf1..d3d59fb435 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -22,6 +22,7 @@ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +#include <json-c/json_object.h> #include <zebra.h> #ifdef CRYPTO_INTERNAL @@ -57,7 +58,8 @@ typedef void (*free_item_func)(struct isis_item *i); typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s, struct sbuf *log, void *dest, int indent); typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent); + struct sbuf *buf, struct json_object *json, + int indent); typedef struct isis_item *(*copy_item_func)(struct isis_item *i); struct tlv_ops { @@ -208,152 +210,430 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) /* 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) + struct sbuf *buf, struct json_object *json, + int indent, uint16_t mtid) { + char aux_buf[255]; + char cnt_buf[255]; /* Standard metrics */ - if (IS_SUBTLV(exts, EXT_ADM_GRP)) - sbuf_push(buf, indent, "Administrative Group: 0x%x\n", - exts->adm_group); + if (IS_SUBTLV(exts, EXT_ADM_GRP)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", + exts->adm_group); + json_object_string_add(json, "adm-group", aux_buf); + } else + sbuf_push(buf, indent, "Administrative Group: 0x%x\n", + exts->adm_group); + } if (IS_SUBTLV(exts, EXT_LLRI)) { - sbuf_push(buf, indent, "Link Local ID: %u\n", - exts->local_llri); - sbuf_push(buf, indent, "Link Remote ID: %u\n", - exts->remote_llri); - } - if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) - sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n", - &exts->local_addr); - if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) - sbuf_push(buf, indent, - "Remote Interface IP Address(es): %pI4\n", - &exts->neigh_addr); - if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) - sbuf_push(buf, indent, - "Local Interface IPv6 Address(es): %pI6\n", - &exts->local_addr6); - if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) - sbuf_push(buf, indent, - "Remote Interface IPv6 Address(es): %pI6\n", - &exts->neigh_addr6); - 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 (json) { + json_object_int_add(json, "link-local-id", + exts->local_llri); + json_object_int_add(json, "link-remote-id", + exts->remote_llri); + } else { + sbuf_push(buf, indent, "Link Local ID: %u\n", + exts->local_llri); + sbuf_push(buf, indent, "Link Remote ID: %u\n", + exts->remote_llri); + } + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) { + if (json) { + inet_ntop(AF_INET, &exts->local_addr, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "local-iface-ip", aux_buf); + } else + sbuf_push(buf, indent, + "Local Interface IP Address(es): %pI4\n", + &exts->local_addr); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) { + if (json) { + inet_ntop(AF_INET, &exts->neigh_addr, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "remote-iface-ip", + aux_buf); + } else + sbuf_push(buf, indent, + "Remote Interface IP Address(es): %pI4\n", + &exts->neigh_addr); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) { + if (json) { + inet_ntop(AF_INET6, &exts->local_addr6, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "local-iface-ipv6", + aux_buf); + } else + sbuf_push(buf, indent, + "Local Interface IPv6 Address(es): %pI6\n", + &exts->local_addr6); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) { + if (json) { + inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "remote-iface-ipv6", + aux_buf); + } else + sbuf_push(buf, indent, + "Remote Interface IPv6 Address(es): %pI6\n", + &exts->neigh_addr6); + } + if (IS_SUBTLV(exts, EXT_MAX_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->max_bw); + json_object_string_add(json, "max-bandwith-bytes-sec", + aux_buf); + } else + sbuf_push(buf, indent, + "Maximum Bandwidth: %g (Bytes/sec)\n", + exts->max_bw); + } + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->max_rsv_bw); + json_object_string_add( + json, "max-res-bandwith-bytes-sec", aux_buf); + } else + 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 (json) { + struct json_object *unrsv_json; + unrsv_json = json_object_new_object(); + json_object_object_add(json, "unrsv-bandwith-bytes-sec", + unrsv_json); + for (int j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->unrsv_bw[j]); + json_object_string_add(unrsv_json, cnt_buf, + aux_buf); + } + } else { + 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: %u\n", - exts->remote_as); - if (IS_SUBTLV(exts, EXT_RMT_IP)) - sbuf_push(buf, indent, - "Inter-AS TE Remote ASBR IP address: %pI4\n", - &exts->remote_ip); + if (IS_SUBTLV(exts, EXT_TE_METRIC)) { + if (json) { + json_object_int_add(json, "te-metric", exts->te_metric); + } else + sbuf_push(buf, indent, + "Traffic Engineering Metric: %u\n", + exts->te_metric); + } + if (IS_SUBTLV(exts, EXT_RMT_AS)) { + if (json) { + json_object_int_add(json, "inter-as-te-remote-as", + exts->remote_as); + } else + sbuf_push(buf, indent, + "Inter-AS TE Remote AS number: %u\n", + exts->remote_as); + } + if (IS_SUBTLV(exts, EXT_RMT_IP)) { + if (json) { + inet_ntop(AF_INET6, &exts->remote_ip, aux_buf, + sizeof(aux_buf)); + json_object_string_add( + json, "inter-as-te-remote-asbr-ip", aux_buf); + } else + sbuf_push(buf, indent, + "Inter-AS TE Remote ASBR IP address: %pI4\n", + &exts->remote_ip); + } /* Extended metrics */ - if (IS_SUBTLV(exts, EXT_DELAY)) - sbuf_push(buf, indent, - "%s Average Link Delay: %u (micro-sec)\n", - IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal", - exts->delay); + if (IS_SUBTLV(exts, EXT_DELAY)) { + if (json) { + struct json_object *avg_json; + avg_json = json_object_new_object(); + json_object_object_add(json, "avg-delay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "micro-sec", exts->delay); + } else + sbuf_push(buf, indent, + "%s Average Link Delay: %u (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: %u / %u (micro-sec)\n", - IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal", - exts->min_delay & TE_EXT_MASK, - exts->max_delay & TE_EXT_MASK); + if (json) { + struct json_object *avg_json; + avg_json = json_object_new_object(); + json_object_object_add(json, "max-min-delay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->min_delay) + ? "Anomalous" + : "Normal"); + snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + json_object_string_add(avg_json, "micro-sec", aux_buf); + + } else + sbuf_push( + buf, indent, + "%s Min/Max Link Delay: %u / %u (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: %u (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); + if (json) { + json_object_int_add(json, "delay-variation-micro-sec", + exts->delay_var & TE_EXT_MASK); + } else + sbuf_push(buf, indent, + "Delay Variation: %u (micro-sec)\n", + exts->delay_var & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (float)((exts->pkt_loss & TE_EXT_MASK) * + LOSS_PRECISION)); + struct json_object *link_json; + link_json = json_object_new_object(); + json_object_object_add(json, "link-packet-loss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(exts->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_add(link_json, "percentaje", + aux_buf); + } else + 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)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->res_bw)); + json_object_string_add(json, + "unidir-residual-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Residual Bandwidth: %g (Bytes/sec)\n", + exts->res_bw); + } + if (IS_SUBTLV(exts, EXT_AVA_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->ava_bw)); + json_object_string_add( + json, "unidir-available-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Available Bandwidth: %g (Bytes/sec)\n", + exts->ava_bw); + } + if (IS_SUBTLV(exts, EXT_USE_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->use_bw)); + json_object_string_add(json, + "unidir-utilized-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n", + exts->use_bw); + } /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */ 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) { - sbuf_push( - buf, indent, - "Adjacency-SID: %u, Weight: %hhu, 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 (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "adj-sid", arr_adj_json); + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + adj->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", + adj->sid); + json_object_int_add(flags_json, "weight", + adj->weight); + json_object_string_add( + flags_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, flags_json); + } + } else + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + sbuf_push( + buf, indent, + "Adjacency-SID: %u, Weight: %hhu, 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'); + } } /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */ 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) { - continue; - sbuf_push(buf, indent, - "Lan-Adjacency-SID: %u, Weight: %hhu, 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)); - } + if (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "lan-adj-sid", + arr_adj_json); + for (lan = (struct isis_lan_adj_sid *) + exts->adj_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; + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + lan->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", + lan->sid); + json_object_int_add(flags_json, "weight", + lan->weight); + json_object_string_add( + flags_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, flags_json); + } + } else + + 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: %u, Weight: %hhu, 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)); + } } } @@ -880,26 +1160,64 @@ static struct isis_item *copy_item_prefix_sid(struct isis_item *i) } static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; - sbuf_push(buf, indent, "SR Prefix-SID "); - if (sid->flags & ISIS_PREFIX_SID_VALUE) { - sbuf_push(buf, 0, "Label: %u, ", sid->value); + if (json) { + struct json_object *sr_json; + sr_json = json_object_new_object(); + json_object_object_add(json, "sr", sr_json); + if (sid->flags & ISIS_PREFIX_SID_VALUE) { + json_object_int_add(sr_json, "label", sid->value); + } else { + json_object_int_add(sr_json, "index", sid->value); + } + json_object_int_add(sr_json, "alg", sid->algorithm); + json_object_string_add( + sr_json, "readvertised", + ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes" + : "")); + json_object_string_add( + sr_json, "node", + ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : "")); + json_object_string_add(sr_json, "php", + ((sid->flags & ISIS_PREFIX_SID_NO_PHP) + ? "no-php" + : "php")); + json_object_string_add( + sr_json, "explicit-null", + ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes" + : "")); + json_object_string_add( + sr_json, "value", + ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : "")); + json_object_string_add( + sr_json, "local", + ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : "")); + } else { - sbuf_push(buf, 0, "Index: %u, ", sid->value); + sbuf_push(buf, indent, "SR Prefix-SID "); + if (sid->flags & ISIS_PREFIX_SID_VALUE) { + sbuf_push(buf, 0, "Label: %u, ", sid->value); + } else { + sbuf_push(buf, 0, "Index: %u, ", sid->value); + } + sbuf_push(buf, 0, "Algorithm: %hhu, ", 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" : ""); } - sbuf_push(buf, 0, "Algorithm: %hhu, ", 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) @@ -977,7 +1295,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, sid.value = stream_getl(s); } - format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2); + format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, NULL, indent + 2); append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid)); return 0; } @@ -997,14 +1315,21 @@ static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p) } static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, + int indent) { if (!p) return; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", - prefix2str(p, prefixbuf, sizeof(prefixbuf))); + if (json) { + prefix2str(p, prefixbuf, sizeof(prefixbuf)); + json_object_string_add(json, "ipv6-src-prefix", prefixbuf); + } else { + sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", + prefix2str(p, prefixbuf, sizeof(prefixbuf))); + } } static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, @@ -1080,7 +1405,8 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *src, struct isis_item_list *dest); static void format_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, - struct sbuf *buf, int indent); + struct sbuf *buf, struct json_object *json, + int indent); #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items); @@ -1124,12 +1450,12 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs) } static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID, - &subtlvs->prefix_sids, buf, indent); + &subtlvs->prefix_sids, buf, json, indent); - format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent); + format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, json, indent); } static void isis_free_subtlvs(struct isis_subtlvs *subtlvs) @@ -1189,12 +1515,18 @@ static struct isis_item *copy_item_area_address(struct isis_item *i) } static void format_item_area_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_area_address *addr = (struct isis_area_address *)i; - sbuf_push(buf, indent, "Area Address: %s\n", - isonet_print(addr->addr, addr->len)); + if (json) { + json_object_string_add(json, "area-addr", + isonet_print(addr->addr, addr->len)); + } else { + sbuf_push(buf, indent, "Area Address: %s\n", + isonet_print(addr->addr, addr->len)); + } } static void free_item_area_address(struct isis_item *i) @@ -1251,7 +1583,7 @@ static int unpack_item_area_address(uint16_t mtid, uint8_t len, stream_get(rv->addr, s, rv->len); format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv, - log, indent + 2); + log, NULL, indent + 2); append_item(&tlvs->area_addresses, (struct isis_item *)rv); return 0; out: @@ -1271,12 +1603,21 @@ static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i) } static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; - sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", - isis_format_id(r->id, 7), r->metric); + if (json) { + struct json_object *old_json; + old_json = json_object_new_object(); + json_object_object_add(json, "old-reach-style", old_json); + json_object_string_add(old_json, "is-reach", + isis_format_id(r->id, 7)); + json_object_int_add(old_json, "metric", r->metric); + } else + sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", + isis_format_id(r->id, 7), r->metric); } static void free_item_oldstyle_reach(struct isis_item *i) @@ -1327,7 +1668,7 @@ static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len, stream_forward_getp(s, 3); /* Skip other metrics */ stream_get(rv->id, s, 7); - format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, + format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv); return 0; @@ -1344,11 +1685,17 @@ static struct isis_item *copy_item_lan_neighbor(struct isis_item *i) } static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; - sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6)); + if (json) { + json_object_string_add(json, "lan-neighbor", + isis_format_id(n->mac, 6)); + } else + sbuf_push(buf, indent, "LAN Neighbor: %s\n", + isis_format_id(n->mac, 6)); } static void free_item_lan_neighbor(struct isis_item *i) @@ -1389,7 +1736,7 @@ static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len, struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(rv->mac, s, 6); - format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->lan_neighbor, (struct isis_item *)rv); return 0; } @@ -1409,10 +1756,23 @@ static struct isis_item *copy_item_lsp_entry(struct isis_item *i) } static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; + if (json) { + char buf[255]; + struct json_object *lsp_json; + lsp_json = json_object_new_object(); + json_object_object_add(json, "lsp-entry", lsp_json); + json_object_string_add(lsp_json, "id", isis_format_id(e->id, 8)); + snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno); + json_object_string_add(lsp_json, "seq", buf); + snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum); + json_object_string_add(lsp_json, "chksum", buf); + json_object_int_add(lsp_json, "lifetime", e->checksum); + } else sbuf_push(buf, indent, "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n", isis_format_id(e->id, 8), e->seqno, e->checksum, @@ -1462,7 +1822,7 @@ static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s, rv->seqno = stream_getl(s); rv->checksum = stream_getw(s); - format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_lsp_entry(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->lsp_entries, (struct isis_item *)rv); return 0; } @@ -1484,19 +1844,40 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i) } static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_extended_reach *r = (struct isis_extended_reach *)i; - sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", - isis_format_id(r->id, 7), r->metric); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); + if (json) { + struct json_object *reach_json; + reach_json = json_object_new_object(); + json_object_object_add(json, "ext-reach", reach_json); + json_object_string_add( + reach_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); + json_object_string_add(reach_json, "id", + isis_format_id(r->id, 7)); + json_object_int_add(reach_json, "metric", r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, NULL, json, + indent + 2, mtid); + } else { + sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + isis_format_id(r->id, 7), r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); - if (r->subtlvs) - format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid); + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, buf, NULL, + indent + 2, mtid); + } } static void free_item_extended_reach(struct isis_item *i) @@ -1579,7 +1960,7 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, } } - format_item_extended_reach(mtid, (struct isis_item *)rv, log, + format_item_extended_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(items, (struct isis_item *)rv); return 0; @@ -1603,11 +1984,20 @@ static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i) } static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; + if (json) { + struct json_object *old_json; + old_json = json_object_new_object(); + json_object_object_add(json, "old-ip-reach-style", old_json); + json_object_string_add(old_json, "prefix", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(old_json, "metric", r->metric); + } else sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric); @@ -1669,7 +2059,7 @@ static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len, stream_get(&mask, s, 4); rv->prefix.prefixlen = ip_masklen(mask); - format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, + format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(dest, (struct isis_item *)rv); return 0; @@ -1689,17 +2079,32 @@ static void copy_tlv_protocols_supported(struct isis_protocols_supported *src, } static void format_tlv_protocols_supported(struct isis_protocols_supported *p, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!p || !p->count || !p->protocols) return; - sbuf_push(buf, indent, "Protocols Supported: "); - for (uint8_t i = 0; i < p->count; i++) { - sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]), - (i + 1 < p->count) ? ", " : ""); + if (json) { + struct json_object *protocol_json; + char buf[255]; + + protocol_json = json_object_new_object(); + json_object_object_add(json, "protocols-supported", + protocol_json); + for (uint8_t i = 0; i < p->count; i++) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(protocol_json, buf, + nlpid2str(p->protocols[i])); + } + } else { + sbuf_push(buf, indent, "Protocols Supported: "); + for (uint8_t i = 0; i < p->count; i++) { + sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]), + (i + 1 < p->count) ? ", " : ""); + } + sbuf_push(buf, 0, "\n"); } - sbuf_push(buf, 0, "\n"); } static void free_tlv_protocols_supported(struct isis_protocols_supported *p) @@ -1746,7 +2151,7 @@ static int unpack_tlv_protocols_supported(enum isis_tlv_context context, tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len); stream_get(tlvs->protocols_supported.protocols, s, tlv_len); - format_tlv_protocols_supported(&tlvs->protocols_supported, log, + format_tlv_protocols_supported(&tlvs->protocols_supported, log, NULL, indent + 2); return 0; } @@ -1762,13 +2167,18 @@ static struct isis_item *copy_item_ipv4_address(struct isis_item *i) } static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf); + if (json) { + json_object_string_add(json, "ipv4", addrbuf); + } else { + sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf); + } } static void free_item_ipv4_address(struct isis_item *i) @@ -1809,7 +2219,7 @@ static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len, struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, 4); - format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv4_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->ipv4_address, (struct isis_item *)rv); return 0; } @@ -1826,13 +2236,17 @@ static struct isis_item *copy_item_ipv6_address(struct isis_item *i) } static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf); + if (json) + json_object_string_add(json, "ipv6", addrbuf); + else + sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf); } static void free_item_ipv6_address(struct isis_item *i) @@ -1873,7 +2287,7 @@ static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len, struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, IPV6_MAX_BYTELEN); - format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->ipv6_address, (struct isis_item *)rv); return 0; } @@ -1890,13 +2304,19 @@ static struct isis_item *copy_item_global_ipv6_address(struct isis_item *i) } static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, + int indent) { struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf); + if (json) + json_object_string_add(json, "global-ipv6", addrbuf); + else + sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", + addrbuf); } static void free_item_global_ipv6_address(struct isis_item *i) @@ -1937,7 +2357,7 @@ static int unpack_item_global_ipv6_address(uint16_t mtid, uint8_t len, struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, IPV6_MAX_BYTELEN); - format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, + format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->global_ipv6_address, (struct isis_item *)rv); return 0; @@ -1956,14 +2376,23 @@ static struct isis_item *copy_item_mt_router_info(struct isis_item *i) } static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; - sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", - isis_mtid2str(info->mtid), - info->overload ? " Overload" : "", - info->attached ? " Attached" : ""); + if (json) { + struct json_object *mt_json; + mt_json = json_object_new_object(); + json_object_object_add(json, "mt", mt_json); + json_object_int_add(mt_json, "mtid", info->mtid); + json_object_string_add(mt_json, "overload", info->overload?"true":"false"); + json_object_string_add(mt_json, "attached", info->attached?"true":"false"); + } else + sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", + isis_mtid2str(info->mtid), + info->overload ? " Overload" : "", + info->attached ? " Attached" : ""); } static void free_item_mt_router_info(struct isis_item *i) @@ -2015,7 +2444,7 @@ static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len, rv->attached = entry & ISIS_MT_AT_MASK; rv->mtid = entry & ISIS_MT_MASK; - format_item_mt_router_info(mtid, (struct isis_item *)rv, log, + format_item_mt_router_info(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->mt_router_info, (struct isis_item *)rv); return 0; @@ -2034,14 +2463,17 @@ static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id) } static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { if (!id) return; char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); + if (json) + json_object_string_add(json, "te-router-id", addrbuf); + else + sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); } static void free_tlv_te_router_id(struct in_addr *id) @@ -2085,7 +2517,7 @@ static int unpack_tlv_te_router_id(enum isis_tlv_context context, tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4); stream_get(tlvs->te_router_id, s, 4); - format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2); + format_tlv_te_router_id(tlvs->te_router_id, log, NULL, indent + 2); return 0; } @@ -2107,22 +2539,46 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i) } static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric, - r->down ? " Down" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); - - if (r->subtlvs) { - sbuf_push(buf, indent, " Subtlvs:\n"); - format_subtlvs(r->subtlvs, buf, indent + 4); + if (json) { + struct json_object *ext_json; + ext_json = json_object_new_object(); + json_object_object_add(json, "ext-ip-reach", ext_json); + json_object_string_add( + json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); + json_object_string_add( + json, "ip-reach", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(json, "ip-reach-metric", r->metric); + json_object_string_add(json, "down", r->down ? "yes" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(json, "mt-name", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlv_json; + subtlv_json = json_object_new_object(); + json_object_object_add(json, "subtlvs", subtlv_json); + format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); + } + } else { + sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), + r->metric, r->down ? " Down" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlvs) { + sbuf_push(buf, indent, " Subtlvs:\n"); + format_subtlvs(r->subtlvs, buf, NULL, indent + 4); + } } } @@ -2216,7 +2672,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, if (orig_prefix != rv->prefix.prefix.s_addr) sbuf_push(log, indent + 2, "WARNING: Prefix had hostbits set.\n"); - format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, + format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) { @@ -2273,12 +2729,15 @@ static char *copy_tlv_dynamic_hostname(const char *hostname) } static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { if (!hostname) return; - sbuf_push(buf, indent, "Hostname: %s\n", hostname); + if (json) + json_object_string_add(json, "hostname", hostname); + else + sbuf_push(buf, indent, "Hostname: %s\n", hostname); } static void free_tlv_dynamic_hostname(char *hostname) @@ -2356,14 +2815,18 @@ static struct in6_addr *copy_tlv_te_router_id_ipv6(const struct in6_addr *id) } static void format_tlv_te_router_id_ipv6(const struct in6_addr *id, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!id) return; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); + if (json) + json_object_string_add(json, "ipv6-te-router-id", addrbuf); + else + sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); } static void free_tlv_te_router_id_ipv6(struct in6_addr *id) @@ -2409,7 +2872,7 @@ static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context, tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, IPV6_MAX_BYTELEN); stream_get(tlvs->te_router_id_ipv6, s, IPV6_MAX_BYTELEN); - format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, indent + 2); + format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, NULL, indent + 2); return 0; } @@ -2429,26 +2892,50 @@ static struct isis_spine_leaf *copy_tlv_spine_leaf( } static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { if (!spine_leaf) return; - sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); - if (spine_leaf->has_tier) { - if (spine_leaf->tier == ISIS_TIER_UNDEFINED) { - sbuf_push(buf, indent, " Tier: undefined\n"); - } else { - sbuf_push(buf, indent, " Tier: %hhu\n", - spine_leaf->tier); + char aux_buf[255]; + + if (json) { + struct json_object *spine_json; + spine_json = json_object_new_object(); + json_object_object_add(json, "spine-leaf-extension", + spine_json); + if (spine_leaf->has_tier) { + snprintfrr(aux_buf, sizeof(aux_buf), "%hhu", + spine_leaf->tier); + json_object_string_add( + spine_json, "tier", + (spine_leaf->tier == ISIS_TIER_UNDEFINED) + ? "undefined" + : aux_buf); + } + json_object_string_add(spine_json, "flag-leaf", + spine_leaf->is_leaf ? "yes" : ""); + json_object_string_add(spine_json, "flag-spine", + spine_leaf->is_spine ? "yes" : ""); + json_object_string_add(spine_json, "flag-backup", + spine_leaf->is_backup ? "yes" : ""); + } else { + sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); + if (spine_leaf->has_tier) { + if (spine_leaf->tier == ISIS_TIER_UNDEFINED) { + sbuf_push(buf, indent, " Tier: undefined\n"); + } else { + sbuf_push(buf, indent, " Tier: %hhu\n", + spine_leaf->tier); + } } - } - - sbuf_push(buf, indent, " Flags:%s%s%s\n", - spine_leaf->is_leaf ? " LEAF" : "", - spine_leaf->is_spine ? " SPINE" : "", - spine_leaf->is_backup ? " BACKUP" : ""); + sbuf_push(buf, indent, " Flags:%s%s%s\n", + spine_leaf->is_leaf ? " LEAF" : "", + spine_leaf->is_spine ? " SPINE" : "", + spine_leaf->is_backup ? " BACKUP" : ""); + } } static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf) @@ -2562,25 +3049,45 @@ static struct isis_threeway_adj *copy_tlv_threeway_adj( return rv; } -static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, - struct sbuf *buf, int indent) +static void +format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, + struct sbuf *buf, struct json_object *json, int indent) { if (!threeway_adj) return; - sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); - sbuf_push(buf, indent, " State: %s (%d)\n", - isis_threeway_state_name(threeway_adj->state), - threeway_adj->state); - sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n", - threeway_adj->local_circuit_id); - if (!threeway_adj->neighbor_set) - return; + if (json) { + struct json_object *three_json; + three_json = json_object_new_object(); + json_object_object_add(json, "p2p-three-way-adj", three_json); + json_object_string_add( + three_json, "state-name", + isis_threeway_state_name(threeway_adj->state)); + json_object_int_add(three_json, "state", threeway_adj->state); + json_object_int_add(three_json, "ext-local-circuit-id", + threeway_adj->local_circuit_id); + if (!threeway_adj->neighbor_set) + return; + json_object_string_add( + three_json, "neigh-system-id", + isis_format_id(threeway_adj->neighbor_id, 6)); + json_object_int_add(three_json, "neigh-ext-circuit-id", + threeway_adj->neighbor_circuit_id); + } else { + sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); + sbuf_push(buf, indent, " State: %s (%d)\n", + isis_threeway_state_name(threeway_adj->state), + threeway_adj->state); + sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n", + threeway_adj->local_circuit_id); + if (!threeway_adj->neighbor_set) + return; - sbuf_push(buf, indent, " Neighbor System ID: %s\n", - isis_format_id(threeway_adj->neighbor_id, 6)); - sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n", - threeway_adj->neighbor_circuit_id); + sbuf_push(buf, indent, " Neighbor System ID: %s\n", + isis_format_id(threeway_adj->neighbor_id, 6)); + sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n", + threeway_adj->neighbor_circuit_id); + } } static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj) @@ -2663,24 +3170,51 @@ static struct isis_item *copy_item_ipv6_reach(struct isis_item *i) } static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", - (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), - r->metric, - r->down ? " Down" : "", - r->external ? " External" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); - - if (r->subtlvs) { - sbuf_push(buf, indent, " Subtlvs:\n"); - format_subtlvs(r->subtlvs, buf, indent + 4); + if (json) { + struct json_object *reach_json; + reach_json = json_object_new_object(); + json_object_object_add(json, "ipv6-reach", reach_json); + json_object_string_add(reach_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" + : "mt"); + json_object_string_add( + reach_json, "prefix", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(reach_json, "metric", r->metric); + json_object_string_add(reach_json, "down", + r->down ? "yes" : ""); + json_object_string_add(reach_json, "external", + r->external ? "yes" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(json, "subtlvs", subtlvs_json); + format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); + } + } else { + sbuf_push(buf, indent, + "%sIPv6 Reachability: %s (Metric: %u)%s%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), + r->metric, r->down ? " Down" : "", + r->external ? " External" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlvs) { + sbuf_push(buf, indent, " Subtlvs:\n"); + format_subtlvs(r->subtlvs, buf, NULL, indent + 4); + } } } @@ -2773,7 +3307,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix))) sbuf_push(log, indent + 2, "WARNING: Prefix had hostbits set.\n"); - format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); if (control & ISIS_IPV6_REACH_SUBTLV) { consume += 1; @@ -2834,6 +3368,77 @@ static struct isis_router_cap *copy_tlv_router_cap( return rv; } +static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, + struct json_object *json) +{ + char addrbuf[INET_ADDRSTRLEN]; + + if (!router_cap) + return; + + /* Router ID and Flags */ + struct json_object *cap_json; + cap_json = json_object_new_object(); + json_object_object_add(json, "router-capability", cap_json); + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + json_object_string_add(cap_json, "id", addrbuf); + json_object_string_add( + cap_json, "flag-d", + router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0"); + json_object_string_add( + cap_json, "flag-s", + router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0"); + + /* Segment Routing Global Block as per RFC8667 section #3.1 */ + if (router_cap->srgb.range_size != 0) { + struct json_object *gb_json; + gb_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-gb", gb_json); + json_object_string_add(gb_json, "ipv4", + IS_SR_IPV4(&router_cap->srgb) ? "1" + : "0"); + json_object_string_add(gb_json, "ipv6", + IS_SR_IPV6(&router_cap->srgb) ? "1" + : "0"); + json_object_int_add(gb_json, "global-block-base", + router_cap->srgb.lower_bound); + json_object_int_add(gb_json, "global-block-range", + router_cap->srgb.range_size); + } + + /* Segment Routing Local Block as per RFC8667 section #3.3 */ + if (router_cap->srlb.range_size != 0) { + struct json_object *lb_json; + lb_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-lb", lb_json); + json_object_int_add(lb_json, "global-block-base", + router_cap->srlb.lower_bound); + json_object_int_add(lb_json, "global-block-range", + router_cap->srlb.range_size); + } + + /* Segment Routing Algorithms as per RFC8667 section #3.2 */ + if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { + char buf[255]; + struct json_object *alg_json; + alg_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-algorithm", + alg_json); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(alg_json, buf, + router_cap->algo[i] == 0 + ? "SPF" + : "Strict SPF"); + } + } + + /* Segment Routing Node MSD as per RFC8491 section #2 */ + if (router_cap->msd != 0) + json_object_int_add(json, "msd", router_cap->msd); +} + static void format_tlv_router_cap(const struct isis_router_cap *router_cap, struct sbuf *buf, int indent) { @@ -3177,26 +3782,40 @@ static struct isis_item *copy_item_auth(struct isis_item *i) } static void format_item_auth(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_auth *auth = (struct isis_auth *)i; char obuf[768]; - sbuf_push(buf, indent, "Authentication:\n"); + if (json) + json_object_string_add(json, "test-auth", "ok"); + else + sbuf_push(buf, indent, "Authentication:\n"); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); - sbuf_push(buf, indent, " Password: %s\n", obuf); + if (json) + json_object_string_add(json, "auth-pass", obuf); + else + sbuf_push(buf, indent, " Password: %s\n", obuf); break; case ISIS_PASSWD_TYPE_HMAC_MD5: for (unsigned int j = 0; j < 16; j++) { - snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, - "%02hhx", auth->value[j]); + snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx", + auth->value[j]); } - sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); + if (json) + json_object_string_add(json, "auth-hmac-md5", obuf); + else + sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); break; default: - sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type); + if (json) + json_object_int_add(json, "auth-unknown", auth->type); + else + sbuf_push(buf, indent, " Unknown (%hhu)\n", + auth->type); break; } } @@ -3270,7 +3889,7 @@ static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s, rv->offset = stream_get_getp(s); stream_get(rv->value, s, rv->length); - format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_auth(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->isis_auth, (struct isis_item *)rv); return 0; } @@ -3294,17 +3913,36 @@ static struct isis_purge_originator *copy_tlv_purge_originator( } static void format_tlv_purge_originator(struct isis_purge_originator *poi, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!poi) return; - sbuf_push(buf, indent, "Purge Originator Identification:\n"); - sbuf_push(buf, indent, " Generator: %s\n", - isis_format_id(poi->generator, sizeof(poi->generator))); - if (poi->sender_set) { - sbuf_push(buf, indent, " Received-From: %s\n", - isis_format_id(poi->sender, sizeof(poi->sender))); + if (json) { + struct json_object *purge_json; + purge_json = json_object_new_object(); + json_object_object_add(json, "purge_originator", purge_json); + + json_object_string_add( + purge_json, "id", + isis_format_id(poi->generator, sizeof(poi->generator))); + if (poi->sender_set) { + json_object_string_add( + purge_json, "rec-from", + isis_format_id(poi->sender, + sizeof(poi->sender))); + } + } else { + sbuf_push(buf, indent, "Purge Originator Identification:\n"); + sbuf_push( + buf, indent, " Generator: %s\n", + isis_format_id(poi->generator, sizeof(poi->generator))); + if (poi->sender_set) { + sbuf_push(buf, indent, " Received-From: %s\n", + isis_format_id(poi->sender, + sizeof(poi->sender))); + } } } @@ -3417,12 +4055,12 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type, static void format_item(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, int indent) { const struct tlv_ops *ops = tlv_table[context][type]; if (ops && ops->format_item) { - ops->format_item(mtid, i, buf, indent); + ops->format_item(mtid, i, buf, json, indent); return; } @@ -3431,12 +4069,13 @@ static void format_item(uint16_t mtid, enum isis_tlv_context context, static void format_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_item *i; for (i = items->head; i; i = i->next) - format_item(mtid, context, type, i, buf, indent); + format_item(mtid, context, type, i, buf, json, indent); } static void free_item(enum isis_tlv_context tlv_context, @@ -3765,12 +4404,12 @@ static void free_mt_items(enum isis_tlv_context context, static void format_mt_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_mt_item_list *m, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { struct isis_item_list *n; RB_FOREACH (n, isis_mt_item_list, m) { - format_items_(n->mtid, context, type, n, buf, indent); + format_items_(n->mtid, context, type, n, buf, json, indent); } } @@ -3917,87 +4556,100 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) return rv; } -static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) +static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_object *json, int indent) { - format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent); + format_tlv_protocols_supported(&tlvs->protocols_supported, buf, json, + indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf, - indent); + json, indent); - format_tlv_purge_originator(tlvs->purge_originator, buf, indent); + format_tlv_purge_originator(tlvs->purge_originator, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, - &tlvs->area_addresses, buf, indent); + &tlvs->area_addresses, buf, json, indent); if (tlvs->mt_router_info_empty) { - sbuf_push(buf, indent, "MT Router Info: None\n"); + if (json) + json_object_string_add(json, "mt-router-info", "none"); + else + sbuf_push(buf, indent, "MT Router Info: None\n"); } else { format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, - &tlvs->mt_router_info, buf, indent); + &tlvs->mt_router_info, buf, json, indent); } format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH, - &tlvs->oldstyle_reach, buf, indent); + &tlvs->oldstyle_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS, - &tlvs->lan_neighbor, buf, indent); + &tlvs->lan_neighbor, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries, - buf, indent); - - format_tlv_dynamic_hostname(tlvs->hostname, buf, indent); - format_tlv_te_router_id(tlvs->te_router_id, buf, indent); - format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, indent); - format_tlv_router_cap(tlvs->router_cap, buf, indent); + buf, json, indent); + + format_tlv_dynamic_hostname(tlvs->hostname, buf, json, indent); + format_tlv_te_router_id(tlvs->te_router_id, buf, json, indent); + format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, json, + indent); + if (json) + format_tlv_router_cap_json(tlvs->router_cap, json); + else + format_tlv_router_cap(tlvs->router_cap, buf, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, - &tlvs->extended_reach, buf, indent); + &tlvs->extended_reach, buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach, - buf, indent); + buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH, - &tlvs->oldstyle_ip_reach, buf, indent); + &tlvs->oldstyle_ip_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT, - &tlvs->oldstyle_ip_reach_ext, buf, indent); + &tlvs->oldstyle_ip_reach_ext, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, - &tlvs->ipv4_address, buf, indent); + &tlvs->ipv4_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, - &tlvs->ipv6_address, buf, indent); + &tlvs->ipv6_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS, - &tlvs->global_ipv6_address, buf, indent); + &tlvs->global_ipv6_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH, - &tlvs->extended_ip_reach, buf, indent); + &tlvs->extended_ip_reach, buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH, - &tlvs->mt_ip_reach, buf, indent); + &tlvs->mt_ip_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach, - buf, indent); + buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, - &tlvs->mt_ipv6_reach, buf, indent); + &tlvs->mt_ipv6_reach, buf, json, indent); - format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent); + format_tlv_threeway_adj(tlvs->threeway_adj, buf, json, indent); - format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent); + format_tlv_spine_leaf(tlvs->spine_leaf, buf, json, indent); } -const char *isis_format_tlvs(struct isis_tlvs *tlvs) +const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json) { - static struct sbuf buf; + if (json) { + format_tlvs(tlvs, NULL, json, 0); + return NULL; + } else { + static struct sbuf buf; - if (!sbuf_buf(&buf)) - sbuf_init(&buf, NULL, 0); + if (!sbuf_buf(&buf)) + sbuf_init(&buf, NULL, 0); - sbuf_reset(&buf); - format_tlvs(tlvs, &buf, 0); - return sbuf_buf(&buf); + sbuf_reset(&buf); + format_tlvs(tlvs, &buf, NULL, 0); + return sbuf_buf(&buf); + } } void isis_free_tlvs(struct isis_tlvs *tlvs) diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 0c6ed11cb6..364e38aba1 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -549,7 +549,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs); struct isis_tlvs *isis_alloc_tlvs(void); int isis_unpack_tlvs(size_t avail_len, struct stream *stream, struct isis_tlvs **dest, const char **error_log); -const char *isis_format_tlvs(struct isis_tlvs *tlvs); +const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json); struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs); struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size); diff --git a/isisd/isisd.c b/isisd/isisd.c index 3fa2b7cc20..369b83396a 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -109,12 +109,19 @@ DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area)); int isis_area_get(struct vty *, const char *); int area_net_title(struct vty *, const char *); int area_clear_net_title(struct vty *, const char *); -int show_isis_interface_common(struct vty *, const char *ifname, char, - const char *vrf_name, bool all_vrf); -int show_isis_neighbor_common(struct vty *, const char *id, char, - const char *vrf_name, bool all_vrf); -int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name, +int show_isis_interface_common(struct vty *, struct json_object *json, + const char *ifname, char, const char *vrf_name, bool all_vrf); +int show_isis_interface_common_vty(struct vty *, const char *ifname, char, + const char *vrf_name, bool all_vrf); +int show_isis_interface_common_json(struct json_object *json, + const char *ifname, char, + const char *vrf_name, bool all_vrf); +int show_isis_neighbor_common(struct vty *, struct json_object *json, + const char *id, char, const char *vrf_name, + bool all_vrf); +int clear_isis_neighbor_common(struct vty *, const char *id, + const char *vrf_name, bool all_vrf); /* Link ISIS instance to VRF. */ void isis_vrf_link(struct isis *isis, struct vrf *vrf) @@ -202,7 +209,7 @@ struct isis *isis_new(const char *vrf_name) /* * Default values */ - isis->max_area_addrs = 3; + isis->max_area_addrs = ISIS_DEFAULT_MAX_AREA_ADDRESSES; isis->process_id = getpid(); isis->router_id = 0; isis->area_list = list_new(); @@ -933,10 +940,125 @@ int area_clear_net_title(struct vty *vty, const char *net_title) /* * 'show isis interface' command */ - -int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, +int show_isis_interface_common(struct vty *vty, struct json_object *json, + const char *ifname, char detail, const char *vrf_name, bool all_vrf) { + if (json) { + return show_isis_interface_common_json(json, ifname, detail, + vrf_name, all_vrf); + } else { + return show_isis_interface_common_vty(vty, ifname, detail, + vrf_name, all_vrf); + } +} + +int show_isis_interface_common_json(struct json_object *json, + const char *ifname, char detail, + const char *vrf_name, bool all_vrf) +{ + struct listnode *anode, *cnode, *inode; + struct isis_area *area; + struct isis_circuit *circuit; + struct isis *isis; + struct json_object *areas_json, *area_json; + struct json_object *circuits_json, *circuit_json; + if (!im) { + // IS-IS Routing Process not enabled + json_object_string_add(json, "is-is-routing-process-enabled", + "no"); + return CMD_SUCCESS; + } + if (vrf_name) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", + areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, + anode, area)) { + area_json = json_object_new_object(); + json_object_string_add( + area_json, "area", + area->area_tag ? area->area_tag + : "null"); + circuits_json = json_object_new_array(); + json_object_object_add(area_json, + "circuits", + circuits_json); + for (ALL_LIST_ELEMENTS_RO( + area->circuit_list, cnode, + circuit)) { + circuit_json = + json_object_new_object(); + json_object_int_add( + circuit_json, "circuit", + circuit->circuit_id); + if (!ifname) + isis_circuit_print_json( + circuit, + circuit_json, + detail); + else if (strcmp(circuit->interface->name, ifname) == 0) + isis_circuit_print_json( + circuit, + circuit_json, + detail); + json_object_array_add( + circuits_json, + circuit_json); + } + json_object_array_add(areas_json, + area_json); + } + } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, + area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag + ? area->area_tag + : "null"); + + circuits_json = json_object_new_array(); + json_object_object_add(area_json, "circuits", + circuits_json); + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, + cnode, circuit)) { + circuit_json = json_object_new_object(); + json_object_int_add( + circuit_json, "circuit", + circuit->circuit_id); + if (!ifname) + isis_circuit_print_json( + circuit, circuit_json, + detail); + else if ( + strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_json( + circuit, circuit_json, + detail); + json_object_array_add(circuits_json, + circuit_json); + } + json_object_array_add(areas_json, area_json); + } + } + } + return CMD_SUCCESS; +} + +int show_isis_interface_common_vty(struct vty *vty, const char *ifname, + char detail, const char *vrf_name, + bool all_vrf) +{ struct listnode *anode, *cnode, *inode; struct isis_area *area; struct isis_circuit *circuit; @@ -990,8 +1112,7 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, circuit, vty, detail); else if ( strcmp(circuit->interface->name, - ifname) - == 0) + ifname) == 0) isis_circuit_print_vty( circuit, vty, detail); } @@ -1003,63 +1124,90 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, DEFUN(show_isis_interface, show_isis_interface_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] interface", + "show " PROTO_NAME " [vrf <NAME|all>] interface [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" + "json output\n" "IS-IS interface\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_interface_detail, show_isis_interface_detail_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] interface detail", + "show " PROTO_NAME " [vrf <NAME|all>] interface detail [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "IS-IS interface\n" - "show detailed information\n") + "show detailed information\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_interface_arg, show_isis_interface_arg_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] interface WORD", + "show " PROTO_NAME " [vrf <NAME|all>] interface WORD [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "IS-IS interface\n" - "IS-IS interface name\n") + "IS-IS interface name\n" + "json output\n") { + int res = CMD_SUCCESS; int idx_word = 0; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); char *ifname = argv_find(argv, argc, "WORD", &idx_word) ? argv[idx_word]->arg : NULL; - return show_isis_interface_common(vty, ifname, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_interface_common( + vty, json, ifname, ISIS_UI_LEVEL_DETAIL, vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid) @@ -1079,8 +1227,65 @@ static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid) return 0; } -static void isis_neighbor_common(struct vty *vty, const char *id, char detail, - struct isis *isis, uint8_t *sysid) +static void isis_neighbor_common_json(struct json_object *json, const char *id, + char detail, struct isis *isis, + uint8_t *sysid) +{ + struct listnode *anode, *cnode, *node; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct json_object *areas_json, *area_json; + struct json_object *circuits_json, *circuit_json; + int i; + + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag ? area->area_tag + : "null"); + circuits_json = json_object_new_array(); + json_object_object_add(area_json, "circuits", circuits_json); + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) { + circuit_json = json_object_new_object(); + json_object_int_add(circuit_json, "circuit", + circuit->circuit_id); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + for (i = 0; i < 2; i++) { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) { + for (ALL_LIST_ELEMENTS_RO( + adjdb, node, adj)) + if (!id || + !memcmp(adj->sysid, + sysid, + ISIS_SYS_ID_LEN)) + isis_adj_print_json( + adj, + circuit_json, + detail); + } + } + } else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) { + adj = circuit->u.p2p.neighbor; + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_print_json(adj, circuit_json, + detail); + } + json_object_array_add(circuits_json, circuit_json); + } + json_object_array_add(areas_json, area_json); + } +} + +static void isis_neighbor_common_vty(struct vty *vty, const char *id, + char detail, struct isis *isis, + uint8_t *sysid) { struct listnode *anode, *cnode, *node; struct isis_area *area; @@ -1103,9 +1308,8 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail, if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS_RO( adjdb, node, adj)) - if (!id - || !memcmp( - adj->sysid, + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty( @@ -1114,24 +1318,35 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail, detail); } } - } else if (circuit->circ_type == CIRCUIT_T_P2P - && circuit->u.p2p.neighbor) { + } else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; - if (!id - || !memcmp(adj->sysid, sysid, - ISIS_SYS_ID_LEN)) + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty(adj, vty, detail); } } } +} +static void isis_neighbor_common(struct vty *vty, struct json_object *json, + const char *id, char detail, struct isis *isis, + uint8_t *sysid) +{ + if (json) { + isis_neighbor_common_json(json, id, detail,isis,sysid); + } else { + isis_neighbor_common_vty(vty, id, detail,isis,sysid); + } } + /* * 'show isis neighbor' command */ -int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, - const char *vrf_name, bool all_vrf) +int show_isis_neighbor_common(struct vty *vty, struct json_object *json, + const char *id, char detail, const char *vrf_name, + bool all_vrf) { struct listnode *node; uint8_t sysid[ISIS_SYS_ID_LEN]; @@ -1150,8 +1365,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, id); return CMD_SUCCESS; } - isis_neighbor_common(vty, id, detail, isis, - sysid); + isis_neighbor_common(vty, json, id, detail, + isis, sysid); } return CMD_SUCCESS; } @@ -1161,7 +1376,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, vty_out(vty, "Invalid system id %s\n", id); return CMD_SUCCESS; } - isis_neighbor_common(vty, id, detail, isis, sysid); + isis_neighbor_common(vty, json, id, detail, isis, + sysid); } } @@ -1254,64 +1470,91 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_ DEFUN(show_isis_neighbor, show_isis_neighbor_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] neighbor", + "show " PROTO_NAME " [vrf <NAME|all>] neighbor [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All vrfs\n" - "IS-IS neighbor adjacencies\n") + "IS-IS neighbor adjacencies\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_neighbor_detail, show_isis_neighbor_detail_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail", + "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "all vrfs\n" "IS-IS neighbor adjacencies\n" - "show detailed information\n") + "show detailed information\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); - return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_neighbor_arg, show_isis_neighbor_arg_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD", + "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All vrfs\n" "IS-IS neighbor adjacencies\n" - "System id\n") + "System id\n" + "json output\n") { + int res = CMD_SUCCESS; int idx_word = 0; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); char *id = argv_find(argv, argc, "WORD", &idx_word) ? argv[idx_word]->arg : NULL; - return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_neighbor_common(vty, json, id, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(clear_isis_neighbor, @@ -2056,7 +2299,152 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd, return CMD_SUCCESS; } -static void common_isis_summary(struct vty *vty, struct isis *isis) + +static const char *pdu_counter_index_to_name_json(enum pdu_counter_index index) +{ + switch (index) { + case L1_LAN_HELLO_INDEX: + return "l1-iih"; + case L2_LAN_HELLO_INDEX: + return "l2-iih"; + case P2P_HELLO_INDEX: + return "p2p-iih"; + case L1_LINK_STATE_INDEX: + return "l1-lsp"; + case L2_LINK_STATE_INDEX: + return "l2-lsp"; + case FS_LINK_STATE_INDEX: + return "fs-lsp"; + case L1_COMPLETE_SEQ_NUM_INDEX: + return "l1-csnp"; + case L2_COMPLETE_SEQ_NUM_INDEX: + return "l2-csnp"; + case L1_PARTIAL_SEQ_NUM_INDEX: + return "l1-psnp"; + case L2_PARTIAL_SEQ_NUM_INDEX: + return "l2-psnp"; + default: + return "???????"; + } +} + +static void common_isis_summary_json(struct json_object *json, + struct isis *isis) +{ + int level; + json_object *areas_json, *area_json, *tx_pdu_json, *rx_pdu_json, + *levels_json, *level_json; + struct listnode *node, *node2; + struct isis_area *area; + time_t cur; + char uptime[MONOTIME_STRLEN]; + char stier[5]; + json_object_string_add(json, "vrf", isis->name); + json_object_int_add(json, "process-id", isis->process_id); + if (isis->sysid_set) + json_object_string_add(json, "system-id", + sysid_print(isis->sysid)); + + cur = time(NULL); + cur -= isis->uptime; + frrtime_to_interval(cur, uptime, sizeof(uptime)); + json_object_string_add(json, "up-time", uptime); + if (isis->area_list) + json_object_int_add(json, "number-areas", + isis->area_list->count); + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag ? area->area_tag + : "null"); + + + if (fabricd) { + uint8_t tier = fabricd_tier(area); + snprintfrr(stier, sizeof(stier), "%s", &tier); + json_object_string_add(area_json, "tier", + tier == ISIS_TIER_UNDEFINED + ? "undefined" + : stier); + } + + if (listcount(area->area_addrs) > 0) { + struct area_addr *area_addr; + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node2, + area_addr)) { + json_object_string_add( + area_json, "net", + isonet_print(area_addr->area_addr, + area_addr->addr_len + + ISIS_SYS_ID_LEN + + 1)); + } + } + + tx_pdu_json = json_object_new_object(); + json_object_object_add(area_json, "tx-pdu-type", tx_pdu_json); + for (int i = 0; i < PDU_COUNTER_SIZE; i++) { + if (!area->pdu_tx_counters[i]) + continue; + json_object_int_add(tx_pdu_json, + pdu_counter_index_to_name_json(i), + area->pdu_tx_counters[i]); + } + json_object_int_add(tx_pdu_json, "lsp-rxmt", + area->lsp_rxmt_count); + + rx_pdu_json = json_object_new_object(); + json_object_object_add(area_json, "rx-pdu-type", rx_pdu_json); + for (int i = 0; i < PDU_COUNTER_SIZE; i++) { + if (!area->pdu_rx_counters[i]) + continue; + json_object_int_add(rx_pdu_json, + pdu_counter_index_to_name_json(i), + area->pdu_rx_counters[i]); + } + + levels_json = json_object_new_array(); + json_object_object_add(area_json, "levels", levels_json); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((area->is_type & level) == 0) + continue; + level_json = json_object_new_object(); + json_object_int_add(level_json, "id", level); + json_object_int_add(level_json, "lsp0-regenerated", + area->lsp_gen_count[level - 1]); + json_object_int_add(level_json, "lsp-purged", + area->lsp_purge_count[level - 1]); + if (area->spf_timer[level - 1]) + json_object_string_add(level_json, "spf", + "pending"); + else + json_object_string_add(level_json, "spf", + "no pending"); + json_object_int_add(level_json, "minimum-interval", + area->min_spf_interval[level - 1]); + if (area->spf_delay_ietf[level - 1]) + json_object_string_add( + level_json, "ietf-spf-delay-activated", + "not used"); + if (area->ip_circuits) { + isis_spf_print_json( + area->spftree[SPFTREE_IPV4][level - 1], + level_json); + } + if (area->ipv6_circuits) { + isis_spf_print_json( + area->spftree[SPFTREE_IPV6][level - 1], + level_json); + } + json_object_array_add(levels_json, level_json); + } + json_object_array_add(areas_json, area_json); + } +} + +static void common_isis_summary_vty(struct vty *vty, struct isis *isis) { struct listnode *node, *node2; struct isis_area *area; @@ -2156,10 +2544,21 @@ static void common_isis_summary(struct vty *vty, struct isis *isis) } } +static void common_isis_summary(struct vty *vty, struct json_object *json, + struct isis *isis) +{ + if (json) { + common_isis_summary_json(json, isis); + } else { + common_isis_summary_vty(vty, isis); + } +} + DEFUN(show_isis_summary, show_isis_summary_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] summary", + "show " PROTO_NAME " [vrf <NAME|all>] summary [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" + "json output\n" "summary\n") { struct listnode *node; @@ -2167,25 +2566,30 @@ DEFUN(show_isis_summary, show_isis_summary_cmd, struct isis *isis; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf) if (!im) { vty_out(vty, PROTO_NAME " is not running\n"); return CMD_SUCCESS; } + if (uj) + json = json_object_new_object(); if (vrf_name) { if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - common_isis_summary(vty, isis); + common_isis_summary(vty, json, isis); return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) - common_isis_summary(vty, isis); + common_isis_summary(vty, json, isis); } - vty_out(vty, "\n"); + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2250,9 +2654,40 @@ struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str, return lsp; } -void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, - int level, struct lspdb_head *lspdb, - const char *sysid_str, int ui_level) +void show_isis_database_lspdb_json(struct json_object *json, + struct isis_area *area, int level, + struct lspdb_head *lspdb, + const char *sysid_str, int ui_level) +{ + struct isis_lsp *lsp; + int lsp_count; + + if (lspdb_count(lspdb) > 0) { + lsp = lsp_for_sysid(lspdb, sysid_str, area->isis); + + if (lsp != NULL || sysid_str == NULL) { + json_object_int_add(json, "id", level + 1); + } + + if (lsp) { + if (ui_level == ISIS_UI_LEVEL_DETAIL) + lsp_print_detail(lsp, NULL, json, + area->dynhostname, area->isis); + else + lsp_print_json(lsp, json, area->dynhostname, + area->isis); + } else if (sysid_str == NULL) { + lsp_count = + lsp_print_all(NULL, json, lspdb, ui_level, + area->dynhostname, area->isis); + + json_object_int_add(json, "count", lsp_count); + } + } +} +void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *sysid_str, int ui_level) { struct isis_lsp *lsp; int lsp_count; @@ -2271,14 +2706,14 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, if (lsp) { if (ui_level == ISIS_UI_LEVEL_DETAIL) - lsp_print_detail(lsp, vty, area->dynhostname, - area->isis); + lsp_print_detail(lsp, vty, NULL, + area->dynhostname, area->isis); else - lsp_print(lsp, vty, area->dynhostname, - area->isis); + lsp_print_vty(lsp, vty, area->dynhostname, + area->isis); } else if (sysid_str == NULL) { lsp_count = - lsp_print_all(vty, lspdb, ui_level, + lsp_print_all(vty, NULL, lspdb, ui_level, area->dynhostname, area->isis); vty_out(vty, " %u LSPs\n\n", lsp_count); @@ -2286,7 +2721,43 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, } } -static void show_isis_database_common(struct vty *vty, const char *sysid_str, +static void show_isis_database_json(struct json_object *json, const char *sysid_str, + int ui_level, struct isis *isis) +{ + struct listnode *node; + struct isis_area *area; + int level; + struct json_object *tag_area_json,*area_json, *lsp_json, *area_arr_json, *arr_json; + uint8_t area_cnt = 0; + + if (isis->area_list->count == 0) + return; + + area_arr_json = json_object_new_array(); + json_object_object_add(json, "areas", area_arr_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + area_json = json_object_new_object(); + tag_area_json = json_object_new_object(); + json_object_string_add(tag_area_json, "name", + area->area_tag ? area->area_tag + : "null"); + + arr_json = json_object_new_array(); + json_object_object_add(area_json,"area",tag_area_json); + json_object_object_add(area_json,"levels",arr_json); + for (level = 0; level < ISIS_LEVELS; level++) { + lsp_json = json_object_new_object(); + show_isis_database_lspdb_json(lsp_json, area, level, + &area->lspdb[level], + sysid_str, ui_level); + json_object_array_add(arr_json, lsp_json); + } + json_object_array_add(area_arr_json, area_json); + area_cnt++; + } +} + +static void show_isis_database_vty(struct vty *vty, const char *sysid_str, int ui_level, struct isis *isis) { struct listnode *node; @@ -2301,11 +2772,22 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str, area->area_tag ? area->area_tag : "null"); for (level = 0; level < ISIS_LEVELS; level++) - show_isis_database_lspdb(vty, area, level, + show_isis_database_lspdb_vty(vty, area, level, &area->lspdb[level], sysid_str, ui_level); } } + +static void show_isis_database_common(struct vty *vty, struct json_object *json, const char *sysid_str, + int ui_level, struct isis *isis) +{ + if (json) { + show_isis_database_json(json, sysid_str, ui_level, isis); + } else { + show_isis_database_vty(vty, sysid_str, ui_level, isis); + } +} + /* * This function supports following display options: * [ show isis database [detail] ] @@ -2322,7 +2804,7 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str, * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ] * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ] */ -static int show_isis_database(struct vty *vty, const char *sysid_str, +static int show_isis_database(struct vty *vty, struct json_object *json, const char *sysid_str, int ui_level, const char *vrf_name, bool all_vrf) { struct listnode *node; @@ -2331,28 +2813,30 @@ static int show_isis_database(struct vty *vty, const char *sysid_str, if (vrf_name) { if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_database_common(vty, sysid_str, + show_isis_database_common(vty, json, sysid_str, ui_level, isis); return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis) - show_isis_database_common(vty, sysid_str, ui_level, - isis); + show_isis_database_common(vty, json, sysid_str, + ui_level, isis); } return CMD_SUCCESS; } DEFUN(show_database, show_database_cmd, - "show " PROTO_NAME " [vrf <NAME|all>] database [detail] [WORD]", + "show " PROTO_NAME " [vrf <NAME|all>] database [detail] [WORD] [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "Link state database\n" "Detailed information\n" - "LSP ID\n") + "LSP ID\n" + "json output\n") { + int res = CMD_SUCCESS; int idx = 0; int idx_vrf = 0; const char *vrf_name = VRF_DEFAULT_NAME; @@ -2361,8 +2845,17 @@ DEFUN(show_database, show_database_cmd, ? ISIS_UI_LEVEL_DETAIL : ISIS_UI_LEVEL_BRIEF; char *id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL; + bool uj = use_json(argc, argv); + json_object *json = NULL; + ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_database(vty, id, uilevel, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + + res = show_isis_database(vty, json, id, uilevel, vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } #ifdef FABRICD diff --git a/isisd/isisd.h b/isisd/isisd.h index 7f8474a5f2..c313fd9ef7 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -89,6 +89,8 @@ struct isis_master { }; #define F_ISIS_UNIT_TEST 0x01 +#define ISIS_DEFAULT_MAX_AREA_ADDRESSES 3 + struct isis { vrf_id_t vrf_id; char *name; @@ -305,9 +307,13 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); -void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, - int level, struct lspdb_head *lspdb, - const char *argv, int ui_level); +void show_isis_database_lspdb_json(struct json_object *json, + struct isis_area *area, int level, + struct lspdb_head *lspdb, const char *argv, + int ui_level); +void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *argv, int ui_level); /* YANG paths */ #define ISIS_INSTANCE "/frr-isisd:isis/instance" diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 34bb1e4986..e2a6290035 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -1,7 +1,7 @@ // +// Copyright (c) 2021-2022, LabN Consulting, L.L.C // Copyright (C) 2019 NetDEF, Inc. // Renato Westphal -// Copyright (c) 2021, LabN Consulting, L.L.C // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free @@ -50,6 +50,8 @@ static struct thread_master *main_master; static struct frr_pthread *fpt; +static bool grpc_running; + #define grpc_debug(...) \ do { \ if (nb_dbg_client_grpc) \ @@ -96,11 +98,11 @@ class Candidates { char errmsg[BUFSIZ] = {0}; - _cdb.erase(c->id); nb_config_free(c->config); if (c->transaction) nb_candidate_commit_abort(c->transaction, errmsg, sizeof(errmsg)); + _cdb.erase(c->id); } struct candidate *get_candidate(uint32_t id) @@ -116,9 +118,11 @@ class Candidates class RpcStateBase { public: + virtual ~RpcStateBase() = default; virtual CallState doCallback() = 0; virtual void do_request(::frr::Northbound::AsyncService *service, - ::grpc::ServerCompletionQueue *cq) = 0; + ::grpc::ServerCompletionQueue *cq, + bool no_copy) = 0; }; /* @@ -188,17 +192,22 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase } void do_request(::frr::Northbound::AsyncService *service, - ::grpc::ServerCompletionQueue *cq) override + ::grpc::ServerCompletionQueue *cq, + bool no_copy) override { grpc_debug("%s, posting a request for: %s", __func__, name); if (requestf) { NewRpcState<Q, S> *copy = - new NewRpcState(cdb, requestf, callback, name); + no_copy ? this + : new NewRpcState(cdb, requestf, + callback, name); (service->*requestf)(©->ctx, ©->request, ©->responder, cq, cq, copy); } else { NewRpcState<Q, S> *copy = - new NewRpcState(cdb, requestsf, callback, name); + no_copy ? this + : new NewRpcState(cdb, requestsf, + callback, name); (service->*requestsf)(©->ctx, ©->request, ©->async_responder, cq, cq, copy); @@ -227,7 +236,6 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase pthread_mutex_unlock(&_tag->cmux); return; } - NewRpcState<Q, S> *orig; const char *name; grpc::ServerContext ctx; @@ -238,12 +246,12 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase Candidates *cdb; void (*callback)(NewRpcState<Q, S> *); - reqfunc_t requestf; - reqsfunc_t requestsf; + reqfunc_t requestf = NULL; + reqsfunc_t requestsf = NULL; pthread_mutex_t cmux = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - void *context; + void *context = 0; CallState state = CREATE; }; @@ -268,10 +276,10 @@ static LYD_FORMAT encoding2lyd_format(enum frr::Encoding encoding) } static int yang_dnode_edit(struct lyd_node *dnode, const std::string &path, - const std::string &value) + const char *value) { - LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), - value.c_str(), LYD_NEW_PATH_UPDATE, &dnode); + LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), value, + LYD_NEW_PATH_UPDATE, &dnode); if (err != LY_SUCCESS) { flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed: %s", __func__, ly_errmsg(ly_native_ctx)); @@ -698,8 +706,8 @@ void HandleUnaryEditCandidate( auto pvs = tag->request.update(); for (const frr::PathValue &pv : pvs) { - if (yang_dnode_edit(candidate_tmp->dnode, pv.path(), pv.value()) - != 0) { + if (yang_dnode_edit(candidate_tmp->dnode, pv.path(), + pv.value().c_str()) != 0) { nb_config_free(candidate_tmp); tag->responder.Finish( @@ -1226,7 +1234,7 @@ void HandleUnaryExecute( frr::NAME##Response>( \ (cdb), &frr::Northbound::AsyncService::Request##NAME, \ &HandleUnary##NAME, #NAME); \ - _rpcState->do_request(service, s_cq); \ + _rpcState->do_request(&service, cq.get(), true); \ } while (0) #define REQUEST_NEWRPC_STREAMING(NAME, cdb) \ @@ -1235,7 +1243,7 @@ void HandleUnaryExecute( frr::NAME##Response>( \ (cdb), &frr::Northbound::AsyncService::Request##NAME, \ &HandleStreaming##NAME, #NAME); \ - _rpcState->do_request(service, s_cq); \ + _rpcState->do_request(&service, cq.get(), true); \ } while (0) struct grpc_pthread_attr { @@ -1244,8 +1252,8 @@ struct grpc_pthread_attr { }; // Capture these objects so we can try to shut down cleanly -static std::unique_ptr<grpc::Server> s_server; -static grpc::ServerCompletionQueue *s_cq; +static pthread_mutex_t s_server_lock = PTHREAD_MUTEX_INITIALIZER; +static grpc::Server *s_server; static void *grpc_pthread_start(void *arg) { @@ -1255,18 +1263,22 @@ static void *grpc_pthread_start(void *arg) Candidates candidates; grpc::ServerBuilder builder; std::stringstream server_address; - frr::Northbound::AsyncService *service = - new frr::Northbound::AsyncService(); + frr::Northbound::AsyncService service; frr_pthread_set_name(fpt); server_address << "0.0.0.0:" << port; builder.AddListeningPort(server_address.str(), grpc::InsecureServerCredentials()); - builder.RegisterService(service); - auto cq = builder.AddCompletionQueue(); - s_cq = cq.get(); - s_server = builder.BuildAndStart(); + builder.RegisterService(&service); + builder.AddChannelArgument( + GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 5000); + std::unique_ptr<grpc::ServerCompletionQueue> cq = + builder.AddCompletionQueue(); + std::unique_ptr<grpc::Server> server = builder.BuildAndStart(); + s_server = server.get(); + + grpc_running = true; /* Schedule all RPC handlers */ REQUEST_NEWRPC(GetCapabilities, NULL); @@ -1287,20 +1299,25 @@ static void *grpc_pthread_start(void *arg) server_address.str().c_str()); /* Process inbound RPCs */ - while (true) { - void *tag; - bool ok; - - s_cq->Next(&tag, &ok); - if (!ok) + bool ok; + void *tag; + while (grpc_running) { + if (!cq->Next(&tag, &ok)) { + grpc_debug("%s: CQ empty exiting", __func__); break; + } - grpc_debug("%s: Got next from CompletionQueue, %p %d", __func__, - tag, ok); + grpc_debug("%s: got next from CQ tag: %p ok: %d", __func__, tag, + ok); + + if (!ok || !grpc_running) { + delete static_cast<RpcStateBase *>(tag); + break; + } RpcStateBase *rpc = static_cast<RpcStateBase *>(tag); CallState state = rpc->doCallback(); - grpc_debug("%s: Callback returned RPC State: %s", __func__, + grpc_debug("%s: callback returned RPC State: %s", __func__, call_states[state]); /* @@ -1310,10 +1327,30 @@ static void *grpc_pthread_start(void *arg) * to be called back once more in the FINISH state (from the * user indicating Finish() for cleanup. */ - if (state == FINISH) - rpc->do_request(service, s_cq); + if (state == FINISH && grpc_running) + rpc->do_request(&service, cq.get(), false); + } + + /* This was probably done for us to get here, but let's be safe */ + pthread_mutex_lock(&s_server_lock); + grpc_running = false; + if (s_server) { + grpc_debug("%s: shutdown server and CQ", __func__); + server->Shutdown(); + s_server = NULL; + } + pthread_mutex_unlock(&s_server_lock); + + grpc_debug("%s: shutting down CQ", __func__); + cq->Shutdown(); + + grpc_debug("%s: draining the CQ", __func__); + while (cq->Next(&tag, &ok)) { + grpc_debug("%s: drain tag %p", __func__, tag); + delete static_cast<RpcStateBase *>(tag); } + zlog_info("%s: exiting from grpc pthread", __func__); return NULL; } @@ -1325,6 +1362,8 @@ static int frr_grpc_init(uint port) .stop = NULL, }; + grpc_debug("%s: entered", __func__); + fpt = frr_pthread_new(&attr, "frr-grpc", "frr-grpc"); fpt->data = reinterpret_cast<void *>((intptr_t)port); @@ -1340,24 +1379,27 @@ static int frr_grpc_init(uint port) static int frr_grpc_finish(void) { - // Shutdown the grpc server - if (s_server) { - s_server->Shutdown(); - s_cq->Shutdown(); - - // And drain the queue - void *ignore; - bool ok; + grpc_debug("%s: entered", __func__); - while (s_cq->Next(&ignore, &ok)) - ; - } + if (!fpt) + return 0; - if (fpt) { - pthread_join(fpt->thread, NULL); - frr_pthread_destroy(fpt); + /* + * Shut the server down here in main thread. This will cause the wait on + * the completion queue (cq.Next()) to exit and cleanup everything else. + */ + pthread_mutex_lock(&s_server_lock); + grpc_running = false; + if (s_server) { + grpc_debug("%s: shutdown server", __func__); + s_server->Shutdown(); + s_server = NULL; } + pthread_mutex_unlock(&s_server_lock); + grpc_debug("%s: joining and destroy grpc thread", __func__); + pthread_join(fpt->thread, NULL); + frr_pthread_destroy(fpt); return 0; } diff --git a/lib/routemap.c b/lib/routemap.c index 7f733c8114..9afe18d10b 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1799,12 +1799,11 @@ static struct list *route_map_get_index_list(struct route_node **rn, /* * This function returns the route-map index that best matches the prefix. */ -static struct route_map_index *route_map_get_index(struct route_map *map, - const struct prefix *prefix, - void *object, - uint8_t *match_ret) +static struct route_map_index * +route_map_get_index(struct route_map *map, const struct prefix *prefix, + void *object, enum route_map_cmd_result_t *match_ret) { - int ret = 0; + enum route_map_cmd_result_t ret = RMAP_NOMATCH; struct list *candidate_rmap_list = NULL; struct route_node *rn = NULL; struct listnode *ln = NULL, *nn = NULL; @@ -2559,7 +2558,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, if ((!map->optimization_disabled) && (map->ipv4_prefix_table || map->ipv6_prefix_table)) { index = route_map_get_index(map, prefix, match_object, - (uint8_t *)&match_ret); + &match_ret); if (index) { index->applied++; if (rmap_debug) @@ -65,7 +65,7 @@ DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history"); DECLARE_DLIST(vtys, struct vty, itm); /* Vty events */ -enum event { +enum vty_event { VTY_SERV, VTY_READ, VTY_WRITE, @@ -90,8 +90,8 @@ struct vty_serv { DECLARE_DLIST(vtyservs, struct vty_serv, itm); -static void vty_event_serv(enum event event, struct vty_serv *); -static void vty_event(enum event, struct vty *); +static void vty_event_serv(enum vty_event event, struct vty_serv *); +static void vty_event(enum vty_event, struct vty *); /* Extern host structure from command.c */ extern struct host host; @@ -2683,7 +2683,7 @@ int vty_config_node_exit(struct vty *vty) /* Master of the threads. */ static struct thread_master *vty_master; -static void vty_event_serv(enum event event, struct vty_serv *vty_serv) +static void vty_event_serv(enum vty_event event, struct vty_serv *vty_serv) { switch (event) { case VTY_SERV: @@ -2701,7 +2701,7 @@ static void vty_event_serv(enum event event, struct vty_serv *vty_serv) } } -static void vty_event(enum event event, struct vty *vty) +static void vty_event(enum vty_event event, struct vty *vty) { switch (event) { #ifdef VTYSH diff --git a/lib/zclient.c b/lib/zclient.c index cfccb21667..930adf6a7a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -47,10 +47,10 @@ DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); /* Zebra client events. */ -enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; +enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; /* Prototype for event manager. */ -static void zclient_event(enum event, struct zclient *); +static void zclient_event(enum zclient_event, struct zclient *); static void zebra_interface_if_set_value(struct stream *s, struct interface *ifp); @@ -4038,7 +4038,7 @@ void zclient_redistribute_default(int command, struct zclient *zclient, zebra_redistribute_default_send(command, zclient, afi, vrf_id); } -static void zclient_event(enum event event, struct zclient *zclient) +static void zclient_event(enum zclient_event event, struct zclient *zclient) { switch (event) { case ZCLIENT_SCHEDULE: diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 93e3b9a8e2..a624f4ce1e 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -278,7 +278,7 @@ struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async) return new; } -void ospf_apiserver_event(enum event event, int fd, +void ospf_apiserver_event(enum ospf_apiserver_event event, int fd, struct ospf_apiserver *apiserv) { switch (event) { @@ -367,7 +367,7 @@ void ospf_apiserver_read(struct thread *thread) struct ospf_apiserver *apiserv; struct msg *msg; int fd; - enum event event; + enum ospf_apiserver_event event; apiserv = THREAD_ARG(thread); fd = THREAD_FD(thread); @@ -710,7 +710,7 @@ static int ospf_apiserver_send_msg(struct ospf_apiserver *apiserv, { struct msg_fifo *fifo; struct msg *msg2; - enum event event; + enum ospf_apiserver_event event; int fd; switch (msg->hdr.msgtype) { diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 3994c8d503..3d57737080 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -68,7 +68,7 @@ struct ospf_apiserver { struct thread *t_async_write; }; -enum event { +enum ospf_apiserver_event { OSPF_APISERVER_ACCEPT, OSPF_APISERVER_SYNC_READ, #ifdef USE_ASYNC_READ @@ -88,7 +88,7 @@ extern int ospf_apiserver_init(void); extern void ospf_apiserver_term(void); extern struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async); extern void ospf_apiserver_free(struct ospf_apiserver *apiserv); -extern void ospf_apiserver_event(enum event event, int fd, +extern void ospf_apiserver_event(enum ospf_apiserver_event event, int fd, struct ospf_apiserver *apiserv); extern int ospf_apiserver_serv_sock_family(unsigned short port, int family); extern void ospf_apiserver_accept(struct thread *thread); diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 06790d3d63..e3130b1564 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -210,6 +210,244 @@ DEFPY (no_ipv6_pim_register_suppress, return pim_process_no_register_suppress_cmd(vty); } +DEFPY (interface_ipv6_pim, + interface_ipv6_pim_cmd, + "ipv6 pim", + IPV6_STR + PIM_STR) +{ + return pim_process_ip_pim_cmd(vty); +} + +DEFPY (interface_no_ipv6_pim, + interface_no_ipv6_pim_cmd, + "no ipv6 pim", + NO_STR + IPV6_STR + PIM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +DEFPY (interface_ipv6_pim_drprio, + interface_ipv6_pim_drprio_cmd, + "ipv6 pim drpriority (1-4294967295)", + IPV6_STR + PIM_STR + "Set the Designated Router Election Priority\n" + "Value of the new DR Priority\n") +{ + return pim_process_ip_pim_drprio_cmd(vty, drpriority_str); +} + +DEFPY (interface_no_ipv6_pim_drprio, + interface_no_ipv6_pim_drprio_cmd, + "no ip pim drpriority [(1-4294967295)]", + NO_STR + IPV6_STR + PIM_STR + "Revert the Designated Router Priority to default\n" + "Old Value of the Priority\n") +{ + return pim_process_no_ip_pim_drprio_cmd(vty); +} + +DEFPY (interface_ipv6_pim_hello, + interface_ipv6_pim_hello_cmd, + "ipv6 pim hello (1-65535) [(1-65535)]$hold", + IPV6_STR + PIM_STR + IFACE_PIM_HELLO_STR + IFACE_PIM_HELLO_TIME_STR + IFACE_PIM_HELLO_HOLD_STR) +{ + return pim_process_ip_pim_hello_cmd(vty, hello_str, hold_str); +} + +DEFPY (interface_no_ipv6_pim_hello, + interface_no_ipv6_pim_hello_cmd, + "no ipv6 pim hello [(1-65535) [(1-65535)]]", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_HELLO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR) +{ + return pim_process_no_ip_pim_hello_cmd(vty); +} + +DEFPY (interface_ipv6_pim_activeactive, + interface_ipv6_pim_activeactive_cmd, + "[no] ipv6 pim active-active", + NO_STR + IPV6_STR + PIM_STR + "Mark interface as Active-Active for MLAG operations\n") +{ + return pim_process_ip_pim_activeactive_cmd(vty, no); +} + +DEFPY_HIDDEN (interface_ipv6_pim_ssm, + interface_ipv6_pim_ssm_cmd, + "ipv6 pim ssm", + IPV6_STR + PIM_STR + IFACE_PIM_STR) +{ + int ret; + + ret = pim_process_ip_pim_cmd(vty); + + if (ret != NB_OK) + return ret; + + vty_out(vty, + "Enabled PIM SM on interface; configure PIM SSM range if needed\n"); + + return NB_OK; +} + +DEFPY_HIDDEN (interface_no_ipv6_pim_ssm, + interface_no_ipv6_pim_ssm_cmd, + "no ipv6 pim ssm", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +DEFPY_HIDDEN (interface_ipv6_pim_sm, + interface_ipv6_pim_sm_cmd, + "ipv6 pim sm", + IPV6_STR + PIM_STR + IFACE_PIM_SM_STR) +{ + return pim_process_ip_pim_cmd(vty); +} + +DEFPY_HIDDEN (interface_no_ipv6_pim_sm, + interface_no_ipv6_pim_sm_cmd, + "no ipv6 pim sm", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_SM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +/* boundaries */ +DEFPY (interface_ipv6_pim_boundary_oil, + interface_ipv6_pim_boundary_oil_cmd, + "ipv6 multicast boundary oil WORD", + IPV6_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Filter OIL by group using prefix list\n" + "Prefix list to filter OIL with\n") +{ + return pim_process_ip_pim_boundary_oil_cmd(vty, oil); +} + +DEFPY (interface_no_ipv6_pim_boundary_oil, + interface_no_ipv6_pim_boundary_oil_cmd, + "no ipv6 multicast boundary oil [WORD]", + NO_STR + IPV6_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Filter OIL by group using prefix list\n" + "Prefix list to filter OIL with\n") +{ + return pim_process_no_ip_pim_boundary_oil_cmd(vty); +} + +DEFPY (interface_ipv6_mroute, + interface_ipv6_mroute_cmd, + "ipv6 mroute INTERFACE X:X::X:X$group [X:X::X:X]$source", + IPV6_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group address\n" + "Source address\n") +{ + return pim_process_ip_mroute_cmd(vty, interface, group_str, source_str); +} + +DEFPY (interface_no_ipv6_mroute, + interface_no_ipv6_mroute_cmd, + "no ipv6 mroute INTERFACE X:X::X:X$group [X:X::X:X]$source", + NO_STR + IPV6_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group Address\n" + "Source Address\n") +{ + return pim_process_no_ip_mroute_cmd(vty, interface, group_str, + source_str); +} + +DEFPY (ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +{ + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + + return pim_process_rp_cmd(vty, rp_str, group_str); +} + +DEFPY (no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +{ + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + + return pim_process_no_rp_cmd(vty, rp_str, group_str); +} + +DEFPY (ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n") +{ + return pim_process_rp_plist_cmd(vty, rp_str, plist); +} + +DEFPY (no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n") +{ + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); +} + void pim_cmd_init(void) { if_cmd_init(pim_interface_config_write); @@ -228,4 +466,29 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_drprio_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_hello_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_hello_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_activeactive_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); + install_element(INTERFACE_NODE, + &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, + &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); } diff --git a/pimd/pim6_cmd.h b/pimd/pim6_cmd.h index e49045a1b5..ac5eb3f9bf 100644 --- a/pimd/pim6_cmd.h +++ b/pimd/pim6_cmd.h @@ -33,6 +33,11 @@ #define IFACE_MLD_LAST_MEMBER_QUERY_INTERVAL_STR \ "MLD last member query interval\n" #define IFACE_MLD_LAST_MEMBER_QUERY_COUNT_STR "MLD last member query count\n" +#define IFACE_PIM_STR "Enable PIM SSM operation\n" +#define IFACE_PIM_SM_STR "Enable PIM SM operation\n" +#define IFACE_PIM_HELLO_STR "Hello Interval\n" +#define IFACE_PIM_HELLO_TIME_STR "Time in seconds for Hello Interval\n" +#define IFACE_PIM_HELLO_HOLD_STR "Time in seconds for Hold Interval\n" #define MROUTE_STR "IP multicast routing table\n" #define DEBUG_MLD_STR "MLD protocol activity\n" #define DEBUG_MLD_EVENTS_STR "MLD protocol events\n" diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index c9e3463969..8c7fca174c 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -185,19 +185,16 @@ int main(int argc, char **argv, char **envp) */ pim_iface_init(); - /* TODO PIM6: next line is temporary since pim_cmd_init is disabled */ - if_cmd_init(NULL); - pim_zebra_init(); #if 0 pim_bfd_init(); pim_mlag_init(); +#endif hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); routing_control_plane_protocols_register_vrf_dependency(); -#endif frr_config_fork(); frr_run(router->master); diff --git a/pimd/pim6_stubs.c b/pimd/pim6_stubs.c index 9f68b7be3d..e689c7aca4 100644 --- a/pimd/pim6_stubs.c +++ b/pimd/pim6_stubs.c @@ -29,40 +29,6 @@ /* * NH lookup / NHT */ -void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, - struct pim_nexthop_cache *pnc, int command) -{ -} - -int pim_ecmp_nexthop_lookup(struct pim_instance *pim, - struct pim_nexthop *nexthop, struct prefix *src, - struct prefix *grp, int neighbor_needed) -{ - return 0; -} - -int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, - struct pim_upstream *up, struct rp_info *rp, - struct pim_nexthop_cache *out_pnc) -{ - return 0; -} - -void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, - struct pim_upstream *up, struct rp_info *rp) -{ -} - -struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim, - struct pim_rpf *rpf) -{ - return NULL; -} - -void pim_rp_nexthop_del(struct rp_info *rp_info) -{ -} - void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) { } @@ -133,3 +99,25 @@ void pim_reg_del_on_couldreg_fail(struct interface *ifp) { } +bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) +{ + return false; +} + +void pim_bsm_proc_free(struct pim_instance *pim) +{ +} + +void pim_bsm_proc_init(struct pim_instance *pim) +{ +} + +struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope, + struct prefix *grp) +{ + return NULL; +} + +void pim_bsm_write_config(struct vty *vty, struct interface *ifp) +{ +} diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index a278a46593..e422a2e2da 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -33,7 +33,6 @@ typedef struct in_addr pim_addr; #define PIM_AFI AFI_IP #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" -#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv4" union pimprefixptr { prefixtype(pimprefixptr, struct prefix, p) @@ -53,7 +52,6 @@ typedef struct in6_addr pim_addr; #define PIM_AFI AFI_IP6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" -#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6" union pimprefixptr { prefixtype(pimprefixptr, struct prefix, p) diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 4d1e700ab0..d2e299a007 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -36,6 +36,7 @@ #include "pim_bsm.h" #include "pim_time.h" #include "pim_zebra.h" +#include "pim_util.h" /* Functions forward declaration */ static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout); @@ -284,7 +285,7 @@ static void pim_on_g2rp_timer(struct thread *t) struct rp_info *rp_info; struct route_node *rn; uint16_t elapse; - struct in_addr bsrp_addr; + pim_addr bsrp_addr; bsrp = THREAD_ARG(t); THREAD_OFF(bsrp->g2rp_timer); @@ -324,10 +325,9 @@ static void pim_on_g2rp_timer(struct thread *t) if (rp_info->rp_src != RP_SRC_STATIC) { /* If new rp available, change it else delete the existing */ if (bsrp) { - bsrp_addr = bsrp->rp_address; pim_g2rp_timer_start( bsrp, (bsrp->rp_holdtime - bsrp->elapse_time)); - pim_rp_change(pim, bsrp_addr, bsgrp_node->group, + pim_rp_change(pim, bsrp->rp_address, bsgrp_node->group, RP_SRC_BSR); } else { pim_rp_del(pim, bsrp_addr, bsgrp_node->group, NULL, @@ -417,7 +417,7 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list); - if (!str2prefix("224.0.0.0/4", &group_all)) + if (!pim_get_all_mcast_group(&group_all)) return; rp_all = pim_rp_find_match_group(pim, &group_all); @@ -430,8 +430,8 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) * install the rp from head(if exists) of partial list. List is * is sorted such that head is the elected RP for the group. */ - if (!rn || (prefix_same(&rp_all->group, &bsgrp_node->group) - && pim_rpf_addr_is_inaddr_none(&rp_all->rp))) { + if (!rn || (prefix_same(&rp_all->group, &bsgrp_node->group) && + pim_rpf_addr_is_inaddr_any(&rp_all->rp))) { if (PIM_DEBUG_BSM) zlog_debug("%s: Route node doesn't exist", __func__); if (pend) @@ -628,14 +628,13 @@ void pim_bsm_clear(struct pim_instance *pim) pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); - if (!str2prefix("224.0.0.0/4", &g_all)) + if (!pim_get_all_mcast_group(&g_all)) return; rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { - rp_all->rp.rpf_addr.family = AF_INET; - rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY); rp_all->i_am_rp = 0; } else { /* Delete the rp_info from rp-list */ @@ -668,7 +667,7 @@ void pim_bsm_clear(struct pim_instance *pim) trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ - if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) { pim_upstream_rpf_clear(pim, up); pim_rp_set_upstream_addr(pim, &up->upstream_addr, up->sg.src, up->sg.grp); diff --git a/pimd/pim_bsm.h b/pimd/pim_bsm.h index a536b50688..fceabef9e6 100644 --- a/pimd/pim_bsm.h +++ b/pimd/pim_bsm.h @@ -115,7 +115,7 @@ struct bsm_rpinfo { uint32_t elapse_time; /* upd at expiry of elected RP node */ uint16_t rp_prio; /* RP priority */ uint16_t rp_holdtime; /* RP holdtime - g2rp timer value */ - struct in_addr rp_address; /* RP Address */ + pim_addr rp_address; /* RP Address */ struct bsgrp_node *bsgrp_node; /* Back ptr to bsgrp_node */ struct thread *g2rp_timer; /* Run only for elected RP node */ }; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 76f90cdba7..3b3d06e791 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6997,98 +6997,36 @@ DEFUN (no_ip_pim_v6_secondary, return nb_cli_apply_changes(vty, NULL); } -DEFUN (ip_pim_rp, +DEFPY (ip_pim_rp, ip_pim_rp_cmd, - "ip pim rp A.B.C.D [A.B.C.D/M]", + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", IP_STR "pim multicast routing\n" "Rendevous Point\n" "ip address of RP\n" "Group Address range to cover\n") { - const char *vrfname; - int idx_rp = 3, idx_group = 4; - char rp_group_xpath[XPATH_MAXLEN]; - int result = 0; - struct prefix group; - struct in_addr rp_addr; - const char *group_str = - (argc == 5) ? argv[idx_group]->arg : "224.0.0.0/4"; - - result = str2prefix(group_str, &group); - if (result) { - struct prefix temp; - - prefix_copy(&temp, &group); - apply_mask(&temp); - if (!prefix_same(&group, &temp)) { - vty_out(vty, "%% Inconsistent address and mask: %s\n", - group_str); - return CMD_WARNING_CONFIG_FAILED; - } - } - - if (!result) { - vty_out(vty, "%% Bad group address specified: %s\n", - group_str); - return CMD_WARNING_CONFIG_FAILED; - } - - result = inet_pton(AF_INET, argv[idx_rp]->arg, &rp_addr); - if (result <= 0) { - vty_out(vty, "%% Bad RP address specified: %s\n", - argv[idx_rp]->arg); - return CMD_WARNING_CONFIG_FAILED; - } + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_group_xpath, sizeof(rp_group_xpath), - FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); - - nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_rp_cmd(vty, rp_str, group_str); } -DEFUN (ip_pim_rp_prefix_list, +DEFPY (ip_pim_rp_prefix_list, ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D prefix-list WORD", + "ip pim rp A.B.C.D$rp prefix-list WORD$plist", IP_STR "pim multicast routing\n" - "Rendevous Point\n" + "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" "Name of a prefix-list\n") { - int idx_rp = 3, idx_plist = 5; - const char *vrfname; - char rp_plist_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); - - nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, - argv[idx_plist]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_rp_plist_cmd(vty, rp_str, plist); } -DEFUN (no_ip_pim_rp, +DEFPY (no_ip_pim_rp, no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D [A.B.C.D/M]", + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR IP_STR "pim multicast routing\n" @@ -7096,106 +7034,23 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - int idx_rp = 4, idx_group = 5; - const char *group_str = - (argc == 6) ? argv[idx_group]->arg : "224.0.0.0/4"; - char group_list_xpath[XPATH_MAXLEN]; - char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; - int printed; - const char *vrfname; - const struct lyd_node *group_dnode; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - - - printed = snprintf(group_list_xpath, sizeof(group_list_xpath), - "%s/group-list", rp_xpath); - - if (printed >= (int)(sizeof(group_list_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']", - group_list_xpath, group_str); - - if (printed >= (int)(sizeof(group_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath); + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; - if (yang_is_last_list_dnode(group_dnode)) - nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); - else - nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY, - group_str); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_rp_cmd(vty, rp_str, group_str); } -DEFUN (no_ip_pim_rp_prefix_list, +DEFPY (no_ip_pim_rp_prefix_list, no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D prefix-list WORD", + "no ip pim rp A.B.C.D$rp prefix-list WORD$plist", NO_STR IP_STR "pim multicast routing\n" - "Rendevous Point\n" + "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" "Name of a prefix-list\n") { - int idx_rp = 4; - int idx_plist = 6; - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; - const struct lyd_node *plist_dnode; - const char *plist; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); - - plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); - if (!plist_dnode) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - plist = yang_dnode_get_string(plist_dnode, plist_xpath); - if (strcmp(argv[idx_plist]->arg, plist)) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } DEFUN (ip_pim_ssm_prefix_list, @@ -7959,11 +7814,7 @@ DEFUN (interface_ip_pim_drprio, { int idx_number = 3; - nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, - argv[idx_number]->arg); - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_drprio_cmd(vty, argv[idx_number]->arg); } DEFUN (interface_no_ip_pim_drprio, @@ -7975,10 +7826,7 @@ DEFUN (interface_no_ip_pim_drprio, "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") { - nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_drprio_cmd(vty); } DEFPY_HIDDEN (interface_ip_igmp_query_generate, @@ -8069,20 +7917,7 @@ DEFPY (interface_ip_pim_activeactive, PIM_STR "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n") { - if (no) - nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, - "false"); - else { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - - nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, - "true"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_activeactive_cmd(vty, no); } DEFUN_HIDDEN (interface_ip_pim_ssm, @@ -8094,11 +7929,7 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, { int ret; - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - ret = nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + ret = pim_process_ip_pim_cmd(vty); if (ret != NB_OK) return ret; @@ -8116,11 +7947,7 @@ DEFUN_HIDDEN (interface_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_cmd(vty); } DEFUN (interface_ip_pim, @@ -8129,12 +7956,7 @@ DEFUN (interface_ip_pim, IP_STR PIM_STR) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); - + return pim_process_ip_pim_cmd(vty); } DEFUN_HIDDEN (interface_no_ip_pim_ssm, @@ -8145,39 +7967,7 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, - VTY_CURR_XPATH, - "frr-routing:ipv4"); - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } DEFUN_HIDDEN (interface_no_ip_pim_sm, @@ -8188,41 +7978,7 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } DEFUN (interface_no_ip_pim, @@ -8232,41 +7988,7 @@ DEFUN (interface_no_ip_pim, IP_STR PIM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } /* boundaries */ @@ -8279,13 +8001,7 @@ DEFUN(interface_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY, - argv[4]->arg); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); - + return pim_process_ip_pim_boundary_oil_cmd(vty, argv[4]->arg); } DEFUN(interface_no_ip_pim_boundary_oil, @@ -8298,12 +8014,7 @@ DEFUN(interface_no_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY, - NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_boundary_oil_cmd(vty); } DEFUN (interface_ip_mroute, @@ -8324,13 +8035,8 @@ DEFUN (interface_ip_mroute, else source_str = argv[idx_ipv4 + 1]->arg; - nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, - argv[idx_interface]->arg); - - return nb_cli_apply_changes(vty, - FRR_PIM_MROUTE_XPATH, - "frr-routing:ipv4", source_str, - argv[idx_ipv4]->arg); + return pim_process_ip_mroute_cmd(vty, argv[idx_interface]->arg, + argv[idx_ipv4]->arg, source_str); } DEFUN (interface_no_ip_mroute, @@ -8343,6 +8049,7 @@ DEFUN (interface_no_ip_mroute, "Group Address\n" "Source Address\n") { + int idx_interface = 3; int idx_ipv4 = 4; const char *source_str; @@ -8351,12 +8058,8 @@ DEFUN (interface_no_ip_mroute, else source_str = argv[idx_ipv4 + 1]->arg; - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_MROUTE_XPATH, - "frr-routing:ipv4", source_str, - argv[idx_ipv4]->arg); + return pim_process_no_ip_mroute_cmd(vty, argv[idx_interface]->arg, + argv[idx_ipv4]->arg, source_str); } DEFUN (interface_ip_pim_hello, @@ -8370,31 +8073,14 @@ DEFUN (interface_ip_pim_hello, { int idx_time = 3; int idx_hold = 4; - const struct lyd_node *igmp_enable_dnode; - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - } - - nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, - argv[idx_time]->arg); if (argc == idx_hold + 1) - nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, - argv[idx_hold]->arg); + return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg, + argv[idx_hold]->arg); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + else + return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg, + NULL); } DEFUN (interface_no_ip_pim_hello, @@ -8407,12 +8093,7 @@ DEFUN (interface_no_ip_pim_hello, IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { - nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_hello_cmd(vty); } DEFUN (debug_igmp, diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 6adea54a61..442760fdfe 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -30,6 +30,7 @@ #include "nexthop.h" #include "vrf.h" #include "ferr.h" +#include "lib/srcdest_table.h" #include "pimd.h" #include "pim_vty.h" @@ -326,3 +327,330 @@ int pim_process_no_register_suppress_cmd(struct vty *vty) return nb_cli_apply_changes(vty, NULL); } + +int pim_process_ip_pim_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_cmd(struct vty *vty) +{ + const struct lyd_node *mld_enable_dnode; + char mld_if_xpath[XPATH_MAXLEN]; + + int printed = + snprintf(mld_if_xpath, sizeof(mld_if_xpath), + "%s/frr-gmp:gmp/address-family[address-family='%s']", + VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL); + + if (printed >= (int)(sizeof(mld_if_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + FRR_PIM_AF_XPATH_VAL); + + if (!mld_enable_dnode) { + nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(mld_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str) +{ + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, + drpriority_str); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_drprio_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str, + const char *hold_str) +{ + const struct lyd_node *mld_enable_dnode; + + mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + FRR_PIM_AF_XPATH_VAL); + + if (!mld_enable_dnode) { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(mld_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } + + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str); + + if (hold_str) + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, + hold_str); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_hello_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no) +{ + if (no) + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "false"); + else { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "true"); + } + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil) +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY, + oil); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str) +{ + nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, interface); + + if (!source_str) { + char buf[SRCDEST2STR_BUFFER]; + + inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf)); + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, buf, + group_str); + } + + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, source_str, + group_str); +} + +int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str) +{ + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + if (!source_str) { + char buf[SRCDEST2STR_BUFFER]; + + inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf)); + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, buf, + group_str); + } + + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, source_str, + group_str); +} + +int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str) +{ + const char *vrfname; + char rp_group_xpath[XPATH_MAXLEN]; + int result = 0; + struct prefix group; + pim_addr rp_addr; + + result = str2prefix(group_str, &group); + if (result) { + struct prefix temp; + + prefix_copy(&temp, &group); + apply_mask(&temp); + if (!prefix_same(&group, &temp)) { + vty_out(vty, "%% Inconsistent address and mask: %s\n", + group_str); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (!result) { + vty_out(vty, "%% Bad group address specified: %s\n", group_str); + return CMD_WARNING_CONFIG_FAILED; + } + + result = inet_pton(PIM_AF, rp_str, &rp_addr); + if (result <= 0) { + vty_out(vty, "%% Bad RP address specified: %s\n", rp_str); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_group_xpath, sizeof(rp_group_xpath), + FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); + + nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str) +{ + char group_list_xpath[XPATH_MAXLEN]; + char group_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN]; + int printed; + const char *vrfname; + const struct lyd_node *group_dnode; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + + printed = snprintf(group_list_xpath, sizeof(group_list_xpath), + "%s/group-list", rp_xpath); + + if (printed >= (int)(sizeof(group_list_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']", + group_list_xpath, group_str); + + if (printed >= (int)(sizeof(group_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath); + + if (yang_is_last_list_dnode(group_dnode)) + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY, + group_str); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list) +{ + const char *vrfname; + char rp_plist_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), + FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); + + nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list) +{ + char rp_xpath[XPATH_MAXLEN]; + char plist_xpath[XPATH_MAXLEN]; + const char *vrfname; + const struct lyd_node *plist_dnode; + const char *plist; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + + snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); + + plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); + if (!plist_dnode) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + plist = yang_dnode_get_string(plist_dnode, plist_xpath); + if (strcmp(prefix_list, plist)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index 49fc6bcbeb..b7e6b6ac80 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -35,5 +35,28 @@ int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat); int pim_process_no_rp_kat_cmd(struct vty *vty); int pim_process_register_suppress_cmd(struct vty *vty, const char *rst); int pim_process_no_register_suppress_cmd(struct vty *vty); +int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str); +int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str); +int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list); +int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list); + +int pim_process_ip_pim_cmd(struct vty *vty); +int pim_process_no_ip_pim_cmd(struct vty *vty); +int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str); +int pim_process_no_ip_pim_drprio_cmd(struct vty *vty); +int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str, + const char *hold_str); +int pim_process_no_ip_pim_hello_cmd(struct vty *vty); +int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no); +int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil); +int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty); +int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str); +int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *src_str); #endif /* PIM_CMD_COMMON_H */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 51a3ceee15..929beea26b 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -148,8 +148,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, } int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size) + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { pim_addr msg_upstream_addr; bool wrong_af = false; @@ -174,10 +173,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, addr_offset = pim_parse_addr_ucast(&msg_upstream_addr, buf, pastend - buf, &wrong_af); if (addr_offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifp->name); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %pPA on %s", + __func__, &src_addr, ifp->name); return -1; } buf += addr_offset; @@ -186,21 +183,17 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, Check upstream address family */ if (wrong_af) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: ignoring join/prune directed to unexpected addr family from %s on %s", - __func__, src_str, ifp->name); + "%s: ignoring join/prune directed to unexpected addr family from %pPA on %s", + __func__, &src_addr, ifp->name); return -2; } remain = pastend - buf; if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", - __func__, remain, 4, src_str, ifp->name); + "%s: short join/prune message buffer for group list: size=%d minimum=%d from %pPA on %s", + __func__, remain, 4, &src_addr, ifp->name); return -4; } @@ -211,14 +204,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, ++buf; ++buf; - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + if (PIM_DEBUG_PIM_J_P) zlog_debug( - "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %s on %s", + "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %pPA on %s", __func__, &msg_upstream_addr, msg_num_groups, - msg_holdtime, src_str, ifp->name); - } + msg_holdtime, &src_addr, ifp->name); /* Scan groups */ for (group = 0; group < msg_num_groups; ++group) { @@ -239,12 +229,9 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, remain = pastend - buf; if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); zlog_warn( - "%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", - __func__, remain, 4, src_str, ifp->name); + "%s: short join/prune buffer for source list: size=%d minimum=%d from %pPA on %s", + __func__, remain, 4, &src_addr, ifp->name); return -6; } @@ -253,16 +240,12 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, msg_num_pruned_sources = ntohs(*(const uint16_t *)buf); buf += 2; - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_J_P) zlog_debug( - "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %s on %s", + "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %pPA on %s", __func__, &msg_upstream_addr, &sg.grp, msg_num_joined_sources, msg_num_pruned_sources, - src_str, ifp->name); - } + &src_addr, ifp->name); /* boundary check */ filtered = pim_is_group_filtered(pim_ifp, &sg.grp); diff --git a/pimd/pim_join.h b/pimd/pim_join.h index 5d28f2ba3c..b359f2e5b7 100644 --- a/pimd/pim_join.h +++ b/pimd/pim_join.h @@ -27,8 +27,7 @@ #include "pim_neighbor.h" int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size); + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_joinprune_send(struct pim_rpf *nexthop, struct list *groups); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index af6f59824c..f381a764cc 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -163,7 +163,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, * the Interface type is SSM we don't need to * do anything here */ - if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) { + if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) { if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug( "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP", @@ -300,8 +300,8 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL; - if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp) - || (!(PIM_I_am_DR(pim_ifp)))) { + if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) || + (!(PIM_I_am_DR(pim_ifp)))) { if (PIM_DEBUG_MROUTE) { zlog_debug("%s: Failed Check send packet", __func__); } diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 72c96d7d73..273c7e8a61 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -198,6 +198,12 @@ int lib_interface_gmp_address_family_static_group_destroy( int routing_control_plane_protocols_name_validate( struct nb_cb_create_args *args); +#if PIM_IPV == 4 +#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv4" +#else +#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6" +#endif + #define FRR_PIM_VRF_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 27cac0c1a7..21f57e2d11 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -34,6 +34,7 @@ #include "pim_util.h" #include "log.h" #include "lib_errors.h" +#include "pim_util.h" #if PIM_IPV == 6 #define pim6_msdp_err(funcname, argtype) \ @@ -256,21 +257,17 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist, return ret; } -static int pim_rp_cmd_worker(struct pim_instance *pim, - struct in_addr rp_addr, - struct prefix group, const char *plist, - char *errmsg, size_t errmsg_len) +static int pim_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr, + struct prefix group, const char *plist, + char *errmsg, size_t errmsg_len) { - char rp_str[INET_ADDRSTRLEN]; int result; - inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); - result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC); if (result == PIM_RP_NO_PATH) { - snprintf(errmsg, errmsg_len, - "No Path to RP address specified: %s", rp_str); + snprintfrr(errmsg, errmsg_len, + "No Path to RP address specified: %pPA", &rp_addr); return NB_ERR_INCONSISTENCY; } @@ -295,16 +292,13 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, return NB_OK; } -static int pim_no_rp_cmd_worker(struct pim_instance *pim, - struct in_addr rp_addr, struct prefix group, - const char *plist, +static int pim_no_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr, + struct prefix group, const char *plist, char *errmsg, size_t errmsg_len) { - char rp_str[INET_ADDRSTRLEN]; char group_str[PREFIX2STR_BUFFER]; int result; - inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); prefix2str(&group, group_str, sizeof(group_str)); result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); @@ -316,8 +310,8 @@ static int pim_no_rp_cmd_worker(struct pim_instance *pim, } if (result == PIM_RP_BAD_ADDRESS) { - snprintf(errmsg, errmsg_len, - "Bad RP address specified: %s", rp_str); + snprintfrr(errmsg, errmsg_len, "Bad RP address specified: %pPA", + &rp_addr); return NB_ERR_INCONSISTENCY; } @@ -2340,7 +2334,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; int result = 0; @@ -2352,31 +2346,30 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "./rp-address"); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "./rp-address"); if (yang_dnode_get(args->dnode, "./group-list")) { - yang_dnode_get_ipv4p(&group, args->dnode, - "./group-list"); - apply_mask_ipv4((struct prefix_ipv4 *)&group); - result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, - group, NULL, args->errmsg, - args->errmsg_len); + yang_dnode_get_prefix(&group, args->dnode, + "./group-list"); + apply_mask(&group); + result = pim_no_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, + args->errmsg_len); } else if (yang_dnode_get(args->dnode, "./prefix-list")) { plist = yang_dnode_get_string(args->dnode, "./prefix-list"); - if (!str2prefix("224.0.0.0/4", &group)) { + if (!pim_get_all_mcast_group(&group)) { flog_err( EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, - group, plist, - args->errmsg, - args->errmsg_len); + result = pim_no_rp_cmd_worker(pim, rp_addr, group, + plist, args->errmsg, + args->errmsg_len); } if (result) @@ -2396,7 +2389,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; switch (args->event) { case NB_EV_VALIDATE: @@ -2406,12 +2399,11 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - yang_dnode_get_ipv4p(&group, args->dnode, NULL); - apply_mask_ipv4((struct prefix_ipv4 *)&group); - - return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - NULL, args->errmsg, args->errmsg_len); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + return pim_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2423,7 +2415,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; switch (args->event) { case NB_EV_VALIDATE: @@ -2433,13 +2425,12 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - yang_dnode_get_ipv4p(&group, args->dnode, NULL); - apply_mask_ipv4((struct prefix_ipv4 *)&group); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); - return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - NULL, args->errmsg, - args->errmsg_len); + return pim_no_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2454,7 +2445,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; switch (args->event) { @@ -2466,14 +2457,14 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; plist = yang_dnode_get_string(args->dnode, NULL); - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - if (!str2prefix("224.0.0.0/4", &group)) { + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + if (!pim_get_all_mcast_group(&group)) { flog_err(EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - plist, args->errmsg, args->errmsg_len); + return pim_rp_cmd_worker(pim, rp_addr, group, plist, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2485,7 +2476,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; switch (args->event) { @@ -2496,16 +2487,15 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); plist = yang_dnode_get_string(args->dnode, NULL); - if (!str2prefix("224.0.0.0/4", &group)) { + if (!pim_get_all_mcast_group(&group)) { flog_err(EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - plist, args->errmsg, - args->errmsg_len); + return pim_no_rp_cmd_worker(pim, rp_addr, group, plist, + args->errmsg, args->errmsg_len); break; } diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index ce5298e5b0..80d214b2f7 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -162,6 +162,7 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, return 0; } +#if PIM_IPV == 4 void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) { struct pim_nexthop_cache *pnc; @@ -175,6 +176,7 @@ void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) pnc->bsr_count++; } +#endif /* PIM_IPV == 4 */ static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) @@ -244,6 +246,7 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, pim_nht_drop_maybe(pim, pnc); } +#if PIM_IPV == 4 void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr) { struct pim_nexthop_cache *pnc = NULL; @@ -398,6 +401,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, } return false; } +#endif /* PIM_IPV == 4 */ void pim_rp_nexthop_del(struct rp_info *rp_info) { @@ -419,7 +423,7 @@ static void pim_update_rp_nh(struct pim_instance *pim, /*Traverse RP list and update each RP Nexthop info */ for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; // Compute PIM RPF using cached nexthop @@ -482,23 +486,13 @@ static int pim_update_upstream_nh(struct pim_instance *pim, uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp) { uint32_t hash_val; - uint32_t s = 0, g = 0; - if ((!src)) + if (!src) return 0; - switch (src->family) { - case AF_INET: { - s = src->u.prefix4.s_addr; - s = s == 0 ? 1 : s; - if (grp) - g = grp->u.prefix4.s_addr; - } break; - default: - break; - } - - hash_val = jhash_2words(g, s, 101); + hash_val = prefix_hash_key(src); + if (grp) + hash_val ^= prefix_hash_key(grp); return hash_val; } @@ -549,9 +543,9 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, break; } - if (curr_route_valid - && !pim_if_connected_to_source(nexthop->interface, - src->u.prefix4)) { + if (curr_route_valid && + !pim_if_connected_to_source(nexthop->interface, + src_addr)) { nbr = pim_neighbor_find_prefix( nexthop->interface, &nexthop->mrib_nexthop_addr); @@ -668,7 +662,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, nh_node->gate.ipv4; #else nexthop->mrib_nexthop_addr.u.prefix6 = - nh_node->gate->ipv6; + nh_node->gate.ipv6; #endif nexthop->mrib_metric_preference = pnc->distance; nexthop->mrib_route_metric = pnc->metric; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 0346a7067b..25eabe6743 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -48,6 +48,7 @@ #include "pim_oil.h" #include "pim_zebra.h" #include "pim_bsm.h" +#include "pim_util.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -113,7 +114,7 @@ void pim_rp_init(struct pim_instance *pim) rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - if (!str2prefix("224.0.0.0/4", &rp_info->group)) { + if (!pim_get_all_mcast_group(&rp_info->group)) { flog_err(EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); list_delete(&pim->rp_list); @@ -122,9 +123,7 @@ void pim_rp_init(struct pim_instance *pim) return; } rp_info->group.family = AF_INET; - rp_info->rp.rpf_addr.family = AF_INET; - rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_info->rp.rpf_addr, PIMADDR_ANY); listnode_add(pim->rp_list, rp_info); @@ -150,15 +149,17 @@ void pim_rp_free(struct pim_instance *pim) * Given an RP's prefix-list, return the RP's rp_info for that prefix-list */ static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim, - struct in_addr rp, - const char *plist) + pim_addr rp, const char *plist) { struct listnode *node; struct rp_info *rp_info; + struct prefix rp_prefix; + + pim_addr_to_prefix(&rp_prefix, rp); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr - && rp_info->plist && strcmp(rp_info->plist, plist) == 0) { + if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) && + rp_info->plist && strcmp(rp_info->plist, plist) == 0) { return rp_info; } } @@ -187,16 +188,17 @@ static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist) * Given an RP's address, return the RP's rp_info that is an exact match for * 'group' */ -static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, - struct in_addr rp, +static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, pim_addr rp, const struct prefix *group) { struct listnode *node; struct rp_info *rp_info; + struct prefix rp_prefix; + pim_addr_to_prefix(&rp_prefix, rp); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr - && prefix_same(&rp_info->group, group)) + if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) && + prefix_same(&rp_info->group, group)) return rp_info; } @@ -240,7 +242,7 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, bp = NULL; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->plist) { - plist = prefix_list_lookup(AFI_IP, rp_info->plist); + plist = prefix_list_lookup(PIM_AFI, rp_info->plist); if (prefix_list_apply_ext(plist, &entry, group, true) == PREFIX_DENY || !entry) @@ -414,12 +416,10 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) } -int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag) +int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag) { int result = 0; - char rp[INET_ADDRSTRLEN]; struct rp_info *rp_info; struct rp_info *rp_all; struct prefix group_all; @@ -431,26 +431,20 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; bool upstream_updated = false; - if (rp_addr.s_addr == INADDR_ANY || - rp_addr.s_addr == INADDR_NONE) + if (pim_addr_is_any(rp_addr)) return PIM_RP_BAD_ADDRESS; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - rp_info->rp.rpf_addr.family = AF_INET; - rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rp_info->rp.rpf_addr.u.prefix4 = rp_addr; + pim_addr_to_prefix(&rp_info->rp.rpf_addr, rp_addr); prefix_copy(&rp_info->group, &group); rp_info->rp_src = rp_src_flag; - inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp, sizeof(rp)); - if (plist) { /* * Return if the prefix-list is already configured for this RP */ - if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4, - plist)) { + if (pim_rp_find_prefix_list(pim, rp_addr, plist)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -468,14 +462,14 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, */ for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr - == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) { + if (prefix_same(&rp_info->rp.rpf_addr, + &tmp_rp_info->rp.rpf_addr)) { if (tmp_rp_info->plist) - pim_rp_del_config(pim, rp, NULL, + pim_rp_del_config(pim, rp_addr, NULL, tmp_rp_info->plist); else pim_rp_del_config( - pim, rp, + pim, rp_addr, prefix2str(&tmp_rp_info->group, buffer, BUFSIZ), NULL); @@ -485,7 +479,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist); } else { - if (!str2prefix("224.0.0.0/4", &group_all)) { + if (!pim_get_all_mcast_group(&group_all)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_GROUP_BAD_ADDRESS; } @@ -504,29 +498,25 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, */ for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { - if (tmp_rp_info->plist - && rp_info->rp.rpf_addr.u.prefix4.s_addr - == tmp_rp_info->rp.rpf_addr.u.prefix4 - .s_addr) { - pim_rp_del_config(pim, rp, NULL, + if (tmp_rp_info->plist && + prefix_same(&rp_info->rp.rpf_addr, + &tmp_rp_info->rp.rpf_addr)) { + pim_rp_del_config(pim, rp_addr, NULL, tmp_rp_info->plist); } } /* - * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE + * Take over the 224.0.0.0/4 group if the rp is INADDR_ANY */ - if (prefix_same(&rp_all->group, &rp_info->group) - && pim_rpf_addr_is_inaddr_none(&rp_all->rp)) { + if (prefix_same(&rp_all->group, &rp_info->group) && + pim_rpf_addr_is_inaddr_any(&rp_all->rp)) { rp_all->rp.rpf_addr = rp_info->rp.rpf_addr; rp_all->rp_src = rp_src_flag; XFREE(MTYPE_PIM_RP, rp_info); /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = - rp_all->rp.rpf_addr.u.prefix4; // RP address + nht_p = rp_all->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug( "%s: NHT Register rp_all addr %pFX grp %pFX ", @@ -568,8 +558,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, /* * Return if the group is already configured for this RP */ - tmp_rp_info = pim_rp_find_exact( - pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group); + tmp_rp_info = pim_rp_find_exact(pim, rp_addr, &rp_info->group); if (tmp_rp_info) { if ((tmp_rp_info->rp_src != rp_src_flag) && (rp_src_flag == RP_SRC_STATIC)) @@ -605,8 +594,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, } result = pim_rp_change( - pim, - rp_info->rp.rpf_addr.u.prefix4, + pim, rp_addr, tmp_rp_info->group, rp_src_flag); XFREE(MTYPE_PIM_RP, rp_info); @@ -647,9 +635,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); @@ -661,32 +647,30 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, return PIM_SUCCESS; } -int pim_rp_del_config(struct pim_instance *pim, const char *rp, - const char *group_range, const char *plist) +void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, + const char *group_range, const char *plist) { struct prefix group; - struct in_addr rp_addr; int result; if (group_range == NULL) - result = str2prefix("224.0.0.0/4", &group); + result = pim_get_all_mcast_group(&group); else result = str2prefix(group_range, &group); - if (!result) - return PIM_GROUP_BAD_ADDRESS; - - result = inet_pton(AF_INET, rp, &rp_addr); - if (result <= 0) - return PIM_RP_BAD_ADDRESS; + if (!result) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s: String to prefix failed for %pPAs group", + __func__, &rp_addr); + return; + } - result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); - return result; + pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); } -int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag) +int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag) { struct prefix g_all; struct rp_info *rp_info; @@ -698,12 +682,8 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; struct bsgrp_node *bsgrp = NULL; struct bsm_rpinfo *bsrp = NULL; - char rp_str[INET_ADDRSTRLEN]; bool upstream_updated = false; - if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str))) - snprintf(rp_str, sizeof(rp_str), "<rp?>"); - if (plist) rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist); else @@ -718,8 +698,8 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: Delete RP %s for the group %pFX", __func__, - rp_str, &group); + zlog_debug("%s: Delete RP %pPA for the group %pFX", __func__, + &rp_addr, &group); /* While static RP is getting deleted, we need to check if dynamic RP * present for the same group in BSM RP table, then install the dynamic @@ -731,19 +711,11 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, if (bsgrp) { bsrp = bsm_rpinfos_first(bsgrp->bsrp_list); if (bsrp) { - if (PIM_DEBUG_PIM_TRACE) { - char bsrp_str[INET_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET, bsrp, bsrp_str, - sizeof(bsrp_str))) - snprintf(bsrp_str, - sizeof(bsrp_str), - "<bsrp?>"); - + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: BSM RP %s found for the group %pFX", - __func__, bsrp_str, &group); - } + "%s: BSM RP %pPA found for the group %pFX", + __func__, &bsrp->rp_address, + &group); return pim_rp_change(pim, bsrp->rp_address, group, RP_SRC_BSR); } @@ -756,15 +728,13 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); - if (!str2prefix("224.0.0.0/4", &g_all)) + if (!pim_get_all_mcast_group(&g_all)) return PIM_RP_BAD_ADDRESS; rp_all = pim_rp_find_match_group(pim, &g_all); @@ -789,8 +759,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } } } - rp_all->rp.rpf_addr.family = AF_INET; - rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY); rp_all->i_am_rp = 0; return PIM_SUCCESS; } @@ -834,7 +803,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ - if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) { pim_upstream_rpf_clear(pim, up); pim_rp_set_upstream_addr( pim, &up->upstream_addr, up->sg.src, @@ -856,7 +825,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, return PIM_SUCCESS; } -int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, +int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, struct prefix group, enum rp_source rp_src_flag) { struct prefix nht_p; @@ -865,6 +834,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, struct rp_info *rp_info = NULL; struct pim_upstream *up; bool upstream_updated = false; + pim_addr old_rp_addr; rn = route_node_lookup(pim->rp_table, &group); if (!rn) { @@ -880,7 +850,8 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, return result; } - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == new_rp_addr.s_addr) { + old_rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) { if (rp_info->rp_src != rp_src_flag) { rp_info->rp_src = rp_src_flag; route_unlock_node(rn); @@ -888,12 +859,13 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, } } - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.family = PIM_AF; + nht_p.prefixlen = PIM_MAX_BITLEN; /* Deregister old RP addr with Zebra NHT */ - if (rp_info->rp.rpf_addr.u.prefix4.s_addr != INADDR_ANY) { - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + + if (!pim_addr_is_any(old_rp_addr)) { + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); @@ -903,7 +875,8 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, pim_rp_nexthop_del(rp_info); listnode_delete(pim->rp_list, rp_info); /* Update the new RP address*/ - rp_info->rp.rpf_addr.u.prefix4 = new_rp_addr; + + pim_addr_to_prefix(&rp_info->rp.rpf_addr, new_rp_addr); rp_info->rp_src = rp_src_flag; rp_info->i_am_rp = 0; @@ -928,7 +901,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, pim_zebra_update_all_interfaces(pim); /* Register new RP addr with Zebra NHT */ - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); @@ -956,7 +929,7 @@ void pim_rp_setup(struct pim_instance *pim) struct prefix nht_p; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; nht_p.family = AF_INET; @@ -987,7 +960,7 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) return; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; /* if i_am_rp is already set nothing to be done (adding new @@ -1029,7 +1002,7 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) return; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; old_i_am_rp = rp_info->i_am_rp; @@ -1058,7 +1031,6 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) } } -#if PIM_IPV == 4 /* * I_am_RP(G) is true if the group-to-RP mapping indicates that * this router is the RP for the group. @@ -1071,10 +1043,7 @@ int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group) struct rp_info *rp_info; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; - + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); if (rp_info) @@ -1093,9 +1062,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) struct rp_info *rp_info; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); @@ -1103,9 +1070,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) struct prefix nht_p; /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug( "%s: NHT Register RP addr %pFX grp %pFX with Zebra", @@ -1136,73 +1101,52 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, struct prefix g; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; + + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_none(&rp_info->rp)) - && (source.s_addr == INADDR_ANY))) { + if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && + (pim_addr_is_any(source)))) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); - up->s_addr = INADDR_ANY; + *up = PIMADDR_ANY; return 0; } - *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4 - : source; + if (pim_addr_is_any(source)) + *up = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + else + *up = source; return 1; } -#else -CPP_NOTICE("functions stubbed out for IPv6"); - -int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group) -{ - return 0; -} - -struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) -{ - return NULL; -} - -int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, - pim_addr source, pim_addr group) -{ - return 0; -} -#endif int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, const char *spaces) { struct listnode *node; struct rp_info *rp_info; - char rp_buffer[32]; int count = 0; + pim_addr rp_addr; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; if (rp_info->rp_src == RP_SRC_BSR) continue; + rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); if (rp_info->plist) - vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces, - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u.prefix4, - rp_buffer, 32), - rp_info->plist); + vty_out(vty, + "%s" PIM_AF_NAME + " pim rp %pPA prefix-list %s\n", + spaces, &rp_addr, rp_info->plist); else - vty_out(vty, "%sip pim rp %s %pFX\n", spaces, - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u.prefix4, - rp_buffer, 32), - &rp_info->group); + vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", + spaces, &rp_addr, &rp_info->group); count++; } @@ -1227,7 +1171,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) vty_out(vty, "RP address group/prefix-list OIF I am RP Source\n"); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { + if (!pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { char buf[48]; if (rp_info->rp_src == RP_SRC_STATIC) @@ -1345,7 +1289,7 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr) struct pim_nexthop_cache pnc; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; nht_p.family = AF_INET; diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index c223402ddd..29834f8e5e 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -47,15 +47,13 @@ void pim_rp_free(struct pim_instance *pim); void pim_rp_list_hash_clean(void *data); -int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag); -int pim_rp_del_config(struct pim_instance *pim, const char *rp, - const char *group, const char *plist); -int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag); -int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, +int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag); +void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, + const char *group, const char *plist); +int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag); +int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, struct prefix group, enum rp_source rp_src_flag); void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index c62a06f85c..cee542aa13 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -67,21 +67,19 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, * 255.255.255.255 address, since * it will never work */ - if (addr.s_addr == INADDR_NONE) + if (pim_addr_is_any(addr)) return false; #endif - if (!pim_addr_cmp(nexthop->last_lookup, addr) - && (nexthop->last_lookup_time > pim->last_route_change_time)) { - if (PIM_DEBUG_PIM_NHT) { - char nexthop_str[PREFIX_STRLEN]; - pim_addr_dump("<nexthop?>", &nexthop->mrib_nexthop_addr, - nexthop_str, sizeof(nexthop_str)); + if ((!pim_addr_cmp(nexthop->last_lookup, addr)) && + (nexthop->last_lookup_time > pim->last_route_change_time)) { + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: Using last lookup for %pPAs at %lld, %" PRId64" addr %s", + "%s: Using last lookup for %pPAs at %lld, %" PRId64 + " addr %pFX", __func__, &addr, nexthop->last_lookup_time, - pim->last_route_change_time, nexthop_str); - } + pim->last_route_change_time, + &nexthop->mrib_nexthop_addr); pim->nexthop_lookups_avoided++; return true; } else { @@ -140,18 +138,13 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, } if (found) { - if (PIM_DEBUG_ZEBRA) { - char nexthop_str[PREFIX_STRLEN]; - pim_addr_dump("<nexthop?>", - &nexthop_tab[i].nexthop_addr, nexthop_str, - sizeof(nexthop_str)); + if (PIM_DEBUG_ZEBRA) zlog_debug( - "%s %s: found nexthop %s for address %pPAs: interface %s ifindex=%d metric=%d pref=%d", - __FILE__, __func__, nexthop_str, &addr, - ifp->name, first_ifindex, - nexthop_tab[i].route_metric, + "%s %s: found nexthop %pFX for address %pPAs: interface %s ifindex=%d metric=%d pref=%d", + __FILE__, __func__, + &nexthop_tab[i].nexthop_addr, &addr, ifp->name, + first_ifindex, nexthop_tab[i].route_metric, nexthop_tab[i].protocol_distance); - } /* update nexthop data */ nexthop->interface = ifp; nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr; @@ -215,7 +208,6 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, bool neigh_needed = true; uint32_t saved_mrib_route_metric; pim_addr rpf_addr; - pim_addr saved_rpf_addr; if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) return PIM_RPF_OK; @@ -264,19 +256,14 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &saved.source_nexthop)) { - if (PIM_DEBUG_ZEBRA) { - char nhaddr_str[PREFIX_STRLEN]; - pim_addr_dump("<addr?>", - &rpf->source_nexthop.mrib_nexthop_addr, - nhaddr_str, sizeof(nhaddr_str)); - zlog_debug("%s(%s): (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d", + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s(%s): (S,G)=%s source nexthop now is: interface=%s address=%pFX pref=%d metric=%d", __func__, caller, up->sg_str, rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>", - nhaddr_str, + &rpf->source_nexthop.mrib_nexthop_addr, rpf->source_nexthop.mrib_metric_preference, rpf->source_nexthop.mrib_route_metric); - } pim_upstream_update_join_desired(pim, up); pim_upstream_update_could_assert(up); @@ -300,10 +287,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, } /* detect change in RPF'(S,G) */ - - saved_rpf_addr = pim_addr_from_prefix(&saved.rpf_addr); - - if (pim_addr_cmp(saved_rpf_addr, rpf_addr) || + if (!prefix_same(&saved.rpf_addr, &rpf->rpf_addr) || saved.source_nexthop.interface != rpf->source_nexthop.interface) { pim_rpf_cost_change(pim, up, saved_mrib_route_metric); return PIM_RPF_CHANGED; @@ -393,19 +377,6 @@ static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) return rpf_addr; } -int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf) -{ - switch (rpf->rpf_addr.family) { - case AF_INET: - return rpf->rpf_addr.u.prefix4.s_addr == INADDR_NONE; - case AF_INET6: - zlog_warn("%s: v6 Unimplmeneted", __func__); - return 1; - default: - return 0; - } -} - int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf) { pim_addr rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr); @@ -431,7 +402,7 @@ unsigned int pim_rpf_hash_key(const void *arg) { const struct pim_nexthop_cache *r = arg; -#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) +#if PIM_IPV == 4 return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0); #else return jhash2(r->rpf.rpf_addr.u.prefix6.s6_addr32, diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 662fd41a7f..74aca43d54 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -64,7 +64,6 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_rpf *old, const char *caller); void pim_upstream_rpf_clear(struct pim_instance *pim, struct pim_upstream *up); -int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf); int pim_rpf_is_same(struct pim_rpf *rpf1, struct pim_rpf *rpf2); diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 8232d7205b..4b67dbf1b1 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -152,3 +152,17 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); return pl ? prefix_list_apply(pl, &grp_pfx) == PREFIX_DENY : false; } + + +/* This function returns all multicast group */ +int pim_get_all_mcast_group(struct prefix *prefix) +{ +#if PIM_IPV == 4 + if (!str2prefix("224.0.0.0/4", prefix)) + return 0; +#else + if (!str2prefix("FF00::0/8", prefix)) + return 0; +#endif + return 1; +} diff --git a/pimd/pim_util.h b/pimd/pim_util.h index b9c227996e..a4362bef90 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -36,4 +36,5 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size); int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); +int pim_get_all_mcast_group(struct prefix *prefix); #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 0acd3c0694..3f418c0870 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -454,10 +454,11 @@ static void pim_zebra_capabilities(struct zclient_capabilities *cap) static zclient_handler *const pim_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del, + + [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, #if PIM_IPV == 4 [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, - [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc, [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc, diff --git a/pimd/subdir.am b/pimd/subdir.am index 0fe40912b1..d617be3cb7 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -21,7 +21,6 @@ pim_common = \ pimd/pim_assert.c \ pimd/pim_bfd.c \ pimd/pim_br.c \ - pimd/pim_bsm.c \ pimd/pim_cmd_common.c \ pimd/pim_errors.c \ pimd/pim_hello.c \ @@ -38,6 +37,7 @@ pim_common = \ pimd/pim_nb.c \ pimd/pim_nb_config.c \ pimd/pim_neighbor.c \ + pimd/pim_nht.c \ pimd/pim_oil.c \ pimd/pim_routemap.c \ pimd/pim_rp.c \ @@ -59,6 +59,7 @@ pim_common = \ pimd_pimd_SOURCES = \ $(pim_common) \ + pimd/pim_bsm.c \ pimd/pim_cmd.c \ pimd/pim_igmp.c \ pimd/pim_igmp_mtrace.c \ @@ -70,7 +71,6 @@ pimd_pimd_SOURCES = \ pimd/pim_msdp.c \ pimd/pim_msdp_packet.c \ pimd/pim_msdp_socket.c \ - pimd/pim_nht.c \ pimd/pim_pim.c \ pimd/pim_register.c \ pimd/pim_signals.c \ diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c index 97aade6578..8f0b92d0fc 100644 --- a/tests/isisd/test_fuzz_isis_tlv.c +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -108,12 +108,12 @@ static int test(FILE *input, FILE *output) } fprintf(output, "Unpack log:\n%s", log); - const char *s_tlvs = isis_format_tlvs(tlvs); + const char *s_tlvs = isis_format_tlvs(tlvs, NULL); fprintf(output, "Unpacked TLVs:\n%s", s_tlvs); struct isis_item *orig_auth = tlvs->isis_auth.head; tlvs->isis_auth.head = NULL; - s_tlvs = isis_format_tlvs(tlvs); + s_tlvs = isis_format_tlvs(tlvs, NULL); struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs); tlvs->isis_auth.head = orig_auth; isis_free_tlvs(tlvs); @@ -133,7 +133,7 @@ static int test(FILE *input, FILE *output) } char *orig_tlvs = XSTRDUP(MTYPE_TMP, s_tlvs); - s_tlvs = isis_format_tlvs(tlvs); + s_tlvs = isis_format_tlvs(tlvs, NULL); if (strcmp(orig_tlvs, s_tlvs)) { fprintf(output, @@ -166,7 +166,7 @@ static int test(FILE *input, FILE *output) fprintf(output, "Could not pack fragment, too large.\n"); assert(0); } - sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs)); + sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs, NULL)); isis_free_tlvs(tlvs); } list_delete(&fragments); diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index a30f33ccad..971aba4c46 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -294,7 +294,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, /* Print the LDPDB. */ if (CHECK_FLAG(flags, F_DISPLAY_LSPDB)) - show_isis_database_lspdb(vty, area, level - 1, + show_isis_database_lspdb_vty(vty, area, level - 1, &area->lspdb[level - 1], NULL, ISIS_UI_LEVEL_DETAIL); diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index 94c5faf2e0..014722387f 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -236,6 +236,94 @@ def test_isis_linux_route6_installation(): assert topotest.json_cmp(actual, expected) is None, assertmsg +def test_isis_summary_json(): + "Check json struct in show isis summary json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking 'show isis summary json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) + assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['vrf'] == "default", assertmsg + assert json_output['areas'][0]['area'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + +def test_isis_interface_json(): + "Check json struct in show isis interface json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking 'show isis interface json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True) + assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True) + assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + +def test_isis_neighbor_json(): + "Check json struct in show isis neighbor json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + #tgen.mininet_cli() + logger.info("Checking 'show isis neighbor json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True) + assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True) + assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + +def test_isis_database_json(): + "Check json struct in show isis database json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + #tgen.mininet_cli() + logger.info("Checking 'show isis database json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True) + assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['area']['name'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True) + assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['area']['name'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang index aeb52a6520..ffc671c99a 100644 --- a/yang/frr-route-types.yang +++ b/yang/frr-route-types.yang @@ -162,9 +162,7 @@ module frr-route-types { typedef ipv6-multicast-group-prefix { type inet:ipv6-prefix { pattern - '(((FF|ff)[0-9a-fA-F]{2}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/((1[6-9])|([2-9][0-9])|(1[0-1][0-9])|(12[0-8])))'; - pattern - '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(/.+)'; + '(([fF]{2}[0-9a-fA-F]{2}):).*'; } description "This type represents an IPv6 multicast group prefix, diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index db8ee3236c..a75b165270 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1876,6 +1876,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else { bool was_bridge_slave, was_bond_slave; uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; + zif = ifp->info; /* Interface update. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1909,9 +1910,21 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_to_zebra_link_type(ifi->ifi_type); netlink_interface_update_hw_addr(tb, ifp); + if (tb[IFLA_PROTO_DOWN]) { + uint8_t protodown; + + protodown = *(uint8_t *)RTA_DATA( + tb[IFLA_PROTO_DOWN]); + netlink_proc_dplane_if_protodown(zif, + !!protodown); + } + if (if_is_no_ptm_operative(ifp)) { + bool is_up = if_is_operative(ifp); ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!if_is_no_ptm_operative(ifp)) { + if (!if_is_no_ptm_operative(ifp) || + CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has gone DOWN", @@ -1927,7 +1940,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zlog_debug( "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); - zebra_interface_up_update(ifp); + if_up(ifp, !is_up); /* Update EVPN VNI when SVI MAC change */ @@ -1956,12 +1969,14 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_operative(ifp)) { + if (if_is_operative(ifp) && + !CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has come UP", name, ifp->ifindex); - if_up(ifp); + if_up(ifp, true); if (IS_ZEBRA_IF_BRIDGE(ifp)) chgflags = ZEBRA_BRIDGE_MASTER_UP; @@ -1990,15 +2005,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); - - if (tb[IFLA_PROTO_DOWN]) { - uint8_t protodown; - - protodown = *(uint8_t *)RTA_DATA( - tb[IFLA_PROTO_DOWN]); - netlink_proc_dplane_if_protodown(ifp->info, - !!protodown); - } } zif = ifp->info; diff --git a/zebra/interface.c b/zebra/interface.c index fbd2aac005..a76f8741e0 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -224,9 +224,13 @@ static int if_zebra_new_hook(struct interface *ifp) static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe) { zebra_nhg_check_valid(nhe); - if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) - /* Assuming uninstalled as well here */ - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { + /* If we're in shutdown, this interface event needs to clean + * up installed NHGs, so don't clear that flag directly. + */ + if (!zrouter.in_shutdown) + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } } static void if_down_nhg_dependents(const struct interface *ifp) @@ -517,7 +521,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags) /* inoperative -> operative? */ ifp->flags = newflags; if (if_is_operative(ifp)) - if_up(ifp); + if_up(ifp, true); } } @@ -1045,7 +1049,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) } /* Interface is up. */ -void if_up(struct interface *ifp) +void if_up(struct interface *ifp, bool install_connected) { struct zebra_if *zif; struct interface *link_if; @@ -1077,7 +1081,8 @@ void if_up(struct interface *ifp) #endif /* Install connected routes to the kernel. */ - if_install_connected(ifp); + if (install_connected) + if_install_connected(ifp); /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed @@ -2778,7 +2783,7 @@ int if_linkdetect(struct interface *ifp, bool detect) /* Interface may come up after disabling link detection */ if (if_is_operative(ifp) && !if_was_operative) - if_up(ifp); + if_up(ifp, true); } /* FIXME: Will defer status change forwarding if interface does not come down! */ diff --git a/zebra/interface.h b/zebra/interface.h index c19e494860..315a3170d8 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -486,7 +486,7 @@ extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(struct interface *ifp); extern void if_delete_update(struct interface *ifp); extern void if_add_update(struct interface *ifp); -extern void if_up(struct interface *); +extern void if_up(struct interface *ifp, bool install_connected); extern void if_down(struct interface *); extern void if_refresh(struct interface *); extern void if_flags_update(struct interface *, uint64_t); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 13b9cc2002..21fb5299bc 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -344,10 +344,10 @@ int zebra_evpn_add_macip_for_intf(struct interface *ifp, for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { struct ipaddr ip; - memset(&ip, 0, sizeof(struct ipaddr)); if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) continue; + memset(&ip, 0, sizeof(struct ipaddr)); if (c->address->family == AF_INET) { ip.ipa_type = IPADDR_V4; memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index e38766bc6b..74043e521c 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1141,14 +1141,6 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) sizeof(mac_buf))); } - /* If the MAC is freed before the neigh we will end up - * with a stale pointer against the neigh - */ - if (!list_isempty(mac->neigh_list)) - zlog_warn("%s: MAC %pEA flags 0x%x neigh list not empty %d", - __func__, &mac->macaddr, mac->flags, - listcount(mac->neigh_list)); - /* force de-ref any ES entry linked to the MAC */ zebra_evpn_es_mac_deref_entry(mac); @@ -1161,6 +1153,26 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) /* Cancel auto recovery */ THREAD_OFF(mac->dad_mac_auto_recovery_timer); + /* If the MAC is freed before the neigh we will end up + * with a stale pointer against the neigh. + * The situation can arise when a MAC is in remote state + * and its associated neigh is local state. + * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs. + * Instead of deleting remote MAC, if its neigh list is non-empty + * (associated to local neighs), mark the MAC as AUTO. + */ + if (!list_isempty(mac->neigh_list)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " + "count %u, mark MAC as AUTO", + &mac->macaddr, mac->flags, zevpn->vni, + listcount(mac->neigh_list)); + + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + return 0; + } + list_delete(&mac->neigh_list); /* Free the VNI hash entry and allocated memory. */ diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 81d610940d..739ba33036 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -136,7 +136,6 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf) ns_id_t ns_id = NS_UNKNOWN; int offset = NETLINK_ALIGN(sizeof(struct nlmsghdr)) + NETLINK_ALIGN(sizeof(struct rtgenmsg)); - int curr_length = offset; void *tail = (void *)((char *)nlh + NETLINK_ALIGN(nlh->nlmsg_len)); struct nlattr *attr; @@ -145,7 +144,6 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf) && attr->nla_len >= sizeof(struct nlattr) && attr->nla_len <= NETLINK_NLATTR_LEN(tail, attr); attr += NETLINK_ALIGN(attr->nla_len)) { - curr_length += attr->nla_len; if ((attr->nla_type & NLA_TYPE_MASK) == NETNSA_NSID) { uint32_t *ptr = (uint32_t *)(attr); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e1d28e1534..469a94a65b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1966,7 +1966,7 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, */ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, const struct prefix *top, int type, uint32_t flags, - uint32_t *pmtu) + uint32_t *pmtu, vrf_id_t vrf_id) { struct prefix p; struct route_table *table; @@ -2061,13 +2061,13 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, return 1; } - if (top - && ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN - && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) - || (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN - && memcmp(&nexthop->gate.ipv6, &top->u.prefix6, - IPV6_MAX_BYTELEN) - == 0))) { + if (top && + ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN && + nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) || + (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN && + memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) == + 0)) && + nexthop->vrf_id == vrf_id) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( " :%s: Attempting to install a max prefixlength route through itself", @@ -2361,6 +2361,7 @@ static unsigned nexthop_active_check(struct route_node *rn, const struct prefix *p, *src_p; struct zebra_vrf *zvrf; uint32_t mtu = 0; + vrf_id_t vrf_id; srcdest_rnode_prefixes(rn, &p, &src_p); @@ -2389,10 +2390,12 @@ static unsigned nexthop_active_check(struct route_node *rn, goto skip_check; } + + vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn))); switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2400,16 +2403,16 @@ static unsigned nexthop_active_check(struct route_node *rn, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: family = AFI_IP6; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2419,8 +2422,8 @@ static unsigned nexthop_active_check(struct route_node *rn, if (rn->p.family != AF_INET) family = AFI_IP6; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 68e5c391cf..c28e251e3a 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -350,7 +350,7 @@ DEFUN (no_zebra_ptm_enable_if, if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Bringing up interface %s", __func__, ifp->name); - if_up(ifp); + if_up(ifp, true); } } @@ -553,7 +553,7 @@ static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, ifp->ptm_status = ZEBRA_PTM_STATUS_UP; if (ifp->ptm_enable && if_is_no_ptm_operative(ifp) && send_linkup) - if_up(ifp); + if_up(ifp, true); } else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR) && (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) { ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN; @@ -1163,7 +1163,7 @@ void zebra_ptm_reset_status(int ptm_disable) zlog_debug( "%s: Bringing up interface %s", __func__, ifp->name); - if_up(ifp); + if_up(ifp, true); } } } |
