summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format3
-rw-r--r--bgpd/bgp_attr.c69
-rw-r--r--bgpd/bgp_attr.h11
-rw-r--r--bgpd/bgp_community.c3
-rw-r--r--bgpd/bgp_debug.c2
-rw-r--r--bgpd/bgp_errors.c6
-rw-r--r--bgpd/bgp_errors.h1
-rw-r--r--bgpd/bgp_evpn_vty.c18
-rw-r--r--bgpd/bgp_fsm.c12
-rw-r--r--bgpd/bgp_labelpool.c10
-rw-r--r--bgpd/bgp_mpath.c14
-rw-r--r--bgpd/bgp_nht.c30
-rw-r--r--bgpd/bgp_packet.c3
-rw-r--r--bgpd/bgp_route.c198
-rw-r--r--bgpd/bgp_routemap.c24
-rw-r--r--bgpd/bgp_rpki.c2
-rw-r--r--bgpd/bgp_vty.c2
-rw-r--r--bgpd/bgp_zebra.c9
-rw-r--r--bgpd/bgpd.c2
-rw-r--r--bgpd/rfapi/rfapi_vty.c7
-rw-r--r--configure.ac2
-rw-r--r--debian/.gitignore1
-rwxr-xr-xdebian/rules2
-rw-r--r--doc/developer/cli.rst10
-rw-r--r--doc/developer/frr-release-procedure.rst15
-rw-r--r--doc/developer/lists.rst186
-rw-r--r--doc/developer/logging.rst4
-rw-r--r--doc/developer/topotests.rst6
-rw-r--r--doc/developer/workflow.rst11
-rw-r--r--doc/user/basic.rst5
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/isisd.rst8
-rw-r--r--doc/user/pim.rst4
-rw-r--r--doc/user/pimv6.rst288
-rw-r--r--doc/user/subdir.am1
-rw-r--r--doc/user/vtysh.rst24
-rw-r--r--doc/user/zebra.rst8
-rw-r--r--isisd/isis_adjacency.c214
-rw-r--r--isisd/isis_adjacency.h2
-rw-r--r--isisd/isis_circuit.c145
-rw-r--r--isisd/isis_circuit.h2
-rw-r--r--isisd/isis_lsp.c76
-rw-r--r--isisd/isis_lsp.h17
-rw-r--r--isisd/isis_nb_notifications.c16
-rw-r--r--isisd/isis_pdu.c4
-rw-r--r--isisd/isis_spf.c12
-rw-r--r--isisd/isis_spf.h2
-rw-r--r--isisd/isis_tlvs.c1288
-rw-r--r--isisd/isis_tlvs.h2
-rw-r--r--isisd/isisd.c633
-rw-r--r--isisd/isisd.h12
-rw-r--r--ldpd/ldp_vty_exec.c4
-rw-r--r--lib/base64.c193
-rw-r--r--lib/base64.h45
-rw-r--r--lib/checksum.c85
-rw-r--r--lib/checksum.h43
-rw-r--r--lib/json.c13
-rw-r--r--lib/json.h22
-rw-r--r--lib/libfrr.c17
-rw-r--r--lib/libfrr.h11
-rw-r--r--lib/log_vty.c17
-rw-r--r--lib/northbound_grpc.cpp935
-rw-r--r--lib/prefix.c37
-rw-r--r--lib/routemap.c45
-rw-r--r--lib/sockunion.c15
-rw-r--r--lib/sockunion.h1
-rw-r--r--lib/subdir.am4
-rw-r--r--lib/thread.c58
-rw-r--r--lib/typerb.c35
-rw-r--r--lib/typerb.h22
-rw-r--r--lib/typesafe.h48
-rw-r--r--lib/vty.c181
-rw-r--r--lib/vty.h26
-rw-r--r--lib/wheel.c1
-rw-r--r--lib/yang_wrappers.c59
-rw-r--r--lib/yang_wrappers.h7
-rw-r--r--lib/zclient.c25
-rw-r--r--lib/zclient.h12
-rw-r--r--lib/zlog.c9
-rw-r--r--lib/zlog.h3
-rw-r--r--lib/zlog_live.c277
-rw-r--r--lib/zlog_live.h83
-rw-r--r--ospf6d/ospf6_gr.c2
-rw-r--r--ospf6d/ospf6_gr_helper.c19
-rw-r--r--ospf6d/ospf6_lsa.c8
-rw-r--r--ospf6d/ospf6_top.c15
-rw-r--r--ospf6d/ospf6_zebra.c7
-rw-r--r--ospfd/ospf_apiserver.c6
-rw-r--r--ospfd/ospf_apiserver.h4
-rw-r--r--ospfd/ospf_gr.c2
-rw-r--r--ospfd/ospf_ldp_sync.c7
-rw-r--r--ospfd/ospf_vty.c63
-rw-r--r--pbrd/pbr_zebra.c9
-rw-r--r--pimd/pim6_cmd.c494
-rw-r--r--pimd/pim6_cmd.h49
-rw-r--r--pimd/pim6_main.c13
-rw-r--r--pimd/pim6_stubs.c58
-rw-r--r--pimd/pim_addr.h2
-rw-r--r--pimd/pim_bfd.c6
-rw-r--r--pimd/pim_br.c10
-rw-r--r--pimd/pim_br.h6
-rw-r--r--pimd/pim_bsm.c23
-rw-r--r--pimd/pim_bsm.h2
-rw-r--r--pimd/pim_cmd.c923
-rw-r--r--pimd/pim_cmd_common.c655
-rw-r--r--pimd/pim_cmd_common.h62
-rw-r--r--pimd/pim_iface.c140
-rw-r--r--pimd/pim_iface.h11
-rw-r--r--pimd/pim_ifchannel.c5
-rw-r--r--pimd/pim_igmp.c268
-rw-r--r--pimd/pim_igmp.h32
-rw-r--r--pimd/pim_igmp_mtrace.c4
-rw-r--r--pimd/pim_igmp_stats.c10
-rw-r--r--pimd/pim_igmp_stats.h28
-rw-r--r--pimd/pim_igmpv2.c25
-rw-r--r--pimd/pim_igmpv3.c103
-rw-r--r--pimd/pim_join.c96
-rw-r--r--pimd/pim_join.h3
-rw-r--r--pimd/pim_mroute.c6
-rw-r--r--pimd/pim_msdp_packet.c4
-rw-r--r--pimd/pim_msg.h27
-rw-r--r--pimd/pim_nb.h6
-rw-r--r--pimd/pim_nb_config.c98
-rw-r--r--pimd/pim_nht.c241
-rw-r--r--pimd/pim_oil.c8
-rw-r--r--pimd/pim_pim.c27
-rw-r--r--pimd/pim_register.c165
-rw-r--r--pimd/pim_register.h5
-rw-r--r--pimd/pim_rp.c487
-rw-r--r--pimd/pim_rp.h20
-rw-r--r--pimd/pim_rpf.c91
-rw-r--r--pimd/pim_rpf.h1
-rw-r--r--pimd/pim_sock.c440
-rw-r--r--pimd/pim_sock.h12
-rw-r--r--pimd/pim_ssm.c2
-rw-r--r--pimd/pim_ssm.h2
-rw-r--r--pimd/pim_ssmpingd.c50
-rw-r--r--pimd/pim_static.c4
-rw-r--r--pimd/pim_tib.c178
-rw-r--r--pimd/pim_tib.h33
-rw-r--r--pimd/pim_tlv.c32
-rw-r--r--pimd/pim_upstream.c42
-rw-r--r--pimd/pim_upstream.h4
-rw-r--r--pimd/pim_util.c14
-rw-r--r--pimd/pim_util.h1
-rw-r--r--pimd/pim_vty.c286
-rw-r--r--pimd/pim_vty.h3
-rw-r--r--pimd/pim_zebra.c350
-rw-r--r--pimd/pim_zebra.h10
-rw-r--r--pimd/pim_zlookup.c42
-rw-r--r--pimd/pimd.c4
-rw-r--r--pimd/subdir.am20
-rw-r--r--python/clidef.py62
-rw-r--r--sharpd/sharp_zebra.c9
-rw-r--r--snapcraft/snapcraft.yaml.in1
-rw-r--r--staticd/static_main.c1
-rw-r--r--staticd/static_zebra.c33
-rw-r--r--tests/.gitignore2
-rw-r--r--tests/isisd/test_fuzz_isis_tlv.c8
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--tests/lib/subdir.am2
-rw-r--r--tests/lib/test_checksum.c70
-rw-r--r--tests/lib/test_grpc.py10
-rw-r--r--tests/lib/test_printfrr.c18
-rw-r--r--tests/lib/test_typelist.c8
-rw-r--r--tests/lib/test_typelist.h64
-rwxr-xr-xtests/topotests/analyze.py7
l---------tests/topotests/grpc_basic/lib1
-rw-r--r--tests/topotests/grpc_basic/r1/zebra.conf8
-rw-r--r--tests/topotests/grpc_basic/r2/zebra.conf8
-rw-r--r--tests/topotests/grpc_basic/test_basic_grpc.py179
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py88
-rwxr-xr-xtests/topotests/lib/grpc-query.py155
-rw-r--r--tests/topotests/lib/topogen.py24
-rw-r--r--tests/topotests/lib/topotest.py44
-rw-r--r--tools/coccinelle/json_object_add_camel_case.cocci19
-rw-r--r--tools/etc/frr/support_bundle_commands.conf1
-rw-r--r--vrrpd/Makefile4
-rwxr-xr-xvtysh/extract.pl.in6
-rw-r--r--vtysh/subdir.am4
-rw-r--r--vtysh/vtysh.c422
-rw-r--r--vtysh/vtysh.h14
-rw-r--r--vtysh/vtysh_main.c62
-rw-r--r--yang/frr-route-types.yang4
-rw-r--r--zebra/dplane_fpm_nl.c3
-rw-r--r--zebra/if_netlink.c32
-rw-r--r--zebra/interface.c45
-rw-r--r--zebra/interface.h3
-rw-r--r--zebra/kernel_netlink.c18
-rw-r--r--zebra/kernel_socket.c39
-rw-r--r--zebra/main.c20
-rw-r--r--zebra/rib.h3
-rw-r--r--zebra/zebra_evpn.c2
-rw-r--r--zebra/zebra_evpn_mac.c28
-rw-r--r--zebra/zebra_evpn_neigh.c29
-rw-r--r--zebra/zebra_netns_id.c2
-rw-r--r--zebra/zebra_nhg.c37
-rw-r--r--zebra/zebra_ptm.c6
-rw-r--r--zebra/zebra_rib.c6
-rw-r--r--zebra/zebra_rnh.c26
-rw-r--r--zebra/zebra_router.h1
-rw-r--r--zebra/zebra_srte.c12
-rw-r--r--zebra/zebra_vty.c1
-rw-r--r--zebra/zebra_vxlan.c23
204 files changed, 9271 insertions, 4050 deletions
diff --git a/.clang-format b/.clang-format
index a620b5c2c0..b01157b051 100644
--- a/.clang-format
+++ b/.clang-format
@@ -28,6 +28,9 @@ ForEachMacros:
- frr_each
- frr_each_safe
- frr_each_from
+ - frr_rev_each
+ - frr_rev_each_safe
+ - frr_rev_each_from
- frr_with_mutex
- frr_with_privs
- LIST_FOREACH
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 21f92c353e..a96b63cac6 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -669,9 +669,8 @@ unsigned int attrhash_key_make(const void *p)
if (attr->aspath)
MIX(aspath_key_make(attr->aspath));
- if (attr->community)
- MIX(community_hash_make(attr->community));
-
+ if (bgp_attr_get_community(attr))
+ MIX(community_hash_make(bgp_attr_get_community(attr)));
if (bgp_attr_get_lcommunity(attr))
MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr)));
if (bgp_attr_get_ecommunity(attr))
@@ -713,7 +712,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
&& attr1->nexthop.s_addr == attr2->nexthop.s_addr
&& attr1->aspath == attr2->aspath
- && attr1->community == attr2->community && attr1->med == attr2->med
+ && bgp_attr_get_community(attr1)
+ == bgp_attr_get_community(attr2)
+ && attr1->med == attr2->med
&& attr1->local_pref == attr2->local_pref
&& attr1->rmap_change_flags == attr2->rmap_change_flags) {
if (attr1->aggregator_as == attr2->aggregator_as
@@ -844,6 +845,7 @@ struct attr *bgp_attr_intern(struct attr *attr)
struct ecommunity *ecomm = NULL;
struct ecommunity *ipv6_ecomm = NULL;
struct lcommunity *lcomm = NULL;
+ struct community *comm = NULL;
/* Intern referenced strucutre. */
if (attr->aspath) {
@@ -852,11 +854,13 @@ struct attr *bgp_attr_intern(struct attr *attr)
else
attr->aspath->refcnt++;
}
- if (attr->community) {
- if (!attr->community->refcnt)
- attr->community = community_intern(attr->community);
+
+ comm = bgp_attr_get_community(attr);
+ if (comm) {
+ if (!comm->refcnt)
+ bgp_attr_set_community(attr, community_intern(comm));
else
- attr->community->refcnt++;
+ comm->refcnt++;
}
ecomm = bgp_attr_get_ecommunity(attr);
@@ -1003,7 +1007,7 @@ struct attr *bgp_attr_aggregate_intern(
community_del_val(community, &gshut);
}
- attr.community = community;
+ bgp_attr_set_community(&attr, community);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
@@ -1084,14 +1088,16 @@ void bgp_attr_unintern_sub(struct attr *attr)
struct ecommunity *ipv6_ecomm = NULL;
struct cluster_list *cluster;
struct lcommunity *lcomm = NULL;
+ struct community *comm = NULL;
/* aspath refcount shoud be decrement. */
aspath_unintern(&attr->aspath);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
- if (attr->community)
- community_unintern(&attr->community);
+ comm = bgp_attr_get_community(attr);
+ community_unintern(&comm);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES));
+ bgp_attr_set_community(attr, NULL);
ecomm = bgp_attr_get_ecommunity(attr);
ecommunity_unintern(&ecomm);
@@ -1171,21 +1177,27 @@ void bgp_attr_flush(struct attr *attr)
struct ecommunity *ipv6_ecomm;
struct cluster_list *cluster;
struct lcommunity *lcomm;
+ struct community *comm;
if (attr->aspath && !attr->aspath->refcnt) {
aspath_free(attr->aspath);
attr->aspath = NULL;
}
- if (attr->community && !attr->community->refcnt)
- community_free(&attr->community);
+ comm = bgp_attr_get_community(attr);
+ if (comm && !comm->refcnt)
+ community_free(&comm);
+ bgp_attr_set_community(attr, NULL);
+
ecomm = bgp_attr_get_ecommunity(attr);
if (ecomm && !ecomm->refcnt)
ecommunity_free(&ecomm);
bgp_attr_set_ecommunity(attr, NULL);
+
ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
if (ipv6_ecomm && !ipv6_ecomm->refcnt)
ecommunity_free(&ipv6_ecomm);
bgp_attr_set_ipv6_ecommunity(attr, NULL);
+
lcomm = bgp_attr_get_lcommunity(attr);
if (lcomm && !lcomm->refcnt)
lcommunity_free(&lcomm);
@@ -1932,13 +1944,14 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
const bgp_size_t length = args->length;
if (length == 0) {
- attr->community = NULL;
+ bgp_attr_set_community(attr, NULL);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
}
- attr->community =
- community_parse((uint32_t *)stream_pnt(peer->curr), length);
+ bgp_attr_set_community(
+ attr,
+ community_parse((uint32_t *)stream_pnt(peer->curr), length));
/* XXX: fix community_parse to use stream API and remove this */
stream_forward_getp(peer->curr, length);
@@ -1946,7 +1959,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
/* The Community attribute SHALL be considered malformed if its
* length is not a non-zero multiple of 4.
*/
- if (!attr->community)
+ if (!bgp_attr_get_community(attr))
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
@@ -4075,20 +4088,23 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
/* Community attribute. */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
- if (attr->community->size * 4 > 255) {
+ struct community *comm = NULL;
+
+ comm = bgp_attr_get_community(attr);
+ if (comm->size * 4 > 255) {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES);
- stream_putw(s, attr->community->size * 4);
+ stream_putw(s, comm->size * 4);
} else {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES);
- stream_putc(s, attr->community->size * 4);
+ stream_putc(s, comm->size * 4);
}
- stream_put(s, attr->community->val, attr->community->size * 4);
+ stream_put(s, comm->val, comm->size * 4);
}
/*
@@ -4525,20 +4541,23 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
- if (attr->community->size * 4 > 255) {
+ struct community *comm = NULL;
+
+ comm = bgp_attr_get_community(attr);
+ if (comm->size * 4 > 255) {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES);
- stream_putw(s, attr->community->size * 4);
+ stream_putw(s, comm->size * 4);
} else {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES);
- stream_putc(s, attr->community->size * 4);
+ stream_putc(s, comm->size * 4);
}
- stream_put(s, attr->community->val, attr->community->size * 4);
+ stream_put(s, comm->val, comm->size * 4);
}
/* Large Community attribute. */
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 16eb956b3d..1f199da161 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -530,6 +530,17 @@ static inline void bgp_attr_set_lcommunity(struct attr *attr,
attr->lcommunity = lcomm;
}
+static inline struct community *bgp_attr_get_community(const struct attr *attr)
+{
+ return attr->community;
+}
+
+static inline void bgp_attr_set_community(struct attr *attr,
+ struct community *comm)
+{
+ attr->community = comm;
+}
+
static inline struct ecommunity *
bgp_attr_get_ipv6_ecommunity(const struct attr *attr)
{
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index a5dafd7757..6e6a3cd587 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -497,6 +497,9 @@ void community_unintern(struct community **com)
{
struct community *ret;
+ if (!*com)
+ return;
+
if ((*com)->refcnt)
(*com)->refcnt--;
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 82e05dc53a..5d14ff0fa6 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -411,7 +411,7 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)))
snprintf(buf + strlen(buf), size - strlen(buf),
", community %s",
- community_str(attr->community, false));
+ community_str(bgp_attr_get_community(attr), false));
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)))
snprintf(buf + strlen(buf), size - strlen(buf),
diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c
index f11717b41f..193c96a169 100644
--- a/bgpd/bgp_errors.c
+++ b/bgpd/bgp_errors.c
@@ -475,6 +475,12 @@ static struct log_ref ferr_bgp_err[] = {
.suggestion = "Get log files from router and open an issue",
},
{
+ .code = EC_BGP_NO_LL_ADDRESS_AVAILABLE,
+ .title = "BGP v6 peer with no LL address on outgoing interface",
+ .description = "BGP when using a v6 peer requires a v6 LL address to be configured on the outgoing interface as per RFC 4291 section 2.1",
+ .suggestion = "Add a v6 LL address to the outgoing interfaces as per RFC",
+ },
+ {
.code = END_FERR,
}
};
diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h
index 20056d382a..0b71af3fc6 100644
--- a/bgpd/bgp_errors.h
+++ b/bgpd/bgp_errors.h
@@ -101,6 +101,7 @@ enum bgp_log_refs {
EC_BGP_ROUTER_ID_SAME,
EC_BGP_INVALID_BGP_INSTANCE,
EC_BGP_INVALID_ROUTE,
+ EC_BGP_NO_LL_ADDRESS_AVAILABLE,
};
extern void bgp_error_init(void);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 557f4ce125..7ddf159844 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -1236,6 +1236,10 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
no_display = 0;
for (; pi; pi = pi->next) {
+ struct community *picomm = NULL;
+
+ picomm = bgp_attr_get_community(pi->attr);
+
total_count++;
if (type == bgp_show_type_neighbor) {
struct peer *peer = output_arg;
@@ -1268,17 +1272,15 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
if (type == bgp_show_type_community) {
struct community *com = output_arg;
- if (!pi->attr->community ||
- !community_match(
- pi->attr->community, com))
+ if (!picomm ||
+ !community_match(picomm, com))
continue;
}
if (type == bgp_show_type_community_exact) {
struct community *com = output_arg;
- if (!pi->attr->community ||
- !community_cmp(
- pi->attr->community, com))
+ if (!picomm ||
+ !community_cmp(picomm, com))
continue;
}
if (header) {
@@ -3513,8 +3515,8 @@ DEFUN (bgp_evpn_advertise_all_vni,
bgp_evpn = bgp_get_evpn();
if (bgp_evpn && bgp_evpn != bgp) {
- vty_out(vty, "%% Please unconfigure EVPN in VRF %s\n",
- bgp_evpn->name);
+ vty_out(vty, "%% Please unconfigure EVPN in %s\n",
+ bgp_evpn->name_pretty);
return CMD_WARNING_CONFIG_FAILED;
}
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index a0b92b6c74..f8de3b8dc4 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -710,9 +710,10 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
if (pi->peer != peer)
continue;
- if (pi->attr->community &&
+ if (bgp_attr_get_community(pi->attr) &&
community_include(
- pi->attr->community,
+ bgp_attr_get_community(
+ pi->attr),
COMMUNITY_NO_LLGR))
continue;
@@ -738,9 +739,10 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
if (pi->peer != peer)
continue;
- if (pi->attr->community &&
- community_include(pi->attr->community,
- COMMUNITY_NO_LLGR))
+ if (bgp_attr_get_community(pi->attr) &&
+ community_include(
+ bgp_attr_get_community(pi->attr),
+ COMMUNITY_NO_LLGR))
continue;
if (bgp_debug_neighbor_events(peer))
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
index 1bc7b62304..8772afd736 100644
--- a/bgpd/bgp_labelpool.c
+++ b/bgpd/bgp_labelpool.c
@@ -631,13 +631,23 @@ DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd,
if (uj) {
json = json_object_new_object();
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
json_object_int_add(json, "Ledger", skiplist_count(lp->ledger));
+ json_object_int_add(json, "ledger", skiplist_count(lp->ledger));
json_object_int_add(json, "InUse", skiplist_count(lp->inuse));
+ json_object_int_add(json, "inUse", skiplist_count(lp->inuse));
json_object_int_add(json, "Requests",
lp_fifo_count(&lp->requests));
+ json_object_int_add(json, "requests",
+ lp_fifo_count(&lp->requests));
json_object_int_add(json, "LabelChunks", listcount(lp->chunks));
+ json_object_int_add(json, "labelChunks", listcount(lp->chunks));
json_object_int_add(json, "Pending", lp->pending_count);
+ json_object_int_add(json, "pending", lp->pending_count);
json_object_int_add(json, "Reconnects", lp->reconnect_count);
+ json_object_int_add(json, "reconnects", lp->reconnect_count);
vty_json(vty, json);
} else {
vty_out(vty, "Labelpool Summary\n");
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 774953f6f8..6e695d0301 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -842,7 +842,9 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
aspath = aspath_dup(attr.aspath);
origin = attr.origin;
community =
- attr.community ? community_dup(attr.community) : NULL;
+ bgp_attr_get_community(&attr)
+ ? community_dup(bgp_attr_get_community(&attr))
+ : NULL;
ecomm = (bgp_attr_get_ecommunity(&attr))
? ecommunity_dup(bgp_attr_get_ecommunity(&attr))
: NULL;
@@ -860,17 +862,19 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
if (origin < mpinfo->attr->origin)
origin = mpinfo->attr->origin;
- if (mpinfo->attr->community) {
+ if (bgp_attr_get_community(mpinfo->attr)) {
if (community) {
commerge = community_merge(
community,
- mpinfo->attr->community);
+ bgp_attr_get_community(
+ mpinfo->attr));
community =
community_uniq_sort(commerge);
community_free(&commerge);
} else
community = community_dup(
- mpinfo->attr->community);
+ bgp_attr_get_community(
+ mpinfo->attr));
}
if (bgp_attr_get_ecommunity(mpinfo->attr)) {
@@ -902,7 +906,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
attr.aspath = aspath;
attr.origin = origin;
if (community) {
- attr.community = community;
+ bgp_attr_set_community(&attr, community);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
if (ecomm) {
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 8313c12e61..d768733545 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -49,10 +49,8 @@
extern struct zclient *zclient;
-static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
- int is_bgp_static_route);
-static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
- int is_bgp_static_route);
+static void register_zebra_rnh(struct bgp_nexthop_cache *bnc);
+static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc);
static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p);
static void bgp_nht_ifp_initial(struct thread *thread);
@@ -92,8 +90,7 @@ static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
}
/* only unregister if this is the last nh for this prefix*/
if (!bnc_existing_for_prefix(bnc))
- unregister_zebra_rnh(
- bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
+ unregister_zebra_rnh(bnc);
bnc_free(bnc);
}
}
@@ -308,7 +305,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
} else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
&& !is_default_host_route(&bnc->prefix))
- register_zebra_rnh(bnc, is_bgp_static_route);
+ register_zebra_rnh(bnc);
if (pi && pi->nexthop != bnc) {
/* Unlink from existing nexthop cache, if any. This will also
@@ -387,7 +384,7 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
zlog_debug(
"Freeing connected NHT node %p for peer %s(%s)",
bnc, peer->host, bnc->bgp->name_pretty);
- unregister_zebra_rnh(bnc, 0);
+ unregister_zebra_rnh(bnc);
bnc_free(bnc);
}
}
@@ -665,6 +662,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc_nhc, *bnc_import;
struct bgp *bgp;
+ struct prefix match;
struct zapi_route nhr;
afi_t afi;
@@ -677,16 +675,16 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
return;
}
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) {
zlog_err("%s[%s]: Failure to decode nexthop update", __func__,
bgp->name_pretty);
return;
}
- afi = family2afi(nhr.prefix.family);
+ afi = family2afi(match.family);
tree = &bgp->nexthop_cache_table[afi];
- bnc_nhc = bnc_find(tree, &nhr.prefix, nhr.srte_color);
+ bnc_nhc = bnc_find(tree, &match, nhr.srte_color);
if (!bnc_nhc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
@@ -697,7 +695,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
tree = &bgp->import_check_table[afi];
- bnc_import = bnc_find(tree, &nhr.prefix, nhr.srte_color);
+ bnc_import = bnc_find(tree, &match, nhr.srte_color);
if (!bnc_import) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
@@ -914,8 +912,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
* RETURNS:
* void.
*/
-static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
- int is_bgp_import_route)
+static void register_zebra_rnh(struct bgp_nexthop_cache *bnc)
{
/* Check if we have already registered */
if (bnc->flags & BGP_NEXTHOP_REGISTERED)
@@ -936,8 +933,7 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
* RETURNS:
* void.
*/
-static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
- int is_bgp_import_route)
+static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc)
{
/* Check if we have already registered */
if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
@@ -1172,7 +1168,7 @@ void bgp_nht_register_nexthops(struct bgp *bgp)
frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
bnc) {
- register_zebra_rnh(bnc, 0);
+ register_zebra_rnh(bnc);
}
}
}
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 8fac36cf60..09db041780 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -665,9 +665,6 @@ static void bgp_write_notify(struct peer *peer)
assert(stream_get_endp(s) >= BGP_HEADER_SIZE);
- /* Stop collecting data within the socket */
- sockopt_cork(peer->fd, 0);
-
/*
* socket is in nonblocking mode, if we can't deliver the NOTIFY, well,
* we only care about getting a clean shutdown at this point.
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index eb1e57de2e..78e4964d9f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -641,8 +641,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
* below). See the Risks of Depreferencing Routes section (Section 5.2)
* for a discussion of potential risks inherent in doing this.
*/
- if (newattr->community &&
- community_include(newattr->community, COMMUNITY_LLGR_STALE)) {
+ if (bgp_attr_get_community(newattr) &&
+ community_include(bgp_attr_get_community(newattr),
+ COMMUNITY_LLGR_STALE)) {
if (debug)
zlog_debug(
"%s: %s wins over %s due to LLGR_STALE community",
@@ -650,8 +651,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
return 0;
}
- if (existattr->community &&
- community_include(existattr->community, COMMUNITY_LLGR_STALE)) {
+ if (bgp_attr_get_community(existattr) &&
+ community_include(bgp_attr_get_community(existattr),
+ COMMUNITY_LLGR_STALE)) {
if (debug)
zlog_debug(
"%s: %s loses to %s due to LLGR_STALE community",
@@ -1522,20 +1524,22 @@ done:
/* If community attribute includes no_export then return 1. */
static bool bgp_community_filter(struct peer *peer, struct attr *attr)
{
- if (attr->community) {
+ if (bgp_attr_get_community(attr)) {
/* NO_ADVERTISE check. */
- if (community_include(attr->community, COMMUNITY_NO_ADVERTISE))
+ if (community_include(bgp_attr_get_community(attr),
+ COMMUNITY_NO_ADVERTISE))
return true;
/* NO_EXPORT check. */
- if (peer->sort == BGP_PEER_EBGP
- && community_include(attr->community, COMMUNITY_NO_EXPORT))
+ if (peer->sort == BGP_PEER_EBGP &&
+ community_include(bgp_attr_get_community(attr),
+ COMMUNITY_NO_EXPORT))
return true;
/* NO_EXPORT_SUBCONFED check. */
if (peer->sort == BGP_PEER_EBGP
|| peer->sort == BGP_PEER_CONFED)
- if (community_include(attr->community,
+ if (community_include(bgp_attr_get_community(attr),
COMMUNITY_NO_EXPORT_SUBCONFED))
return true;
}
@@ -1745,7 +1749,7 @@ void bgp_attr_add_llgr_community(struct attr *attr)
struct community *merge;
struct community *llgr;
- old = attr->community;
+ old = bgp_attr_get_community(attr);
llgr = community_str2com("llgr-stale");
assert(llgr);
@@ -1764,7 +1768,7 @@ void bgp_attr_add_llgr_community(struct attr *attr)
community_free(&llgr);
- attr->community = new;
+ bgp_attr_set_community(attr, new);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
@@ -1775,7 +1779,7 @@ void bgp_attr_add_gshut_community(struct attr *attr)
struct community *merge;
struct community *gshut;
- old = attr->community;
+ old = bgp_attr_get_community(attr);
gshut = community_str2com("graceful-shutdown");
assert(gshut);
@@ -1793,7 +1797,7 @@ void bgp_attr_add_gshut_community(struct attr *attr)
}
community_free(&gshut);
- attr->community = new;
+ bgp_attr_set_community(attr, new);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
/* When we add the graceful-shutdown community we must also
@@ -2270,8 +2274,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* The route SHOULD NOT be advertised to any neighbor from which the
* Long-lived Graceful Restart Capability has not been received.
*/
- if (attr->community &&
- community_include(attr->community, COMMUNITY_LLGR_STALE) &&
+ if (bgp_attr_get_community(attr) &&
+ community_include(bgp_attr_get_community(attr),
+ COMMUNITY_LLGR_STALE) &&
!CHECK_FLAG(peer->cap, PEER_CAP_LLGR_RCV) &&
!CHECK_FLAG(peer->cap, PEER_CAP_LLGR_ADV))
return false;
@@ -3686,7 +3691,7 @@ static void bgp_attr_add_no_export_community(struct attr *attr)
struct community *merge;
struct community *no_export;
- old = attr->community;
+ old = bgp_attr_get_community(attr);
no_export = community_str2com("no-export");
assert(no_export);
@@ -3705,7 +3710,7 @@ static void bgp_attr_add_no_export_community(struct attr *attr)
community_free(&no_export);
- attr->community = new;
+ bgp_attr_set_community(attr, new);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
@@ -3915,15 +3920,16 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* propagation SHOULD be chosen according to the operator's
* routing policy.
*/
- if (new_attr.community
- && community_include(new_attr.community,
- COMMUNITY_BLACKHOLE))
+ if (bgp_attr_get_community(&new_attr) &&
+ community_include(bgp_attr_get_community(&new_attr),
+ COMMUNITY_BLACKHOLE))
bgp_attr_add_no_export_community(&new_attr);
/* If we receive the graceful-shutdown community from an eBGP
* peer we must lower local-preference */
- if (new_attr.community
- && community_include(new_attr.community, COMMUNITY_GSHUT)) {
+ if (bgp_attr_get_community(&new_attr) &&
+ community_include(bgp_attr_get_community(&new_attr),
+ COMMUNITY_GSHUT)) {
new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
@@ -5365,14 +5371,15 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
if (CHECK_FLAG(
peer->af_sflags[afi][safi],
PEER_STATUS_LLGR_WAIT) &&
- pi->attr->community &&
+ bgp_attr_get_community(pi->attr) &&
!community_include(
- pi->attr->community,
+ 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
@@ -5398,12 +5405,13 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
continue;
if (CHECK_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_LLGR_WAIT) &&
- pi->attr->community &&
- !community_include(pi->attr->community,
- COMMUNITY_NO_LLGR))
- break;
+ bgp_attr_get_community(pi->attr) &&
+ !community_include(
+ bgp_attr_get_community(pi->attr),
+ COMMUNITY_NO_LLGR))
+ continue;
if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE))
- break;
+ continue;
if (safi == SAFI_UNICAST &&
(peer->bgp->inst_type ==
BGP_INSTANCE_TYPE_VRF ||
@@ -7044,7 +7052,7 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin,
if (!aspath_cmp(pi->attr->aspath, (aspath) ? aspath : ae))
return false;
- if (!community_cmp(pi->attr->community, comm))
+ if (!community_cmp(bgp_attr_get_community(pi->attr), comm))
return false;
if (!ecommunity_cmp(bgp_attr_get_ecommunity(pi->attr), ecomm))
@@ -7463,10 +7471,10 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
/* Compute aggregate route's community.
*/
- if (pi->attr->community)
+ if (bgp_attr_get_community(pi->attr))
bgp_compute_aggregate_community_hash(
- aggregate,
- pi->attr->community);
+ aggregate,
+ bgp_attr_get_community(pi->attr));
/* Compute aggregate route's extended community.
*/
@@ -7585,12 +7593,13 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
aggregate,
pi->attr->aspath);
- if (pi->attr->community)
+ if (bgp_attr_get_community(pi->attr))
/* Remove community from aggregate.
*/
bgp_remove_comm_from_aggregate_hash(
- aggregate,
- pi->attr->community);
+ aggregate,
+ bgp_attr_get_community(
+ pi->attr));
if (bgp_attr_get_ecommunity(pi->attr))
/* Remove ecommunity from aggregate.
@@ -7705,10 +7714,9 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp,
/* Compute aggregate route's community.
*/
- if (pinew->attr->community)
+ if (bgp_attr_get_community(pinew->attr))
bgp_compute_aggregate_community(
- aggregate,
- pinew->attr->community);
+ aggregate, bgp_attr_get_community(pinew->attr));
/* Compute aggregate route's extended community.
*/
@@ -7808,12 +7816,11 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
bgp_remove_aspath_from_aggregate(aggregate,
pi->attr->aspath);
- if (pi->attr->community)
+ if (bgp_attr_get_community(pi->attr))
/* Remove community from aggregate.
*/
bgp_remove_community_from_aggregate(
- aggregate,
- pi->attr->community);
+ aggregate, bgp_attr_get_community(pi->attr));
if (bgp_attr_get_ecommunity(pi->attr))
/* Remove ecommunity from aggregate.
@@ -9522,6 +9529,8 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
} else {
json_object_string_add(json_nexthop, "Error",
"Unsupported address-family");
+ json_object_string_add(json_nexthop, "error",
+ "Unsupported address-family");
}
}
@@ -9891,9 +9900,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (tag_buf[0] != '\0')
vty_out(vty, " VNI %s", tag_buf);
} else {
- if (tag_buf[0])
+ if (tag_buf[0]) {
json_object_string_add(json_path, "VNI",
tag_buf);
+ json_object_string_add(json_path, "vni",
+ tag_buf);
+ }
}
}
@@ -10492,14 +10504,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Line 4 display Community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
if (json_paths) {
- if (!attr->community->json)
- community_str(attr->community, true);
- json_object_lock(attr->community->json);
- json_object_object_add(json_path, "community",
- attr->community->json);
+ if (!bgp_attr_get_community(attr)->json)
+ community_str(bgp_attr_get_community(attr),
+ true);
+ json_object_lock(bgp_attr_get_community(attr)->json);
+ json_object_object_add(
+ json_path, "community",
+ bgp_attr_get_community(attr)->json);
} else {
vty_out(vty, " Community: %s\n",
- attr->community->str);
+ bgp_attr_get_community(attr)->str);
}
}
@@ -10744,8 +10758,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
gr_remaining);
}
- if (path->peer->t_llgr_stale[afi][safi] && attr->community &&
- community_include(attr->community, COMMUNITY_LLGR_STALE)) {
+ if (path->peer->t_llgr_stale[afi][safi] &&
+ bgp_attr_get_community(attr) &&
+ community_include(bgp_attr_get_community(attr),
+ COMMUNITY_LLGR_STALE)) {
unsigned long llgr_remaining = thread_timer_remain_second(
path->peer->t_llgr_stale[afi][safi]);
@@ -10883,6 +10899,10 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
json_paths = NULL;
for (; pi; pi = pi->next) {
+ struct community *picomm = NULL;
+
+ picomm = bgp_attr_get_community(pi->attr);
+
total_count++;
if (type == bgp_show_type_prefix_version) {
@@ -10898,9 +10918,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
int num;
bool found = false;
- if (pi->attr->community) {
- frrstr_split(pi->attr->community->str,
- " ", &communities, &num);
+ if (picomm) {
+ frrstr_split(picomm->str, " ",
+ &communities, &num);
for (int i = 0; i < num; i++) {
const char *com2alias =
bgp_community2alias(
@@ -11024,36 +11044,31 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
continue;
}
if (type == bgp_show_type_community_all) {
- if (!pi->attr->community)
+ if (!picomm)
continue;
}
if (type == bgp_show_type_community) {
struct community *com = output_arg;
- if (!pi->attr->community
- || !community_match(pi->attr->community,
- com))
+ if (!picomm || !community_match(picomm, com))
continue;
}
if (type == bgp_show_type_community_exact) {
struct community *com = output_arg;
- if (!pi->attr->community
- || !community_cmp(pi->attr->community, com))
+ if (!picomm || !community_cmp(picomm, com))
continue;
}
if (type == bgp_show_type_community_list) {
struct community_list *list = output_arg;
- if (!community_list_match(pi->attr->community,
- list))
+ if (!community_list_match(picomm, list))
continue;
}
if (type == bgp_show_type_community_list_exact) {
struct community_list *list = output_arg;
- if (!community_list_exact_match(
- pi->attr->community, list))
+ if (!community_list_exact_match(picomm, list))
continue;
}
if (type == bgp_show_type_lcommunity) {
@@ -11471,44 +11486,43 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
vty_out(vty, "not allocated\n");
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+ struct community *picomm = NULL;
+
+ picomm = bgp_attr_get_community(pi->attr);
+
count++;
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
best = count;
if (bgp_path_suppressed(pi))
suppress = 1;
- if (pi->attr->community == NULL)
+ if (!picomm)
continue;
no_advertise += community_include(
- pi->attr->community, COMMUNITY_NO_ADVERTISE);
- no_export += community_include(pi->attr->community,
- COMMUNITY_NO_EXPORT);
- local_as += community_include(pi->attr->community,
- COMMUNITY_LOCAL_AS);
- accept_own += community_include(pi->attr->community,
- COMMUNITY_ACCEPT_OWN);
+ picomm, COMMUNITY_NO_ADVERTISE);
+ no_export +=
+ community_include(picomm, COMMUNITY_NO_EXPORT);
+ local_as +=
+ community_include(picomm, COMMUNITY_LOCAL_AS);
+ accept_own +=
+ community_include(picomm, COMMUNITY_ACCEPT_OWN);
route_filter_translated_v4 += community_include(
- pi->attr->community,
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v4);
+ picomm, COMMUNITY_ROUTE_FILTER_TRANSLATED_v4);
route_filter_translated_v6 += community_include(
- pi->attr->community,
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v6);
+ picomm, COMMUNITY_ROUTE_FILTER_TRANSLATED_v6);
route_filter_v4 += community_include(
- pi->attr->community, COMMUNITY_ROUTE_FILTER_v4);
+ picomm, COMMUNITY_ROUTE_FILTER_v4);
route_filter_v6 += community_include(
- pi->attr->community, COMMUNITY_ROUTE_FILTER_v6);
- llgr_stale += community_include(pi->attr->community,
- COMMUNITY_LLGR_STALE);
- no_llgr += community_include(pi->attr->community,
- COMMUNITY_NO_LLGR);
- accept_own_nexthop +=
- community_include(pi->attr->community,
- COMMUNITY_ACCEPT_OWN_NEXTHOP);
- blackhole += community_include(pi->attr->community,
- COMMUNITY_BLACKHOLE);
- no_peer += community_include(pi->attr->community,
- COMMUNITY_NO_PEER);
+ picomm, COMMUNITY_ROUTE_FILTER_v6);
+ llgr_stale +=
+ community_include(picomm, COMMUNITY_LLGR_STALE);
+ no_llgr += community_include(picomm, COMMUNITY_NO_LLGR);
+ accept_own_nexthop += community_include(
+ picomm, COMMUNITY_ACCEPT_OWN_NEXTHOP);
+ blackhole +=
+ community_include(picomm, COMMUNITY_BLACKHOLE);
+ no_peer += community_include(picomm, COMMUNITY_NO_PEER);
}
}
@@ -14152,7 +14166,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_routemap.c b/bgpd/bgp_routemap.c
index 657e022db8..6fcc083e33 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1246,10 +1246,10 @@ route_match_alias(void *rule, const struct prefix *prefix, void *object)
int num;
bool found;
- if (path->attr->community) {
+ if (bgp_attr_get_community(path->attr)) {
found = false;
- frrstr_split(path->attr->community->str, " ", &communities,
- &num);
+ frrstr_split(bgp_attr_get_community(path->attr)->str, " ",
+ &communities, &num);
for (int i = 0; i < num; i++) {
const char *com2alias =
bgp_community2alias(communities[i]);
@@ -1441,10 +1441,12 @@ route_match_community(void *rule, const struct prefix *prefix, void *object)
return RMAP_NOMATCH;
if (rcom->exact) {
- if (community_list_exact_match(path->attr->community, list))
+ if (community_list_exact_match(
+ bgp_attr_get_community(path->attr), list))
return RMAP_MATCH;
} else {
- if (community_list_match(path->attr->community, list))
+ if (community_list_match(bgp_attr_get_community(path->attr),
+ list))
return RMAP_MATCH;
}
@@ -2193,12 +2195,12 @@ route_set_community(void *rule, const struct prefix *prefix, void *object)
rcs = rule;
path = object;
attr = path->attr;
- old = attr->community;
+ old = bgp_attr_get_community(attr);
/* "none" case. */
if (rcs->none) {
attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES));
- attr->community = NULL;
+ bgp_attr_set_community(attr, NULL);
/* See the longer comment down below. */
if (old && old->refcnt == 0)
community_free(&old);
@@ -2223,7 +2225,7 @@ route_set_community(void *rule, const struct prefix *prefix, void *object)
community_free(&old);
/* will be interned by caller if required */
- attr->community = new;
+ bgp_attr_set_community(attr, new);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
@@ -2507,7 +2509,7 @@ route_set_community_delete(void *rule, const struct prefix *prefix,
path = object;
list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
COMMUNITY_LIST_MASTER);
- old = path->attr->community;
+ old = bgp_attr_get_community(path->attr);
if (list && old) {
merge = community_list_match_delete(community_dup(old), list);
@@ -2523,12 +2525,12 @@ route_set_community_delete(void *rule, const struct prefix *prefix,
community_free(&old);
if (new->size == 0) {
- path->attr->community = NULL;
+ bgp_attr_set_community(path->attr, NULL);
path->attr->flag &=
~ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
community_free(&new);
} else {
- path->attr->community = new;
+ bgp_attr_set_community(path->attr, new);
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
}
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/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index d21e257cb5..dea1433f6d 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1486,7 +1486,7 @@ DEFUN (no_router_bgp,
}
if (bgp->l3vni) {
- vty_out(vty, "%% Please unconfigure l3vni %u",
+ vty_out(vty, "%% Please unconfigure l3vni %u\n",
bgp->l3vni);
return CMD_WARNING_CONFIG_FAILED;
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 5a060d46f5..78eaac7806 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -882,6 +882,12 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
*/
if (!v6_ll_avail && if_is_loopback(ifp))
v6_ll_avail = true;
+ else {
+ flog_warn(
+ EC_BGP_NO_LL_ADDRESS_AVAILABLE,
+ "Interface: %s does not have a v6 LL address associated with it, waiting until one is created for it",
+ ifp->name);
+ }
} else
/* Link-local address. */
{
@@ -1510,7 +1516,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
sizeof(bzo.aspath));
if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
- strlcpy(bzo.community, info->attr->community->str,
+ strlcpy(bzo.community,
+ bgp_attr_get_community(info->attr)->str,
sizeof(bzo.community));
if (info->attr->flag
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 16488eb4a4..38a106359e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1223,7 +1223,7 @@ int bgp_global_gr_init(struct bgp *bgp)
{
/*Event -> */
/*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
- GLOBAL_INVALID, GLOBAL_HELPER,
+ GLOBAL_GR, GLOBAL_HELPER,
/*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
GLOBAL_DISABLE, GLOBAL_INVALID
},
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 174fadc23e..b95bace0d1 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -468,6 +468,7 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
struct cluster_list *cluster;
char buf[BUFSIZ];
struct ecommunity *ecomm;
+ struct community *comm;
if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0)
return;
@@ -482,8 +483,10 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
fp(out, " aspath=%p, refcnt=%d%s", attr->aspath,
(attr->aspath ? attr->aspath->refcnt : 0), HVTYNL);
- fp(out, " community=%p, refcnt=%d%s", attr->community,
- (attr->community ? attr->community->refcnt : 0), HVTYNL);
+
+ comm = bgp_attr_get_community(attr);
+ fp(out, " community=%p, refcnt=%d%s", comm, (comm ? comm->refcnt : 0),
+ HVTYNL);
ecomm = bgp_attr_get_ecommunity(attr);
fp(out, " ecommunity=%p, refcnt=%d%s", ecomm,
diff --git a/configure.ac b/configure.ac
index ddd883e54f..170d16ca6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1371,6 +1371,8 @@ case "${enable_vtysh}" in
AC_MSG_ERROR([libreadline (needed for vtysh) not found and/or missing dependencies])
], [$LIBREADLINE])
], [])
+ LIBS="$LIBS -lreadline"
+ AC_CHECK_FUNCS([rl_clear_visible_line])
LIBS="$prev_libs"
AC_CHECK_HEADER([readline/history.h])
diff --git a/debian/.gitignore b/debian/.gitignore
index 0b267c6f5c..d95d33a610 100644
--- a/debian/.gitignore
+++ b/debian/.gitignore
@@ -11,3 +11,4 @@
/files
/frr.init
/frr.service
+/frr@.service
diff --git a/debian/rules b/debian/rules
index 0fa9c3a3b0..7a719b7c60 100755
--- a/debian/rules
+++ b/debian/rules
@@ -72,6 +72,7 @@ override_dh_auto_install:
# let dh_systemd_* and dh_installinit do their thing automatically
cp tools/frr.service debian/frr.service
+ cp tools/frr@.service debian/frr@.service
cp tools/frrinit.sh debian/frr.init
-rm -f debian/tmp/usr/lib/frr/frr
@@ -112,3 +113,4 @@ override_dh_auto_clean:
if test -f Makefile; then make redistclean; fi
-rm -f debian/frr.init
-rm -f debian/frr.service
+ -rm -f debian/frr@.service
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index 9254eb4739..ff6c4f6e16 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -48,6 +48,16 @@ a node and returns the parent of the node. This interface causes all manner of
insidious problems, even for experienced developers, and needs to be fixed at
some point in the future.
+Deprecation of old style of commands
+------------------------------------
+
+There are currently 2 styles of defining commands within a FRR source file.
+``DEFUN`` and ``DEFPY``. ``DEFPY`` should be used for all new commands that
+a developer is writing. This is because it allows for much better handling
+of command line arguments as well as ensuring that input is correct. ``DEFUN``
+is listed here for historical reasons as well as for ensuring that existing
+code can be understood by new developers.
+
Defining Commands
-----------------
All definitions for the CLI system are exposed in ``lib/command.h``. In this
diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst
index 6a7f9c4ca9..4ef0ca8416 100644
--- a/doc/developer/frr-release-procedure.rst
+++ b/doc/developer/frr-release-procedure.rst
@@ -204,7 +204,7 @@ Stage 3 - Publish
.. code-block:: console
- cp <old-version>.md <version>.md
+ cp content/release/<old-version>.md content/release/<new-version>.md
Paste the GitHub release announcement text into this document, and **remove
line breaks**. In other words, this::
@@ -220,10 +220,17 @@ Stage 3 - Publish
This is very important otherwise the announcement will be unreadable on the
website.
- Make sure to add a link to the GitHub releases page at the top.
+ To get the number of commiters and commits, here is a couple of handy commands:
+
+ .. code-block:: console
- Once finished, manually add a new entry into ``index.html`` to link to this
- new announcement. Look at past commits to see how to do this.
+ # The number of commits
+ % git log --oneline --no-merges base_8.2...base_8.1 | wc -l
+
+ # The number of commiters
+ % git shortlog --summary --no-merges base_8.2...base_8.1 | wc -l
+
+ Make sure to add a link to the GitHub releases page at the top.
#. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
that the announcement text is visible.
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index dc8f236927..4eaa85115e 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -1,23 +1,23 @@
.. _lists:
-List implementations
+Type-safe containers
====================
.. note::
- The term *list* is used generically for lists, skiplists, trees and hash
- tables in this document.
+ This section previously used the term *list*; it was changed to *container*
+ to be more clear.
-Common list interface
----------------------
+Common container interface
+--------------------------
-FRR includes a set of list-like data structure implementations with abstracted
+FRR includes a set of container implementations with abstracted
common APIs. The purpose of this is easily allow swapping out one
data structure for another while also making the code easier to read and write.
-There is one API for unsorted lists and a similar but not identical API for
-sorted lists - and heaps use a middle ground of both.
+There is one API for unsorted containers and a similar but not identical API
+for sorted containers - and heaps use a middle ground of both.
-For unsorted lists, the following implementations exist:
+For unsorted containers, the following implementations exist:
- single-linked list with tail pointer (e.g. STAILQ in BSD)
@@ -31,7 +31,7 @@ Being partially sorted, the oddball structure:
- an 8-ary heap
-For sorted lists, these data structures are implemented:
+For sorted containers, these data structures are implemented:
- single-linked list
@@ -44,7 +44,7 @@ For sorted lists, these data structures are implemented:
- hash table (note below)
Except for hash tables, each of the sorted data structures has a variant with
-unique and non-unique list items. Hash tables always require unique items
+unique and non-unique items. Hash tables always require unique items
and mostly follow the "sorted" API but use the hash value as sorting
key. Also, iterating while modifying does not work with hash tables.
Conversely, the heap always has non-unique items, but iterating while modifying
@@ -60,7 +60,7 @@ in the future:
The APIs are all designed to be as type-safe as possible. This means that
-there will be a compiler warning when an item doesn't match the list, or
+there will be a compiler warning when an item doesn't match the container, or
the return value has a different type, or other similar situations. **You
should never use casts with these APIs.** If a cast is neccessary in relation
to these APIs, there is probably something wrong with the overall design.
@@ -100,35 +100,39 @@ Available types:
Functions provided:
-+------------------------------------+------+------+------+---------+------------+
-| Function | LIST | HEAP | HASH | \*_UNIQ | \*_NONUNIQ |
-+====================================+======+======+======+=========+============+
-| _init, _fini | yes | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
-| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
-| | | | | | |
-| _const_first, _const_next | | | | | |
-+------------------------------------+------+------+------+---------+------------+
-| _swap_all | yes | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
-| _anywhere | yes | -- | -- | -- | -- |
-+------------------------------------+------+------+------+---------+------------+
-| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
-+------------------------------------+------+------+------+---------+------------+
-| _add | -- | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
-| _member | yes | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
-| _del, _pop | yes | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
-| _find, _const_find | -- | -- | yes | yes | -- |
-+------------------------------------+------+------+------+---------+------------+
-| _find_lt, _find_gteq, | -- | -- | -- | yes | yes |
-| | | | | | |
-| _const_find_lt, _const_find_gteq | | | | | |
-+------------------------------------+------+------+------+---------+------------+
-| use with frr_each() macros | yes | yes | yes | yes | yes |
-+------------------------------------+------+------+------+---------+------------+
++------------------------------------+-------+------+------+---------+------------+
+| Function | LIST | HEAP | HASH | \*_UNIQ | \*_NONUNIQ |
++====================================+=======+======+======+=========+============+
+| _init, _fini | yes | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
+| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
+| | | | | | |
+| _const_first, _const_next | | | | | |
++------------------------------------+-------+------+------+---------+------------+
+| _last, _prev, _prev_safe, | DLIST | -- | -- | RB only | RB only |
+| | only | | | | |
+| _const_last, _const_prev | | | | | |
++------------------------------------+-------+------+------+---------+------------+
+| _swap_all | yes | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
+| _anywhere | yes | -- | -- | -- | -- |
++------------------------------------+-------+------+------+---------+------------+
+| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
++------------------------------------+-------+------+------+---------+------------+
+| _add | -- | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
+| _member | yes | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
+| _del, _pop | yes | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
+| _find, _const_find | -- | -- | yes | yes | -- |
++------------------------------------+-------+------+------+---------+------------+
+| _find_lt, _find_gteq, | -- | -- | -- | yes | yes |
+| | | | | | |
+| _const_find_lt, _const_find_gteq | | | | | |
++------------------------------------+-------+------+------+---------+------------+
+| use with frr_each() macros | yes | yes | yes | yes | yes |
++------------------------------------+-------+------+------+---------+------------+
@@ -136,7 +140,7 @@ Datastructure type setup
------------------------
Each of the data structures has a ``PREDECL_*`` and a ``DECLARE_*`` macro to
-set up an "instantiation" of the list. This works somewhat similar to C++
+set up an "instantiation" of the container. This works somewhat similar to C++
templating, though much simpler.
**In all following text, the Z prefix is replaced with a name choosen
@@ -174,8 +178,8 @@ The common setup pattern will look like this:
``XXX`` is replaced with the name of the data structure, e.g. ``SKIPLIST``
or ``ATOMLIST``. The ``DECLARE_XXX`` invocation can either occur in a `.h`
-file (if the list needs to be accessed from several C files) or it can be
-placed in a `.c` file (if the list is only accessed from that file.) The
+file (if the container needs to be accessed from several C files) or it can be
+placed in a `.c` file (if the container is only accessed from that file.) The
``PREDECL_XXX`` invocation defines the ``struct Z_item`` and ``struct
Z_head`` types and must therefore occur before these are used.
@@ -196,7 +200,7 @@ The following iteration macros work across all data structures:
for (item = Z_first(&head); item; item = Z_next(&head, item))
- Note that this will fail if the list is modified while being iterated
+ Note that this will fail if the container is modified while being iterated
over.
.. c:macro:: frr_each_safe(Z, head, item)
@@ -220,8 +224,8 @@ The following iteration macros work across all data structures:
.. c:macro:: frr_each_from(Z, head, item, from)
- Iterates over the list, starting at item ``from``. This variant is "safe"
- as in the previous macro. Equivalent to:
+ Iterates over the container, starting at item ``from``. This variant is
+ "safe" as in the previous macro. Equivalent to:
.. code-block:: c
@@ -236,6 +240,13 @@ The following iteration macros work across all data structures:
resume iteration after breaking out of the loop by keeping the ``from``
value persistent and reusing it for the next loop.
+.. c:macro:: frr_rev_each(Z, head, item)
+.. c:macro:: frr_rev_each_safe(Z, head, item)
+.. c:macro:: frr_rev_each_from(Z, head, item, from)
+
+ Reverse direction variants of the above. Only supported on containers that
+ implement ``_last`` and ``_prev`` (i.e. ``RBTREE`` and ``DLIST``).
+
To iterate over ``const`` pointers, add ``_const`` to the name of the
datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes
``frr_each (mylist_const, head, item)``.
@@ -243,24 +254,24 @@ datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes
Common API
----------
-The following documentation assumes that a list has been defined using
-``Z`` as the name, and ``itemtype`` being the type of the list items (e.g.
+The following documentation assumes that a container has been defined using
+``Z`` as the name, and ``itemtype`` being the type of the items (e.g.
``struct item``.)
.. c:function:: void Z_init(struct Z_head *)
- Initializes the list for use. For most implementations, this just sets
+ Initializes the container for use. For most implementations, this just sets
some values. Hash tables are the only implementation that allocates
memory in this call.
.. c:function:: void Z_fini(struct Z_head *)
- Reverse the effects of :c:func:`Z_init()`. The list must be empty
+ Reverse the effects of :c:func:`Z_init()`. The container must be empty
when this function is called.
.. warning::
- This function may ``assert()`` if the list is not empty.
+ This function may ``assert()`` if the container is not empty.
.. c:function:: size_t Z_count(const struct Z_head *)
@@ -270,7 +281,7 @@ The following documentation assumes that a list has been defined using
.. note::
- For atomic lists with concurrent access, the value will already be
+ For atomic containers with concurrent access, the value will already be
outdated by the time this function returns and can therefore only be
used as an estimate.
@@ -291,6 +302,12 @@ The following documentation assumes that a list has been defined using
empty. This is O(1) for all data structures except red-black trees
where it is O(log n).
+.. c:function:: const itemtype *Z_const_last(const struct Z_head *)
+.. c:function:: itemtype *Z_last(struct Z_head *)
+
+ Last item in the structure, or ``NULL``. Only available on containers
+ that support reverse iteration (i.e. ``RBTREE`` and ``DLIST``).
+
.. c:function:: itemtype *Z_pop(struct Z_head *)
Remove and return the first item in the structure, or ``NULL`` if the
@@ -300,7 +317,7 @@ The following documentation assumes that a list has been defined using
This function can be used to build queues (with unsorted structures) or
priority queues (with sorted structures.)
- Another common pattern is deleting all list items:
+ Another common pattern is deleting all container items:
.. code-block:: c
@@ -329,16 +346,23 @@ The following documentation assumes that a list has been defined using
Same as :c:func:`Z_next()`, except that ``NULL`` is returned if
``prev`` is ``NULL``.
+.. c:function:: const itemtype *Z_const_prev(const struct Z_head *, const itemtype *next)
+.. c:function:: itemtype *Z_prev(struct Z_head *, itemtype *next)
+.. c:function:: itemtype *Z_prev_safe(struct Z_head *, itemtype *next)
+
+ As above, but preceding item. Only available on structures that support
+ reverse iteration (i.e. ``RBTREE`` and ``DLIST``).
+
.. c:function:: itemtype *Z_del(struct Z_head *, itemtype *item)
- Remove ``item`` from the list and return it.
+ Remove ``item`` from the container and return it.
.. note::
This function's behaviour is undefined if ``item`` is not actually
- on the list. Some structures return ``NULL`` in this case while others
- return ``item``. The function may also call ``assert()`` (but most
- don't.)
+ on the container. Some structures return ``NULL`` in this case while
+ others return ``item``. The function may also call ``assert()`` (but
+ most don't.)
.. c:function:: itemtype *Z_swap_all(struct Z_head *, struct Z_head *)
@@ -427,8 +451,8 @@ API for sorted structures
-------------------------
Sorted data structures do not need to have an insertion position specified,
-therefore the insertion calls are different from unsorted lists. Also,
-sorted lists can be searched for a value.
+therefore the insertion calls are different from unsorted containers. Also,
+sorted containers can be searched for a value.
.. c:macro:: DECLARE_XXX_UNIQ(Z, type, field, compare_func)
@@ -439,7 +463,7 @@ sorted lists can be searched for a value.
created for this instantiation. ``DECLARE_XXX(foo, ...)``
gives ``struct foo_item``, ``foo_add()``, ``foo_count()``, etc. Note
that this must match the value given in ``PREDECL_XXX(foo)``.
- :param typename type: Specifies the data type of the list items, e.g.
+ :param typename type: Specifies the data type of the items, e.g.
``struct item``. Note that ``struct`` must be added here, it is not
automatically added.
:param token field: References a struct member of ``type`` that must be
@@ -448,29 +472,29 @@ sorted lists can be searched for a value.
:param funcptr compare_func: Item comparison function, must have the
following function signature:
``int function(const itemtype *, const itemtype*)``. This function
- may be static if the list is only used in one file.
+ may be static if the container is only used in one file.
.. c:macro:: DECLARE_XXX_NONUNIQ(Z, type, field, compare_func)
- Same as above, but allow adding multiple items to the list that compare
+ Same as above, but allow adding multiple items to the container that compare
as equal in ``compare_func``. Ordering between these items is undefined
- and depends on the list implementation.
+ and depends on the container implementation.
.. c:function:: itemtype *Z_add(struct Z_head *, itemtype *item)
Insert an item at the appropriate sorted position. If another item exists
- in the list that compares as equal (``compare_func()`` == 0), ``item`` is
- not inserted into the list and the already-existing item in the list is
+ in the container that compares as equal (``compare_func()`` == 0), ``item``
+ is not inserted and the already-existing item in the container is
returned. Otherwise, on successful insertion, ``NULL`` is returned.
- For ``_NONUNIQ`` lists, this function always returns NULL since ``item``
- can always be successfully added to the list.
+ For ``_NONUNIQ`` containers, this function always returns NULL since
+ ``item`` can always be successfully added to the container.
.. c:function:: const itemtype *Z_const_find(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref)
- Search the list for an item that compares equal to ``ref``. If no equal
- item is found, return ``NULL``.
+ Search the container for an item that compares equal to ``ref``. If no
+ equal item is found, return ``NULL``.
This function is likely used with a temporary stack-allocated value for
``ref`` like so:
@@ -483,21 +507,21 @@ sorted lists can be searched for a value.
.. note::
- The ``Z_find()`` function is only available for lists that contain
- unique items (i.e. ``DECLARE_XXX_UNIQ``.) This is because on a list
- containing non-unique items, more than one item may compare as equal to
+ The ``Z_find()`` function is only available for containers that contain
+ unique items (i.e. ``DECLARE_XXX_UNIQ``.) This is because on a container
+ with non-unique items, more than one item may compare as equal to
the item that is searched for.
.. c:function:: const itemtype *Z_const_find_gteq(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref)
- Search the list for an item that compares greater or equal to
+ Search the container for an item that compares greater or equal to
``ref``. See :c:func:`Z_find()` above.
.. c:function:: const itemtype *Z_const_find_lt(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref)
- Search the list for an item that compares less than
+ Search the container for an item that compares less than
``ref``. See :c:func:`Z_find()` above.
@@ -511,7 +535,7 @@ API for hash tables
created for this instantiation. ``DECLARE_XXX(foo, ...)``
gives ``struct foo_item``, ``foo_add()``, ``foo_count()``, etc. Note
that this must match the value given in ``PREDECL_XXX(foo)``.
- :param typename type: Specifies the data type of the list items, e.g.
+ :param typename type: Specifies the data type of the items, e.g.
``struct item``. Note that ``struct`` must be added here, it is not
automatically added.
:param token field: References a struct member of ``type`` that must be
@@ -520,7 +544,7 @@ API for hash tables
:param funcptr compare_func: Item comparison function, must have the
following function signature:
``int function(const itemtype *, const itemtype*)``. This function
- may be static if the list is only used in one file. For hash tables,
+ may be static if the container is only used in one file. For hash tables,
this function is only used to check for equality, the ordering is
ignored.
:param funcptr hash_func: Hash calculation function, must have the
@@ -725,13 +749,9 @@ Head removal (pop) and deallocation:
FAQ
---
-What are the semantics of ``const`` in the list APIs?
+What are the semantics of ``const`` in the container APIs?
``const`` pointers to list heads and/or items are interpreted to mean that
- both the list itself as well as the data items are read-only.
-
-Why is there no "is this item on a/the list" test?
- It's slow for several of the data structures, and the work of adding it
- just hasn't been done. It can certainly be added if it's needed.
+ both the container itself as well as the data items are read-only.
Why is it ``PREDECL`` + ``DECLARE`` instead of ``DECLARE`` + ``DEFINE``?
The rule is that a ``DEFINE`` must be in a ``.c`` file, and linked exactly
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index 4e6fc04206..7046361204 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -163,6 +163,10 @@ Networking data types
- :c:union:`prefixptr` (dereference to get :c:struct:`prefix`)
- :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`)
+ Options:
+
+ ``%pFXh``: (address only) :frrfmtout:`1.2.3.0` / :frrfmtout:`fe80::1234`
+
.. frrfmt:: %pPSG4 (struct prefix_sg *)
:frrfmtout:`(*,1.2.3.4)`
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index fa1fd20067..6c1d9148d1 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -35,6 +35,9 @@ Installing Topotest Requirements
python2 -m pip install 'exabgp<4.0.0'
useradd -d /var/run/exabgp/ -s /bin/false exabgp
+ # To enable the gRPC topotest install:
+ python3 -m pip install grpcio grpcio-tools
+
Enable Coredumps
""""""""""""""""
@@ -1088,6 +1091,9 @@ Requirements:
a pull request. This ensures we have a unified code style.
- Mark test modules with pytest markers depending on the daemons used during the
tests (see :ref:`topotests-markers`)
+- Always use IPv4 :rfc:`5737` (``192.0.2.0/24``, ``198.51.100.0/24``,
+ ``203.0.113.0/24``) and IPv6 :rfc:`3849` (``2001:db8::/32``) ranges reserved
+ for documentation.
Tips:
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 45bee17b71..af8756a909 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -346,6 +346,13 @@ Pre-submission Checklist
the new feature within our existing CI infrastructure. Also the
addition of automated testing to cover any pull request is encouraged.
+- All new code must use the current latest version of acceptable code.
+
+ - If a daemon is converted to YANG, then new code must use YANG.
+ - DEFPY's must be used for new cli
+ - Typesafe lists must be used
+ - printf formatting changes must be used
+
.. _signing-off:
Signing Off
@@ -1250,8 +1257,8 @@ CLI changes
-----------
CLI's are a complicated ugly beast. Additions or changes to the CLI should use
-a DEFUN to encapsulate one setting as much as is possible. Additionally as new
-DEFUN's are added to the system, documentation should be provided for the new
+a DEFPY to encapsulate one setting as much as is possible. Additionally as new
+DEFPY's are added to the system, documentation should be provided for the new
commands.
Backwards Compatibility
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 21432039c1..4c196cfcfe 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -673,6 +673,11 @@ Terminal Mode Commands
we are setting each individual fd for the poll command at that point
in time.
+.. clicmd:: show thread timers
+
+ This command displays FRR's timer data for timers that will pop in
+ the future.
+
.. _common-invocation-options:
Common Invocation Options
diff --git a/doc/user/index.rst b/doc/user/index.rst
index cadf4cb9cf..5a018a5583 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -54,6 +54,7 @@ Protocols
ospf6d
pathd
pim
+ pimv6
pbr
ripd
ripngd
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/pim.rst b/doc/user/pim.rst
index 1c3a0110ac..30363dfdf6 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -505,10 +505,12 @@ cause great confusion.
Display information about a S,G pair and how the RPF would be chosen. This
is especially useful if there are ECMP's available from the RPF lookup.
-.. clicmd:: show ip pim rp-info
+.. clicmd:: show ip pim [vrf NAME] rp-info [A.B.C.D/M] [json]
Display information about RP's that are configured on this router.
+ You can filter the output by specifying an arbitrary group.
+
.. clicmd:: show ip pim rpf
Display information about currently being used S,G's and their RPF lookup
diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst
new file mode 100644
index 0000000000..e71cf4631c
--- /dev/null
+++ b/doc/user/pimv6.rst
@@ -0,0 +1,288 @@
+.. _pimv6:
+
+*****
+PIMv6
+*****
+
+PIMv6 -- Protocol Independent Multicast for IPv6
+
+*pim6d* supports pim-sm as well as MLD v1 and v2. PIMv6 is
+vrf aware and can work within the context of vrf's in order to
+do S,G mrouting.
+
+.. _starting-and-stopping-pim6d:
+
+Starting and Stopping pim6d
+===========================
+
+The default configuration file name of *pim6d*'s is :file:`pim6d.conf`. When
+invoked *pim6d* searches directory |INSTALL_PREFIX_ETC|. If
+:file:`pim6d.conf` is not there then next search current directory.
+
+*pim6d* requires zebra for proper operation. Additionally *pim6d* depends on
+routing properly setup and working in the network that it is working on.
+
+::
+
+ # zebra -d
+ # pim6d -d
+
+
+Please note that *zebra* must be invoked before *pim6d*.
+
+To stop *pim6d* please use::
+
+ kill `cat /var/run/pim6d.pid`
+
+Certain signals have special meanings to *pim6d*.
+
++---------+---------------------------------------------------------------------+
+| Signal | Meaning |
++=========+=====================================================================+
+| SIGUSR1 | Rotate the *pim6d* logfile |
++---------+---------------------------------------------------------------------+
+| SIGINT | *pim6d* sweeps all installed PIM mroutes then terminates gracefully.|
+| SIGTERM | |
++---------+---------------------------------------------------------------------+
+
+*pim6d* invocation options. Common options that can be specified
+(:ref:`common-invocation-options`).
+
+.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M
+
+ In order to use pimv6, it is necessary to configure a RP for join messages to
+ be sent to. Currently the only methodology to do this is via static rp
+ commands. All routers in the pimv6 network must agree on these values. The
+ first ipv6 address is the RP's address and the second value is the matching
+ prefix of group ranges covered. This command is vrf aware, to configure for
+ a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD
+
+ This CLI helps in configuring RP address for a range of groups specified
+ by the prefix-list.
+
+.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535)
+
+ Modify the time out value for a S,G flow from 1-65535 seconds at RP.
+ The normal keepalive period for the KAT(S,G) defaults to 210 seconds.
+ However, at the RP, the keepalive period must be at least the
+ Register_Suppression_Time, or the RP may time out the (S,G) state
+ before the next Null-Register arrives. Thus, the KAT(S,G) is set to
+ max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent.
+ If choosing a value below 31 seconds be aware that some hardware platforms
+ cannot see data flowing in better than 30 second chunks. This command is
+ vrf aware, to configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST]
+
+ On the last hop router if it is desired to not switch over to the SPT tree
+ configure this command. Optional parameter prefix-list can be use to control
+ which groups to switch or not switch. If a group is PERMIT as per the
+ PLIST, then the SPT switchover does not happen for it and if it is DENY,
+ then the SPT switchover happens.
+ This command is vrf aware, to configure for a vrf,
+ enter the vrf submode.
+
+.. clicmd:: ipv6 pim join-prune-interval (1-65535)
+
+ Modify the join/prune interval that pim uses to the new value. Time is
+ specified in seconds. This command is vrf aware, to configure for a vrf,
+ enter the vrf submode. The default time is 60 seconds. If you enter
+ a value smaller than 60 seconds be aware that this can and will affect
+ convergence at scale.
+
+.. clicmd:: ipv6 pim keep-alive-timer (1-65535)
+
+ Modify the time out value for a S,G flow from 1-65535 seconds. If choosing
+ a value below 31 seconds be aware that some hardware platforms cannot see data
+ flowing in better than 30 second chunks. This command is vrf aware, to
+ configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim packets (1-255)
+
+ When processing packets from a neighbor process the number of packets
+ incoming at one time before moving on to the next task. The default value is
+ 3 packets. This command is only useful at scale when you can possibly have
+ a large number of pim control packets flowing. This command is vrf aware, to
+ configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim register-suppress-time (1-65535)
+
+ Modify the time that pim will register suppress a FHR will send register
+ notifications to the kernel. This command is vrf aware, to configure for a
+ vrf, enter the vrf submode.
+
+.. _pimv6-interface-configuration:
+
+PIMv6 Interface Configuration
+=============================
+
+PIMv6 interface commands allow you to configure an interface as either a Receiver
+or a interface that you would like to form pimv6 neighbors on. If the interface
+is in a vrf, enter the interface command with the vrf keyword at the end.
+
+.. clicmd:: ipv6 pim active-active
+
+ Turn on pim active-active configuration for a Vxlan interface. This
+ command will not do anything if you do not have the underlying ability
+ of a mlag implementation.
+
+.. clicmd:: ipv6 pim drpriority (1-4294967295)
+
+ Set the DR Priority for the interface. This command is useful to allow the
+ user to influence what node becomes the DR for a lan segment.
+
+.. clicmd:: ipv6 pim hello (1-65535) (1-65535)
+
+ Set the pim hello and hold interval for a interface.
+
+.. clicmd:: ipv6 pim
+
+ Tell pim that we would like to use this interface to form pim neighbors
+ over. Please note that this command does not enable the reception of MLD
+ reports on the interface. Refer to the next ``ipv6 mld`` command for MLD
+ management.
+
+.. clicmd:: ipv6 pim use-source X:X::X:X
+
+ If you have multiple addresses configured on a particular interface
+ and would like pim to use a specific source address associated with
+ that interface.
+
+.. clicmd:: ipv6 mld
+
+ Tell pim to receive MLD reports and Query on this interface. The default
+ version is v2. This command is useful on a LHR.
+
+.. clicmd:: ipv6 mld join X:X::X:X [Y:Y::Y:Y]
+
+ Join multicast group or source-group on an interface.
+
+.. clicmd:: ipv6 mld query-interval (1-65535)
+
+ Set the MLD query interval that PIM will use.
+
+.. clicmd:: ipv6 mld query-max-response-time (1-65535)
+
+ Set the MLD query response timeout value. If an report is not returned in
+ the specified time we will assume the S,G or \*,G has timed out.
+
+.. clicmd:: ipv6 mld version (1-2)
+
+ Set the MLD version used on this interface. The default value is 2.
+
+.. clicmd:: ipv6 multicast boundary oil WORD
+
+ Set a PIMv6 multicast boundary, based upon the WORD prefix-list. If a PIMv6
+ join or MLD report is received on this interface and the Group is denied by
+ the prefix-list, PIMv6 will ignore the join or report.
+
+.. clicmd:: ipv6 mld last-member-query-count (1-255)
+
+ Set the MLD last member query count. The default value is 2. 'no' form of
+ this command is used to configure back to the default value.
+
+.. clicmd:: ipv6 MLD last-member-query-interval (1-65535)
+
+ Set the MLD last member query interval in deciseconds. The default value is
+ 10 deciseconds. 'no' form of this command is used to to configure back to the
+ default value.
+
+.. clicmd:: ipv6 mroute INTERFACE X:X::X:X [Y:Y::Y:Y]
+
+ Set a static multicast route for a traffic coming on the current interface to
+ be forwarded on the given interface if the traffic matches the group address
+ and optionally the source address.
+
+.. _show-pimv6-information:
+
+Show PIMv6 Information
+======================
+
+All PIMv6 show commands are vrf aware and typically allow you to insert a
+specified vrf command if information is desired about a specific vrf. If no
+vrf is specified then the default vrf is assumed. Finally the special keyword
+'all' allows you to look at all vrfs for the command. Naming a vrf 'all' will
+cause great confusion.
+
+.. clicmd:: show ipv6 pim [vrf NAME] group-type [json]
+
+ Display SSM group ranges.
+
+.. clicmd:: show ipv6 pim interface
+
+ Display information about interfaces PIM is using.
+
+.. clicmd:: show ipv6 pim [vrf NAME] join [X:X::X:X [X:X::X:X]] [json]
+.. clicmd:: show ipv6 pim vrf all join [json]
+
+ Display information about PIM joins received. If one address is specified
+ then we assume it is the Group we are interested in displaying data on.
+ If the second address is specified then it is Source Group.
+
+.. clicmd:: show ipv6 pim [vrf NAME] local-membership [json]
+
+ Display information about PIM interface local-membership.
+
+.. clicmd:: show ipv6 pim [vrf NAME] neighbor [detail|WORD] [json]
+.. clicmd:: show ipv6 pim vrf all neighbor [detail|WORD] [json]
+
+ Display information about PIM neighbors.
+
+.. clicmd:: show ipv6 pim [vrf NAME] nexthop
+
+ Display information about pim nexthops that are being used.
+
+.. clicmd:: show ipv6 pim [vrf NAME] nexthop-lookup X:X::X:X X:X::X:X
+
+ Display information about a S,G pair and how the RPF would be chosen. This
+ is especially useful if there are ECMP's available from the RPF lookup.
+
+.. clicmd:: show ipv6 pim [vrf NAME] rp-info [json]
+.. clicmd:: show ipv6 pim vrf all rp-info [json]
+
+ Display information about RP's that are configured on this router.
+
+.. clicmd:: show ipv6 pim [vrf NAME] rpf [json]
+.. clicmd:: show ipv6 pim vrf all rpf [json]
+
+ Display information about currently being used S,G's and their RPF lookup
+ information. Additionally display some statistics about what has been
+ happening on the router.
+
+.. clicmd:: show ipv6 pim [vrf NAME] secondary
+
+ Display information about an interface and all the secondary addresses
+ associated with it.
+
+.. clicmd:: show ipv6 pim [vrf NAME] state [X:X::X:X [X:X::X:X]] [json]
+.. clicmd:: show ipv6 pim vrf all state [X:X::X:X [X:X::X:X]] [json]
+
+ Display information about known S,G's and incoming interface as well as the
+ OIL and how they were chosen.
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream [X:X::X:X [Y:Y::Y:Y]] [json]
+.. clicmd:: show ipv6 pim vrf all upstream [json]
+
+ Display upstream information about a S,G mroute. Allow the user to
+ specify sub Source and Groups that we are interested in.
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream-join-desired [json]
+
+ Display upstream information for S,G's and if we desire to
+ join the multicast tree
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream-rpf [json]
+
+ Display upstream information for S,G's and the RPF data associated with them.
+
+PIMv6 Debug Commands
+====================
+
+The debugging subsystem for PIMv6 behaves in accordance with how FRR handles
+debugging. You can specify debugging at the enable CLI mode as well as the
+configure CLI mode. If you specify debug commands in the configuration cli
+mode, the debug commands can be persistent across restarts of the FRR pim6d if
+the config was written out.
+
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index 31158cb5f7..14ace2c856 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -30,6 +30,7 @@ user_RSTFILES = \
doc/user/packet-dumps.rst \
doc/user/pathd.rst \
doc/user/pim.rst \
+ doc/user/pimv6.rst \
doc/user/ripd.rst \
doc/user/pbr.rst \
doc/user/ripngd.rst \
diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst
index ec674e377c..97b3863ef5 100644
--- a/doc/user/vtysh.rst
+++ b/doc/user/vtysh.rst
@@ -29,6 +29,30 @@ administrator with an external editor.
vtysh.
+Live logs
+=========
+
+.. clicmd:: terminal monitor [DAEMON]
+
+ Receive and display log messages.
+
+ It is not currently possible to change the minimum message priority (fixed
+ to debug) or output formatting. These will likely be made configurable in
+ the future.
+
+ Log messages are received asynchronously and may be printed both during
+ command execution as well as while on the prompt. They are printed to
+ stderr, unlike regular CLI output which is printed to stdout. The intent is
+ that stdin/stdout might be driven by some script while log messages are
+ visible on stderr. If stdout and stderr are the same file, the prompt and
+ pending input will be cleared and reprinted appropriately.
+
+ .. note::
+
+ If ``vtysh`` cannot keep up, some log messages may be lost. The daemons
+ do **not** wait for, get blocked by, or buffer messages for ``vtysh``.
+
+
Pager usage
===========
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 7ca473ceb6..221e9c6fe2 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -29,6 +29,9 @@ 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
+ route and the route types in this case will show up as a static route
+ with an admin distance of 255.
.. option:: -r, --retain
@@ -78,6 +81,11 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
protocols about route installation/update on ack received from
the linux kernel or from offload notification.
+.. option:: -s <SIZE>, --nl-bufsize <SIZE>
+
+ Allow zebra to modify the default receive buffer size to SIZE
+ in bytes. Under \*BSD only the -s option is available.
+
.. _interface-commands:
Configuration Addresses behaviour
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_nb_notifications.c b/isisd/isis_nb_notifications.c
index f219632acf..fd7b1b3159 100644
--- a/isisd/isis_nb_notifications.c
+++ b/isisd/isis_nb_notifications.c
@@ -245,7 +245,7 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, max_area_addrs);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_max_area_addr_mismatch, circuit, max_area_addrs,
@@ -270,7 +270,7 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_authentication_type_failure, circuit, raw_pdu,
@@ -294,7 +294,7 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_authentication_failure, circuit, raw_pdu,
@@ -361,7 +361,7 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
data = yang_data_new_string(xpath_arg, reason);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_reject_adjacency, circuit, raw_pdu, raw_pdu_len);
@@ -384,7 +384,7 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_area_mismatch, circuit, raw_pdu, raw_pdu_len);
@@ -467,7 +467,7 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, rcv_id_len);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_id_len_mismatch, circuit, rcv_id_len, raw_pdu,
@@ -495,7 +495,7 @@ void isis_notif_version_skew(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, version);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_version_skew, circuit, version, raw_pdu,
@@ -525,7 +525,7 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit,
data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
+ data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
/* ignore offset and tlv_type which cannot be set properly */
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/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
index 7bad1dca7c..c4053f5374 100644
--- a/ldpd/ldp_vty_exec.c
+++ b/ldpd/ldp_vty_exec.c
@@ -1472,7 +1472,11 @@ show_l2vpn_pw_msg_json(struct imsg *imsg, struct show_params *params,
json_pw = json_object_new_object();
json_object_string_addf(json_pw, "peerId", "%pI4", &pw->lsr_id);
json_object_int_add(json_pw, "vcId", pw->pwid);
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
json_object_string_add(json_pw, "VpnName", pw->l2vpn_name);
+ json_object_string_add(json_pw, "vpnName", pw->l2vpn_name);
if (pw->status == PW_FORWARDING)
json_object_string_add(json_pw, "status", "up");
else
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 0000000000..e3f238969b
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,193 @@
+/*
+ * This is part of the libb64 project, and has been placed in the public domain.
+ * For details, see http://sourceforge.net/projects/libb64
+ */
+
+#include "base64.h"
+
+static const int CHARS_PER_LINE = 72;
+static const char *ENCODING =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+void base64_init_encodestate(struct base64_encodestate *state_in)
+{
+ state_in->step = step_A;
+ state_in->result = 0;
+ state_in->stepcount = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+ if (value_in > 63)
+ return '=';
+ return ENCODING[(int)value_in];
+}
+
+int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
+ struct base64_encodestate *state_in)
+{
+ const char *plainchar = plaintext_in;
+ const char *const plaintextend = plaintext_in + length_in;
+ char *codechar = code_out;
+ char result;
+ char fragment;
+
+ result = state_in->result;
+
+ switch (state_in->step) {
+ while (1) {
+ case step_A:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_A;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result = (fragment & 0x0fc) >> 2;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x003) << 4;
+ /* fall through */
+ case step_B:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_B;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0f0) >> 4;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x00f) << 2;
+ /* fall through */
+ case step_C:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_C;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0c0) >> 6;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x03f) >> 0;
+ *codechar++ = base64_encode_value(result);
+
+ ++(state_in->stepcount);
+ if (state_in->stepcount == CHARS_PER_LINE/4) {
+ *codechar++ = '\n';
+ state_in->stepcount = 0;
+ }
+ }
+ }
+ /* control should not reach here */
+ return codechar - code_out;
+}
+
+int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
+{
+ char *codechar = code_out;
+
+ switch (state_in->step) {
+ case step_B:
+ *codechar++ = base64_encode_value(state_in->result);
+ *codechar++ = '=';
+ *codechar++ = '=';
+ break;
+ case step_C:
+ *codechar++ = base64_encode_value(state_in->result);
+ *codechar++ = '=';
+ break;
+ case step_A:
+ break;
+ }
+ *codechar++ = '\n';
+
+ return codechar - code_out;
+}
+
+
+signed char base64_decode_value(signed char value_in)
+{
+ static const signed char decoding[] = {
+ 62, -1, -1, -1, 63, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, -1,
+ -1, -1, -2, -1, -1, -1, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25,
+ -1, -1, -1, -1, -1, -1, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51
+ };
+ value_in -= 43;
+ if (value_in < 0 || value_in >= 80)
+ return -1;
+ return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(struct base64_decodestate *state_in)
+{
+ state_in->step = step_a;
+ state_in->plainchar = 0;
+}
+
+int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
+ struct base64_decodestate *state_in)
+{
+ const char *codec = code_in;
+ char *plainc = plaintext_out;
+ signed char fragmt;
+
+ *plainc = state_in->plainchar;
+
+ switch (state_in->step) {
+ while (1) {
+ case step_a:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_a;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc = (fragmt & 0x03f) << 2;
+ /* fall through */
+ case step_b:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_b;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x030) >> 4;
+ *plainc = (fragmt & 0x00f) << 4;
+ /* fall through */
+ case step_c:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_c;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x03c) >> 2;
+ *plainc = (fragmt & 0x003) << 6;
+ /* fall through */
+ case step_d:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_d;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x03f);
+ }
+ }
+ /* control should not reach here */
+ return plainc - plaintext_out;
+}
diff --git a/lib/base64.h b/lib/base64.h
new file mode 100644
index 0000000000..3dc1559aa4
--- /dev/null
+++ b/lib/base64.h
@@ -0,0 +1,45 @@
+/*
+ * This is part of the libb64 project, and has been placed in the public domain.
+ * For details, see http://sourceforge.net/projects/libb64
+ */
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+enum base64_encodestep {
+ step_A, step_B, step_C
+};
+
+struct base64_encodestate {
+ enum base64_encodestep step;
+ char result;
+ int stepcount;
+};
+
+void base64_init_encodestate(struct base64_encodestate *state_in);
+
+char base64_encode_value(char value_in);
+
+int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
+ struct base64_encodestate *state_in);
+
+int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in);
+
+
+enum base64_decodestep {
+ step_a, step_b, step_c, step_d
+};
+
+struct base64_decodestate {
+ enum base64_decodestep step;
+ char plainchar;
+};
+
+void base64_init_decodestate(struct base64_decodestate *state_in);
+
+signed char base64_decode_value(signed char value_in);
+
+int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
+ struct base64_decodestate *state_in);
+
+#endif /* _BASE64_H_ */
diff --git a/lib/checksum.c b/lib/checksum.c
index 3473370041..6c5f06de45 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -9,13 +9,24 @@
#include <zebra.h>
#include "checksum.h"
-int /* return checksum in low-order 16 bits */
- in_cksum(void *parg, int nbytes)
+#define add_carry(dst, add) \
+ do { \
+ typeof(dst) _add = (add); \
+ dst += _add; \
+ if (dst < _add) \
+ dst++; \
+ } while (0)
+
+uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
{
- unsigned short *ptr = parg;
- register long sum; /* assumes long == 32 bits */
- unsigned short oddbyte;
- register unsigned short answer; /* assumes unsigned short == 16 bits */
+ const struct iovec *iov_end;
+ uint32_t sum = 0;
+
+ union {
+ uint8_t bytes[2];
+ uint16_t word;
+ } wordbuf;
+ bool have_oddbyte = false;
/*
* Our algorithm is simple, using a 32-bit accumulator (sum),
@@ -23,17 +34,42 @@ int /* return checksum in low-order 16 bits */
* all the carry bits from the top 16 bits into the lower 16 bits.
*/
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
+ for (iov_end = iov + iov_len; iov < iov_end; iov++) {
+ const uint8_t *ptr, *end;
+
+ ptr = (const uint8_t *)iov->iov_base;
+ end = ptr + iov->iov_len;
+ if (ptr == end)
+ continue;
+
+ if (have_oddbyte) {
+ have_oddbyte = false;
+ wordbuf.bytes[1] = *ptr++;
+
+ add_carry(sum, wordbuf.word);
+ }
+
+ while (ptr + 8 <= end) {
+ add_carry(sum, *(const uint32_t *)(ptr + 0));
+ add_carry(sum, *(const uint32_t *)(ptr + 4));
+ ptr += 8;
+ }
+
+ while (ptr + 2 <= end) {
+ add_carry(sum, *(const uint16_t *)ptr);
+ ptr += 2;
+ }
+
+ if (ptr + 1 <= end) {
+ wordbuf.bytes[0] = *ptr++;
+ have_oddbyte = true;
+ }
}
/* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- oddbyte = 0; /* make sure top half is zero */
- *((uint8_t *)&oddbyte) = *(uint8_t *)ptr; /* one byte only */
- sum += oddbyte;
+ if (have_oddbyte) {
+ wordbuf.bytes[1] = 0;
+ add_carry(sum, wordbuf.word);
}
/*
@@ -42,26 +78,7 @@ int /* return checksum in low-order 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
sum += (sum >> 16); /* add carry */
- answer = ~sum; /* ones-complement, then truncate to 16 bits */
- return (answer);
-}
-
-int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes)
-{
- uint8_t dat[sizeof(struct ipv4_ph) + nbytes];
-
- memcpy(dat, ph, sizeof(struct ipv4_ph));
- memcpy(dat + sizeof(struct ipv4_ph), data, nbytes);
- return in_cksum(dat, sizeof(dat));
-}
-
-int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes)
-{
- uint8_t dat[sizeof(struct ipv6_ph) + nbytes];
-
- memcpy(dat, ph, sizeof(struct ipv6_ph));
- memcpy(dat + sizeof(struct ipv6_ph), data, nbytes);
- return in_cksum(dat, sizeof(dat));
+ return ~sum;
}
/* Fletcher Checksum -- Refer to RFC1008. */
diff --git a/lib/checksum.h b/lib/checksum.h
index 56771d4f24..508c3f38a6 100644
--- a/lib/checksum.h
+++ b/lib/checksum.h
@@ -1,3 +1,6 @@
+#ifndef _FRR_CHECKSUM_H
+#define _FRR_CHECKSUM_H
+
#include <stdint.h>
#include <netinet/in.h>
@@ -24,9 +27,41 @@ struct ipv6_ph {
uint8_t next_hdr;
} __attribute__((packed));
-extern int in_cksum(void *data, int nbytes);
-extern int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes);
-extern int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes);
+
+extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len);
+
+static inline uint16_t in_cksum(const void *data, size_t nbytes)
+{
+ struct iovec iov[1];
+
+ iov[0].iov_base = (void *)data;
+ iov[0].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
+
+static inline uint16_t in_cksum_with_ph4(const struct ipv4_ph *ph,
+ const void *data, size_t nbytes)
+{
+ struct iovec iov[2];
+
+ iov[0].iov_base = (void *)ph;
+ iov[0].iov_len = sizeof(*ph);
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
+
+static inline uint16_t in_cksum_with_ph6(const struct ipv6_ph *ph,
+ const void *data, size_t nbytes)
+{
+ struct iovec iov[2];
+
+ iov[0].iov_base = (void *)ph;
+ iov[0].iov_len = sizeof(*ph);
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
#define FLETCHER_CHECKSUM_VALIDATE 0xffff
extern uint16_t fletcher_checksum(uint8_t *, const size_t len,
@@ -35,3 +70,5 @@ extern uint16_t fletcher_checksum(uint8_t *, const size_t len,
#ifdef __cplusplus
}
#endif
+
+#endif /* _FRR_CHECKSUM_H */
diff --git a/lib/json.c b/lib/json.c
index 854a3d59d1..d85a21215c 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -74,6 +74,19 @@ void json_object_string_addv(struct json_object *obj, const char *key,
json_object_object_add(obj, key, json_object_new_stringv(fmt, args));
}
+void json_object_object_addv(struct json_object *parent,
+ struct json_object *child, const char *keyfmt,
+ va_list args)
+{
+ char *text, buf[256];
+
+ text = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), keyfmt, args);
+ json_object_object_add(parent, text, child);
+
+ if (text != buf)
+ XFREE(MTYPE_TMP, text);
+}
+
void json_object_int_add(struct json_object *obj, const char *key, int64_t i)
{
json_object_object_add(obj, key, json_object_new_int64(i));
diff --git a/lib/json.h b/lib/json.h
index fcaa84c816..78c3836515 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -116,6 +116,28 @@ static inline struct json_object *json_object_new_stringf(const char *fmt, ...)
return ret;
}
+/* NOTE: argument order differs! (due to varargs)
+ * json_object_object_add(parent, key, child)
+ * json_object_object_addv(parent, child, key, va)
+ * json_object_object_addf(parent, child, key, ...)
+ * (would be weird to have the child inbetween the format string and args)
+ */
+PRINTFRR(3, 0)
+extern void json_object_object_addv(struct json_object *parent,
+ struct json_object *child,
+ const char *keyfmt, va_list args);
+PRINTFRR(3, 4)
+static inline void json_object_object_addf(struct json_object *parent,
+ struct json_object *child,
+ const char *keyfmt, ...)
+{
+ va_list args;
+
+ va_start(args, keyfmt);
+ json_object_object_addv(parent, child, keyfmt, args);
+ va_end(args);
+}
+
#define JSON_STR "JavaScript Object Notation\n"
/* NOTE: json-c lib has following commit 316da85 which
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 10b3aad89e..042c9d3704 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -333,6 +333,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
umask(0027);
+ log_args_init(daemon->early_logging);
+
opt_extend(&os_always);
if (!(di->flags & FRR_NO_SPLIT_CONFIG))
opt_extend(&os_cfg);
@@ -431,6 +433,8 @@ static int frr_opt(int opt)
static int vty_port_set = 0;
static int vty_addr_set = 0;
struct option_chain *oc;
+ struct log_arg *log_arg;
+ size_t arg_len;
char *err;
switch (opt) {
@@ -613,7 +617,10 @@ static int frr_opt(int opt)
di->privs->group = optarg;
break;
case OPTION_LOG:
- di->early_logging = optarg;
+ arg_len = strlen(optarg) + 1;
+ log_arg = XCALLOC(MTYPE_TMP, sizeof(*log_arg) + arg_len);
+ memcpy(log_arg->target, optarg, arg_len);
+ log_args_add_tail(di->early_logging, log_arg);
break;
case OPTION_LOGLEVEL:
di->early_loglevel = optarg;
@@ -706,10 +713,12 @@ static struct thread_master *master;
struct thread_master *frr_init(void)
{
struct option_chain *oc;
+ struct log_arg *log_arg;
struct frrmod_runtime *module;
struct zprivs_ids_t ids;
char p_instance[16] = "", p_pathspace[256] = "";
const char *dir;
+
dir = di->module_path ? di->module_path : frr_moduledir;
srandom(time(NULL));
@@ -739,7 +748,11 @@ struct thread_master *frr_init(void)
zlog_init(di->progname, di->logname, di->instance,
ids.uid_normal, ids.gid_normal);
- command_setup_early_logging(di->early_logging, di->early_loglevel);
+ while ((log_arg = log_args_pop(di->early_logging))) {
+ command_setup_early_logging(log_arg->target,
+ di->early_loglevel);
+ XFREE(MTYPE_TMP, log_arg);
+ }
if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
frr_zclientpath)) {
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 65c1df9675..69054e4264 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -21,6 +21,7 @@
#ifndef _ZEBRA_FRR_H
#define _ZEBRA_FRR_H
+#include "typesafe.h"
#include "sigevent.h"
#include "privs.h"
#include "thread.h"
@@ -52,6 +53,14 @@ extern "C" {
*/
#define FRR_DETACH_LATER (1 << 6)
+PREDECL_DLIST(log_args);
+struct log_arg {
+ struct log_args_item itm;
+
+ char target[0];
+};
+DECLARE_DLIST(log_args, struct log_arg, itm);
+
enum frr_cli_mode {
FRR_CLI_CLASSIC = 0,
FRR_CLI_TRANSACTIONAL,
@@ -88,7 +97,7 @@ struct frr_daemon_info {
const char *pathspace;
bool zpathspace;
- const char *early_logging;
+ struct log_args_head early_logging[1];
const char *early_loglevel;
const char *proghelp;
diff --git a/lib/log_vty.c b/lib/log_vty.c
index 682c9ea372..81280f302f 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -159,6 +159,7 @@ void zlog_rotate(void)
{
zlog_file_rotate(&zt_file);
zlog_file_rotate(&zt_filterfile.parent);
+ zlog_file_rotate(&zt_file_cmdline);
hook_call(zlog_rotate);
}
@@ -427,6 +428,22 @@ void command_setup_early_logging(const char *dest, const char *level)
set_log_file(&zt_file_cmdline, NULL, sep, nlevel);
return;
}
+ if (strcmp(type, "monitor") == 0 && sep) {
+ struct zlog_live_cfg cfg = {};
+ unsigned long fd;
+ char *endp;
+
+ sep++;
+ fd = strtoul(sep, &endp, 10);
+ if (!*sep || *endp) {
+ fprintf(stderr, "invalid monitor fd \"%s\"\n", sep);
+ exit(1);
+ }
+
+ zlog_live_open_fd(&cfg, nlevel, fd);
+ zlog_live_disown(&cfg);
+ return;
+ }
fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest);
exit(1);
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 34bb1e4986..dda1756214 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
@@ -39,6 +39,11 @@
#define GRPC_DEFAULT_PORT 50051
+
+// ------------------------------------------------------
+// File Local Variables
+// ------------------------------------------------------
+
/*
* NOTE: we can't use the FRR debugging infrastructure here since it uses
* atomics and C++ has a different atomics API. Enable gRPC debugging
@@ -50,6 +55,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) \
@@ -76,7 +83,7 @@ class Candidates
{
// Delete candidates.
for (auto it = _cdb.begin(); it != _cdb.end(); it++)
- delete_candidate(&it->second);
+ delete_candidate(it->first);
}
struct candidate *create_candidate(void)
@@ -92,123 +99,106 @@ class Candidates
return c;
}
- void delete_candidate(struct candidate *c)
+ bool contains(uint64_t candidate_id)
+ {
+ return _cdb.count(candidate_id) > 0;
+ }
+
+ void delete_candidate(uint64_t candidate_id)
{
+ struct candidate *c = &_cdb[candidate_id];
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)
+ struct candidate *get_candidate(uint64_t id)
{
return _cdb.count(id) == 0 ? NULL : &_cdb[id];
}
private:
uint64_t _next_id = 0;
- std::map<uint32_t, struct candidate> _cdb;
+ std::map<uint64_t, struct candidate> _cdb;
};
+/*
+ * RpcStateBase is the common base class used to track a gRPC RPC.
+ */
class RpcStateBase
{
public:
- virtual CallState doCallback() = 0;
virtual void do_request(::frr::Northbound::AsyncService *service,
- ::grpc::ServerCompletionQueue *cq) = 0;
-};
+ ::grpc::ServerCompletionQueue *cq,
+ bool no_copy) = 0;
-/*
- * The RPC state class is used to track the execution of an RPC.
- */
-template <typename Q, typename S> class NewRpcState : RpcStateBase
-{
- typedef void (frr::Northbound::AsyncService::*reqfunc_t)(
- ::grpc::ServerContext *, Q *,
- ::grpc::ServerAsyncResponseWriter<S> *,
- ::grpc::CompletionQueue *, ::grpc::ServerCompletionQueue *,
- void *);
- typedef void (frr::Northbound::AsyncService::*reqsfunc_t)(
- ::grpc::ServerContext *, Q *, ::grpc::ServerAsyncWriter<S> *,
- ::grpc::CompletionQueue *, ::grpc::ServerCompletionQueue *,
- void *);
+ RpcStateBase(const char *name) : name(name){};
- public:
- NewRpcState(Candidates *cdb, reqfunc_t rfunc,
- void (*cb)(NewRpcState<Q, S> *), const char *name)
- : requestf(rfunc), callback(cb), responder(&ctx),
- async_responder(&ctx), name(name), cdb(cdb){};
- NewRpcState(Candidates *cdb, reqsfunc_t rfunc,
- void (*cb)(NewRpcState<Q, S> *), const char *name)
- : requestsf(rfunc), callback(cb), responder(&ctx),
- async_responder(&ctx), name(name), cdb(cdb){};
-
- CallState doCallback() override
+ virtual ~RpcStateBase() = default;
+
+ CallState get_state() const
{
- CallState enter_state = this->state;
- CallState new_state;
- if (enter_state == FINISH) {
- grpc_debug("%s RPC FINISH -> DELETED", name);
- new_state = FINISH;
- } else {
- grpc_debug("%s RPC: %s -> PROCESS", name,
- call_states[this->state]);
- new_state = PROCESS;
- }
+ return state;
+ }
+
+ bool is_initial_process() const
+ {
+ /* Will always be true for Unary */
+ return entered_state == CREATE;
+ }
+
+ // Returns "more" status, if false caller can delete
+ bool run(frr::Northbound::AsyncService *service,
+ grpc::ServerCompletionQueue *cq)
+ {
+ /*
+ * We enter in either CREATE or MORE state, and transition to
+ * PROCESS state.
+ */
+ this->entered_state = this->state;
+ this->state = PROCESS;
+ grpc_debug("%s RPC: %s -> %s on grpc-io-thread", name,
+ call_states[this->entered_state],
+ call_states[this->state]);
/*
- * We are either in state CREATE, MORE or FINISH. If CREATE or
- * MORE move back to PROCESS, otherwise we are cleaning up
- * (FINISH) so leave it in that state. Run the callback on the
- * main threadmaster/pthread; and wait for expected transition
- * from main thread. If transition is to FINISH->DELETED.
- * delete us.
- *
- * We update the state prior to scheduling the callback which
- * may then update the state in the master pthread. Then we
- * obtain the lock in the condvar-check-loop as the callback
- * will be modifying updating the state value.
+ * We schedule the callback on the main pthread, and wait for
+ * the state to transition out of the PROCESS state. The new
+ * state will either be MORE or FINISH. It will always be FINISH
+ * for Unary RPCs.
*/
- this->state = new_state;
thread_add_event(main_master, c_callback, (void *)this, 0,
NULL);
+
pthread_mutex_lock(&this->cmux);
- while (this->state == new_state)
+ while (this->state == PROCESS)
pthread_cond_wait(&this->cond, &this->cmux);
pthread_mutex_unlock(&this->cmux);
- if (this->state == DELETED) {
- grpc_debug("%s RPC: -> [DELETED]", name);
- delete this;
- return DELETED;
- }
- return this->state;
- }
-
- void do_request(::frr::Northbound::AsyncService *service,
- ::grpc::ServerCompletionQueue *cq) override
- {
- grpc_debug("%s, posting a request for: %s", __func__, name);
- if (requestf) {
- NewRpcState<Q, S> *copy =
- new NewRpcState(cdb, requestf, callback, name);
- (service->*requestf)(&copy->ctx, &copy->request,
- &copy->responder, cq, cq, copy);
- } else {
- NewRpcState<Q, S> *copy =
- new NewRpcState(cdb, requestsf, callback, name);
- (service->*requestsf)(&copy->ctx, &copy->request,
- &copy->async_responder, cq, cq,
- copy);
+ grpc_debug("%s RPC in %s on grpc-io-thread", name,
+ call_states[this->state]);
+
+ if (this->state == FINISH) {
+ /*
+ * Server is done (FINISH) so prep to receive a new
+ * request of this type. We could do this earlier but
+ * that would mean we could be handling multiple same
+ * type requests in parallel without limit.
+ */
+ this->do_request(service, cq, false);
}
+ return true;
}
+ protected:
+ virtual CallState run_mainthread(struct thread *thread) = 0;
static void c_callback(struct thread *thread)
{
- auto _tag = static_cast<NewRpcState<Q, S> *>(thread->arg);
+ auto _tag = static_cast<RpcStateBase *>(thread->arg);
/*
* We hold the lock until the callback finishes and has updated
* _tag->state, then we signal done and release.
@@ -216,36 +206,131 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase
pthread_mutex_lock(&_tag->cmux);
CallState enter_state = _tag->state;
- grpc_debug("%s RPC running on main thread", _tag->name);
+ grpc_debug("%s RPC: running %s on main thread", _tag->name,
+ call_states[enter_state]);
- _tag->callback(_tag);
+ _tag->state = _tag->run_mainthread(thread);
- grpc_debug("%s RPC: %s -> %s", _tag->name,
+ grpc_debug("%s RPC: %s -> %s [main thread]", _tag->name,
call_states[enter_state], call_states[_tag->state]);
pthread_cond_signal(&_tag->cond);
pthread_mutex_unlock(&_tag->cmux);
return;
}
- NewRpcState<Q, S> *orig;
- const char *name;
grpc::ServerContext ctx;
+ pthread_mutex_t cmux = PTHREAD_MUTEX_INITIALIZER;
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ CallState state = CREATE;
+ CallState entered_state;
+
+ public:
+ const char *name;
+};
+
+/*
+ * The UnaryRpcState class is used to track the execution of a Unary RPC.
+ *
+ * Template Args:
+ * Q - the request type for a given unary RPC
+ * S - the response type for a given unary RPC
+ */
+template <typename Q, typename S> class UnaryRpcState : public RpcStateBase
+{
+ public:
+ typedef void (frr::Northbound::AsyncService::*reqfunc_t)(
+ ::grpc::ServerContext *, Q *,
+ ::grpc::ServerAsyncResponseWriter<S> *,
+ ::grpc::CompletionQueue *, ::grpc::ServerCompletionQueue *,
+ void *);
+
+ UnaryRpcState(Candidates *cdb, reqfunc_t rfunc,
+ grpc::Status (*cb)(UnaryRpcState<Q, S> *),
+ const char *name)
+ : RpcStateBase(name), cdb(cdb), requestf(rfunc), callback(cb),
+ responder(&ctx){};
+
+ void do_request(::frr::Northbound::AsyncService *service,
+ ::grpc::ServerCompletionQueue *cq,
+ bool no_copy) override
+ {
+ grpc_debug("%s, posting a request for: %s", __func__, name);
+ auto copy = no_copy ? this
+ : new UnaryRpcState(cdb, requestf, callback,
+ name);
+ (service->*requestf)(&copy->ctx, &copy->request,
+ &copy->responder, cq, cq, copy);
+ }
+
+ CallState run_mainthread(struct thread *thread) override
+ {
+ // Unary RPC are always finished, see "Unary" :)
+ grpc::Status status = this->callback(this);
+ responder.Finish(response, status, this);
+ return FINISH;
+ }
+
+ Candidates *cdb;
+
Q request;
S response;
grpc::ServerAsyncResponseWriter<S> responder;
- grpc::ServerAsyncWriter<S> async_responder;
- Candidates *cdb;
- void (*callback)(NewRpcState<Q, S> *);
- reqfunc_t requestf;
- reqsfunc_t requestsf;
+ grpc::Status (*callback)(UnaryRpcState<Q, S> *);
+ reqfunc_t requestf = NULL;
+};
- pthread_mutex_t cmux = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- void *context;
+/*
+ * The StreamRpcState class is used to track the execution of a Streaming RPC.
+ *
+ * Template Args:
+ * Q - the request type for a given streaming RPC
+ * S - the response type for a given streaming RPC
+ * X - the type used to track the streaming state
+ */
+template <typename Q, typename S, typename X>
+class StreamRpcState : public RpcStateBase
+{
+ public:
+ typedef void (frr::Northbound::AsyncService::*reqsfunc_t)(
+ ::grpc::ServerContext *, Q *, ::grpc::ServerAsyncWriter<S> *,
+ ::grpc::CompletionQueue *, ::grpc::ServerCompletionQueue *,
+ void *);
- CallState state = CREATE;
+ StreamRpcState(reqsfunc_t rfunc, bool (*cb)(StreamRpcState<Q, S, X> *),
+ const char *name)
+ : RpcStateBase(name), requestsf(rfunc), callback(cb),
+ async_responder(&ctx){};
+
+ void do_request(::frr::Northbound::AsyncService *service,
+ ::grpc::ServerCompletionQueue *cq,
+ bool no_copy) override
+ {
+ grpc_debug("%s, posting a request for: %s", __func__, name);
+ auto copy =
+ no_copy ? this
+ : new StreamRpcState(requestsf, callback, name);
+ (service->*requestsf)(&copy->ctx, &copy->request,
+ &copy->async_responder, cq, cq, copy);
+ }
+
+ CallState run_mainthread(struct thread *thread) override
+ {
+ if (this->callback(this))
+ return MORE;
+ else
+ return FINISH;
+ }
+
+ Q request;
+ S response;
+ grpc::ServerAsyncWriter<S> async_responder;
+
+ bool (*callback)(StreamRpcState<Q, S, X> *);
+ reqsfunc_t requestsf = NULL;
+
+ X context;
};
// ------------------------------------------------------
@@ -268,10 +353,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));
@@ -464,15 +549,11 @@ static grpc::Status get_path(frr::DataTree *dt, const std::string &path,
// RPC Callback Functions: run on main thread
// ------------------------------------------------------
-void HandleUnaryGetCapabilities(NewRpcState<frr::GetCapabilitiesRequest,
- frr::GetCapabilitiesResponse> *tag)
+grpc::Status HandleUnaryGetCapabilities(
+ UnaryRpcState<frr::GetCapabilitiesRequest, frr::GetCapabilitiesResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
// Response: string frr_version = 1;
tag->response.set_frr_version(FRR_VERSION);
@@ -498,30 +579,24 @@ void HandleUnaryGetCapabilities(NewRpcState<frr::GetCapabilitiesRequest,
tag->response.add_supported_encodings(frr::JSON);
tag->response.add_supported_encodings(frr::XML);
- /* Should we do this in the async process call? */
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
-
- /* Indicate we are done. */
- tag->state = FINISH;
+ return grpc::Status::OK;
}
-void HandleStreamingGet(NewRpcState<frr::GetRequest, frr::GetResponse> *tag)
-{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
+// Define the context variable type for this streaming handler
+typedef std::list<std::string> GetContextType;
- if (tag->state == FINISH) {
- delete static_cast<std::list<std::string> *>(tag->context);
- tag->state = DELETED;
- return;
- }
+bool HandleStreamingGet(
+ StreamRpcState<frr::GetRequest, frr::GetResponse, GetContextType> *tag)
+{
+ grpc_debug("%s: entered", __func__);
- if (!tag->context) {
- /* Creating, first time called for this RPC */
- auto mypaths = new std::list<std::string>();
- tag->context = mypaths;
+ auto mypathps = &tag->context;
+ if (tag->is_initial_process()) {
+ // Fill our context container first time through
+ grpc_debug("%s: initialize streaming state", __func__);
auto paths = tag->request.path();
for (const std::string &path : paths) {
- mypaths->push_back(std::string(path));
+ mypathps->push_back(std::string(path));
}
}
@@ -532,11 +607,9 @@ void HandleStreamingGet(NewRpcState<frr::GetRequest, frr::GetResponse> *tag)
// Request: bool with_defaults = 3;
bool with_defaults = tag->request.with_defaults();
- auto mypathps = static_cast<std::list<std::string> *>(tag->context);
if (mypathps->empty()) {
tag->async_responder.Finish(grpc::Status::OK, tag);
- tag->state = FINISH;
- return;
+ return false;
}
frr::GetResponse response;
@@ -554,86 +627,57 @@ void HandleStreamingGet(NewRpcState<frr::GetRequest, frr::GetResponse> *tag)
if (!status.ok()) {
tag->async_responder.WriteAndFinish(
response, grpc::WriteOptions(), status, tag);
- tag->state = FINISH;
- return;
+ return false;
}
mypathps->pop_back();
if (mypathps->empty()) {
tag->async_responder.WriteAndFinish(
response, grpc::WriteOptions(), grpc::Status::OK, tag);
- tag->state = FINISH;
+ return false;
} else {
tag->async_responder.Write(response, tag);
- tag->state = MORE;
+ return true;
}
}
-void HandleUnaryCreateCandidate(NewRpcState<frr::CreateCandidateRequest,
- frr::CreateCandidateResponse> *tag)
+grpc::Status HandleUnaryCreateCandidate(
+ UnaryRpcState<frr::CreateCandidateRequest, frr::CreateCandidateResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
struct candidate *candidate = tag->cdb->create_candidate();
- if (!candidate) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Can't create candidate configuration"),
- tag);
- } else {
- tag->response.set_candidate_id(candidate->id);
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- }
-
- tag->state = FINISH;
+ if (!candidate)
+ return grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED,
+ "Can't create candidate configuration");
+ tag->response.set_candidate_id(candidate->id);
+ return grpc::Status::OK;
}
-void HandleUnaryDeleteCandidate(NewRpcState<frr::DeleteCandidateRequest,
- frr::DeleteCandidateResponse> *tag)
+grpc::Status HandleUnaryDeleteCandidate(
+ UnaryRpcState<frr::DeleteCandidateRequest, frr::DeleteCandidateResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
+ grpc_debug("%s: entered", __func__);
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
-
- // Request: uint32 candidate_id = 1;
uint32_t candidate_id = tag->request.candidate_id();
grpc_debug("%s(candidate_id: %u)", __func__, candidate_id);
- struct candidate *candidate = tag->cdb->get_candidate(candidate_id);
- if (!candidate) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found"),
- tag);
- } else {
- tag->cdb->delete_candidate(candidate);
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- }
- tag->state = FINISH;
+ if (!tag->cdb->contains(candidate_id))
+ return grpc::Status(grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found");
+ tag->cdb->delete_candidate(candidate_id);
+ return grpc::Status::OK;
}
-void HandleUnaryUpdateCandidate(NewRpcState<frr::UpdateCandidateRequest,
- frr::UpdateCandidateResponse> *tag)
+grpc::Status HandleUnaryUpdateCandidate(
+ UnaryRpcState<frr::UpdateCandidateRequest, frr::UpdateCandidateResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
- // Request: uint32 candidate_id = 1;
uint32_t candidate_id = tag->request.candidate_id();
grpc_debug("%s(candidate_id: %u)", __func__, candidate_id);
@@ -641,76 +685,45 @@ void HandleUnaryUpdateCandidate(NewRpcState<frr::UpdateCandidateRequest,
struct candidate *candidate = tag->cdb->get_candidate(candidate_id);
if (!candidate)
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found"),
- tag);
- else if (candidate->transaction)
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "candidate is in the middle of a transaction"),
- tag);
- else if (nb_candidate_update(candidate->config) != NB_OK)
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::INTERNAL,
- "failed to update candidate configuration"),
- tag);
-
- else
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
+ return grpc::Status(grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found");
+ if (candidate->transaction)
+ return grpc::Status(
+ grpc::StatusCode::FAILED_PRECONDITION,
+ "candidate is in the middle of a transaction");
+ if (nb_candidate_update(candidate->config) != NB_OK)
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ "failed to update candidate configuration");
- tag->state = FINISH;
+ return grpc::Status::OK;
}
-void HandleUnaryEditCandidate(
- NewRpcState<frr::EditCandidateRequest, frr::EditCandidateResponse> *tag)
+grpc::Status HandleUnaryEditCandidate(
+ UnaryRpcState<frr::EditCandidateRequest, frr::EditCandidateResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
+ grpc_debug("%s: entered", __func__);
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
-
- // Request: uint32 candidate_id = 1;
uint32_t candidate_id = tag->request.candidate_id();
grpc_debug("%s(candidate_id: %u)", __func__, candidate_id);
struct candidate *candidate = tag->cdb->get_candidate(candidate_id);
-
- if (!candidate) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!candidate)
+ return grpc::Status(grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found");
struct nb_config *candidate_tmp = nb_config_dup(candidate->config);
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(
- tag->response,
- grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Failed to update \"" + pv.path()
- + "\""),
- tag);
-
- tag->state = FINISH;
- return;
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Failed to update \"" + pv.path() +
+ "\"");
}
}
@@ -718,36 +731,23 @@ void HandleUnaryEditCandidate(
for (const frr::PathValue &pv : pvs) {
if (yang_dnode_delete(candidate_tmp->dnode, pv.path()) != 0) {
nb_config_free(candidate_tmp);
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Failed to remove \"" + pv.path()
- + "\""),
- tag);
- tag->state = FINISH;
- return;
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Failed to remove \"" + pv.path() +
+ "\"");
}
}
// No errors, accept all changes.
nb_config_replace(candidate->config, candidate_tmp, false);
-
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
-
- tag->state = FINISH;
+ return grpc::Status::OK;
}
-void HandleUnaryLoadToCandidate(NewRpcState<frr::LoadToCandidateRequest,
- frr::LoadToCandidateResponse> *tag)
+grpc::Status HandleUnaryLoadToCandidate(
+ UnaryRpcState<frr::LoadToCandidateRequest, frr::LoadToCandidateResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
- // Request: uint32 candidate_id = 1;
uint32_t candidate_id = tag->request.candidate_id();
grpc_debug("%s(candidate_id: %u)", __func__, candidate_id);
@@ -757,59 +757,31 @@ void HandleUnaryLoadToCandidate(NewRpcState<frr::LoadToCandidateRequest,
// Request: DataTree config = 3;
auto config = tag->request.config();
-
struct candidate *candidate = tag->cdb->get_candidate(candidate_id);
-
- if (!candidate) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!candidate)
+ return grpc::Status(grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found");
struct lyd_node *dnode = dnode_from_data_tree(&config, true);
- if (!dnode) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INTERNAL,
- "Failed to parse the configuration"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!dnode)
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ "Failed to parse the configuration");
struct nb_config *loaded_config = nb_config_new(dnode);
-
if (load_type == frr::LoadToCandidateRequest::REPLACE)
nb_config_replace(candidate->config, loaded_config, false);
- else if (nb_config_merge(candidate->config, loaded_config, false)
- != NB_OK) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::INTERNAL,
- "Failed to merge the loaded configuration"),
- tag);
- tag->state = FINISH;
- return;
- }
+ else if (nb_config_merge(candidate->config, loaded_config, false) !=
+ NB_OK)
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ "Failed to merge the loaded configuration");
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- tag->state = FINISH;
+ return grpc::Status::OK;
}
-void HandleUnaryCommit(
- NewRpcState<frr::CommitRequest, frr::CommitResponse> *tag)
+grpc::Status
+HandleUnaryCommit(UnaryRpcState<frr::CommitRequest, frr::CommitResponse> *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
// Request: uint32 candidate_id = 1;
uint32_t candidate_id = tag->request.candidate_id();
@@ -823,15 +795,9 @@ void HandleUnaryCommit(
// Find candidate configuration.
struct candidate *candidate = tag->cdb->get_candidate(candidate_id);
- if (!candidate) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!candidate)
+ return grpc::Status(grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found");
int ret = NB_OK;
uint32_t transaction_id = 0;
@@ -840,29 +806,17 @@ void HandleUnaryCommit(
switch (phase) {
case frr::CommitRequest::PREPARE:
case frr::CommitRequest::ALL:
- if (candidate->transaction) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "candidate is in the middle of a transaction"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (candidate->transaction)
+ return grpc::Status(
+ grpc::StatusCode::FAILED_PRECONDITION,
+ "candidate is in the middle of a transaction");
break;
case frr::CommitRequest::ABORT:
case frr::CommitRequest::APPLY:
- if (!candidate->transaction) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "no transaction in progress"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!candidate->transaction)
+ return grpc::Status(
+ grpc::StatusCode::FAILED_PRECONDITION,
+ "no transaction in progress");
break;
default:
break;
@@ -942,53 +896,30 @@ void HandleUnaryCommit(
if (strlen(errmsg) > 0)
tag->response.set_error_message(errmsg);
- tag->responder.Finish(tag->response, status, tag);
- tag->state = FINISH;
+ return status;
}
-void HandleUnaryLockConfig(
- NewRpcState<frr::LockConfigRequest, frr::LockConfigResponse> *tag)
+grpc::Status HandleUnaryLockConfig(
+ UnaryRpcState<frr::LockConfigRequest, frr::LockConfigResponse> *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
+ grpc_debug("%s: entered", __func__);
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
-
- if (nb_running_lock(NB_CLIENT_GRPC, NULL)) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
- "running configuration is locked already"),
- tag);
- } else {
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- }
- tag->state = FINISH;
+ if (nb_running_lock(NB_CLIENT_GRPC, NULL))
+ return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
+ "running configuration is locked already");
+ return grpc::Status::OK;
}
-void HandleUnaryUnlockConfig(
- NewRpcState<frr::UnlockConfigRequest, frr::UnlockConfigResponse> *tag)
+grpc::Status HandleUnaryUnlockConfig(
+ UnaryRpcState<frr::UnlockConfigRequest, frr::UnlockConfigResponse> *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
+ grpc_debug("%s: entered", __func__);
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
-
- if (nb_running_unlock(NB_CLIENT_GRPC, NULL)) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "failed to unlock the running configuration"),
- tag);
- } else {
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- }
- tag->state = FINISH;
+ if (nb_running_unlock(NB_CLIENT_GRPC, NULL))
+ return grpc::Status(
+ grpc::StatusCode::FAILED_PRECONDITION,
+ "failed to unlock the running configuration");
+ return grpc::Status::OK;
}
static void list_transactions_cb(void *arg, int transaction_id,
@@ -1002,45 +933,34 @@ static void list_transactions_cb(void *arg, int transaction_id,
std::string(date), std::string(comment)));
}
-void HandleStreamingListTransactions(
- NewRpcState<frr::ListTransactionsRequest, frr::ListTransactionsResponse>
- *tag)
-{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- delete static_cast<std::list<std::tuple<
- int, std::string, std::string, std::string>> *>(
- tag->context);
- tag->state = DELETED;
- return;
- }
-
- if (!tag->context) {
- /* Creating, first time called for this RPC */
- auto new_list =
- new std::list<std::tuple<int, std::string, std::string,
- std::string>>();
- tag->context = new_list;
- nb_db_transactions_iterate(list_transactions_cb, tag->context);
+// Define the context variable type for this streaming handler
+typedef std::list<std::tuple<int, std::string, std::string, std::string>>
+ ListTransactionsContextType;
- new_list->push_back(std::make_tuple(
+bool HandleStreamingListTransactions(
+ StreamRpcState<frr::ListTransactionsRequest,
+ frr::ListTransactionsResponse,
+ ListTransactionsContextType> *tag)
+{
+ grpc_debug("%s: entered", __func__);
+
+ auto list = &tag->context;
+ if (tag->is_initial_process()) {
+ grpc_debug("%s: initialize streaming state", __func__);
+ // Fill our context container first time through
+ nb_db_transactions_iterate(list_transactions_cb, list);
+ list->push_back(std::make_tuple(
0xFFFF, std::string("fake client"),
std::string("fake date"), std::string("fake comment")));
- new_list->push_back(
- std::make_tuple(0xFFFE, std::string("fake client2"),
- std::string("fake date"),
- std::string("fake comment2")));
+ list->push_back(std::make_tuple(0xFFFE,
+ std::string("fake client2"),
+ std::string("fake date"),
+ std::string("fake comment2")));
}
- auto list = static_cast<std::list<
- std::tuple<int, std::string, std::string, std::string>> *>(
- tag->context);
-
if (list->empty()) {
tag->async_responder.Finish(grpc::Status::OK, tag);
- tag->state = FINISH;
- return;
+ return false;
}
auto item = list->back();
@@ -1063,22 +983,18 @@ void HandleStreamingListTransactions(
if (list->empty()) {
tag->async_responder.WriteAndFinish(
response, grpc::WriteOptions(), grpc::Status::OK, tag);
- tag->state = FINISH;
+ return false;
} else {
tag->async_responder.Write(response, tag);
- tag->state = MORE;
+ return true;
}
}
-void HandleUnaryGetTransaction(NewRpcState<frr::GetTransactionRequest,
- frr::GetTransactionResponse> *tag)
+grpc::Status HandleUnaryGetTransaction(
+ UnaryRpcState<frr::GetTransactionRequest, frr::GetTransactionResponse>
+ *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
// Request: uint32 transaction_id = 1;
uint32_t transaction_id = tag->request.transaction_id();
@@ -1094,15 +1010,9 @@ void HandleUnaryGetTransaction(NewRpcState<frr::GetTransactionRequest,
// Load configuration from the transactions database.
nb_config = nb_db_transaction_load(transaction_id);
- if (!nb_config) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Transaction not found"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!nb_config)
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Transaction not found");
// Response: DataTree config = 1;
auto config = tag->response.mutable_config();
@@ -1113,29 +1023,19 @@ void HandleUnaryGetTransaction(NewRpcState<frr::GetTransactionRequest,
encoding2lyd_format(encoding), with_defaults)
!= 0) {
nb_config_free(nb_config);
- tag->responder.Finish(tag->response,
- grpc::Status(grpc::StatusCode::INTERNAL,
- "Failed to dump data"),
- tag);
- tag->state = FINISH;
- return;
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ "Failed to dump data");
}
nb_config_free(nb_config);
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- tag->state = FINISH;
+ return grpc::Status::OK;
}
-void HandleUnaryExecute(
- NewRpcState<frr::ExecuteRequest, frr::ExecuteResponse> *tag)
+grpc::Status HandleUnaryExecute(
+ UnaryRpcState<frr::ExecuteRequest, frr::ExecuteResponse> *tag)
{
- grpc_debug("%s: state: %s", __func__, call_states[tag->state]);
-
- if (tag->state == FINISH) {
- tag->state = DELETED;
- return;
- }
+ grpc_debug("%s: entered", __func__);
struct nb_node *nb_node;
struct list *input_list;
@@ -1150,26 +1050,14 @@ void HandleUnaryExecute(
grpc_debug("%s(path: \"%s\")", __func__, xpath);
- if (tag->request.path().empty()) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Data path is empty"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (tag->request.path().empty())
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Data path is empty");
nb_node = nb_node_find(xpath);
- if (!nb_node) {
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Unknown data path"),
- tag);
- tag->state = FINISH;
- return;
- }
+ if (!nb_node)
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Unknown data path");
input_list = yang_data_list_new();
output_list = yang_data_list_new();
@@ -1191,12 +1079,7 @@ void HandleUnaryExecute(
list_delete(&input_list);
list_delete(&output_list);
- tag->responder.Finish(
- tag->response,
- grpc::Status(grpc::StatusCode::INTERNAL, "RPC failed"),
- tag);
- tag->state = FINISH;
- return;
+ return grpc::Status(grpc::StatusCode::INTERNAL, "RPC failed");
}
// Process output parameters.
@@ -1211,8 +1094,7 @@ void HandleUnaryExecute(
list_delete(&input_list);
list_delete(&output_list);
- tag->responder.Finish(tag->response, grpc::Status::OK, tag);
- tag->state = FINISH;
+ return grpc::Status::OK;
}
// ------------------------------------------------------
@@ -1222,20 +1104,21 @@ void HandleUnaryExecute(
#define REQUEST_NEWRPC(NAME, cdb) \
do { \
- auto _rpcState = new NewRpcState<frr::NAME##Request, \
- frr::NAME##Response>( \
+ auto _rpcState = new UnaryRpcState<frr::NAME##Request, \
+ 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) \
+#define REQUEST_NEWRPC_STREAMING(NAME) \
do { \
- auto _rpcState = new NewRpcState<frr::NAME##Request, \
- frr::NAME##Response>( \
- (cdb), &frr::Northbound::AsyncService::Request##NAME, \
+ auto _rpcState = new StreamRpcState<frr::NAME##Request, \
+ frr::NAME##Response, \
+ NAME##ContextType>( \
+ &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 +1127,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,20 +1138,24 @@ 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 */
+ /* Schedule unary RPC handlers */
REQUEST_NEWRPC(GetCapabilities, NULL);
REQUEST_NEWRPC(CreateCandidate, &candidates);
REQUEST_NEWRPC(DeleteCandidate, &candidates);
@@ -1280,40 +1167,60 @@ static void *grpc_pthread_start(void *arg)
REQUEST_NEWRPC(LockConfig, NULL);
REQUEST_NEWRPC(UnlockConfig, NULL);
REQUEST_NEWRPC(Execute, NULL);
- REQUEST_NEWRPC_STREAMING(Get, NULL);
- REQUEST_NEWRPC_STREAMING(ListTransactions, NULL);
+
+ /* Schedule streaming RPC handlers */
+ REQUEST_NEWRPC_STREAMING(Get);
+ REQUEST_NEWRPC_STREAMING(ListTransactions);
zlog_notice("gRPC server listening on %s",
server_address.str().c_str());
/* Process inbound RPCs */
+ bool ok;
+ void *tag;
while (true) {
- void *tag;
- bool ok;
-
- s_cq->Next(&tag, &ok);
- if (!ok)
+ if (!cq->Next(&tag, &ok)) {
+ grpc_debug("%s: CQ empty exiting", __func__);
break;
+ }
+
+ grpc_debug("%s: got next from CQ tag: %p ok: %d", __func__, tag,
+ ok);
- grpc_debug("%s: Got next from CompletionQueue, %p %d", __func__,
- tag, ok);
+ if (!ok) {
+ 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__,
- call_states[state]);
+ if (rpc->get_state() != FINISH)
+ rpc->run(&service, cq.get());
+ else {
+ grpc_debug("%s RPC FINISH -> [delete]", rpc->name);
+ delete rpc;
+ }
+ }
- /*
- * Our side is done (FINISH) receive new requests of this type
- * We could do this earlier but that would mean we could be
- * handling multiple same type requests in parallel. We expect
- * 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);
+ /* 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 +1232,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,23 +1249,31 @@ 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();
+ grpc_debug("%s: entered", __func__);
- // And drain the queue
- void *ignore;
- bool ok;
+ if (!fpt)
+ return 0;
- while (s_cq->Next(&ignore, &ok))
- ;
+ /*
+ * 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);
- if (fpt) {
- pthread_join(fpt->thread, NULL);
- frr_pthread_destroy(fpt);
- }
+ grpc_debug("%s: joining and destroy grpc thread", __func__);
+ pthread_join(fpt->thread, NULL);
+ frr_pthread_destroy(fpt);
+
+ // Fix protobuf 'memory leaks' during shutdown.
+ // https://groups.google.com/g/protobuf/c/4y_EmQiCGgs
+ google::protobuf::ShutdownProtobufLibrary();
return 0;
}
diff --git a/lib/prefix.c b/lib/prefix.c
index 90ab48a13b..89c5be8f38 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1071,6 +1071,26 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
return str;
}
+static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu)
+{
+ const struct prefix *p = pu.p;
+ char buf[PREFIX2STR_BUFFER];
+
+ switch (p->family) {
+ case AF_INET:
+ case AF_INET6:
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
+ return bputs(fbuf, buf);
+
+ case AF_ETHERNET:
+ prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf));
+ return bputs(fbuf, buf);
+
+ default:
+ return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family);
+ }
+}
+
void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
char *buf, int buf_size)
{
@@ -1458,13 +1478,24 @@ printfrr_ext_autoreg_p("FX", printfrr_pfx);
static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
- char cbuf[PREFIX_STRLEN];
+ bool host_only = false;
+
+ if (ea->fmt[0] == 'h') {
+ ea->fmt++;
+ host_only = true;
+ }
if (!ptr)
return bputs(buf, "(null)");
- prefix2str(ptr, cbuf, sizeof(cbuf));
- return bputs(buf, cbuf);
+ if (host_only)
+ return prefixhost2str(buf, (struct prefix *)ptr);
+ else {
+ char cbuf[PREFIX_STRLEN];
+
+ prefix2str(ptr, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
+ }
}
printfrr_ext_autoreg_p("PSG4", printfrr_psg);
diff --git a/lib/routemap.c b/lib/routemap.c
index 7f733c8114..46161fd817 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -100,6 +100,7 @@ static void route_map_del_plist_entries(afi_t afi,
struct prefix_list_entry *entry);
static struct hash *route_map_get_dep_hash(route_map_event_t event);
+static void route_map_free_map(struct route_map *map);
struct route_map_match_set_hooks rmap_match_set_hook;
@@ -566,15 +567,8 @@ static bool route_map_hash_cmp(const void *p1, const void *p2)
const struct route_map *map1 = p1;
const struct route_map *map2 = p2;
- if (map1->deleted == map2->deleted) {
- if (map1->name && map2->name) {
- if (!strcmp(map1->name, map2->name)) {
- return true;
- }
- } else if (!map1->name && !map2->name) {
- return true;
- }
- }
+ if (!strcmp(map1->name, map2->name))
+ return true;
return false;
}
@@ -636,13 +630,25 @@ static struct route_map *route_map_new(const char *name)
/* Add new name to route_map. */
static struct route_map *route_map_add(const char *name)
{
- struct route_map *map;
+ struct route_map *map, *exist;
struct route_map_list *list;
map = route_map_new(name);
list = &route_map_master;
- /* Add map to the hash */
+ /*
+ * Add map to the hash
+ *
+ * If the map already exists in the hash, then we know that
+ * FRR is now in a sequence of delete/create.
+ * All FRR needs to do here is set the to_be_processed
+ * bit (to inherit from the old one
+ */
+ exist = hash_release(route_map_master_hash, map);
+ if (exist) {
+ map->to_be_processed = exist->to_be_processed;
+ route_map_free_map(exist);
+ }
hash_get(route_map_master_hash, map, hash_alloc_intern);
/* Add new entry to the head of the list to match how it is added in the
@@ -752,11 +758,15 @@ struct route_map *route_map_lookup_by_name(const char *name)
if (!name)
return NULL;
- // map.deleted is 0 via memset
+ // map.deleted is false via memset
memset(&tmp_map, 0, sizeof(struct route_map));
tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
map = hash_lookup(route_map_master_hash, &tmp_map);
XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
+
+ if (map && map->deleted)
+ return NULL;
+
return map;
}
@@ -1799,12 +1809,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 +2568,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)
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 006ac142aa..9763b38e28 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -351,21 +351,6 @@ int sockopt_ttl(int family, int sock, int ttl)
return 0;
}
-/*
- * This function called setsockopt(.., TCP_CORK,...)
- * Which on linux is a no-op since it is enabled by
- * default and on BSD it uses TCP_NOPUSH to do
- * the same thing( which it was not configured to
- * use). This cleanup of the api occurred on 8/1/17
- * I imagine if after more than 1 year of no-one
- * complaining, and a major upgrade release we
- * can deprecate and remove this function call
- */
-int sockopt_cork(int sock, int onoff)
-{
- return 0;
-}
-
int sockopt_minttl(int family, int sock, int minttl)
{
#ifdef IP_MINTTL
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 9e6719ccf9..8ace3e4781 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -95,7 +95,6 @@ extern int sockunion_bind(int sock, union sockunion *, unsigned short,
union sockunion *);
extern int sockopt_ttl(int family, int sock, int ttl);
extern int sockopt_minttl(int family, int sock, int minttl);
-extern int sockopt_cork(int sock, int onoff);
extern int sockunion_socket(const union sockunion *su);
extern const char *inet_sutop(const union sockunion *su, char *str);
extern enum connect_result sockunion_connect(int fd, const union sockunion *su,
diff --git a/lib/subdir.am b/lib/subdir.am
index 648ab7f14a..b505e235ca 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -8,6 +8,7 @@ lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
lib/atomlist.c \
+ lib/base64.c \
lib/bfd.c \
lib/buffer.c \
lib/checksum.c \
@@ -113,6 +114,7 @@ lib_libfrr_la_SOURCES = \
lib/zlog.c \
lib/zlog_5424.c \
lib/zlog_5424_cli.c \
+ lib/zlog_live.c \
lib/zlog_targets.c \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
@@ -177,6 +179,7 @@ clippy_scan += \
pkginclude_HEADERS += \
lib/agg_table.h \
lib/atomlist.h \
+ lib/base64.h \
lib/bfd.h \
lib/bitfield.h \
lib/buffer.h \
@@ -287,6 +290,7 @@ pkginclude_HEADERS += \
lib/zebra.h \
lib/zlog.h \
lib/zlog_5424.h \
+ lib/zlog_live.h \
lib/zlog_targets.h \
lib/pbr.h \
lib/routing_nb.h \
diff --git a/lib/thread.c b/lib/thread.c
index bc3bfe89d4..90074b3d89 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -498,6 +498,41 @@ DEFUN (clear_thread_cpu,
return CMD_SUCCESS;
}
+static void show_thread_timers_helper(struct vty *vty, struct thread_master *m)
+{
+ const char *name = m->name ? m->name : "main";
+ char underline[strlen(name) + 1];
+ struct thread *thread;
+
+ memset(underline, '-', sizeof(underline));
+ underline[sizeof(underline) - 1] = '\0';
+
+ vty_out(vty, "\nShowing timers for %s\n", name);
+ vty_out(vty, "-------------------%s\n", underline);
+
+ frr_each (thread_timer_list, &m->timer, thread) {
+ vty_out(vty, " %-50s%pTH\n", thread->hist->funcname, thread);
+ }
+}
+
+DEFPY_NOSH (show_thread_timers,
+ show_thread_timers_cmd,
+ "show thread timers",
+ SHOW_STR
+ "Thread information\n"
+ "Show all timers and how long they have in the system\n")
+{
+ struct listnode *node;
+ struct thread_master *m;
+
+ frr_with_mutex (&masters_mtx) {
+ for (ALL_LIST_ELEMENTS_RO(masters, node, m))
+ show_thread_timers_helper(vty, m);
+ }
+
+ return CMD_SUCCESS;
+}
+
void thread_cmd_init(void)
{
install_element(VIEW_NODE, &show_thread_cpu_cmd);
@@ -509,6 +544,8 @@ void thread_cmd_init(void)
install_element(CONFIG_NODE, &no_service_cputime_warning_cmd);
install_element(CONFIG_NODE, &service_walltime_warning_cmd);
install_element(CONFIG_NODE, &no_service_walltime_warning_cmd);
+
+ install_element(VIEW_NODE, &show_thread_timers_cmd);
}
/* CLI end ------------------------------------------------------------------ */
@@ -1847,6 +1884,27 @@ unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
unsigned long *cputime)
{
#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+
+#ifdef __FreeBSD__
+ /*
+ * FreeBSD appears to have an issue when calling clock_gettime
+ * with CLOCK_THREAD_CPUTIME_ID really close to each other
+ * occassionally the now time will be before the start time.
+ * This is not good and FRR is ending up with CPU HOG's
+ * when the subtraction wraps to very large numbers
+ *
+ * What we are going to do here is cheat a little bit
+ * and notice that this is a problem and just correct
+ * it so that it is impossible to happen
+ */
+ if (start->cpu.tv_sec == now->cpu.tv_sec &&
+ start->cpu.tv_nsec > now->cpu.tv_nsec)
+ now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+ else if (start->cpu.tv_sec > now->cpu.tv_sec) {
+ now->cpu.tv_sec = start->cpu.tv_sec;
+ now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+ }
+#endif
*cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO
+ (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000;
#else
diff --git a/lib/typerb.c b/lib/typerb.c
index e1346df191..fe142ff354 100644
--- a/lib/typerb.c
+++ b/lib/typerb.c
@@ -468,6 +468,28 @@ struct rb_entry *typed_rb_next(const struct rb_entry *rbe_const)
return rbe;
}
+struct rb_entry *typed_rb_prev(const struct rb_entry *rbe_const)
+{
+ struct rb_entry *rbe = (struct rb_entry *)rbe_const;
+
+ if (RBE_LEFT(rbe)) {
+ rbe = RBE_LEFT(rbe);
+ while (RBE_RIGHT(rbe))
+ rbe = RBE_RIGHT(rbe);
+ } else {
+ if (RBE_PARENT(rbe) && (rbe == RBE_RIGHT(RBE_PARENT(rbe))))
+ rbe = RBE_PARENT(rbe);
+ else {
+ while (RBE_PARENT(rbe)
+ && (rbe == RBE_LEFT(RBE_PARENT(rbe))))
+ rbe = RBE_PARENT(rbe);
+ rbe = RBE_PARENT(rbe);
+ }
+ }
+
+ return rbe;
+}
+
struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
@@ -481,6 +503,19 @@ struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
return parent;
}
+struct rb_entry *typed_rb_max(const struct rbt_tree *rbt)
+{
+ struct rb_entry *rbe = RBH_ROOT(rbt);
+ struct rb_entry *parent = NULL;
+
+ while (rbe != NULL) {
+ parent = rbe;
+ rbe = RBE_RIGHT(rbe);
+ }
+
+ return parent;
+}
+
bool typed_rb_member(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe)
{
diff --git a/lib/typerb.h b/lib/typerb.h
index 75a1de77b3..8ac1821742 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -62,6 +62,8 @@ const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt,
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
+struct typed_rb_entry *typed_rb_max(const struct typed_rb_root *rbt);
+struct typed_rb_entry *typed_rb_prev(const struct typed_rb_entry *rbe);
struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
bool typed_rb_member(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe);
@@ -135,12 +137,32 @@ macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
return container_of_null(re, type, field.re); \
} \
TYPESAFE_FIRST_NEXT(prefix, type) \
+macro_pure const type *prefix ## _const_last(const struct prefix##_head *h) \
+{ \
+ const struct typed_rb_entry *re; \
+ re = typed_rb_max(&h->rr); \
+ return container_of_null(re, type, field.re); \
+} \
+macro_pure const type *prefix ## _const_prev(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ const struct typed_rb_entry *re; \
+ re = typed_rb_prev(&item->field.re); \
+ return container_of_null(re, type, field.re); \
+} \
+TYPESAFE_LAST_PREV(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
struct typed_rb_entry *re; \
re = item ? typed_rb_next(&item->field.re) : NULL; \
return container_of_null(re, type, field.re); \
} \
+macro_pure type *prefix ## _prev_safe(struct prefix##_head *h, type *item) \
+{ \
+ struct typed_rb_entry *re; \
+ re = item ? typed_rb_prev(&item->field.re) : NULL; \
+ return container_of_null(re, type, field.re); \
+} \
macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->rr.count; \
diff --git a/lib/typesafe.h b/lib/typesafe.h
index b284397d98..06fdc52e78 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -43,6 +43,22 @@ extern "C" {
item; \
item = from, from = prefix##_next_safe(head, from))
+/* reverse direction, only supported by a few containers */
+
+#define frr_rev_each(prefix, head, item) \
+ for (item = prefix##_last(head); item; \
+ item = prefix##_prev(head, item))
+#define frr_rev_each_safe(prefix, head, item) \
+ for (typeof(prefix##_prev_safe(head, NULL)) prefix##_safe = \
+ prefix##_prev_safe(head, \
+ (item = prefix##_last(head))); \
+ item; \
+ item = prefix##_safe, \
+ prefix##_safe = prefix##_prev_safe(head, prefix##_safe))
+#define frr_rev_each_from(prefix, head, item, from) \
+ for (item = from, from = prefix##_prev_safe(head, item); \
+ item; \
+ item = from, from = prefix##_prev_safe(head, from))
/* non-const variants. these wrappers are the same for all the types, so
* bundle them together here.
@@ -57,6 +73,16 @@ macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
return (type *)prefix ## _const_next(h, item); \
} \
/* ... */
+#define TYPESAFE_LAST_PREV(prefix, type) \
+macro_pure type *prefix ## _last(struct prefix##_head *h) \
+{ \
+ return (type *)prefix ## _const_last(h); \
+} \
+macro_pure type *prefix ## _prev(struct prefix##_head *h, type *item) \
+{ \
+ return (type *)prefix ## _const_prev(h, item); \
+} \
+/* ... */
#define TYPESAFE_FIND(prefix, type) \
macro_inline type *prefix ## _find(struct prefix##_head *h, \
const type *item) \
@@ -398,12 +424,34 @@ macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
return container_of(ditem->next, type, field.di); \
} \
TYPESAFE_FIRST_NEXT(prefix, type) \
+macro_pure const type *prefix ## _const_last(const struct prefix##_head *h) \
+{ \
+ const struct dlist_item *ditem = h->dh.hitem.prev; \
+ if (ditem == &h->dh.hitem) \
+ return NULL; \
+ return container_of(ditem, type, field.di); \
+} \
+macro_pure const type *prefix ## _const_prev(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ const struct dlist_item *ditem = &item->field.di; \
+ if (ditem->prev == &h->dh.hitem) \
+ return NULL; \
+ return container_of(ditem->prev, type, field.di); \
+} \
+TYPESAFE_LAST_PREV(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
if (!item) \
return NULL; \
return prefix ## _next(h, item); \
} \
+macro_pure type *prefix ## _prev_safe(struct prefix##_head *h, type *item) \
+{ \
+ if (!item) \
+ return NULL; \
+ return prefix ## _prev(h, item); \
+} \
macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->dh.count; \
diff --git a/lib/vty.c b/lib/vty.c
index a42b8c92be..78ef9894de 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -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;
@@ -1314,8 +1314,6 @@ static void vty_read(struct thread *thread)
vty_event(VTY_READ, vty);
return;
}
- vty->monitor = 0; /* disable monitoring to avoid
- infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read error on vty client fd %d, closing: %s",
@@ -1464,6 +1462,11 @@ static void vty_read(struct thread *thread)
vty_out(vty, "\n");
buffer_flush_available(vty->obuf, vty->wfd);
vty_execute(vty);
+
+ if (vty->pass_fd != -1) {
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ }
break;
case '\t':
vty_complete_command(vty);
@@ -1524,8 +1527,6 @@ static void vty_flush(struct thread *thread)
vty->lines >= 0 ? vty->lines : vty->height, erase, 0);
switch (flushrc) {
case BUFFER_ERROR:
- vty->monitor =
- 0; /* disable monitoring to avoid infinite recursion */
zlog_info("buffer_flush failed on vty client fd %d/%d, closing",
vty->fd, vty->wfd);
buffer_reset(vty->lbuf);
@@ -1561,6 +1562,7 @@ struct vty *vty_new(void)
new->obuf = buffer_new(0); /* Use default buffer size. */
new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
new->max = VTY_BUFSIZ;
+ new->pass_fd = -1;
return new;
}
@@ -2010,15 +2012,68 @@ static void vtysh_accept(struct thread *thread)
vty_event(VTYSH_READ, vty);
}
+static int vtysh_do_pass_fd(struct vty *vty)
+{
+ struct iovec iov[1] = {
+ {
+ .iov_base = vty->pass_fd_status,
+ .iov_len = sizeof(vty->pass_fd_status),
+ },
+ };
+ union {
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr align;
+ } u;
+ struct msghdr mh = {
+ .msg_iov = iov,
+ .msg_iovlen = array_size(iov),
+ .msg_control = u.buf,
+ .msg_controllen = sizeof(u.buf),
+ };
+ struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
+ ssize_t ret;
+
+ cmh->cmsg_level = SOL_SOCKET;
+ cmh->cmsg_type = SCM_RIGHTS;
+ cmh->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmh), &vty->pass_fd, sizeof(int));
+
+ ret = sendmsg(vty->wfd, &mh, 0);
+ if (ret < 0 && ERRNO_IO_RETRY(errno))
+ return BUFFER_PENDING;
+
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ vty->status = VTY_NORMAL;
+
+ if (ret <= 0)
+ return BUFFER_ERROR;
+
+ /* resume accepting commands (suspended in vtysh_read) */
+ vty_event(VTYSH_READ, vty);
+
+ if ((size_t)ret < sizeof(vty->pass_fd_status)) {
+ size_t remains = sizeof(vty->pass_fd_status) - ret;
+
+ buffer_put(vty->obuf, vty->pass_fd_status + ret, remains);
+ return BUFFER_PENDING;
+ }
+ return BUFFER_EMPTY;
+}
+
static int vtysh_flush(struct vty *vty)
{
- switch (buffer_flush_available(vty->obuf, vty->wfd)) {
+ int ret;
+
+ ret = buffer_flush_available(vty->obuf, vty->wfd);
+ if (ret == BUFFER_EMPTY && vty->status == VTY_PASSFD)
+ ret = vtysh_do_pass_fd(vty);
+
+ switch (ret) {
case BUFFER_PENDING:
vty_event(VTYSH_WRITE, vty);
break;
case BUFFER_ERROR:
- vty->monitor =
- 0; /* disable monitoring to avoid infinite recursion */
flog_err(EC_LIB_SOCKET, "%s: write error to fd %d, closing",
__func__, vty->fd);
buffer_reset(vty->lbuf);
@@ -2031,6 +2086,14 @@ static int vtysh_flush(struct vty *vty)
return 0;
}
+void vty_pass_fd(struct vty *vty, int fd)
+{
+ if (vty->pass_fd != -1)
+ close(vty->pass_fd);
+
+ vty->pass_fd = fd;
+}
+
static void vtysh_read(struct thread *thread)
{
int ret;
@@ -2050,8 +2113,6 @@ static void vtysh_read(struct thread *thread)
vty_event(VTYSH_READ, vty);
return;
}
- vty->monitor = 0; /* disable monitoring to avoid
- infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read failed on vtysh client fd %d, closing: %s",
@@ -2090,6 +2151,26 @@ static void vtysh_read(struct thread *thread)
printf("vtysh node: %d\n", vty->node);
#endif /* VTYSH_DEBUG */
+ if (vty->pass_fd != -1) {
+ memset(vty->pass_fd_status, 0, 4);
+ vty->pass_fd_status[3] = ret;
+ vty->status = VTY_PASSFD;
+
+ if (!vty->t_write)
+ vty_event(VTYSH_WRITE, vty);
+
+ /* this introduces a "sequence point"
+ * command output is written normally,
+ * read processing is suspended until
+ * buffer is empty
+ * then retcode + FD is written
+ * then normal processing resumes
+ *
+ * => skip vty_event(VTYSH_READ, vty)!
+ */
+ return;
+ }
+
/* hack for asynchronous "write integrated"
* - other commands in "buf" will be ditched
* - input during pending config-write is
@@ -2161,6 +2242,12 @@ void vty_close(struct vty *vty)
THREAD_OFF(vty->t_write);
THREAD_OFF(vty->t_timeout);
+ if (vty->pass_fd != -1) {
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ }
+ zlog_live_close(&vty->live_log);
+
/* Flush buffer. */
buffer_flush_all(vty->obuf, vty->wfd);
@@ -2596,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:
@@ -2614,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
@@ -2661,8 +2748,9 @@ DEFUN_NOSH (config_who,
struct vty *v;
frr_each (vtys, vty_sessions, v)
- vty_out(vty, "%svty[%d] connected from %s.\n",
- v->config ? "*" : " ", v->fd, v->address);
+ vty_out(vty, "%svty[%d] connected from %s%s.\n",
+ v->config ? "*" : " ", v->fd, v->address,
+ zlog_live_is_null(&v->live_log) ? "" : ", live log");
return CMD_SUCCESS;
}
@@ -2855,35 +2943,56 @@ DEFUN (no_service_advanced_vty,
return CMD_SUCCESS;
}
-DEFUN_NOSH (terminal_monitor,
- terminal_monitor_cmd,
- "terminal monitor",
- "Set terminal line parameters\n"
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(terminal_monitor,
+ terminal_monitor_cmd,
+ "terminal monitor [detach]",
+ "Set terminal line parameters\n"
+ "Copy debug output to the current terminal line\n"
+ "Keep logging feed open independent of VTY session\n")
{
- vty->monitor = 1;
+ int fd_ret = -1;
+
+ if (vty->type != VTY_SHELL_SERV) {
+ vty_out(vty, "%% not supported\n");
+ return CMD_WARNING;
+ }
+
+ if (argc == 3) {
+ struct zlog_live_cfg detach_log = {};
+
+ zlog_live_open(&detach_log, LOG_DEBUG, &fd_ret);
+ zlog_live_disown(&detach_log);
+ } else
+ zlog_live_open(&vty->live_log, LOG_DEBUG, &fd_ret);
+
+ if (fd_ret == -1) {
+ vty_out(vty, "%% error opening live log: %m\n");
+ return CMD_WARNING;
+ }
+
+ vty_pass_fd(vty, fd_ret);
return CMD_SUCCESS;
}
-DEFUN_NOSH (terminal_no_monitor,
- terminal_no_monitor_cmd,
- "terminal no monitor",
- "Set terminal line parameters\n"
- NO_STR
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(no_terminal_monitor,
+ no_terminal_monitor_cmd,
+ "no terminal monitor",
+ NO_STR
+ "Set terminal line parameters\n"
+ "Copy debug output to the current terminal line\n")
{
- vty->monitor = 0;
+ zlog_live_close(&vty->live_log);
return CMD_SUCCESS;
}
-DEFUN_NOSH (no_terminal_monitor,
- no_terminal_monitor_cmd,
- "no terminal monitor",
- NO_STR
- "Set terminal line parameters\n"
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(terminal_no_monitor,
+ terminal_no_monitor_cmd,
+ "terminal no monitor",
+ "Set terminal line parameters\n"
+ NO_STR
+ "Copy debug output to the current terminal line\n")
{
- return terminal_no_monitor(self, vty, argc, argv);
+ return no_terminal_monitor(self, vty, argc, argv);
}
diff --git a/lib/vty.h b/lib/vty.h
index 9ffbce3268..e42a3b210f 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -34,6 +34,7 @@
#include "qobj.h"
#include "compiler.h"
#include "northbound.h"
+#include "zlog_live.h"
#ifdef __cplusplus
extern "C" {
@@ -161,7 +162,22 @@ struct vty {
unsigned char escape;
/* Current vty status. */
- enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status;
+ enum {
+ VTY_NORMAL,
+ VTY_CLOSE,
+ VTY_MORE,
+ VTY_MORELINE,
+ VTY_PASSFD,
+ } status;
+
+ /* vtysh socket/fd passing (for terminal monitor) */
+ int pass_fd;
+
+ /* CLI command return value (likely CMD_SUCCESS) when pass_fd != -1 */
+ uint8_t pass_fd_status[4];
+
+ /* live logging target / terminal monitor */
+ struct zlog_live_cfg live_log;
/* IAC handling: was the last character received the
IAC (interpret-as-command) escape character (and therefore the next
@@ -186,9 +202,6 @@ struct vty {
/* Configure lines. */
int lines;
- /* Terminal monitor. */
- int monitor;
-
/* Read and write thread. */
struct thread *t_read;
struct thread *t_write;
@@ -329,6 +342,11 @@ extern bool vty_set_include(struct vty *vty, const char *regexp);
*/
extern int vty_json(struct vty *vty, struct json_object *json);
+/* post fd to be passed to the vtysh client
+ * fd is owned by the VTY code after this and will be closed when done
+ */
+extern void vty_pass_fd(struct vty *vty, int fd);
+
extern bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir);
extern void vty_time_print(struct vty *, int);
diff --git a/lib/wheel.c b/lib/wheel.c
index 463410bea4..cdf738a137 100644
--- a/lib/wheel.c
+++ b/lib/wheel.c
@@ -40,7 +40,6 @@ static void wheel_timer_thread_helper(struct thread *t)
void *data;
wheel = THREAD_ARG(t);
- THREAD_OFF(wheel->timer);
wheel->curr_slot += wheel->slots_to_skip;
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index 85aa003db7..bee76c6e0f 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -19,6 +19,7 @@
#include <zebra.h>
+#include "base64.h"
#include "log.h"
#include "lib_errors.h"
#include "northbound.h"
@@ -677,6 +678,64 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt,
}
/*
+ * Primitive type: binary.
+ */
+struct yang_data *yang_data_new_binary(const char *xpath, const char *value,
+ size_t len)
+{
+ char *value_str;
+ struct base64_encodestate s;
+ int cnt;
+ char *c;
+ struct yang_data *data;
+
+ value_str = (char *)malloc(len * 2);
+ base64_init_encodestate(&s);
+ cnt = base64_encode_block(value, len, value_str, &s);
+ c = value_str + cnt;
+ cnt = base64_encode_blockend(c, &s);
+ c += cnt;
+ *c = 0;
+ data = yang_data_new(xpath, value_str);
+ free(value_str);
+ return data;
+}
+
+size_t yang_dnode_get_binary_buf(char *buf, size_t size,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...)
+{
+ const char *canon;
+ size_t cannon_len;
+ size_t decode_len;
+ size_t ret_len;
+ size_t cnt;
+ char *value_str;
+ struct base64_decodestate s;
+
+ canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
+ cannon_len = strlen(canon);
+ decode_len = cannon_len;
+ value_str = (char *)malloc(decode_len);
+ base64_init_decodestate(&s);
+ cnt = base64_decode_block(canon, cannon_len, value_str, &s);
+
+ ret_len = size > cnt ? cnt : size;
+ memcpy(buf, value_str, ret_len);
+ if (size < cnt) {
+ char xpath[XPATH_MAXLEN];
+
+ yang_dnode_get_path(dnode, xpath, sizeof(xpath));
+ flog_warn(EC_LIB_YANG_DATA_TRUNCATED,
+ "%s: value was truncated [xpath %s]", __func__,
+ xpath);
+ }
+ free(value_str);
+ return ret_len;
+}
+
+
+/*
* Primitive type: empty.
*/
struct yang_data *yang_data_new_empty(const char *xpath)
diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h
index d781dfb1e4..56b314876f 100644
--- a/lib/yang_wrappers.h
+++ b/lib/yang_wrappers.h
@@ -118,6 +118,13 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...);
extern void yang_get_default_string_buf(char *buf, size_t size,
const char *xpath_fmt, ...);
+/* binary */
+extern struct yang_data *yang_data_new_binary(const char *xpath,
+ const char *value, size_t len);
+extern size_t yang_dnode_get_binary_buf(char *buf, size_t size,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
+
/* empty */
extern struct yang_data *yang_data_new_empty(const char *xpath);
extern bool yang_dnode_get_empty(const struct lyd_node *dnode,
diff --git a/lib/zclient.c b/lib/zclient.c
index cfccb21667..f6c5a8af08 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);
@@ -1924,7 +1924,8 @@ const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf,
/*
* Decode the nexthop-tracking update message
*/
-bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
+bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match,
+ struct zapi_route *nhr)
{
uint32_t i;
@@ -1932,6 +1933,22 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
STREAM_GETL(s, nhr->message);
STREAM_GETW(s, nhr->safi);
+ STREAM_GETW(s, match->family);
+ STREAM_GETC(s, match->prefixlen);
+ /*
+ * What we got told to match against
+ */
+ switch (match->family) {
+ case AF_INET:
+ STREAM_GET(&match->u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
+ break;
+ case AF_INET6:
+ STREAM_GET(&match->u.prefix6, s, IPV6_MAX_BYTELEN);
+ break;
+ }
+ /*
+ * What we matched against
+ */
STREAM_GETW(s, nhr->prefix.family);
STREAM_GETC(s, nhr->prefix.prefixlen);
switch (nhr->prefix.family) {
@@ -4038,7 +4055,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/lib/zclient.h b/lib/zclient.h
index ca62b1afeb..092754f602 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -1111,7 +1111,17 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
const struct nexthop *nh);
int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
const struct nexthop *nh);
-extern bool zapi_nexthop_update_decode(struct stream *s,
+/*
+ * match -> is the prefix that the calling daemon asked to be matched
+ * against.
+ * nhr->prefix -> is the actual prefix that was matched against in the
+ * rib itself.
+ *
+ * This distinction is made because a LPM can be made if there is a
+ * covering route. This way the upper level protocol can make a decision
+ * point about whether or not it wants to use the match or not.
+ */
+extern bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match,
struct zapi_route *nhr);
const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf,
int bufsize);
diff --git a/lib/zlog.c b/lib/zlog.c
index 1b0751559d..e0bb34a258 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -401,7 +401,7 @@ void zlog_tls_buffer_flush(void)
return;
rcu_read_lock();
- frr_each (zlog_targets, &zlog_targets, zt) {
+ frr_each_safe (zlog_targets, &zlog_targets, zt) {
if (!zt->logfn)
continue;
@@ -431,7 +431,7 @@ static void vzlog_notls(const struct xref_logmsg *xref, int prio,
msg->stackbufsz = sizeof(stackbuf);
rcu_read_lock();
- frr_each (zlog_targets, &zlog_targets, zt) {
+ frr_each_safe (zlog_targets, &zlog_targets, zt) {
if (prio > zt->prio_min)
continue;
if (!zt->logfn)
@@ -908,6 +908,11 @@ size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out, uint32_t flags)
return bputs(out, msg->ts_3164_str);
}
+void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts)
+{
+ memcpy(ts, &msg->ts, sizeof(*ts));
+}
+
void zlog_set_prefix_ec(bool enable)
{
atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
diff --git a/lib/zlog.h b/lib/zlog.h
index 6e84fe8923..a530c589a8 100644
--- a/lib/zlog.h
+++ b/lib/zlog.h
@@ -183,8 +183,11 @@ extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
/* default is local time zone */
#define ZLOG_TS_UTC (1 << 10)
+struct timespec;
+
extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
uint32_t flags);
+extern void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts);
/* "mmm dd hh:mm:ss" for RFC3164 syslog. Only ZLOG_TS_UTC for flags. */
extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
diff --git a/lib/zlog_live.c b/lib/zlog_live.c
new file mode 100644
index 0000000000..931aa3461d
--- /dev/null
+++ b/lib/zlog_live.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "zebra.h"
+
+#include "zlog_live.h"
+
+#include "memory.h"
+#include "frrcu.h"
+#include "zlog.h"
+#include "printfrr.h"
+#include "network.h"
+
+DEFINE_MTYPE_STATIC(LOG, LOG_LIVE, "log vtysh live target");
+
+enum {
+ STATE_NORMAL = 0,
+ STATE_FD_DEAD,
+ STATE_DISOWNED,
+};
+
+struct zlt_live {
+ struct zlog_target zt;
+
+ atomic_uint_fast32_t fd;
+ struct rcu_head_close head_close;
+ struct rcu_head head_self;
+
+ atomic_uint_fast32_t state;
+ atomic_uint_fast32_t lost_msgs;
+};
+
+static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
+ size_t nmsgs)
+{
+ struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
+ struct zlog_live_hdr hdrs[nmsgs], *hdr = hdrs;
+ struct mmsghdr mmhs[nmsgs], *mmh = mmhs;
+ struct iovec iovs[nmsgs * 3], *iov = iovs;
+ struct timespec ts;
+ size_t i, textlen;
+ int fd;
+ uint_fast32_t state;
+
+ fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
+
+ if (fd < 0)
+ return;
+
+ memset(mmhs, 0, sizeof(mmhs));
+ memset(hdrs, 0, sizeof(hdrs));
+
+ for (i = 0; i < nmsgs; i++) {
+ const struct fmt_outpos *argpos;
+ size_t n_argpos, texthdrlen;
+ struct zlog_msg *msg = msgs[i];
+ int prio = zlog_msg_prio(msg);
+ const struct xref_logmsg *xref;
+ intmax_t pid, tid;
+
+ if (prio > zt->prio_min)
+ continue;
+
+ zlog_msg_args(msg, &texthdrlen, &n_argpos, &argpos);
+
+ mmh->msg_hdr.msg_iov = iov;
+
+ iov->iov_base = hdr;
+ iov->iov_len = sizeof(*hdr);
+ iov++;
+
+ if (n_argpos) {
+ iov->iov_base = (char *)argpos;
+ iov->iov_len = sizeof(*argpos) * n_argpos;
+ iov++;
+ }
+
+ iov->iov_base = (char *)zlog_msg_text(msg, &textlen);
+ iov->iov_len = textlen;
+ iov++;
+
+ zlog_msg_tsraw(msg, &ts);
+ zlog_msg_pid(msg, &pid, &tid);
+ xref = zlog_msg_xref(msg);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->pid = pid;
+ hdr->tid = tid;
+ hdr->lost_msgs = atomic_load_explicit(&zte->lost_msgs,
+ memory_order_relaxed);
+ hdr->prio = prio;
+ hdr->flags = 0;
+ hdr->textlen = textlen;
+ hdr->texthdrlen = texthdrlen;
+ hdr->n_argpos = n_argpos;
+ if (xref) {
+ memcpy(hdr->uid, xref->xref.xrefdata->uid,
+ sizeof(hdr->uid));
+ hdr->ec = xref->ec;
+ } else {
+ memset(hdr->uid, 0, sizeof(hdr->uid));
+ hdr->ec = 0;
+ }
+ hdr->hdrlen = sizeof(*hdr) + sizeof(*argpos) * n_argpos;
+
+ mmh->msg_hdr.msg_iovlen = iov - mmh->msg_hdr.msg_iov;
+ mmh++;
+ hdr++;
+ }
+
+ size_t msgtotal = mmh - mmhs;
+ ssize_t sent;
+
+ for (size_t msgpos = 0; msgpos < msgtotal; msgpos += sent) {
+ sent = sendmmsg(fd, mmhs + msgpos, msgtotal - msgpos, 0);
+
+ if (sent <= 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ atomic_fetch_add_explicit(&zte->lost_msgs,
+ msgtotal - msgpos,
+ memory_order_relaxed);
+ break;
+ }
+ if (sent <= 0)
+ goto out_err;
+ }
+ return;
+
+out_err:
+ fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
+ if (fd < 0)
+ return;
+
+ rcu_close(&zte->head_close, fd);
+ zlog_target_replace(zt, NULL);
+
+ state = STATE_NORMAL;
+ atomic_compare_exchange_strong_explicit(
+ &zte->state, &state, STATE_FD_DEAD, memory_order_relaxed,
+ memory_order_relaxed);
+ if (state == STATE_DISOWNED)
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
+
+static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
+ size_t len)
+{
+ struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
+ struct zlog_live_hdr hdr[1] = {};
+ struct iovec iovs[2], *iov = iovs;
+ struct timespec ts;
+ int fd;
+
+ fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
+ if (fd < 0)
+ return;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->prio = LOG_CRIT;
+ hdr->textlen = len;
+
+ iov->iov_base = (char *)hdr;
+ iov->iov_len = sizeof(hdr);
+ iov++;
+
+ iov->iov_base = (char *)text;
+ iov->iov_len = len;
+ iov++;
+
+ writev(fd, iovs, iov - iovs);
+}
+
+void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd)
+{
+ int sockets[2];
+
+ if (cfg->target)
+ zlog_live_close(cfg);
+
+ *other_fd = -1;
+ if (prio_min == ZLOG_DISABLED)
+ return;
+
+ /* the only reason for SEQPACKET here is getting close notifications.
+ * otherwise if you open a bunch of vtysh connections with live logs
+ * and close them all, the fds will stick around until we get an error
+ * when trying to log something to them at some later point -- which
+ * eats up fds and might be *much* later for some daemons.
+ */
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) < 0) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
+ zlog_warn("%% could not open socket pair: %m");
+ return;
+ }
+ } else
+ /* SEQPACKET only: try to zap read direction */
+ shutdown(sockets[0], SHUT_RD);
+
+ *other_fd = sockets[1];
+ zlog_live_open_fd(cfg, prio_min, sockets[0]);
+}
+
+void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd)
+{
+ struct zlt_live *zte;
+ struct zlog_target *zt;
+
+ if (cfg->target)
+ zlog_live_close(cfg);
+
+ zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte));
+ zte = container_of(zt, struct zlt_live, zt);
+ cfg->target = zte;
+
+ set_nonblocking(fd);
+ zte->fd = fd;
+ zte->zt.prio_min = prio_min;
+ zte->zt.logfn = zlog_live;
+ zte->zt.logfn_sigsafe = zlog_live_sigsafe;
+
+ zlog_target_replace(NULL, zt);
+}
+
+void zlog_live_close(struct zlog_live_cfg *cfg)
+{
+ struct zlt_live *zte;
+ int fd;
+
+ if (!cfg->target)
+ return;
+
+ zte = cfg->target;
+ cfg->target = NULL;
+
+ fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
+
+ if (fd >= 0) {
+ rcu_close(&zte->head_close, fd);
+ zlog_target_replace(&zte->zt, NULL);
+ }
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
+
+void zlog_live_disown(struct zlog_live_cfg *cfg)
+{
+ struct zlt_live *zte;
+ uint_fast32_t state;
+
+ if (!cfg->target)
+ return;
+
+ zte = cfg->target;
+ cfg->target = NULL;
+
+ state = STATE_NORMAL;
+ atomic_compare_exchange_strong_explicit(
+ &zte->state, &state, STATE_DISOWNED, memory_order_relaxed,
+ memory_order_relaxed);
+ if (state == STATE_FD_DEAD)
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
diff --git a/lib/zlog_live.h b/lib/zlog_live.h
new file mode 100644
index 0000000000..55e60ae674
--- /dev/null
+++ b/lib/zlog_live.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRR_ZLOG_LIVE_H
+#define _FRR_ZLOG_LIVE_H
+
+#include "printfrr.h"
+
+struct zlog_live_hdr {
+ /* timestamp (CLOCK_REALTIME) */
+ uint64_t ts_sec;
+ uint32_t ts_nsec;
+
+ /* length of zlog_live_hdr, including variable length bits and
+ * possible future extensions - aka start of text
+ */
+ uint32_t hdrlen;
+
+ /* process & thread ID, meaning depends on OS */
+ int64_t pid;
+ int64_t tid;
+
+ /* number of lost messages due to best-effort non-blocking mode */
+ uint32_t lost_msgs;
+ /* syslog priority value */
+ uint32_t prio;
+ /* flags: currently unused */
+ uint32_t flags;
+ /* length of message text - extra data (e.g. future key/value metadata)
+ * may follow after it
+ */
+ uint32_t textlen;
+ /* length of "[XXXXX-XXXXX][EC 0] " header; consumer may want to skip
+ * over it if using the raw values below. Note that this text may be
+ * absent depending on "log error-category" and "log unique-id"
+ * settings
+ */
+ uint32_t texthdrlen;
+
+ /* xref unique identifier, "XXXXX-XXXXX\0" = 12 bytes */
+ char uid[12];
+ /* EC value */
+ uint32_t ec;
+
+ /* recorded printf formatting argument positions (variable length) */
+ uint32_t n_argpos;
+ struct fmt_outpos argpos[0];
+};
+
+struct zlt_live;
+
+struct zlog_live_cfg {
+ struct zlt_live *target;
+
+ /* nothing else here */
+};
+
+extern void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min,
+ int *other_fd);
+extern void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd);
+
+static inline bool zlog_live_is_null(struct zlog_live_cfg *cfg)
+{
+ return cfg->target == NULL;
+}
+
+extern void zlog_live_close(struct zlog_live_cfg *cfg);
+extern void zlog_live_disown(struct zlog_live_cfg *cfg);
+
+#endif /* _FRR_ZLOG_5424_H */
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
index d618ed86e0..87407245b3 100644
--- a/ospf6d/ospf6_gr.c
+++ b/ospf6d/ospf6_gr.c
@@ -689,7 +689,7 @@ DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
"graceful-restart prepare ipv6 ospf",
"Graceful Restart commands\n"
"Prepare upcoming graceful restart\n" IPV6_STR
- "Prepare to restart the OSPFv3 process")
+ "Prepare to restart the OSPFv3 process\n")
{
ospf6_gr_prepare();
diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c
index 5f9b7f0294..7b5ffc920b 100644
--- a/ospf6d/ospf6_gr_helper.c
+++ b/ospf6d/ospf6_gr_helper.c
@@ -960,13 +960,22 @@ static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
json, "supportedGracePeriod",
ospf6->ospf6_helper_cfg.supported_grace_time);
- if (ospf6->ospf6_helper_cfg.last_exit_reason
- != OSPF6_GR_HELPER_EXIT_NONE)
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
+ if (ospf6->ospf6_helper_cfg.last_exit_reason !=
+ OSPF6_GR_HELPER_EXIT_NONE) {
json_object_string_add(
json, "LastExitReason",
ospf6_exit_reason_desc
[ospf6->ospf6_helper_cfg
.last_exit_reason]);
+ json_object_string_add(
+ json, "lastExitReason",
+ ospf6_exit_reason_desc
+ [ospf6->ospf6_helper_cfg
+ .last_exit_reason]);
+ }
if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
struct json_object *json_rid_array =
@@ -995,12 +1004,18 @@ static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
json_object_object_get_ex(
json, "Neighbors",
&json_neighbors);
+ json_object_object_get_ex(
+ json, "neighbors",
+ &json_neighbors);
if (!json_neighbors) {
json_neighbors =
json_object_new_object();
json_object_object_add(
json, "Neighbors",
json_neighbors);
+ json_object_object_add(
+ json, "neighbors",
+ json_neighbors);
}
}
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 740a94ba84..779076f387 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -85,9 +85,13 @@ static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
start = (uint8_t *)lsa->header + sizeof(struct ospf6_lsa_header);
end = (uint8_t *)lsa->header + ntohs(lsa->header->length);
- if (use_json)
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
+ if (use_json) {
json_object_string_add(json_obj, "LsaType", "unknown");
- else {
+ json_object_string_add(json_obj, "lsaType", "unknown");
+ } else {
vty_out(vty, " Unknown contents:\n");
for (current = start; current < end; current++) {
if ((current - start) % 16 == 0)
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index e64bf24b66..2a6d7cd099 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -2017,6 +2017,9 @@ ospf6_show_vrf_name(struct vty *vty, struct ospf6 *ospf6,
}
}
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys containing whitespaces")
+#endif
static int
ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
json_object *json,
@@ -2037,7 +2040,9 @@ ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
ospf6_show_vrf_name(vty, ospf6, json_vrf);
json_object_int_add(json_vrf, "aggregation delay interval",
- ospf6->aggr_delay_interval);
+ ospf6->aggr_delay_interval);
+ json_object_int_add(json_vrf, "aggregationDelayInterval",
+ ospf6->aggr_delay_interval);
}
@@ -2062,12 +2067,18 @@ ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
json_object_string_add(json_aggr,
"Summary address",
buf);
+ json_object_string_add(json_aggr, "summaryAddress",
+ buf);
json_object_string_add(
json_aggr, "Metric-type",
(aggr->mtype == DEFAULT_METRIC_TYPE)
? "E2"
: "E1");
+ json_object_string_add(
+ json_aggr, "metricType",
+ (aggr->mtype == DEFAULT_METRIC_TYPE) ? "E2"
+ : "E1");
json_object_int_add(json_aggr, "Metric",
(aggr->metric != -1)
@@ -2080,6 +2091,8 @@ ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
json_object_int_add(json_aggr,
"External route count",
OSPF6_EXTERNAL_RT_COUNT(aggr));
+ json_object_int_add(json_aggr, "externalRouteCount",
+ OSPF6_EXTERNAL_RT_COUNT(aggr));
if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) {
json_object_int_add(json_aggr, "ID",
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index e279d0411b..4b37c5bc20 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -166,19 +166,20 @@ static int ospf6_zebra_import_check_update(ZAPI_CALLBACK_ARGS)
{
struct ospf6 *ospf6;
struct zapi_route nhr;
+ struct prefix matched;
ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
if (ospf6 == NULL || !IS_OSPF6_ASBR(ospf6))
return 0;
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
zlog_err("%s[%u]: Failure to decode route", __func__,
ospf6->vrf_id);
return -1;
}
- if (nhr.prefix.family != AF_INET6 || nhr.prefix.prefixlen != 0
- || nhr.type == ZEBRA_ROUTE_OSPF6)
+ if (matched.family != AF_INET6 || matched.prefixlen != 0 ||
+ nhr.type == ZEBRA_ROUTE_OSPF6)
return 0;
ospf6->nssa_default_import_check.status = !!nhr.nexthop_num;
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/ospfd/ospf_gr.c b/ospfd/ospf_gr.c
index ee1ca256e3..2521f2fce0 100644
--- a/ospfd/ospf_gr.c
+++ b/ospfd/ospf_gr.c
@@ -730,7 +730,7 @@ DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd,
"Graceful Restart commands\n"
"Prepare upcoming graceful restart\n"
IP_STR
- "Prepare to restart the OSPF process")
+ "Prepare to restart the OSPF process\n")
{
struct ospf *ospf;
struct listnode *node;
diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c
index 9b3498bc1e..f6c1b43610 100644
--- a/ospfd/ospf_ldp_sync.c
+++ b/ospfd/ospf_ldp_sync.c
@@ -508,10 +508,17 @@ void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
if (use_json) {
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
json_object_boolean_true_add(json_vrf,
"MplsLdpIgpSyncEnabled");
+ json_object_boolean_true_add(json_vrf,
+ "mplsLdpIgpSyncEnabled");
json_object_int_add(json_vrf, "MplsLdpIgpSyncHolddown",
ospf->ldp_sync_cmd.holddown);
+ json_object_int_add(json_vrf, "mplsLdpIgpSyncHolddown",
+ ospf->ldp_sync_cmd.holddown);
} else {
vty_out(vty, " MPLS LDP-IGP Sync is enabled\n");
if (ospf->ldp_sync_cmd.holddown == 0)
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 780521bfe4..da90435c5b 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -10185,10 +10185,17 @@ static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf,
json_object_int_add(json_vrf, "supportedGracePeriod",
ospf->supported_grace_time);
- if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE)
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
+ if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) {
json_object_string_add(
json_vrf, "LastExitReason",
ospf_exit_reason2str(ospf->last_exit_reason));
+ json_object_string_add(
+ json_vrf, "lastExitReason",
+ ospf_exit_reason2str(ospf->last_exit_reason));
+ }
if (ospf->active_restarter_cnt)
json_object_int_add(json_vrf, "activeRestarterCnt",
@@ -10211,12 +10218,17 @@ static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf,
if (uj) {
json_object_object_get_ex(json_vrf, "Neighbors",
&json_neighbors);
+ json_object_object_get_ex(json_vrf, "neighbors",
+ &json_neighbors);
if (!json_neighbors) {
json_neighbors =
json_object_new_object();
json_object_object_add(json_vrf,
"Neighbors",
json_neighbors);
+ json_object_object_add(json_vrf,
+ "neighbors",
+ json_neighbors);
}
}
@@ -10514,6 +10526,9 @@ static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
return;
}
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys containing whitespaces")
+#endif
static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
struct route_table *rt,
json_object *json)
@@ -10621,6 +10636,12 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
ifindex2ifname(
path->ifindex,
ospf->vrf_id));
+ json_object_string_add(
+ json_nexthop,
+ "directlyAttachedTo",
+ ifindex2ifname(
+ path->ifindex,
+ ospf->vrf_id));
} else {
vty_out(vty,
"%24s directly attached to %s\n",
@@ -10706,9 +10727,12 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
json_object_string_addf(json_route, "area",
"%pI4",
&or->u.std.area_id);
- if (or->path_type == OSPF_PATH_INTER_AREA)
+ if (or->path_type == OSPF_PATH_INTER_AREA) {
json_object_boolean_true_add(json_route,
"IA");
+ json_object_boolean_true_add(json_route,
+ "ia");
+ }
if (or->u.std.flags & ROUTER_LSA_BORDER)
json_object_string_add(json_route,
"routerType",
@@ -10760,6 +10784,12 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
ifindex2ifname(
path->ifindex,
ospf->vrf_id));
+ json_object_string_add(
+ json_nexthop,
+ "directlyAttachedTo",
+ ifindex2ifname(
+ path->ifindex,
+ ospf->vrf_id));
} else {
vty_out(vty,
"%24s directly attached to %s\n",
@@ -10886,6 +10916,12 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
ifindex2ifname(
path->ifindex,
ospf->vrf_id));
+ json_object_string_add(
+ json_nexthop,
+ "directlyAttachedTo",
+ ifindex2ifname(
+ path->ifindex,
+ ospf->vrf_id));
} else {
vty_out(vty,
"%24s directly attached to %s\n",
@@ -11408,12 +11444,15 @@ static int ospf_show_summary_address(struct vty *vty, struct ospf *ospf,
ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
- if (!uj)
+ if (!uj) {
vty_out(vty, "aggregation delay interval :%u(in seconds)\n\n",
ospf->aggr_delay_interval);
- else
+ } else {
json_object_int_add(json_vrf, "aggregation delay interval",
ospf->aggr_delay_interval);
+ json_object_int_add(json_vrf, "aggregationDelayInterval",
+ ospf->aggr_delay_interval);
+ }
for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn))
if (rn->info) {
@@ -11432,21 +11471,37 @@ static int ospf_show_summary_address(struct vty *vty, struct ospf *ospf,
json_object_string_add(json_aggr,
"Summary address", buf);
+ json_object_string_add(json_aggr,
+ "summaryAddress", buf);
json_object_string_add(
json_aggr, "Metric-type",
(mtype == EXTERNAL_METRIC_TYPE_1)
? "E1"
: "E2");
+ json_object_string_add(
+ json_aggr, "metricType",
+ (mtype == EXTERNAL_METRIC_TYPE_1)
+ ? "E1"
+ : "E2");
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
json_object_int_add(json_aggr, "Metric", mval);
+ json_object_int_add(json_aggr, "metric", mval);
json_object_int_add(json_aggr, "Tag",
aggr->tag);
+ json_object_int_add(json_aggr, "tag",
+ aggr->tag);
json_object_int_add(
json_aggr, "External route count",
OSPF_EXTERNAL_RT_COUNT(aggr));
+ json_object_int_add(
+ json_aggr, "externalRouteCount",
+ OSPF_EXTERNAL_RT_COUNT(aggr));
if (OSPF_EXTERNAL_RT_COUNT(aggr) && detail) {
hash_walk(
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index b480d4072e..f992588729 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -399,17 +399,19 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
{
struct zapi_route nhr;
+ struct prefix matched;
uint32_t i;
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
zlog_err("Failure to decode Nexthop update message");
return 0;
}
if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) {
- DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %pFX",
- __func__, &nhr.prefix);
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: Received Nexthop update: %pFX against %pFX",
+ __func__, &matched, &nhr.prefix);
DEBUGD(&pbr_dbg_zebra, "%s: (Nexthops(%u)", __func__,
nhr.nexthop_num);
@@ -423,6 +425,7 @@ static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
}
}
+ nhr.prefix = matched;
pbr_nht_nexthop_update(&nhr);
return 1;
}
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
new file mode 100644
index 0000000000..e3130b1564
--- /dev/null
+++ b/pimd/pim6_cmd.c
@@ -0,0 +1,494 @@
+/*
+ * PIM for IPv6 FRR
+ * Copyright (C) 2022 Vmware, Inc.
+ * Mobashshera Rasool <mrasool@vmware.com>
+ *
+ * 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 Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/json.h"
+#include "command.h"
+#include "if.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
+#include "vrf.h"
+#include "ferr.h"
+
+#include "pimd.h"
+#include "pim6_cmd.h"
+#include "pim_vty.h"
+#include "lib/northbound_cli.h"
+#include "pim_errors.h"
+#include "pim_nb.h"
+#include "pim_cmd_common.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "pimd/pim6_cmd_clippy.c"
+#endif
+
+DEFPY (ipv6_pim_joinprune_time,
+ ipv6_pim_joinprune_time_cmd,
+ "ipv6 pim join-prune-interval (1-65535)$jpi",
+ IPV6_STR
+ PIM_STR
+ "Join Prune Send Interval\n"
+ "Seconds\n")
+{
+ return pim_process_join_prune_cmd(vty, jpi_str);
+}
+
+DEFPY (no_ipv6_pim_joinprune_time,
+ no_ipv6_pim_joinprune_time_cmd,
+ "no ipv6 pim join-prune-interval [(1-65535)]",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Join Prune Send Interval\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_join_prune_cmd(vty);
+}
+
+DEFPY (ipv6_pim_spt_switchover_infinity,
+ ipv6_pim_spt_switchover_infinity_cmd,
+ "ipv6 pim spt-switchover infinity-and-beyond",
+ IPV6_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ return pim_process_spt_switchover_infinity_cmd(vty);
+}
+
+DEFPY (ipv6_pim_spt_switchover_infinity_plist,
+ ipv6_pim_spt_switchover_infinity_plist_cmd,
+ "ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD$plist",
+ IPV6_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n"
+ "Prefix-List to control which groups to switch\n"
+ "Prefix-List name\n")
+{
+ return pim_process_spt_switchover_prefixlist_cmd(vty, plist);
+}
+
+DEFPY (no_ipv6_pim_spt_switchover_infinity,
+ no_ipv6_pim_spt_switchover_infinity_cmd,
+ "no ipv6 pim spt-switchover infinity-and-beyond",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ return pim_process_no_spt_switchover_cmd(vty);
+}
+
+DEFPY (no_ipv6_pim_spt_switchover_infinity_plist,
+ no_ipv6_pim_spt_switchover_infinity_plist_cmd,
+ "no ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n"
+ "Prefix-List to control which groups to switch\n"
+ "Prefix-List name\n")
+{
+ return pim_process_no_spt_switchover_cmd(vty);
+}
+
+DEFPY (ipv6_pim_packets,
+ ipv6_pim_packets_cmd,
+ "ipv6 pim packets (1-255)",
+ IPV6_STR
+ PIM_STR
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
+{
+ return pim_process_pim_packet_cmd(vty, packets_str);
+}
+
+DEFPY (no_ipv6_pim_packets,
+ no_ipv6_pim_packets_cmd,
+ "no ipv6 pim packets [(1-255)]",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "packets to process at one time per fd\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_pim_packet_cmd(vty);
+}
+
+DEFPY (ipv6_pim_keep_alive,
+ ipv6_pim_keep_alive_cmd,
+ "ipv6 pim keep-alive-timer (1-65535)$kat",
+ IPV6_STR
+ PIM_STR
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ return pim_process_keepalivetimer_cmd(vty, kat_str);
+}
+
+DEFPY (no_ipv6_pim_keep_alive,
+ no_ipv6_pim_keep_alive_cmd,
+ "no ipv6 pim keep-alive-timer [(1-65535)]",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Keep alive Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_keepalivetimer_cmd(vty);
+}
+
+DEFPY (ipv6_pim_rp_keep_alive,
+ ipv6_pim_rp_keep_alive_cmd,
+ "ipv6 pim rp keep-alive-timer (1-65535)$kat",
+ IPV6_STR
+ PIM_STR
+ "Rendevous Point\n"
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ return pim_process_rp_kat_cmd(vty, kat_str);
+}
+
+DEFPY (no_ipv6_pim_rp_keep_alive,
+ no_ipv6_pim_rp_keep_alive_cmd,
+ "no ipv6 pim rp keep-alive-timer [(1-65535)]",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Rendevous Point\n"
+ "Keep alive Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_rp_kat_cmd(vty);
+}
+
+DEFPY (ipv6_pim_register_suppress,
+ ipv6_pim_register_suppress_cmd,
+ "ipv6 pim register-suppress-time (1-65535)$rst",
+ IPV6_STR
+ PIM_STR
+ "Register Suppress Timer\n"
+ "Seconds\n")
+{
+ return pim_process_register_suppress_cmd(vty, rst_str);
+}
+
+DEFPY (no_ipv6_pim_register_suppress,
+ no_ipv6_pim_register_suppress_cmd,
+ "no ipv6 pim register-suppress-time [(1-65535)]",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Register Suppress Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ 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);
+
+ install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd);
+ install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd);
+ install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_plist_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_pim_spt_switchover_infinity_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_pim_spt_switchover_infinity_plist_cmd);
+ install_element(CONFIG_NODE, &ipv6_pim_packets_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_pim_packets_cmd);
+ install_element(CONFIG_NODE, &ipv6_pim_keep_alive_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_pim_keep_alive_cmd);
+ install_element(CONFIG_NODE, &ipv6_pim_rp_keep_alive_cmd);
+ 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
new file mode 100644
index 0000000000..ac5eb3f9bf
--- /dev/null
+++ b/pimd/pim6_cmd.h
@@ -0,0 +1,49 @@
+/*
+ * PIM for IPv6 FRR
+ * Copyright (C) 2022 Vmware, Inc.
+ * Mobashshera Rasool <mrasool@vmware.com>
+ *
+ * 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 Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef PIM6_CMD_H
+#define PIM6_CMD_H
+
+#define PIM_STR "PIM information\n"
+#define MLD_STR "MLD information\n"
+#define MLD_GROUP_STR "MLD groups information\n"
+#define MLD_SOURCE_STR "MLD sources information\n"
+#define IFACE_MLD_STR "Enable MLD operation\n"
+#define IFACE_MLD_QUERY_INTERVAL_STR "MLD host query interval\n"
+#define IFACE_MLD_QUERY_MAX_RESPONSE_TIME_STR \
+ "MLD max query response value (seconds)\n"
+#define IFACE_MLD_QUERY_MAX_RESPONSE_TIME_DSEC_STR \
+ "MLD max query response value (deciseconds)\n"
+#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"
+#define DEBUG_MLD_PACKETS_STR "MLD protocol packets\n"
+#define DEBUG_MLD_TRACE_STR "MLD internal daemon activity\n"
+
+void pim_cmd_init(void);
+
+#endif /* PIM6_CMD_H */
diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c
index a6cfe7682c..ed53924616 100644
--- a/pimd/pim6_main.c
+++ b/pimd/pim6_main.c
@@ -36,6 +36,8 @@
#include "pim_errors.h"
#include "pim_iface.h"
#include "pim_zebra.h"
+#include "pim_nb.h"
+#include "pim6_cmd.h"
zebra_capabilities_t _caps_p[] = {
ZCAP_SYS_ADMIN,
@@ -109,6 +111,9 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
&frr_route_map_info,
&frr_vrf_info,
&frr_routing_info,
+ &frr_pim_info,
+ &frr_pim_rp_info,
+ &frr_gmp_info,
};
/* clang-format off */
@@ -172,27 +177,23 @@ int main(int argc, char **argv, char **envp)
prefix_list_delete_hook(pim_prefix_list_update);
pim_route_map_init();
- pim_init();
#endif
-
+ pim_init();
/*
* Initialize zclient "update" and "lookup" sockets
*/
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 038baa0692..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,9 +99,25 @@ void pim_reg_del_on_couldreg_fail(struct interface *ifp)
{
}
-/*
- * CLI
- */
-void pim_cmd_init(void)
+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 1351fca225..e422a2e2da 100644
--- a/pimd/pim_addr.h
+++ b/pimd/pim_addr.h
@@ -32,6 +32,7 @@ typedef struct in_addr pim_addr;
#define PIM_AF AF_INET
#define PIM_AFI AFI_IP
#define PIM_MAX_BITLEN IPV4_MAX_BITLEN
+#define PIM_AF_NAME "ip"
union pimprefixptr {
prefixtype(pimprefixptr, struct prefix, p)
@@ -50,6 +51,7 @@ typedef struct in6_addr pim_addr;
#define PIM_AF AF_INET6
#define PIM_AFI AFI_IP6
#define PIM_MAX_BITLEN IPV6_MAX_BITLEN
+#define PIM_AF_NAME "ipv6"
union pimprefixptr {
prefixtype(pimprefixptr, struct prefix, p)
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index c2fe525b2d..c1f8220db6 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -50,15 +50,15 @@ void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
|| pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX
|| pim_ifp->bfd_config.min_tx != BFD_DEF_MIN_TX)
- vty_out(vty, " ip pim bfd %d %d %d\n",
+ vty_out(vty, " " PIM_AF_NAME " pim bfd %d %d %d\n",
pim_ifp->bfd_config.detection_multiplier,
pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
else
#endif /* ! HAVE_BFDD */
- vty_out(vty, " ip pim bfd\n");
+ vty_out(vty, " " PIM_AF_NAME " pim bfd\n");
if (pim_ifp->bfd_config.profile)
- vty_out(vty, " ip pim bfd profile %s\n",
+ vty_out(vty, " " PIM_AF_NAME " pim bfd profile %s\n",
pim_ifp->bfd_config.profile);
}
diff --git a/pimd/pim_br.c b/pimd/pim_br.c
index 3e64296deb..6ec6b11e7b 100644
--- a/pimd/pim_br.c
+++ b/pimd/pim_br.c
@@ -30,14 +30,12 @@
struct pim_br {
pim_sgaddr sg;
- struct in_addr pmbr;
+ pim_addr pmbr;
};
-struct in_addr pim_br_unknown = {.s_addr = 0};
-
static struct list *pim_br_list = NULL;
-struct in_addr pim_br_get_pmbr(pim_sgaddr *sg)
+pim_addr pim_br_get_pmbr(pim_sgaddr *sg)
{
struct listnode *node;
struct pim_br *pim_br;
@@ -47,10 +45,10 @@ struct in_addr pim_br_get_pmbr(pim_sgaddr *sg)
return pim_br->pmbr;
}
- return pim_br_unknown;
+ return PIMADDR_ANY;
}
-void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr br)
+void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr br)
{
struct listnode *node, *next;
struct pim_br *pim_br;
diff --git a/pimd/pim_br.h b/pimd/pim_br.h
index ef24ef3c19..7b87c0f1fd 100644
--- a/pimd/pim_br.h
+++ b/pimd/pim_br.h
@@ -20,13 +20,11 @@
#ifndef PIM_BR_H
#define PIM_BR_H
-struct in_addr pim_br_get_pmbr(pim_sgaddr *sg);
+pim_addr pim_br_get_pmbr(pim_sgaddr *sg);
-void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr value);
+void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr value);
void pim_br_clear_pmbr(pim_sgaddr *sg);
void pim_br_init(void);
-extern struct in_addr pim_br_unknown;
-
#endif
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 8d65901b57..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);
@@ -59,9 +60,9 @@ void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
if (pim_ifp) {
if (!pim_ifp->bsm_enable)
- vty_out(vty, " no ip pim bsm\n");
+ vty_out(vty, " no " PIM_AF_NAME " pim bsm\n");
if (!pim_ifp->ucast_bsm_accept)
- vty_out(vty, " no ip pim unicast-bsm\n");
+ vty_out(vty, " no " PIM_AF_NAME " pim unicast-bsm\n");
}
}
@@ -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 3e3074827f..2a6d03fb91 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -67,6 +67,7 @@
#include "lib/northbound_cli.h"
#include "pim_errors.h"
#include "pim_nb.h"
+#include "pim_cmd_common.h"
#ifndef VTYSH_EXTRACT_PL
#include "pimd/pim_cmd_clippy.c"
@@ -454,8 +455,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
json_object_free(json);
}
-static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
- int mloop)
+static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
{
vty_out(vty, "Flags\n");
vty_out(vty, "-----\n");
@@ -468,7 +468,6 @@ static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
vty_out(vty, "Multicast : %s\n",
if_is_multicast(ifp) ? "yes" : "no");
- vty_out(vty, "Multicast Loop : %d\n", mloop);
vty_out(vty, "Promiscuous : %s\n",
(ifp->flags & IFF_PROMISC) ? "yes" : "no");
vty_out(vty, "\n");
@@ -575,7 +574,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
char other_hhmmss[10];
int found_ifname = 0;
int sqi;
- int mloop = 0;
long gmi_msec; /* Group Membership Interval */
long lmqt_msec;
long ohpi_msec;
@@ -638,11 +636,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
qri_msec =
pim_ifp->gm_query_max_response_time_dsec * 100;
- if (pim_ifp->pim_sock_fd >= 0)
- mloop = pim_socket_mcastloop_get(
- pim_ifp->pim_sock_fd);
- else
- mloop = 0;
lmqc = pim_ifp->gm_last_member_query_count;
if (uj) {
@@ -775,7 +768,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
vty_out(vty, "\n");
vty_out(vty, "\n");
- pim_print_ifp_flags(vty, ifp, mloop);
+ pim_print_ifp_flags(vty, ifp);
}
}
}
@@ -902,7 +895,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
char src_str[INET_ADDRSTRLEN];
char stat_uptime[10];
char uptime[10];
- int mloop = 0;
int found_ifname = 0;
int print_header;
json_object *json = NULL;
@@ -944,10 +936,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
pim_ifp->pim_hello_period);
pim_time_uptime(stat_uptime, sizeof(stat_uptime),
now - pim_ifp->pim_ifstat_start);
- if (pim_ifp->pim_sock_fd >= 0)
- mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
- else
- mloop = 0;
if (uj) {
char pbuf[PREFIX2STR_BUFFER];
@@ -1095,8 +1083,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
pim_ifp->pim_ifstat_hello_sendfail);
json_object_int_add(json_row, "helloGenerationId",
pim_ifp->pim_generation_id);
- json_object_int_add(json_row, "flagMulticastLoop",
- mloop);
json_object_int_add(
json_row, "effectivePropagationDelay",
@@ -1249,7 +1235,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
vty_out(vty, "\n");
vty_out(vty, "\n");
- pim_print_ifp_flags(vty, ifp, mloop);
+ pim_print_ifp_flags(vty, ifp);
vty_out(vty, "Join Prune Interval\n");
vty_out(vty, "-------------------\n");
@@ -1298,14 +1284,21 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
const char *ifname, bool uj)
{
struct interface *ifp;
- struct igmp_stats rx_stats;
+ struct igmp_stats igmp_stats;
+ bool found_ifname = false;
+ json_object *json = NULL;
- igmp_stats_init(&rx_stats);
+ igmp_stats_init(&igmp_stats);
+
+ if (uj)
+ json = json_object_new_object();
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
- struct listnode *sock_node;
+ struct listnode *sock_node, *source_node, *group_node;
struct gm_sock *igmp;
+ struct gm_group *group;
+ struct gm_source *src;
pim_ifp = ifp->info;
@@ -1315,50 +1308,119 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
if (ifname && strcmp(ifname, ifp->name))
continue;
+ found_ifname = true;
+
+ igmp_stats.joins_failed += pim_ifp->igmp_ifstat_joins_failed;
+ igmp_stats.joins_sent += pim_ifp->igmp_ifstat_joins_sent;
+ igmp_stats.total_groups +=
+ pim_ifp->gm_group_list
+ ? listcount(pim_ifp->gm_group_list)
+ : 0;
+ igmp_stats.peak_groups += pim_ifp->igmp_peak_group_count;
+
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node,
+ group)) {
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list,
+ source_node, src)) {
+ if (pim_addr_is_any(src->source_addr))
+ continue;
+
+ igmp_stats.total_source_groups++;
+ }
+ }
+
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node,
igmp)) {
- igmp_stats_add(&rx_stats, &igmp->rx_stats);
+ igmp_stats_add(&igmp_stats, &igmp->igmp_stats);
}
}
- if (uj) {
- json_object *json = NULL;
- json_object *json_row = NULL;
- json = json_object_new_object();
- json_row = json_object_new_object();
+ if (!found_ifname) {
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty, "%% No such interface\n");
+ return;
+ }
- json_object_string_add(json_row, "name", ifname ? ifname :
- "global");
- json_object_int_add(json_row, "queryV1", rx_stats.query_v1);
- json_object_int_add(json_row, "queryV2", rx_stats.query_v2);
- json_object_int_add(json_row, "queryV3", rx_stats.query_v3);
- json_object_int_add(json_row, "leaveV3", rx_stats.leave_v2);
- json_object_int_add(json_row, "reportV1", rx_stats.report_v1);
- json_object_int_add(json_row, "reportV2", rx_stats.report_v2);
- json_object_int_add(json_row, "reportV3", rx_stats.report_v3);
+ if (uj) {
+ json_object *json_row = json_object_new_object();
+
+ json_object_string_add(json_row, "name",
+ ifname ? ifname : "global");
+ json_object_int_add(json_row, "queryV1", igmp_stats.query_v1);
+ json_object_int_add(json_row, "queryV2", igmp_stats.query_v2);
+ json_object_int_add(json_row, "queryV3", igmp_stats.query_v3);
+ json_object_int_add(json_row, "leaveV2", igmp_stats.leave_v2);
+ json_object_int_add(json_row, "reportV1", igmp_stats.report_v1);
+ json_object_int_add(json_row, "reportV2", igmp_stats.report_v2);
+ json_object_int_add(json_row, "reportV3", igmp_stats.report_v3);
json_object_int_add(json_row, "mtraceResponse",
- rx_stats.mtrace_rsp);
+ igmp_stats.mtrace_rsp);
json_object_int_add(json_row, "mtraceRequest",
- rx_stats.mtrace_req);
+ igmp_stats.mtrace_req);
json_object_int_add(json_row, "unsupported",
- rx_stats.unsupported);
+ igmp_stats.unsupported);
+ json_object_int_add(json_row, "totalReceivedMessages",
+ igmp_stats.total_recv_messages);
+ json_object_int_add(json_row, "peakGroups",
+ igmp_stats.peak_groups);
+ json_object_int_add(json_row, "totalGroups",
+ igmp_stats.total_groups);
+ json_object_int_add(json_row, "totalSourceGroups",
+ igmp_stats.total_source_groups);
+ json_object_int_add(json_row, "joinsFailed",
+ igmp_stats.joins_failed);
+ json_object_int_add(json_row, "joinsSent",
+ igmp_stats.joins_sent);
+ json_object_int_add(json_row, "generalQueriesSent",
+ igmp_stats.general_queries_sent);
+ json_object_int_add(json_row, "groupQueriesSent",
+ igmp_stats.group_queries_sent);
json_object_object_add(json, ifname ? ifname : "global",
json_row);
vty_json(vty, json);
} else {
- vty_out(vty, "IGMP RX statistics\n");
- vty_out(vty, "Interface : %s\n",
+ vty_out(vty, "IGMP statistics\n");
+ vty_out(vty, "Interface : %s\n",
ifname ? ifname : "global");
- vty_out(vty, "V1 query : %u\n", rx_stats.query_v1);
- vty_out(vty, "V2 query : %u\n", rx_stats.query_v2);
- vty_out(vty, "V3 query : %u\n", rx_stats.query_v3);
- vty_out(vty, "V2 leave : %u\n", rx_stats.leave_v2);
- vty_out(vty, "V1 report : %u\n", rx_stats.report_v1);
- vty_out(vty, "V2 report : %u\n", rx_stats.report_v2);
- vty_out(vty, "V3 report : %u\n", rx_stats.report_v3);
- vty_out(vty, "mtrace response : %u\n", rx_stats.mtrace_rsp);
- vty_out(vty, "mtrace request : %u\n", rx_stats.mtrace_req);
- vty_out(vty, "unsupported : %u\n", rx_stats.unsupported);
+ vty_out(vty, "V1 query : %u\n",
+ igmp_stats.query_v1);
+ vty_out(vty, "V2 query : %u\n",
+ igmp_stats.query_v2);
+ vty_out(vty, "V3 query : %u\n",
+ igmp_stats.query_v3);
+ vty_out(vty, "V2 leave : %u\n",
+ igmp_stats.leave_v2);
+ vty_out(vty, "V1 report : %u\n",
+ igmp_stats.report_v1);
+ vty_out(vty, "V2 report : %u\n",
+ igmp_stats.report_v2);
+ vty_out(vty, "V3 report : %u\n",
+ igmp_stats.report_v3);
+ vty_out(vty, "mtrace response : %u\n",
+ igmp_stats.mtrace_rsp);
+ vty_out(vty, "mtrace request : %u\n",
+ igmp_stats.mtrace_req);
+ vty_out(vty, "unsupported : %u\n",
+ igmp_stats.unsupported);
+ vty_out(vty, "total received messages : %u\n",
+ igmp_stats.total_recv_messages);
+ vty_out(vty, "joins failed : %u\n",
+ igmp_stats.joins_failed);
+ vty_out(vty, "joins sent : %u\n",
+ igmp_stats.joins_sent);
+ vty_out(vty, "general queries sent : %u\n",
+ igmp_stats.general_queries_sent);
+ vty_out(vty, "group queries sent : %u\n",
+ igmp_stats.group_queries_sent);
+ vty_out(vty, "peak groups : %u\n",
+ igmp_stats.peak_groups);
+ vty_out(vty, "total groups : %u\n",
+ igmp_stats.total_groups);
+ vty_out(vty, "total source groups : %u\n",
+ igmp_stats.total_source_groups);
}
}
@@ -1685,8 +1747,13 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
json_object_string_add(
json_row, "channelJoinName",
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
- if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
+ if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
+#if CONFDATE > 20230131
+CPP_NOTICE("Remove JSON object commands with keys starting with capital")
+#endif
json_object_int_add(json_row, "SGRpt", 1);
+ json_object_int_add(json_row, "sgRpt", 1);
+ }
if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
json_object_int_add(json_row, "protocolPim", 1);
if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
@@ -2036,6 +2103,8 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_ifp_in);
json_object_int_add(json_source, "Installed",
c_oil->installed);
+ json_object_int_add(json_source, "installed",
+ c_oil->installed);
if (isRpt)
json_object_boolean_true_add(
json_source, "isRpt");
@@ -2044,20 +2113,36 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_source, "isRpt");
json_object_int_add(json_source, "RefCount",
c_oil->oil_ref_count);
+ json_object_int_add(json_source, "refCount",
+ c_oil->oil_ref_count);
json_object_int_add(json_source, "OilListSize",
c_oil->oil_size);
+ json_object_int_add(json_source, "oilListSize",
+ c_oil->oil_size);
json_object_int_add(
json_source, "OilRescan",
c_oil->oil_inherited_rescan);
+ json_object_int_add(
+ json_source, "oilRescan",
+ c_oil->oil_inherited_rescan);
json_object_int_add(json_source, "LastUsed",
c_oil->cc.lastused);
+ json_object_int_add(json_source, "lastUsed",
+ c_oil->cc.lastused);
json_object_int_add(json_source, "PacketCount",
c_oil->cc.pktcnt);
+ json_object_int_add(json_source, "packetCount",
+ c_oil->cc.pktcnt);
json_object_int_add(json_source, "ByteCount",
c_oil->cc.bytecnt);
+ json_object_int_add(json_source, "byteCount",
+ c_oil->cc.bytecnt);
json_object_int_add(json_source,
"WrongInterface",
c_oil->cc.wrong_if);
+ json_object_int_add(json_source,
+ "wrongInterface",
+ c_oil->cc.wrong_if);
}
} else {
vty_out(vty, "%-6d %-15s %-15s %-3s %-16s ",
@@ -3761,32 +3846,6 @@ static void clear_interfaces(struct pim_instance *pim)
}
/**
- * Get current node VRF name.
- *
- * NOTE:
- * In case of failure it will print error message to user.
- *
- * \returns name or NULL if failed to get VRF.
- */
-static const char *pim_cli_get_vrf_name(struct vty *vty)
-{
- const struct lyd_node *vrf_node;
-
- /* Not inside any VRF context. */
- if (vty->xpath_index == 0)
- return VRF_DEFAULT_NAME;
-
- vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (vrf_node == NULL) {
- vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
- return NULL;
- }
-
- return yang_dnode_get_string(vrf_node, "./name");
-}
-
-#if PIM_IPV != 6
-/**
* Compatibility function to keep the legacy mesh group CLI behavior:
* Delete group when there are no more configurations in it.
*
@@ -3833,7 +3892,6 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
/* No configurations found: delete it. */
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
}
-#endif /* PIM_IPV != 6 */
DEFUN (clear_ip_interfaces,
clear_ip_interfaces_cmd,
@@ -4009,6 +4067,9 @@ DEFUN (clear_ip_pim_interface_traffic,
pim_ifp->pim_ifstat_assert_send = 0;
pim_ifp->pim_ifstat_bsm_rx = 0;
pim_ifp->pim_ifstat_bsm_tx = 0;
+ pim_ifp->igmp_ifstat_joins_sent = 0;
+ pim_ifp->igmp_ifstat_joins_failed = 0;
+ pim_ifp->igmp_peak_group_count = 0;
}
return CMD_SUCCESS;
@@ -5339,39 +5400,56 @@ DEFUN (show_ip_pim_upstream_rpf,
DEFUN (show_ip_pim_rp,
show_ip_pim_rp_cmd,
- "show ip pim [vrf NAME] rp-info [json]",
+ "show ip pim [vrf NAME] rp-info [A.B.C.D/M] [json]",
SHOW_STR
IP_STR
PIM_STR
VRF_CMD_HELP_STR
"PIM RP information\n"
+ "Multicast Group range\n"
JSON_STR)
{
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
bool uj = use_json(argc, argv);
+ struct prefix *range = NULL;
if (!vrf)
return CMD_WARNING;
- pim_rp_show_information(vrf->info, vty, uj);
+ if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
+ range = prefix_new();
+ (void)str2prefix(argv[idx]->arg, range);
+ apply_mask(range);
+ }
+
+ pim_rp_show_information(vrf->info, range, vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_rp_vrf_all,
show_ip_pim_rp_vrf_all_cmd,
- "show ip pim vrf all rp-info [json]",
+ "show ip pim vrf all rp-info [A.B.C.D/M] [json]",
SHOW_STR
IP_STR
PIM_STR
VRF_CMD_HELP_STR
"PIM RP information\n"
+ "Multicast Group range\n"
JSON_STR)
{
+ int idx = 0;
bool uj = use_json(argc, argv);
struct vrf *vrf;
bool first = true;
+ struct prefix *range = NULL;
+
+ if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
+ range = prefix_new();
+ (void)str2prefix(argv[idx]->arg, range);
+ apply_mask(range);
+ }
if (uj)
vty_out(vty, "{ ");
@@ -5383,7 +5461,7 @@ DEFUN (show_ip_pim_rp_vrf_all,
first = false;
} else
vty_out(vty, "VRF: %s\n", vrf->name);
- pim_rp_show_information(vrf->info, vty, uj);
+ pim_rp_show_information(vrf->info, range, vty, uj);
}
if (uj)
vty_out(vty, "}\n");
@@ -5986,6 +6064,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
c_oil->oil_size);
json_object_int_add(json_source, "OilInheritedRescan",
c_oil->oil_inherited_rescan);
+ json_object_int_add(json_source, "oilInheritedRescan",
+ c_oil->oil_inherited_rescan);
json_object_string_add(json_source, "iif", in_ifname);
json_object_string_add(json_source, "upTime",
mroute_uptime);
@@ -6750,38 +6830,12 @@ DEFUN (ip_pim_spt_switchover_infinity,
"SPT-Switchover\n"
"Never switch to SPT Tree\n")
{
- const char *vrfname;
- char spt_plist_xpath[XPATH_MAXLEN];
- char spt_action_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
- sizeof(spt_plist_xpath));
-
- snprintf(spt_action_xpath, sizeof(spt_action_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_action_xpath, "/spt-switchover/spt-action",
- sizeof(spt_action_xpath));
-
- if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
- nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
- NULL);
- nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
- "PIM_SPT_INFINITY");
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_spt_switchover_infinity_cmd(vty);
}
-DEFUN (ip_pim_spt_switchover_infinity_plist,
+DEFPY (ip_pim_spt_switchover_infinity_plist,
ip_pim_spt_switchover_infinity_plist_cmd,
- "ip pim spt-switchover infinity-and-beyond prefix-list WORD",
+ "ip pim spt-switchover infinity-and-beyond prefix-list WORD$plist",
IP_STR
PIM_STR
"SPT-Switchover\n"
@@ -6789,32 +6843,7 @@ DEFUN (ip_pim_spt_switchover_infinity_plist,
"Prefix-List to control which groups to switch\n"
"Prefix-List name\n")
{
- const char *vrfname;
- char spt_plist_xpath[XPATH_MAXLEN];
- char spt_action_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
- sizeof(spt_plist_xpath));
-
- snprintf(spt_action_xpath, sizeof(spt_action_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_action_xpath, "/spt-switchover/spt-action",
- sizeof(spt_action_xpath));
-
- nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
- "PIM_SPT_INFINITY");
- nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
- argv[5]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_spt_switchover_prefixlist_cmd(vty, plist);
}
DEFUN (no_ip_pim_spt_switchover_infinity,
@@ -6826,31 +6855,7 @@ DEFUN (no_ip_pim_spt_switchover_infinity,
"SPT_Switchover\n"
"Never switch to SPT Tree\n")
{
- const char *vrfname;
- char spt_plist_xpath[XPATH_MAXLEN];
- char spt_action_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
- sizeof(spt_plist_xpath));
-
- snprintf(spt_action_xpath, sizeof(spt_action_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_action_xpath, "/spt-switchover/spt-action",
- sizeof(spt_action_xpath));
-
- nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
- nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
- "PIM_SPT_IMMEDIATE");
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_spt_switchover_cmd(vty);
}
DEFUN (no_ip_pim_spt_switchover_infinity_plist,
@@ -6864,31 +6869,7 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist,
"Prefix-List to control which groups to switch\n"
"Prefix-List name\n")
{
- const char *vrfname;
- char spt_plist_xpath[XPATH_MAXLEN];
- char spt_action_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
- sizeof(spt_plist_xpath));
-
- snprintf(spt_action_xpath, sizeof(spt_action_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(spt_action_xpath, "/spt-switchover/spt-action",
- sizeof(spt_action_xpath));
-
- nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
- nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
- "PIM_SPT_IMMEDIATE");
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_spt_switchover_cmd(vty);
}
DEFPY (pim_register_accept_list,
@@ -6923,23 +6904,15 @@ DEFPY (pim_register_accept_list,
return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (ip_pim_joinprune_time,
+DEFPY (ip_pim_joinprune_time,
ip_pim_joinprune_time_cmd,
- "ip pim join-prune-interval (1-65535)",
+ "ip pim join-prune-interval (1-65535)$jpi",
IP_STR
"pim multicast routing\n"
"Join Prune Send Interval\n"
"Seconds\n")
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/join-prune-interval", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_join_prune_cmd(vty, jpi_str);
}
DEFUN (no_ip_pim_joinprune_time,
@@ -6951,34 +6924,18 @@ DEFUN (no_ip_pim_joinprune_time,
"Join Prune Send Interval\n"
IGNORED_IN_NO_STR)
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/join-prune-interval", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_join_prune_cmd(vty);
}
-DEFUN (ip_pim_register_suppress,
+DEFPY (ip_pim_register_suppress,
ip_pim_register_suppress_cmd,
- "ip pim register-suppress-time (1-65535)",
+ "ip pim register-suppress-time (1-65535)$rst",
IP_STR
"pim multicast routing\n"
"Register Suppress Timer\n"
"Seconds\n")
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/register-suppress-time", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_register_suppress_cmd(vty, rst_str);
}
DEFUN (no_ip_pim_register_suppress,
@@ -6990,43 +6947,19 @@ DEFUN (no_ip_pim_register_suppress,
"Register Suppress Timer\n"
IGNORED_IN_NO_STR)
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/register-suppress-time", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_register_suppress_cmd(vty);
}
-DEFUN (ip_pim_rp_keep_alive,
+DEFPY (ip_pim_rp_keep_alive,
ip_pim_rp_keep_alive_cmd,
- "ip pim rp keep-alive-timer (1-65535)",
+ "ip pim rp keep-alive-timer (1-65535)$kat",
IP_STR
"pim multicast routing\n"
"Rendevous Point\n"
"Keep alive Timer\n"
"Seconds\n")
{
- const char *vrfname;
- char rp_ka_timer_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
- sizeof(rp_ka_timer_xpath));
-
- nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
- argv[4]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_rp_kat_cmd(vty, kat_str);
}
DEFUN (no_ip_pim_rp_keep_alive,
@@ -7039,64 +6972,18 @@ DEFUN (no_ip_pim_rp_keep_alive,
"Keep alive Timer\n"
IGNORED_IN_NO_STR)
{
- const char *vrfname;
- char rp_ka_timer[6];
- char rp_ka_timer_xpath[XPATH_MAXLEN];
- uint v;
- char rs_timer_xpath[XPATH_MAXLEN];
-
- snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
- FRR_PIM_ROUTER_XPATH, "frr-routing:ipv4");
- strlcat(rs_timer_xpath, "/register-suppress-time",
- sizeof(rs_timer_xpath));
-
- /* RFC4601 */
- v = yang_dnode_get_uint16(vty->candidate_config->dnode,
- rs_timer_xpath);
- v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
- if (v > UINT16_MAX)
- v = UINT16_MAX;
- snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
- "frr-routing:ipv4");
- strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
- sizeof(rp_ka_timer_xpath));
-
- nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
- rp_ka_timer);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_rp_kat_cmd(vty);
}
-DEFUN (ip_pim_keep_alive,
+DEFPY (ip_pim_keep_alive,
ip_pim_keep_alive_cmd,
- "ip pim keep-alive-timer (1-65535)",
+ "ip pim keep-alive-timer (1-65535)$kat",
IP_STR
"pim multicast routing\n"
"Keep alive Timer\n"
"Seconds\n")
{
- const char *vrfname;
- char ka_timer_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
-
- nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
- argv[3]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_keepalivetimer_cmd(vty, kat_str);
}
DEFUN (no_ip_pim_keep_alive,
@@ -7108,23 +6995,10 @@ DEFUN (no_ip_pim_keep_alive,
"Keep alive Timer\n"
IGNORED_IN_NO_STR)
{
- const char *vrfname;
- char ka_timer_xpath[XPATH_MAXLEN];
-
- vrfname = pim_cli_get_vrf_name(vty);
- if (vrfname == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
-
- nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_keepalivetimer_cmd(vty);
}
-DEFUN (ip_pim_packets,
+DEFPY (ip_pim_packets,
ip_pim_packets_cmd,
"ip pim packets (1-255)",
IP_STR
@@ -7132,15 +7006,7 @@ DEFUN (ip_pim_packets,
"packets to process at one time per fd\n"
"Number of packets\n")
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/packets", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_pim_packet_cmd(vty, packets_str);
}
DEFUN (no_ip_pim_packets,
@@ -7152,15 +7018,7 @@ DEFUN (no_ip_pim_packets,
"packets to process at one time per fd\n"
IGNORED_IN_NO_STR)
{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
- "frr-routing:ipv4");
- strlcat(xpath, "/packets", sizeof(xpath));
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return pim_process_no_pim_packet_cmd(vty);
}
DEFPY (igmp_group_watermark,
@@ -7245,98 +7103,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;
- }
- }
+ const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4";
- 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;
- }
-
- 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"
@@ -7344,106 +7140,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;
+ 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_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);
-
- 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,
@@ -8207,11 +7920,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,
@@ -8223,10 +7932,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,
@@ -8317,20 +8023,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,
@@ -8342,11 +8035,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;
@@ -8364,11 +8053,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,
@@ -8377,12 +8062,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,
@@ -8393,39 +8073,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,
@@ -8436,41 +8084,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,
@@ -8480,41 +8094,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 */
@@ -8527,13 +8107,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,
@@ -8546,12 +8120,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,
@@ -8572,13 +8141,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,
@@ -8591,6 +8155,7 @@ DEFUN (interface_no_ip_mroute,
"Group Address\n"
"Source Address\n")
{
+ int idx_interface = 3;
int idx_ipv4 = 4;
const char *source_str;
@@ -8599,12 +8164,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,
@@ -8618,31 +8179,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,
@@ -8655,12 +8199,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,
@@ -9543,7 +9082,6 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
"Desired min transmit interval\n")
#endif /* !HAVE_BFDD */
-#if PIM_IPV != 6
DEFPY(ip_msdp_peer, ip_msdp_peer_cmd,
"ip msdp peer A.B.C.D$peer source A.B.C.D$source",
IP_STR
@@ -10571,7 +10109,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all,
return CMD_SUCCESS;
}
-#endif /* PIM_IPV != 6 */
struct pim_sg_cache_walk_data {
struct vty *vty;
@@ -11005,12 +10542,10 @@ void pim_cmd_init(void)
install_element(VRF_NODE, &ip_ssmpingd_cmd);
install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd);
install_element(VRF_NODE, &no_ip_ssmpingd_cmd);
-#if PIM_IPV != 6
install_element(CONFIG_NODE, &ip_msdp_peer_cmd);
install_element(VRF_NODE, &ip_msdp_peer_cmd);
install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd);
install_element(VRF_NODE, &no_ip_msdp_peer_cmd);
-#endif /* PIM_IPV != 6 */
install_element(CONFIG_NODE, &ip_pim_ecmp_cmd);
install_element(VRF_NODE, &ip_pim_ecmp_cmd);
install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd);
@@ -11179,14 +10714,12 @@ void pim_cmd_init(void)
install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd);
install_element(ENABLE_NODE, &debug_pim_vxlan_cmd);
install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd);
-#if PIM_IPV != 6
install_element(ENABLE_NODE, &debug_msdp_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_cmd);
install_element(ENABLE_NODE, &debug_msdp_events_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_events_cmd);
install_element(ENABLE_NODE, &debug_msdp_packets_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
-#endif /* PIM_IPV != 6 */
install_element(ENABLE_NODE, &debug_mtrace_cmd);
install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
install_element(ENABLE_NODE, &debug_bsm_cmd);
@@ -11232,20 +10765,17 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd);
install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
-#if PIM_IPV != 6
install_element(CONFIG_NODE, &debug_msdp_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_cmd);
install_element(CONFIG_NODE, &debug_msdp_events_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_events_cmd);
install_element(CONFIG_NODE, &debug_msdp_packets_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
-#endif /* PIM_IPV != 6 */
install_element(CONFIG_NODE, &debug_mtrace_cmd);
install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
install_element(CONFIG_NODE, &debug_bsm_cmd);
install_element(CONFIG_NODE, &no_debug_bsm_cmd);
-#if PIM_IPV != 6
install_element(CONFIG_NODE, &ip_msdp_timers_cmd);
install_element(VRF_NODE, &ip_msdp_timers_cmd);
install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd);
@@ -11268,7 +10798,6 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
-#endif /* PIM_IPV != 6 */
install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd);
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
new file mode 100644
index 0000000000..c5d89f8065
--- /dev/null
+++ b/pimd/pim_cmd_common.c
@@ -0,0 +1,655 @@
+/*
+ * PIM for IPv6 FRR
+ * Copyright (C) 2022 Vmware, Inc.
+ * Mobashshera Rasool <mrasool@vmware.com>
+ *
+ * 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 Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/json.h"
+#include "command.h"
+#include "if.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
+#include "vrf.h"
+#include "ferr.h"
+#include "lib/srcdest_table.h"
+
+#include "pimd.h"
+#include "pim_vty.h"
+#include "lib/northbound_cli.h"
+#include "pim_errors.h"
+#include "pim_nb.h"
+#include "pim_cmd_common.h"
+
+/**
+ * Get current node VRF name.
+ *
+ * NOTE:
+ * In case of failure it will print error message to user.
+ *
+ * \returns name or NULL if failed to get VRF.
+ */
+const char *pim_cli_get_vrf_name(struct vty *vty)
+{
+ const struct lyd_node *vrf_node;
+
+ /* Not inside any VRF context. */
+ if (vty->xpath_index == 0)
+ return VRF_DEFAULT_NAME;
+
+ vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (vrf_node == NULL) {
+ vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
+ return NULL;
+ }
+
+ return yang_dnode_get_string(vrf_node, "./name");
+}
+
+int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/join-prune-interval", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_join_prune_cmd(struct vty *vty)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/join-prune-interval", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_spt_switchover_infinity_cmd(struct vty *vty)
+{
+ const char *vrfname;
+ char spt_plist_xpath[XPATH_MAXLEN];
+ char spt_action_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+ sizeof(spt_plist_xpath));
+
+ snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+ sizeof(spt_action_xpath));
+
+ if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
+ nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
+ NULL);
+ nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+ "PIM_SPT_INFINITY");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
+ const char *plist)
+{
+ const char *vrfname;
+ char spt_plist_xpath[XPATH_MAXLEN];
+ char spt_action_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+ sizeof(spt_plist_xpath));
+
+ snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+ sizeof(spt_action_xpath));
+
+ nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+ "PIM_SPT_INFINITY");
+ nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
+ plist);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_spt_switchover_cmd(struct vty *vty)
+{
+ const char *vrfname;
+ char spt_plist_xpath[XPATH_MAXLEN];
+ char spt_action_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+ sizeof(spt_plist_xpath));
+
+ snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+ sizeof(spt_action_xpath));
+
+ nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+ "PIM_SPT_IMMEDIATE");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_pim_packet_cmd(struct vty *vty, const char *packet)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/packets", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_pim_packet_cmd(struct vty *vty)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/packets", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat)
+{
+ const char *vrfname;
+ char ka_timer_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
+ strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
+
+ nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
+ kat);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_keepalivetimer_cmd(struct vty *vty)
+{
+ const char *vrfname;
+ char ka_timer_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
+ strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
+
+ nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat)
+{
+ const char *vrfname;
+ char rp_ka_timer_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
+ sizeof(rp_ka_timer_xpath));
+
+ nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
+ rpkat);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_rp_kat_cmd(struct vty *vty)
+{
+ const char *vrfname;
+ char rp_ka_timer[6];
+ char rp_ka_timer_xpath[XPATH_MAXLEN];
+ uint v;
+ char rs_timer_xpath[XPATH_MAXLEN];
+
+ snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
+ FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL);
+ strlcat(rs_timer_xpath, "/register-suppress-time",
+ sizeof(rs_timer_xpath));
+
+ /* RFC4601 */
+ v = yang_dnode_get_uint16(vty->candidate_config->dnode,
+ rs_timer_xpath);
+ v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
+ if (v > UINT16_MAX)
+ v = UINT16_MAX;
+ snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
+ sizeof(rp_ka_timer_xpath));
+
+ nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
+ rp_ka_timer);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_register_suppress_cmd(struct vty *vty, const char *rst)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/register-suppress-time", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_register_suppress_cmd(struct vty *vty)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ strlcat(xpath, "/register-suppress-time", sizeof(xpath));
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ 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;
+ }
+
+ group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
+ if (!group_dnode) {
+ vty_out(vty, "%% Unable to find specified RP\n");
+ return NB_OK;
+ }
+
+ 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
new file mode 100644
index 0000000000..b7e6b6ac80
--- /dev/null
+++ b/pimd/pim_cmd_common.h
@@ -0,0 +1,62 @@
+/*
+ * PIM for IPv6 FRR
+ * Copyright (C) 2022 Vmware, Inc.
+ * Mobashshera Rasool <mrasool@vmware.com>
+ *
+ * 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 Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef PIM_CMD_COMMON_H
+#define PIM_CMD_COMMON_H
+
+const char *pim_cli_get_vrf_name(struct vty *vty);
+int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str);
+int pim_process_no_join_prune_cmd(struct vty *vty);
+int pim_process_spt_switchover_infinity_cmd(struct vty *vty);
+int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
+ const char *plist);
+int pim_process_no_spt_switchover_cmd(struct vty *vty);
+int pim_process_pim_packet_cmd(struct vty *vty, const char *packet);
+int pim_process_no_pim_packet_cmd(struct vty *vty);
+int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat);
+int pim_process_no_keepalivetimer_cmd(struct vty *vty);
+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_iface.c b/pimd/pim_iface.c
index 5425aec233..98fa4c4882 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -53,8 +53,8 @@
#if PIM_IPV == 4
static void pim_if_igmp_join_del_all(struct interface *ifp);
static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
- struct in_addr group_addr,
- struct in_addr source_addr);
+ struct in_addr group_addr, struct in_addr source_addr,
+ struct pim_interface *pim_ifp);
#endif
void pim_if_init(struct pim_instance *pim)
@@ -127,7 +127,6 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
pim_ifp->pim = ifp->vrf->info;
pim_ifp->mroute_vif_index = -1;
-#if PIM_IPV == 4
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->gm_default_robustness_variable =
IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
@@ -153,10 +152,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
if (pim)
PIM_IF_DO_PIM(pim_ifp->options);
+#if PIM_IPV == 4
if (igmp)
PIM_IF_DO_IGMP(pim_ifp->options);
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
+#endif
pim_ifp->gm_join_list = NULL;
pim_ifp->pim_neighbor_list = NULL;
@@ -186,10 +187,11 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
ifp->info = pim_ifp;
+#if PIM_IPV == 4
pim_sock_reset(ifp);
+#endif
pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
-#endif
pim_ifp->pim->mcast_if_count++;
return pim_ifp;
@@ -208,9 +210,12 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->gm_join_list) {
pim_if_igmp_join_del_all(ifp);
}
+#endif
pim_ifchannel_delete_all(ifp);
+#if PIM_IPV == 4
igmp_sock_delete_all(ifp);
+#endif
pim_neighbor_delete_all(ifp, "Interface removed from configuration");
@@ -224,7 +229,6 @@ void pim_if_delete(struct interface *ifp)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
-#endif
ifp->info = NULL;
}
@@ -512,6 +516,26 @@ void pim_if_addr_add(struct connected *ifc)
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
? "secondary"
: "primary");
+#if PIM_IPV != 4
+ if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
+ IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
+ pim_ifp->ll_lowest = ifc->address->u.prefix6;
+ else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest) < 0)
+ pim_ifp->ll_lowest = ifc->address->u.prefix6;
+
+ if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
+ &pim_ifp->ll_highest) > 0)
+ pim_ifp->ll_highest = ifc->address->u.prefix6;
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug(
+ "%s: new link-local %pI6, lowest now %pI6, highest %pI6",
+ ifc->ifp->name, &ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
+ }
+#endif
detect_address_change(ifp, 0, __func__);
@@ -552,7 +576,7 @@ void pim_if_addr_add(struct connected *ifc)
close(ij->sock_fd);
join_fd = igmp_join_sock(
ifp->name, ifp->ifindex, ij->group_addr,
- ij->source_addr);
+ ij->source_addr, pim_ifp);
if (join_fd < 0) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
@@ -711,6 +735,43 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
? "secondary"
: "primary");
+#if PIM_IPV == 6
+ struct pim_interface *pim_ifp = ifc->ifp->info;
+
+ if (pim_ifp &&
+ (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
+ !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
+ struct listnode *cnode;
+ struct connected *cc;
+
+ memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
+ memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
+
+ for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
+ if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
+ !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
+ continue;
+
+ if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
+ &pim_ifp->ll_lowest) < 0)
+ pim_ifp->ll_lowest = cc->address->u.prefix6;
+ if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
+ &pim_ifp->ll_highest) > 0)
+ pim_ifp->ll_highest = cc->address->u.prefix6;
+ }
+
+ if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
+ memset(&pim_ifp->ll_lowest, 0,
+ sizeof(pim_ifp->ll_lowest));
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug(
+ "%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
+ ifc->ifp->name, &ifc->address->u.prefix6,
+ &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
+ }
+#endif
+
detect_address_change(ifp, force_prim_as_any, __func__);
pim_if_addr_del_igmp(ifc);
@@ -825,17 +886,36 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
{
struct connected *ifc;
struct listnode *node;
- int v4_addrs = 0;
- int v6_addrs = 0;
struct pim_interface *pim_ifp = ifp->info;
- if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source)) {
+ if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
return pim_ifp->update_source;
- }
+
+#if PIM_IPV == 6
+ if (pim_ifp)
+ return pim_ifp->ll_highest;
+
+ pim_addr best_addr = PIMADDR_ANY;
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
pim_addr addr;
+ if (ifc->address->family != AF_INET6)
+ continue;
+
+ addr = pim_addr_from_prefix(ifc->address);
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr))
+ continue;
+ if (pim_addr_cmp(addr, best_addr) > 0)
+ best_addr = addr;
+ }
+
+ return best_addr;
+#else
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
switch (ifc->address->family) {
case AF_INET:
v4_addrs++;
@@ -853,16 +933,9 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
if (ifc->address->family != PIM_AF)
continue;
- addr = pim_addr_from_prefix(ifc->address);
-
-#if PIM_IPV == 6
- if (!IN6_IS_ADDR_LINKLOCAL(&addr))
- continue;
-#endif
- return addr;
+ return pim_addr_from_prefix(ifc->address);
}
-#if PIM_IPV == 4
/*
* If we have no v4_addrs and v6 is configured
* We probably are using unnumbered
@@ -882,8 +955,8 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
if (lo_ifp && (lo_ifp != ifp))
return pim_find_primary_addr(lo_ifp);
}
-#endif
return PIMADDR_ANY;
+#endif
}
static int pim_iface_next_vif_index(struct interface *ifp)
@@ -1175,12 +1248,16 @@ static struct gm_join *igmp_join_find(struct list *join_list,
}
static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
- struct in_addr group_addr, struct in_addr source_addr)
+ struct in_addr group_addr, struct in_addr source_addr,
+ struct pim_interface *pim_ifp)
{
int join_fd;
+ pim_ifp->igmp_ifstat_joins_sent++;
+
join_fd = pim_socket_raw(IPPROTO_IGMP);
if (join_fd < 0) {
+ pim_ifp->igmp_ifstat_joins_failed++;
return -1;
}
@@ -1196,6 +1273,8 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
__func__, join_fd, group_str, source_str, ifindex,
ifname, errno, safe_strerror(errno));
+ pim_ifp->igmp_ifstat_joins_failed++;
+
close(join_fd);
return -2;
}
@@ -1215,7 +1294,7 @@ static struct gm_join *igmp_join_new(struct interface *ifp,
assert(pim_ifp);
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
- source_addr);
+ source_addr, pim_ifp);
if (join_fd < 0) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
@@ -1549,7 +1628,6 @@ static int pim_ifp_create(struct interface *ifp)
*/
if (pim_ifp)
pim_ifp->pim = pim;
-#if PIM_IPV == 4
pim_if_addr_add_all(ifp);
/*
@@ -1561,7 +1639,6 @@ static int pim_ifp_create(struct interface *ifp)
* this is a no-op if it's already been done.
*/
pim_if_create_pimreg(pim);
-#endif
}
#if PIM_IPV == 4
@@ -1599,6 +1676,7 @@ static int pim_ifp_create(struct interface *ifp)
static int pim_ifp_up(struct interface *ifp)
{
+ uint32_t table_id;
struct pim_interface *pim_ifp;
struct pim_instance *pim;
@@ -1621,9 +1699,6 @@ static int pim_ifp_up(struct interface *ifp)
if (pim_ifp)
pim_ifp->pim = pim;
-#if PIM_IPV == 4
- uint32_t table_id;
-
/*
pim_if_addr_add_all() suffices for bringing up both IGMP and
PIM
@@ -1652,7 +1727,6 @@ static int pim_ifp_up(struct interface *ifp)
}
}
}
-#endif
return 0;
}
@@ -1666,7 +1740,6 @@ static int pim_ifp_down(struct interface *ifp)
ifp->mtu, if_is_operative(ifp));
}
-#if PIM_IPV == 4
if (!if_is_operative(ifp)) {
pim_ifchannel_delete_all(ifp);
/*
@@ -1675,6 +1748,7 @@ static int pim_ifp_down(struct interface *ifp)
*/
pim_if_addr_del_all(ifp);
+#if PIM_IPV == 4
/*
pim_sock_delete() closes the socket, stops read and timer
threads,
@@ -1683,13 +1757,15 @@ static int pim_ifp_down(struct interface *ifp)
if (ifp->info) {
pim_sock_delete(ifp, "link down");
}
+#endif
}
if (ifp->info) {
pim_if_del_vif(ifp);
+#if PIM_IPV == 4
pim_ifstat_reset(ifp);
- }
#endif
+ }
return 0;
}
@@ -1704,12 +1780,12 @@ static int pim_ifp_destroy(struct interface *ifp)
ifp->mtu, if_is_operative(ifp));
}
-#if PIM_IPV == 4
- struct pim_instance *pim;
-
if (!if_is_operative(ifp))
pim_if_addr_del_all(ifp);
+#if PIM_IPV == 4
+ struct pim_instance *pim;
+
pim = ifp->vrf->info;
if (pim && pim->vxlan.term_if == ifp)
pim_vxlan_del_term_dev(pim);
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 00ec8e7427..bab73eae86 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -96,6 +96,13 @@ struct pim_interface {
uint32_t options; /* bit vector */
ifindex_t mroute_vif_index;
struct pim_instance *pim;
+
+#if PIM_IPV == 6
+ /* link-locals: MLD uses lowest addr, PIM uses highest... */
+ pim_addr ll_lowest;
+ pim_addr ll_highest;
+#endif
+
pim_addr primary_address; /* remember addr to detect change */
struct list *sec_addr_list; /* list of struct pim_secondary_addr */
pim_addr update_source; /* user can statically set the primary
@@ -182,6 +189,10 @@ struct pim_interface {
bool bsm_enable; /* bsm processing enable */
bool ucast_bsm_accept; /* ucast bsm processing */
+ uint32_t igmp_ifstat_joins_sent;
+ uint32_t igmp_ifstat_joins_failed;
+ uint32_t igmp_peak_group_count;
+
struct {
bool enabled;
uint32_t min_rx;
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 76d7341a33..f9fb8cf094 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -764,8 +764,7 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp,
if (is_join) {
/* Join(S,G) to RPF'(S,G) */
- pim_upstream_join_suppress(up, up->rpf.rpf_addr.u.prefix4,
- holdtime);
+ pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
return;
}
@@ -873,7 +872,7 @@ void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr,
address of the join message is our primary address.
*/
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- zlog_warn("%s: Assert Loser recv Join%s from %pI4 on %s",
+ zlog_warn("%s: Assert Loser recv Join%s from %pPA on %s",
__func__, ch->sg_str, &neigh_addr, ifp->name);
assert_action_a5(ch);
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 34268ecf90..aa6b30c624 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -37,11 +37,180 @@
#include "pim_str.h"
#include "pim_util.h"
#include "pim_time.h"
-#include "pim_zebra.h"
+#include "pim_ssm.h"
+#include "pim_tib.h"
static void group_timer_off(struct gm_group *group);
static void pim_igmp_general_query(struct thread *t);
+void igmp_anysource_forward_start(struct pim_instance *pim,
+ struct gm_group *group)
+{
+ struct gm_source *source;
+ struct in_addr src_addr = {.s_addr = 0};
+ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
+ assert(group->group_filtermode_isexcl);
+ assert(listcount(group->group_source_list) < 1);
+
+ source = igmp_get_source_by_addr(group, src_addr, NULL);
+ if (!source) {
+ zlog_warn("%s: Failure to create * source", __func__);
+ return;
+ }
+
+ igmp_source_forward_start(pim, source);
+}
+
+void igmp_anysource_forward_stop(struct gm_group *group)
+{
+ struct gm_source *source;
+ struct in_addr star = {.s_addr = 0};
+
+ source = igmp_find_source_by_addr(group, star);
+ if (source)
+ igmp_source_forward_stop(source);
+}
+
+static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
+ struct gm_source *source)
+{
+ pim_sgaddr sg;
+ struct gm_group *group = source->source_group;
+ struct pim_ifchannel *ch;
+
+ if ((source->source_addr.s_addr != INADDR_ANY) ||
+ !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
+ return;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source->source_addr;
+ sg.grp = group->group_addr;
+
+ ch = pim_ifchannel_find(group->interface, &sg);
+ if (pim_is_grp_ssm(pim, group->group_addr)) {
+ /* If SSM group withdraw local membership */
+ if (ch &&
+ (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug(
+ "local membership del for %pSG as G is now SSM",
+ &sg);
+ pim_ifchannel_local_membership_del(group->interface,
+ &sg);
+ }
+ } else {
+ /* If ASM group add local membership */
+ if (!ch ||
+ (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug(
+ "local membership add for %pSG as G is now ASM",
+ &sg);
+ pim_ifchannel_local_membership_add(
+ group->interface, &sg, false /*is_vxlan*/);
+ }
+ }
+}
+
+void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
+{
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *grpnode;
+ struct gm_group *grp;
+ struct pim_ifchannel *ch, *ch_temp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ grp)) {
+ struct listnode *srcnode;
+ struct gm_source *src;
+
+ /* scan group sources */
+ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+ srcnode, src)) {
+ igmp_source_forward_reevaluate_one(pim, src);
+ } /* scan group sources */
+ } /* scan igmp groups */
+
+ RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
+ ch_temp) {
+ if (pim_is_grp_ssm(pim, ch->sg.grp)) {
+ if (pim_addr_is_any(ch->sg.src))
+ pim_ifchannel_delete(ch);
+ }
+ }
+ } /* scan interfaces */
+}
+
+void igmp_source_forward_start(struct pim_instance *pim,
+ struct gm_source *source)
+{
+ struct gm_group *group;
+ pim_sgaddr sg;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source->source_addr;
+ sg.grp = source->source_group->group_addr;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
+ source->source_group->interface->name,
+ IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
+ }
+
+ /* Prevent IGMP interface from installing multicast route multiple
+ times */
+ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
+ return;
+ }
+
+ group = source->source_group;
+
+ if (tib_sg_gm_join(pim, sg, group->interface,
+ &source->source_channel_oil))
+ IGMP_SOURCE_DO_FORWARDING(source->source_flags);
+}
+
+/*
+ igmp_source_forward_stop: stop fowarding, but keep the source
+ igmp_source_delete: stop fowarding, and delete the source
+ */
+void igmp_source_forward_stop(struct gm_source *source)
+{
+ struct pim_interface *pim_oif;
+ struct gm_group *group;
+ pim_sgaddr sg;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source->source_addr;
+ sg.grp = source->source_group->group_addr;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
+ source->source_group->interface->name,
+ IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
+ }
+
+ /* Prevent IGMP interface from removing multicast route multiple
+ times */
+ if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
+ return;
+ }
+
+ group = source->source_group;
+ pim_oif = group->interface->info;
+
+ tib_sg_gm_prune(pim_oif->pim, sg, group->interface,
+ &source->source_channel_oil);
+ IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
+}
+
/* This socket is used for TXing IGMP packets only, IGMP RX happens
* in pim_mroute_msg()
*/
@@ -51,6 +220,7 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
int fd;
int join = 0;
struct in_addr group;
+ struct pim_interface *pim_ifp = ifp->info;
fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifp, 1);
@@ -59,7 +229,8 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) {
if (inet_aton(PIM_ALL_ROUTERS, &group)) {
- if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
+ if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex,
+ pim_ifp))
++join;
} else {
zlog_warn(
@@ -75,7 +246,7 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
IGMP routers must receive general queries for querier election.
*/
if (inet_aton(PIM_ALL_SYSTEMS, &group)) {
- if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
+ if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex, pim_ifp))
++join;
} else {
zlog_warn(
@@ -85,7 +256,8 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
}
if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) {
- if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) {
+ if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex,
+ pim_ifp)) {
++join;
}
} else {
@@ -320,16 +492,16 @@ static int igmp_recv_query(struct gm_sock *igmp, int query_version,
/* Collecting IGMP Rx stats */
switch (query_version) {
case 1:
- igmp->rx_stats.query_v1++;
+ igmp->igmp_stats.query_v1++;
break;
case 2:
- igmp->rx_stats.query_v2++;
+ igmp->igmp_stats.query_v2++;
break;
case 3:
- igmp->rx_stats.query_v3++;
+ igmp->igmp_stats.query_v3++;
break;
default:
- igmp->rx_stats.unsupported++;
+ igmp->igmp_stats.unsupported++;
}
/*
@@ -461,7 +633,7 @@ static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from,
}
/* Collecting IGMP Rx stats */
- igmp->rx_stats.report_v1++;
+ igmp->igmp_stats.report_v1++;
if (PIM_DEBUG_IGMP_TRACE) {
zlog_warn("%s %s: FIXME WRITEME", __FILE__, __func__);
@@ -526,17 +698,6 @@ bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *hlen)
}
}
- if ((msg_type == PIM_IGMP_V3_MEMBERSHIP_REPORT)
- || ((msg_type == PIM_IGMP_MEMBERSHIP_QUERY)
- && (igmp_msg_len >= IGMP_V3_SOURCES_OFFSET))) {
- /* All IGMPv3 messages must be received with TOS set to 0xC0*/
- if (ip_hdr->ip_tos != IPTOS_PREC_INTERNETCONTROL) {
- zlog_warn("Received IGMP Packet with invalid TOS %u",
- ip_hdr->ip_tos);
- return false;
- }
- }
-
return true;
}
@@ -624,7 +785,7 @@ int pim_igmp_packet(struct gm_sock *igmp, char *buf, size_t len)
zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
/* Collecting IGMP Rx stats */
- igmp->rx_stats.unsupported++;
+ igmp->igmp_stats.unsupported++;
return -1;
}
@@ -748,13 +909,10 @@ static void pim_igmp_general_query(struct thread *t)
querier_str, dst_str, igmp->interface->name);
}
- igmp_send_query(pim_ifp->igmp_version, 0 /* igmp_group */, igmp->fd,
- igmp->interface->name, query_buf, sizeof(query_buf),
- 0 /* num_sources */, dst_addr, group_addr,
- pim_ifp->gm_query_max_response_time_dsec,
- 1 /* s_flag: always set for general queries */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ igmp_send_query(pim_ifp->igmp_version, 0 /* igmp_group */, query_buf,
+ sizeof(query_buf), 0 /* num_sources */, dst_addr,
+ group_addr, pim_ifp->gm_query_max_response_time_dsec,
+ 1 /* s_flag: always set for general queries */, igmp);
pim_igmp_general_query_on(igmp);
}
@@ -819,6 +977,8 @@ static void igmp_group_free(struct gm_group *group)
static void igmp_group_count_incr(struct pim_interface *pim_ifp)
{
+ uint32_t group_count = listcount(pim_ifp->gm_group_list);
+
++pim_ifp->pim->igmp_group_count;
if (pim_ifp->pim->igmp_group_count
== pim_ifp->pim->igmp_watermark_limit) {
@@ -827,6 +987,9 @@ static void igmp_group_count_incr(struct pim_interface *pim_ifp)
pim_ifp->pim->igmp_group_count,
VRF_LOGNAME(pim_ifp->pim->vrf));
}
+
+ if (pim_ifp->igmp_peak_group_count < group_count)
+ pim_ifp->igmp_peak_group_count = group_count;
}
static void igmp_group_count_decr(struct pim_interface *pim_ifp)
@@ -1001,7 +1164,7 @@ static struct gm_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
pim_ifp->gm_default_robustness_variable;
igmp->sock_creation = pim_time_monotonic_sec();
- igmp_stats_init(&igmp->rx_stats);
+ igmp_stats_init(&igmp->igmp_stats);
if (mtrace_only) {
igmp->mtrace_only = mtrace_only;
@@ -1027,8 +1190,8 @@ static void pim_igmp_read(struct thread *t)
{
uint8_t buf[10000];
struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t);
- struct sockaddr_in from;
- struct sockaddr_in to;
+ struct sockaddr_storage from;
+ struct sockaddr_storage to;
socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1;
@@ -1293,23 +1456,29 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
return group;
}
-void igmp_send_query(int igmp_version, struct gm_group *group, int fd,
- const char *ifname, char *query_buf, int query_buf_size,
- int num_sources, struct in_addr dst_addr,
- struct in_addr group_addr,
+void igmp_send_query(int igmp_version, struct gm_group *group, char *query_buf,
+ int query_buf_size, int num_sources,
+ struct in_addr dst_addr, struct in_addr group_addr,
int query_max_response_time_dsec, uint8_t s_flag,
- uint8_t querier_robustness_variable,
- uint16_t querier_query_interval)
+ struct gm_sock *igmp)
{
+ if (pim_addr_is_any(group_addr) &&
+ ntohl(dst_addr.s_addr) == INADDR_ALLHOSTS_GROUP)
+ igmp->igmp_stats.general_queries_sent++;
+ else if (group)
+ igmp->igmp_stats.group_queries_sent++;
+
if (igmp_version == 3) {
- igmp_v3_send_query(group, fd, ifname, query_buf, query_buf_size,
- num_sources, dst_addr, group_addr,
+ igmp_v3_send_query(group, igmp->fd, igmp->interface->name,
+ query_buf, query_buf_size, num_sources,
+ dst_addr, group_addr,
query_max_response_time_dsec, s_flag,
- querier_robustness_variable,
- querier_query_interval);
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
} else if (igmp_version == 2) {
- igmp_v2_send_query(group, fd, ifname, query_buf, dst_addr,
- group_addr, query_max_response_time_dsec);
+ igmp_v2_send_query(group, igmp->fd, igmp->interface->name,
+ query_buf, dst_addr, group_addr,
+ query_max_response_time_dsec);
}
}
@@ -1340,13 +1509,10 @@ void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver)
char query_buf[query_buf_size];
- igmp_send_query(igmp_ver, 0 /* igmp_group */, igmp->fd,
- igmp->interface->name, query_buf,
- sizeof(query_buf), 0 /* num_sources */,
- dst_addr, group_addr,
- pim_ifp->gm_query_max_response_time_dsec,
- 1 /* s_flag: always set for general queries */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ igmp_send_query(
+ igmp_ver, 0 /* igmp_group */, query_buf,
+ sizeof(query_buf), 0 /* num_sources */, dst_addr,
+ group_addr, pim_ifp->gm_query_max_response_time_dsec,
+ 1 /* s_flag: always set for general queries */, igmp);
}
}
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index 5c35996634..a642469f27 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -100,7 +100,7 @@ struct gm_sock {
bool mtrace_only;
- struct igmp_stats rx_stats;
+ struct igmp_stats igmp_stats;
};
struct pim_interface;
@@ -128,6 +128,15 @@ void pim_igmp_other_querier_timer_off(struct gm_sock *igmp);
int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len);
#else /* PIM_IPV != 4 */
+static inline void pim_igmp_if_init(struct pim_interface *pim_ifp,
+ struct interface *ifp)
+{
+}
+
+static inline void pim_igmp_if_fini(struct pim_interface *pim_ifp)
+{
+}
+
static inline void pim_igmp_general_query_on(struct gm_sock *igmp)
{
}
@@ -204,6 +213,17 @@ struct gm_group {
};
#if PIM_IPV == 4
+struct pim_instance;
+
+void igmp_anysource_forward_start(struct pim_instance *pim,
+ struct gm_group *group);
+void igmp_anysource_forward_stop(struct gm_group *group);
+
+void igmp_source_forward_start(struct pim_instance *pim,
+ struct gm_source *source);
+void igmp_source_forward_stop(struct gm_source *source);
+void igmp_source_forward_reevaluate_all(struct pim_instance *pim);
+
struct gm_group *find_group_by_addr(struct gm_sock *igmp,
struct in_addr group_addr);
struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
@@ -220,13 +240,11 @@ void igmp_startup_mode_on(struct gm_sock *igmp);
void igmp_group_timer_on(struct gm_group *group, long interval_msec,
const char *ifname);
-void igmp_send_query(int igmp_version, struct gm_group *group, int fd,
- const char *ifname, char *query_buf, int query_buf_size,
- int num_sources, struct in_addr dst_addr,
- struct in_addr group_addr,
+void igmp_send_query(int igmp_version, struct gm_group *group, char *query_buf,
+ int query_buf_size, int num_sources,
+ struct in_addr dst_addr, struct in_addr group_addr,
int query_max_response_time_dsec, uint8_t s_flag,
- uint8_t querier_robustness_variable,
- uint16_t querier_query_interval);
+ struct gm_sock *igmp);
void igmp_group_delete(struct gm_group *group);
void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver);
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
index d8210168e2..11bb2db7eb 100644
--- a/pimd/pim_igmp_mtrace.c
+++ b/pimd/pim_igmp_mtrace.c
@@ -626,7 +626,7 @@ int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr,
}
/* Collecting IGMP Rx stats */
- igmp->rx_stats.mtrace_req++;
+ igmp->igmp_stats.mtrace_req++;
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
@@ -843,7 +843,7 @@ int igmp_mtrace_recv_response(struct gm_sock *igmp, struct ip *ip_hdr,
mtracep->checksum = checksum;
/* Collecting IGMP Rx stats */
- igmp->rx_stats.mtrace_rsp++;
+ igmp->igmp_stats.mtrace_rsp++;
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
diff --git a/pimd/pim_igmp_stats.c b/pimd/pim_igmp_stats.c
index 40851a4529..1d51104687 100644
--- a/pimd/pim_igmp_stats.c
+++ b/pimd/pim_igmp_stats.c
@@ -43,4 +43,14 @@ void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b)
a->mtrace_rsp += b->mtrace_rsp;
a->mtrace_req += b->mtrace_req;
a->unsupported += b->unsupported;
+ a->peak_groups += b->peak_groups;
+ a->total_groups += b->total_groups;
+ a->total_source_groups += b->total_source_groups;
+ a->joins_sent += b->joins_sent;
+ a->joins_failed += b->joins_failed;
+ a->general_queries_sent += b->general_queries_sent;
+ a->group_queries_sent += b->group_queries_sent;
+ a->total_recv_messages += b->query_v1 + b->query_v2 + b->query_v3 +
+ b->report_v1 + b->report_v2 + b->report_v3 +
+ b->leave_v2 + b->mtrace_rsp + b->mtrace_req;
}
diff --git a/pimd/pim_igmp_stats.h b/pimd/pim_igmp_stats.h
index a70a433557..8c66986e03 100644
--- a/pimd/pim_igmp_stats.h
+++ b/pimd/pim_igmp_stats.h
@@ -23,16 +23,24 @@
#include <zebra.h>
struct igmp_stats {
- uint32_t query_v1;
- uint32_t query_v2;
- uint32_t query_v3;
- uint32_t report_v1;
- uint32_t report_v2;
- uint32_t report_v3;
- uint32_t leave_v2;
- uint32_t mtrace_rsp;
- uint32_t mtrace_req;
- uint32_t unsupported;
+ uint32_t query_v1;
+ uint32_t query_v2;
+ uint32_t query_v3;
+ uint32_t report_v1;
+ uint32_t report_v2;
+ uint32_t report_v3;
+ uint32_t leave_v2;
+ uint32_t mtrace_rsp;
+ uint32_t mtrace_req;
+ uint32_t unsupported;
+ uint32_t peak_groups;
+ uint32_t total_groups;
+ uint32_t total_source_groups;
+ uint32_t joins_sent;
+ uint32_t joins_failed;
+ uint32_t general_queries_sent;
+ uint32_t group_queries_sent;
+ uint32_t total_recv_messages;
};
#if PIM_IPV == 4
diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c
index a7c7c99ebf..34cda25963 100644
--- a/pimd/pim_igmpv2.c
+++ b/pimd/pim_igmpv2.c
@@ -24,6 +24,7 @@
#include "pim_igmp.h"
#include "pim_igmpv2.h"
#include "pim_igmpv3.h"
+#include "pim_ssm.h"
#include "pim_str.h"
#include "pim_time.h"
#include "pim_util.h"
@@ -107,10 +108,13 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from,
{
struct interface *ifp = igmp->interface;
struct in_addr group_addr;
+ struct pim_interface *pim_ifp;
char group_str[INET_ADDRSTRLEN];
on_trace(__func__, igmp->interface, from);
+ pim_ifp = ifp->info;
+
if (igmp->mtrace_only)
return 0;
@@ -130,7 +134,7 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from,
}
/* Collecting IGMP Rx stats */
- igmp->rx_stats.report_v2++;
+ igmp->igmp_stats.report_v2++;
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
@@ -142,6 +146,23 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from,
}
/*
+ * RFC 4604
+ * section 2.2.1
+ * EXCLUDE mode does not apply to SSM addresses, and an SSM-aware router
+ * will ignore MODE_IS_EXCLUDE and CHANGE_TO_EXCLUDE_MODE requests in
+ * the SSM range.
+ */
+ if (pim_is_grp_ssm(pim_ifp->pim, group_addr)) {
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Ignoring IGMPv2 group record %pI4 from %s on %s exclude mode in SSM range",
+ &group_addr.s_addr, from_str, ifp->name);
+ }
+ return -1;
+ }
+
+
+ /*
* RFC 3376
* 7.3.2. In the Presence of Older Version Group Members
*
@@ -221,7 +242,7 @@ int igmp_v2_recv_leave(struct gm_sock *igmp, struct ip *ip_hdr,
}
/* Collecting IGMP Rx stats */
- igmp->rx_stats.leave_v2++;
+ igmp->igmp_stats.leave_v2++;
/*
* RFC 3376
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index 87554bc8ba..b6114f9ead 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -32,6 +32,7 @@
#include "pim_time.h"
#include "pim_zebra.h"
#include "pim_oil.h"
+#include "pim_ssm.h"
static void group_retransmit_timer_on(struct gm_group *group);
static long igmp_group_timer_remain_msec(struct gm_group *group);
@@ -984,12 +985,10 @@ static void igmp_send_query_group(struct gm_group *group, char *query_buf,
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) {
igmp_send_query(
- pim_ifp->igmp_version, group, igmp->fd, ifp->name,
- query_buf, query_buf_size, num_sources,
- group->group_addr, group->group_addr,
+ pim_ifp->igmp_version, group, query_buf, query_buf_size,
+ num_sources, group->group_addr, group->group_addr,
pim_ifp->gm_specific_query_max_response_time_dsec,
- s_flag, igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ s_flag, igmp);
}
}
@@ -1822,6 +1821,64 @@ void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str,
} /* s_flag is clear: timer updates */
}
+static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str,
+ struct in_addr grp, int rec_type)
+{
+ struct pim_interface *pim_ifp;
+ struct in_addr grp_addr;
+
+ pim_ifp = ifp->info;
+
+ /* determine filtering status for group */
+ if (pim_is_group_filtered(pim_ifp, &grp)) {
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s",
+ &grp.s_addr, from_str, ifp->name,
+ pim_ifp->boundary_oil_plist);
+ }
+ return false;
+ }
+
+ /*
+ * If we receive a igmp report with the group in 224.0.0.0/24
+ * then we should ignore it
+ */
+
+ grp_addr.s_addr = ntohl(grp.s_addr);
+
+ if (pim_is_group_224_0_0_0_24(grp_addr)) {
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Ignoring IGMPv3 group record %pI4 from %s on %s group range falls in 224.0.0.0/24",
+ &grp.s_addr, from_str, ifp->name);
+ }
+ return false;
+ }
+
+ /*
+ * RFC 4604
+ * section 2.2.1
+ * EXCLUDE mode does not apply to SSM addresses, and an SSM-aware router
+ * will ignore MODE_IS_EXCLUDE and CHANGE_TO_EXCLUDE_MODE requests in
+ * the SSM range.
+ */
+ if (pim_is_grp_ssm(pim_ifp->pim, grp)) {
+ switch (rec_type) {
+ case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
+ case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Ignoring IGMPv3 group record %pI4 from %s on %s exclude mode in SSM range",
+ &grp.s_addr, from_str, ifp->name);
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
const char *from_str, char *igmp_msg, int igmp_msg_len)
{
@@ -1830,14 +1887,10 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
uint8_t *report_pastend = (uint8_t *)igmp_msg + igmp_msg_len;
struct interface *ifp = igmp->interface;
int i;
- int local_ncb = 0;
- struct pim_interface *pim_ifp;
if (igmp->mtrace_only)
return 0;
- pim_ifp = igmp->interface->info;
-
if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
zlog_warn(
"Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
@@ -1854,7 +1907,7 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
}
/* Collecting IGMP Rx stats */
- igmp->rx_stats.report_v3++;
+ igmp->igmp_stats.report_v3++;
num_groups = ntohs(
*(uint16_t *)(igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
@@ -1882,9 +1935,6 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
int rec_auxdatalen;
int rec_num_sources;
int j;
- struct prefix lncb;
- struct prefix g;
- bool filtered = false;
if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE)
> report_pastend) {
@@ -1942,31 +1992,7 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
} /* for (sources) */
- lncb.family = AF_INET;
- lncb.u.prefix4.s_addr = 0x000000E0;
- lncb.prefixlen = 24;
-
- g.family = AF_INET;
- g.u.prefix4 = rec_group;
- g.prefixlen = IPV4_MAX_BITLEN;
-
- /* determine filtering status for group */
- filtered = pim_is_group_filtered(ifp->info, &rec_group);
-
- if (PIM_DEBUG_IGMP_PACKETS && filtered)
- zlog_debug(
- "Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s",
- &rec_group, from_str, ifp->name,
- pim_ifp->boundary_oil_plist);
-
- /*
- * If we receive a igmp report with the group in 224.0.0.0/24
- * then we should ignore it
- */
- if (prefix_match(&lncb, &g))
- local_ncb = 1;
-
- if (!local_ncb && !filtered)
+ if (igmp_pkt_grp_addr_ok(ifp, from_str, rec_group, rec_type))
switch (rec_type) {
case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
igmpv3_report_isin(igmp, from, rec_group,
@@ -2006,7 +2032,6 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
group_record +=
8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
- local_ncb = 0;
} /* for (group records) */
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 51a3ceee15..2c11d5d13f 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -43,14 +43,10 @@
#include "pim_util.h"
#include "pim_ssm.h"
-static void on_trace(const char *label, struct interface *ifp,
- struct in_addr src)
+static void on_trace(const char *label, struct interface *ifp, pim_addr src)
{
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
- zlog_debug("%s: from %s on %s", label, src_str, ifp->name);
- }
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s: from %pPA on %s", label, &src, ifp->name);
}
static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
@@ -148,8 +144,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 +169,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 +179,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 +200,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 +225,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 +236,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);
@@ -439,6 +418,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
size_t packet_left = 0;
size_t packet_size = 0;
size_t group_size = 0;
+ pim_addr rpf_addr;
if (rpf->source_nexthop.interface)
pim_ifp = rpf->source_nexthop.interface->info;
@@ -447,8 +427,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
return -1;
}
- on_trace(__func__, rpf->source_nexthop.interface,
- rpf->rpf_addr.u.prefix4);
+ rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr);
+
+ on_trace(__func__, rpf->source_nexthop.interface, rpf_addr);
if (!pim_ifp) {
zlog_warn("%s: multicast not enabled on interface %s", __func__,
@@ -456,15 +437,12 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
return -1;
}
- if (rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY) {
- if (PIM_DEBUG_PIM_J_P) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
- dst_str, sizeof(dst_str));
- zlog_debug("%s: upstream=%s is myself on interface %s",
- __func__, dst_str,
- rpf->source_nexthop.interface->name);
- }
+ if (pim_addr_is_any(rpf_addr)) {
+ if (PIM_DEBUG_PIM_J_P)
+ zlog_debug(
+ "%s: upstream=%pPA is myself on interface %s",
+ __func__, &rpf_addr,
+ rpf->source_nexthop.interface->name);
return 0;
}
@@ -485,8 +463,8 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
memset(msg, 0, sizeof(*msg));
- pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
- rpf->rpf_addr.u.prefix4);
+ pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
+ rpf_addr);
msg->reserved = 0;
msg->holdtime = htons(PIM_JP_HOLDTIME);
@@ -502,15 +480,11 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
packet_left = rpf->source_nexthop.interface->mtu - 24;
packet_left -= packet_size;
}
- if (PIM_DEBUG_PIM_J_P) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
- dst_str, sizeof(dst_str));
+ if (PIM_DEBUG_PIM_J_P)
zlog_debug(
- "%s: sending (G)=%pPAs to upstream=%s on interface %s",
- __func__, &group->group, dst_str,
+ "%s: sending (G)=%pPAs to upstream=%pPA on interface %s",
+ __func__, &group->group, &rpf_addr,
rpf->source_nexthop.interface->name);
- }
group_size = pim_msg_get_jp_group_size(group->sources);
if (group_size > packet_left) {
@@ -530,8 +504,8 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
msg = (struct pim_jp *)pim_msg;
memset(msg, 0, sizeof(*msg));
- pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
- rpf->rpf_addr.u.prefix4);
+ pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
+ rpf_addr);
msg->reserved = 0;
msg->holdtime = htons(PIM_JP_HOLDTIME);
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_msdp_packet.c b/pimd/pim_msdp_packet.c
index 03284ffa56..4adaca4e78 100644
--- a/pimd/pim_msdp_packet.c
+++ b/pimd/pim_msdp_packet.c
@@ -214,8 +214,6 @@ void pim_msdp_write(struct thread *thread)
return;
}
- sockopt_cork(mp->fd, 1);
-
/* Nonblocking write until TCP output buffer is full */
do {
int writenum;
@@ -280,8 +278,6 @@ void pim_msdp_write(struct thread *thread)
} while ((s = stream_fifo_head(mp->obuf)) != NULL);
pim_msdp_write_proceed_actions(mp);
- sockopt_cork(mp->fd, 0);
-
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
mp->key_str, work_cnt);
diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h
index 522e94504a..456c356d9f 100644
--- a/pimd/pim_msg.h
+++ b/pimd/pim_msg.h
@@ -21,6 +21,9 @@
#define PIM_MSG_H
#include <netinet/in.h>
+#if PIM_IPV == 6
+#include <netinet/ip6.h>
+#endif
#include "pim_jp_agg.h"
@@ -181,6 +184,30 @@ struct pim_jp {
struct pim_jp_groups groups[1];
} __attribute__((packed));
+#if PIM_IPV == 4
+static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr)
+{
+ const struct ip *ipv4_hdr = iphdr;
+ pim_sgaddr sg;
+
+ sg.src = ipv4_hdr->ip_src;
+ sg.grp = ipv4_hdr->ip_dst;
+
+ return sg;
+}
+#else
+static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr)
+{
+ const struct ip6_hdr *ipv6_hdr = iphdr;
+ pim_sgaddr sg;
+
+ sg.src = ipv6_hdr->ip6_src;
+ sg.grp = ipv6_hdr->ip6_dst;
+
+ return sg;
+}
+#endif
+
void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size,
uint8_t pim_msg_type, bool no_fwd);
uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr);
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 a494968e91..35c8469090 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -42,6 +42,7 @@
#include "pim_zebra.h"
#include "pim_zlookup.h"
#include "pim_rp.h"
+#include "pim_addr.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
@@ -75,10 +76,7 @@ struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
- lookup.rpf.rpf_addr.family = rpf->rpf_addr.family;
- lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen;
- lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
-
+ lookup.rpf.rpf_addr = rpf->rpf_addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
return pnc;
@@ -92,10 +90,7 @@ static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE,
sizeof(struct pim_nexthop_cache));
- pnc->rpf.rpf_addr.family = rpf_addr->rpf_addr.family;
- pnc->rpf.rpf_addr.prefixlen = rpf_addr->rpf_addr.prefixlen;
- pnc->rpf.rpf_addr.u.prefix4.s_addr =
- rpf_addr->rpf_addr.u.prefix4.s_addr;
+ pnc->rpf.rpf_addr = rpf_addr->rpf_addr;
pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern);
@@ -119,9 +114,7 @@ static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim,
zclient = pim_zebra_zclient_get();
memset(&rpf, 0, sizeof(struct pim_rpf));
- rpf.rpf_addr.family = addr->family;
- rpf.rpf_addr.prefixlen = addr->prefixlen;
- rpf.rpf_addr.u.prefix4 = addr->u.prefix4;
+ rpf.rpf_addr = *addr;
pnc = pim_nexthop_cache_find(pim, &rpf);
if (!pnc) {
@@ -169,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;
@@ -182,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)
@@ -251,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;
@@ -405,12 +401,13 @@ 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)
{
rp_info->rp.source_nexthop.interface = NULL;
- rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
- PIM_NET_INADDR_ANY;
+ pim_addr_to_prefix(&rp_info->rp.source_nexthop.mrib_nexthop_addr,
+ PIMADDR_ANY);
rp_info->rp.source_nexthop.mrib_metric_preference =
router->infinite_assert_metric.metric_preference;
rp_info->rp.source_nexthop.mrib_route_metric =
@@ -426,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
@@ -489,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;
}
@@ -523,6 +510,9 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
uint32_t i, num_nbrs = 0;
+ pim_addr nh_addr = pim_addr_from_prefix(&(nexthop->mrib_nexthop_addr));
+ pim_addr src_addr = pim_addr_from_prefix(src);
+ pim_addr grp_addr = pim_addr_from_prefix(grp);
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
@@ -530,10 +520,10 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
memset(&nbrs, 0, sizeof(nbrs));
memset(&ifps, 0, sizeof(ifps));
+
// Current Nexthop is VALID, check to stay on the current path.
- if (nexthop->interface && nexthop->interface->info
- && nexthop->mrib_nexthop_addr.u.prefix4.s_addr
- != PIM_NET_INADDR_ANY) {
+ if (nexthop->interface && nexthop->interface->info &&
+ (!pim_addr_is_any(nh_addr))) {
/* User configured knob to explicitly switch
to new path is disabled or current path
metric is less than nexthop update.
@@ -553,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);
@@ -573,23 +563,13 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
pnc->distance;
nexthop->mrib_route_metric =
pnc->metric;
- if (PIM_DEBUG_PIM_NHT) {
- char src_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>",
- src->u.prefix4,
- src_str,
- sizeof(src_str));
- char grp_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>",
- grp->u.prefix4,
- grp_str,
- sizeof(grp_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
- __func__, src_str,
- grp_str, pim->vrf->name,
+ "%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection",
+ __func__, &src_addr,
+ &grp_addr,
+ pim->vrf->name,
nexthop->interface->name);
- }
return 1;
}
}
@@ -612,7 +592,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
#endif
nbrs[i] = pim_neighbor_find(ifps[i], nhaddr);
if (nbrs[i] ||
- pim_if_connected_to_source(ifps[i], src->u.prefix4))
+ pim_if_connected_to_source(ifps[i], src_addr))
num_nbrs++;
}
}
@@ -635,38 +615,30 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
first_ifindex = nh_node->ifindex;
ifp = ifps[nh_iter];
if (!ifp) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", src->u.prefix4,
- addr_str, sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s %s: could not find interface for ifindex %d (address %s(%s))",
+ "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
__FILE__, __func__, first_ifindex,
- addr_str, pim->vrf->name);
- }
+ &src_addr, pim->vrf->name);
if (nh_iter == mod_val)
mod_val++; // Select nexthpath
nh_iter++;
continue;
}
if (!ifp->info) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", src->u.prefix4,
- addr_str, sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
+ "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
- first_ifindex, addr_str);
- }
+ first_ifindex, &src_addr);
if (nh_iter == mod_val)
mod_val++; // Select nexthpath
nh_iter++;
continue;
}
- if (neighbor_needed
- && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
+ if (neighbor_needed &&
+ !pim_if_connected_to_source(ifp, src_addr)) {
nbr = nbrs[nh_iter];
if (!nbr && !if_is_loopback(ifp)) {
if (PIM_DEBUG_PIM_NHT)
@@ -683,34 +655,27 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
if (nh_iter == mod_val) {
nexthop->interface = ifp;
- nexthop->mrib_nexthop_addr.family = AF_INET;
- nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN;
+ nexthop->mrib_nexthop_addr.family = PIM_AF;
+ nexthop->mrib_nexthop_addr.prefixlen = PIM_MAX_BITLEN;
+#if PIM_IPV == 4
nexthop->mrib_nexthop_addr.u.prefix4 =
nh_node->gate.ipv4;
+#else
+ nexthop->mrib_nexthop_addr.u.prefix6 =
+ nh_node->gate.ipv6;
+#endif
nexthop->mrib_metric_preference = pnc->distance;
nexthop->mrib_route_metric = pnc->metric;
- nexthop->last_lookup = src->u.prefix4;
+ nexthop->last_lookup = src_addr;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
- if (PIM_DEBUG_PIM_NHT) {
- char buf[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- char buf3[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", src->u.prefix4, buf2,
- sizeof(buf2));
- pim_inet4_dump("<grp?>", grp->u.prefix4, buf3,
- sizeof(buf3));
- pim_inet4_dump(
- "<rpf?>",
- nexthop->mrib_nexthop_addr.u.prefix4,
- buf, sizeof(buf));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
- __func__, buf2, buf3, pim->vrf->name,
- ifp->name, buf, mod_val, nh_iter,
- pim->ecmp_enable);
- }
+ "%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d",
+ __func__, &src_addr, &grp_addr,
+ pim->vrf->name, ifp->name, &nh_addr,
+ mod_val, nh_iter, pim->ecmp_enable);
}
nh_iter++;
}
@@ -737,19 +702,20 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct pim_instance *pim;
struct zapi_route nhr;
+ struct prefix match;
if (!vrf)
return 0;
pim = vrf->info;
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) {
zlog_err("%s: Decode of nexthop update from zebra failed",
__func__);
return 0;
}
if (cmd == ZEBRA_NEXTHOP_UPDATE) {
- prefix_copy(&rpf.rpf_addr, &nhr.prefix);
+ prefix_copy(&rpf.rpf_addr, &match);
pnc = pim_nexthop_cache_find(pim, &rpf);
if (!pnc) {
if (PIM_DEBUG_PIM_NHT)
@@ -784,9 +750,15 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
* RPF address from nexthop cache (i.e.
* destination) as PIM nexthop.
*/
+#if PIM_IPV == 4
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 =
pnc->rpf.rpf_addr.u.prefix4;
+#else
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nexthop->gate.ipv6 =
+ pnc->rpf.rpf_addr.u.prefix6;
+#endif
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
ifp1 = if_lookup_by_index(nexthop->ifindex,
@@ -806,8 +778,11 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
else {
// Mark nexthop address to 0 until PIM
// Nbr is resolved.
- nexthop->gate.ipv4.s_addr =
- PIM_NET_INADDR_ANY;
+#if PIM_IPV == 4
+ nexthop->gate.ipv4 = PIMADDR_ANY;
+#else
+ nexthop->gate.ipv6 = PIMADDR_ANY;
+#endif
}
break;
@@ -832,9 +807,9 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: NHT addr %pFX(%s) %d-nhop via %pI4(%s) type %d distance:%u metric:%u ",
- __func__, &nhr.prefix, pim->vrf->name,
- i + 1, &nexthop->gate.ipv4,
- ifp->name, nexthop->type, nhr.distance,
+ __func__, &match, pim->vrf->name, i + 1,
+ &nexthop->gate.ipv4, ifp->name,
+ nexthop->type, nhr.distance,
nhr.metric);
if (!ifp->info) {
@@ -888,7 +863,7 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
- __func__, &nhr.prefix, pim->vrf->name, nhr.nexthop_num,
+ __func__, &match, pim->vrf->name, nhr.nexthop_num,
pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
listcount(pnc->rp_list));
@@ -917,20 +892,14 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
uint32_t num_nbrs = 0;
- char addr_str[PREFIX_STRLEN];
+ pim_addr src_addr = pim_addr_from_prefix(src);
- if (PIM_DEBUG_PIM_NHT) {
- pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
- sizeof(addr_str));
- zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
- __func__, addr_str, pim->vrf->name,
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
+ __func__, &src_addr, pim->vrf->name,
nexthop->last_lookup_time);
- }
- memset(&rpf, 0, sizeof(struct pim_rpf));
- rpf.rpf_addr.family = AF_INET;
- rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
- rpf.rpf_addr.u.prefix4 = src->u.prefix4;
+ rpf.rpf_addr = *src;
pnc = pim_nexthop_cache_find(pim, &rpf);
if (pnc) {
@@ -941,14 +910,13 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
memset(nexthop_tab, 0,
sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
- num_ifindex =
- zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
- src->u.prefix4, PIM_NEXTHOP_LOOKUP_MAX);
+ num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+ src_addr, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
if (PIM_DEBUG_PIM_NHT)
zlog_warn(
- "%s: could not find nexthop ifindex for address %s(%s)",
- __func__, addr_str, pim->vrf->name);
+ "%s: could not find nexthop ifindex for address %pPA(%s)",
+ __func__, &src_addr, pim->vrf->name);
return 0;
}
@@ -965,9 +933,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
if (ifps[i]) {
nbrs[i] = pim_neighbor_find_prefix(
ifps[i], &nexthop_tab[i].nexthop_addr);
- if (nbrs[i]
- || pim_if_connected_to_source(ifps[i],
- src->u.prefix4))
+ if (nbrs[i] ||
+ pim_if_connected_to_source(ifps[i], src_addr))
num_nbrs++;
}
}
@@ -997,9 +964,9 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
if (!ifp) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s %s: could not find interface for ifindex %d (address %s(%s))",
+ "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
__FILE__, __func__, first_ifindex,
- addr_str, pim->vrf->name);
+ &src_addr, pim->vrf->name);
if (i == mod_val)
mod_val++;
i++;
@@ -1009,16 +976,16 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
if (!ifp->info) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
+ "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
- first_ifindex, addr_str);
+ first_ifindex, &src_addr);
if (i == mod_val)
mod_val++;
i++;
continue;
}
- if (neighbor_needed
- && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
+ if (neighbor_needed &&
+ !pim_if_connected_to_source(ifp, src_addr)) {
nbr = nbrs[i];
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("ifp name: %s(%s), pim nbr: %p",
@@ -1026,12 +993,14 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
if (!nbr && !if_is_loopback(ifp)) {
if (i == mod_val)
mod_val++;
- i++;
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
- __func__, ifp->name,
- pim->vrf->name, addr_str);
+ "%s: NBR (%pFXh) not found on input interface %s(%s) (RPF for source %pPA)",
+ __func__,
+ &nexthop_tab[i].nexthop_addr,
+ ifp->name, pim->vrf->name,
+ &src_addr);
+ i++;
continue;
}
}
@@ -1044,8 +1013,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
&nexthop_tab[i].nexthop_addr,
nexthop_str, sizeof(nexthop_str));
zlog_debug(
- "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
- __func__, nexthop_str, addr_str,
+ "%s: found nhop %s for addr %pPA interface %s(%s) metric %d dist %d",
+ __func__, nexthop_str, &src_addr,
ifp->name, pim->vrf->name,
nexthop_tab[i].route_metric,
nexthop_tab[i].protocol_distance);
@@ -1058,7 +1027,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
nexthop_tab[i].protocol_distance;
nexthop->mrib_route_metric =
nexthop_tab[i].route_metric;
- nexthop->last_lookup = src->u.prefix4;
+ nexthop->last_lookup = src_addr;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
@@ -1078,36 +1047,36 @@ int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
struct pim_nexthop nhop;
int vif_index;
ifindex_t ifindex;
- char addr_str[PREFIX_STRLEN];
+ pim_addr src_addr;
- if (PIM_DEBUG_PIM_NHT)
- pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT) {
+ src_addr = pim_addr_from_prefix(src);
+ }
memset(&nhop, 0, sizeof(nhop));
if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 1)) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: could not find nexthop ifindex for address %s(%s)",
- __func__, addr_str, pim->vrf->name);
+ "%s: could not find nexthop ifindex for address %pPA(%s)",
+ __func__, &src_addr, pim->vrf->name);
return -1;
}
ifindex = nhop.interface->ifindex;
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
+ "%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA",
__func__, ifindex,
ifindex2ifname(ifindex, pim->vrf->vrf_id),
- pim->vrf->name, addr_str);
+ pim->vrf->name, &src_addr);
vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
if (vif_index < 0) {
if (PIM_DEBUG_PIM_NHT) {
zlog_debug(
- "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
- __func__, vif_index, pim->vrf->name, addr_str);
+ "%s: low vif_index=%d(%s) < 1 nexthop for address %pPA",
+ __func__, vif_index, pim->vrf->name, &src_addr);
}
return -2;
}
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index a499c884b4..d5e459b44e 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -216,6 +216,10 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
pim_ifp = oif->info;
+ assertf(pim_ifp->mroute_vif_index >= 0,
+ "trying to del OIF %s with VIF (%d)", oif->name,
+ pim_ifp->mroute_vif_index);
+
/*
* Don't do anything if we've been asked to remove a source
* that is not actually on it.
@@ -418,6 +422,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
pim_ifp = oif->info;
+ assertf(pim_ifp->mroute_vif_index >= 0,
+ "trying to add OIF %s with VIF (%d)", oif->name,
+ pim_ifp->mroute_vif_index);
+
/* Prevent single protocol from subscribing same interface to
channel (S,G) multiple times */
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 5cc0d63e31..535448f013 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -331,8 +331,8 @@ static void pim_sock_read(struct thread *t)
struct interface *ifp, *orig_ifp;
struct pim_interface *pim_ifp;
int fd;
- struct sockaddr_in from;
- struct sockaddr_in to;
+ struct sockaddr_storage from;
+ struct sockaddr_storage to;
socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to);
uint8_t buf[PIM_PIM_BUFSIZE_READ];
@@ -428,7 +428,7 @@ static int pim_sock_open(struct interface *ifp)
return -1;
if (pim_socket_join(fd, qpim_all_pim_routers_addr,
- pim_ifp->primary_address, ifp->ifindex)) {
+ pim_ifp->primary_address, ifp->ifindex, pim_ifp)) {
close(fd);
return -2;
}
@@ -467,6 +467,9 @@ void pim_ifstat_reset(struct interface *ifp)
pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
+ pim_ifp->igmp_ifstat_joins_sent = 0;
+ pim_ifp->igmp_ifstat_joins_failed = 0;
+ pim_ifp->igmp_peak_group_count = 0;
}
void pim_sock_reset(struct interface *ifp)
@@ -521,7 +524,8 @@ static uint16_t ip_id = 0;
static int pim_msg_send_frame(int fd, char *buf, size_t len,
- struct sockaddr *dst, size_t salen)
+ struct sockaddr *dst, size_t salen,
+ const char *ifname)
{
struct ip *ip = (struct ip *)buf;
@@ -537,8 +541,8 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len,
ip->ip_len = htons(sendlen);
ip->ip_off = htons(offset | IP_MF);
- if (pim_msg_send_frame(fd, buf, sendlen, dst, salen)
- == 0) {
+ if (pim_msg_send_frame(fd, buf, sendlen, dst, salen,
+ ifname) == 0) {
struct ip *ip2 = (struct ip *)(buf + newlen1);
size_t newlen2 = len - sendlen;
sendlen = newlen2 + hdrsize;
@@ -547,7 +551,8 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len,
ip2->ip_len = htons(sendlen);
ip2->ip_off = htons(offset + (newlen1 >> 3));
return pim_msg_send_frame(fd, (char *)ip2,
- sendlen, dst, salen);
+ sendlen, dst, salen,
+ ifname);
}
}
@@ -557,9 +562,9 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len,
pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
sizeof(dst_str));
zlog_warn(
- "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
- __func__, dst_str, fd, len, errno,
- safe_strerror(errno));
+ "%s: sendto() failure to %s: iface=%s fd=%d msg_size=%zd: errno=%d: %s",
+ __func__, dst_str, ifname, fd, len,
+ errno, safe_strerror(errno));
}
return -1;
}
@@ -641,7 +646,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
}
pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
- tolen);
+ tolen, ifname);
return 0;
}
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 2cc80f957c..7fa36e5a44 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -61,7 +61,7 @@ void pim_register_join(struct pim_upstream *up)
pim_channel_add_oif(up->channel_oil, pim->regiface,
PIM_OIF_FLAG_PROTO_PIM, __func__);
up->reg_state = PIM_REG_JOIN;
- pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
+ pim_vxlan_update_sg_reg_state(pim, up, true);
}
void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg,
@@ -108,13 +108,39 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg,
++pinfo->pim_ifstat_reg_stop_send;
}
+static void pim_reg_stop_upstream(struct pim_instance *pim,
+ struct pim_upstream *up)
+{
+ switch (up->reg_state) {
+ case PIM_REG_NOINFO:
+ case PIM_REG_PRUNE:
+ return;
+ case PIM_REG_JOIN:
+ up->reg_state = PIM_REG_PRUNE;
+ pim_channel_del_oif(up->channel_oil, pim->regiface,
+ PIM_OIF_FLAG_PROTO_PIM, __func__);
+ pim_upstream_start_register_stop_timer(up, 0);
+ pim_vxlan_update_sg_reg_state(pim, up, false);
+ break;
+ case PIM_REG_JOIN_PENDING:
+ up->reg_state = PIM_REG_PRUNE;
+ pim_upstream_start_register_stop_timer(up, 0);
+ return;
+ }
+}
+
int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
{
struct pim_interface *pim_ifp = ifp->info;
struct pim_instance *pim = pim_ifp->pim;
- struct pim_upstream *upstream = NULL;
+ struct pim_upstream *up = NULL;
+ struct pim_rpf *rp;
+ pim_addr rpf_addr;
pim_sgaddr sg;
+ struct listnode *up_node;
+ struct pim_upstream *child;
bool wrong_af = false;
+ bool handling_star = false;
int l;
++pim_ifp->pim_ifstat_reg_stop_recv;
@@ -127,33 +153,65 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
if (wrong_af) {
zlog_err("invalid AF in Register-Stop on %s", ifp->name);
- return 0;
+ return -1;
}
- upstream = pim_upstream_find(pim, &sg);
- if (!upstream) {
- return 0;
- }
if (PIM_DEBUG_PIM_REG)
- zlog_debug("Received Register stop for %s", upstream->sg_str);
+ zlog_debug("Received Register stop for %pSG", &sg);
+
+ rp = RP(pim_ifp->pim, sg.grp);
+ if (rp) {
+ rpf_addr = pim_addr_from_prefix(&rp->rpf_addr);
+ if (pim_addr_cmp(sg.src, rpf_addr) == 0) {
+ handling_star = true;
+ sg.src = PIMADDR_ANY;
+ }
+ }
- switch (upstream->reg_state) {
- case PIM_REG_NOINFO:
- case PIM_REG_PRUNE:
- return 0;
- case PIM_REG_JOIN:
- upstream->reg_state = PIM_REG_PRUNE;
- pim_channel_del_oif(upstream->channel_oil, pim->regiface,
- PIM_OIF_FLAG_PROTO_PIM, __func__);
- pim_upstream_start_register_stop_timer(upstream, 0);
- pim_vxlan_update_sg_reg_state(pim, upstream,
- false/*reg_join*/);
- break;
- case PIM_REG_JOIN_PENDING:
- upstream->reg_state = PIM_REG_PRUNE;
- pim_upstream_start_register_stop_timer(upstream, 0);
- return 0;
+ /*
+ * RFC 7761 Sec 4.4.1
+ * Handling Register-Stop(*,G) Messages at the DR:
+ * A Register-Stop(*,G) should be treated as a
+ * Register-Stop(S,G) for all (S,G) Register state
+ * machines that are not in the NoInfo state.
+ */
+ up = pim_upstream_find(pim, &sg);
+ if (up) {
+ /*
+ * If the upstream find actually found a particular
+ * S,G then we *know* that the following for loop
+ * is not going to execute and this is ok
+ */
+ for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug("Executing Reg stop for %s",
+ child->sg_str);
+
+ pim_reg_stop_upstream(pim, child);
+ }
+
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug("Executing Reg stop for %s", up->sg_str);
+ pim_reg_stop_upstream(pim, up);
+ } else {
+ if (!handling_star)
+ return 0;
+ /*
+ * Unfortunately pim was unable to find a *,G
+ * but pim may still actually have individual
+ * S,G's that need to be processed. In that
+ * case pim must do the expensive walk to find
+ * and stop
+ */
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
+ if (pim_addr_cmp(up->sg.grp, sg.grp) == 0) {
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug("Executing Reg stop for %s",
+ up->sg_str);
+ pim_reg_stop_upstream(pim, up);
+ }
+ }
}
return 0;
@@ -311,30 +369,26 @@ void pim_null_register_send(struct pim_upstream *up)
* }
* }
*/
-int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
- struct in_addr src_addr, uint8_t *tlv_buf,
- int tlv_buf_size)
+int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
+ pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size)
{
int sentRegisterStop = 0;
- struct ip *ip_hdr;
+ const void *ip_hdr;
pim_sgaddr sg;
uint32_t *bits;
int i_am_rp = 0;
struct pim_interface *pim_ifp = ifp->info;
struct pim_instance *pim = pim_ifp->pim;
+ pim_addr rp_addr;
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
- ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
-
- if (!if_address_is_local(&dest_addr, AF_INET, pim->vrf->vrf_id)) {
- if (PIM_DEBUG_PIM_REG) {
- char dest[INET_ADDRSTRLEN];
+ ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
- pim_inet4_dump("<dst?>", dest_addr, dest, sizeof(dest));
+ if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) {
+ if (PIM_DEBUG_PIM_REG)
zlog_debug(
- "%s: Received Register message for destination address: %s that I do not own",
- __func__, dest);
- }
+ "%s: Received Register message for destination address: %pPA that I do not own",
+ __func__, &dest_addr);
return 0;
}
@@ -367,18 +421,14 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
* start of the actual Encapsulated data.
*/
memset(&sg, 0, sizeof(sg));
- sg.src = ip_hdr->ip_src;
- sg.grp = ip_hdr->ip_dst;
+ sg = pim_sgaddr_from_iphdr(ip_hdr);
i_am_rp = I_am_RP(pim, sg.grp);
- if (PIM_DEBUG_PIM_REG) {
- char src_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_debug("Received Register message%pSG from %s on %s, rp: %d",
- &sg, src_str, ifp->name, i_am_rp);
- }
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug(
+ "Received Register message%pSG from %pPA on %s, rp: %d",
+ &sg, &src_addr, ifp->name, i_am_rp);
if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
if (pim_addr_is_any(sg.src)) {
@@ -390,9 +440,8 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
}
}
- if (i_am_rp
- && (dest_addr.s_addr
- == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) {
+ rp_addr = pim_addr_from_prefix(&(RP(pim, sg.grp))->rpf_addr);
+ if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) {
sentRegisterStop = 0;
if (pim->register_plist) {
@@ -407,31 +456,25 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
if (prefix_list_apply(plist, &src) == PREFIX_DENY) {
pim_register_stop_send(ifp, &sg, dest_addr,
src_addr);
- if (PIM_DEBUG_PIM_PACKETS) {
- char src_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<src?>", src_addr,
- src_str,
- sizeof(src_str));
+ if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
- "%s: Sending register-stop to %s for %pSG due to prefix-list denial, dropping packet",
- __func__, src_str, &sg);
- }
+ "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet",
+ __func__, &src_addr, &sg);
return 0;
}
}
if (*bits & PIM_REGISTER_BORDER_BIT) {
- struct in_addr pimbr = pim_br_get_pmbr(&sg);
+ pim_addr pimbr = pim_br_get_pmbr(&sg);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
"%s: Received Register message with Border bit set",
__func__);
- if (pimbr.s_addr == pim_br_unknown.s_addr)
+ if (pim_addr_is_any(pimbr))
pim_br_set_pmbr(&sg, src_addr);
- else if (src_addr.s_addr != pimbr.s_addr) {
+ else if (pim_addr_cmp(src_addr, pimbr)) {
pim_register_stop_send(ifp, &sg, dest_addr,
src_addr);
if (PIM_DEBUG_PIM_PACKETS)
diff --git a/pimd/pim_register.h b/pimd/pim_register.h
index fd4284b802..0ebef40c58 100644
--- a/pimd/pim_register.h
+++ b/pimd/pim_register.h
@@ -32,9 +32,8 @@
int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size);
-int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
- struct in_addr src_addr, uint8_t *tlv_buf,
- int tlv_buf_size);
+int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
+ pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size);
void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
struct pim_rpf *rpg, int null_register,
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 0346a7067b..99727cf837 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -48,6 +48,8 @@
#include "pim_oil.h"
#include "pim_zebra.h"
#include "pim_bsm.h"
+#include "pim_util.h"
+#include "pim_ssm.h"
/* Cleanup pim->rpf_hash each node data */
void pim_rp_list_hash_clean(void *data)
@@ -76,26 +78,21 @@ int pim_rp_list_cmp(void *v1, void *v2)
{
struct rp_info *rp1 = (struct rp_info *)v1;
struct rp_info *rp2 = (struct rp_info *)v2;
+ int ret;
/*
* Sort by RP IP address
*/
- if (rp1->rp.rpf_addr.u.prefix4.s_addr
- < rp2->rp.rpf_addr.u.prefix4.s_addr)
- return -1;
-
- if (rp1->rp.rpf_addr.u.prefix4.s_addr
- > rp2->rp.rpf_addr.u.prefix4.s_addr)
- return 1;
+ ret = prefix_cmp(&rp1->rp.rpf_addr, &rp2->rp.rpf_addr);
+ if (ret)
+ return ret;
/*
* Sort by group IP address
*/
- if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
- return -1;
-
- if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
- return 1;
+ ret = prefix_cmp(&rp1->group, &rp2->group);
+ if (ret)
+ return ret;
return 0;
}
@@ -113,27 +110,24 @@ 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");
+ "Unable to convert all-multicast prefix");
list_delete(&pim->rp_list);
route_table_finish(pim->rp_table);
XFREE(MTYPE_PIM_RP, rp_info);
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);
rn = route_node_get(pim->rp_table, &rp_info->group);
rn->info = rp_info;
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug(
- "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
- rn, rp_info, route_node_get_lock_count(rn));
+ zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
+ rp_info, &rp_info->group,
+ route_node_get_lock_count(rn));
}
void pim_rp_free(struct pim_instance *pim)
@@ -150,15 +144,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 +183,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 +237,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)
@@ -373,7 +370,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
up->sg.grp);
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: pim upstream update for old upstream %pI4",
+ zlog_debug("%s: pim upstream update for old upstream %pPA",
__func__, &old_upstream_addr);
if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr))
@@ -414,12 +411,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 +426,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 +457,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 +474,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 +493,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 +553,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 +589,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 +630,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 +642,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 +677,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 +693,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 +706,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 +723,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 +754,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 +798,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 +820,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 +829,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 +845,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 +854,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 +870,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 +896,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,12 +924,10 @@ 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;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ nht_p = rp_info->rp.rpf_addr;
pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
@@ -987,7 +953,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 +995,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 +1024,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 +1036,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 +1055,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 +1063,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,86 +1094,65 @@ 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++;
}
return count;
}
-void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
+void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
+ struct vty *vty, bool uj)
{
struct rp_info *rp_info;
struct rp_info *prev_rp_info = NULL;
struct listnode *node;
char source[7];
- char buf[PREFIX_STRLEN];
json_object *json = NULL;
json_object *json_rp_rows = NULL;
@@ -1225,112 +1162,105 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
json = json_object_new_object();
else
vty_out(vty,
- "RP address group/prefix-list OIF I am RP Source\n");
+ "RP address group/prefix-list OIF I am RP Source Group-Type\n");
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
- if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) {
- char buf[48];
+ if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
+ continue;
- if (rp_info->rp_src == RP_SRC_STATIC)
- strlcpy(source, "Static", sizeof(source));
- else if (rp_info->rp_src == RP_SRC_BSR)
- strlcpy(source, "BSR", sizeof(source));
- else
- strlcpy(source, "None", sizeof(source));
- if (uj) {
- /*
- * If we have moved on to a new RP then add the
- * entry for the previous RP
- */
- if (prev_rp_info
- && prev_rp_info->rp.rpf_addr.u.prefix4
- .s_addr
- != rp_info->rp.rpf_addr.u.prefix4
- .s_addr) {
- json_object_object_add(
- json,
- inet_ntop(AF_INET,
- &prev_rp_info->rp
- .rpf_addr.u
- .prefix4,
- buf, sizeof(buf)),
- json_rp_rows);
- json_rp_rows = NULL;
- }
+#if PIM_IPV == 4
+ pim_addr group = rp_info->group.u.prefix4;
+#else
+ pim_addr group = rp_info->group.u.prefix6;
+#endif
+ const char *group_type =
+ pim_is_grp_ssm(pim, group) ? "SSM" : "ASM";
- if (!json_rp_rows)
- json_rp_rows = json_object_new_array();
-
- json_row = json_object_new_object();
- json_object_string_addf(
- json_row, "rpAddress", "%pI4",
- &rp_info->rp.rpf_addr.u.prefix4);
- if (rp_info->rp.source_nexthop.interface)
- json_object_string_add(
- json_row, "outboundInterface",
- rp_info->rp.source_nexthop
- .interface->name);
- else
- json_object_string_add(
- json_row, "outboundInterface",
- "Unknown");
- if (rp_info->i_am_rp)
- json_object_boolean_true_add(json_row,
- "iAmRP");
- else
- json_object_boolean_false_add(json_row,
- "iAmRP");
+ if (range && !prefix_same(&rp_info->group, range))
+ continue;
- if (rp_info->plist)
- json_object_string_add(json_row,
- "prefixList",
- rp_info->plist);
- else
- json_object_string_addf(
- json_row, "group", "%pFX",
- &rp_info->group);
- json_object_string_add(json_row, "source",
- source);
+ if (rp_info->rp_src == RP_SRC_STATIC)
+ strlcpy(source, "Static", sizeof(source));
+ else if (rp_info->rp_src == RP_SRC_BSR)
+ strlcpy(source, "BSR", sizeof(source));
+ else
+ strlcpy(source, "None", sizeof(source));
+ if (uj) {
+ /*
+ * If we have moved on to a new RP then add the
+ * entry for the previous RP
+ */
+ if (prev_rp_info &&
+ prefix_cmp(&prev_rp_info->rp.rpf_addr,
+ &rp_info->rp.rpf_addr)) {
+ json_object_object_addf(
+ json, json_rp_rows, "%pFXh",
+ &prev_rp_info->rp.rpf_addr);
+ json_rp_rows = NULL;
+ }
- json_object_array_add(json_rp_rows, json_row);
- } else {
- vty_out(vty, "%-15s ",
- inet_ntop(AF_INET,
- &rp_info->rp.rpf_addr.u
- .prefix4,
- buf, sizeof(buf)));
-
- if (rp_info->plist)
- vty_out(vty, "%-18s ", rp_info->plist);
- else
- vty_out(vty, "%-18pFX ",
- &rp_info->group);
+ if (!json_rp_rows)
+ json_rp_rows = json_object_new_array();
+
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "rpAddress", "%pFXh",
+ &rp_info->rp.rpf_addr);
+ if (rp_info->rp.source_nexthop.interface)
+ json_object_string_add(
+ json_row, "outboundInterface",
+ rp_info->rp.source_nexthop
+ .interface->name);
+ else
+ json_object_string_add(json_row,
+ "outboundInterface",
+ "Unknown");
+ if (rp_info->i_am_rp)
+ json_object_boolean_true_add(json_row, "iAmRP");
+ else
+ json_object_boolean_false_add(json_row,
+ "iAmRP");
- if (rp_info->rp.source_nexthop.interface)
- vty_out(vty, "%-16s ",
- rp_info->rp.source_nexthop
- .interface->name);
- else
- vty_out(vty, "%-16s ", "(Unknown)");
+ if (rp_info->plist)
+ json_object_string_add(json_row, "prefixList",
+ rp_info->plist);
+ else
+ json_object_string_addf(json_row, "group",
+ "%pFX",
+ &rp_info->group);
+ json_object_string_add(json_row, "source", source);
+ json_object_string_add(json_row, "groupType",
+ group_type);
+
+ json_object_array_add(json_rp_rows, json_row);
+ } else {
+ vty_out(vty, "%-15pFXh ", &rp_info->rp.rpf_addr);
- if (rp_info->i_am_rp)
- vty_out(vty, "yes");
- else
- vty_out(vty, "no");
+ if (rp_info->plist)
+ vty_out(vty, "%-18s ", rp_info->plist);
+ else
+ vty_out(vty, "%-18pFX ", &rp_info->group);
- vty_out(vty, "%14s\n", source);
- }
- prev_rp_info = rp_info;
+ if (rp_info->rp.source_nexthop.interface)
+ vty_out(vty, "%-16s ",
+ rp_info->rp.source_nexthop
+ .interface->name);
+ else
+ vty_out(vty, "%-16s ", "(Unknown)");
+
+ if (rp_info->i_am_rp)
+ vty_out(vty, "yes");
+ else
+ vty_out(vty, "no");
+
+ vty_out(vty, "%14s", source);
+ vty_out(vty, "%6s\n", group_type);
}
+ prev_rp_info = rp_info;
}
if (uj) {
if (prev_rp_info && json_rp_rows)
- json_object_object_add(
- json,
- inet_ntop(AF_INET,
- &prev_rp_info->rp.rpf_addr.u.prefix4,
- buf, sizeof(buf)),
- json_rp_rows);
+ json_object_object_addf(json, json_rp_rows, "%pFXh",
+ &prev_rp_info->rp.rpf_addr);
vty_json(vty, json);
}
@@ -1345,20 +1275,23 @@ 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;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ nht_p = rp_info->rp.rpf_addr;
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
&pnc))
continue;
for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
- if (nh_node->gate.ipv4.s_addr != INADDR_ANY)
+#if PIM_IPV == 4
+ if (!pim_addr_is_any(nh_node->gate.ipv4))
+ continue;
+#else
+ if (!pim_addr_is_any(nh_node->gate.ipv6))
continue;
+#endif
struct interface *ifp1 = if_lookup_by_index(
nh_node->ifindex, pim->vrf->vrf_id);
@@ -1371,15 +1304,11 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
#else
nh_node->gate.ipv6 = nbr->source_addr;
#endif
- if (PIM_DEBUG_PIM_NHT_RP) {
- char str[PREFIX_STRLEN];
- pim_addr_dump("<nht_addr?>", &nht_p, str,
- sizeof(str));
+ if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
- "%s: addr %s new nexthop addr %pPAs interface %s",
- __func__, str, &nbr->source_addr,
+ "%s: addr %pFXh new nexthop addr %pPAs interface %s",
+ __func__, &nht_p, &nbr->source_addr,
ifp1->name);
- }
}
}
}
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index c223402ddd..04faeb5f26 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);
@@ -80,8 +78,8 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group);
#define I_am_RP(P, G) pim_rp_i_am_rp ((P), (G))
#define RP(P, G) pim_rp_g ((P), (G))
-void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
- bool uj);
+void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
+ struct vty *vty, bool uj);
void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr);
int pim_rp_list_cmp(void *v1, void *v2);
struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index d971cef24b..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;
@@ -169,11 +162,13 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
static int nexthop_mismatch(const struct pim_nexthop *nh1,
const struct pim_nexthop *nh2)
{
- return (nh1->interface != nh2->interface)
- || (nh1->mrib_nexthop_addr.u.prefix4.s_addr
- != nh2->mrib_nexthop_addr.u.prefix4.s_addr)
- || (nh1->mrib_metric_preference != nh2->mrib_metric_preference)
- || (nh1->mrib_route_metric != nh2->mrib_route_metric);
+ pim_addr nh_addr1 = pim_addr_from_prefix(&nh1->mrib_nexthop_addr);
+ pim_addr nh_addr2 = pim_addr_from_prefix(&nh2->mrib_nexthop_addr);
+
+ return (nh1->interface != nh2->interface) ||
+ (pim_addr_cmp(nh_addr1, nh_addr2)) ||
+ (nh1->mrib_metric_preference != nh2->mrib_metric_preference) ||
+ (nh1->mrib_route_metric != nh2->mrib_route_metric);
}
static void pim_rpf_cost_change(struct pim_instance *pim,
@@ -261,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);
@@ -297,9 +287,8 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
}
/* detect change in RPF'(S,G) */
- if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr
- || saved.source_nexthop
- .interface != rpf->source_nexthop.interface) {
+ 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;
}
@@ -327,13 +316,13 @@ void pim_upstream_rpf_clear(struct pim_instance *pim,
if (up->rpf.source_nexthop.interface) {
pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
up->rpf.source_nexthop.interface = NULL;
- up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
- PIM_NET_INADDR_ANY;
+ pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr,
+ PIMADDR_ANY);
up->rpf.source_nexthop.mrib_metric_preference =
router->infinite_assert_metric.metric_preference;
up->rpf.source_nexthop.mrib_route_metric =
router->infinite_assert_metric.route_metric;
- up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+ pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY);
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
}
}
@@ -388,27 +377,14 @@ 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);
+
switch (rpf->rpf_addr.family) {
case AF_INET:
- return rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY;
case AF_INET6:
- zlog_warn("%s: v6 Unimplmented", __func__);
- return 1;
+ return pim_addr_is_any(rpf_addr);
default:
return 0;
}
@@ -426,7 +402,12 @@ unsigned int pim_rpf_hash_key(const void *arg)
{
const struct pim_nexthop_cache *r = arg;
+#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,
+ array_size(r->rpf.rpf_addr.u.prefix6.s6_addr32), 0);
+#endif
}
bool pim_rpf_equal(const void *arg1, const void *arg2)
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_sock.c b/pimd/pim_sock.c
index 05b0f92a4b..8619cc3f83 100644
--- a/pimd/pim_sock.c
+++ b/pimd/pim_sock.c
@@ -34,22 +34,28 @@
#include "vrf.h"
#include "sockopt.h"
#include "lib_errors.h"
+#include "network.h"
#include "pimd.h"
#include "pim_mroute.h"
+#include "pim_iface.h"
#include "pim_sock.h"
#include "pim_str.h"
-/* GLOBAL VARS */
+#if PIM_IPV == 4
+#define setsockopt_iptos setsockopt_ipv4_tos
+#define setsockopt_multicast_loop setsockopt_ipv4_multicast_loop
+#else
+#define setsockopt_iptos setsockopt_ipv6_tclass
+#define setsockopt_multicast_loop setsockopt_ipv6_multicast_loop
+#endif
int pim_socket_raw(int protocol)
{
int fd;
frr_with_privs(&pimd_privs) {
-
- fd = socket(AF_INET, SOCK_RAW, protocol);
-
+ fd = socket(PIM_AF, SOCK_RAW, protocol);
}
if (fd < 0) {
@@ -66,10 +72,16 @@ void pim_socket_ip_hdr(int fd)
const int on = 1;
frr_with_privs(&pimd_privs) {
-
+#if PIM_IPV == 4
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
- zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
- __func__, safe_strerror(errno));
+ zlog_err("%s: Could not turn on IP_HDRINCL option: %m",
+ __func__);
+#else
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_HDRINCL, &on, sizeof(on)))
+ zlog_err(
+ "%s: Could not turn on IPV6_HDRINCL option: %m",
+ __func__);
+#endif
}
}
@@ -80,248 +92,256 @@ void pim_socket_ip_hdr(int fd)
int pim_socket_bind(int fd, struct interface *ifp)
{
int ret = 0;
-#ifdef SO_BINDTODEVICE
+#ifdef SO_BINDTODEVICE
frr_with_privs(&pimd_privs) {
-
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
strlen(ifp->name));
-
}
-
#endif
return ret;
}
-int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
- uint8_t loop)
+#if PIM_IPV == 4
+static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp)
{
- int rcvbuf = 1024 * 1024 * 8;
-#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
- struct ip_mreqn mreq;
-#else
- struct ip_mreq mreq;
-#endif
- int fd;
-
- fd = pim_socket_raw(protocol);
- if (fd < 0) {
- zlog_warn("Could not create multicast socket: errno=%d: %s",
- errno, safe_strerror(errno));
- return PIM_SOCK_ERR_SOCKET;
- }
-
-#ifdef SO_BINDTODEVICE
- int ret;
-
- ret = pim_socket_bind(fd, ifp);
- if (ret) {
- close(fd);
- zlog_warn(
- "Could not set fd: %d for interface: %s to device",
- fd, ifp->name);
- return PIM_SOCK_ERR_BIND;
- }
-#else
-/* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to
- * only use 1 socket for all interfaces? */
-#endif
+ int one = 1;
+ int ttl = 1;
- /* Needed to obtain destination address from recvmsg() */
- {
#if defined(HAVE_IP_PKTINFO)
- /* Linux and Solaris IP_PKTINFO */
- int opt = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
- zlog_warn(
- "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- }
+ /* Linux and Solaris IP_PKTINFO */
+ if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)))
+ zlog_warn("Could not set PKTINFO on socket fd=%d: %m", fd);
#elif defined(HAVE_IP_RECVDSTADDR)
- /* BSD IP_RECVDSTADDR */
- int opt = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt,
- sizeof(opt))) {
- zlog_warn(
- "Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- }
+ /* BSD IP_RECVDSTADDR */
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one)))
+ zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: %m",
+ fd);
#else
- flog_err(
- EC_LIB_DEVELOPMENT,
- "%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
- __FILE__, __func__);
- close(fd);
- return PIM_SOCK_ERR_DSTADDR;
+ flog_err(
+ EC_LIB_DEVELOPMENT,
+ "Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()");
+ close(fd);
+ return PIM_SOCK_ERR_DSTADDR;
#endif
- }
-
- /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4.
- * Message Formats)*/
+ /* Set router alert (RFC 2113) for all IGMP messages (RFC
+ * 3376 4. Message Formats)*/
if (protocol == IPPROTO_IGMP) {
uint8_t ra[4];
+
ra[0] = 148;
ra[1] = 4;
ra[2] = 0;
ra[3] = 0;
if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) {
zlog_warn(
- "Could not set Router Alert Option on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
+ "Could not set Router Alert Option on socket fd=%d: %m",
+ fd);
close(fd);
return PIM_SOCK_ERR_RA;
}
}
- {
- int reuse = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse,
- sizeof(reuse))) {
- zlog_warn(
- "Could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- close(fd);
- return PIM_SOCK_ERR_REUSE;
- }
- }
-
- {
- const int MTTL = 1;
- int ttl = MTTL;
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl,
- sizeof(ttl))) {
- zlog_warn(
- "Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
- MTTL, fd, errno, safe_strerror(errno));
- close(fd);
- return PIM_SOCK_ERR_TTL;
- }
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) {
+ zlog_warn("Could not set multicast TTL=%d on socket fd=%d: %m",
+ ttl, fd);
+ close(fd);
+ return PIM_SOCK_ERR_TTL;
}
- if (setsockopt_ipv4_multicast_loop(fd, loop)) {
+ if (setsockopt_ipv4_multicast_if(fd, PIMADDR_ANY, ifp->ifindex)) {
zlog_warn(
- "Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s",
- loop ? "enable" : "disable", fd, errno,
- safe_strerror(errno));
+ "Could not set Outgoing Interface Option on socket fd=%d: %m",
+ fd);
close(fd);
- return PIM_SOCK_ERR_LOOP;
+ return PIM_SOCK_ERR_IFACE;
}
- memset(&mreq, 0, sizeof(mreq));
-#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
- mreq.imr_ifindex = ifp->ifindex;
-#else
-/*
- * I am not sure what to do here yet for *BSD
- */
-// mreq.imr_interface = ifindex;
-#endif
+ return 0;
+}
+#else /* PIM_IPV != 4 */
+static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp)
+{
+ int ttl = 1;
+ struct ipv6_mreq mreq = {};
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreq,
+ setsockopt_ipv6_pktinfo(fd, 1);
+ setsockopt_ipv6_multicast_hops(fd, ttl);
+
+ mreq.ipv6mr_interface = ifp->ifindex;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mreq,
sizeof(mreq))) {
zlog_warn(
- "Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
+ "Could not set Outgoing Interface Option on socket fd=%d: %m",
+ fd);
close(fd);
return PIM_SOCK_ERR_IFACE;
}
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)))
- zlog_warn("%s: Failure to set buffer size to %d", __func__,
- rcvbuf);
+ return 0;
+}
+#endif
- {
- long flags;
+int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
+ uint8_t loop)
+{
+ int fd;
+ int ret;
- flags = fcntl(fd, F_GETFL, 0);
- if (flags < 0) {
- zlog_warn(
- "Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- close(fd);
- return PIM_SOCK_ERR_NONBLOCK_GETFL;
- }
+ fd = pim_socket_raw(protocol);
+ if (fd < 0) {
+ zlog_warn("Could not create multicast socket: errno=%d: %s",
+ errno, safe_strerror(errno));
+ return PIM_SOCK_ERR_SOCKET;
+ }
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
- zlog_warn(
- "Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- close(fd);
- return PIM_SOCK_ERR_NONBLOCK_SETFL;
- }
+ /* XXX: if SO_BINDTODEVICE isn't available, use IP_PKTINFO / IP_RECVIF
+ * to emulate behaviour? Or change to only use 1 socket for all
+ * interfaces? */
+ ret = pim_socket_bind(fd, ifp);
+ if (ret) {
+ close(fd);
+ zlog_warn("Could not set fd: %d for interface: %s to device",
+ fd, ifp->name);
+ return PIM_SOCK_ERR_BIND;
}
- /* Set Tx socket DSCP byte */
- if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) {
- zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s",
- fd, safe_strerror(errno));
+ set_nonblocking(fd);
+ sockopt_reuseaddr(fd);
+ setsockopt_so_recvbuf(fd, 8 * 1024 * 1024);
+
+ ret = pim_setsockopt(protocol, fd, ifp);
+ if (ret) {
+ zlog_warn("pim_setsockopt failed for interface: %s to device ",
+ ifp->name);
+ return ret;
+ }
+
+ /* leftover common sockopts */
+ if (setsockopt_multicast_loop(fd, loop)) {
+ zlog_warn(
+ "Could not %s Multicast Loopback Option on socket fd=%d: %m",
+ loop ? "enable" : "disable", fd);
+ close(fd);
+ return PIM_SOCK_ERR_LOOP;
}
+ /* Set Tx socket DSCP byte */
+ if (setsockopt_iptos(fd, IPTOS_PREC_INTERNETCONTROL))
+ zlog_warn("can't set sockopt IP[V6]_TOS to socket %d: %m", fd);
+
return fd;
}
-int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr,
- ifindex_t ifindex)
+int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
+ struct pim_interface *pim_ifp)
{
int ret;
-#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
- struct ip_mreqn opt;
+#if PIM_IPV == 4
+ ret = setsockopt_ipv4_multicast(fd, IP_ADD_MEMBERSHIP, ifaddr,
+ group.s_addr, ifindex);
#else
- struct ip_mreq opt;
-#endif
+ struct ipv6_mreq opt;
- opt.imr_multiaddr = group;
-
-#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
- opt.imr_address = ifaddr;
- opt.imr_ifindex = ifindex;
-#else
- opt.imr_interface = ifaddr;
+ memcpy(&opt.ipv6mr_multiaddr, &group, 16);
+ opt.ipv6mr_interface = ifindex;
+ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &opt, sizeof(opt));
#endif
- ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
- if (ret) {
- char group_str[INET_ADDRSTRLEN];
- char ifaddr_str[INET_ADDRSTRLEN];
- if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str)))
- snprintf(group_str, sizeof(group_str), "<group?>");
- if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str,
- sizeof(ifaddr_str)))
- snprintf(ifaddr_str, sizeof(ifaddr_str), "<ifaddr?>");
+ pim_ifp->igmp_ifstat_joins_sent++;
+ if (ret) {
flog_err(
EC_LIB_SOCKET,
- "Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
- fd, group_str, ifaddr_str, errno, safe_strerror(errno));
+ "Failure socket joining fd=%d group %pPAs on interface address %pPAs: %m",
+ fd, &group, &ifaddr);
+ pim_ifp->igmp_ifstat_joins_failed++;
return ret;
}
- if (PIM_DEBUG_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char ifaddr_str[INET_ADDRSTRLEN];
- if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str)))
- snprintf(group_str, sizeof(group_str), "<group?>");
- if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str,
- sizeof(ifaddr_str)))
- snprintf(ifaddr_str, sizeof(ifaddr_str), "<ifaddr?>");
-
+ if (PIM_DEBUG_TRACE)
zlog_debug(
- "Socket fd=%d joined group %s on interface address %s",
- fd, group_str, ifaddr_str);
+ "Socket fd=%d joined group %pPAs on interface address %pPAs",
+ fd, &group, &ifaddr);
+ return ret;
+}
+
+#if PIM_IPV == 4
+static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
+ ifindex_t *ifindex)
+{
+ struct cmsghdr *cmsg;
+ struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
+
+ for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(mh, cmsg)) {
+#ifdef HAVE_IP_PKTINFO
+ if ((cmsg->cmsg_level == IPPROTO_IP) &&
+ (cmsg->cmsg_type == IP_PKTINFO)) {
+ struct in_pktinfo *i;
+
+ i = (struct in_pktinfo *)CMSG_DATA(cmsg);
+ if (dst4)
+ dst4->sin_addr = i->ipi_addr;
+ if (ifindex)
+ *ifindex = i->ipi_ifindex;
+
+ break;
+ }
+#endif
+
+#ifdef HAVE_IP_RECVDSTADDR
+ if ((cmsg->cmsg_level == IPPROTO_IP) &&
+ (cmsg->cmsg_type == IP_RECVDSTADDR)) {
+ struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
+
+ if (dst4)
+ dst4->sin_addr = *i;
+
+ break;
+ }
+#endif
+
+#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
+ if (cmsg->cmsg_type == IP_RECVIF)
+ if (ifindex)
+ *ifindex = CMSG_IFINDEX(cmsg);
+#endif
}
+}
+#else /* PIM_IPV != 4 */
+static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
+ ifindex_t *ifindex)
+{
+ struct cmsghdr *cmsg;
+ struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
- return ret;
+ for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(mh, cmsg)) {
+ if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+ (cmsg->cmsg_type == IPV6_PKTINFO)) {
+ struct in6_pktinfo *i;
+
+ i = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+
+ if (dst6)
+ dst6->sin6_addr = i->ipi6_addr;
+ if (ifindex)
+ *ifindex = i->ipi6_ifindex;
+ break;
+ }
+ }
}
+#endif /* PIM_IPV != 4 */
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
- struct sockaddr_in *from, socklen_t *fromlen,
- struct sockaddr_in *to, socklen_t *tolen,
+ struct sockaddr_storage *from, socklen_t *fromlen,
+ struct sockaddr_storage *to, socklen_t *tolen,
ifindex_t *ifindex)
{
struct msghdr msgh;
- struct cmsghdr *cmsg;
struct iovec iov;
char cbuf[1000];
int err;
@@ -331,19 +351,12 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
* Use getsockname() to get sin_port.
*/
if (to) {
- struct sockaddr_in si;
- socklen_t si_len = sizeof(si);
-
- memset(&si, 0, sizeof(si));
- to->sin_family = AF_INET;
-
- pim_socket_getsockname(fd, (struct sockaddr *)&si, &si_len);
+ socklen_t to_len = sizeof(*to);
- to->sin_port = si.sin_port;
- to->sin_addr = si.sin_addr;
+ pim_socket_getsockname(fd, (struct sockaddr *)to, &to_len);
if (tolen)
- *tolen = sizeof(si);
+ *tolen = sizeof(*to);
}
memset(&msgh, 0, sizeof(struct msghdr));
@@ -364,66 +377,11 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (fromlen)
*fromlen = msgh.msg_namelen;
- for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
-
-#ifdef HAVE_IP_PKTINFO
- if ((cmsg->cmsg_level == IPPROTO_IP)
- && (cmsg->cmsg_type == IP_PKTINFO)) {
- struct in_pktinfo *i =
- (struct in_pktinfo *)CMSG_DATA(cmsg);
- if (to)
- to->sin_addr = i->ipi_addr;
- if (tolen)
- *tolen = sizeof(struct sockaddr_in);
- if (ifindex)
- *ifindex = i->ipi_ifindex;
-
- break;
- }
-#endif
-
-#ifdef HAVE_IP_RECVDSTADDR
- if ((cmsg->cmsg_level == IPPROTO_IP)
- && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
- struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
- if (to)
- to->sin_addr = *i;
- if (tolen)
- *tolen = sizeof(struct sockaddr_in);
-
- break;
- }
-#endif
-
-#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
- if (cmsg->cmsg_type == IP_RECVIF)
- if (ifindex)
- *ifindex = CMSG_IFINDEX(cmsg);
-#endif
-
- } /* for (cmsg) */
+ cmsg_getdstaddr(&msgh, to, ifindex);
return err; /* len */
}
-int pim_socket_mcastloop_get(int fd)
-{
- int loop;
- socklen_t loop_len = sizeof(loop);
-
- if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &loop_len)) {
- int e = errno;
- zlog_warn(
- "Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- errno = e;
- return PIM_SOCK_ERR_LOOP;
- }
-
- return loop;
-}
-
int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
{
if (getsockname(fd, name, namelen)) {
diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h
index 08b0099321..2e9c043e84 100644
--- a/pimd/pim_sock.h
+++ b/pimd/pim_sock.h
@@ -38,17 +38,15 @@
int pim_socket_bind(int fd, struct interface *ifp);
void pim_socket_ip_hdr(int fd);
int pim_socket_raw(int protocol);
-int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
+int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop);
-int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr,
- ifindex_t ifindex);
+int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
+ struct pim_interface *pim_ifp);
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
- struct sockaddr_in *from, socklen_t *fromlen,
- struct sockaddr_in *to, socklen_t *tolen,
+ struct sockaddr_storage *from, socklen_t *fromlen,
+ struct sockaddr_storage *to, socklen_t *tolen,
ifindex_t *ifindex);
-int pim_socket_mcastloop_get(int fd);
-
int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen);
#endif /* PIM_SOCK_H */
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
index 688d38c84c..74310474d4 100644
--- a/pimd/pim_ssm.c
+++ b/pimd/pim_ssm.c
@@ -28,7 +28,7 @@
#include "pimd.h"
#include "pim_ssm.h"
-#include "pim_zebra.h"
+#include "pim_igmp.h"
static void pim_ssm_range_reevaluate(struct pim_instance *pim)
{
diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h
index 117713b866..c6b6978218 100644
--- a/pimd/pim_ssm.h
+++ b/pimd/pim_ssm.h
@@ -34,7 +34,7 @@ struct pim_ssm {
void pim_ssm_prefix_list_update(struct pim_instance *pim,
struct prefix_list *plist);
-int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr);
+extern int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr);
int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id,
const char *plist_name);
void *pim_ssm_init(void);
diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c
index 596b06cb38..e43b46604c 100644
--- a/pimd/pim_ssmpingd.c
+++ b/pimd/pim_ssmpingd.c
@@ -244,8 +244,8 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf,
static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
{
struct interface *ifp;
- struct sockaddr_in from;
- struct sockaddr_in to;
+ struct sockaddr_storage from;
+ struct sockaddr_storage to;
socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1;
@@ -256,13 +256,11 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from,
&fromlen, &to, &tolen, &ifindex);
+
if (len < 0) {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", ss->source_addr, source_str,
- sizeof(source_str));
zlog_warn(
- "%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s",
- __func__, source_str, ss->sock_fd, errno,
+ "%s: failure receiving ssmping for source %pI4 on fd=%d: errno=%d: %s",
+ __func__, &ss->source_addr, ss->sock_fd, errno,
safe_strerror(errno));
return -1;
}
@@ -270,47 +268,31 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
ifp = if_lookup_by_index(ifindex, ss->pim->vrf->vrf_id);
if (buf[0] != PIM_SSMPINGD_REQUEST) {
- char source_str[INET_ADDRSTRLEN];
- char from_str[INET_ADDRSTRLEN];
- char to_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", ss->source_addr, source_str,
- sizeof(source_str));
- pim_inet4_dump("<from?>", from.sin_addr, from_str,
- sizeof(from_str));
- pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
zlog_warn(
- "%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s",
- __func__, buf[0], from_str, ntohs(from.sin_port),
- to_str, ntohs(to.sin_port),
+ "%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pI4",
+ __func__, buf[0], &from, &to,
ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd,
- source_str);
+ &ss->source_addr);
return 0;
}
if (PIM_DEBUG_SSMPINGD) {
- char source_str[INET_ADDRSTRLEN];
- char from_str[INET_ADDRSTRLEN];
- char to_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", ss->source_addr, source_str,
- sizeof(source_str));
- pim_inet4_dump("<from?>", from.sin_addr, from_str,
- sizeof(from_str));
- pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
zlog_debug(
- "%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s",
- __func__, from_str, ntohs(from.sin_port), to_str,
- ntohs(to.sin_port), ifp ? ifp->name : "<iface?>",
- ifindex, ss->sock_fd, source_str);
+ "%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pI4",
+ __func__, &from, &to, ifp ? ifp->name : "<iface?>",
+ ifindex, ss->sock_fd, &ss->source_addr);
}
buf[0] = PIM_SSMPINGD_REPLY;
+ struct sockaddr_in *from_addr = (struct sockaddr_in *)&from;
+
/* unicast reply */
- ssmpingd_sendto(ss, buf, len, from);
+ ssmpingd_sendto(ss, buf, len, *from_addr);
/* multicast reply */
- from.sin_addr = ss->pim->ssmpingd_group_addr;
- ssmpingd_sendto(ss, buf, len, from);
+ from_addr->sin_addr = ss->pim->ssmpingd_group_addr;
+ ssmpingd_sendto(ss, buf, len, *from_addr);
return 0;
}
diff --git a/pimd/pim_static.c b/pimd/pim_static.c
index 45f0a194b0..d3b31771a0 100644
--- a/pimd/pim_static.c
+++ b/pimd/pim_static.c
@@ -305,11 +305,11 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
i);
if (pim_addr_is_any(sroute->source))
vty_out(vty,
- " ip mroute %s %pPA\n",
+ " " PIM_AF_NAME " mroute %s %pPA\n",
oifp->name, &sroute->group);
else
vty_out(vty,
- " ip mroute %s %pPA %pPA\n",
+ " " PIM_AF_NAME " mroute %s %pPA %pPA\n",
oifp->name, &sroute->group,
&sroute->source);
count++;
diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c
new file mode 100644
index 0000000000..838f11211e
--- /dev/null
+++ b/pimd/pim_tib.c
@@ -0,0 +1,178 @@
+/*
+ * TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now
+ * Copyright (C) 2022 David Lamparter for NetDEF, Inc.
+ *
+ * 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "pim_tib.h"
+
+#include "pimd.h"
+#include "pim_iface.h"
+#include "pim_upstream.h"
+#include "pim_oil.h"
+#include "pim_nht.h"
+
+static struct channel_oil *
+tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
+{
+ struct pim_interface *pim_oif = oif->info;
+ int input_iface_vif_index = 0;
+ pim_addr vif_source;
+ struct prefix src, grp;
+ struct pim_nexthop nexthop;
+ struct pim_upstream *up = NULL;
+
+ if (!pim_rp_set_upstream_addr(pim, &vif_source, sg.src, sg.grp)) {
+ /* no PIM RP - create a dummy channel oil */
+ return pim_channel_oil_add(pim, &sg, __func__);
+ }
+
+ pim_addr_to_prefix(&src, vif_source); // RP or Src addr
+ pim_addr_to_prefix(&grp, sg.grp);
+
+ up = pim_upstream_find(pim, &sg);
+ if (up) {
+ memcpy(&nexthop, &up->rpf.source_nexthop,
+ sizeof(struct pim_nexthop));
+ pim_ecmp_nexthop_lookup(pim, &nexthop, &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
+ pim, nexthop.interface->ifindex);
+ } else
+ input_iface_vif_index =
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp);
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug("%s: NHT %pSG vif_source %pPAs vif_index:%d",
+ __func__, &sg, &vif_source, input_iface_vif_index);
+
+ if (input_iface_vif_index < 1) {
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug(
+ "%s %s: could not find input interface for %pSG",
+ __FILE__, __func__, &sg);
+
+ return pim_channel_oil_add(pim, &sg, __func__);
+ }
+
+ /*
+ * Protect IGMP against adding looped MFC entries created by both
+ * source and receiver attached to the same interface. See TODO T22.
+ * Block only when the intf is non DR DR must create upstream.
+ */
+ if ((input_iface_vif_index == pim_oif->mroute_vif_index) &&
+ !(PIM_I_am_DR(pim_oif))) {
+ /* ignore request for looped MFC entry */
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug(
+ "%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
+ __func__, &sg, oif->name,
+ input_iface_vif_index);
+
+ return NULL;
+ }
+
+ return pim_channel_oil_add(pim, &sg, __func__);
+}
+
+bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
+ struct interface *oif, struct channel_oil **oilp)
+{
+ struct pim_interface *pim_oif = oif->info;
+
+ if (!pim_oif) {
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug("%s: multicast not enabled on oif=%s?",
+ __func__, oif->name);
+ return false;
+ }
+
+ if (!*oilp)
+ *oilp = tib_sg_oil_setup(pim, sg, oif);
+ if (!*oilp)
+ return false;
+
+ if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
+ int result;
+
+ result = pim_channel_add_oif(*oilp, oif,
+ PIM_OIF_FLAG_PROTO_IGMP, __func__);
+ if (result) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_warn("%s: add_oif() failed with return=%d",
+ __func__, result);
+ return false;
+ }
+ } else {
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug(
+ "%s: %pSG was received on %s interface but we are not DR for that interface",
+ __func__, &sg, oif->name);
+
+ return false;
+ }
+ /*
+ Feed IGMPv3-gathered local membership information into PIM
+ per-interface (S,G) state.
+ */
+ if (!pim_ifchannel_local_membership_add(oif, &sg, false /*is_vxlan*/)) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_warn(
+ "%s: Failure to add local membership for %pSG",
+ __func__, &sg);
+
+ pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP,
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
+ struct interface *oif, struct channel_oil **oilp)
+{
+ int result;
+
+ /*
+ It appears that in certain circumstances that
+ igmp_source_forward_stop is called when IGMP forwarding
+ was not enabled in oif_flags for this outgoing interface.
+ Possibly because of multiple calls. When that happens, we
+ enter the below if statement and this function returns early
+ which in turn triggers the calling function to assert.
+ Making the call to pim_channel_del_oif and ignoring the return code
+ fixes the issue without ill effect, similar to
+ pim_forward_stop below.
+ */
+ result = pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP,
+ __func__);
+ if (result) {
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug(
+ "%s: pim_channel_del_oif() failed with return=%d",
+ __func__, result);
+ return;
+ }
+
+ /*
+ Feed IGMPv3-gathered local membership information into PIM
+ per-interface (S,G) state.
+ */
+ pim_ifchannel_local_membership_del(oif, &sg);
+}
diff --git a/pimd/pim_tib.h b/pimd/pim_tib.h
new file mode 100644
index 0000000000..b320f4cde0
--- /dev/null
+++ b/pimd/pim_tib.h
@@ -0,0 +1,33 @@
+/*
+ * TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now
+ * Copyright (C) 2022 David Lamparter for NetDEF, Inc.
+ *
+ * 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_PIM_GLUE_H
+#define _FRR_PIM_GLUE_H
+
+#include "pim_addr.h"
+
+struct pim_instance;
+struct channel_oil;
+
+extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
+ struct interface *oif, struct channel_oil **oilp);
+extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
+ struct interface *oif, struct channel_oil **oilp);
+
+#endif /* _FRR_PIM_GLUE_H */
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index 86403dd54a..028514659b 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -127,11 +127,7 @@ int pim_encode_addr_ucast(uint8_t *buf, pim_addr addr)
{
uint8_t *start = buf;
-#if PIM_IPV == 4
- *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV4;
-#else
- *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV6;
-#endif
+ *buf++ = PIM_MSG_ADDRESS_FAMILY;
*buf++ = 0;
memcpy(buf, &addr, sizeof(addr));
buf += sizeof(addr);
@@ -624,16 +620,15 @@ int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf,
}
switch (family) {
- case PIM_MSG_ADDRESS_FAMILY_IPV4:
- if ((addr + sizeof(struct in_addr)) > pastend) {
+ case PIM_MSG_ADDRESS_FAMILY:
+ if ((addr + sizeof(sg->src)) > pastend) {
zlog_warn(
- "%s: IPv4 source address overflow: left=%td needed=%zu",
- __func__, pastend - addr,
- sizeof(struct in_addr));
+ "%s: IP source address overflow: left=%td needed=%zu",
+ __func__, pastend - addr, sizeof(sg->src));
return -3;
}
- memcpy(&sg->src, addr, sizeof(struct in_addr));
+ memcpy(&sg->src, addr, sizeof(sg->src));
/*
RFC 4601: 4.9.1 Encoded Source and Group Address Formats
@@ -642,27 +637,24 @@ int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf,
The mask length MUST be equal to the mask length in bits for
the given Address Family and Encoding Type (32 for IPv4
- native
- and 128 for IPv6 native). A router SHOULD ignore any
- messages
- received with any other mask length.
+ native and 128 for IPv6 native). A router SHOULD ignore any
+ messages received with any other mask length.
*/
- if (mask_len != IPV4_MAX_BITLEN) {
- zlog_warn("%s: IPv4 bad source address mask: %d",
+ if (mask_len != PIM_MAX_BITLEN) {
+ zlog_warn("%s: IP bad source address mask: %d",
__func__, mask_len);
return -4;
}
- addr += sizeof(struct in_addr);
+ addr += sizeof(sg->src);
break;
- default: {
+ default:
zlog_warn(
"%s: unknown source address encoding family=%d: %02x%02x%02x%02x",
__func__, family, buf[0], buf[1], buf[2], buf[3]);
return -5;
}
- }
return addr - buf;
}
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 7d835996f0..571117ac0a 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -178,6 +178,14 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
}
+static void pim_upstream_timers_stop(struct pim_upstream *up)
+{
+ THREAD_OFF(up->t_ka_timer);
+ THREAD_OFF(up->t_rs_timer);
+ THREAD_OFF(up->t_msdp_reg_timer);
+ THREAD_OFF(up->t_join_timer);
+}
+
struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
struct pim_upstream *up, const char *name)
{
@@ -207,9 +215,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
if (pim_up_mlag_is_local(up))
pim_mlag_up_local_del(pim, up);
- THREAD_OFF(up->t_ka_timer);
- THREAD_OFF(up->t_rs_timer);
- THREAD_OFF(up->t_msdp_reg_timer);
+ pim_upstream_timers_stop(up);
if (up->join_state == PIM_UPSTREAM_JOINED) {
pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
@@ -422,8 +428,8 @@ void pim_update_suppress_timers(uint32_t suppress_time)
}
}
-void pim_upstream_join_suppress(struct pim_upstream *up,
- struct in_addr rpf_addr, int holdtime)
+void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf,
+ int holdtime)
{
long t_joinsuppress_msec;
long join_timer_remain_msec = 0;
@@ -455,7 +461,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up,
if (PIM_DEBUG_PIM_TRACE) {
char rpf_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
+
+ pim_addr_dump("<rpf?>", &rpf, rpf_str, sizeof(rpf_str));
zlog_debug(
"%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
__FILE__, __func__, up->sg_str, rpf_str,
@@ -512,8 +519,10 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
if (PIM_DEBUG_PIM_TRACE) {
char rpf_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str,
- sizeof(rpf_str));
+
+ pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
+ sizeof(rpf_str));
+
zlog_debug(
"%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
debug_label, up->sg_str, rpf_str,
@@ -829,9 +838,8 @@ void pim_upstream_fill_static_iif(struct pim_upstream *up,
up->rpf.source_nexthop.interface = incoming;
/* reset other parameters to matched a connected incoming interface */
- up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
- up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
- PIM_NET_INADDR_ANY;
+ pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr,
+ PIMADDR_ANY);
up->rpf.source_nexthop.mrib_metric_preference =
ZEBRA_CONNECT_DISTANCE_DEFAULT;
up->rpf.source_nexthop.mrib_route_metric = 0;
@@ -891,16 +899,13 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
up->rpf.source_nexthop.interface = NULL;
- up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
- up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
- PIM_NET_INADDR_ANY;
+ pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr,
+ PIMADDR_ANY);
up->rpf.source_nexthop.mrib_metric_preference =
router->infinite_assert_metric.metric_preference;
up->rpf.source_nexthop.mrib_route_metric =
router->infinite_assert_metric.route_metric;
- up->rpf.rpf_addr.family = AF_INET;
- up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
-
+ pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY);
up->ifchannels = list_new();
up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
@@ -960,7 +965,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug(
- "%s: Created Upstream %s upstream_addr %pI4 ref count %d increment",
+ "%s: Created Upstream %s upstream_addr %pPAs ref count %d increment",
__func__, up->sg_str, &up->upstream_addr,
up->ref_count);
}
@@ -1946,6 +1951,7 @@ void pim_upstream_terminate(struct pim_instance *pim)
while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
pim_upstream_del(pim, up, __func__);
+ pim_upstream_timers_stop(up);
}
rb_pim_upstream_fini(&pim->upstream_head);
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index ad936a2839..8feffb8fdb 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -317,8 +317,8 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
struct pim_upstream *up);
void pim_update_suppress_timers(uint32_t suppress_time);
-void pim_upstream_join_suppress(struct pim_upstream *up,
- struct in_addr rpf_addr, int holdtime);
+void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf,
+ int holdtime);
void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
struct pim_upstream *up);
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_vty.c b/pimd/pim_vty.c
index b452b024ed..6de3a04b66 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -193,30 +193,30 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
if (pim->vrf->vrf_id == VRF_DEFAULT) {
if (router->register_suppress_time
!= PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) {
- vty_out(vty, "%sip pim register-suppress-time %d\n",
- spaces, router->register_suppress_time);
+ vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n",
+ spaces, router->register_suppress_time);
++writes;
}
if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) {
- vty_out(vty, "%sip pim join-prune-interval %d\n",
+ vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n",
spaces, router->t_periodic);
++writes;
}
if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) {
- vty_out(vty, "%sip pim packets %d\n", spaces,
+ vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces,
router->packet_process);
++writes;
}
}
if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) {
- vty_out(vty, "%sip pim keep-alive-timer %d\n", spaces,
- pim->keep_alive_time);
+ vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n",
+ spaces, pim->keep_alive_time);
++writes;
}
if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) {
- vty_out(vty, "%sip pim rp keep-alive-timer %d\n", spaces,
- pim->rp_keep_alive_time);
+ vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n",
+ spaces, pim->rp_keep_alive_time);
++writes;
}
if (ssm->plist_name) {
@@ -232,11 +232,11 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
if (pim->spt.switchover == PIM_SPT_INFINITY) {
if (pim->spt.plist)
vty_out(vty,
- "%sip pim spt-switchover infinity-and-beyond prefix-list %s\n",
+ "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n",
spaces, pim->spt.plist);
else
vty_out(vty,
- "%sip pim spt-switchover infinity-and-beyond\n",
+ "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n",
spaces);
++writes;
}
@@ -281,6 +281,134 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
return writes;
}
+#if PIM_IPV == 4
+static int pim_igmp_config_write(struct vty *vty, int writes,
+ struct pim_interface *pim_ifp)
+{
+ /* IF ip igmp */
+ if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
+ vty_out(vty, " ip igmp\n");
+ ++writes;
+ }
+
+ /* ip igmp version */
+ if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) {
+ vty_out(vty, " ip igmp version %d\n", pim_ifp->igmp_version);
+ ++writes;
+ }
+
+ /* IF ip igmp query-max-response-time */
+ if (pim_ifp->gm_query_max_response_time_dsec !=
+ IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) {
+ vty_out(vty, " ip igmp query-max-response-time %d\n",
+ pim_ifp->gm_query_max_response_time_dsec);
+ ++writes;
+ }
+
+ /* IF ip igmp query-interval */
+ if (pim_ifp->gm_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) {
+ vty_out(vty, " ip igmp query-interval %d\n",
+ pim_ifp->gm_default_query_interval);
+ ++writes;
+ }
+
+ /* IF ip igmp last-member_query-count */
+ if (pim_ifp->gm_last_member_query_count !=
+ IGMP_DEFAULT_ROBUSTNESS_VARIABLE) {
+ vty_out(vty, " ip igmp last-member-query-count %d\n",
+ pim_ifp->gm_last_member_query_count);
+ ++writes;
+ }
+
+ /* IF ip igmp last-member_query-interval */
+ if (pim_ifp->gm_specific_query_max_response_time_dsec !=
+ IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
+ vty_out(vty, " ip igmp last-member-query-interval %d\n",
+ pim_ifp->gm_specific_query_max_response_time_dsec);
+ ++writes;
+ }
+
+ /* IF ip igmp join */
+ if (pim_ifp->gm_join_list) {
+ struct listnode *node;
+ struct gm_join *ij;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<grp?>", ij->group_addr, group_str,
+ sizeof(group_str));
+ if (ij->source_addr.s_addr == INADDR_ANY) {
+ vty_out(vty, " ip igmp join %s\n", group_str);
+ } else {
+ inet_ntop(AF_INET, &ij->source_addr, source_str,
+ sizeof(source_str));
+ vty_out(vty, " ip igmp join %s %s\n", group_str,
+ source_str);
+ }
+ ++writes;
+ }
+ }
+
+ return writes;
+}
+#endif
+
+int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
+ struct pim_instance *pim)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (PIM_IF_TEST_PIM(pim_ifp->options)) {
+ vty_out(vty, " " PIM_AF_NAME " pim\n");
+ ++writes;
+ }
+
+ /* IF ip pim drpriority */
+ if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
+ vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n",
+ pim_ifp->pim_dr_priority);
+ ++writes;
+ }
+
+ /* IF ip pim hello */
+ if (pim_ifp->pim_hello_period != PIM_DEFAULT_HELLO_PERIOD) {
+ vty_out(vty, " " PIM_AF_NAME " pim hello %d", pim_ifp->pim_hello_period);
+ if (pim_ifp->pim_default_holdtime != -1)
+ vty_out(vty, " %d", pim_ifp->pim_default_holdtime);
+ vty_out(vty, "\n");
+ ++writes;
+ }
+
+#if PIM_IPV == 4
+ writes += pim_igmp_config_write(vty, writes, pim_ifp);
+#endif
+
+ /* update source */
+ if (!pim_addr_is_any(pim_ifp->update_source)) {
+ vty_out(vty, " " PIM_AF_NAME " pim use-source %pPA\n",
+ &pim_ifp->update_source);
+ ++writes;
+ }
+
+ if (pim_ifp->activeactive)
+ vty_out(vty, " " PIM_AF_NAME " pim active-active\n");
+
+ /* boundary */
+ if (pim_ifp->boundary_oil_plist) {
+ vty_out(vty, " " PIM_AF_NAME " multicast boundary oil %s\n",
+ pim_ifp->boundary_oil_plist);
+ ++writes;
+ }
+
+ writes += pim_static_write_mroute(pim, vty, ifp);
+ pim_bsm_write_config(vty, ifp);
+ ++writes;
+ pim_bfd_write_config(vty, ifp);
+ ++writes;
+
+ return writes;
+}
+
int pim_interface_config_write(struct vty *vty)
{
struct pim_instance *pim;
@@ -312,144 +440,10 @@ int pim_interface_config_write(struct vty *vty)
}
if (ifp->info) {
- struct pim_interface *pim_ifp = ifp->info;
-
- if (PIM_IF_TEST_PIM(pim_ifp->options)) {
- vty_out(vty, " ip pim\n");
- ++writes;
- }
-
- /* IF ip pim drpriority */
- if (pim_ifp->pim_dr_priority
- != PIM_DEFAULT_DR_PRIORITY) {
- vty_out(vty, " ip pim drpriority %u\n",
- pim_ifp->pim_dr_priority);
- ++writes;
- }
-
- /* IF ip pim hello */
- if (pim_ifp->pim_hello_period
- != PIM_DEFAULT_HELLO_PERIOD) {
- vty_out(vty, " ip pim hello %d",
- pim_ifp->pim_hello_period);
- if (pim_ifp->pim_default_holdtime != -1)
- vty_out(vty, " %d",
- pim_ifp->pim_default_holdtime);
- vty_out(vty, "\n");
- ++writes;
- }
-
- /* update source */
- if (!pim_addr_is_any(pim_ifp->update_source)) {
- vty_out(vty,
- " ip pim use-source %pPA\n",
- &pim_ifp->update_source);
- ++writes;
- }
-
- /* IF ip igmp */
- if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
- vty_out(vty, " ip igmp\n");
- ++writes;
- }
-
- /* ip igmp version */
- if (pim_ifp->igmp_version
- != IGMP_DEFAULT_VERSION) {
- vty_out(vty, " ip igmp version %d\n",
- pim_ifp->igmp_version);
- ++writes;
- }
-
- /* IF ip igmp query-max-response-time */
- if (pim_ifp->gm_query_max_response_time_dsec !=
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) {
- vty_out(vty,
- " ip igmp query-max-response-time %d\n",
- pim_ifp->gm_query_max_response_time_dsec);
- ++writes;
- }
-
- /* IF ip igmp query-interval */
- if (pim_ifp->gm_default_query_interval !=
- IGMP_GENERAL_QUERY_INTERVAL) {
- vty_out(vty,
- " ip igmp query-interval %d\n",
- pim_ifp->gm_default_query_interval);
- ++writes;
- }
-
- /* IF ip igmp last-member_query-count */
- if (pim_ifp->gm_last_member_query_count !=
- IGMP_DEFAULT_ROBUSTNESS_VARIABLE) {
- vty_out(vty,
- " ip igmp last-member-query-count %d\n",
- pim_ifp->gm_last_member_query_count);
- ++writes;
- }
-
- /* IF ip igmp last-member_query-interval */
- if (pim_ifp->gm_specific_query_max_response_time_dsec !=
- IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
- vty_out(vty,
- " ip igmp last-member-query-interval %d\n",
- pim_ifp->gm_specific_query_max_response_time_dsec);
- ++writes;
- }
-
-#if PIM_IPV == 4
- /* IF ip igmp join */
- if (pim_ifp->gm_join_list) {
- struct listnode *node;
- struct gm_join *ij;
- for (ALL_LIST_ELEMENTS_RO(
- pim_ifp->gm_join_list,
- node, ij)) {
- char group_str[INET_ADDRSTRLEN];
- char source_str
- [INET_ADDRSTRLEN];
- pim_inet4_dump(
- "<grp?>",
- ij->group_addr,
- group_str,
- sizeof(group_str));
- if (ij->source_addr.s_addr == INADDR_ANY) {
- vty_out(vty,
- " ip igmp join %s\n",
- group_str);
- } else {
- inet_ntop(AF_INET,
- &ij->source_addr,
- source_str,
- sizeof(source_str));
- vty_out(vty,
- " ip igmp join %s %s\n",
- group_str, source_str);
- }
- ++writes;
- }
- }
-#endif /* PIM_IPV == 4 */
-
- if (pim_ifp->activeactive)
- vty_out(vty, " ip pim active-active\n");
-
- /* boundary */
- if (pim_ifp->boundary_oil_plist) {
- vty_out(vty,
- " ip multicast boundary oil %s\n",
- pim_ifp->boundary_oil_plist);
- ++writes;
- }
-
- writes +=
- pim_static_write_mroute(pim, vty, ifp);
- pim_bsm_write_config(vty, ifp);
- ++writes;
- pim_bfd_write_config(vty, ifp);
- ++writes;
+ pim_config_write(vty, writes, ifp, pim);
}
if_vty_config_end(vty);
+
++writes;
}
}
diff --git a/pimd/pim_vty.h b/pimd/pim_vty.h
index 22ac3333e4..c192ba3bbd 100644
--- a/pimd/pim_vty.h
+++ b/pimd/pim_vty.h
@@ -25,5 +25,6 @@
int pim_debug_config_write(struct vty *vty);
int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty);
int pim_interface_config_write(struct vty *vty);
-
+int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
+ struct pim_instance *pim);
#endif /* PIM_VTY_H */
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 0acd3c0694..7f463715a5 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -55,7 +55,6 @@ struct zclient *zclient;
/* Router-id update message from zebra. */
-__attribute__((unused))
static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
{
struct prefix router_id;
@@ -65,7 +64,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
return 0;
}
-__attribute__((unused))
static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
@@ -158,6 +156,10 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
}
}
+#else /* PIM_IPV != 4 */
+ if (p->family != PIM_AF)
+ return 0;
+#endif
pim_if_addr_add(c);
if (pim_ifp) {
@@ -178,10 +180,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
pim_if_addr_add_all(ifp);
}
}
-#else /* PIM_IPV != 4 */
- /* unused - for now */
- (void)pim_ifp;
-#endif
return 0;
}
@@ -220,8 +218,7 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
#endif
}
-#if PIM_IPV == 4
- if (p->family == AF_INET) {
+ if (p->family == PIM_AF) {
struct pim_instance *pim;
pim = vrf->info;
@@ -229,7 +226,6 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
pim_rp_setup(pim);
pim_i_am_rp_re_evaluate(pim);
}
-#endif
connected_free(&c);
return 0;
@@ -454,11 +450,12 @@ 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,
-#if PIM_IPV == 4
+
+ [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
[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,
+#if PIM_IPV == 4
[ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
[ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
@@ -485,342 +482,13 @@ void pim_zebra_init(void)
zclient_lookup_new();
}
-#if PIM_IPV == 4
-void igmp_anysource_forward_start(struct pim_instance *pim,
- struct gm_group *group)
-{
- struct gm_source *source;
- struct in_addr src_addr = {.s_addr = 0};
- /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
- assert(group->group_filtermode_isexcl);
- assert(listcount(group->group_source_list) < 1);
-
- source = igmp_get_source_by_addr(group, src_addr, NULL);
- if (!source) {
- zlog_warn("%s: Failure to create * source", __func__);
- return;
- }
-
- igmp_source_forward_start(pim, source);
-}
-
-void igmp_anysource_forward_stop(struct gm_group *group)
-{
- struct gm_source *source;
- struct in_addr star = {.s_addr = 0};
-
- source = igmp_find_source_by_addr(group, star);
- if (source)
- igmp_source_forward_stop(source);
-}
-
-static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
- struct gm_source *source)
-{
- pim_sgaddr sg;
- struct gm_group *group = source->source_group;
- struct pim_ifchannel *ch;
-
- if ((source->source_addr.s_addr != INADDR_ANY)
- || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
- return;
-
- memset(&sg, 0, sizeof(sg));
- sg.src = source->source_addr;
- sg.grp = group->group_addr;
-
- ch = pim_ifchannel_find(group->interface, &sg);
- if (pim_is_grp_ssm(pim, group->group_addr)) {
- /* If SSM group withdraw local membership */
- if (ch
- && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
- if (PIM_DEBUG_PIM_EVENTS)
- zlog_debug("local membership del for %pSG as G is now SSM",
- &sg);
- pim_ifchannel_local_membership_del(group->interface,
- &sg);
- }
- } else {
- /* If ASM group add local membership */
- if (!ch
- || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
- if (PIM_DEBUG_PIM_EVENTS)
- zlog_debug("local membership add for %pSG as G is now ASM",
- &sg);
- pim_ifchannel_local_membership_add(
- group->interface, &sg, false /*is_vxlan*/);
- }
- }
-}
-
-void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
-{
- struct interface *ifp;
-
- FOR_ALL_INTERFACES (pim->vrf, ifp) {
- struct pim_interface *pim_ifp = ifp->info;
- struct listnode *grpnode;
- struct gm_group *grp;
- struct pim_ifchannel *ch, *ch_temp;
-
- if (!pim_ifp)
- continue;
-
- /* scan igmp groups */
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
- grp)) {
- struct listnode *srcnode;
- struct gm_source *src;
-
- /* scan group sources */
- for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
- srcnode, src)) {
- igmp_source_forward_reevaluate_one(pim, src);
- } /* scan group sources */
- } /* scan igmp groups */
-
- RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
- ch_temp) {
- if (pim_is_grp_ssm(pim, ch->sg.grp)) {
- if (pim_addr_is_any(ch->sg.src))
- pim_ifchannel_delete(ch);
- }
- }
- } /* scan interfaces */
-}
-
-void igmp_source_forward_start(struct pim_instance *pim,
- struct gm_source *source)
-{
- struct pim_interface *pim_oif;
- struct gm_group *group;
- pim_sgaddr sg;
- int result;
- int input_iface_vif_index = 0;
-
- memset(&sg, 0, sizeof(sg));
- sg.src = source->source_addr;
- sg.grp = source->source_group->group_addr;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
- source->source_group->interface->name,
- IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
- }
-
- /* Prevent IGMP interface from installing multicast route multiple
- times */
- if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
- return;
- }
-
- group = source->source_group;
- pim_oif = group->interface->info;
- if (!pim_oif) {
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug("%s: multicast not enabled on oif=%s ?",
- __func__,
- source->source_group->interface->name);
- }
- return;
- }
-
- if (!source->source_channel_oil) {
- pim_addr vif_source;
- struct prefix src, grp;
- struct pim_nexthop nexthop;
- struct pim_upstream *up = NULL;
-
- if (!pim_rp_set_upstream_addr(pim, &vif_source,
- source->source_addr, sg.grp)) {
- /*Create a dummy channel oil */
- source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, __func__);
- }
-
- else {
- pim_addr_to_prefix(&src, vif_source); // RP or Src addr
- pim_addr_to_prefix(&grp, sg.grp);
-
- up = pim_upstream_find(pim, &sg);
- if (up) {
- memcpy(&nexthop, &up->rpf.source_nexthop,
- sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
- &grp, 0);
- if (nexthop.interface)
- input_iface_vif_index =
- pim_if_find_vifindex_by_ifindex(
- pim,
- nexthop.interface->ifindex);
- } else
- input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(
- pim, &src, &grp);
-
- if (PIM_DEBUG_ZEBRA)
- zlog_debug(
- "%s: NHT %pSG vif_source %pPAs vif_index:%d ",
- __func__, &sg, &vif_source,
- input_iface_vif_index);
-
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>",
- source->source_addr,
- source_str, sizeof(source_str));
- zlog_debug(
- "%s %s: could not find input interface for source %s",
- __FILE__, __func__, source_str);
- }
- source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, __func__);
- }
-
- else {
- /*
- * Protect IGMP against adding looped MFC
- * entries created by both source and receiver
- * attached to the same interface. See TODO
- * T22. Block only when the intf is non DR
- * DR must create upstream.
- */
- if ((input_iface_vif_index ==
- pim_oif->mroute_vif_index) &&
- !(PIM_I_am_DR(pim_oif))) {
- /* ignore request for looped MFC entry
- */
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
- __func__,
- &sg,
- source->source_group
- ->interface->name,
- input_iface_vif_index);
- }
- return;
- }
-
- source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, __func__);
- if (!source->source_channel_oil) {
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
- __FILE__, __func__,
- &sg);
- }
- return;
- }
- }
- }
- }
-
- if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
- result = pim_channel_add_oif(source->source_channel_oil,
- group->interface,
- PIM_OIF_FLAG_PROTO_IGMP, __func__);
- if (result) {
- if (PIM_DEBUG_MROUTE) {
- zlog_warn("%s: add_oif() failed with return=%d",
- __func__, result);
- }
- return;
- }
- } else {
- if (PIM_DEBUG_IGMP_TRACE)
- zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
- __func__, &sg,
- group->interface->name);
-
- return;
- }
- /*
- Feed IGMPv3-gathered local membership information into PIM
- per-interface (S,G) state.
- */
- if (!pim_ifchannel_local_membership_add(group->interface, &sg,
- false /*is_vxlan*/)) {
- if (PIM_DEBUG_MROUTE)
- zlog_warn("%s: Failure to add local membership for %pSG",
- __func__, &sg);
-
- pim_channel_del_oif(source->source_channel_oil,
- group->interface, PIM_OIF_FLAG_PROTO_IGMP,
- __func__);
- return;
- }
-
- IGMP_SOURCE_DO_FORWARDING(source->source_flags);
-}
-
-/*
- igmp_source_forward_stop: stop fowarding, but keep the source
- igmp_source_delete: stop fowarding, and delete the source
- */
-void igmp_source_forward_stop(struct gm_source *source)
-{
- struct gm_group *group;
- pim_sgaddr sg;
- int result;
-
- memset(&sg, 0, sizeof(sg));
- sg.src = source->source_addr;
- sg.grp = source->source_group->group_addr;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
- source->source_group->interface->name,
- IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
- }
-
- /* Prevent IGMP interface from removing multicast route multiple
- times */
- if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
- return;
- }
-
- group = source->source_group;
-
- /*
- It appears that in certain circumstances that
- igmp_source_forward_stop is called when IGMP forwarding
- was not enabled in oif_flags for this outgoing interface.
- Possibly because of multiple calls. When that happens, we
- enter the below if statement and this function returns early
- which in turn triggers the calling function to assert.
- Making the call to pim_channel_del_oif and ignoring the return code
- fixes the issue without ill effect, similar to
- pim_forward_stop below.
- */
- result = pim_channel_del_oif(source->source_channel_oil,
- group->interface, PIM_OIF_FLAG_PROTO_IGMP,
- __func__);
- if (result) {
- if (PIM_DEBUG_IGMP_TRACE)
- zlog_debug(
- "%s: pim_channel_del_oif() failed with return=%d",
- __func__, result);
- return;
- }
-
- /*
- Feed IGMPv3-gathered local membership information into PIM
- per-interface (S,G) state.
- */
- pim_ifchannel_local_membership_del(group->interface, &sg);
-
- IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
-}
-#endif /* PIM_IPV == 4 */
-
void pim_forward_start(struct pim_ifchannel *ch)
{
struct pim_upstream *up = ch->upstream;
uint32_t mask = 0;
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: (S,G)=%pSG oif=%s (%pI4)", __func__, &ch->sg,
+ zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__, &ch->sg,
ch->interface->name, &up->upstream_addr);
if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index 8656d7563d..5879cdefb0 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -23,7 +23,6 @@
#include <zebra.h>
#include "zclient.h"
-#include "pim_igmp.h"
#include "pim_ifchannel.h"
void pim_zebra_init(void);
@@ -32,15 +31,6 @@ void pim_zebra_zclient_update(struct vty *vty);
void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index);
void pim_scan_oil(struct pim_instance *pim_matcher);
-void igmp_anysource_forward_start(struct pim_instance *pim,
- struct gm_group *group);
-void igmp_anysource_forward_stop(struct gm_group *group);
-
-void igmp_source_forward_start(struct pim_instance *pim,
- struct gm_source *source);
-void igmp_source_forward_stop(struct gm_source *source);
-void igmp_source_forward_reevaluate_all(struct pim_instance *pim);
-
void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch);
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index a0877b883c..c33e6032bf 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -36,6 +36,7 @@
#include "pim_str.h"
#include "pim_oil.h"
#include "pim_zlookup.h"
+#include "pim_addr.h"
static struct zclient *zlookup = NULL;
struct thread *zlookup_read;
@@ -411,15 +412,11 @@ int zclient_lookup_nexthop(struct pim_instance *pim,
num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab,
tab_size, addr);
if (num_ifindex < 1) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: lookup=%d/%d: could not find nexthop ifindex for address %s(%s)",
- __func__, lookup, max_lookup, addr_str,
+ "%s: lookup=%d/%d: could not find nexthop ifindex for address %pPA(%s)",
+ __func__, lookup, max_lookup, &addr,
pim->vrf->name);
- }
return -1;
}
@@ -448,23 +445,19 @@ int zclient_lookup_nexthop(struct pim_instance *pim,
if (lookup > 0) {
/* Report non-recursive success after first
* lookup */
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr,
- addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %s(%s) dist=%d met=%d",
+ "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %pPA(%s) dist=%d met=%d",
__func__, lookup, max_lookup,
- first_ifindex, addr_str,
+ first_ifindex, &addr,
pim->vrf->name,
nexthop_tab[0]
.protocol_distance,
nexthop_tab[0].route_metric);
- }
/* use last address as nexthop address */
- nexthop_tab[0].nexthop_addr.u.prefix4 = addr;
+ pim_addr_to_prefix(
+ &(nexthop_tab[0].nexthop_addr), addr);
/* report original route metric/distance */
nexthop_tab[0].route_metric = route_metric;
@@ -483,25 +476,22 @@ int zclient_lookup_nexthop(struct pim_instance *pim,
pim_addr_dump("<nexthop?>", &nexthop_addr, nexthop_str,
sizeof(nexthop_str));
zlog_debug(
- "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s(%s) dist=%d met=%d",
+ "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %pPA(%s) dist=%d met=%d",
__func__, lookup, max_lookup, nexthop_str,
- addr_str, pim->vrf->name,
+ &addr, pim->vrf->name,
nexthop_tab[0].protocol_distance,
nexthop_tab[0].route_metric);
}
- addr = nexthop_addr.u.prefix4; /* use nexthop addr for
- recursive lookup */
+ addr = pim_addr_from_prefix(&(nexthop_addr)); /* use nexthop
+ addr for recursive lookup */
} /* for (max_lookup) */
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_warn(
- "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s(%s)",
- __func__, lookup, max_lookup, addr_str, pim->vrf->name);
- }
+ "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %pPA(%s)",
+ __func__, lookup, max_lookup, &addr, pim->vrf->name);
return -2;
}
diff --git a/pimd/pimd.c b/pimd/pimd.c
index 9621f9794d..58e874fd11 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -32,7 +32,11 @@
#include "bfd.h"
#include "pimd.h"
+#if PIM_IPV == 4
#include "pim_cmd.h"
+#else
+#include "pim6_cmd.h"
+#endif
#include "pim_str.h"
#include "pim_oil.h"
#include "pim_pim.h"
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 86e8ca780b..cda5acb004 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -6,8 +6,12 @@ if PIMD
sbin_PROGRAMS += pimd/pimd
bin_PROGRAMS += pimd/mtracebis
noinst_PROGRAMS += pimd/test_igmpv3_join
-vtysh_scan += pimd/pim_cmd.c
+vtysh_scan += \
+ pimd/pim_cmd.c \
+ pimd/pim6_cmd.c \
+ #end
vtysh_daemons += pimd
+vtysh_daemons += pim6d
man8 += $(MANBUILD)/frr-pimd.8
man8 += $(MANBUILD)/mtracebis.8
endif
@@ -17,7 +21,7 @@ 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 \
pimd/pim_iface.c \
@@ -33,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 \
@@ -42,6 +47,7 @@ pim_common = \
pimd/pim_ssmpingd.c \
pimd/pim_static.c \
pimd/pim_str.c \
+ pimd/pim_tib.c \
pimd/pim_time.c \
pimd/pim_tlv.c \
pimd/pim_upstream.c \
@@ -54,6 +60,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 \
@@ -65,7 +72,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 \
@@ -83,9 +89,13 @@ pimd_pim6d_SOURCES = \
$(pim_common) \
pimd/pim6_main.c \
pimd/pim6_stubs.c \
+ pimd/pim6_cmd.c \
# end
nodist_pimd_pim6d_SOURCES = \
+ yang/frr-pim.yang.c \
+ yang/frr-pim-rp.yang.c \
+ yang/frr-gmp.yang.c \
# end
noinst_HEADERS += \
@@ -95,6 +105,7 @@ noinst_HEADERS += \
pimd/pim_br.h \
pimd/pim_bsm.h \
pimd/pim_cmd.h \
+ pimd/pim_cmd_common.h \
pimd/pim_errors.h \
pimd/pim_hello.h \
pimd/pim_iface.h \
@@ -131,6 +142,7 @@ noinst_HEADERS += \
pimd/pim_ssmpingd.h \
pimd/pim_static.h \
pimd/pim_str.h \
+ pimd/pim_tib.h \
pimd/pim_time.h \
pimd/pim_tlv.h \
pimd/pim_upstream.h \
@@ -143,10 +155,12 @@ noinst_HEADERS += \
pimd/pimd.h \
pimd/mtracebis_netlink.h \
pimd/mtracebis_routeget.h \
+ pimd/pim6_cmd.h \
# end
clippy_scan += \
pimd/pim_cmd.c \
+ pimd/pim6_cmd.c \
# end
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
diff --git a/python/clidef.py b/python/clidef.py
index b57a00fc89..101c9a5ae3 100644
--- a/python/clidef.py
+++ b/python/clidef.py
@@ -241,24 +241,51 @@ def get_always_args(token, always_args, args=[], stack=[]):
class Macros(dict):
+ def __init__(self):
+ super().__init__()
+ self._loc = {}
+
def load(self, filename):
filedata = clippy.parse(filename)
for entry in filedata["data"]:
if entry["type"] != "PREPROC":
continue
- ppdir = entry["line"].lstrip().split(None, 1)
- if ppdir[0] != "define" or len(ppdir) != 2:
- continue
- ppdef = ppdir[1].split(None, 1)
- name = ppdef[0]
- if "(" in name:
- continue
- val = ppdef[1] if len(ppdef) == 2 else ""
-
- val = val.strip(" \t\n\\")
- if name in self:
- sys.stderr.write("warning: macro %s redefined!\n" % (name))
+ self.load_preproc(filename, entry)
+
+ def setup(self, key, val, where="built-in"):
+ self[key] = val
+ self._loc[key] = (where, 0)
+
+ def load_preproc(self, filename, entry):
+ ppdir = entry["line"].lstrip().split(None, 1)
+ if ppdir[0] != "define" or len(ppdir) != 2:
+ return
+ ppdef = ppdir[1].split(None, 1)
+ name = ppdef[0]
+ if "(" in name:
+ return
+ val = ppdef[1] if len(ppdef) == 2 else ""
+
+ val = val.strip(" \t\n\\")
+ if self.get(name, val) != val:
+ sys.stderr.write(
+ "%s:%d: warning: macro %s redefined!\n"
+ % (
+ filename,
+ entry["lineno"],
+ name,
+ )
+ )
+ sys.stderr.write(
+ "%s:%d: note: previously defined here\n"
+ % (
+ self._loc[name][0],
+ self._loc[name][1],
+ )
+ )
+ else:
self[name] = val
+ self._loc[name] = (filename, entry["lineno"])
def process_file(fn, ofd, dumpfd, all_defun, macros):
@@ -283,6 +310,11 @@ def process_file(fn, ofd, dumpfd, all_defun, macros):
cond_stack.append(prev_line + line)
elif tokens[0] in ["endif"]:
cond_stack.pop(-1)
+ elif tokens[0] in ["define"]:
+ if not cond_stack:
+ macros.load_preproc(fn, entry)
+ elif len(cond_stack) == 1 and cond_stack[0] == "#ifdef CLIPPY\n":
+ macros.load_preproc(fn, entry)
continue
if entry["type"].startswith("DEFPY") or (
all_defun and entry["type"].startswith("DEFUN")
@@ -454,9 +486,9 @@ if __name__ == "__main__":
macros.load(os.path.join(basepath, "lib/command.h"))
macros.load(os.path.join(basepath, "bgpd/bgp_vty.h"))
# sigh :(
- macros["PROTO_REDIST_STR"] = "FRR_REDIST_STR_ISISD"
- macros["PROTO_IP_REDIST_STR"] = "FRR_IP_REDIST_STR_ISISD"
- macros["PROTO_IP6_REDIST_STR"] = "FRR_IP6_REDIST_STR_ISISD"
+ macros.setup("PROTO_REDIST_STR", "FRR_REDIST_STR_ISISD")
+ macros.setup("PROTO_IP_REDIST_STR", "FRR_IP_REDIST_STR_ISISD")
+ macros.setup("PROTO_IP6_REDIST_STR", "FRR_IP6_REDIST_STR_ISISD")
errors = process_file(args.cfile, ofd, dumpfd, args.all_defun, macros)
if errors != 0:
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 313febd9bb..5304b17f06 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -680,16 +680,17 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
{
struct sharp_nh_tracker *nht;
struct zapi_route nhr;
+ struct prefix matched;
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
zlog_err("%s: Decode of update failed", __func__);
return 0;
}
- zlog_debug("Received update for %pFX metric: %u", &nhr.prefix,
- nhr.metric);
+ zlog_debug("Received update for %pFX actual match: %pFX metric: %u",
+ &matched, &nhr.prefix, nhr.metric);
- nht = sharp_nh_tracker_get(&nhr.prefix);
+ nht = sharp_nh_tracker_get(&matched);
nht->nhop_num = nhr.nexthop_num;
nht->updates++;
diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in
index 51252ede0c..01033d0413 100644
--- a/snapcraft/snapcraft.yaml.in
+++ b/snapcraft/snapcraft.yaml.in
@@ -306,6 +306,7 @@ parts:
- make
- gawk
- libreadline-dev
+ - libelf-dev
- texinfo
- libncurses5-dev
- texlive-latex-base
diff --git a/staticd/static_main.c b/staticd/static_main.c
index 3bd784b594..7badd50049 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -43,7 +43,6 @@
char backup_config_file[256];
bool mpls_enabled;
-uint32_t zebra_ecmp_count = MULTIPATH_NUM;
zebra_capabilities_t _caps_p[] = {
};
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index b75e1a1cdf..bd293edebc 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -47,6 +47,7 @@
/* Zebra structure to hold current status. */
struct zclient *zclient;
static struct hash *static_nht_hash;
+uint32_t zebra_ecmp_count = MULTIPATH_NUM;
/* Inteface addition message from zebra. */
static int static_ifp_create(struct interface *ifp)
@@ -168,24 +169,25 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
{
struct static_nht_data *nhtd, lookup;
struct zapi_route nhr;
+ struct prefix matched;
afi_t afi = AFI_IP;
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
zlog_err("Failure to decode nexthop update message");
return 1;
}
- if (nhr.prefix.family == AF_INET6)
+ if (matched.family == AF_INET6)
afi = AFI_IP6;
if (nhr.type == ZEBRA_ROUTE_CONNECT) {
- if (static_nexthop_is_local(vrf_id, &nhr.prefix,
- nhr.prefix.family))
+ if (static_nexthop_is_local(vrf_id, &matched,
+ nhr.prefix.family))
nhr.nexthop_num = 0;
}
memset(&lookup, 0, sizeof(lookup));
- lookup.nh = &nhr.prefix;
+ lookup.nh = &matched;
lookup.nh_vrf_id = vrf_id;
nhtd = hash_lookup(static_nht_hash, &lookup);
@@ -193,8 +195,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
if (nhtd) {
nhtd->nh_num = nhr.nexthop_num;
- static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id);
- static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi,
+ static_nht_reset_start(&matched, afi, nhtd->nh_vrf_id);
+ static_nht_update(NULL, &matched, nhr.nexthop_num, afi,
nhtd->nh_vrf_id);
} else
zlog_err("No nhtd?");
@@ -302,12 +304,14 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
static_nht_hash_alloc);
nhtd->refcount++;
- DEBUGD(&static_dbg_route,
- "Registered nexthop(%pFX) for %pRN %d", &p, rn,
- nhtd->nh_num);
- if (nhtd->refcount > 1 && nhtd->nh_num) {
- static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi,
- nh->nh_vrf_id);
+ if (nhtd->refcount > 1) {
+ DEBUGD(&static_dbg_route,
+ "Already registered nexthop(%pFX) for %pRN %d",
+ &p, rn, nhtd->nh_num);
+ if (nhtd->nh_num)
+ static_nht_update(&rn->p, nhtd->nh,
+ nhtd->nh_num, afi,
+ nh->nh_vrf_id);
return;
}
} else {
@@ -323,6 +327,9 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
static_nht_hash_free(nhtd);
}
+ DEBUGD(&static_dbg_route, "%s nexthop(%pFX) for %pRN",
+ reg ? "Registering" : "Unregistering", &p, rn);
+
if (zclient_send_rnh(zclient, cmd, &p, false, false, nh->nh_vrf_id)
== ZCLIENT_SEND_FAILURE)
zlog_warn("%s: Failure to send nexthop to zebra", __func__);
diff --git a/tests/.gitignore b/tests/.gitignore
index 70d0ef6e0a..f00177abd8 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,6 +1,8 @@
*.log
*.sum
*.xml
+frr-northbound.proto
+frr_northbound*
.pytest_cache
/bgpd/test_aspath
/bgpd/test_bgp_table
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/lib/subdir.am b/tests/lib/subdir.am
index 6c897b132e..62b194439f 100644
--- a/tests/lib/subdir.am
+++ b/tests/lib/subdir.am
@@ -148,7 +148,7 @@ check_PROGRAMS += tests/lib/test_checksum
tests_lib_test_checksum_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_checksum_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_checksum_LDADD = $(ALL_TESTS_LDADD)
-tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c
+tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c tests/helpers/c/prng.c
check_PROGRAMS += tests/lib/test_graph
diff --git a/tests/lib/test_checksum.c b/tests/lib/test_checksum.c
index 301078867a..9a7f2b1472 100644
--- a/tests/lib/test_checksum.c
+++ b/tests/lib/test_checksum.c
@@ -24,6 +24,7 @@
#include "checksum.h"
#include "network.h"
+#include "prng.h"
struct thread_master *master;
@@ -468,45 +469,88 @@ int main(int argc, char **argv)
uint8_t buffer[BUFSIZE];
int exercise = 0;
#define EXERCISESTEP 257
- srandom(time(NULL));
+ struct prng *prng = prng_new(0);
while (1) {
uint16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
- int i, j;
+ int i;
exercise += EXERCISESTEP;
exercise %= MAXDATALEN;
- for (i = 0; i < exercise; i += sizeof(long int)) {
- long int rand = frr_weak_random();
+ printf("\rexercising length %d\033[K", exercise);
- for (j = sizeof(long int); j > 0; j--)
- buffer[i + (sizeof(long int) - j)] =
- (rand >> (j * 8)) & 0xff;
- }
+ for (i = 0; i < exercise; i++)
+ buffer[i] = prng_rand(prng);
in_csum = in_cksum(buffer, exercise);
in_csum_res = in_cksum_optimized(buffer, exercise);
in_csum_rfc = in_cksum_rfc(buffer, exercise);
if (in_csum_res != in_csum || in_csum != in_csum_rfc)
- printf("verify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n",
+ printf("\nverify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n",
in_csum, in_csum_res, in_csum_rfc, exercise);
+ struct iovec iov[3];
+ uint16_t in_csum_iov;
+
+ iov[0].iov_base = buffer;
+ iov[0].iov_len = exercise / 2;
+ iov[1].iov_base = buffer + iov[0].iov_len;
+ iov[1].iov_len = exercise - iov[0].iov_len;
+
+ in_csum_iov = in_cksumv(iov, 2);
+ if (in_csum_iov != in_csum)
+ printf("\nverify: in_cksumv failed, lens: %zu+%zu\n",
+ iov[0].iov_len, iov[1].iov_len);
+
+ if (exercise >= 6) {
+ /* force split with byte leftover */
+ iov[0].iov_base = buffer;
+ iov[0].iov_len = (exercise / 2) | 1;
+ iov[1].iov_base = buffer + iov[0].iov_len;
+ iov[1].iov_len = 2;
+ iov[2].iov_base = buffer + iov[0].iov_len + 2;
+ iov[2].iov_len = exercise - iov[0].iov_len - 2;
+
+ in_csum_iov = in_cksumv(iov, 3);
+ if (in_csum_iov != in_csum)
+ printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
+ iov[0].iov_len, iov[1].iov_len,
+ iov[2].iov_len, in_csum_iov, in_csum);
+
+ /* force split without byte leftover */
+ iov[0].iov_base = buffer;
+ iov[0].iov_len = (exercise / 2) & ~1UL;
+ iov[1].iov_base = buffer + iov[0].iov_len;
+ iov[1].iov_len = 2;
+ iov[2].iov_base = buffer + iov[0].iov_len + 2;
+ iov[2].iov_len = exercise - iov[0].iov_len - 2;
+
+ in_csum_iov = in_cksumv(iov, 3);
+ if (in_csum_iov != in_csum)
+ printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
+ iov[0].iov_len, iov[1].iov_len,
+ iov[2].iov_len, in_csum_iov, in_csum);
+ }
+
+ if (exercise >= FLETCHER_CHECKSUM_VALIDATE)
+ continue;
+
ospfd = ospfd_checksum(buffer, exercise + sizeof(uint16_t),
exercise);
if (verify(buffer, exercise + sizeof(uint16_t)))
- printf("verify: ospfd failed\n");
+ printf("\nverify: ospfd failed\n");
isisd = iso_csum_create(buffer, exercise + sizeof(uint16_t),
exercise);
if (verify(buffer, exercise + sizeof(uint16_t)))
- printf("verify: isisd failed\n");
+ printf("\nverify: isisd failed\n");
lib = fletcher_checksum(buffer, exercise + sizeof(uint16_t),
exercise);
if (verify(buffer, exercise + sizeof(uint16_t)))
- printf("verify: lib failed\n");
+ printf("\nverify: lib failed\n");
if (ospfd != lib) {
- printf("Mismatch in values at size %d\n"
+ printf("\nMismatch in values at size %d\n"
"ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
"isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
"lib: 0x%04x\n",
diff --git a/tests/lib/test_grpc.py b/tests/lib/test_grpc.py
index 06ae6c05dd..2e292fadc9 100644
--- a/tests/lib/test_grpc.py
+++ b/tests/lib/test_grpc.py
@@ -1,8 +1,10 @@
import inspect
import os
import subprocess
-import pytest
+
import frrtest
+import pytest
+
class TestGRPC(object):
program = "./test_grpc"
@@ -15,9 +17,13 @@ class TestGRPC(object):
basedir = os.path.dirname(inspect.getsourcefile(type(self)))
program = os.path.join(basedir, self.program)
proc = subprocess.Popen(
- [frrtest.binpath(program)], stdin=subprocess.PIPE, stdout=subprocess.PIPE
+ [frrtest.binpath(program)],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
)
output, _ = proc.communicate()
self.exitcode = proc.wait()
if self.exitcode != 0:
+ print("OUTPUT:\n" + output.decode("ascii"))
raise frrtest.TestExitNonzero(self)
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 8f9d637afd..59d08ae82b 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -207,6 +207,24 @@ int main(int argc, char **argv)
assert(strcmp(p, "test#5") == 0);
XFREE(MTYPE_TMP, p);
+ struct prefix pfx;
+
+ str2prefix("192.168.1.23/24", &pfx);
+ printchk("192.168.1.23/24", "%pFX", &pfx);
+ printchk("192.168.1.23", "%pFXh", &pfx);
+
+ str2prefix("2001:db8::1234/64", &pfx);
+ printchk("2001:db8::1234/64", "%pFX", &pfx);
+ printchk("2001:db8::1234", "%pFXh", &pfx);
+
+ pfx.family = AF_UNIX;
+ printchk("UNK prefix", "%pFX", &pfx);
+ printchk("{prefix.af=AF_UNIX}", "%pFXh", &pfx);
+
+ str2prefix_eth("02:ca:fe:f0:0d:1e/48", (struct prefix_eth *)&pfx);
+ printchk("02:ca:fe:f0:0d:1e/48", "%pFX", &pfx);
+ printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx);
+
struct prefix_sg sg;
sg.src.s_addr = INADDR_ANY;
sg.grp.s_addr = INADDR_ANY;
diff --git a/tests/lib/test_typelist.c b/tests/lib/test_typelist.c
index 607e29e56b..6e69658490 100644
--- a/tests/lib/test_typelist.c
+++ b/tests/lib/test_typelist.c
@@ -58,9 +58,10 @@
#define T_HASH (1 << 2)
#define T_HEAP (1 << 3)
#define T_ATOMIC (1 << 4)
+#define T_REVERSE (1 << 5)
#define _T_LIST (0)
-#define _T_DLIST (0)
+#define _T_DLIST (0 | T_REVERSE)
#define _T_ATOMLIST (0 | T_ATOMIC)
#define _T_HEAP (T_SORTED | T_HEAP)
#define _T_SORTLIST_UNIQ (T_SORTED | T_UNIQ)
@@ -68,8 +69,8 @@
#define _T_HASH (T_SORTED | T_UNIQ | T_HASH)
#define _T_SKIPLIST_UNIQ (T_SORTED | T_UNIQ)
#define _T_SKIPLIST_NONUNIQ (T_SORTED)
-#define _T_RBTREE_UNIQ (T_SORTED | T_UNIQ)
-#define _T_RBTREE_NONUNIQ (T_SORTED)
+#define _T_RBTREE_UNIQ (T_SORTED | T_UNIQ | T_REVERSE)
+#define _T_RBTREE_NONUNIQ (T_SORTED | T_REVERSE)
#define _T_ATOMSORT_UNIQ (T_SORTED | T_UNIQ | T_ATOMIC)
#define _T_ATOMSORT_NONUNIQ (T_SORTED | T_ATOMIC)
@@ -79,6 +80,7 @@
#define IS_HASH(type) (_T_TYPE(type) & T_HASH)
#define IS_HEAP(type) (_T_TYPE(type) & T_HEAP)
#define IS_ATOMIC(type) (_T_TYPE(type) & T_ATOMIC)
+#define IS_REVERSE(type) (_T_TYPE(type) & T_REVERSE)
static struct timeval ref, ref0;
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index 8261616ed2..e3579c67a2 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -31,6 +31,11 @@
#define list_const_next concat(TYPE, _const_next)
#define list_next concat(TYPE, _next)
#define list_next_safe concat(TYPE, _next_safe)
+#define list_const_last concat(TYPE, _const_last)
+#define list_last concat(TYPE, _last)
+#define list_const_prev concat(TYPE, _const_prev)
+#define list_prev concat(TYPE, _prev)
+#define list_prev_safe concat(TYPE, _prev_safe)
#define list_count concat(TYPE, _count)
#define list_add concat(TYPE, _add)
#define list_add_head concat(TYPE, _add_head)
@@ -171,6 +176,9 @@ static void concat(test_, TYPE)(void)
list_init(&head);
assert(list_first(&head) == NULL);
+#if IS_REVERSE(REALTYPE)
+ assert(list_last(&head) == NULL);
+#endif
ts_hash("init", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119");
@@ -203,6 +211,10 @@ static void concat(test_, TYPE)(void)
assert(!list_first(&head));
assert(list_count(&other) == k);
assert(list_first(&other) != NULL);
+#if IS_REVERSE(REALTYPE)
+ assert(!list_last(&head));
+ assert(list_last(&other) != NULL);
+#endif
ts_hash_headx(
&other, "swap1",
"a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
@@ -269,13 +281,36 @@ static void concat(test_, TYPE)(void)
(void)cprev;
#else
assert(!cprev || cprev->val < citem->val);
+#if IS_REVERSE(REALTYPE)
+ assert(list_const_prev(chead, citem) == cprev);
+#endif
#endif
cprev = citem;
k++;
}
assert(list_count(chead) == k);
+#if IS_REVERSE(REALTYPE)
+ assert(cprev == list_const_last(chead));
+#endif
ts_ref("walk");
+#if IS_REVERSE(REALTYPE) && !IS_HASH(REALTYPE) && !IS_HEAP(REALTYPE)
+ cprev = NULL;
+ k = 0;
+
+ frr_rev_each(list_const, chead, citem) {
+ assert(!cprev || cprev->val > citem->val);
+ assert(list_const_next(chead, citem) == cprev);
+
+ cprev = citem;
+ k++;
+ }
+ assert(list_count(chead) == k);
+ assert(cprev == list_const_first(chead));
+
+ ts_ref("reverse-walk");
+#endif
+
#if IS_UNIQ(REALTYPE)
prng_free(prng);
prng = prng_new(0);
@@ -439,6 +474,9 @@ static void concat(test_, TYPE)(void)
}
assert(list_count(&head) == k);
assert(list_first(&head) != NULL);
+#if IS_REVERSE(REALTYPE)
+ assert(list_last(&head) != NULL);
+#endif
ts_hash("fill / add_tail", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
#if !IS_ATOMIC(REALTYPE)
@@ -451,6 +489,10 @@ static void concat(test_, TYPE)(void)
assert(!list_first(&head));
assert(list_count(&other) == k);
assert(list_first(&other) != NULL);
+#if IS_REVERSE(REALTYPE)
+ assert(!list_last(&head));
+ assert(list_last(&other) != NULL);
+#endif
ts_hash_head(
&other, "swap1",
"eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
@@ -534,6 +576,21 @@ static void concat(test_, TYPE)(void)
}
ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
#endif
+#if IS_REVERSE(REALTYPE)
+ i = 0;
+ prev = NULL;
+
+ frr_rev_each (list, &head, item) {
+ assert(item->scratchpad != 0);
+ assert(list_next(&head, item) == prev);
+
+ i++;
+ prev = item;
+ }
+ assert(list_first(&head) == prev);
+ assert(list_count(&head) == i);
+ ts_hash("reverse-walk", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d");
+#endif
while ((item = list_pop(&head))) {
assert(item->scratchpad != 0);
@@ -746,6 +803,13 @@ static void concat(test_, TYPE)(void)
#undef list_first
#undef list_next
#undef list_next_safe
+#undef list_const_first
+#undef list_const_next
+#undef list_last
+#undef list_prev
+#undef list_prev_safe
+#undef list_const_last
+#undef list_const_prev
#undef list_count
#undef list_add
#undef list_add_head
diff --git a/tests/topotests/analyze.py b/tests/topotests/analyze.py
index 888e706339..bdb2e56ee1 100755
--- a/tests/topotests/analyze.py
+++ b/tests/topotests/analyze.py
@@ -198,9 +198,12 @@ def main():
logging.critical("%s doesn't exist", args.results)
sys.exit(1)
ttfiles = [args.results]
+ elif os.path.exists("/tmp/topotests/topotests.xml"):
+ ttfiles.append("/tmp/topotests/topotests.xml")
- if not ttfiles and os.path.exists("/tmp/topotests.xml"):
- ttfiles.append("/tmp/topotests.xml")
+ if not ttfiles:
+ if os.path.exists("/tmp/topotests.xml"):
+ ttfiles.append("/tmp/topotests.xml")
for f in ttfiles:
m = re.match(r"tt-group-(\d+)/topotests.xml", f)
diff --git a/tests/topotests/grpc_basic/lib b/tests/topotests/grpc_basic/lib
new file mode 120000
index 0000000000..dc598c56dc
--- /dev/null
+++ b/tests/topotests/grpc_basic/lib
@@ -0,0 +1 @@
+../lib \ No newline at end of file
diff --git a/tests/topotests/grpc_basic/r1/zebra.conf b/tests/topotests/grpc_basic/r1/zebra.conf
new file mode 100644
index 0000000000..49a0911c53
--- /dev/null
+++ b/tests/topotests/grpc_basic/r1/zebra.conf
@@ -0,0 +1,8 @@
+log record-priority
+log timestamp precision 6
+log extended extlog
+ destination file ext-log.txt create
+ timestamp precision 6
+ structured-data code-location
+interface r1-eth0
+ ip address 192.168.1.1/24 \ No newline at end of file
diff --git a/tests/topotests/grpc_basic/r2/zebra.conf b/tests/topotests/grpc_basic/r2/zebra.conf
new file mode 100644
index 0000000000..20da1885d4
--- /dev/null
+++ b/tests/topotests/grpc_basic/r2/zebra.conf
@@ -0,0 +1,8 @@
+log record-priority
+log timestamp precision 6
+log extended extlog
+ destination file ext-log.txt create
+ timestamp precision 6
+ structured-data code-location
+interface r2-eth0
+ ip address 192.168.1.2/24
diff --git a/tests/topotests/grpc_basic/test_basic_grpc.py b/tests/topotests/grpc_basic/test_basic_grpc.py
new file mode 100644
index 0000000000..b6812a5afc
--- /dev/null
+++ b/tests/topotests/grpc_basic/test_basic_grpc.py
@@ -0,0 +1,179 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+#
+# February 21 2022, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2022, 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 Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; see the file COPYING; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+"""
+test_basic_grpc.py: Test Basic gRPC.
+"""
+
+import logging
+import os
+import sys
+
+import pytest
+
+from lib.common_config import step
+from lib.micronet import commander
+from lib.topogen import Topogen, TopoRouter
+from lib.topolog import logger
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+GRPCP_ZEBRA = 50051
+GRPCP_STATICD = 50052
+GRPCP_BFDD = 50053
+GRPCP_ISISD = 50054
+GRPCP_OSPFD = 50055
+GRPCP_PIMD = 50056
+
+pytestmark = [
+ # pytest.mark.mgmtd -- Need a new non-protocol marker
+ # pytest.mark.bfdd,
+ # pytest.mark.isisd,
+ # pytest.mark.ospfd,
+ # pytest.mark.pimd,
+ pytest.mark.staticd,
+]
+
+script_path = os.path.realpath(os.path.join(CWD, "../lib/grpc-query.py"))
+
+try:
+ commander.cmd_raises([script_path, "--check"])
+except Exception:
+ pytest.skip(
+ "skipping; cannot create or import gRPC proto modules", allow_module_level=True
+ )
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, request.module.__name__)
+
+ tgen.start_topology()
+ router_list = tgen.routers()
+
+ for rname, router in router_list.items():
+ router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}")
+ router.load_config(TopoRouter.RD_STATIC, None, f"-M grpc:{GRPCP_STATICD}")
+ # router.load_config(TopoRouter.RD_BFD, None, f"-M grpc:{GRPCP_BFDD}")
+ # router.load_config(TopoRouter.RD_ISIS, None, f"-M grpc:{GRPCP_ISISD}")
+ # router.load_config(TopoRouter.RD_OSPF, None, f"-M grpc:{GRPCP_OSPFD}")
+ # router.load_config(TopoRouter.RD_PIM, None, f"-M grpc:{GRPCP_PIMD}")
+
+ tgen.start_router()
+ yield tgen
+
+ logging.info("Stopping all routers (no assert on error)")
+ tgen.stop_topology()
+
+
+# Let's not do this so we catch errors
+# Fixture that executes before each test
+@pytest.fixture(autouse=True)
+def skip_on_failure(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of previous test failure")
+
+
+# ===================
+# The tests functions
+# ===================
+
+
+def run_grpc_client(r, port, commands):
+ if not isinstance(commands, str):
+ commands = "\n".join(commands) + "\n"
+ if not commands.endswith("\n"):
+ commands += "\n"
+ return r.cmd_raises([script_path, f"--port={port}"], stdin=commands)
+
+
+def test_connectivity(tgen):
+ r1 = tgen.gears["r1"]
+ output = r1.cmd_raises("ping -c1 192.168.1.2")
+ logging.info("ping output: %s", output)
+
+
+def test_capabilities(tgen):
+ r1 = tgen.gears["r1"]
+ output = run_grpc_client(r1, GRPCP_ZEBRA, "GETCAP")
+ logging.info("grpc output: %s", output)
+
+
+def test_get_config(tgen):
+ nrepeat = 5
+ r1 = tgen.gears["r1"]
+
+ step("'GET' inteface config 10 times, once per invocation")
+
+ for i in range(0, nrepeat):
+ output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-interface:lib")
+ logging.info("[iteration %s]: grpc GET output: %s", i, output)
+
+ step(f"'GET' YANG {nrepeat} times in one invocation")
+ commands = ["GET,/frr-interface:lib" for _ in range(0, 10)]
+ output = run_grpc_client(r1, GRPCP_ZEBRA, commands)
+ logging.info("grpc GET*{%d} output: %s", nrepeat, output)
+
+
+def test_get_vrf_config(tgen):
+ r1 = tgen.gears["r1"]
+
+ step("'GET' get VRF config")
+
+ output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-vrf:lib")
+ logging.info("grpc GET /frr-vrf:lib output: %s", output)
+
+
+def test_shutdown_checks(tgen):
+ # Start a process rnuning that will fetch bunches of data then shut the routers down
+ # and check for cores.
+ nrepeat = 100
+ r1 = tgen.gears["r1"]
+ commands = ["GET,/frr-interface:lib" for _ in range(0, nrepeat)]
+ p = r1.popen([script_path, f"--port={GRPCP_ZEBRA}"] + commands)
+ import time
+
+ time.sleep(1)
+ try:
+ for r in tgen.routers().values():
+ r.net.stopRouter()
+ r.net.checkRouterCores()
+ finally:
+ if p:
+ p.terminate()
+ p.wait()
+
+
+# Memory leak test template
+# Not compatible with the shutdown check above
+def _test_memory_leak(tgen):
+ "Run the memory leak test and report results."
+
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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/tests/topotests/lib/grpc-query.py b/tests/topotests/lib/grpc-query.py
new file mode 100755
index 0000000000..61f01c36bb
--- /dev/null
+++ b/tests/topotests/lib/grpc-query.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+#
+# February 22 2022, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2022, LabN Consulting, L.L.C.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import argparse
+import logging
+import os
+import sys
+
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+# This is painful but works if you have installed grpc and grpc_tools would be *way*
+# better if we actually built and installed these but ... python packaging.
+try:
+ import grpc
+ import grpc_tools
+
+ from micronet import commander
+
+ commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .")
+ commander.cmd_raises(
+ f"python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto"
+ )
+except Exception as error:
+ logging.error("can't create proto definition modules %s", error)
+ raise
+
+try:
+ sys.path[0:0] = "."
+ import frr_northbound_pb2
+ import frr_northbound_pb2_grpc
+
+ # Would be nice if compiling the modules internally from the source worked
+ # # import grpc_tools.protoc
+ # # proto_include = pkg_resources.resource_filename("grpc_tools", "_proto")
+ # from grpc_tools.protoc import _proto_file_to_module_name, _protos_and_services
+ # try:
+ # frr_northbound_pb2, frr_northbound_pb2_grpc = _protos_and_services(
+ # "frr_northbound.proto"
+ # )
+ # finally:
+ # os.chdir(CWD)
+except Exception as error:
+ logging.error("can't import proto definition modules %s", error)
+ raise
+
+
+class GRPCClient:
+ def __init__(self, server, port):
+ self.channel = grpc.insecure_channel("{}:{}".format(server, port))
+ self.stub = frr_northbound_pb2_grpc.NorthboundStub(self.channel)
+
+ def get_capabilities(self):
+ request = frr_northbound_pb2.GetCapabilitiesRequest()
+ response = "NONE"
+ try:
+ response = self.stub.GetCapabilities(request)
+ except Exception as error:
+ logging.error("Got exception from stub: %s", error)
+
+ logging.debug("GRPC Capabilities: %s", response)
+ return response
+
+ def get(self, xpath):
+ request = frr_northbound_pb2.GetRequest()
+ request.path.append(xpath)
+ request.type = frr_northbound_pb2.GetRequest.ALL
+ request.encoding = frr_northbound_pb2.XML
+ xml = ""
+ for r in self.stub.Get(request):
+ logging.info('GRPC Get path: "%s" value: %s', request.path, r)
+ xml += str(r.data.data)
+ return xml
+
+
+def next_action(action_list=None):
+ "Get next action from list or STDIN"
+ if action_list:
+ for action in action_list:
+ yield action
+ else:
+ while True:
+ try:
+ action = input("")
+ if not action:
+ break
+ yield action.strip()
+ except EOFError:
+ break
+
+
+def main(*args):
+ parser = argparse.ArgumentParser(description="gRPC Client")
+ parser.add_argument(
+ "-s", "--server", default="localhost", help="gRPC Server Address"
+ )
+ parser.add_argument(
+ "-p", "--port", type=int, default=50051, help="gRPC Server TCP Port"
+ )
+ parser.add_argument("-v", "--verbose", action="store_true", help="be verbose")
+ parser.add_argument("--check", action="store_true", help="check runable")
+ parser.add_argument("actions", nargs="*", help="GETCAP|GET,xpath")
+ args = parser.parse_args(*args)
+
+ level = logging.DEBUG if args.verbose else logging.INFO
+ logging.basicConfig(
+ level=level,
+ format="%(asctime)s %(levelname)s: GRPC-CLI-CLIENT: %(name)s %(message)s",
+ )
+
+ if args.check:
+ sys.exit(0)
+
+ c = GRPCClient(args.server, args.port)
+
+ for action in next_action(args.actions):
+ action = action.casefold()
+ logging.info("GOT ACTION: %s", action)
+ if action == "getcap":
+ caps = c.get_capabilities()
+ print("Capabilities:", caps)
+ elif action.startswith("get,"):
+ # Print Interface State and Config
+ _, xpath = action.split(",", 1)
+ print("Get XPath: ", xpath)
+ xml = c.get(xpath)
+ print("{}: {}".format(xpath, xml))
+ # for _ in range(0, 1):
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 33e1388639..a83ae7071f 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -706,6 +706,7 @@ class TopoRouter(TopoGear):
]
# Router Daemon enumeration definition.
+ RD_FRR = 0 # not a daemon, but use to setup unified configs
RD_ZEBRA = 1
RD_RIP = 2
RD_RIPNG = 3
@@ -725,6 +726,7 @@ class TopoRouter(TopoGear):
RD_PATH = 17
RD_SNMP = 18
RD = {
+ RD_FRR: "frr",
RD_ZEBRA: "zebra",
RD_RIP: "ripd",
RD_RIPNG: "ripngd",
@@ -789,6 +791,28 @@ class TopoRouter(TopoGear):
self.logger.info('check capability {} for "{}"'.format(param, daemonstr))
return self.net.checkCapability(daemonstr, param)
+ def load_frr_config(self, source, daemons=None):
+ """
+ Loads the unified configuration file source
+ Start the daemons in the list
+ If daemons is None, try to infer daemons from the config file
+ """
+ self.load_config(self.RD_FRR, source)
+ if not daemons:
+ # Always add zebra
+ self.load_config(self.RD_ZEBRA)
+ for daemon in self.RD:
+ # This will not work for all daemons
+ daemonstr = self.RD.get(daemon).rstrip("d")
+ result = self.run(
+ "grep 'router {}' {}".format(daemonstr, source)
+ ).strip()
+ if result:
+ self.load_config(daemon)
+ else:
+ for daemon in daemons:
+ self.load_config(daemon)
+
def load_config(self, daemon, source=None, param=None):
"""Loads daemon configuration from the specified source
Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP,
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index d3438f67e5..62b6a8a70e 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1319,6 +1319,7 @@ class Router(Node):
self.daemondir = None
self.hasmpls = False
self.routertype = "frr"
+ self.unified_config = None
self.daemons = {
"zebra": 0,
"ripd": 0,
@@ -1521,21 +1522,28 @@ class Router(Node):
)
# print "Daemons before:", self.daemons
- if daemon in self.daemons.keys():
- self.daemons[daemon] = 1
+ if daemon in self.daemons.keys() or daemon == "frr":
+ if daemon == "frr":
+ self.unified_config = 1
+ else:
+ self.daemons[daemon] = 1
if param is not None:
self.daemons_options[daemon] = param
conf_file = "/etc/{}/{}.conf".format(self.routertype, daemon)
if source is None or not os.path.exists(source):
- self.cmd_raises("rm -f " + conf_file)
- self.cmd_raises("touch " + conf_file)
+ if daemon == "frr" or not self.unified_config:
+ self.cmd_raises("rm -f " + conf_file)
+ self.cmd_raises("touch " + conf_file)
else:
self.cmd_raises("cp {} {}".format(source, conf_file))
- self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file))
- self.cmd_raises("chmod 664 {}".format(conf_file))
+
+ if not self.unified_config or daemon == "frr":
+ self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file))
+ self.cmd_raises("chmod 664 {}".format(conf_file))
+
if (daemon == "snmpd") and (self.routertype == "frr"):
# /etc/snmp is private mount now
- self.cmd('echo "agentXSocket /etc/frr/agentx" > /etc/snmp/frr.conf')
+ self.cmd('echo "agentXSocket /etc/frr/agentx" >> /etc/snmp/frr.conf')
self.cmd('echo "mibs +ALL" > /etc/snmp/snmp.conf')
if (daemon == "zebra") and (self.daemons["staticd"] == 0):
@@ -1557,11 +1565,18 @@ class Router(Node):
return self.run_in_window(cmd, title)
def startRouter(self, tgen=None):
- # Disable integrated-vtysh-config
- self.cmd(
- 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf'
- % self.routertype
- )
+ if self.unified_config:
+ self.cmd(
+ 'echo "service integrated-vtysh-config" >> /etc/%s/vtysh.conf'
+ % self.routertype
+ )
+ else:
+ # Disable integrated-vtysh-config
+ self.cmd(
+ 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf'
+ % self.routertype
+ )
+
self.cmd(
"chown %s:%svty /etc/%s/vtysh.conf"
% (self.routertype, self.routertype, self.routertype)
@@ -1633,6 +1648,9 @@ class Router(Node):
if "all" in vtysh_routers or self.name in vtysh_routers:
self.run_in_window("vtysh", title="vt-%s" % self.name)
+ if self.unified_config:
+ self.cmd("vtysh -f /etc/frr/frr.conf")
+
return status
def getStdErr(self, daemon):
@@ -1731,7 +1749,7 @@ class Router(Node):
daemon, self.logdir, self.name
)
- cmdopt = "{} --log file:{}.log --log-level debug".format(
+ cmdopt = "{} --command-log-always --log file:{}.log --log-level debug".format(
daemon_opts, daemon
)
if extra_opts:
diff --git a/tools/coccinelle/json_object_add_camel_case.cocci b/tools/coccinelle/json_object_add_camel_case.cocci
new file mode 100644
index 0000000000..279ba213ac
--- /dev/null
+++ b/tools/coccinelle/json_object_add_camel_case.cocci
@@ -0,0 +1,19 @@
+// Catch whitespaces in JSON keys
+
+@r@
+identifier json;
+constant key;
+identifier func =~ "json_object_";
+position p;
+@@
+
+func(json, key, ...)@p
+
+@script:python@
+fmt << r.key;
+p << r.p;
+@@
+if " " in str(fmt):
+ print("Whitespace detected in JSON keys %s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt))
+if str(fmt)[1].isupper():
+ print("Capital first detected in JSON keys %s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt))
diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf
index e223eb2743..46e0625d8c 100644
--- a/tools/etc/frr/support_bundle_commands.conf
+++ b/tools/etc/frr/support_bundle_commands.conf
@@ -78,6 +78,7 @@ show debugging hashtable
show running-config
show thread cpu
show thread poll
+show thread timers
show daemons
show version
CMD_LIST_END
diff --git a/vrrpd/Makefile b/vrrpd/Makefile
index 027c6ee1f8..0abb1a6381 100644
--- a/vrrpd/Makefile
+++ b/vrrpd/Makefile
@@ -1,7 +1,7 @@
all: ALWAYS
- @$(MAKE) -s -C .. vrrp/vrrp
+ @$(MAKE) -s -C .. vrrpd/vrrpd
%: ALWAYS
- @$(MAKE) -s -C .. vrrp/$@
+ @$(MAKE) -s -C .. vrrpd/$@
Makefile:
#nothing
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index c2b4e779de..d940e03e1c 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -118,7 +118,7 @@ sub scan_file {
if ($defun_array[1] =~ m/ipv6/) {
$protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
} else {
- $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
+ $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
}
}
elsif ($file =~ /lib\/if_rmap\.c$/) {
@@ -143,6 +143,10 @@ sub scan_file {
elsif ($fabricd) {
$protocol = "VTYSH_FABRICD";
}
+# Enable VTYSH_PIM6D once pim6_cmd.c is merged
+# elsif ($file =~ /pimd\/pim6_cmd\.c$/) {
+# $protocol = "VTYSH_PIM6D";
+# }
else {
($protocol) = ($file =~ /^(?:.*\/)?([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/);
$protocol = "VTYSH_" . uc $protocol;
diff --git a/vtysh/subdir.am b/vtysh/subdir.am
index 5f7d854948..624361645e 100644
--- a/vtysh/subdir.am
+++ b/vtysh/subdir.am
@@ -7,6 +7,10 @@ bin_PROGRAMS += vtysh/vtysh
man1 += $(MANBUILD)/vtysh.1
endif
+clippy_scan += \
+ vtysh/vtysh.c \
+ # end
+
vtysh_vtysh_SOURCES = \
vtysh/vtysh_main.c \
vtysh/vtysh.c \
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 336fe8b30e..ed1f1fb5bb 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -40,6 +40,7 @@
#include "linklist.h"
#include "command.h"
#include "memory.h"
+#include "network.h"
#include "filter.h"
#include "vtysh/vtysh.h"
#include "vtysh/vtysh_daemons.h"
@@ -69,8 +70,15 @@ struct vtysh_client {
int flag;
char path[MAXPATHLEN];
struct vtysh_client *next;
+
+ struct thread *log_reader;
+ int log_fd;
+ uint32_t lost_msgs;
};
+static bool stderr_tty;
+static bool stderr_stdout_same;
+
/* Some utility functions for working on vtysh-specific vty tasks */
static FILE *vty_open_pager(struct vty *vty)
@@ -126,26 +134,27 @@ static void vtysh_pager_envdef(bool fallback)
/* --- */
struct vtysh_client vtysh_client[] = {
- {.fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .next = NULL},
- {.fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .next = NULL},
- {.fd = -1, .name = "ripngd", .flag = VTYSH_RIPNGD, .next = NULL},
- {.fd = -1, .name = "ospfd", .flag = VTYSH_OSPFD, .next = NULL},
- {.fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .next = NULL},
- {.fd = -1, .name = "ldpd", .flag = VTYSH_LDPD, .next = NULL},
- {.fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .next = NULL},
- {.fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .next = NULL},
- {.fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .next = NULL},
- {.fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .next = NULL},
- {.fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL},
- {.fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .next = NULL},
- {.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
- {.fd = -1, .name = "fabricd", .flag = VTYSH_FABRICD, .next = NULL},
- {.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
- {.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
- {.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
- {.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
- {.fd = -1, .name = "vrrpd", .flag = VTYSH_VRRPD, .next = NULL},
- {.fd = -1, .name = "pathd", .flag = VTYSH_PATHD, .next = NULL},
+ {.name = "zebra", .flag = VTYSH_ZEBRA},
+ {.name = "ripd", .flag = VTYSH_RIPD},
+ {.name = "ripngd", .flag = VTYSH_RIPNGD},
+ {.name = "ospfd", .flag = VTYSH_OSPFD},
+ {.name = "ospf6d", .flag = VTYSH_OSPF6D},
+ {.name = "ldpd", .flag = VTYSH_LDPD},
+ {.name = "bgpd", .flag = VTYSH_BGPD},
+ {.name = "isisd", .flag = VTYSH_ISISD},
+ {.name = "pimd", .flag = VTYSH_PIMD},
+ {.name = "nhrpd", .flag = VTYSH_NHRPD},
+ {.name = "eigrpd", .flag = VTYSH_EIGRPD},
+ {.name = "babeld", .flag = VTYSH_BABELD},
+ {.name = "sharpd", .flag = VTYSH_SHARPD},
+ {.name = "fabricd", .flag = VTYSH_FABRICD},
+ {.name = "watchfrr", .flag = VTYSH_WATCHFRR},
+ {.name = "pbrd", .flag = VTYSH_PBRD},
+ {.name = "staticd", .flag = VTYSH_STATICD},
+ {.name = "bfdd", .flag = VTYSH_BFDD},
+ {.name = "vrrpd", .flag = VTYSH_VRRPD},
+ {.name = "pathd", .flag = VTYSH_PATHD},
+ {.name = "pim6d", .flag = VTYSH_PIM6D},
};
/* Searches for client by name, returns index */
@@ -181,6 +190,53 @@ static void vclient_close(struct vtysh_client *vclient)
}
}
+static ssize_t vtysh_client_receive(struct vtysh_client *vclient, char *buf,
+ size_t bufsz, int *pass_fd)
+{
+ struct iovec iov[1] = {
+ {
+ .iov_base = buf,
+ .iov_len = bufsz,
+ },
+ };
+ union {
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr align;
+ } u;
+ struct msghdr mh = {
+ .msg_iov = iov,
+ .msg_iovlen = array_size(iov),
+ .msg_control = u.buf,
+ .msg_controllen = sizeof(u.buf),
+ };
+ struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
+ ssize_t ret;
+
+ cmh->cmsg_level = SOL_SOCKET;
+ cmh->cmsg_type = SCM_RIGHTS;
+ cmh->cmsg_len = CMSG_LEN(sizeof(int));
+ memset(CMSG_DATA(cmh), -1, sizeof(int));
+
+ do {
+ ret = recvmsg(vclient->fd, &mh, 0);
+ if (ret >= 0 || (errno != EINTR && errno != EAGAIN))
+ break;
+ } while (true);
+
+ if (cmh->cmsg_len == CMSG_LEN(sizeof(int))) {
+ int fd;
+
+ memcpy(&fd, CMSG_DATA(cmh), sizeof(int));
+ if (fd != -1) {
+ if (pass_fd)
+ *pass_fd = fd;
+ else
+ close(fd);
+ }
+ }
+ return ret;
+}
+
/*
* Send a CLI command to a client and read the response.
*
@@ -204,7 +260,8 @@ static void vclient_close(struct vtysh_client *vclient)
* a status code
*/
static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
- void (*callback)(void *, const char *), void *cbarg)
+ void (*callback)(void *, const char *), void *cbarg,
+ int *pass_fd)
{
int ret;
char stackbuf[4096];
@@ -238,8 +295,10 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
bufvalid = buf;
do {
- ssize_t nread =
- read(vclient->fd, bufvalid, buf + bufsz - bufvalid - 1);
+ ssize_t nread;
+
+ nread = vtysh_client_receive(
+ vclient, bufvalid, buf + bufsz - bufvalid - 1, pass_fd);
if (nread < 0 && (errno == EINTR || errno == EAGAIN))
continue;
@@ -381,7 +440,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
int correct_instance = 0, wrong_instance = 0;
for (client = head_client; client; client = client->next) {
- rc = vtysh_client_run(client, line, callback, cbarg);
+ rc = vtysh_client_run(client, line, callback, cbarg, NULL);
if (rc == CMD_NOT_MY_INSTANCE) {
wrong_instance++;
continue;
@@ -1578,6 +1637,8 @@ static int vtysh_end(void)
return CMD_SUCCESS;
}
+#include "vtysh/vtysh_clippy.c"
+
DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
"End current mode and change to enable mode\n")
{
@@ -2714,6 +2775,16 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc,
return ret;
}
+DEFUN (vtysh_show_thread_timer,
+ vtysh_show_thread_timer_cmd,
+ "show thread timers",
+ SHOW_STR
+ "Thread information\n"
+ "Show all timers and how long they have in the system\n")
+{
+ return show_per_daemon(vty, argv, argc, "Thread timers for %s:\n");
+}
+
DEFUN (vtysh_show_poll,
vtysh_show_poll_cmd,
"show thread poll",
@@ -3460,6 +3531,292 @@ DEFUN (vtysh_show_daemons,
return CMD_SUCCESS;
}
+struct visual_prio {
+ /* 4 characters for nice alignment */
+ const char *label;
+
+ int c256_background;
+ int c256_formatarg;
+};
+
+/* clang-format off */
+struct visual_prio visual_prios[] = {
+ [LOG_EMERG] = {
+ .label = "\e[31;1mEMRG",
+ .c256_background = 53,
+ .c256_formatarg = 225,
+ },
+ [LOG_ALERT] = {
+ .label = "\e[31;1mALRT",
+ .c256_background = 53,
+ .c256_formatarg = 225,
+ },
+ [LOG_CRIT] = {
+ .label = "\e[31;1mCRIT",
+ .c256_background = 53,
+ .c256_formatarg = 225,
+ },
+ [LOG_ERR] = {
+ .label = "\e[38;5;202mERR!",
+ .c256_background = 52,
+ .c256_formatarg = 224,
+ },
+ [LOG_WARNING] = {
+ .label = "\e[38;5;222mWARN",
+ .c256_background = 58,
+ .c256_formatarg = 230,
+ },
+ [LOG_NOTICE] = {
+ .label = "NTFY",
+ .c256_background = 234,
+ .c256_formatarg = 195,
+ },
+ [LOG_INFO] = {
+ .label = "\e[38;5;192mINFO",
+ .c256_background = 236,
+ .c256_formatarg = 195,
+ },
+ [LOG_DEBUG] = {
+ .label = "\e[38;5;116mDEBG",
+ .c256_background = 238,
+ .c256_formatarg = 195,
+ },
+};
+/* clang-format on */
+
+static void vtysh_log_print(struct vtysh_client *vclient,
+ struct zlog_live_hdr *hdr, const char *text)
+{
+ size_t textlen = hdr->textlen, textpos = 0;
+ time_t ts = hdr->ts_sec;
+ struct visual_prio *vis;
+ struct tm tm;
+ char ts_buf[32];
+
+ if (hdr->prio >= array_size(visual_prios))
+ vis = &visual_prios[LOG_CRIT];
+ else
+ vis = &visual_prios[hdr->prio];
+
+ localtime_r(&ts, &tm);
+ strftime(ts_buf, sizeof(ts_buf), "%Y-%m-%d %H:%M:%S", &tm);
+
+ if (!stderr_tty) {
+ const char *label = vis->label + strlen(vis->label) - 4;
+
+ fprintf(stderr, "%s.%03u [%s] %s: %.*s\n", ts_buf,
+ hdr->ts_nsec / 1000000U, label, vclient->name,
+ (int)textlen, text);
+ return;
+ }
+
+ fprintf(stderr,
+ "\e[48;5;%dm\e[38;5;247m%s.%03u [%s\e[38;5;247m] \e[38;5;255m%s\e[38;5;247m: \e[38;5;251m",
+ vis->c256_background, ts_buf, hdr->ts_nsec / 1000000U,
+ vis->label, vclient->name);
+
+ for (size_t fmtpos = 0; fmtpos < hdr->n_argpos; fmtpos++) {
+ struct fmt_outpos *fmt = &hdr->argpos[fmtpos];
+
+ if (fmt->off_start < textpos || fmt->off_end < fmt->off_start ||
+ fmt->off_end > textlen)
+ continue;
+
+ while (fmt->off_end > fmt->off_start &&
+ text[fmt->off_end - 1] == ' ')
+ fmt->off_end--;
+
+ fprintf(stderr, "%.*s\e[38;5;%dm%.*s\e[38;5;251m",
+ (int)(fmt->off_start - textpos), text + textpos,
+ vis->c256_formatarg,
+ (int)(fmt->off_end - fmt->off_start),
+ text + fmt->off_start);
+ textpos = fmt->off_end;
+ }
+ fprintf(stderr, "%.*s\033[K\033[m\n", (int)(textlen - textpos),
+ text + textpos);
+}
+
+static void vtysh_log_read(struct thread *thread)
+{
+ struct vtysh_client *vclient = THREAD_ARG(thread);
+ struct {
+ struct zlog_live_hdr hdr;
+ char text[4096];
+ } buf;
+ const char *text;
+ ssize_t ret;
+
+ thread_add_read(master, vtysh_log_read, vclient, vclient->log_fd,
+ &vclient->log_reader);
+
+ ret = recv(vclient->log_fd, &buf, sizeof(buf), 0);
+
+ if (ret < 0 && ERRNO_IO_RETRY(errno))
+ return;
+
+ if (stderr_stdout_same) {
+#ifdef HAVE_RL_CLEAR_VISIBLE_LINE
+ rl_clear_visible_line();
+#else
+ puts("\r");
+#endif
+ fflush(stdout);
+ }
+
+ if (ret <= 0) {
+ struct timespec ts;
+
+ buf.text[0] = '\0'; /* coverity */
+
+ if (ret != 0)
+ snprintfrr(buf.text, sizeof(buf.text),
+ "log monitor connection error: %m");
+ else
+ snprintfrr(
+ buf.text, sizeof(buf.text),
+ "log monitor connection closed unexpectedly");
+ buf.hdr.textlen = strlen(buf.text);
+
+ THREAD_OFF(vclient->log_reader);
+ close(vclient->log_fd);
+ vclient->log_fd = -1;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ buf.hdr.ts_sec = ts.tv_sec;
+ buf.hdr.ts_nsec = ts.tv_nsec;
+ buf.hdr.prio = LOG_ERR;
+ buf.hdr.flags = 0;
+ buf.hdr.texthdrlen = 0;
+ buf.hdr.n_argpos = 0;
+ } else {
+ int32_t lost_msgs = buf.hdr.lost_msgs - vclient->lost_msgs;
+
+ if (lost_msgs > 0) {
+ vclient->lost_msgs = buf.hdr.lost_msgs;
+ fprintf(stderr,
+ "%d log messages from %s lost (vtysh reading too slowly)\n",
+ lost_msgs, vclient->name);
+ }
+ }
+
+ text = buf.text + sizeof(buf.hdr.argpos[0]) * buf.hdr.n_argpos;
+ vtysh_log_print(vclient, &buf.hdr, text);
+
+ if (stderr_stdout_same)
+ rl_forced_update_display();
+
+ return;
+}
+
+#ifdef CLIPPY
+/* clippy/clidef can't process the DEFPY below without some value for this */
+#define DAEMONS_LIST "daemon"
+#endif
+
+DEFPY (vtysh_terminal_monitor,
+ vtysh_terminal_monitor_cmd,
+ "terminal monitor ["DAEMONS_LIST"]$daemon",
+ "Set terminal line parameters\n"
+ "Receive log messages to active VTY session\n"
+ DAEMONS_STR)
+{
+ static const char line[] = "terminal monitor\n";
+ int ret_all = CMD_SUCCESS, ret, fd;
+ size_t i, ok = 0;
+
+ for (i = 0; i < array_size(vtysh_client); i++) {
+ struct vtysh_client *vclient = &vtysh_client[i];
+
+ if (daemon && strcmp(vclient->name, daemon))
+ continue;
+
+ for (; vclient; vclient = vclient->next) {
+ if (vclient->log_fd != -1) {
+ vty_out(vty, "%% %s: already monitoring logs\n",
+ vclient->name);
+ ok++;
+ continue;
+ }
+
+ fd = -1;
+ ret = vtysh_client_run(vclient, line, NULL, NULL, &fd);
+ if (fd != -1) {
+ set_nonblocking(fd);
+ vclient->log_fd = fd;
+ thread_add_read(master, vtysh_log_read, vclient,
+ vclient->log_fd,
+ &vclient->log_reader);
+ }
+ if (ret != CMD_SUCCESS) {
+ vty_out(vty, "%% failed to enable logs on %s\n",
+ vclient->name);
+ ret_all = CMD_WARNING;
+ } else
+ ok++;
+ }
+ }
+
+ if (!ok && ret_all == CMD_SUCCESS) {
+ vty_out(vty,
+ "%% command had no effect, relevant daemons not connected?\n");
+ ret_all = CMD_WARNING;
+ }
+ return ret_all;
+}
+
+DEFPY (no_vtysh_terminal_monitor,
+ no_vtysh_terminal_monitor_cmd,
+ "no terminal monitor ["DAEMONS_LIST"]$daemon",
+ NO_STR
+ "Set terminal line parameters\n"
+ "Receive log messages to active VTY session\n"
+ DAEMONS_STR)
+{
+ static const char line[] = "no terminal monitor\n";
+ int ret_all = CMD_SUCCESS, ret;
+ size_t i, ok = 0;
+
+ for (i = 0; i < array_size(vtysh_client); i++) {
+ struct vtysh_client *vclient = &vtysh_client[i];
+
+ if (daemon && strcmp(vclient->name, daemon))
+ continue;
+
+ for (; vclient; vclient = vclient->next) {
+ /* run this even if log_fd == -1, in case something
+ * got desync'd
+ */
+ ret = vtysh_client_run(vclient, line, NULL, NULL, NULL);
+ if (ret != CMD_SUCCESS) {
+ vty_out(vty,
+ "%% failed to disable logs on %s\n",
+ vclient->name);
+ ret_all = CMD_WARNING;
+ } else
+ ok++;
+
+ /* with this being a datagram socket, we can't expect
+ * a close notification...
+ */
+ if (vclient->log_fd != -1) {
+ THREAD_OFF(vclient->log_reader);
+
+ close(vclient->log_fd);
+ vclient->log_fd = -1;
+ }
+ }
+ }
+
+ if (!ok && ret_all == CMD_SUCCESS) {
+ vty_out(vty,
+ "%% command had no effect, relevant daemons not connected?\n");
+ ret_all = CMD_WARNING;
+ }
+ return ret_all;
+}
+
+
/* Execute command in child process. */
static void execute_command(const char *command, int argc, const char *arg1,
const char *arg2)
@@ -3967,8 +4324,21 @@ void vtysh_uninit(void)
void vtysh_init_vty(void)
{
+ struct stat st_out, st_err;
+
cmd_defer_tree(true);
+ for (size_t i = 0; i < array_size(vtysh_client); i++) {
+ vtysh_client[i].fd = -1;
+ vtysh_client[i].log_fd = -1;
+ }
+
+ stderr_tty = isatty(STDERR_FILENO);
+
+ if (fstat(STDOUT_FILENO, &st_out) || fstat(STDERR_FILENO, &st_err) ||
+ (st_out.st_dev == st_err.st_dev && st_out.st_ino == st_err.st_ino))
+ stderr_stdout_same = true;
+
/* Make vty structure. */
vty = vty_new();
vty->type = VTY_SHELL;
@@ -4462,6 +4832,9 @@ void vtysh_init_vty(void)
install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd);
install_element(VIEW_NODE, &vtysh_show_daemons_cmd);
+ install_element(VIEW_NODE, &vtysh_terminal_monitor_cmd);
+ install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd);
+
install_element(VIEW_NODE, &vtysh_ping_cmd);
install_element(VIEW_NODE, &vtysh_ping_ip_cmd);
install_element(VIEW_NODE, &vtysh_traceroute_cmd);
@@ -4507,6 +4880,7 @@ void vtysh_init_vty(void)
install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
install_element(VIEW_NODE, &vtysh_show_thread_cmd);
install_element(VIEW_NODE, &vtysh_show_poll_cmd);
+ install_element(VIEW_NODE, &vtysh_show_thread_timer_cmd);
/* Logging */
install_element(VIEW_NODE, &vtysh_show_logging_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 66af248354..6053955be9 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -24,6 +24,10 @@
#include "memory.h"
DECLARE_MGROUP(MVTYSH);
+struct thread_master;
+
+extern struct thread_master *master;
+
#define VTYSH_ZEBRA 0x00001
#define VTYSH_RIPD 0x00002
#define VTYSH_RIPNGD 0x00004
@@ -44,6 +48,7 @@ DECLARE_MGROUP(MVTYSH);
#define VTYSH_FABRICD 0x20000
#define VTYSH_VRRPD 0x40000
#define VTYSH_PATHD 0x80000
+#define VTYSH_PIM6D 0x100000
#define VTYSH_WAS_ACTIVE (-2)
@@ -52,10 +57,10 @@ DECLARE_MGROUP(MVTYSH);
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
-#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
-#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
-#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
-#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
+#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
+#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
+#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD
+#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
#define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
/* Daemons who can process nexthop-group configs */
@@ -72,6 +77,7 @@ extern enum vtysh_write_integrated vtysh_write_integrated;
extern char frr_config[];
extern char vtydir[];
+extern bool vtysh_loop_exited;
void vtysh_init_vty(void);
void vtysh_uninit(void);
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index a4f27b61cb..04eb47feeb 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -84,9 +84,6 @@ static sigjmp_buf jmpbuf;
/* Flag for avoid recursive siglongjmp() call. */
static int jmpflag = 0;
-/* A static variable for holding the line. */
-static char *line_read;
-
/* Master of threads. */
struct thread_master *master;
@@ -208,23 +205,22 @@ struct option longopts[] = {
{"timestamp", no_argument, NULL, 't'},
{0}};
-/* Read a string, and return a pointer to it. Returns NULL on EOF. */
-static char *vtysh_rl_gets(void)
+bool vtysh_loop_exited;
+
+static void vtysh_rl_callback(char *line_read)
{
HIST_ENTRY *last;
- /* If the buffer has already been allocated, return the memory
- * to the free pool. */
- if (line_read) {
- free(line_read);
- line_read = NULL;
- }
- /* Get a line from the user. Change prompt according to node. XXX. */
- line_read = readline(vtysh_prompt());
+ rl_callback_handler_remove();
+
+ if (!line_read) {
+ vtysh_loop_exited = true;
+ return;
+ }
/* If the line has any text in it, save it on the history. But only if
* last command in history isn't the same one. */
- if (line_read && *line_read) {
+ if (*line_read) {
using_history();
last = previous_history();
if (!last || strcmp(last->line, line_read) != 0) {
@@ -233,7 +229,39 @@ static char *vtysh_rl_gets(void)
}
}
- return (line_read);
+ vtysh_execute(line_read);
+
+ if (!vtysh_loop_exited)
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+}
+
+static struct thread *vtysh_rl_read_thread;
+
+static void vtysh_rl_read(struct thread *thread)
+{
+ thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+ &vtysh_rl_read_thread);
+ rl_callback_read_char();
+}
+
+/* Read a string, and return a pointer to it. Returns NULL on EOF. */
+static void vtysh_rl_run(void)
+{
+ struct thread thread;
+
+ master = thread_master_create(NULL);
+
+ rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+ thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+ &vtysh_rl_read_thread);
+
+ while (!vtysh_loop_exited && thread_fetch(master, &thread))
+ thread_call(&thread);
+
+ if (!vtysh_loop_exited)
+ rl_callback_handler_remove();
+
+ thread_master_free(master);
}
static void log_it(const char *line)
@@ -458,7 +486,6 @@ int main(int argc, char **argv, char **env)
}
/* Initialize user input buffer. */
- line_read = NULL;
setlinebuf(stdout);
/* Signal and others. */
@@ -730,8 +757,7 @@ int main(int argc, char **argv, char **env)
jmpflag = 1;
/* Main command loop. */
- while (vtysh_rl_gets())
- vtysh_execute(line_read);
+ vtysh_rl_run();
vtysh_uninit();
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/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 8c8004190b..4cd2bef307 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -1232,7 +1232,8 @@ static void fpm_process_queue(struct thread *t)
* the output data in the STREAM_WRITEABLE
* check above, so we can ignore the return
*/
- (void)fpm_nl_enqueue(fnc, ctx);
+ if (fnc->socket != -1)
+ (void)fpm_nl_enqueue(fnc, ctx);
/* Account the processed entries. */
processed_contexts++;
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 739edda3b5..e3506ecb14 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 c30f43456c..a76f8741e0 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -72,8 +72,6 @@ static void if_zebra_speed_update(struct thread *thread)
bool changed = false;
int error = 0;
- zif->speed_update = NULL;
-
new_speed = kernel_get_speed(ifp, &error);
/* error may indicate vrf not available or
@@ -92,8 +90,27 @@ static void if_zebra_speed_update(struct thread *thread)
}
if (changed || new_speed == UINT32_MAX) {
- thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 5,
- &zif->speed_update);
+#define SPEED_UPDATE_SLEEP_TIME 5
+#define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME)
+ /*
+ * Some interfaces never actually have an associated speed
+ * with them ( I am looking at you bridges ).
+ * So instead of iterating forever, let's give the
+ * system 4 minutes to try to figure out the speed
+ * if after that it it's probably never going to become
+ * useful.
+ * Since I don't know all the wonderful types of interfaces
+ * that may come into existence in the future I am going
+ * to not update the system to keep track of that. This
+ * is far simpler to just stop trying after 4 minutes
+ */
+ if (new_speed == UINT32_MAX &&
+ zif->speed_update_count == SPEED_UPDATE_COUNT_MAX)
+ return;
+
+ zif->speed_update_count++;
+ thread_add_timer(zrouter.master, if_zebra_speed_update, ifp,
+ SPEED_UPDATE_SLEEP_TIME, &zif->speed_update);
thread_ignore_late_timer(zif->speed_update);
}
}
@@ -196,6 +213,7 @@ static int if_zebra_new_hook(struct interface *ifp)
* of seconds and ask again. Hopefully it's all settled
* down upon startup.
*/
+ zebra_if->speed_update_count = 0;
thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15,
&zebra_if->speed_update);
thread_ignore_late_timer(zebra_if->speed_update);
@@ -206,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)
@@ -499,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);
}
}
@@ -1027,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;
@@ -1059,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
@@ -2760,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 85617961af..315a3170d8 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -412,6 +412,7 @@ struct zebra_if {
ifindex_t link_ifindex;
struct interface *link;
+ uint8_t speed_update_count;
struct thread *speed_update;
/*
@@ -485,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/kernel_netlink.c b/zebra/kernel_netlink.c
index 031ac0733c..d84b0c1325 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -155,7 +155,6 @@ static const struct message rttype_str[] = {{RTN_UNSPEC, "none"},
{0}};
extern struct thread_master *master;
-extern uint32_t nl_rcvbufsize;
extern struct zebra_privs_t zserv_privs;
@@ -261,12 +260,11 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize)
/* Try force option (linux >= 2.6.14) and fall back to normal set */
frr_with_privs(&zserv_privs) {
ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE,
- &nl_rcvbufsize,
- sizeof(nl_rcvbufsize));
+ &rcvbufsize, sizeof(rcvbufsize));
}
if (ret < 0)
- ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF,
- &nl_rcvbufsize, sizeof(nl_rcvbufsize));
+ ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+ sizeof(rcvbufsize));
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET,
"Can't set %s receive buffer size: %s", nl->name,
@@ -1732,11 +1730,11 @@ void kernel_init(struct zebra_ns *zns)
errno);
/* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize) {
- netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize);
+ if (rcvbufsize) {
+ netlink_recvbuf(&zns->netlink, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_cmd, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize);
}
/* Set filter for inbound sockets, to exclude events we've generated
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 53b7a21d32..ce1f17111b 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1011,6 +1011,8 @@ void rtm_read(struct rt_msghdr *rtm)
ifindex_t ifindex = 0;
afi_t afi;
char fbuf[64];
+ int32_t proto = ZEBRA_ROUTE_KERNEL;
+ uint8_t distance = 0;
zebra_flags = 0;
@@ -1042,8 +1044,11 @@ void rtm_read(struct rt_msghdr *rtm)
if (!(flags & RTF_GATEWAY))
return;
- if (flags & RTF_PROTO1)
+ if (flags & RTF_PROTO1) {
SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
+ proto = ZEBRA_ROUTE_STATIC;
+ distance = 255;
+ }
memset(&nh, 0, sizeof(nh));
@@ -1111,13 +1116,13 @@ void rtm_read(struct rt_msghdr *rtm)
0, true);
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
- rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
- zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN,
- 0, 0, 0, 0, false);
+ rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, zebra_flags,
+ &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, 0, distance, 0,
+ false);
else
- rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
- 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
- 0, true);
+ rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0,
+ zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
+ distance, true);
}
/* Interface function for the kernel routing table updates. Support
@@ -1408,6 +1413,9 @@ static void kernel_read(struct thread *thread)
/* Make routing socket. */
static void routing_socket(struct zebra_ns *zns)
{
+ uint32_t default_rcvbuf;
+ socklen_t optlen;
+
frr_with_privs(&zserv_privs) {
routing_sock = ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id);
@@ -1442,6 +1450,23 @@ static void routing_socket(struct zebra_ns *zns)
/*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
zlog_warn ("Can't set O_NONBLOCK to routing socket");*/
+ /*
+ * Attempt to set a more useful receive buffer size
+ */
+ optlen = sizeof(default_rcvbuf);
+ if (getsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
+ &optlen) == -1)
+ flog_err_sys(EC_LIB_SOCKET,
+ "routing_sock sockopt SOL_SOCKET SO_RCVBUF");
+ else {
+ for (; rcvbufsize > default_rcvbuf &&
+ setsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF,
+ &rcvbufsize, sizeof(rcvbufsize)) == -1 &&
+ errno == ENOBUFS;
+ rcvbufsize /= 2)
+ ;
+ }
+
/* kernel_read needs rewrite. */
thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL);
}
diff --git a/zebra/main.c b/zebra/main.c
index 9deafb532e..7ef30d1d49 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -78,10 +78,12 @@ int graceful_restart;
bool v6_rr_semantics = false;
+/* Receive buffer size for kernel control sockets */
#ifdef HAVE_NETLINK
-/* Receive buffer size for netlink socket */
-uint32_t nl_rcvbufsize = 4194304;
-#endif /* HAVE_NETLINK */
+uint32_t rcvbufsize = 4194304;
+#else
+uint32_t rcvbufsize = 128 * 1024;
+#endif
#define OPTION_V6_RR_SEMANTICS 2000
#define OPTION_ASIC_OFFLOAD 2001
@@ -294,9 +296,9 @@ int main(int argc, char **argv)
frr_preinit(&zebra_di, argc, argv);
frr_opt_add(
- "baz:e:rK:"
+ "baz:e:rK:s:"
#ifdef HAVE_NETLINK
- "s:n"
+ "n"
#endif
,
longopts,
@@ -308,9 +310,11 @@ int main(int argc, char **argv)
" -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n"
" -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n"
#ifdef HAVE_NETLINK
- " -n, --vrfwnetns Use NetNS as VRF backend\n"
" -s, --nl-bufsize Set netlink receive buffer size\n"
+ " -n, --vrfwnetns Use NetNS as VRF backend\n"
" --v6-rr-semantics Use v6 RR semantics\n"
+#else
+ " -s, Set kernel socket receive buffer size\n"
#endif /* HAVE_NETLINK */
);
@@ -359,10 +363,10 @@ int main(int argc, char **argv)
case 'K':
graceful_restart = atoi(optarg);
break;
-#ifdef HAVE_NETLINK
case 's':
- nl_rcvbufsize = atoi(optarg);
+ rcvbufsize = atoi(optarg);
break;
+#ifdef HAVE_NETLINK
case 'n':
vrf_configure_backend(VRF_BACKEND_NETNS);
break;
diff --git a/zebra/rib.h b/zebra/rib.h
index c6f3528cec..c8abfaf023 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -54,8 +54,7 @@ struct rnh {
#define ZEBRA_NHT_CONNECTED 0x1
#define ZEBRA_NHT_DELETED 0x2
-#define ZEBRA_NHT_EXACT_MATCH 0x4
-#define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x8
+#define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x4
/* VRF identifier. */
vrf_id_t vrf_id;
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_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index f557e66384..ed224151ba 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -1311,14 +1311,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
if (!n) {
/* New neighbor - create */
n = zebra_evpn_neigh_add(zevpn, ip, macaddr, zmac, 0);
- if (!n) {
- flog_err(
- EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u",
- ip, macaddr, ifp->name, ifp->ifindex,
- zevpn->vni);
- return -1;
- }
+
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
n->ifindex = ifp->ifindex;
@@ -2070,14 +2063,6 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
if (!n) {
n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr,
mac, 0);
- if (!n) {
- zlog_warn(
- "Failed to add Neigh %pIA MAC %pEA VNI %u Remote VTEP %pI4",
- ipaddr, &mac->macaddr, zevpn->vni,
- &vtep_ip);
- return;
- }
-
} else {
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
@@ -2182,17 +2167,8 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp,
assert(mac);
n = zebra_evpn_neigh_lookup(zevpn, ip);
- if (!n) {
+ if (!n)
n = zebra_evpn_neigh_add(zevpn, ip, &mac->macaddr, mac, 0);
- if (!n) {
- flog_err(
- EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u",
- ip, &mac->macaddr,
- ifp->name, ifp->ifindex, zevpn->vni);
- return -1;
- }
- }
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
@@ -2203,7 +2179,6 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp,
/* Only advertise in BGP if the knob is enabled */
if (advertise_gw_macip_enabled(zevpn)) {
- SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
/* Set Router flag (R-bit) */
if (ip->ipa_type == IPADDR_V6)
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 858309f3e7..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);
@@ -2475,7 +2478,7 @@ skip_check:
memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
- zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
+ zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(" %s: zvrf is NULL", __func__);
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);
}
}
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index af159da3cc..e376d4b2af 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -116,6 +116,7 @@ static const struct {
[ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5},
[ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7},
[ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7},
+ [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, 7},
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
@@ -4386,9 +4387,8 @@ static void check_route_info(void)
* ZEBRA_ROUTE_ALL is also ignored.
*/
for (int i = 0; i < len; i++) {
- if (i == ZEBRA_ROUTE_SYSTEM || i == ZEBRA_ROUTE_ALL)
- continue;
- assert(route_info[i].key);
+ assert(route_info[i].key >= ZEBRA_ROUTE_SYSTEM &&
+ route_info[i].key < ZEBRA_ROUTE_MAX);
assert(route_info[i].meta_q_map < MQ_SIZE);
}
}
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 8ca25359be..4d5336120d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1169,15 +1169,17 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
SET_FLAG(message, ZAPI_MESSAGE_SRTE);
stream_putl(s, message);
+ /*
+ * Put what we were told to match against
+ */
stream_putw(s, rnh->safi);
stream_putw(s, rn->p.family);
+ stream_putc(s, rn->p.prefixlen);
switch (rn->p.family) {
case AF_INET:
- stream_putc(s, rn->p.prefixlen);
stream_put_in_addr(s, &rn->p.u.prefix4);
break;
case AF_INET6:
- stream_putc(s, rn->p.prefixlen);
stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
break;
default:
@@ -1186,6 +1188,26 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
__func__, rn->p.family);
goto failure;
}
+
+ /*
+ * What we matched against
+ */
+ stream_putw(s, rnh->resolved_route.family);
+ stream_putc(s, rnh->resolved_route.prefixlen);
+ switch (rnh->resolved_route.family) {
+ case AF_INET:
+ stream_put_in_addr(s, &rnh->resolved_route.u.prefix4);
+ break;
+ case AF_INET6:
+ stream_put(s, &rnh->resolved_route.u.prefix6, IPV6_MAX_BYTELEN);
+ break;
+ default:
+ flog_err(EC_ZEBRA_RNH_UNKNOWN_FAMILY,
+ "%s: Unknown family (%d) notification attempted",
+ __func__, rn->p.family);
+ goto failure;
+ }
+
if (srte_color)
stream_putl(s, srte_color);
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index dafe925c26..63a61d5293 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -216,6 +216,7 @@ struct zebra_router {
#define GRACEFUL_RESTART_TIME 60
extern struct zebra_router zrouter;
+extern uint32_t rcvbufsize;
extern void zebra_router_init(bool asic_offload, bool notify_on_ack);
extern void zebra_router_cleanup(void);
diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c
index 7933ef66b1..c0f18dd091 100644
--- a/zebra/zebra_srte.c
+++ b/zebra/zebra_srte.c
@@ -117,16 +117,28 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
stream_putl(s, message);
stream_putw(s, SAFI_UNICAST);
+ /*
+ * The prefix is copied twice because the ZEBRA_NEXTHOP_UPDATE
+ * code was modified to send back both the matched against
+ * as well as the actual matched. There does not appear to
+ * be an equivalent here so just send the same thing twice.
+ */
switch (policy->endpoint.ipa_type) {
case IPADDR_V4:
stream_putw(s, AF_INET);
stream_putc(s, IPV4_MAX_BITLEN);
stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
+ stream_putw(s, AF_INET);
+ stream_putc(s, IPV4_MAX_BITLEN);
+ stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
break;
case IPADDR_V6:
stream_putw(s, AF_INET6);
stream_putc(s, IPV6_MAX_BITLEN);
stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
+ stream_putw(s, AF_INET6);
+ stream_putc(s, IPV6_MAX_BITLEN);
+ stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
break;
default:
flog_warn(EC_LIB_DEVELOPMENT,
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index bb16232118..cc1ba3d8f8 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -3976,6 +3976,7 @@ DEFUN (show_zebra,
ttable_rowseps(table, 0, BOTTOM, true, '-');
ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get());
+ ttable_add_row(table, "ECMP Maximum|%d", zrouter.multipath_num);
ttable_add_row(table, "v4 Forwarding|%s", ipforward() ? "On" : "Off");
ttable_add_row(table, "v6 Forwarding|%s",
ipforward_ipv6() ? "On" : "Off");
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index b6da445e38..676b92d429 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -826,8 +826,7 @@ static int zvni_map_to_svi_ns(struct ns *ns,
struct interface **p_ifp = (struct interface **)_p_ifp;
struct zebra_if *zif;
- if (!in_param)
- return NS_WALK_STOP;
+ assert(in_param && p_ifp);
/* TODO: Optimize with a hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
@@ -842,8 +841,7 @@ static int zvni_map_to_svi_ns(struct ns *ns,
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
if (vl->vid == in_param->vid) {
- if (p_ifp)
- *p_ifp = tmp_if;
+ *p_ifp = tmp_if;
return NS_WALK_STOP;
}
}
@@ -2124,13 +2122,6 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
return 0;
zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- flog_err(EC_ZEBRA_VNI_ADD_FAILED,
- "Adding L2-VNI - Failed to add VNI hash, VNI %u",
- vni);
-
- return -1;
- }
/* Find bridge interface for the VNI */
vlan_if = zvni_map_to_svi(vxl->access_vlan,
@@ -5171,16 +5162,8 @@ int zebra_vxlan_if_add(struct interface *ifp)
/* Create or update EVPN hash. */
zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
+ if (!zevpn)
zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- flog_err(
- EC_ZEBRA_VNI_ADD_FAILED,
- "Failed to add EVPN hash, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
- }
if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {