summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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_evpn_vty.c28
-rw-r--r--bgpd/bgp_fsm.c12
-rw-r--r--bgpd/bgp_mpath.c14
-rw-r--r--bgpd/bgp_mplsvpn.c58
-rw-r--r--bgpd/bgp_mplsvpn.h1
-rw-r--r--bgpd/bgp_route.c216
-rw-r--r--bgpd/bgp_route.h2
-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.c19
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--bgpd/rfapi/rfapi_vty.c7
-rw-r--r--configure.ac11
-rw-r--r--doc/developer/cli.rst10
-rw-r--r--doc/developer/topotests.rst3
-rw-r--r--doc/developer/workflow.rst11
-rw-r--r--doc/user/basic.rst5
-rw-r--r--doc/user/vtysh.rst24
-rw-r--r--doc/user/zebra.rst8
-rw-r--r--include/linux/netconf.h30
-rw-r--r--include/subdir.am1
-rw-r--r--isisd/isis_nb_notifications.c16
-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/command.c4
-rw-r--r--lib/lib_errors.c6
-rw-r--r--lib/lib_errors.h1
-rw-r--r--lib/subdir.am4
-rw-r--r--lib/thread.c64
-rw-r--r--lib/vty.c171
-rw-r--r--lib/vty.h26
-rw-r--r--lib/yang_wrappers.c59
-rw-r--r--lib/yang_wrappers.h7
-rw-r--r--lib/zlog.c5
-rw-r--r--lib/zlog.h3
-rw-r--r--lib/zlog_live.c245
-rw-r--r--lib/zlog_live.h53
-rw-r--r--ospfd/ospf_vty.c4
-rw-r--r--pbrd/pbr_vty.c2
-rw-r--r--pimd/pim6_cmd.c231
-rw-r--r--pimd/pim6_cmd.h44
-rw-r--r--pimd/pim6_main.c11
-rw-r--r--pimd/pim6_stubs.c135
-rw-r--r--pimd/pim_addr.c3
-rw-r--r--pimd/pim_addr.h10
-rw-r--r--pimd/pim_bfd.c8
-rw-r--r--pimd/pim_bsm.c11
-rw-r--r--pimd/pim_cmd.c317
-rw-r--r--pimd/pim_cmd_common.c328
-rw-r--r--pimd/pim_cmd_common.h39
-rw-r--r--pimd/pim_iface.c50
-rw-r--r--pimd/pim_ifchannel.c9
-rw-r--r--pimd/pim_igmp.h27
-rw-r--r--pimd/pim_igmp_join.h6
-rw-r--r--pimd/pim_igmp_stats.h10
-rw-r--r--pimd/pim_igmpv3.h13
-rw-r--r--pimd/pim_jp_agg.c7
-rw-r--r--pimd/pim_mlag.h46
-rw-r--r--pimd/pim_mroute.c118
-rw-r--r--pimd/pim_mroute.h16
-rw-r--r--pimd/pim_msg.c2
-rw-r--r--pimd/pim_nb_config.c53
-rw-r--r--pimd/pim_nht.c198
-rw-r--r--pimd/pim_oil.c226
-rw-r--r--pimd/pim_oil.h57
-rw-r--r--pimd/pim_rp.c2
-rw-r--r--pimd/pim_rpf.c111
-rw-r--r--pimd/pim_rpf.h2
-rw-r--r--pimd/pim_ssm.c2
-rw-r--r--pimd/pim_static.c121
-rw-r--r--pimd/pim_static.h10
-rw-r--r--pimd/pim_upstream.c49
-rw-r--r--pimd/pim_upstream.h6
-rw-r--r--pimd/pim_vty.c284
-rw-r--r--pimd/pim_vty.h3
-rw-r--r--pimd/pim_zebra.c52
-rw-r--r--pimd/pim_zlookup.c44
-rw-r--r--pimd/pim_zlookup.h2
-rw-r--r--pimd/pimd.c4
-rw-r--r--pimd/subdir.am41
-rw-r--r--python/clidef.py62
-rw-r--r--sharpd/sharp_vty.c2
-rw-r--r--snapcraft/snapcraft.yaml.in1
-rw-r--r--staticd/static_main.c1
-rw-r--r--staticd/static_zebra.c18
-rw-r--r--tests/lib/subdir.am2
-rw-r--r--tests/lib/test_checksum.c70
-rw-r--r--tests/topotests/lib/topogen.py24
-rw-r--r--tests/topotests/lib/topotest.py42
-rw-r--r--tools/etc/frr/support_bundle_commands.conf1
-rwxr-xr-xvtysh/extract.pl.in6
-rw-r--r--vtysh/subdir.am4
-rw-r--r--vtysh/vtysh.c412
-rw-r--r--vtysh/vtysh.h14
-rw-r--r--vtysh/vtysh_main.c62
-rw-r--r--zebra/debug_nl.c93
-rw-r--r--zebra/dplane_fpm_nl.c25
-rw-r--r--zebra/if_netlink.c2
-rw-r--r--zebra/interface.c81
-rw-r--r--zebra/interface.h5
-rw-r--r--zebra/kernel_netlink.c65
-rw-r--r--zebra/kernel_socket.c39
-rw-r--r--zebra/main.c20
-rw-r--r--zebra/netconf_netlink.c175
-rw-r--r--zebra/netconf_netlink.h48
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/zebra_dplane.c190
-rw-r--r--zebra/zebra_dplane.h34
-rw-r--r--zebra/zebra_nhg.c3
-rw-r--r--zebra/zebra_rib.c10
-rw-r--r--zebra/zebra_router.h1
-rw-r--r--zebra/zebra_script.c2
-rw-r--r--zebra/zebra_vty.c2
120 files changed, 4321 insertions, 1515 deletions
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_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index caf0444850..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;
}
@@ -3865,19 +3867,19 @@ DEFUN (bgp_evpn_advertise_type5,
if (!(afi == AFI_IP || afi == AFI_IP6)) {
vty_out(vty,
- "%%only ipv4 or ipv6 address families are supported");
+ "%%only ipv4 or ipv6 address families are supported\n");
return CMD_WARNING;
}
if (safi != SAFI_UNICAST) {
vty_out(vty,
- "%%only ipv4 unicast or ipv6 unicast are supported");
+ "%%only ipv4 unicast or ipv6 unicast are supported\n");
return CMD_WARNING;
}
if ((oly != OVERLAY_INDEX_TYPE_NONE)
&& (oly != OVERLAY_INDEX_GATEWAY_IP)) {
- vty_out(vty, "%%Unknown overlay-index type specified");
+ vty_out(vty, "%%Unknown overlay-index type specified\n");
return CMD_WARNING;
}
@@ -4056,13 +4058,13 @@ DEFUN (no_bgp_evpn_advertise_type5,
if (!(afi == AFI_IP || afi == AFI_IP6)) {
vty_out(vty,
- "%%only ipv4 or ipv6 address families are supported");
+ "%%only ipv4 or ipv6 address families are supported\n");
return CMD_WARNING;
}
if (safi != SAFI_UNICAST) {
vty_out(vty,
- "%%only ipv4 unicast or ipv6 unicast are supported");
+ "%%only ipv4 unicast or ipv6 unicast are supported\n");
return CMD_WARNING;
}
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_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_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index eafc37f20c..32a1d9a152 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -520,7 +520,7 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
* else: try to allocate as auto-mode
*/
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct in6_addr *sid)
+ struct in6_addr *sid_locator)
{
struct listnode *node;
struct prefix_ipv6 *chunk;
@@ -528,10 +528,11 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
bool alloced = false;
int label = 0;
- if (!bgp || !sid)
+ if (!bgp || !sid_locator)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
+ *sid_locator = chunk->prefix;
sid_buf = chunk->prefix;
if (index != 0) {
label = index << 12;
@@ -556,7 +557,6 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
return 0;
sid_register(bgp, &sid_buf, bgp->srv6_locator_name);
- *sid = sid_buf;
return label;
}
@@ -564,7 +564,7 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
char buf[256];
- struct in6_addr *sid;
+ struct in6_addr *tovpn_sid, *tovpn_sid_locator;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
@@ -598,24 +598,33 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
return;
}
- sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ tovpn_sid_locator =
+ XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
tovpn_sid_transpose_label =
- alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
+ alloc_new_sid(bgp_vpn, tovpn_sid_index, tovpn_sid_locator);
if (tovpn_sid_transpose_label == 0) {
zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
return;
}
+ tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ *tovpn_sid = *tovpn_sid_locator;
+ transpose_sid(tovpn_sid, tovpn_sid_transpose_label,
+ BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET,
+ BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH);
+
if (debug) {
- inet_ntop(AF_INET6, sid, buf, sizeof(buf));
+ inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf));
zlog_debug("%s: new sid %s allocated for vrf %s: afi %s",
__func__, buf, bgp_vrf->name_pretty,
afi2str(afi));
}
+
+ bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
+ bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
tovpn_sid_transpose_label;
- bgp_vrf->vpn_policy[afi].tovpn_sid = sid;
}
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
@@ -847,16 +856,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
new_attr->srv6_l3vpn->func_len;
extra->sid[0].arg_len =
new_attr->srv6_l3vpn->arg_len;
-
- if (new_attr->srv6_l3vpn->transposition_len
- != 0)
- transpose_sid(
- &extra->sid[0].sid,
- decode_label(label),
- new_attr->srv6_l3vpn
- ->transposition_offset,
- new_attr->srv6_l3vpn
- ->transposition_len);
+ extra->sid[0].transposition_len =
+ new_attr->srv6_l3vpn->transposition_len;
+ extra->sid[0].transposition_offset =
+ new_attr->srv6_l3vpn
+ ->transposition_offset;
} else if (new_attr->srv6_vpn)
setsids(bpi, &new_attr->srv6_vpn->sid,
num_sids);
@@ -951,14 +955,10 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
new_attr->srv6_l3vpn->loc_node_len;
extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len;
extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len;
-
- if (new_attr->srv6_l3vpn->transposition_len != 0)
- transpose_sid(&extra->sid[0].sid,
- decode_label(label),
- new_attr->srv6_l3vpn
- ->transposition_offset,
- new_attr->srv6_l3vpn
- ->transposition_len);
+ extra->sid[0].transposition_len =
+ new_attr->srv6_l3vpn->transposition_len;
+ extra->sid[0].transposition_offset =
+ new_attr->srv6_l3vpn->transposition_offset;
} else if (new_attr->srv6_vpn)
setsids(new, &new_attr->srv6_vpn->sid, num_sids);
} else
@@ -1235,7 +1235,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
static_attr.originator_id = bgp_vpn->router_id;
/* Set SID for SRv6 VPN */
- if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+ if (bgp_vrf->vpn_policy[afi].tovpn_sid_locator) {
encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
@@ -1255,8 +1255,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
static_attr.srv6_l3vpn->transposition_offset =
BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
memcpy(&static_attr.srv6_l3vpn->sid,
- bgp_vrf->vpn_policy[afi].tovpn_sid,
- sizeof(static_attr.srv6_l3vpn->sid));
+ bgp_vrf->vpn_policy[afi].tovpn_sid_locator,
+ sizeof(struct in6_addr));
}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index b0d586223f..5bf772fefe 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -21,6 +21,7 @@
#ifndef _QUAGGA_BGP_MPLSVPN_H
#define _QUAGGA_BGP_MPLSVPN_H
+#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_zebra.h"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index bd7031defe..ef8537f039 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;
@@ -4198,6 +4204,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
extra->sid[0].loc_node_len = 0;
extra->sid[0].func_len = 0;
extra->sid[0].arg_len = 0;
+ extra->sid[0].transposition_len = 0;
+ extra->sid[0].transposition_offset = 0;
if (attr->srv6_l3vpn->loc_block_len != 0) {
extra->sid[0].loc_block_len =
@@ -4208,21 +4216,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
attr->srv6_l3vpn->func_len;
extra->sid[0].arg_len =
attr->srv6_l3vpn->arg_len;
- }
-
- /*
- * draft-ietf-bess-srv6-services-07
- * The part of SRv6 SID may be encoded as MPLS
- * Label for the efficient packing.
- */
- if (attr->srv6_l3vpn->transposition_len != 0)
- transpose_sid(
- &extra->sid[0].sid,
- decode_label(label),
+ extra->sid[0].transposition_len =
attr->srv6_l3vpn
- ->transposition_offset,
+ ->transposition_len;
+ extra->sid[0].transposition_offset =
attr->srv6_l3vpn
- ->transposition_len);
+ ->transposition_offset;
+ }
}
} else if (attr->srv6_vpn) {
extra = bgp_path_info_extra_get(pi);
@@ -4419,17 +4419,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
attr->srv6_l3vpn->loc_node_len;
extra->sid[0].func_len = attr->srv6_l3vpn->func_len;
extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len;
-
- /*
- * draft-ietf-bess-srv6-services-07
- * The part of SRv6 SID may be encoded as MPLS Label for
- * the efficient packing.
- */
- if (attr->srv6_l3vpn->transposition_len != 0)
- transpose_sid(
- &extra->sid[0].sid, decode_label(label),
- attr->srv6_l3vpn->transposition_offset,
- attr->srv6_l3vpn->transposition_len);
+ extra->sid[0].transposition_len =
+ attr->srv6_l3vpn->transposition_len;
+ extra->sid[0].transposition_offset =
+ attr->srv6_l3vpn->transposition_offset;
} else if (attr->srv6_vpn) {
sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid);
extra->num_sids = 1;
@@ -5378,9 +5371,10 @@ 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;
if (!CHECK_FLAG(pi->flags,
@@ -5411,9 +5405,10 @@ 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))
+ bgp_attr_get_community(pi->attr) &&
+ !community_include(
+ bgp_attr_get_community(pi->attr),
+ COMMUNITY_NO_LLGR))
break;
if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE))
break;
@@ -7057,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))
@@ -7476,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.
*/
@@ -7598,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.
@@ -7718,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.
*/
@@ -7821,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.
@@ -10505,14 +10499,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);
}
}
@@ -10757,8 +10753,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]);
@@ -10896,6 +10894,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) {
@@ -10911,9 +10913,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(
@@ -11037,36 +11039,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) {
@@ -11484,44 +11481,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);
}
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index a8ec2dc907..743b369bfa 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -154,6 +154,8 @@ struct bgp_sid_info {
uint8_t loc_node_len;
uint8_t func_len;
uint8_t arg_len;
+ uint8_t transposition_len;
+ uint8_t transposition_offset;
};
/* Ancillary information to struct bgp_path_info,
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 5d1ae766e2..857462a601 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -1261,7 +1261,7 @@ DEFPY (show_rpki_prefix,
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
asn, &addr, prefix->prefixlen, &result)
!= PFX_SUCCESS) {
- vty_out(vty, "Prefix lookup failed");
+ vty_out(vty, "Prefix lookup failed\n");
return CMD_WARNING;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index afe4c7ae6f..d21e257cb5 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -8566,7 +8566,7 @@ DEFPY (af_sid_vpn_export,
if (!yes) {
/* implement me */
- vty_out(vty, "It's not implemented");
+ vty_out(vty, "It's not implemented\n");
return CMD_WARNING_CONFIG_FAILED;
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c295b06601..c0a9a38773 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1260,6 +1260,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
struct bgp_path_info *mpinfo_cp = &local_info;
route_tag_t tag;
mpls_label_t label;
+ struct bgp_sid_info *sid_info;
int nh_othervrf = 0;
bool is_evpn;
bool nh_updated = false;
@@ -1476,9 +1477,22 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid)
&& !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
- memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0].sid,
+ sid_info = &mpinfo->extra->sid[0];
+
+ memcpy(&api_nh->seg6_segs, &sid_info->sid,
sizeof(api_nh->seg6_segs));
+ if (sid_info->transposition_len != 0) {
+ if (!bgp_is_valid_label(
+ &mpinfo->extra->label[0]))
+ continue;
+
+ label = label_pton(&mpinfo->extra->label[0]);
+ transpose_sid(&api_nh->seg6_segs, label,
+ sid_info->transposition_offset,
+ sid_info->transposition_len);
+ }
+
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
}
@@ -1496,7 +1510,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.h b/bgpd/bgpd.h
index 926b0b033f..a9475f39a7 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -234,6 +234,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
+ struct in6_addr *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
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 bdddf4b846..170d16ca6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -765,7 +765,7 @@ AC_ARG_ENABLE([scripting],
AS_HELP_STRING([--enable-scripting], [Build with scripting support]))
AC_ARG_ENABLE([netlink-debug],
- AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages]))
+ AS_HELP_STRING([--disable-netlink-debug], [don't pretty print netlink debug messages]))
if test "$enable_netlink_debug" != "no" ; then
AC_DEFINE([NETLINK_DEBUG], [1], [Netlink extra debugging code])
@@ -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])
@@ -1526,6 +1528,13 @@ AC_CHECK_HEADERS([linux/mroute.h], [], [],[
#include <linux/types.h>
])
+AC_CHECK_HEADERS([linux/mroute6.h], [], [],[
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #define _LINUX_IN_H /* For Linux <= 2.6.25 */
+ #include <linux/types.h>
+])
+
m4_define([FRR_INCLUDES],
FRR_INCLUDES
[#ifdef HAVE_LINUX_MROUTE_H
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/topotests.rst b/doc/developer/topotests.rst
index fa1fd20067..b41181f4e9 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -1088,6 +1088,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/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..15c6088b7a 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/include/linux/netconf.h b/include/linux/netconf.h
new file mode 100644
index 0000000000..fac4edd553
--- /dev/null
+++ b/include/linux/netconf.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_NETCONF_H_
+#define _UAPI_LINUX_NETCONF_H_
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct netconfmsg {
+ __u8 ncm_family;
+};
+
+enum {
+ NETCONFA_UNSPEC,
+ NETCONFA_IFINDEX,
+ NETCONFA_FORWARDING,
+ NETCONFA_RP_FILTER,
+ NETCONFA_MC_FORWARDING,
+ NETCONFA_PROXY_NEIGH,
+ NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+ NETCONFA_INPUT,
+ NETCONFA_BC_FORWARDING,
+ __NETCONFA_MAX
+};
+#define NETCONFA_MAX (__NETCONFA_MAX - 1)
+#define NETCONFA_ALL -1
+
+#define NETCONFA_IFINDEX_ALL -1
+#define NETCONFA_IFINDEX_DEFAULT -2
+
+#endif /* _UAPI_LINUX_NETCONF_H_ */
diff --git a/include/subdir.am b/include/subdir.am
index 86129c4d68..a06a8e5649 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -5,6 +5,7 @@ noinst_HEADERS += \
include/linux/lwtunnel.h \
include/linux/mpls_iptunnel.h \
include/linux/neighbour.h \
+ include/linux/netconf.h \
include/linux/netlink.h \
include/linux/nexthop.h \
include/linux/rtnetlink.h \
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/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/command.c b/lib/command.c
index ebdbf162d1..1989668bf0 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2239,9 +2239,9 @@ DEFUN (banner_motd_file,
int cmd = cmd_banner_motd_file(filename);
if (cmd == CMD_ERR_NO_FILE)
- vty_out(vty, "%s does not exist", filename);
+ vty_out(vty, "%s does not exist\n", filename);
else if (cmd == CMD_WARNING_CONFIG_FAILED)
- vty_out(vty, "%s must be in %s", filename, SYSCONFDIR);
+ vty_out(vty, "%s must be in %s\n", filename, SYSCONFDIR);
return cmd;
}
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
index acc9a05c33..a658e4c295 100644
--- a/lib/lib_errors.c
+++ b/lib/lib_errors.c
@@ -69,6 +69,12 @@ static struct log_ref ferr_lib_warn[] = {
.suggestion = "Gather log data and open an Issue",
},
{
+ .code = EC_LIB_TIMER_TOO_LONG,
+ .title = "The Event subsystem has detected an internal timer that is scheduled to pop in greater than one year",
+ .description = "The Event subsystem has detected a timer being started that will pop in a timer that is greater than one year. This is a bug, please collect log data and open an issue.",
+ .suggestion = "Gather log data and open an Issue",
+ },
+ {
.code = EC_LIB_RMAP_RECURSION_LIMIT,
.title = "Reached the Route-Map Recursion Limit",
.description = "The Route-Map subsystem has detected a route-map depth of RMAP_RECURSION_LIMIT and has stopped processing",
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
index 64ac6c1ceb..91f206f74a 100644
--- a/lib/lib_errors.h
+++ b/lib/lib_errors.h
@@ -48,6 +48,7 @@ enum lib_log_refs {
EC_LIB_SLOW_THREAD_WALL,
EC_LIB_STARVE_THREAD,
EC_LIB_NO_THREAD,
+ EC_LIB_TIMER_TOO_LONG,
EC_LIB_RMAP_RECURSION_LIMIT,
EC_LIB_BACKUP_CONFIG,
EC_LIB_VRF_LENGTH,
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 58b8e206fa..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 ------------------------------------------------------------------ */
@@ -1052,6 +1089,12 @@ static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
if (thread_timer_list_first(&m->timer) == thread)
AWAKEN(m);
}
+#define ONEYEAR2SEC (60 * 60 * 24 * 365)
+ if (time_relative->tv_sec > ONEYEAR2SEC)
+ flog_err(
+ EC_LIB_TIMER_TOO_LONG,
+ "Timer: %pTHD is created with an expiration that is greater than 1 year",
+ thread);
}
@@ -1841,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/vty.c b/lib/vty.c
index a42b8c92be..6aa8a0bbb5 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -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);
@@ -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/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/zlog.c b/lib/zlog.c
index 1b0751559d..85606d2624 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -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..fbe0e5ee49
--- /dev/null
+++ b/lib/zlog_live.c
@@ -0,0 +1,245 @@
+/*
+ * 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"
+
+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;
+};
+
+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, arghdrlen;
+ struct zlog_msg *msg = msgs[i];
+ int prio = zlog_msg_prio(msg);
+
+ if (prio > zt->prio_min)
+ continue;
+
+ zlog_msg_args(msg, &arghdrlen, &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);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->prio = zlog_msg_prio(msg);
+ hdr->flags = 0;
+ hdr->textlen = textlen;
+ hdr->arghdrlen = arghdrlen;
+ hdr->n_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)
+ 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_MONOTONIC, &ts);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->prio = LOG_CRIT;
+ hdr->flags = 0;
+ hdr->textlen = len;
+ hdr->n_argpos = 0;
+
+ 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];
+ struct zlt_live *zte;
+ struct zlog_target *zt;
+
+ 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];
+
+ zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte));
+ zte = container_of(zt, struct zlt_live, zt);
+ cfg->target = zte;
+
+ zte->fd = sockets[0];
+ 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..c948baeab1
--- /dev/null
+++ b/lib/zlog_live.h
@@ -0,0 +1,53 @@
+/*
+ * 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 {
+ uint64_t ts_sec;
+ uint32_t ts_nsec;
+ uint32_t prio;
+ uint32_t flags;
+ uint32_t textlen;
+
+ uint32_t arghdrlen;
+ 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);
+
+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/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 0b7c3c6831..780521bfe4 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -9705,7 +9705,7 @@ DEFUN (ospf_max_metric_router_lsa_startup,
unsigned int seconds;
if (argc < 4) {
- vty_out(vty, "%% Must supply stub-router period");
+ vty_out(vty, "%% Must supply stub-router period\n");
return CMD_WARNING_CONFIG_FAILED;
}
@@ -9761,7 +9761,7 @@ DEFUN (ospf_max_metric_router_lsa_shutdown,
unsigned int seconds;
if (argc < 4) {
- vty_out(vty, "%% Must supply stub-router shutdown period");
+ vty_out(vty, "%% Must supply stub-router shutdown period\n");
return CMD_WARNING_CONFIG_FAILED;
}
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 21c1409e91..b5946bd40d 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -358,7 +358,7 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
#ifndef GNU_LINUX
- vty_out(vty, "pbr marks are not supported on this platform");
+ vty_out(vty, "pbr marks are not supported on this platform\n");
return CMD_WARNING_CONFIG_FAILED;
#endif
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
new file mode 100644
index 0000000000..06790d3d63
--- /dev/null
+++ b/pimd/pim6_cmd.c
@@ -0,0 +1,231 @@
+/*
+ * 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);
+}
+
+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);
+}
diff --git a/pimd/pim6_cmd.h b/pimd/pim6_cmd.h
new file mode 100644
index 0000000000..e49045a1b5
--- /dev/null
+++ b/pimd/pim6_cmd.h
@@ -0,0 +1,44 @@
+/*
+ * 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 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 3d8ebd0d86..c9e3463969 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,9 +177,9 @@ 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(); */
+ pim_cmd_init();
/*
* Initialize zclient "update" and "lookup" sockets
*/
@@ -183,8 +188,8 @@ int main(int argc, char **argv, char **envp)
/* TODO PIM6: next line is temporary since pim_cmd_init is disabled */
if_cmd_init(NULL);
-#if 0
pim_zebra_init();
+#if 0
pim_bfd_init();
pim_mlag_init();
diff --git a/pimd/pim6_stubs.c b/pimd/pim6_stubs.c
new file mode 100644
index 0000000000..9f68b7be3d
--- /dev/null
+++ b/pimd/pim6_stubs.c
@@ -0,0 +1,135 @@
+/*
+ * PIMv6 temporary stubs
+ * 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 "pimd.h"
+#include "pim_nht.h"
+#include "pim_zlookup.h"
+#include "pim_pim.h"
+#include "pim_register.h"
+#include "pim_cmd.h"
+
+/*
+ * 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)
+{
+}
+
+void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
+{
+}
+
+int zclient_lookup_nexthop(struct pim_instance *pim,
+ struct pim_zlookup_nexthop nexthop_tab[],
+ const int tab_size, pim_addr addr,
+ int max_lookup)
+{
+ return -1;
+}
+
+void zclient_lookup_new(void)
+{
+}
+
+void zclient_lookup_free(void)
+{
+}
+
+/*
+ * packet handling
+ */
+int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
+ int pim_msg_size, const char *ifname)
+{
+ return 0;
+}
+
+int pim_hello_send(struct interface *ifp, uint16_t holdtime)
+{
+ return -1;
+}
+
+void pim_hello_restart_now(struct interface *ifp)
+{
+}
+
+void pim_hello_restart_triggered(struct interface *ifp)
+{
+}
+
+int pim_sock_add(struct interface *ifp)
+{
+ return -1;
+}
+
+void pim_sock_delete(struct interface *ifp, const char *delete_message)
+{
+}
+
+/*
+ * PIM register
+ */
+void pim_register_join(struct pim_upstream *up)
+{
+}
+
+void pim_null_register_send(struct pim_upstream *up)
+{
+}
+
+void pim_reg_del_on_couldreg_fail(struct interface *ifp)
+{
+}
+
diff --git a/pimd/pim_addr.c b/pimd/pim_addr.c
index 2a6b4fe20f..6ba0947c2f 100644
--- a/pimd/pim_addr.c
+++ b/pimd/pim_addr.c
@@ -44,9 +44,6 @@ static ssize_t printfrr_pimaddr(struct fbuf *buf, struct printfrr_eargs *ea,
#if PIM_IPV == 4
return bprintfrr(buf, "%pI4", addr);
-#elif !defined(PIM_V6_TEMP_BREAK)
- CPP_NOTICE("note IPv6 typing for pim_addr is temporarily disabled.");
- return bprintfrr(buf, "%pI4", addr);
#else
return bprintfrr(buf, "%pI6", addr);
#endif
diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h
index 3c4b5a84d1..a278a46593 100644
--- a/pimd/pim_addr.h
+++ b/pimd/pim_addr.h
@@ -25,17 +25,15 @@
/* clang-format off */
-/* temporarily disable IPv6 types to keep code compiling.
- * Defining PIM_V6_TEMP_BREAK will show a lot of compile errors - they are
- * very useful to see TODOs.
- */
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
typedef struct in_addr pim_addr;
#define PIM_ADDRSTRLEN INET_ADDRSTRLEN
#define PIM_AF AF_INET
#define PIM_AFI AFI_IP
#define PIM_MAX_BITLEN IPV4_MAX_BITLEN
+#define PIM_AF_NAME "ip"
+#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv4"
union pimprefixptr {
prefixtype(pimprefixptr, struct prefix, p)
@@ -54,6 +52,8 @@ 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"
+#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6"
union pimprefixptr {
prefixtype(pimprefixptr, struct prefix, p)
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 3e3021dc4d..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);
}
@@ -94,7 +94,7 @@ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
bfd_sess_set_timers(
neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier,
pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr);
#else
bfd_sess_set_ipv6_addrs(neigh->bfd_session, NULL, &neigh->source_addr);
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 5901ae3439..4d1e700ab0 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -59,9 +59,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");
}
}
@@ -1371,7 +1371,12 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
}
}
- if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) {
+#if PIM_IPV == 4
+ if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr)
+#else
+ if (0)
+#endif
+ {
/* Multicast BSMs are only accepted if source interface & IP
* match RPF towards the BSR's IP address, or they have
* no-forward set
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 83ba74f69f..76f90cdba7 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"
@@ -3761,32 +3762,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 +3808,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,
@@ -3901,7 +3875,6 @@ static void clear_mroute(struct pim_instance *pim)
/* scan interfaces */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp = ifp->info;
- struct gm_group *grp;
struct pim_ifchannel *ch;
if (!pim_ifp)
@@ -3914,7 +3887,9 @@ static void clear_mroute(struct pim_instance *pim)
pim_ifchannel_delete(ch);
}
+#if PIM_IPV == 4
/* clean up all igmp groups */
+ struct gm_group *grp;
if (pim_ifp->gm_group_list) {
while (pim_ifp->gm_group_list->count) {
@@ -3922,6 +3897,7 @@ static void clear_mroute(struct pim_instance *pim)
igmp_group_delete(grp);
}
}
+#endif
}
/* clean up all upstreams*/
@@ -6748,38 +6724,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"
@@ -6787,32 +6737,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,
@@ -6824,31 +6749,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,
@@ -6862,31 +6763,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,
@@ -6921,23 +6798,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,
@@ -6949,34 +6818,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,
@@ -6988,43 +6841,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,
@@ -7037,64 +6866,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,
@@ -7106,23 +6889,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
@@ -7130,15 +6900,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,
@@ -7150,15 +6912,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,
@@ -8236,6 +7990,7 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate,
"IGMP version\n"
"IGMP version number\n")
{
+#if PIM_IPV == 4
VTY_DECLVAR_CONTEXT(interface, ifp);
int igmp_version;
struct pim_interface *pim_ifp = ifp->info;
@@ -8253,7 +8008,7 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate,
igmp_version = atoi(argv[4]->arg);
igmp_send_query_on_intf(ifp, igmp_version);
-
+#endif
return CMD_SUCCESS;
}
@@ -9540,7 +9295,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
@@ -10568,7 +10322,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;
@@ -11002,12 +10755,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);
@@ -11176,14 +10927,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);
@@ -11229,20 +10978,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);
@@ -11265,7 +11011,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..6adea54a61
--- /dev/null
+++ b/pimd/pim_cmd_common.c
@@ -0,0 +1,328 @@
+/*
+ * 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 "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);
+}
diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h
new file mode 100644
index 0000000000..49fc6bcbeb
--- /dev/null
+++ b/pimd/pim_cmd_common.h
@@ -0,0 +1,39 @@
+/*
+ * 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);
+
+#endif /* PIM_CMD_COMMON_H */
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 57fe97816e..5425aec233 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -50,10 +50,12 @@
#include "pim_igmp_join.h"
#include "pim_vxlan.h"
+#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);
+#endif
void pim_if_init(struct pim_instance *pim)
{
@@ -83,6 +85,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
}
+__attribute__((unused))
static int pim_sec_addr_comp(const void *p1, const void *p2)
{
const struct pim_secondary_addr *sec1 = p1;
@@ -124,6 +127,7 @@ 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;
@@ -185,6 +189,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
pim_sock_reset(ifp);
pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
+#endif
pim_ifp->pim->mcast_if_count++;
return pim_ifp;
@@ -198,6 +203,8 @@ void pim_if_delete(struct interface *ifp)
pim_ifp = ifp->info;
assert(pim_ifp);
+ pim_ifp->pim->mcast_if_count--;
+#if PIM_IPV == 4
if (pim_ifp->gm_join_list) {
pim_if_igmp_join_del_all(ifp);
}
@@ -208,7 +215,6 @@ void pim_if_delete(struct interface *ifp)
pim_neighbor_delete_all(ifp, "Interface removed from configuration");
pim_if_del_vif(ifp);
- pim_ifp->pim->mcast_if_count--;
pim_igmp_if_fini(pim_ifp);
@@ -218,6 +224,7 @@ 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;
}
@@ -486,7 +493,6 @@ void pim_if_addr_add(struct connected *ifc)
{
struct pim_interface *pim_ifp;
struct interface *ifp;
- struct in_addr ifaddr;
bool vxlan_term;
assert(ifc);
@@ -507,13 +513,14 @@ void pim_if_addr_add(struct connected *ifc)
? "secondary"
: "primary");
- ifaddr = ifc->address->u.prefix4;
-
detect_address_change(ifp, 0, __func__);
// if (ifc->address->family != AF_INET)
// return;
+#if PIM_IPV == 4
+ struct in_addr ifaddr = ifc->address->u.prefix4;
+
if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
struct gm_sock *igmp;
@@ -579,6 +586,7 @@ void pim_if_addr_add(struct connected *ifc)
true);
}
} /* igmp mtrace only */
+#endif
if (PIM_IF_TEST_PIM(pim_ifp->options)) {
@@ -630,6 +638,7 @@ void pim_if_addr_add(struct connected *ifc)
static void pim_if_addr_del_igmp(struct connected *ifc)
{
+#if PIM_IPV == 4
struct pim_interface *pim_ifp = ifc->ifp->info;
struct gm_sock *igmp;
struct in_addr ifaddr;
@@ -652,6 +661,7 @@ static void pim_if_addr_del_igmp(struct connected *ifc)
/* if addr found, del IGMP socket */
igmp_sock_delete(igmp);
}
+#endif
}
static void pim_if_addr_del_pim(struct connected *ifc)
@@ -1140,6 +1150,7 @@ long pim_if_t_suppressed_msec(struct interface *ifp)
return t_suppressed_msec;
}
+#if PIM_IPV == 4
static void igmp_join_free(struct gm_join *ij)
{
XFREE(MTYPE_PIM_IGMP_JOIN, ij);
@@ -1330,6 +1341,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
return 0;
}
+__attribute__((unused))
static void pim_if_igmp_join_del_all(struct interface *ifp)
{
struct pim_interface *pim_ifp;
@@ -1350,6 +1362,19 @@ static void pim_if_igmp_join_del_all(struct interface *ifp)
for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
}
+#else /* PIM_IPV != 4 */
+ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
+ struct in_addr source_addr)
+{
+ return ferr_ok();
+}
+
+int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
+ struct in_addr source_addr)
+{
+ return 0;
+}
+#endif /* PIM_IPV != 4 */
/*
RFC 4601
@@ -1524,6 +1549,7 @@ 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);
/*
@@ -1535,8 +1561,10 @@ 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
/*
* If we are a vrf device that is up, open up the pim_socket for
* listening
@@ -1564,6 +1592,7 @@ static int pim_ifp_create(struct interface *ifp)
"%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
__func__, ifp->name, MAXVIFS);
}
+#endif
return 0;
}
@@ -1572,7 +1601,6 @@ static int pim_ifp_up(struct interface *ifp)
{
struct pim_interface *pim_ifp;
struct pim_instance *pim;
- uint32_t table_id;
if (PIM_DEBUG_ZEBRA) {
zlog_debug(
@@ -1593,6 +1621,9 @@ 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
@@ -1621,6 +1652,7 @@ static int pim_ifp_up(struct interface *ifp)
}
}
}
+#endif
return 0;
}
@@ -1634,6 +1666,7 @@ 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);
/*
@@ -1656,14 +1689,13 @@ static int pim_ifp_down(struct interface *ifp)
pim_if_del_vif(ifp);
pim_ifstat_reset(ifp);
}
+#endif
return 0;
}
static int pim_ifp_destroy(struct interface *ifp)
{
- struct pim_instance *pim;
-
if (PIM_DEBUG_ZEBRA) {
zlog_debug(
"%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
@@ -1672,12 +1704,16 @@ 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);
pim = ifp->vrf->info;
if (pim && pim->vxlan.term_if == ifp)
pim_vxlan_del_term_dev(pim);
+#endif
return 0;
}
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 3079c25a1c..956ab0d67c 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -306,8 +306,8 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
* supplying the implied
* if channel. So remove it.
*/
- if (c_oil->oil.mfcc_ttls
- [pim_ifp->mroute_vif_index])
+ if (oil_if_has(c_oil,
+ pim_ifp->mroute_vif_index))
pim_channel_del_inherited_oif(
c_oil, ch->interface,
__func__);
@@ -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;
}
@@ -1287,7 +1286,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg)
if (!pim_upstream_evaluate_join_desired_interface(
child, ch, starch) ||
(!chchannel &&
- c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])) {
+ oil_if_has(c_oil, pim_ifp->mroute_vif_index))) {
pim_channel_del_inherited_oif(c_oil, ifp,
__func__);
}
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index b82b62ea74..5c35996634 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -105,6 +105,7 @@ struct gm_sock {
struct pim_interface;
+#if PIM_IPV == 4
void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp);
void pim_igmp_if_reset(struct pim_interface *pim_ifp);
void pim_igmp_if_fini(struct pim_interface *pim_ifp);
@@ -126,6 +127,24 @@ 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_general_query_on(struct gm_sock *igmp)
+{
+}
+
+static inline void pim_igmp_general_query_off(struct gm_sock *igmp)
+{
+}
+
+static inline void pim_igmp_other_querier_timer_on(struct gm_sock *igmp)
+{
+}
+
+static inline void pim_igmp_other_querier_timer_off(struct gm_sock *igmp)
+{
+}
+#endif /* PIM_IPV == 4 */
+
#define IGMP_SOURCE_MASK_FORWARDING (1 << 0)
#define IGMP_SOURCE_MASK_DELETE (1 << 1)
#define IGMP_SOURCE_MASK_SEND (1 << 2)
@@ -184,6 +203,7 @@ struct gm_group {
int64_t last_igmp_v2_report_dsec;
};
+#if PIM_IPV == 4
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,
@@ -210,4 +230,11 @@ void igmp_send_query(int igmp_version, struct gm_group *group, int fd,
void igmp_group_delete(struct gm_group *group);
void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver);
+
+#else /* PIM_IPV != 4 */
+static inline void igmp_startup_mode_on(struct gm_sock *igmp)
+{
+}
+#endif /* PIM_IPV != 4 */
+
#endif /* PIM_IGMP_H */
diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h
index c323902764..8027b8b94b 100644
--- a/pimd/pim_igmp_join.h
+++ b/pimd/pim_igmp_join.h
@@ -39,9 +39,9 @@ struct group_source_req {
};
#endif
-static int pim_igmp_join_source(int fd, ifindex_t ifindex,
- struct in_addr group_addr,
- struct in_addr source_addr)
+static inline int pim_igmp_join_source(int fd, ifindex_t ifindex,
+ struct in_addr group_addr,
+ struct in_addr source_addr)
{
struct group_source_req req;
struct sockaddr_in group;
diff --git a/pimd/pim_igmp_stats.h b/pimd/pim_igmp_stats.h
index 57b5cc62f4..a70a433557 100644
--- a/pimd/pim_igmp_stats.h
+++ b/pimd/pim_igmp_stats.h
@@ -35,7 +35,17 @@ struct igmp_stats {
uint32_t unsupported;
};
+#if PIM_IPV == 4
void igmp_stats_init(struct igmp_stats *stats);
void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b);
+#else
+static inline void igmp_stats_init(struct igmp_stats *stats)
+{
+}
+
+static inline void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b)
+{
+}
+#endif
#endif /* PIM_IGMP_STATS_H */
diff --git a/pimd/pim_igmpv3.h b/pimd/pim_igmpv3.h
index 7449e420e4..5041e54cb4 100644
--- a/pimd/pim_igmpv3.h
+++ b/pimd/pim_igmpv3.h
@@ -53,6 +53,7 @@
/* OHPI: Older Host Present Interval */
#define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec))
+#if PIM_IPV == 4
void igmp_group_reset_gmi(struct gm_group *group);
void igmp_source_reset_gmi(struct gm_group *group, struct gm_source *source);
@@ -98,4 +99,16 @@ void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str,
int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from,
const char *from_str, char *igmp_msg, int igmp_msg_len);
+#else /* PIM_IPV != 4 */
+static inline void igmp_group_reset_gmi(struct gm_group *group)
+{
+}
+
+
+static inline void igmp_source_reset_gmi(struct gm_group *group,
+ struct gm_source *source)
+{
+}
+#endif
+
#endif /* PIM_IGMPV3_H */
diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c
index 42ad5dcd1e..7cbd0304ae 100644
--- a/pimd/pim_jp_agg.c
+++ b/pimd/pim_jp_agg.c
@@ -109,6 +109,7 @@ pim_jp_agg_get_interface_upstream_switch_list(struct pim_rpf *rpf)
struct pim_interface *pim_ifp;
struct pim_iface_upstream_switch *pius;
struct listnode *node, *nnode;
+ pim_addr rpf_addr;
if (!ifp)
return NULL;
@@ -119,16 +120,18 @@ pim_jp_agg_get_interface_upstream_switch_list(struct pim_rpf *rpf)
if (!pim_ifp)
return NULL;
+ rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr);
+
for (ALL_LIST_ELEMENTS(pim_ifp->upstream_switch_list, node, nnode,
pius)) {
- if (pius->address.s_addr == rpf->rpf_addr.u.prefix4.s_addr)
+ if (!pim_addr_cmp(pius->address, rpf_addr))
break;
}
if (!pius) {
pius = XCALLOC(MTYPE_PIM_JP_AGG_GROUP,
sizeof(struct pim_iface_upstream_switch));
- pius->address.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
+ pius->address = rpf_addr;
pius->us = list_new();
listnode_add_sort(pim_ifp->upstream_switch_list, pius);
}
diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h
index 996e4d473f..0555c7d3ff 100644
--- a/pimd/pim_mlag.h
+++ b/pimd/pim_mlag.h
@@ -28,6 +28,7 @@
#include "mlag.h"
#include "pim_iface.h"
+#if PIM_IPV == 4
extern void pim_mlag_init(void);
extern void pim_mlag_terminate(void);
extern void pim_instance_mlag_init(struct pim_instance *pim);
@@ -52,4 +53,49 @@ extern void pim_mlag_up_local_del(struct pim_instance *pim,
extern bool pim_mlag_up_df_role_update(struct pim_instance *pim,
struct pim_upstream *up, bool is_df,
const char *reason);
+#else /* PIM_IPV == 4 */
+static inline void pim_mlag_terminate(void)
+{
+}
+
+static inline void pim_instance_mlag_init(struct pim_instance *pim)
+{
+}
+
+static inline void pim_instance_mlag_terminate(struct pim_instance *pim)
+{
+}
+
+static inline void pim_if_configure_mlag_dualactive(
+ struct pim_interface *pim_ifp)
+{
+}
+
+static inline void pim_if_unconfigure_mlag_dualactive(
+ struct pim_interface *pim_ifp)
+{
+}
+
+static inline void pim_mlag_register(void)
+{
+}
+
+static inline void pim_mlag_up_local_add(struct pim_instance *pim,
+ struct pim_upstream *upstream)
+{
+}
+
+static inline void pim_mlag_up_local_del(struct pim_instance *pim,
+ struct pim_upstream *upstream)
+{
+}
+
+static inline bool pim_mlag_up_df_role_update(struct pim_instance *pim,
+ struct pim_upstream *up,
+ bool is_df, const char *reason)
+{
+ return false;
+}
+#endif
+
#endif
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index cf9127bc91..af6f59824c 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -145,6 +145,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable)
return 0;
}
+#if PIM_IPV == 4
static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
"<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
@@ -227,7 +228,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
up->channel_oil->cc.pktcnt++;
// resolve mfcc_parent prior to mroute_add in channel_add_oif
if (up->rpf.source_nexthop.interface &&
- up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
+ *oil_parent(up->channel_oil) >= MAXVIFS) {
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
}
pim_register_join(up);
@@ -580,12 +581,8 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
int buf_size, ifindex_t ifindex)
{
struct interface *ifp;
- struct pim_interface *pim_ifp;
const struct ip *ip_hdr;
const struct igmpmsg *msg;
- struct in_addr ifaddr;
- struct gm_sock *igmp;
- const struct prefix *connected_src;
if (buf_size < (int)sizeof(struct ip))
return 0;
@@ -593,6 +590,11 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
ip_hdr = (const struct ip *)buf;
if (ip_hdr->ip_p == IPPROTO_IGMP) {
+#if PIM_IPV == 4
+ struct pim_interface *pim_ifp;
+ struct in_addr ifaddr;
+ struct gm_sock *igmp;
+ const struct prefix *connected_src;
/* We have the IP packet but we do not know which interface this
* packet was
@@ -632,6 +634,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
zlog_debug("No IGMP socket on interface: %s with connected source: %pFX",
ifp->name, connected_src);
}
+#endif
} else if (ip_hdr->ip_p) {
if (PIM_DEBUG_MROUTE_DETAIL) {
zlog_debug(
@@ -676,6 +679,14 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
return 0;
}
+#else /* PIM_IPV != 4 */
+
+static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
+ int buf_size, ifindex_t ifindex)
+{
+ return 0;
+}
+#endif /* PIM_IPV != 4 */
static void mroute_read(struct thread *t)
{
@@ -797,7 +808,7 @@ int pim_mroute_socket_disable(struct pim_instance *pim)
would be used for multicast forwarding, a corresponding multicast
interface must be added to the kernel.
*/
-int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
+int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
unsigned char flags)
{
struct pim_interface *pim_ifp = ifp->info;
@@ -836,15 +847,10 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
(void *)&vc, sizeof(vc));
if (err) {
- char ifaddr_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
- sizeof(ifaddr_str));
-
zlog_warn(
- "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
+ "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
__func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
- ifaddr_str, flags, errno, safe_strerror(errno));
+ &ifaddr, flags, errno, safe_strerror(errno));
return -2;
}
@@ -918,26 +924,26 @@ bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
#endif
}
-static inline void pim_mroute_copy(struct mfcctl *oil,
- struct channel_oil *c_oil)
+static inline void pim_mroute_copy(struct channel_oil *out,
+ struct channel_oil *in)
{
int i;
- oil->mfcc_origin = c_oil->oil.mfcc_origin;
- oil->mfcc_mcastgrp = c_oil->oil.mfcc_mcastgrp;
- oil->mfcc_parent = c_oil->oil.mfcc_parent;
+ *oil_origin(out) = *oil_origin(in);
+ *oil_mcastgrp(out) = *oil_mcastgrp(in);
+ *oil_parent(out) = *oil_parent(in);
for (i = 0; i < MAXVIFS; ++i) {
- if ((oil->mfcc_parent == i) &&
- !pim_mroute_allow_iif_in_oil(c_oil, i)) {
- oil->mfcc_ttls[i] = 0;
+ if (*oil_parent(out) == i &&
+ !pim_mroute_allow_iif_in_oil(in, i)) {
+ oil_if_set(out, i, 0);
continue;
}
- if (c_oil->oif_flags[i] & PIM_OIF_FLAG_MUTE)
- oil->mfcc_ttls[i] = 0;
+ if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
+ oil_if_set(out, i, 0);
else
- oil->mfcc_ttls[i] = c_oil->oil.mfcc_ttls[i];
+ oil_if_set(out, i, oil_if_has(in, i));
}
}
@@ -947,7 +953,7 @@ static inline void pim_mroute_copy(struct mfcctl *oil,
static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
{
struct pim_instance *pim = c_oil->pim;
- struct mfcctl tmp_oil = { {0} };
+ struct channel_oil tmp_oil[1] = { };
int err;
pim->mroute_add_last = pim_time_monotonic_sec();
@@ -956,14 +962,14 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
/* Copy the oil to a temporary structure to fixup (without need to
* later restore) before sending the mroute add to the dataplane
*/
- pim_mroute_copy(&tmp_oil, c_oil);
+ pim_mroute_copy(tmp_oil, c_oil);
/* The linux kernel *expects* the incoming
* vif to be part of the outgoing list
* in the case of a (*,G).
*/
- if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
- tmp_oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
+ if (pim_addr_is_any(*oil_origin(c_oil))) {
+ oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
}
/*
@@ -973,19 +979,19 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
* the packets to be forwarded. Then set it
* to the correct IIF afterwords.
*/
- if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
- && c_oil->oil.mfcc_parent != 0) {
- tmp_oil.mfcc_parent = 0;
+ if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
+ && *oil_parent(c_oil) != 0) {
+ *oil_parent(tmp_oil) = 0;
}
err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
- &tmp_oil, sizeof(tmp_oil));
+ &tmp_oil->oil, sizeof(tmp_oil->oil));
if (!err && !c_oil->installed
- && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
- && c_oil->oil.mfcc_parent != 0) {
- tmp_oil.mfcc_parent = c_oil->oil.mfcc_parent;
+ && !pim_addr_is_any(*oil_origin(c_oil))
+ && *oil_parent(c_oil) != 0) {
+ *oil_parent(tmp_oil) = *oil_parent(c_oil);
err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
- &tmp_oil, sizeof(tmp_oil));
+ &tmp_oil->oil, sizeof(tmp_oil->oil));
}
if (err) {
@@ -1040,7 +1046,7 @@ static int pim_upstream_mroute_update(struct channel_oil *c_oil,
{
char buf[1000];
- if (c_oil->oil.mfcc_parent >= MAXVIFS) {
+ if (*oil_parent(c_oil) >= MAXVIFS) {
/* the c_oil cannot be installed as a mroute yet */
if (PIM_DEBUG_MROUTE)
zlog_debug(
@@ -1087,13 +1093,13 @@ int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
iif = pim_upstream_get_mroute_iif(c_oil, name);
- if (c_oil->oil.mfcc_parent != iif) {
- c_oil->oil.mfcc_parent = iif;
- if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
+ if (*oil_parent(c_oil) != iif) {
+ *oil_parent(c_oil) = iif;
+ if (pim_addr_is_any(*oil_origin(c_oil)) &&
c_oil->up)
pim_upstream_all_sources_iif_update(c_oil->up);
} else {
- c_oil->oil.mfcc_parent = iif;
+ *oil_parent(c_oil) = iif;
}
return pim_upstream_mroute_update(c_oil, name);
@@ -1108,13 +1114,13 @@ int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
char buf[1000];
iif = pim_upstream_get_mroute_iif(c_oil, name);
- if (c_oil->oil.mfcc_parent == iif) {
+ if (*oil_parent(c_oil) == iif) {
/* no change */
return 0;
}
- c_oil->oil.mfcc_parent = iif;
+ *oil_parent(c_oil) = iif;
- if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
+ if (pim_addr_is_any(*oil_origin(c_oil)) &&
c_oil->up)
pim_upstream_all_sources_iif_update(c_oil->up);
@@ -1137,10 +1143,10 @@ void pim_static_mroute_iif_update(struct channel_oil *c_oil,
int input_vif_index,
const char *name)
{
- if (c_oil->oil.mfcc_parent == input_vif_index)
+ if (*oil_parent(c_oil) == input_vif_index)
return;
- c_oil->oil.mfcc_parent = input_vif_index;
+ *oil_parent(c_oil) = input_vif_index;
if (input_vif_index == MAXVIFS)
pim_mroute_del(c_oil, name);
else
@@ -1160,7 +1166,7 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
char buf[1000];
zlog_debug(
"%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
- __FILE__, __func__, c_oil->oil.mfcc_parent,
+ __FILE__, __func__, *oil_parent(c_oil),
pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
}
return -2;
@@ -1193,7 +1199,6 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
void pim_mroute_update_counters(struct channel_oil *c_oil)
{
struct pim_instance *pim = c_oil->pim;
- struct sioc_sg_req sgreq;
c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
@@ -1204,24 +1209,27 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
if (PIM_DEBUG_MROUTE) {
pim_sgaddr sg;
- sg.src = c_oil->oil.mfcc_origin;
- sg.grp = c_oil->oil.mfcc_mcastgrp;
+ sg.src = *oil_origin(c_oil);
+ sg.grp = *oil_mcastgrp(c_oil);
zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
&sg);
}
return;
}
+#if PIM_IPV == 4
+ struct sioc_sg_req sgreq;
+
memset(&sgreq, 0, sizeof(sgreq));
- sgreq.src = c_oil->oil.mfcc_origin;
- sgreq.grp = c_oil->oil.mfcc_mcastgrp;
+ sgreq.src = *oil_origin(c_oil);
+ sgreq.grp = *oil_mcastgrp(c_oil);
pim_zlookup_sg_statistics(c_oil);
if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
pim_sgaddr sg;
- sg.src = c_oil->oil.mfcc_origin;
- sg.grp = c_oil->oil.mfcc_mcastgrp;
+ sg.src = *oil_origin(c_oil);
+ sg.grp = *oil_mcastgrp(c_oil);
zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
(unsigned long)SIOCGETSGCNT, &sg,
@@ -1232,6 +1240,6 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
c_oil->cc.pktcnt = sgreq.pktcnt;
c_oil->cc.bytecnt = sgreq.bytecnt;
c_oil->cc.wrong_if = sgreq.wrong_if;
-
+#endif
return;
}
diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h
index 4cd6b9f0ac..14b0a8ccaf 100644
--- a/pimd/pim_mroute.h
+++ b/pimd/pim_mroute.h
@@ -37,6 +37,7 @@
#define PIM_MROUTE_MIN_TTL (1)
+#if PIM_IPV == 4
#if defined(HAVE_LINUX_MROUTE_H)
#include <linux/mroute.h>
#else
@@ -157,6 +158,19 @@ struct igmpmsg {
struct in_addr im_src, im_dst;
};
#endif
+
+#endif /* HAVE_LINUX_MROUTE_H */
+
+typedef struct mfcctl pim_mfcctl;
+
+#else /* PIM_IPV != 4 */
+#if defined(HAVE_LINUX_MROUTE6_H)
+#include <linux/mroute6.h>
+#endif
+
+typedef struct mf6cctl pim_mfcctl;
+
+#define MAXVIFS IF_SETSIZE
#endif
#ifndef IGMPMSG_WRVIFWHOLE
@@ -172,7 +186,7 @@ struct channel_oil;
int pim_mroute_socket_enable(struct pim_instance *pim);
int pim_mroute_socket_disable(struct pim_instance *pim);
-int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
+int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
unsigned char flags);
int pim_mroute_del_vif(struct interface *ifp);
diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c
index e25cf11549..a0653e1a57 100644
--- a/pimd/pim_msg.c
+++ b/pimd/pim_msg.c
@@ -138,7 +138,7 @@ uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr)
return buf;
}
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv4_##what
#else
#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv6_##what
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 8a78489ae0..27cac0c1a7 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -46,9 +46,13 @@ int funcname(struct argtype *args) \
} \
MACRO_REQUIRE_SEMICOLON()
+#define yang_dnode_get_pimaddr yang_dnode_get_ipv6
+
#else /* PIM_IPV != 6 */
#define pim6_msdp_err(funcname, argtype) \
MACRO_REQUIRE_SEMICOLON()
+
+#define yang_dnode_get_pimaddr yang_dnode_get_ipv4
#endif /* PIM_IPV != 6 */
static void pim_if_membership_clear(struct interface *ifp)
@@ -173,8 +177,7 @@ static int pim_cmd_interface_delete(struct interface *ifp)
}
static int interface_pim_use_src_cmd_worker(struct interface *ifp,
- struct in_addr source_addr,
- char *errmsg, size_t errmsg_len)
+ pim_addr source_addr, char *errmsg, size_t errmsg_len)
{
int result;
int ret = NB_OK;
@@ -397,15 +400,10 @@ static void igmp_sock_query_interval_reconfig(struct gm_sock *igmp)
ifp = igmp->interface;
pim_ifp = ifp->info;
- if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
- sizeof(ifaddr_str));
- zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
- __func__, ifaddr_str, ifp->name,
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug("%s: Querier %pPAs on %s reconfig query_interval=%d",
+ __func__, &igmp->ifaddr, ifp->name,
pim_ifp->gm_default_query_interval);
- }
/*
* igmp_startup_mode_on() will reset QQI:
@@ -2016,7 +2014,7 @@ int lib_interface_pim_address_family_use_source_modify(
struct nb_cb_modify_args *args)
{
struct interface *ifp;
- struct ipaddr source_addr;
+ pim_addr source_addr;
int result;
const struct lyd_node *if_dnode;
@@ -2034,10 +2032,14 @@ int lib_interface_pim_address_family_use_source_modify(
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
- yang_dnode_get_ip(&source_addr, args->dnode, NULL);
+#if PIM_IPV == 4
+ yang_dnode_get_ipv4(&source_addr, args->dnode, NULL);
+#else
+ yang_dnode_get_ipv6(&source_addr, args->dnode, NULL);
+#endif
result = interface_pim_use_src_cmd_worker(
- ifp, source_addr.ip._v4_addr,
+ ifp, source_addr,
args->errmsg, args->errmsg_len);
if (result != PIM_SUCCESS)
@@ -2053,7 +2055,6 @@ int lib_interface_pim_address_family_use_source_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
- struct in_addr source_addr = {INADDR_ANY};
int result;
const struct lyd_node *if_dnode;
@@ -2072,7 +2073,7 @@ int lib_interface_pim_address_family_use_source_destroy(
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
- result = interface_pim_use_src_cmd_worker(ifp, source_addr,
+ result = interface_pim_use_src_cmd_worker(ifp, PIMADDR_ANY,
args->errmsg,
args->errmsg_len);
@@ -2180,8 +2181,8 @@ int lib_interface_pim_address_family_mroute_destroy(
struct interface *iif;
struct interface *oif;
const char *oifname;
- struct ipaddr source_addr;
- struct ipaddr group_addr;
+ pim_addr source_addr;
+ pim_addr group_addr;
const struct lyd_node *if_dnode;
switch (args->event) {
@@ -2211,11 +2212,10 @@ int lib_interface_pim_address_family_mroute_destroy(
return NB_ERR_INCONSISTENCY;
}
- yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
- yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+ yang_dnode_get_pimaddr(&source_addr, args->dnode, "./source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
- if (pim_static_del(pim, iif, oif, group_addr.ip._v4_addr,
- source_addr.ip._v4_addr)) {
+ if (pim_static_del(pim, iif, oif, group_addr, source_addr)) {
snprintf(args->errmsg, args->errmsg_len,
"Failed to remove static mroute");
return NB_ERR_INCONSISTENCY;
@@ -2238,8 +2238,8 @@ int lib_interface_pim_address_family_mroute_oif_modify(
struct interface *iif;
struct interface *oif;
const char *oifname;
- struct ipaddr source_addr;
- struct ipaddr group_addr;
+ pim_addr source_addr;
+ pim_addr group_addr;
const struct lyd_node *if_dnode;
switch (args->event) {
@@ -2288,11 +2288,10 @@ int lib_interface_pim_address_family_mroute_oif_modify(
return NB_ERR_INCONSISTENCY;
}
- yang_dnode_get_ip(&source_addr, args->dnode, "../source-addr");
- yang_dnode_get_ip(&group_addr, args->dnode, "../group-addr");
+ yang_dnode_get_pimaddr(&source_addr, args->dnode, "../source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "../group-addr");
- if (pim_static_add(pim, iif, oif, group_addr.ip._v4_addr,
- source_addr.ip._v4_addr)) {
+ if (pim_static_add(pim, iif, oif, group_addr, source_addr)) {
snprintf(args->errmsg, args->errmsg_len,
"Failed to add static mroute");
return NB_ERR_INCONSISTENCY;
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 2e690d85f6..ce5298e5b0 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) {
@@ -361,7 +354,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
pim_addr nhaddr;
switch (nh->type) {
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
case NEXTHOP_TYPE_IPV4:
if (nh->ifindex == IFINDEX_INTERNAL)
continue;
@@ -409,8 +402,8 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
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 =
@@ -523,6 +516,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 +526,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.
@@ -573,23 +569,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;
}
}
@@ -605,14 +591,14 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
ifps[i] =
if_lookup_by_index(nh_node->ifindex, pim->vrf->vrf_id);
if (ifps[i]) {
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
pim_addr nhaddr = nh_node->gate.ipv4;
#else
pim_addr nhaddr = nh_node->gate.ipv6;
#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 +621,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 +661,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++;
}
@@ -784,9 +755,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,
@@ -798,7 +775,7 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
nbr = pim_neighbor_find_if(ifp1);
/* Overwrite with Nbr address as NH addr */
if (nbr)
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
nexthop->gate.ipv4 = nbr->source_addr;
#else
nexthop->gate.ipv6 = nbr->source_addr;
@@ -806,8 +783,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;
@@ -917,20 +897,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 +915,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 +938,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 +969,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 +981,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",
@@ -1029,9 +1001,9 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
i++;
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
+ "%s: NBR not found on input interface %s(%s) (RPF for source %pPA)",
__func__, ifp->name,
- pim->vrf->name, addr_str);
+ pim->vrf->name, &src_addr);
continue;
}
}
@@ -1044,8 +1016,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 +1030,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 +1050,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 b17f821dd6..a499c884b4 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -42,15 +42,15 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
pim_sgaddr sg;
int i;
- sg.src = c_oil->oil.mfcc_origin;
- sg.grp = c_oil->oil.mfcc_mcastgrp;
- ifp = pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent);
+ sg.src = *oil_origin(c_oil);
+ sg.grp = *oil_mcastgrp(c_oil);
+ ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil));
snprintfrr(buf, size, "%pSG IIF: %s, OIFS: ", &sg,
ifp ? ifp->name : "(?)");
out = buf + strlen(buf);
for (i = 0; i < MAXVIFS; i++) {
- if (c_oil->oil.mfcc_ttls[i] != 0) {
+ if (oil_if_has(c_oil, i) != 0) {
ifp = pim_if_find_by_vif_index(c_oil->pim, i);
snprintf(out, buf + size - out, "%s ",
ifp ? ifp->name : "(?)");
@@ -61,25 +61,19 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
return buf;
}
-int pim_channel_oil_compare(const struct channel_oil *c1,
- const struct channel_oil *c2)
+int pim_channel_oil_compare(const struct channel_oil *cc1,
+ const struct channel_oil *cc2)
{
- if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
- < ntohl(c2->oil.mfcc_mcastgrp.s_addr))
- return -1;
-
- if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
- > ntohl(c2->oil.mfcc_mcastgrp.s_addr))
- return 1;
-
- if (ntohl(c1->oil.mfcc_origin.s_addr)
- < ntohl(c2->oil.mfcc_origin.s_addr))
- return -1;
-
- if (ntohl(c1->oil.mfcc_origin.s_addr)
- > ntohl(c2->oil.mfcc_origin.s_addr))
- return 1;
-
+ struct channel_oil *c1 = (struct channel_oil *)cc1;
+ struct channel_oil *c2 = (struct channel_oil *)cc2;
+ int rv;
+
+ rv = pim_addr_cmp(*oil_mcastgrp(c1), *oil_mcastgrp(c2));
+ if (rv)
+ return rv;
+ rv = pim_addr_cmp(*oil_origin(c1), *oil_origin(c2));
+ if (rv)
+ return rv;
return 0;
}
@@ -109,8 +103,8 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
struct channel_oil *c_oil = NULL;
struct channel_oil lookup;
- lookup.oil.mfcc_mcastgrp = sg->grp;
- lookup.oil.mfcc_origin = sg->src;
+ *oil_mcastgrp(&lookup) = sg->grp;
+ *oil_origin(&lookup) = sg->src;
c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
@@ -151,10 +145,10 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
- c_oil->oil.mfcc_mcastgrp = sg->grp;
- c_oil->oil.mfcc_origin = sg->src;
+ *oil_mcastgrp(c_oil) = sg->grp;
+ *oil_origin(c_oil) = sg->src;
- c_oil->oil.mfcc_parent = MAXVIFS;
+ *oil_parent(c_oil) = MAXVIFS;
c_oil->oil_ref_count = 1;
c_oil->installed = 0;
c_oil->up = pim_upstream_find(pim, sg);
@@ -172,8 +166,8 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
const char *name)
{
if (PIM_DEBUG_MROUTE) {
- pim_sgaddr sg = {.src = c_oil->oil.mfcc_mcastgrp,
- .grp = c_oil->oil.mfcc_origin};
+ pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil),
+ .grp = *oil_origin(c_oil)};
zlog_debug(
"%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)",
@@ -228,23 +222,15 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
*/
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, proto_mask,
channel_oil
->oif_flags[pim_ifp->mroute_vif_index],
oif->name, pim_ifp->mroute_vif_index,
- channel_oil->oil
- .mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
return 0;
}
@@ -254,44 +240,29 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] &
PIM_OIF_FLAG_PROTO_ANY) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, oif->name,
pim_ifp->mroute_vif_index,
- channel_oil->oil
- .mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
return 0;
}
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
+ oil_if_set(channel_oil, pim_ifp->mroute_vif_index, false);
/* clear mute; will be re-evaluated when the OIF becomes valid again */
channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE;
if (pim_upstream_mroute_add(channel_oil, __func__)) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, oif->name,
- pim_ifp->mroute_vif_index, source_str,
- group_str);
+ pim_ifp->mroute_vif_index,
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
return -1;
}
@@ -299,16 +270,12 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
--channel_oil->oil_size;
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
- source_str, sizeof(source_str));
zlog_debug(
- "%s(%s): (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
- __func__, caller, source_str, group_str, proto_mask,
- channel_oil->oil.mfcc_parent, oif->name,
+ "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
+ __func__, caller, oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil),
+ proto_mask,
+ *oil_parent(channel_oil), oif->name,
pim_ifp->mroute_vif_index);
}
@@ -397,7 +364,7 @@ void pim_channel_update_oif_mute(struct channel_oil *c_oil,
bool new_mute;
/* If pim_ifp is not a part of the OIL there is nothing to do */
- if (!c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
+ if (!oil_if_has(c_oil, pim_ifp->mroute_vif_index))
return;
old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] &
@@ -455,21 +422,13 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
channel (S,G) multiple times */
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, proto_mask, oif->name,
pim_ifp->mroute_vif_index,
- channel_oil->oil
- .mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
return -3;
}
@@ -487,36 +446,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
/* Check the OIF really exists before returning, and only log
warning otherwise */
- if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
+ if (oil_if_has(channel_oil, pim_ifp->mroute_vif_index) < 1) {
zlog_warn(
- "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, proto_mask, oif->name,
pim_ifp->mroute_vif_index,
- channel_oil->oil
- .mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d added to 0x%x",
- __func__, caller, source_str, group_str,
+ "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d added to 0x%x",
+ __func__, caller, oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil),
proto_mask, oif->name,
pim_ifp->mroute_vif_index,
channel_oil
@@ -525,29 +469,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
return 0;
}
- old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
+ old_ttl = oil_if_has(channel_oil, pim_ifp->mroute_vif_index);
if (old_ttl > 0) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
+ "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, oif->name,
- pim_ifp->mroute_vif_index, source_str,
- group_str);
+ pim_ifp->mroute_vif_index,
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
return -4;
}
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
- PIM_MROUTE_MIN_TTL;
+ oil_if_set(channel_oil, pim_ifp->mroute_vif_index, PIM_MROUTE_MIN_TTL);
/* Some OIFs are held in a muted state i.e. the PIM state machine
* decided to include the OIF but additional status check such as
@@ -564,26 +500,19 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
/* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
* valid to get installed in kernel.
*/
- if (channel_oil->oil.mfcc_parent != MAXVIFS) {
+ if (*oil_parent(channel_oil) != MAXVIFS) {
if (pim_upstream_mroute_add(channel_oil, __func__)) {
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
zlog_debug(
- "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+ "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
__FILE__, __func__, oif->name,
- pim_ifp->mroute_vif_index, source_str,
- group_str);
+ pim_ifp->mroute_vif_index,
+ oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil));
}
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
- = old_ttl;
+ oil_if_set(channel_oil, pim_ifp->mroute_vif_index,
+ old_ttl);
return -5;
}
}
@@ -594,15 +523,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
- source_str, sizeof(source_str));
zlog_debug(
- "%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
- __func__, caller, source_str, group_str, proto_mask,
+ "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d: DONE",
+ __func__, caller, oil_origin(channel_oil),
+ oil_mcastgrp(channel_oil),
+ proto_mask,
oif->name, pim_ifp->mroute_vif_index);
}
@@ -611,8 +536,6 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
int pim_channel_oil_empty(struct channel_oil *c_oil)
{
- static struct mfcctl null_oil;
-
if (!c_oil)
return 1;
@@ -620,6 +543,13 @@ int pim_channel_oil_empty(struct channel_oil *c_oil)
* non-NULL.
* pimreg device (in all vrfs) uses a vifi of
* 0 (PIM_OIF_PIM_REGISTER_VIF) so we simply mfcc_ttls[0] */
+#if PIM_IPV == 4
+ static pim_mfcctl null_oil;
+
return !memcmp(&c_oil->oil.mfcc_ttls[1], &null_oil.mfcc_ttls[1],
sizeof(null_oil.mfcc_ttls) - sizeof(null_oil.mfcc_ttls[0]));
+#else
+ CPP_NOTICE("FIXME STUB");
+ return false;
+#endif
}
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index 696ef70645..a52e23351e 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -98,7 +98,7 @@ struct channel_oil {
struct rb_pim_oil_item oil_rb;
- struct mfcctl oil;
+ pim_mfcctl oil;
int installed;
int oil_inherited_rescan;
int oil_size;
@@ -110,6 +110,61 @@ struct channel_oil {
time_t mroute_creation;
};
+#if PIM_IPV == 4
+static inline pim_addr *oil_origin(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mfcc_origin;
+}
+
+static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mfcc_mcastgrp;
+}
+
+static inline vifi_t *oil_parent(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mfcc_parent;
+}
+
+static inline uint8_t oil_if_has(struct channel_oil *c_oil, vifi_t ifi)
+{
+ return c_oil->oil.mfcc_ttls[ifi];
+}
+
+static inline void oil_if_set(struct channel_oil *c_oil, vifi_t ifi, uint8_t set)
+{
+ c_oil->oil.mfcc_ttls[ifi] = set;
+}
+#else
+static inline pim_addr *oil_origin(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mf6cc_origin.sin6_addr;
+}
+
+static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mf6cc_mcastgrp.sin6_addr;
+}
+
+static inline mifi_t *oil_parent(struct channel_oil *c_oil)
+{
+ return &c_oil->oil.mf6cc_parent;
+}
+
+static inline bool oil_if_has(struct channel_oil *c_oil, mifi_t ifi)
+{
+ return !!IF_ISSET(ifi, &c_oil->oil.mf6cc_ifset);
+}
+
+static inline void oil_if_set(struct channel_oil *c_oil, mifi_t ifi, bool set)
+{
+ if (set)
+ IF_SET(ifi, &c_oil->oil.mf6cc_ifset);
+ else
+ IF_CLR(ifi, &c_oil->oil.mf6cc_ifset);
+}
+#endif
+
extern int pim_channel_oil_compare(const struct channel_oil *c1,
const struct channel_oil *c2);
DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index a5183c9e9b..0346a7067b 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -1366,7 +1366,7 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
if (nbr->interface != ifp1)
continue;
-#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
+#if PIM_IPV == 4
nh_node->gate.ipv4 = nbr->source_addr;
#else
nh_node->gate.ipv6 = nbr->source_addr;
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index 2e8fc8e661..c62a06f85c 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -39,7 +39,7 @@
#include "pim_oil.h"
#include "pim_mlag.h"
-static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
+static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
void pim_rpf_set_refresh_time(struct pim_instance *pim)
{
@@ -51,7 +51,7 @@ void pim_rpf_set_refresh_time(struct pim_instance *pim)
}
bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
- struct in_addr addr, int neighbor_needed)
+ pim_addr addr, int neighbor_needed)
{
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
struct pim_neighbor *nbr = NULL;
@@ -61,6 +61,7 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
int found = 0;
int i = 0;
+#if PIM_IPV == 4
/*
* We should not attempt to lookup a
* 255.255.255.255 address, since
@@ -68,33 +69,27 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
*/
if (addr.s_addr == INADDR_NONE)
return false;
+#endif
- if ((nexthop->last_lookup.s_addr == addr.s_addr)
+ if (!pim_addr_cmp(nexthop->last_lookup, addr)
&& (nexthop->last_lookup_time > pim->last_route_change_time)) {
if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
char nexthop_str[PREFIX_STRLEN];
pim_addr_dump("<nexthop?>", &nexthop->mrib_nexthop_addr,
nexthop_str, sizeof(nexthop_str));
zlog_debug(
- "%s: Using last lookup for %s at %lld, %" PRId64" addr %s",
- __func__, addr_str, nexthop->last_lookup_time,
+ "%s: Using last lookup for %pPAs at %lld, %" PRId64" addr %s",
+ __func__, &addr, nexthop->last_lookup_time,
pim->last_route_change_time, nexthop_str);
}
pim->nexthop_lookups_avoided++;
return true;
} else {
- 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: Looking up: %s, last lookup time: %lld, %" PRId64,
- __func__, addr_str, nexthop->last_lookup_time,
+ "%s: Looking up: %pPAs, last lookup time: %lld, %" PRId64,
+ __func__, &addr, nexthop->last_lookup_time,
pim->last_route_change_time);
- }
}
memset(nexthop_tab, 0,
@@ -102,11 +97,9 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
addr, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn(
- "%s %s: could not find nexthop ifindex for address %s",
- __FILE__, __func__, addr_str);
+ "%s %s: could not find nexthop ifindex for address %pPAs",
+ __FILE__, __func__, &addr);
return false;
}
@@ -115,29 +108,21 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
if (!ifp) {
- if (PIM_DEBUG_ZEBRA) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_ZEBRA)
zlog_debug(
- "%s %s: could not find interface for ifindex %d (address %s)",
+ "%s %s: could not find interface for ifindex %d (address %pPAs)",
__FILE__, __func__, first_ifindex,
- addr_str);
- }
+ &addr);
i++;
continue;
}
if (!ifp->info) {
- if (PIM_DEBUG_ZEBRA) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_ZEBRA)
zlog_debug(
- "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
+ "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
__func__, ifp->name, first_ifindex,
- addr_str);
- }
+ &addr);
i++;
} else if (neighbor_needed
&& !pim_if_connected_to_source(ifp, addr)) {
@@ -157,15 +142,12 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
if (found) {
if (PIM_DEBUG_ZEBRA) {
char nexthop_str[PREFIX_STRLEN];
- char addr_str[INET_ADDRSTRLEN];
pim_addr_dump("<nexthop?>",
&nexthop_tab[i].nexthop_addr, nexthop_str,
sizeof(nexthop_str));
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
zlog_debug(
- "%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
- __FILE__, __func__, nexthop_str, addr_str,
+ "%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,
nexthop_tab[i].protocol_distance);
@@ -187,11 +169,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,
@@ -230,6 +214,8 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
struct prefix src, grp;
bool neigh_needed = true;
uint32_t saved_mrib_route_metric;
+ pim_addr rpf_addr;
+ pim_addr saved_rpf_addr;
if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags))
return PIM_RPF_OK;
@@ -265,8 +251,9 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
return PIM_RPF_FAILURE;
}
- rpf->rpf_addr.family = AF_INET;
- rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
+ rpf_addr = pim_rpf_find_rpf_addr(up);
+ pim_addr_to_prefix(&rpf->rpf_addr, rpf_addr);
+
if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) {
/* RPF'(S,G) not found */
zlog_debug("%s(%s): RPF'%s not found: won't send join upstream",
@@ -313,9 +300,11 @@ 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) {
+
+ saved_rpf_addr = pim_addr_from_prefix(&saved.rpf_addr);
+
+ if (pim_addr_cmp(saved_rpf_addr, rpf_addr) ||
+ saved.source_nexthop.interface != rpf->source_nexthop.interface) {
pim_rpf_cost_change(pim, up, saved_mrib_route_metric);
return PIM_RPF_CHANGED;
}
@@ -343,13 +332,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__);
}
}
@@ -369,18 +358,17 @@ void pim_upstream_rpf_clear(struct pim_instance *pim,
packets should be coming and to which joins should be sent on the RP
tree and SPT, respectively.
*/
-static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
+static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
{
struct pim_ifchannel *rpf_ch;
struct pim_neighbor *neigh;
- struct in_addr rpf_addr;
+ pim_addr rpf_addr;
if (!up->rpf.source_nexthop.interface) {
zlog_warn("%s: missing RPF interface for upstream (S,G)=%s",
__func__, up->sg_str);
- rpf_addr.s_addr = PIM_NET_INADDR_ANY;
- return rpf_addr;
+ return PIMADDR_ANY;
}
rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, &up->sg);
@@ -400,7 +388,7 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
if (neigh)
rpf_addr = neigh->source_addr;
else
- rpf_addr.s_addr = PIM_NET_INADDR_ANY;
+ rpf_addr = PIMADDR_ANY;
return rpf_addr;
}
@@ -420,12 +408,12 @@ int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf)
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;
}
@@ -443,7 +431,12 @@ unsigned int pim_rpf_hash_key(const void *arg)
{
const struct pim_nexthop_cache *r = arg;
+#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK)
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 d6a8880ffb..662fd41a7f 100644
--- a/pimd/pim_rpf.h
+++ b/pimd/pim_rpf.h
@@ -58,7 +58,7 @@ unsigned int pim_rpf_hash_key(const void *arg);
bool pim_rpf_equal(const void *arg1, const void *arg2);
bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
- struct in_addr addr, int neighbor_needed);
+ pim_addr addr, int neighbor_needed);
enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
struct pim_upstream *up,
struct pim_rpf *old, const char *caller);
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
index 45aac7756a..688d38c84c 100644
--- a/pimd/pim_ssm.c
+++ b/pimd/pim_ssm.c
@@ -32,6 +32,7 @@
static void pim_ssm_range_reevaluate(struct pim_instance *pim)
{
+#if PIM_IPV == 4
/* 1. Setup register state for (S,G) entries if G has changed from SSM
* to
* ASM.
@@ -50,6 +51,7 @@ static void pim_ssm_range_reevaluate(struct pim_instance *pim)
*/
pim_upstream_register_reevaluate(pim);
igmp_source_forward_reevaluate_all(pim);
+#endif
}
void pim_ssm_prefix_list_update(struct pim_instance *pim,
diff --git a/pimd/pim_static.c b/pimd/pim_static.c
index be06a25bea..d3b31771a0 100644
--- a/pimd/pim_static.c
+++ b/pimd/pim_static.c
@@ -43,8 +43,8 @@ static struct static_route *static_route_alloc(void)
}
static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif,
- struct in_addr group,
- struct in_addr source)
+ pim_addr group,
+ pim_addr source)
{
struct static_route *s_route;
s_route = static_route_alloc();
@@ -54,10 +54,10 @@ static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif,
s_route->iif = iif;
s_route->oif_ttls[oif] = 1;
s_route->c_oil.oil_ref_count = 1;
- s_route->c_oil.oil.mfcc_origin = source;
- s_route->c_oil.oil.mfcc_mcastgrp = group;
- s_route->c_oil.oil.mfcc_parent = iif;
- s_route->c_oil.oil.mfcc_ttls[oif] = 1;
+ *oil_origin(&s_route->c_oil) = source;
+ *oil_mcastgrp(&s_route->c_oil) = group;
+ *oil_parent(&s_route->c_oil) = iif;
+ oil_if_set(&s_route->c_oil, oif, 1);
s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec();
return s_route;
@@ -65,8 +65,7 @@ static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif,
int pim_static_add(struct pim_instance *pim, struct interface *iif,
- struct interface *oif, struct in_addr group,
- struct in_addr source)
+ struct interface *oif, pim_addr group, pim_addr source)
{
struct listnode *node = NULL;
struct static_route *s_route = NULL;
@@ -97,20 +96,14 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
}
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
- if (s_route->group.s_addr == group.s_addr
- && s_route->source.s_addr == source.s_addr) {
+ if (!pim_addr_cmp(s_route->group, group)
+ && !pim_addr_cmp(s_route->source, source)) {
if (s_route->iif == iif_index
&& s_route->oif_ttls[oif_index]) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_warn(
- "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
+ "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
__FILE__, __func__, iif_index,
- oif_index, gifaddr_str, sifaddr_str);
+ oif_index, &group, &source);
return -3;
}
@@ -130,7 +123,7 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
* adding a new output interface */
if (s_route->iif == iif_index) {
s_route->oif_ttls[oif_index] = 1;
- s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
+ oil_if_set(&s_route->c_oil, oif_index, 1);
s_route->c_oil.oif_creation[oif_index] =
pim_time_monotonic_sec();
++s_route->c_oil.oil_ref_count;
@@ -147,8 +140,8 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
s_route->oif_ttls[iif_index] = 0;
s_route->c_oil.oif_creation[iif_index] =
0;
- s_route->c_oil.oil
- .mfcc_ttls[iif_index] = 0;
+ oil_if_set(&s_route->c_oil, iif_index,
+ 0);
--s_route->c_oil.oil_ref_count;
}
#endif
@@ -158,8 +151,8 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
s_route->oif_ttls[oif_index] = 1;
s_route->c_oil.oif_creation[oif_index] =
pim_time_monotonic_sec();
- s_route->c_oil.oil
- .mfcc_ttls[oif_index] = 1;
+ oil_if_set(&s_route->c_oil, oif_index,
+ 1);
++s_route->c_oil.oil_ref_count;
}
}
@@ -178,16 +171,10 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
s_route->c_oil.pim = pim;
if (pim_static_mroute_add(&s_route->c_oil, __func__)) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_warn(
- "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
- __FILE__, __func__, iif_index, oif_index, gifaddr_str,
- sifaddr_str);
+ "%s %s: Unable to add static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
+ __FILE__, __func__, iif_index, oif_index, &group,
+ &source);
/* Need to put s_route back to the way it was */
if (original_s_route) {
@@ -213,24 +200,17 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
}
if (PIM_DEBUG_STATIC) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_debug(
- "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
- __func__, iif_index, oif_index, gifaddr_str,
- sifaddr_str);
+ "%s: Static route added(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
+ __func__, iif_index, oif_index, &group,
+ &source);
}
return 0;
}
int pim_static_del(struct pim_instance *pim, struct interface *iif,
- struct interface *oif, struct in_addr group,
- struct in_addr source)
+ struct interface *oif, pim_addr group, pim_addr source)
{
struct listnode *node = NULL;
struct listnode *nextnode = NULL;
@@ -249,11 +229,11 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif,
for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) {
if (s_route->iif == iif_index
- && s_route->group.s_addr == group.s_addr
- && s_route->source.s_addr == source.s_addr
+ && !pim_addr_cmp(s_route->group, group)
+ && !pim_addr_cmp(s_route->source, source)
&& s_route->oif_ttls[oif_index]) {
s_route->oif_ttls[oif_index] = 0;
- s_route->c_oil.oil.mfcc_ttls[oif_index] = 0;
+ oil_if_set(&s_route->c_oil, oif_index, 0);
--s_route->c_oil.oil_ref_count;
/* If there are no more outputs then delete the whole
@@ -263,19 +243,13 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif,
? pim_mroute_del(&s_route->c_oil, __func__)
: pim_static_mroute_add(&s_route->c_oil,
__func__)) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_warn(
- "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
+ "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
__FILE__, __func__, iif_index,
- oif_index, gifaddr_str, sifaddr_str);
+ oif_index, &group, &source);
s_route->oif_ttls[oif_index] = 1;
- s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
+ oil_if_set(&s_route->c_oil, oif_index, 1);
++s_route->c_oil.oil_ref_count;
return -1;
@@ -289,16 +263,10 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif,
}
if (PIM_DEBUG_STATIC) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_debug(
- "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
+ "%s: Static route removed(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
__func__, iif_index, oif_index,
- gifaddr_str, sifaddr_str);
+ &group, &source);
}
break;
@@ -306,16 +274,10 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif,
}
if (!node) {
- char gifaddr_str[INET_ADDRSTRLEN];
- char sifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
- sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
- sizeof(sifaddr_str));
zlog_warn(
- "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
- __FILE__, __func__, iif_index, oif_index, gifaddr_str,
- sifaddr_str);
+ "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
+ __FILE__, __func__, iif_index, oif_index, &group,
+ &source);
return -3;
}
@@ -329,15 +291,11 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
struct listnode *node;
struct static_route *sroute;
int count = 0;
- char sbuf[INET_ADDRSTRLEN];
- char gbuf[INET_ADDRSTRLEN];
if (!pim_ifp)
return 0;
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) {
- pim_inet4_dump("<ifaddr?>", sroute->group, gbuf, sizeof(gbuf));
- pim_inet4_dump("<ifaddr?>", sroute->source, sbuf, sizeof(sbuf));
if (sroute->iif == pim_ifp->mroute_vif_index) {
int i;
for (i = 0; i < MAXVIFS; i++)
@@ -345,14 +303,15 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
struct interface *oifp =
pim_if_find_by_vif_index(pim,
i);
- if (sroute->source.s_addr == INADDR_ANY)
+ if (pim_addr_is_any(sroute->source))
vty_out(vty,
- " ip mroute %s %s\n",
- oifp->name, gbuf);
+ " " PIM_AF_NAME " mroute %s %pPA\n",
+ oifp->name, &sroute->group);
else
vty_out(vty,
- " ip mroute %s %s %s\n",
- oifp->name, gbuf, sbuf);
+ " " PIM_AF_NAME " mroute %s %pPA %pPA\n",
+ oifp->name, &sroute->group,
+ &sroute->source);
count++;
}
}
diff --git a/pimd/pim_static.h b/pimd/pim_static.h
index 953ec0a70a..56bfbd4e4f 100644
--- a/pimd/pim_static.h
+++ b/pimd/pim_static.h
@@ -26,8 +26,8 @@
struct static_route {
/* Each static route is unique by these pair of addresses */
- struct in_addr group;
- struct in_addr source;
+ pim_addr group;
+ pim_addr source;
struct channel_oil c_oil;
ifindex_t iif;
@@ -37,11 +37,9 @@ struct static_route {
void pim_static_route_free(struct static_route *s_route);
int pim_static_add(struct pim_instance *pim, struct interface *iif,
- struct interface *oif, struct in_addr group,
- struct in_addr source);
+ struct interface *oif, pim_addr group, pim_addr source);
int pim_static_del(struct pim_instance *pim, struct interface *iif,
- struct interface *oif, struct in_addr group,
- struct in_addr source);
+ struct interface *oif, pim_addr group, pim_addr source);
int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
struct interface *ifp);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index ae62823161..24833f5a63 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -422,8 +422,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 +455,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 +513,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 +832,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 +893,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 +959,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);
}
@@ -1261,7 +1260,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
it so that it expires after t_override seconds.
*/
void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
- struct in_addr neigh_addr)
+ pim_addr neigh_addr)
{
struct pim_upstream *up;
@@ -1269,24 +1268,24 @@ void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
*/
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
- if (PIM_DEBUG_PIM_TRACE) {
- char rpf_addr_str[PREFIX_STRLEN];
- pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
- sizeof(rpf_addr_str));
+ pim_addr rpf_addr;
+
+ rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr);
+
+ if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
- "%s: matching neigh=%pI4 against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
+ "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA",
__func__, &neigh_addr, up->sg_str,
pim->vrf->name,
up->join_state == PIM_UPSTREAM_JOINED,
- rpf_addr_str);
- }
+ &rpf_addr);
/* consider only (S,G) upstream in Joined state */
if (up->join_state != PIM_UPSTREAM_JOINED)
continue;
/* match RPF'(S,G)=neigh_addr */
- if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
+ if (pim_addr_cmp(rpf_addr, neigh_addr))
continue;
pim_upstream_join_timer_decrease_to_t_override(
@@ -1992,7 +1991,7 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
return false;
pim_ifp = ifp->info;
- if (pim_ifp->mroute_vif_index != c_oil->oil.mfcc_parent)
+ if (pim_ifp->mroute_vif_index != *oil_parent(c_oil))
return false;
if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index 25ff3bffe7..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);
@@ -326,7 +326,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
void pim_upstream_join_timer_restart(struct pim_upstream *up,
struct pim_rpf *old);
void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
- struct in_addr neigh_addr);
+ pim_addr neigh_addr);
void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
struct interface *old_rpf_ifp);
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 8130aac872..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,142 +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 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;
- }
- }
-
- 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 8be930aeb4..0acd3c0694 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -55,6 +55,7 @@ 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;
@@ -64,6 +65,7 @@ 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;
@@ -112,7 +114,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
struct connected *c;
struct prefix *p;
struct pim_interface *pim_ifp;
- struct pim_instance *pim;
/*
zebra api notifies address adds/dels events by using the same call
@@ -141,6 +142,7 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
#endif
}
+#if PIM_IPV == 4
if (p->family != PIM_AF)
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
@@ -159,6 +161,8 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
pim_if_addr_add(c);
if (pim_ifp) {
+ struct pim_instance *pim;
+
pim = pim_get_pim_instance(vrf_id);
pim_ifp->pim = pim;
@@ -174,7 +178,10 @@ 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;
}
@@ -183,11 +190,9 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
struct connected *c;
struct prefix *p;
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
- struct pim_instance *pim;
if (!vrf)
return 0;
- pim = vrf->info;
/*
zebra api notifies address adds/dels events by using the same call
@@ -202,24 +207,29 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
return 0;
p = c->address;
- if (p->family == AF_INET) {
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug(
- "%s: %s(%u) disconnected IP address %pFX flags %u %s",
- __func__, c->ifp->name, vrf_id, p, c->flags,
- CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
- ? "secondary"
- : "primary");
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug(
+ "%s: %s(%u) disconnected IP address %pFX flags %u %s",
+ __func__, c->ifp->name, vrf_id, p, c->flags,
+ CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
+ ? "secondary"
+ : "primary");
#ifdef PIM_DEBUG_IFADDR_DUMP
- dump_if_address(c->ifp);
+ dump_if_address(c->ifp);
#endif
- }
+ }
+
+#if PIM_IPV == 4
+ if (p->family == AF_INET) {
+ struct pim_instance *pim;
+ pim = vrf->info;
pim_if_addr_del(c, 0);
pim_rp_setup(pim);
pim_i_am_rp_re_evaluate(pim);
}
+#endif
connected_free(&c);
return 0;
@@ -242,7 +252,7 @@ void pim_zebra_update_all_interfaces(struct pim_instance *pim)
struct pim_rpf rpf;
rpf.source_nexthop.interface = ifp;
- rpf.rpf_addr.u.prefix4 = us->address;
+ pim_addr_to_prefix(&rpf.rpf_addr, us->address);
pim_joinprune_send(&rpf, us->us);
pim_jp_agg_clear_group(us->us);
}
@@ -325,6 +335,7 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
pim_upstream_update_join_desired(pim, up);
}
+__attribute__((unused))
static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
{
struct stream *s;
@@ -354,6 +365,7 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
return 0;
}
+__attribute__((unused))
static void pim_zebra_vxlan_replay(void)
{
struct stream *s = NULL;
@@ -421,13 +433,17 @@ void sched_rpf_cache_refresh(struct pim_instance *pim)
static void pim_zebra_connected(struct zclient *zclient)
{
+#if PIM_IPV == 4
/* Send the client registration */
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
+#endif
zclient_send_reg_requests(zclient, router->vrf_id);
+#if PIM_IPV == 4
/* request for VxLAN BUM group addresses */
pim_zebra_vxlan_replay();
+#endif
}
static void pim_zebra_capabilities(struct zclient_capabilities *cap)
@@ -436,9 +452,10 @@ static void pim_zebra_capabilities(struct zclient_capabilities *cap)
}
static zclient_handler *const pim_handlers[] = {
- [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
[ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
[ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
+#if PIM_IPV == 4
+ [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
[ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
[ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
@@ -448,6 +465,7 @@ static zclient_handler *const pim_handlers[] = {
[ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up,
[ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down,
[ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg,
+#endif
};
void pim_zebra_init(void)
@@ -467,6 +485,7 @@ 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)
{
@@ -793,6 +812,7 @@ void igmp_source_forward_stop(struct gm_source *source)
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
}
+#endif /* PIM_IPV == 4 */
void pim_forward_start(struct pim_ifchannel *ch)
{
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index 3cdf596ae2..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;
@@ -394,7 +395,7 @@ void zclient_lookup_read_pipe(struct thread *thread)
int zclient_lookup_nexthop(struct pim_instance *pim,
struct pim_zlookup_nexthop nexthop_tab[],
- const int tab_size, struct in_addr addr,
+ const int tab_size, pim_addr addr,
int max_lookup)
{
int lookup;
@@ -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/pim_zlookup.h b/pimd/pim_zlookup.h
index 09e8dcd51f..c3818dbdbc 100644
--- a/pimd/pim_zlookup.h
+++ b/pimd/pim_zlookup.h
@@ -39,7 +39,7 @@ void zclient_lookup_free(void);
int zclient_lookup_nexthop(struct pim_instance *pim,
struct pim_zlookup_nexthop nexthop_tab[],
- const int tab_size, struct in_addr addr,
+ const int tab_size, pim_addr addr,
int max_lookup);
void pim_zlookup_show_ip_multicast(struct vty *vty);
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 6c267f290c..0fe40912b1 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
@@ -18,32 +22,23 @@ pim_common = \
pimd/pim_bfd.c \
pimd/pim_br.c \
pimd/pim_bsm.c \
- pimd/pim_cmd.c \
+ pimd/pim_cmd_common.c \
pimd/pim_errors.c \
pimd/pim_hello.c \
pimd/pim_iface.c \
pimd/pim_ifchannel.c \
- pimd/pim_igmp.c \
- pimd/pim_igmp_mtrace.c \
- pimd/pim_igmp_stats.c \
- pimd/pim_igmpv2.c \
- pimd/pim_igmpv3.c \
pimd/pim_instance.c \
pimd/pim_int.c \
pimd/pim_join.c \
pimd/pim_jp_agg.c \
pimd/pim_macro.c \
pimd/pim_memory.c \
- pimd/pim_mlag.c \
pimd/pim_mroute.c \
pimd/pim_msg.c \
pimd/pim_nb.c \
pimd/pim_nb_config.c \
pimd/pim_neighbor.c \
- pimd/pim_nht.c \
pimd/pim_oil.c \
- pimd/pim_pim.c \
- pimd/pim_register.c \
pimd/pim_routemap.c \
pimd/pim_rp.c \
pimd/pim_rpf.c \
@@ -58,19 +53,29 @@ pim_common = \
pimd/pim_util.c \
pimd/pim_vty.c \
pimd/pim_zebra.c \
- pimd/pim_zlookup.c \
pimd/pim_vxlan.c \
- pimd/pim_zpthread.c \
pimd/pimd.c \
# end
pimd_pimd_SOURCES = \
$(pim_common) \
+ pimd/pim_cmd.c \
+ pimd/pim_igmp.c \
+ pimd/pim_igmp_mtrace.c \
+ pimd/pim_igmp_stats.c \
+ pimd/pim_igmpv2.c \
+ pimd/pim_igmpv3.c \
pimd/pim_main.c \
+ pimd/pim_mlag.c \
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 \
+ pimd/pim_zlookup.c \
+ pimd/pim_zpthread.c \
# end
nodist_pimd_pimd_SOURCES = \
@@ -82,9 +87,14 @@ nodist_pimd_pimd_SOURCES = \
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 += \
@@ -94,6 +104,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 \
@@ -142,10 +153,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
@@ -158,7 +171,7 @@ if DEV_BUILD
# (change noinst_ to sbin_ below to install it.)
#
noinst_PROGRAMS += pimd/pim6d
-pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6 $(and $(PIM_V6_TEMP_BREAK),-DPIM_V6_TEMP_BREAK)
+pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
endif
endif
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_vty.c b/sharpd/sharp_vty.c
index ceed9cf739..78cc57cc44 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -540,7 +540,7 @@ DEFPY(vrf_label, vrf_label_cmd,
vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
- vty_out(vty, "Unable to find vrf you silly head");
+ vty_out(vty, "Unable to find vrf you silly head\n");
return CMD_WARNING_CONFIG_FAILED;
}
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..f937492ec2 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)
@@ -302,12 +303,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 +326,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/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/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..4e5fe4c90b 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):
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/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..f8c6a1fc1d 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,14 @@ struct vtysh_client {
int flag;
char path[MAXPATHLEN];
struct vtysh_client *next;
+
+ struct thread *log_reader;
+ int log_fd;
};
+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 +133,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 +189,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 +259,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 +294,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 +439,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 +1636,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 +2774,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 +3530,283 @@ 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 (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.arghdrlen = 0;
+ buf.hdr.n_argpos = 0;
+ }
+
+ if (stderr_stdout_same) {
+#ifdef HAVE_RL_CLEAR_VISIBLE_LINE
+ rl_clear_visible_line();
+#else
+ puts("\r");
+#endif
+ fflush(stdout);
+ }
+
+ 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 +4314,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 +4822,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 +4870,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/zebra/debug_nl.c b/zebra/debug_nl.c
index 825497fff3..260ba30b3c 100644
--- a/zebra/debug_nl.c
+++ b/zebra/debug_nl.c
@@ -20,6 +20,7 @@
#include <sys/socket.h>
+#include <linux/netconf.h>
#include <linux/netlink.h>
#include <linux/nexthop.h>
#include <linux/rtnetlink.h>
@@ -90,6 +91,11 @@ const char *nlmsg_type2str(uint16_t type)
case RTM_GETNEXTHOP:
return "GETNEXTHOP";
+ case RTM_NEWNETCONF:
+ return "RTM_NEWNETCONF";
+ case RTM_DELNETCONF:
+ return "RTM_DELNETCONF";
+
default:
return "UNKNOWN";
}
@@ -657,6 +663,37 @@ const char *frh_action2str(uint8_t action)
}
}
+static const char *ncm_rta2str(int type)
+{
+ switch (type) {
+ case NETCONFA_UNSPEC:
+ return "UNSPEC";
+ case NETCONFA_IFINDEX:
+ return "IFINDEX";
+ case NETCONFA_FORWARDING:
+ return "FORWARDING";
+ case NETCONFA_RP_FILTER:
+ return "RP_FILTER";
+ case NETCONFA_MC_FORWARDING:
+ return "MCAST";
+ case NETCONFA_PROXY_NEIGH:
+ return "PROXY_NEIGH";
+ case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
+ return "IGNORE_LINKDOWN";
+ case NETCONFA_INPUT:
+ return "MPLS";
+ case NETCONFA_BC_FORWARDING:
+ return "BCAST";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static void dump_on_off(uint32_t ival, const char *prefix)
+{
+ zlog_debug("%s%s", prefix, (ival != 0) ? "on" : "off");
+}
+
static inline void flag_write(int flags, int flag, const char *flagstr,
char *buf, size_t buflen)
{
@@ -1118,6 +1155,7 @@ static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
struct nexthop_grp *nhgrp;
rta = RTM_NHA(nhm);
+
next_rta:
/* Check the header for valid length and for outbound access. */
if (RTA_OK(rta, msglen) == 0)
@@ -1296,6 +1334,52 @@ next_rta:
goto next_rta;
}
+static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen)
+{
+ const struct rtattr *rta;
+ size_t plen;
+ uint32_t ival;
+
+ rta = (void *)((const char *)ncm +
+ NLMSG_ALIGN(sizeof(struct netconfmsg)));
+
+next_rta:
+ /* Check the attr header for valid length. */
+ if (RTA_OK(rta, msglen) == 0)
+ return;
+
+ plen = RTA_PAYLOAD(rta);
+
+ zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+ plen, rta->rta_type, ncm_rta2str(rta->rta_type));
+
+ switch (rta->rta_type) {
+ case NETCONFA_IFINDEX:
+ ival = *(uint32_t *)RTA_DATA(rta);
+ zlog_debug(" %d", (int32_t)ival);
+ break;
+
+ /* Most attrs are just on/off. */
+ case NETCONFA_FORWARDING:
+ case NETCONFA_RP_FILTER:
+ case NETCONFA_MC_FORWARDING:
+ case NETCONFA_PROXY_NEIGH:
+ case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
+ case NETCONFA_INPUT:
+ case NETCONFA_BC_FORWARDING:
+ ival = *(uint32_t *)RTA_DATA(rta);
+ dump_on_off(ival, " ");
+ break;
+ default:
+ /* NOTHING: unhandled. */
+ break;
+ }
+
+ /* Get next pointer and start iteration again. */
+ rta = RTA_NEXT(rta, msglen);
+ goto next_rta;
+}
+
void nl_dump(void *msg, size_t msglen)
{
struct nlmsghdr *nlmsg = msg;
@@ -1305,6 +1389,7 @@ void nl_dump(void *msg, size_t msglen)
struct ndmsg *ndm;
struct rtmsg *rtm;
struct nhmsg *nhm;
+ struct netconfmsg *ncm;
struct ifinfomsg *ifi;
struct fib_rule_hdr *frh;
char fbuf[128];
@@ -1422,6 +1507,14 @@ next_header:
nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm)));
break;
+ case RTM_NEWNETCONF:
+ case RTM_DELNETCONF:
+ ncm = NLMSG_DATA(nlmsg);
+ zlog_debug(" ncm [family=%s (%d)]",
+ af_type2str(ncm->ncm_family), ncm->ncm_family);
+ nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm)));
+ break;
+
default:
break;
}
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index ce3c8d4b11..8c8004190b 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -780,6 +780,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
nl_buf_len += (size_t)rv;
break;
+ /* Un-handled by FPM at this time. */
case DPLANE_OP_PW_INSTALL:
case DPLANE_OP_PW_UNINSTALL:
case DPLANE_OP_ADDR_INSTALL:
@@ -793,15 +794,27 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
case DPLANE_OP_SYS_ROUTE_DELETE:
case DPLANE_OP_ROUTE_NOTIFY:
case DPLANE_OP_LSP_NOTIFY:
+ case DPLANE_OP_RULE_ADD:
+ case DPLANE_OP_RULE_DELETE:
+ case DPLANE_OP_RULE_UPDATE:
+ case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_IPTABLE_ADD:
+ case DPLANE_OP_IPTABLE_DELETE:
+ case DPLANE_OP_IPSET_ADD:
+ case DPLANE_OP_IPSET_DELETE:
+ case DPLANE_OP_IPSET_ENTRY_ADD:
+ case DPLANE_OP_IPSET_ENTRY_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ case DPLANE_OP_GRE_SET:
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_NONE:
break;
- default:
- if (IS_ZEBRA_DEBUG_FPM)
- zlog_debug("%s: unhandled data plane message (%d) %s",
- __func__, dplane_ctx_get_op(ctx),
- dplane_op2str(dplane_ctx_get_op(ctx)));
- break;
}
/* Skip empty enqueues. */
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 141e4074d5..db8ee3236c 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -74,6 +74,7 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_l2.h"
+#include "zebra/netconf_netlink.h"
extern struct zebra_privs_t zserv_privs;
@@ -1001,6 +1002,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Hardware type and address. */
ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type);
+
netlink_interface_update_hw_addr(tb, ifp);
if_add_update(ifp);
diff --git a/zebra/interface.c b/zebra/interface.c
index 5d1080fd72..fbd2aac005 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);
@@ -1318,6 +1336,56 @@ done:
dplane_ctx_fini(&ctx);
}
+/*
+ * Handle netconf change from a dplane context object; runs in the main
+ * pthread so it can update zebra data structs.
+ */
+int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx)
+{
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ struct zebra_if *zif;
+ enum dplane_netconf_status_e mpls;
+ int ret = 0;
+
+ zns = zebra_ns_lookup(dplane_ctx_get_netconf_ns_id(ctx));
+ if (zns == NULL) {
+ ret = -1;
+ goto done;
+ }
+
+ ifp = if_lookup_by_index_per_ns(zns,
+ dplane_ctx_get_netconf_ifindex(ctx));
+ if (ifp == NULL) {
+ ret = -1;
+ goto done;
+ }
+
+ zif = ifp->info;
+ if (zif == NULL) {
+ ret = -1;
+ goto done;
+ }
+
+ mpls = dplane_ctx_get_netconf_mpls(ctx);
+
+ if (mpls == DPLANE_NETCONF_STATUS_ENABLED)
+ zif->mpls = true;
+ else if (mpls == DPLANE_NETCONF_STATUS_DISABLED)
+ zif->mpls = false;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: if %s, ifindex %d, mpls %s",
+ __func__, ifp->name, ifp->ifindex,
+ (zif->mpls ? "ON" : "OFF"));
+
+done:
+ /* Free the context */
+ dplane_ctx_fini(&ctx);
+
+ return ret;
+}
+
/* Dump if address information to vty. */
static void connected_dump_vty(struct vty *vty, json_object *json,
struct connected *connected)
@@ -1670,6 +1738,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
vty_out(vty, "mtu6 %d ", ifp->mtu6);
vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags));
+ if (zebra_if->mpls)
+ vty_out(vty, " MPLS enabled\n");
+
/* Hardware address. */
vty_out(vty, " Type: %s\n", if_link_type_str(ifp->ll_type));
if (ifp->hw_addr_len != 0) {
@@ -1990,6 +2061,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
json_object_string_add(json_if, "OsDescription",
zebra_if->desc);
+ json_object_boolean_add(json_if, "mplsEnabled", zebra_if->mpls);
+
if (ifp->ifindex == IFINDEX_INTERNAL) {
json_object_boolean_add(json_if, "pseudoInterface", true);
return;
diff --git a/zebra/interface.h b/zebra/interface.h
index 413a67469a..c19e494860 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -329,6 +329,9 @@ struct zebra_if {
/* Multicast configuration. */
uint8_t multicast;
+ /* MPLS status. */
+ bool mpls;
+
/* Router advertise configuration. */
uint8_t rtadv_enable;
@@ -409,6 +412,7 @@ struct zebra_if {
ifindex_t link_ifindex;
struct interface *link;
+ uint8_t speed_update_count;
struct thread *speed_update;
/*
@@ -520,6 +524,7 @@ extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif);
extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
char *pd_buf, uint32_t pd_buf_len);
void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
+int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx);
#ifdef HAVE_PROC_NET_DEV
extern void ifstat_update_proc(void);
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 23e7098d04..d84b0c1325 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -38,7 +38,6 @@
#include "lib_errors.h"
#include "hash.h"
-//#include "zebra/zserv.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
@@ -48,6 +47,7 @@
#include "zebra/rt_netlink.h"
#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
+#include "zebra/netconf_netlink.h"
#include "zebra/zebra_errors.h"
#ifndef SO_RCVBUFFORCE
@@ -108,6 +108,8 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"},
{RTM_DELNEXTHOP, "RTM_DELNEXTHOP"},
{RTM_GETNEXTHOP, "RTM_GETNEXTHOP"},
+ {RTM_NEWNETCONF, "RTM_NEWNETCONF"},
+ {RTM_DELNETCONF, "RTM_DELNETCONF"},
{0}};
static const struct message rtproto_str[] = {
@@ -153,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;
@@ -259,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,
@@ -373,6 +373,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
/* Messages handled in the dplane thread */
case RTM_NEWADDR:
case RTM_DELADDR:
+ case RTM_NEWNETCONF:
+ case RTM_DELNETCONF:
return 0;
default:
@@ -407,7 +409,12 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
case RTM_DELADDR:
return netlink_interface_addr_dplane(h, ns_id, startup);
- /* TODO */
+ case RTM_NEWNETCONF:
+ case RTM_DELNETCONF:
+ return netlink_netconf_change(h, ns_id, startup);
+
+ /* TODO -- other messages for the dplane socket and pthread */
+
case RTM_NEWLINK:
case RTM_DELLINK:
@@ -456,8 +463,8 @@ int kernel_dplane_read(struct zebra_dplane_info *info)
* then the normal course of operations). We are intentionally
* allowing some messages from ourselves through
* ( I'm looking at you Interface based netlink messages )
- * so that we only had to write one way to handle incoming
- * address add/delete changes.
+ * so that we only have to write one way to handle incoming
+ * address add/delete and xxxNETCONF changes.
*/
static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
{
@@ -473,7 +480,8 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
* if (nlmsg_pid == pid ||
* nlmsg_pid == dplane_pid) {
* if (the incoming nlmsg_type ==
- * RTM_NEWADDR | RTM_DELADDR)
+ * RTM_NEWADDR || RTM_DELADDR || RTM_NEWNETCONF ||
+ * RTM_DELNETCONF)
* keep this message
* else
* skip this message
@@ -492,7 +500,7 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
/*
* 2: Compare to dplane pid
*/
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 4),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 6),
/*
* 3: Load the nlmsg_type into BPF register
*/
@@ -501,17 +509,27 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
/*
* 4: Compare to RTM_NEWADDR
*/
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 4, 0),
/*
* 5: Compare to RTM_DELADDR
*/
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 3, 0),
+ /*
+ * 6: Compare to RTM_NEWNETCONF
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWNETCONF), 2,
+ 0),
/*
- * 6: This is the end state of we want to skip the
+ * 7: Compare to RTM_DELNETCONF
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELNETCONF), 1,
+ 0),
+ /*
+ * 8: This is the end state of we want to skip the
* message
*/
BPF_STMT(BPF_RET | BPF_K, 0),
- /* 7: This is the end state of we want to keep
+ /* 9: This is the end state of we want to keep
* the message
*/
BPF_STMT(BPF_RET | BPF_K, 0xffff),
@@ -1470,6 +1488,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
+ case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR;
}
@@ -1597,7 +1616,11 @@ void kernel_init(struct zebra_ns *zns)
dplane_groups = (RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
- RTMGRP_IPV6_IFADDR);
+ RTMGRP_IPV6_IFADDR |
+ ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_IPV6_NETCONF - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1)));
+
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
@@ -1707,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/netconf_netlink.c b/zebra/netconf_netlink.c
new file mode 100644
index 0000000000..587f6c749e
--- /dev/null
+++ b/zebra/netconf_netlink.c
@@ -0,0 +1,175 @@
+/*
+ * netconf_netlink.c - netconf interaction with the kernel using
+ * netlink
+ * Copyright (C) 2021 Nvidia, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#ifdef HAVE_NETLINK /* Netlink OSes only */
+
+#include <ns.h>
+
+#include "linux/netconf.h"
+
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/kernel_netlink.h"
+#include "zebra/netconf_netlink.h"
+#include "zebra/debug.h"
+
+static struct rtattr *netconf_rta(struct netconfmsg *ncm)
+{
+ return (struct rtattr *)((char *)ncm +
+ NLMSG_ALIGN(sizeof(struct netconfmsg)));
+}
+
+/*
+ * Handle netconf update about a single interface: create dplane
+ * context, and enqueue for processing in the main zebra pthread.
+ */
+static int netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex,
+ enum dplane_netconf_status_e mpls_on,
+ enum dplane_netconf_status_e mcast_on)
+{
+ struct zebra_dplane_ctx *ctx;
+
+ ctx = dplane_ctx_alloc();
+ dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
+ dplane_ctx_set_netconf_ns_id(ctx, ns_id);
+ dplane_ctx_set_netconf_ifindex(ctx, ifindex);
+
+ dplane_ctx_set_netconf_mpls(ctx, mpls_on);
+ dplane_ctx_set_netconf_mcast(ctx, mcast_on);
+
+ /* Enqueue ctx for main pthread to process */
+ dplane_provider_enqueue_to_zebra(ctx);
+
+ return 0;
+}
+
+/*
+ * Parse and process an incoming netlink netconf update.
+ */
+int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
+{
+ struct netconfmsg *ncm;
+ struct rtattr *tb[NETCONFA_MAX + 1] = {};
+ int len;
+ ifindex_t ifindex;
+ uint32_t ival;
+ enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
+ enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
+
+ if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg));
+ if (len < 0) {
+ zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu",
+ __func__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg)));
+ return -1;
+ }
+
+ ncm = NLMSG_DATA(h);
+
+ netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
+
+ if (!tb[NETCONFA_IFINDEX]) {
+ zlog_err("NETCONF message received from netlink without an ifindex");
+ return 0;
+ }
+
+ ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
+
+ switch (ifindex) {
+ case NETCONFA_IFINDEX_ALL:
+ case NETCONFA_IFINDEX_DEFAULT:
+ /*
+ * We need the ability to handle netlink messages intended
+ * for all and default interfaces. I am not 100% sure
+ * what that is yet, or where we would store it.
+ */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: Ignoring global ifindex %d",
+ __func__, ifindex);
+
+ return 0;
+ default:
+ break;
+ }
+
+ if (tb[NETCONFA_INPUT]) {
+ ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
+ if (ival != 0)
+ mpls_on = DPLANE_NETCONF_STATUS_ENABLED;
+ else
+ mpls_on = DPLANE_NETCONF_STATUS_DISABLED;
+ }
+
+ if (tb[NETCONFA_MC_FORWARDING]) {
+ ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]);
+ if (ival != 0)
+ mcast_on = DPLANE_NETCONF_STATUS_ENABLED;
+ else
+ mcast_on = DPLANE_NETCONF_STATUS_DISABLED;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: interface %u is mpls on: %d multicast on: %d",
+ __func__, ifindex, mpls_on, mcast_on);
+
+ /* Create a dplane context and pass it along for processing */
+ netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on);
+
+ return 0;
+}
+
+/*
+ * Request info from the host OS. This only sends the request; any replies
+ * are processed asynchronously.
+ */
+int netlink_request_netconf(int sockfd)
+{
+ struct nlsock *nls;
+ struct {
+ struct nlmsghdr n;
+ struct netconfmsg ncm;
+ char buf[1024];
+ } req = {};
+
+ nls = kernel_netlink_nlsock_lookup(sockfd);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL");
+
+ if (nls == NULL)
+ return -1;
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg));
+ req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETNETCONF;
+ req.ncm.ncm_family = AF_UNSPEC;
+
+ return netlink_request(nls, &req);
+}
+
+#endif /* HAVE_NETLINK */
diff --git a/zebra/netconf_netlink.h b/zebra/netconf_netlink.h
new file mode 100644
index 0000000000..3f2e7af768
--- /dev/null
+++ b/zebra/netconf_netlink.h
@@ -0,0 +1,48 @@
+/*
+ * netconf_netlink.h - netconf interaction with the kernel using
+ * netlink
+ * Copyright (C) 2021 Nvidia, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef __NETCONF_NETLINK_H__
+#define __NETCONF_NETLINK_H__
+
+#ifdef HAVE_NETLINK /* Netlink-only module */
+
+#include "zebra/zebra_ns.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Parse and handle a NETCONF message. */
+extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id,
+ int startup);
+/* Request info from the host OS. */
+int netlink_request_netconf(int sockfd);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAVE_NETLINK */
+
+#endif /* NETCONF_NETLINK_H */
diff --git a/zebra/subdir.am b/zebra/subdir.am
index f0cc6ce71b..77e0898d81 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -69,6 +69,7 @@ zebra_zebra_SOURCES = \
zebra/kernel_socket.c \
zebra/label_manager.c \
zebra/main.c \
+ zebra/netconf_netlink.c \
zebra/redistribute.c \
zebra/router-id.c \
zebra/rt_netlink.c \
@@ -148,6 +149,7 @@ noinst_HEADERS += \
zebra/kernel_netlink.h \
zebra/kernel_socket.h \
zebra/label_manager.h \
+ zebra/netconf_netlink.h \
zebra/redistribute.h \
zebra/rib.h \
zebra/router-id.h \
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 1967345d22..6de2be3ab8 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -28,6 +28,7 @@
#include "lib/memory.h"
#include "lib/queue.h"
#include "lib/zebra.h"
+#include "zebra/netconf_netlink.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_vxlan_private.h"
@@ -290,6 +291,19 @@ struct dplane_gre_ctx {
unsigned int mtu;
struct zebra_l2info_gre info;
};
+
+
+/*
+ * Network interface configuration info - aligned with netlink's NETCONF
+ * info. The flags values are public, in the dplane.h file...
+ */
+struct dplane_netconf_info {
+ ns_id_t ns_id;
+ ifindex_t ifindex;
+ enum dplane_netconf_status_e mpls_val;
+ enum dplane_netconf_status_e mcast_val;
+};
+
/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
@@ -347,6 +361,7 @@ struct zebra_dplane_ctx {
} ipset_entry;
struct dplane_neigh_table neightable;
struct dplane_gre_ctx gre;
+ struct dplane_netconf_info netconf;
} u;
/* Namespace info, used especially for netlink kernel communication */
@@ -416,6 +431,9 @@ PREDECL_DLIST(zns_info_list);
struct dplane_zns_info {
struct zebra_dplane_info info;
+ /* Request data from the OS */
+ struct thread *t_request;
+
/* Read event */
struct thread *t_read;
@@ -540,8 +558,6 @@ DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
/* Prototypes */
static void dplane_thread_loop(struct thread *event);
-static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
- struct zebra_ns *zns);
static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp,
enum dplane_op_e op);
static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
@@ -769,6 +785,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
}
break;
case DPLANE_OP_GRE_SET:
+ case DPLANE_OP_INTF_NETCONFIG:
break;
}
}
@@ -1053,6 +1070,9 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_INTF_ADDR_DEL:
return "INTF_ADDR_DEL";
+
+ case DPLANE_OP_INTF_NETCONFIG:
+ return "INTF_NETCONFIG";
}
return ret;
@@ -2239,6 +2259,10 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr)
return ptr->status;
}
+/*
+ * End of interface extra info accessors
+ */
+
uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -2270,9 +2294,66 @@ dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx)
return ctx->u.neightable.mcast_probes;
}
-/*
- * End of interface extra info accessors
- */
+ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.netconf.ifindex;
+}
+
+ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.netconf.ns_id;
+}
+
+void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx,
+ ifindex_t ifindex)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.netconf.ifindex = ifindex;
+}
+
+void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.netconf.ns_id = ns_id;
+}
+
+enum dplane_netconf_status_e
+dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.netconf.mpls_val;
+}
+
+enum dplane_netconf_status_e
+dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.netconf.mcast_val;
+}
+
+void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx,
+ enum dplane_netconf_status_e val)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.netconf.mpls_val = val;
+}
+
+void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx,
+ enum dplane_netconf_status_e val)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.netconf.mcast_val = val;
+}
/*
* Retrieve the limit on the number of pending, unprocessed updates.
@@ -2306,13 +2387,29 @@ uint32_t dplane_get_in_queue_len(void)
}
/*
+ * Internal helper that copies information from a zebra ns object; this is
+ * called in the zebra main pthread context as part of dplane ctx init.
+ */
+static void ctx_info_from_zns(struct zebra_dplane_info *ns_info,
+ struct zebra_ns *zns)
+{
+ ns_info->ns_id = zns->ns_id;
+
+#if defined(HAVE_NETLINK)
+ ns_info->is_cmd = true;
+ ns_info->sock = zns->netlink_dplane_out.sock;
+ ns_info->seq = zns->netlink_dplane_out.seq;
+#endif /* NETLINK */
+}
+
+/*
* Common dataplane context init with zebra namespace info.
*/
static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
struct zebra_ns *zns,
bool is_update)
{
- dplane_info_from_zns(&(ctx->zd_ns_info), zns);
+ ctx_info_from_zns(&(ctx->zd_ns_info), zns); /* */
ctx->zd_is_update = is_update;
@@ -4844,21 +4941,6 @@ bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov)
return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED);
}
-/*
- * Internal helper that copies information from a zebra ns object; this is
- * called in the zebra main pthread context as part of dplane ctx init.
- */
-static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
- struct zebra_ns *zns)
-{
- ns_info->ns_id = zns->ns_id;
-
-#if defined(HAVE_NETLINK)
- ns_info->is_cmd = true;
- ns_info->sock = zns->netlink_dplane_out.sock;
-#endif /* NETLINK */
-}
-
#ifdef HAVE_NETLINK
/*
* Callback when an OS (netlink) incoming event read is ready. This runs
@@ -4874,6 +4956,40 @@ static void dplane_incoming_read(struct thread *event)
thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
zi->info.sock, &zi->t_read);
}
+
+/*
+ * Callback in the dataplane pthread that requests info from the OS and
+ * initiates netlink reads.
+ */
+static void dplane_incoming_request(struct thread *event)
+{
+ struct dplane_zns_info *zi = THREAD_ARG(event);
+
+ /* Start read task */
+ thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
+ zi->info.sock, &zi->t_read);
+
+ /* Send requests */
+ netlink_request_netconf(zi->info.sock);
+}
+
+/*
+ * Initiate requests for existing info from the OS. This is called by the
+ * main pthread, but we want all activity on the dplane netlink socket to
+ * take place on the dplane pthread, so we schedule an event to accomplish
+ * that.
+ */
+static void dplane_kernel_info_request(struct dplane_zns_info *zi)
+{
+ /* If we happen to encounter an enabled zns before the dplane
+ * pthread is running, we'll initiate this later on.
+ */
+ if (zdplane_info.dg_master)
+ thread_add_event(zdplane_info.dg_master,
+ dplane_incoming_request, zi, 0,
+ &zi->t_request);
+}
+
#endif /* HAVE_NETLINK */
/*
@@ -4917,11 +5033,10 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
zi->info.is_cmd = false;
zi->info.sock = zns->netlink_dplane_in.sock;
- /* Start read task for the dplane pthread. */
- if (zdplane_info.dg_master)
- thread_add_read(zdplane_info.dg_master,
- dplane_incoming_read, zi, zi->info.sock,
- &zi->t_read);
+ /* Initiate requests for existing info from the OS, and
+ * begin reading from the netlink socket.
+ */
+ dplane_kernel_info_request(zi);
#endif
} else if (zi) {
if (IS_ZEBRA_DEBUG_DPLANE)
@@ -4931,9 +5046,14 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
/* Stop reading, free memory */
zns_info_list_del(&zdplane_info.dg_zns_list, zi);
- if (zdplane_info.dg_master)
+ /* Stop any outstanding tasks */
+ if (zdplane_info.dg_master) {
+ thread_cancel_async(zdplane_info.dg_master,
+ &zi->t_request, NULL);
+
thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
NULL);
+ }
XFREE(MTYPE_DP_NS, zi);
}
@@ -5113,6 +5233,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_ifname(ctx),
dplane_ctx_get_intf_addr(ctx));
break;
+
+ case DPLANE_OP_INTF_NETCONFIG:
+ zlog_debug("%s: ifindex %d, mpls %d, mcast %d",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_netconf_ifindex(ctx),
+ dplane_ctx_get_netconf_mpls(ctx),
+ dplane_ctx_get_netconf_mcast(ctx));
+ break;
}
}
@@ -5258,6 +5386,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
/* TODO -- error counters for incoming events? */
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
+ case DPLANE_OP_INTF_NETCONFIG:
break;
case DPLANE_OP_NONE:
@@ -5604,8 +5733,10 @@ static void dplane_check_shutdown_status(struct thread *event)
frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
zns_info_list_del(&zdplane_info.dg_zns_list, zi);
- if (zdplane_info.dg_master)
+ if (zdplane_info.dg_master) {
thread_cancel(&zi->t_read);
+ thread_cancel(&zi->t_request);
+ }
XFREE(MTYPE_DP_NS, zi);
}
@@ -5935,11 +6066,12 @@ void zebra_dplane_start(void)
thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
&zdplane_info.dg_t_update);
- /* Enqueue reads if necessary */
+ /* Enqueue requests and reads if necessary */
frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
#if defined(HAVE_NETLINK)
thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
zi, zi->info.sock, &zi->t_read);
+ dplane_kernel_info_request(zi);
#endif
}
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index a7a5f99e45..29555d5b56 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -185,6 +185,9 @@ enum dplane_op_e {
/* Incoming interface address events */
DPLANE_OP_INTF_ADDR_ADD,
DPLANE_OP_INTF_ADDR_DEL,
+
+ /* Incoming interface config events */
+ DPLANE_OP_INTF_NETCONFIG,
};
/*
@@ -222,6 +225,22 @@ enum dplane_op_e {
#define DPLANE_BR_PORT_NON_DF (1 << 0)
+/* Definitions for the dplane 'netconf' apis, corresponding to the netlink
+ * NETCONF api.
+ * Sadly, netlink sends incremental updates, so its messages may contain
+ * just a single changed attribute, and not necessarily
+ * a complete snapshot of the attributes.
+ */
+enum dplane_netconf_status_e {
+ DPLANE_NETCONF_STATUS_UNKNOWN = 0,
+ DPLANE_NETCONF_STATUS_ENABLED,
+ DPLANE_NETCONF_STATUS_DISABLED
+};
+
+/* Some special ifindex values that may be part of the dplane netconf api. */
+#define DPLANE_NETCONF_IFINDEX_ALL -1
+#define DPLANE_NETCONF_IFINDEX_DEFAULT -2
+
/* Enable system route notifications */
void dplane_enable_sys_route_notifs(void);
@@ -564,6 +583,21 @@ dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx);
const struct zebra_l2info_gre *
dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx);
+/* Interface netconf info */
+ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx);
+ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx,
+ ifindex_t ifindex);
+void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id);
+enum dplane_netconf_status_e
+dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx);
+enum dplane_netconf_status_e
+dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx,
+ enum dplane_netconf_status_e val);
+void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx,
+ enum dplane_netconf_status_e val);
+
/* Namespace fd info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index c1b104aec7..e1d28e1534 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2475,7 +2475,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__);
@@ -2989,6 +2989,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_GRE_SET:
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
+ case DPLANE_OP_INTF_NETCONFIG:
break;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index c386fc4871..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 */
@@ -4320,6 +4321,10 @@ static void rib_process_dplane_results(struct thread *thread)
zebra_if_addr_update_ctx(ctx);
break;
+ case DPLANE_OP_INTF_NETCONFIG:
+ zebra_if_netconf_update_ctx(ctx);
+ break;
+
/* Some op codes not handled here */
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
@@ -4382,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_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_script.c b/zebra/zebra_script.c
index 0e19376abe..4087749fd7 100644
--- a/zebra/zebra_script.c
+++ b/zebra/zebra_script.c
@@ -412,6 +412,8 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx)
lua_setfield(L, -2, "mtu");
}
lua_setfield(L, -2, "gre");
+
+ case DPLANE_OP_INTF_NETCONFIG: /*NYI*/
case DPLANE_OP_NONE:
break;
} /* Dispatch by op code */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 1d9ed4ddd9..bb16232118 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -3425,7 +3425,7 @@ DEFUN (show_evpn_mac_vni_mac,
vni = strtoul(argv[4]->arg, NULL, 10);
if (!prefix_str2mac(argv[6]->arg, &mac)) {
- vty_out(vty, "%% Malformed MAC address");
+ vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();