summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn_vty.c6
-rw-r--r--bgpd/bgp_flowspec_util.c8
-rw-r--r--bgpd/bgp_zebra.c24
-rw-r--r--bgpd/bgpd.c2
-rw-r--r--eigrpd/eigrp_network.c2
-rw-r--r--lib/prefix.h8
-rw-r--r--ospf6d/ospf6_asbr.c63
-rw-r--r--ospf6d/ospf6_asbr.h3
-rw-r--r--ospf6d/ospf6_top.h3
-rw-r--r--pimd/pim_cmd.c37
-rw-r--r--pimd/pim_msdp.c135
-rw-r--r--pimd/pim_msdp.h41
-rw-r--r--pimd/pim_msdp_packet.c14
-rw-r--r--pimd/pim_nb.c1
-rw-r--r--pimd/pim_nb.h2
-rw-r--r--pimd/pim_nb_config.c142
-rw-r--r--tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py2
-rw-r--r--tests/topotests/msdp_topo1/__init__.py0
-rw-r--r--tests/topotests/msdp_topo1/r1/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r1/pimd.conf20
-rw-r--r--tests/topotests/msdp_topo1/r1/zebra.conf14
-rw-r--r--tests/topotests/msdp_topo1/r2/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r2/pimd.conf16
-rw-r--r--tests/topotests/msdp_topo1/r2/zebra.conf11
-rw-r--r--tests/topotests/msdp_topo1/r3/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r3/pimd.conf16
-rw-r--r--tests/topotests/msdp_topo1/r3/zebra.conf11
-rw-r--r--tests/topotests/msdp_topo1/r4/bgpd.conf9
-rw-r--r--tests/topotests/msdp_topo1/r4/pimd.conf20
-rw-r--r--tests/topotests/msdp_topo1/r4/zebra.conf14
-rwxr-xr-xtests/topotests/msdp_topo1/test_msdp_topo1.py499
-rw-r--r--yang/frr-pim.yang1
-rw-r--r--zebra/connected.c12
33 files changed, 841 insertions, 319 deletions
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 190323859f..2bda5dbf9a 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -63,10 +63,8 @@ int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
enum overlay_index_type *oly)
{
*oly = OVERLAY_INDEX_TYPE_NONE;
- if (argv_find(argv, argc, "gateway-ip", oly_idx)) {
- if (oly)
- *oly = OVERLAY_INDEX_GATEWAY_IP;
- }
+ if (argv_find(argv, argc, "gateway-ip", oly_idx))
+ *oly = OVERLAY_INDEX_GATEWAY_IP;
return 1;
}
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 23baa0184e..348dc7c9d1 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -227,12 +227,8 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
BGP_FLOWSPEC_STRING_DISPLAY_MAX);
break;
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
- if (prefix) {
- if (prefix_local.family == AF_INET)
- PREFIX_COPY_IPV4(prefix, &prefix_local);
- else
- PREFIX_COPY_IPV6(prefix, &prefix_local);
- }
+ if (prefix)
+ prefix_copy(prefix, &prefix_local);
break;
case BGP_FLOWSPEC_VALIDATE_ONLY:
default:
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 5d3176537b..ec71e17034 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -683,7 +683,7 @@ static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr)
return 0;
}
-static int if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr)
+static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr)
{
struct listnode *cnode;
struct connected *connected;
@@ -695,10 +695,10 @@ static int if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr)
if (cp->family == AF_INET6)
if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6)) {
memcpy(addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static int if_get_ipv4_address(struct interface *ifp, struct in_addr *addr)
@@ -724,6 +724,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
{
int ret = 0;
struct interface *ifp = NULL;
+ bool v6_ll_avail = true;
memset(nexthop, 0, sizeof(struct bgp_nexthop));
@@ -793,12 +794,20 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
* route-map to
* specify the global IPv6 nexthop.
*/
- if_get_ipv6_local(ifp, &nexthop->v6_global);
+ v6_ll_avail =
+ if_get_ipv6_local(ifp, &nexthop->v6_global);
memcpy(&nexthop->v6_local, &nexthop->v6_global,
IPV6_MAX_BYTELEN);
} else
- if_get_ipv6_local(ifp, &nexthop->v6_local);
+ v6_ll_avail =
+ if_get_ipv6_local(ifp, &nexthop->v6_local);
+ /*
+ * If we are a v4 connection and we are not doing unnumbered
+ * not having a v6 LL address is ok
+ */
+ if (!v6_ll_avail && !peer->conf_if)
+ v6_ll_avail = true;
if (if_lookup_by_ipv4(&remote->sin.sin_addr, peer->bgp->vrf_id))
peer->shared_network = 1;
else
@@ -824,7 +833,8 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
remote->sin6.sin6_scope_id,
peer->bgp->vrf_id);
if (direct)
- if_get_ipv6_local(ifp, &nexthop->v6_local);
+ v6_ll_avail = if_get_ipv6_local(
+ ifp, &nexthop->v6_local);
} else
/* Link-local address. */
{
@@ -871,7 +881,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
/* If we have identified the local interface, there is no error for now.
*/
- return true;
+ return v6_ll_avail;
}
static struct in6_addr *
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 95cfb205e9..197133cbb4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1538,7 +1538,7 @@ static int bgp_peer_conf_if_to_su_update_v4(struct peer *peer,
*/
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
if (ifc->address && (ifc->address->family == AF_INET)) {
- PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
+ prefix_copy(&p, CONNECTED_PREFIX(ifc));
if (p.prefixlen == 30) {
peer->su.sa.sa_family = AF_INET;
addr = ntohl(p.u.prefix4.s_addr);
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 69dcc20253..9a5fbc52b4 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -219,7 +219,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
}
struct prefix *pref = prefix_new();
- PREFIX_COPY_IPV4(pref, p);
+ prefix_copy(pref, p);
rn->info = (void *)pref;
/* Schedule Router ID Update. */
diff --git a/lib/prefix.h b/lib/prefix.h
index 217a23d561..c47e701dfd 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -481,11 +481,6 @@ extern void prefix_ipv4_free(struct prefix_ipv4 **p);
extern int str2prefix_ipv4(const char *, struct prefix_ipv4 *);
extern void apply_mask_ipv4(struct prefix_ipv4 *);
-#define PREFIX_COPY(DST, SRC) \
- *((struct prefix *)(DST)) = *((const struct prefix *)(SRC))
-#define PREFIX_COPY_IPV4(DST, SRC) \
- *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC))
-
extern int prefix_ipv4_any(const struct prefix_ipv4 *);
extern void apply_classful_mask_ipv4(struct prefix_ipv4 *);
@@ -503,9 +498,6 @@ extern void prefix_ipv6_free(struct prefix_ipv6 **p);
extern int str2prefix_ipv6(const char *, struct prefix_ipv6 *);
extern void apply_mask_ipv6(struct prefix_ipv6 *);
-#define PREFIX_COPY_IPV6(DST, SRC) \
- *((struct prefix_ipv6 *)(DST)) = *((const struct prefix_ipv6 *)(SRC))
-
extern int ip6_masklen(struct in6_addr);
extern void masklen2ip6(const int, struct in6_addr *);
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index c537816d3b..1836d81b08 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1010,53 +1010,55 @@ static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
static int ospf6_asbr_routemap_update_timer(struct thread *thread)
{
- void **arg;
- int arg_type;
- struct ospf6 *ospf6;
+ struct ospf6 *ospf6 = THREAD_ARG(thread);
struct ospf6_redist *red;
-
- arg = THREAD_ARG(thread);
- ospf6 = (struct ospf6 *)arg[0];
- arg_type = (int)(intptr_t)arg[1];
+ int type;
ospf6->t_distribute_update = NULL;
- red = ospf6_redist_lookup(ospf6, arg_type, 0);
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ red = ospf6_redist_lookup(ospf6, type, 0);
- if (red && ROUTEMAP_NAME(red))
- ROUTEMAP(red) = route_map_lookup_by_name(ROUTEMAP_NAME(red));
- if (red && ROUTEMAP(red)) {
- if (IS_OSPF6_DEBUG_ASBR)
- zlog_debug("%s: route-map %s update, reset redist %s",
- __func__, ROUTEMAP_NAME(red),
- ZROUTE_NAME(arg_type));
+ if (!red)
+ continue;
+
+ if (!CHECK_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED))
+ continue;
+
+ if (ROUTEMAP_NAME(red))
+ ROUTEMAP(red) =
+ route_map_lookup_by_name(ROUTEMAP_NAME(red));
+
+ if (ROUTEMAP(red)) {
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug(
+ "%s: route-map %s update, reset redist %s",
+ __func__, ROUTEMAP_NAME(red),
+ ZROUTE_NAME(type));
+
+ ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
+ ospf6_zebra_redistribute(type, ospf6->vrf_id);
+ }
- ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id);
- ospf6_zebra_redistribute(arg_type, ospf6->vrf_id);
+ UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
}
- XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
return 0;
}
-void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6)
+void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
+ struct ospf6_redist *red)
{
- void **args = NULL;
+ SET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
if (ospf6->t_distribute_update)
return;
- args = XCALLOC(MTYPE_OSPF6_DIST_ARGS, sizeof(void *) * 2);
-
- args[0] = ospf6;
- args[1] = (void *)((ptrdiff_t)type);
-
if (IS_OSPF6_DEBUG_ASBR)
- zlog_debug("%s: trigger redistribute %s reset thread", __func__,
- ZROUTE_NAME(type));
+ zlog_debug("%s: trigger redistribute reset thread", __func__);
ospf6->t_distribute_update = NULL;
- thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, args,
+ thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
OSPF_MIN_LS_INTERVAL,
&ospf6->t_distribute_update);
}
@@ -1092,8 +1094,7 @@ void ospf6_asbr_routemap_update(const char *mapname)
type));
route_map_counter_increment(ROUTEMAP(red));
-
- ospf6_asbr_distribute_list_update(type, ospf6);
+ ospf6_asbr_distribute_list_update(ospf6, red);
} else {
/*
* if the mapname matches a
@@ -1131,7 +1132,7 @@ static void ospf6_asbr_routemap_event(const char *name)
red = ospf6_redist_lookup(ospf6, type, 0);
if (red && ROUTEMAP_NAME(red)
&& (strcmp(ROUTEMAP_NAME(red), name) == 0))
- ospf6_asbr_distribute_list_update(type, ospf6);
+ ospf6_asbr_distribute_list_update(ospf6, red);
}
}
}
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 8f2135ef30..7ccd1c992b 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -105,7 +105,8 @@ extern void install_element_ospf6_debug_asbr(void);
extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
struct ospf6_route *route,
struct ospf6 *ospf6);
-extern void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6);
+extern void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
+ struct ospf6_redist *red);
struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
unsigned short instance);
extern void ospf6_asbr_routemap_update(const char *mapname);
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index f58af459ba..820622c743 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -37,9 +37,12 @@ enum {
OSPF6_LOG_ADJACENCY_DETAIL = (1 << 1),
};
+/* For processing route-map change update in the callback */
+#define OSPF6_IS_RMAP_CHANGED 0x01
struct ospf6_redist {
uint8_t instance;
+ uint8_t flag;
/* Redistribute metric info. */
struct {
int type; /* External metric type (E1 or E2). */
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 98eab9b694..c4afd04a07 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -9668,15 +9668,14 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
"Desired min transmit interval\n")
#endif /* !HAVE_BFDD */
- DEFUN (ip_msdp_peer,
- ip_msdp_peer_cmd,
- "ip msdp peer A.B.C.D source A.B.C.D",
- IP_STR
- CFG_MSDP_STR
- "Configure MSDP peer\n"
- "peer ip address\n"
- "Source address for TCP connection\n"
- "local ip address\n")
+DEFPY(ip_msdp_peer, ip_msdp_peer_cmd,
+ "ip msdp peer A.B.C.D$peer source A.B.C.D$source",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP peer\n"
+ "Peer IP address\n"
+ "Source address for TCP connection\n"
+ "Local IP address\n")
{
const char *vrfname;
char temp_xpath[XPATH_MAXLEN];
@@ -9687,16 +9686,15 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ "frr-routing:ipv4");
snprintf(temp_xpath, sizeof(temp_xpath),
- "/msdp-peer[peer-ip='%s']/source-ip",
- argv[3]->arg);
+ "/msdp-peer[peer-ip='%s']/source-ip", peer_str);
strlcat(msdp_peer_source_xpath, temp_xpath,
sizeof(msdp_peer_source_xpath));
nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY,
- argv[5]->arg);
+ source_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -10150,8 +10148,10 @@ static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
json_row = json_object_new_object();
json_object_string_add(json_row, "peer", peer_str);
json_object_string_add(json_row, "local", local_str);
- json_object_string_add(json_row, "meshGroupName",
- mp->mesh_group_name);
+ if (mp->flags & PIM_MSDP_PEERF_IN_GROUP)
+ json_object_string_add(json_row,
+ "meshGroupName",
+ mp->mesh_group_name);
json_object_string_add(json_row, "state", state_str);
json_object_string_add(json_row, "upTime", timebuf);
json_object_string_add(json_row, "keepAliveTimer",
@@ -10175,8 +10175,9 @@ static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
} else {
vty_out(vty, "Peer : %s\n", peer_str);
vty_out(vty, " Local : %s\n", local_str);
- vty_out(vty, " Mesh Group : %s\n",
- mp->mesh_group_name);
+ if (mp->flags & PIM_MSDP_PEERF_IN_GROUP)
+ vty_out(vty, " Mesh Group : %s\n",
+ mp->mesh_group_name);
vty_out(vty, " State : %s\n", state_str);
vty_out(vty, " Uptime : %s\n", timebuf);
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 095c6de549..be2df7693c 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -761,25 +761,6 @@ char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf,
return buf;
}
-char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size,
- bool long_format)
-{
- char peer_str[INET_ADDRSTRLEN];
- char local_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
- if (long_format) {
- pim_inet4_dump("<local?>", mp->local, local_str,
- sizeof(local_str));
- snprintf(buf, buf_size, "MSDP peer %s local %s mg %s", peer_str,
- local_str, mp->mesh_group_name);
- } else {
- snprintf(buf, buf_size, "MSDP peer %s", peer_str);
- }
-
- return buf;
-}
-
static void pim_msdp_peer_state_chg_log(struct pim_msdp_peer *mp)
{
char state_str[PIM_MSDP_STATE_STRLEN];
@@ -1063,11 +1044,10 @@ static void pim_msdp_addr2su(union sockunion *su, struct in_addr addr)
}
/* 11.2.A1: create a new peer and transition state to listen or connecting */
-static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim,
- struct in_addr peer_addr,
- struct in_addr local_addr,
- const char *mesh_group_name,
- struct pim_msdp_peer **mp_p)
+struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim,
+ const struct in_addr *peer,
+ const struct in_addr *local,
+ const char *mesh_group_name)
{
struct pim_msdp_peer *mp;
@@ -1076,14 +1056,17 @@ static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim,
mp = XCALLOC(MTYPE_PIM_MSDP_PEER, sizeof(*mp));
mp->pim = pim;
- mp->peer = peer_addr;
+ mp->peer = *peer;
pim_inet4_dump("<peer?>", mp->peer, mp->key_str, sizeof(mp->key_str));
pim_msdp_addr2su(&mp->su_peer, mp->peer);
- mp->local = local_addr;
+ mp->local = *local;
/* XXX: originator_id setting needs to move to the mesh group */
- pim->msdp.originator_id = local_addr;
+ pim->msdp.originator_id = *local;
pim_msdp_addr2su(&mp->su_local, mp->local);
- mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name);
+ if (mesh_group_name)
+ mp->mesh_group_name =
+ XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name);
+
mp->state = PIM_MSDP_INACTIVE;
mp->fd = -1;
strlcpy(mp->last_reset, "-", sizeof(mp->last_reset));
@@ -1112,10 +1095,7 @@ static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim,
} else {
pim_msdp_peer_connect(mp);
}
- if (mp_p) {
- *mp_p = mp;
- }
- return PIM_MSDP_ERR_NONE;
+ return mp;
}
struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim,
@@ -1127,43 +1107,6 @@ struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim,
return hash_lookup(pim->msdp.peer_hash, &lookup);
}
-/* add peer configuration if it doesn't already exist */
-enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim,
- struct in_addr peer_addr,
- struct in_addr local_addr,
- const char *mesh_group_name,
- struct pim_msdp_peer **mp_p)
-{
- struct pim_msdp_peer *mp;
-
- if (mp_p) {
- *mp_p = NULL;
- }
-
- if (peer_addr.s_addr == local_addr.s_addr) {
- /* skip session setup if config is invalid */
- if (PIM_DEBUG_MSDP_EVENTS) {
- char peer_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<peer?>", peer_addr, peer_str,
- sizeof(peer_str));
- zlog_debug("%s add skipped as DIP=SIP", peer_str);
- }
- return PIM_MSDP_ERR_SIP_EQ_DIP;
- }
-
- mp = pim_msdp_peer_find(pim, peer_addr);
- if (mp) {
- if (mp_p) {
- *mp_p = mp;
- }
- return PIM_MSDP_ERR_PEER_EXISTS;
- }
-
- return pim_msdp_peer_new(pim, peer_addr, local_addr, mesh_group_name,
- mp_p);
-}
-
/* release all mem associated with a peer */
static void pim_msdp_peer_free(struct pim_msdp_peer *mp)
{
@@ -1188,36 +1131,38 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp)
}
/* delete the peer config */
-static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp)
+void pim_msdp_peer_del(struct pim_msdp_peer **mp)
{
+ if (*mp == NULL)
+ return;
+
/* stop the tcp connection and shutdown all timers */
- pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
+ pim_msdp_peer_stop_tcp_conn(*mp, true /* chg_state */);
/* remove the session from various tables */
- listnode_delete(mp->pim->msdp.peer_list, mp);
- hash_release(mp->pim->msdp.peer_hash, mp);
+ listnode_delete((*mp)->pim->msdp.peer_list, *mp);
+ hash_release((*mp)->pim->msdp.peer_hash, *mp);
if (PIM_DEBUG_MSDP_EVENTS) {
- zlog_debug("MSDP peer %s deleted", mp->key_str);
+ zlog_debug("MSDP peer %s deleted", (*mp)->key_str);
}
/* free up any associated memory */
- pim_msdp_peer_free(mp);
-
- return PIM_MSDP_ERR_NONE;
+ pim_msdp_peer_free(*mp);
+ *mp = NULL;
}
-enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim,
- struct in_addr peer_addr)
+void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
+ const struct in_addr *addr)
{
- struct pim_msdp_peer *mp;
+ pim_msdp_peer_stop_tcp_conn(mp, true);
- mp = pim_msdp_peer_find(pim, peer_addr);
- if (!mp) {
- return PIM_MSDP_ERR_NO_PEER;
- }
+ mp->local = *addr;
- return pim_msdp_peer_do_del(mp);
+ if (PIM_MSDP_PEER_IS_LISTENER(mp))
+ pim_msdp_peer_listen(mp);
+ else
+ pim_msdp_peer_connect(mp);
}
/* peer hash and peer list helpers */
@@ -1319,7 +1264,7 @@ void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr)
{
/* Delete active peer session if any */
if (mbr->mp) {
- pim_msdp_peer_do_del(mbr->mp);
+ pim_msdp_peer_del(&mbr->mp);
}
listnode_delete(mg->mbr_list, mbr);
@@ -1342,10 +1287,8 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg)
/* SIP is being removed - tear down all active peer sessions */
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
- if (mbr->mp) {
- pim_msdp_peer_do_del(mbr->mp);
- mbr->mp = NULL;
- }
+ if (mbr->mp)
+ pim_msdp_peer_del(&mbr->mp);
}
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_debug("MSDP mesh-group %s src cleared",
@@ -1396,8 +1339,8 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim,
bool written = false;
for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) {
- /* Non meshed peers have the group name set to 'default'. */
- if (strcmp(mp->mesh_group_name, "default"))
+ /* Skip meshed group peers. */
+ if (mp->flags & PIM_MSDP_PEERF_IN_GROUP)
continue;
vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces,
@@ -1504,8 +1447,8 @@ void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
/* Create data structures and start TCP connection. */
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr))
- pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
- mg->mesh_group_name, &mbr->mp);
+ mbr->mp = pim_msdp_peer_add(pim, &mbr->mbr_ip, &mg->src_ip,
+ mg->mesh_group_name);
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug("MSDP mesh-group %s src %pI4 set",
@@ -1524,8 +1467,8 @@ struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
/* if valid SIP has been configured add peer session */
if (mg->src_ip.s_addr != INADDR_ANY)
- pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
- mg->mesh_group_name, &mbr->mp);
+ mbr->mp = pim_msdp_peer_add(pim, &mbr->mbr_ip, &mg->src_ip,
+ mg->mesh_group_name);
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug("MSDP mesh-group %s mbr %pI4 created",
diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h
index bb7ee01ad8..6bf02f2b9f 100644
--- a/pimd/pim_msdp.h
+++ b/pimd/pim_msdp.h
@@ -97,7 +97,9 @@ enum pim_msdp_peer_flags {
PIM_MSDP_PEERF_NONE = 0,
PIM_MSDP_PEERF_LISTENER = (1 << 0),
#define PIM_MSDP_PEER_IS_LISTENER(mp) (mp->flags & PIM_MSDP_PEERF_LISTENER)
- PIM_MSDP_PEERF_SA_JUST_SENT = (1 << 1)
+ PIM_MSDP_PEERF_SA_JUST_SENT = (1 << 1),
+ /** Flag to signalize that peer belongs to a group. */
+ PIM_MSDP_PEERF_IN_GROUP = (1 << 2),
};
struct pim_msdp_peer {
@@ -222,12 +224,6 @@ struct pim_msdp {
struct pim_instance;
void pim_msdp_init(struct pim_instance *pim, struct thread_master *master);
void pim_msdp_exit(struct pim_instance *pim);
-enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim,
- struct in_addr peer, struct in_addr local,
- const char *mesh_group_name,
- struct pim_msdp_peer **mp_p);
-enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim,
- struct in_addr peer_addr);
char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf,
int buf_size);
struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim,
@@ -237,8 +233,6 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp);
void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state);
void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str);
int pim_msdp_write(struct thread *thread);
-char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size,
- bool long_format);
int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty,
const char *spaces);
bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim,
@@ -288,4 +282,33 @@ struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
*/
void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr);
+/**
+ * Allocates MSDP peer data structure, adds peer to group name
+ * `mesh_group_name` and starts state machine. If no group name is provided then
+ * the peer will work standalone.
+ *
+ * \param pim PIM instance
+ * \param peer_addr peer address
+ * \param local_addr local listening address
+ * \param mesh_group_name mesh group name (or `NULL` for peers without group).
+ */
+struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim,
+ const struct in_addr *peer_addr,
+ const struct in_addr *local_addr,
+ const char *mesh_group_name);
+
+/**
+ * Stops peer state machine and free memory.
+ */
+void pim_msdp_peer_del(struct pim_msdp_peer **mp);
+
+/**
+ * Changes peer source address.
+ *
+ * NOTE:
+ * This will cause the connection to drop and start again.
+ */
+void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
+ const struct in_addr *addr);
+
#endif
diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c
index 4aaf0f53d1..6d49708827 100644
--- a/pimd/pim_msdp_packet.c
+++ b/pimd/pim_msdp_packet.c
@@ -522,11 +522,15 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
* If the message group is not set, i.e. "default", then we assume that
* the message must be forwarded.*/
for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
- if (!pim_msdp_peer_rpf_check(peer, rp)
- && (strcmp(mp->mesh_group_name, peer->mesh_group_name)
- || !strcmp(mp->mesh_group_name, "default"))) {
- pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
- }
+ /* Not a RPF peer, so skip it. */
+ if (pim_msdp_peer_rpf_check(peer, rp))
+ continue;
+ /* Don't forward inside the meshed group. */
+ if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
+ && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
+ continue;
+
+ pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
}
}
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index ea53f1ef12..848a28d31a 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -149,7 +149,6 @@ const struct frr_yang_module_info frr_pim_info = {
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify,
- .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy,
}
},
{
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index 1959b403ff..07387be763 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -72,8 +72,6 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy(
- struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index b70656ea7b..d69ab3aeb6 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -243,65 +243,6 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
return ret;
}
-static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
- struct in_addr peer_addr,
- struct in_addr local_addr,
- char *errmsg, size_t errmsg_len)
-{
- enum pim_msdp_err result;
- int ret = NB_OK;
-
- result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default",
- NULL /* mp_p */);
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_OOM:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% Out of memory");
- break;
- case PIM_MSDP_ERR_PEER_EXISTS:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% Peer exists");
- break;
- case PIM_MSDP_ERR_MAX_MESH_GROUPS:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% Only one mesh-group allowed currently");
- break;
- default:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% peer add failed");
- }
-
- return ret;
-}
-
-static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim,
- struct in_addr peer_addr,
- char *errmsg, size_t errmsg_len)
-{
- enum pim_msdp_err result;
-
- result = pim_msdp_peer_del(pim, peer_addr);
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_NO_PEER:
- snprintf(errmsg, errmsg_len,
- "%% Peer does not exist");
- break;
- default:
- snprintf(errmsg, errmsg_len,
- "%% peer del failed");
- }
-
- return result ? NB_ERR : NB_OK;
-}
-
static int pim_rp_cmd_worker(struct pim_instance *pim,
struct in_addr rp_addr,
struct prefix group, const char *plist,
@@ -1163,11 +1104,25 @@ int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
struct nb_cb_create_args *args)
{
+ struct pim_msdp_peer *mp;
+ struct pim_instance *pim;
+ struct vrf *vrf;
+ struct ipaddr peer_ip;
+ struct ipaddr source_ip;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
+ vrf = nb_running_get_entry(args->dnode, NULL, true);
+ pim = vrf->info;
+ yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip");
+ yang_dnode_get_ip(&source_ip, args->dnode, "./source-ip");
+ mp = pim_msdp_peer_add(pim, &peer_ip.ipaddr_v4,
+ &source_ip.ipaddr_v4, NULL);
+ nb_running_set_entry(args->dnode, mp);
break;
}
@@ -1177,10 +1132,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
struct nb_cb_destroy_args *args)
{
- int result;
- struct pim_instance *pim;
- struct ipaddr peer_ip;
- struct vrf *vrf;
+ struct pim_msdp_peer *mp;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1188,16 +1140,8 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip");
- result = ip_no_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
- args->errmsg,
- args->errmsg_len);
-
- if (result)
- return NB_ERR_INCONSISTENCY;
-
+ mp = nb_running_unset_entry(args->dnode);
+ pim_msdp_peer_del(&mp);
break;
}
@@ -1210,64 +1154,18 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
struct nb_cb_modify_args *args)
{
- int result;
- struct vrf *vrf;
- struct pim_instance *pim;
- struct ipaddr peer_ip;
+ struct pim_msdp_peer *mp;
struct ipaddr source_ip;
- const struct lyd_node *mesh_group_name_dnode;
- const char *mesh_group_name;
switch (args->event) {
case NB_EV_VALIDATE:
- mesh_group_name_dnode =
- yang_dnode_get(args->dnode,
- "../../msdp-mesh-group/mesh-group-name");
- if (mesh_group_name_dnode) {
- mesh_group_name =
- yang_dnode_get_string(mesh_group_name_dnode,
- ".");
- if (strcmp(mesh_group_name, "default")) {
- /* currently only one mesh-group can exist at a
- * time
- */
- snprintf(args->errmsg, args->errmsg_len,
- "%% Only one mesh-group allowed currently");
- return NB_ERR_VALIDATION;
- }
- }
- break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- yang_dnode_get_ip(&peer_ip, args->dnode, "../peer-ip");
+ mp = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_ip(&source_ip, args->dnode, NULL);
-
- result = ip_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
- source_ip.ip._v4_addr,
- args->errmsg,
- args->errmsg_len);
-
- if (result)
- return NB_ERR_INCONSISTENCY;
-
- break;
- }
-
- return NB_OK;
-}
-
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- case NB_EV_APPLY:
+ pim_msdp_peer_change_source(mp, &source_ip.ipaddr_v4);
break;
}
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
index 719ead091c..222fb28ade 100644
--- a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
+++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
@@ -223,7 +223,7 @@ def test_wait_msdp_convergence():
"show ip msdp peer json",
{peer: {"state": "established", "saCount": sa_count}}
)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=2)
assertmsg = '"{}" MSDP connection failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/msdp_topo1/__init__.py b/tests/topotests/msdp_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/msdp_topo1/__init__.py
diff --git a/tests/topotests/msdp_topo1/r1/bgpd.conf b/tests/topotests/msdp_topo1/r1/bgpd.conf
new file mode 100644
index 0000000000..01d8ddbdfa
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.2 remote-as 65002
+ neighbor 192.168.1.2 remote-as 65003
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf
new file mode 100644
index 0000000000..7f2958ac8c
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/pimd.conf
@@ -0,0 +1,20 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.1
+!
+interface r1-eth0
+ ip pim
+!
+interface r1-eth1
+ ip pim
+!
+interface r1-eth2
+ ip pim
+ ip igmp
+!
+ip msdp peer 192.168.0.2 source 192.168.0.1
+ip msdp peer 192.168.1.2 source 192.168.1.1
+ip pim rp 10.254.254.1
diff --git a/tests/topotests/msdp_topo1/r1/zebra.conf b/tests/topotests/msdp_topo1/r1/zebra.conf
new file mode 100644
index 0000000000..fb6eabccdf
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+!
+interface r1-eth0
+ ip address 192.168.0.1/24
+!
+interface r1-eth1
+ ip address 192.168.1.1/24
+!
+interface r1-eth2
+ ip address 192.168.10.1/24
+!
+interface lo
+ ip address 10.254.254.1/32
+!
diff --git a/tests/topotests/msdp_topo1/r2/bgpd.conf b/tests/topotests/msdp_topo1/r2/bgpd.conf
new file mode 100644
index 0000000000..987bef40dd
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.1 remote-as 65001
+ neighbor 192.168.2.2 remote-as 65004
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf
new file mode 100644
index 0000000000..dc4e0fa0ea
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/pimd.conf
@@ -0,0 +1,16 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.2
+!
+interface r2-eth0
+ ip pim
+!
+interface r2-eth1
+ ip pim
+!
+ip msdp peer 192.168.0.1 source 192.168.0.2
+ip msdp peer 192.168.2.2 source 192.168.2.1
+ip pim rp 10.254.254.2
diff --git a/tests/topotests/msdp_topo1/r2/zebra.conf b/tests/topotests/msdp_topo1/r2/zebra.conf
new file mode 100644
index 0000000000..527f7dd766
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface r2-eth0
+ ip address 192.168.0.2/24
+!
+interface r2-eth1
+ ip address 192.168.2.1/24
+!
+interface lo
+ ip address 10.254.254.2/32
+!
diff --git a/tests/topotests/msdp_topo1/r3/bgpd.conf b/tests/topotests/msdp_topo1/r3/bgpd.conf
new file mode 100644
index 0000000000..02d685b0e8
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as 65001
+ neighbor 192.168.3.2 remote-as 65004
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r3/pimd.conf b/tests/topotests/msdp_topo1/r3/pimd.conf
new file mode 100644
index 0000000000..7dae3d6da8
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/pimd.conf
@@ -0,0 +1,16 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.3
+!
+interface r3-eth0
+ ip pim
+!
+interface r3-eth1
+ ip pim
+!
+ip msdp peer 192.168.1.1 source 192.168.1.2
+ip msdp peer 192.168.3.2 source 192.168.3.1
+ip pim rp 10.254.254.3
diff --git a/tests/topotests/msdp_topo1/r3/zebra.conf b/tests/topotests/msdp_topo1/r3/zebra.conf
new file mode 100644
index 0000000000..688e752f42
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface r3-eth0
+ ip address 192.168.1.2/24
+!
+interface r3-eth1
+ ip address 192.168.3.1/24
+!
+interface lo
+ ip address 10.254.254.3/32
+!
diff --git a/tests/topotests/msdp_topo1/r4/bgpd.conf b/tests/topotests/msdp_topo1/r4/bgpd.conf
new file mode 100644
index 0000000000..633e8db245
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65004
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as 65002
+ neighbor 192.168.3.1 remote-as 65003
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
+
diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf
new file mode 100644
index 0000000000..1b422f7780
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/pimd.conf
@@ -0,0 +1,20 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.4
+!
+interface r4-eth0
+ ip pim
+!
+interface r4-eth1
+ ip pim
+!
+interface r4-eth2
+ ip pim
+ ip igmp
+!
+ip msdp peer 192.168.2.1 source 192.168.2.2
+ip msdp peer 192.168.3.1 source 192.168.3.2
+ip pim rp 10.254.254.4
diff --git a/tests/topotests/msdp_topo1/r4/zebra.conf b/tests/topotests/msdp_topo1/r4/zebra.conf
new file mode 100644
index 0000000000..1db8132256
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+!
+interface r4-eth0
+ ip address 192.168.2.2/24
+!
+interface r4-eth1
+ ip address 192.168.3.2/24
+!
+interface r4-eth2
+ ip address 192.168.4.1/24
+!
+interface lo
+ ip address 10.254.254.4/32
+!
diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py
new file mode 100755
index 0000000000..d85e16086d
--- /dev/null
+++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py
@@ -0,0 +1,499 @@
+#!/usr/bin/env python
+
+#
+# test_msdp_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_msdp_topo1.py: Test the FRR PIM MSDP peer.
+"""
+
+import os
+import sys
+import json
+import socket
+import tempfile
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.pimd]
+
+#
+# Test global variables:
+# They are used to handle communicating with external application.
+#
+APP_SOCK_PATH = '/tmp/topotests/apps.sock'
+HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
+app_listener = None
+app_clients = {}
+
+
+def listen_to_applications():
+ "Start listening socket to connect with applications."
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+ sock.bind(APP_SOCK_PATH)
+ sock.listen(10)
+ global app_listener
+ app_listener = sock
+
+
+def accept_host(host):
+ "Accept connection from application running in hosts."
+ global app_listener, app_clients
+ conn = app_listener.accept()
+ app_clients[host] = {
+ 'fd': conn[0],
+ 'address': conn[1]
+ }
+
+
+def close_applications():
+ "Signal applications to stop and close all sockets."
+ global app_listener, app_clients
+
+ # Close listening socket.
+ app_listener.close()
+
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ # Close all host connections.
+ for host in ["h1", "h2"]:
+ if app_clients.get(host) is None:
+ continue
+ app_clients[host]["fd"].close()
+
+
+class MSDPTopo1(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r4"])
+
+ # Create a host connected and direct at r4:
+ tgen.add_host("h1", "192.168.4.100/24", "192.168.4.1")
+ switch.add_link(tgen.gears["h1"])
+
+ # Create a host connected and direct at r1:
+ switch = tgen.add_switch("s6")
+ tgen.add_host("h2", "192.168.10.100/24", "192.168.10.1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["h2"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(MSDPTopo1, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BGP, daemon_file)
+
+ daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_PIM, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Start applications socket.
+ listen_to_applications()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ close_applications()
+ tgen.stop_topology()
+
+
+def test_bgp_convergence():
+ "Wait for BGP protocol convergence"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_loopback_route(router, iptype, route, proto):
+ "Wait until route is present on RIB for protocol."
+ logger.info("waiting route {} in {}".format(route, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show {} route json".format(iptype),
+ {route: [{"protocol": proto}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ # Wait for R1
+ expect_loopback_route("r1", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r1", "ip", "10.254.254.3/32", "bgp")
+ expect_loopback_route("r1", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R2
+ expect_loopback_route("r2", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r2", "ip", "10.254.254.3/32", "bgp")
+ expect_loopback_route("r2", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R3
+ expect_loopback_route("r3", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r3", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r3", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R4
+ expect_loopback_route("r4", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r4", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r4", "ip", "10.254.254.3/32", "bgp")
+
+
+def test_mroute_install():
+ "Test that multicast routes propagated and installed"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.gears["h1"].run("{} '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.1.2.3', 'h1-eth0'))
+ accept_host("h1")
+
+ tgen.gears["h2"].run("{} --send='0.7' '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.1.2.3', 'h2-eth0'))
+ accept_host("h2")
+
+ #
+ # Test R1 mroute
+ #
+ expect_1 = {
+ '229.1.2.3': {
+ '192.168.10.100': {
+ 'iif': 'r1-eth2',
+ 'flags': 'SFT',
+ 'oil': {
+ 'r1-eth0': {
+ 'source': '192.168.10.100',
+ 'group': '229.1.2.3'
+ },
+ 'r1-eth1': None
+ }
+ }
+ }
+ }
+ # Create a deep copy of `expect_1`.
+ expect_2 = json.loads(json.dumps(expect_1))
+ # The route will be either via R2 or R3.
+ expect_2['229.1.2.3']['192.168.10.100']['oil']['r1-eth0'] = None
+ expect_2['229.1.2.3']['192.168.10.100']['oil']['r1-eth1'] = {
+ 'source': '192.168.10.100',
+ 'group': '229.1.2.3'
+ }
+
+ def test_r1_mroute():
+ "Test r1 multicast routing table function"
+ out = tgen.gears['r1'].vtysh_cmd('show ip mroute json', isjson=True)
+ if topotest.json_cmp(out, expect_1) is None:
+ return None
+ return topotest.json_cmp(out, expect_2)
+
+ logger.info('Waiting for R1 multicast routes')
+ _, val = topotest.run_and_expect(test_r1_mroute, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+ #
+ # Test routers 2 and 3.
+ #
+ # NOTE: only one of the paths will get the multicast route.
+ #
+ expect_r2 = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "iif": "r2-eth0",
+ "flags": "S",
+ "oil": {
+ "r2-eth1": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ }
+ }
+ }
+ }
+ }
+ expect_r3 = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "iif": "r3-eth0",
+ "flags": "S",
+ "oil": {
+ "r3-eth1": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ }
+ }
+ }
+ }
+ }
+
+ def test_r2_r3_mroute():
+ "Test r2/r3 multicast routing table function"
+ r2_out = tgen.gears['r2'].vtysh_cmd('show ip mroute json', isjson=True)
+ r3_out = tgen.gears['r3'].vtysh_cmd('show ip mroute json', isjson=True)
+
+ if topotest.json_cmp(r2_out, expect_r2) is not None:
+ return topotest.json_cmp(r3_out, expect_r3)
+
+ return topotest.json_cmp(r2_out, expect_r2)
+
+ logger.info('Waiting for R2 and R3 multicast routes')
+ _, val = topotest.run_and_expect(test_r2_r3_mroute, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+ #
+ # Test router 4
+ #
+ expect_4 = {
+ "229.1.2.3": {
+ "*": {
+ "iif": "lo",
+ "flags": "SC",
+ "oil": {
+ "pimreg": {
+ "source": "*",
+ "group": "229.1.2.3",
+ "inboundInterface": "lo",
+ "outboundInterface": "pimreg"
+ },
+ "r4-eth2": {
+ "source": "*",
+ "group": "229.1.2.3",
+ "inboundInterface": "lo",
+ "outboundInterface": "r4-eth2"
+ }
+ }
+ },
+ "192.168.10.100": {
+ "iif": "r4-eth0",
+ "flags": "ST",
+ "oil": {
+ "r4-eth2": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "inboundInterface": "r4-eth0",
+ "outboundInterface": "r4-eth2",
+ }
+ }
+ }
+ }
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears['r4'], "show ip mroute json", expect_4,
+ )
+ logger.info('Waiting for R4 multicast routes')
+ _, val = topotest.run_and_expect(test_func, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+
+def test_msdp():
+ """
+ Test MSDP convergence.
+
+ MSDP non meshed groups must propagate the whole SA database (not just
+ their own) to all peers because not all peers talk with each other.
+
+ This setup leads to a potential loop that can be prevented by checking
+ the route's first AS in AS path: it must match the remote eBGP AS number.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1_expect = {
+ "192.168.0.2": {
+ "peer": "192.168.0.2",
+ "local": "192.168.0.1",
+ "state": "established"
+ },
+ "192.168.1.2": {
+ "peer": "192.168.1.2",
+ "local": "192.168.1.1",
+ "state": "established"
+ }
+ }
+ r1_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "-",
+ "local": "yes",
+ "sptSetup": "-"
+ }
+ }
+ }
+ r2_expect = {
+ "192.168.0.1": {
+ "peer": "192.168.0.1",
+ "local": "192.168.0.2",
+ "state": "established"
+ },
+ "192.168.2.2": {
+ "peer": "192.168.2.2",
+ "local": "192.168.2.1",
+ "state": "established"
+ }
+ }
+ # Only R2 or R3 will get this SA.
+ r2_r3_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "192.168.1.1",
+ "local": "no",
+ "sptSetup": "no",
+ }
+ }
+ }
+ r3_expect = {
+ "192.168.1.1": {
+ "peer": "192.168.1.1",
+ "local": "192.168.1.2",
+ "state": "established"
+ },
+ "192.168.3.2": {
+ "peer": "192.168.3.2",
+ "local": "192.168.3.1",
+ "state": "established"
+ }
+ }
+ r4_expect = {
+ "192.168.2.1": {
+ "peer": "192.168.2.1",
+ "local": "192.168.2.2",
+ "state": "established"
+ },
+ "192.168.3.1": {
+ "peer": "192.168.3.1",
+ "local": "192.168.3.2",
+ "state": "established"
+ }
+ }
+ r4_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "192.168.1.1",
+ "local": "no",
+ "sptSetup": "yes"
+ }
+ }
+ }
+
+ for router in [('r1', r1_expect, r1_sa_expect),
+ ('r2', r2_expect, r2_r3_sa_expect),
+ ('r3', r3_expect, r2_r3_sa_expect),
+ ('r4', r4_expect, r4_sa_expect)]:
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router[0]], "show ip msdp peer json", router[1]
+ )
+ logger.info('Waiting for {} msdp peer data'.format(router[0]))
+ _, val = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert val is None, 'multicast route convergence failure'
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router[0]], "show ip msdp sa json", router[2]
+ )
+ logger.info('Waiting for {} msdp SA data'.format(router[0]))
+ _, val = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert val is None, 'multicast route convergence failure'
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang
index 4c4819ac25..922ee5d105 100644
--- a/yang/frr-pim.yang
+++ b/yang/frr-pim.yang
@@ -219,6 +219,7 @@ module frr-pim {
}
leaf source-ip {
+ mandatory true;
type inet:ip-address;
description
"MSDP source IP address.";
diff --git a/zebra/connected.c b/zebra/connected.c
index d110ccf6dd..dc7193eb4c 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -198,7 +198,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc)
void connected_up(struct interface *ifp, struct connected *ifc)
{
afi_t afi;
- struct prefix p = {0};
+ struct prefix p;
struct nexthop nh = {
.type = NEXTHOP_TYPE_IFINDEX,
.ifindex = ifp->ifindex,
@@ -225,7 +225,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
/* Ensure 'down' flag is cleared */
UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
- PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
+ prefix_copy(&p, CONNECTED_PREFIX(ifc));
/* Apply mask to the network. */
apply_mask(&p);
@@ -277,9 +277,9 @@ void connected_up(struct interface *ifp, struct connected *ifc)
* resolve to the same network and mask
*/
for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
- struct prefix cp = {0};
+ struct prefix cp;
- PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
+ prefix_copy(&cp, CONNECTED_PREFIX(c));
apply_mask(&cp);
if (prefix_same(&cp, &p) &&
@@ -412,7 +412,7 @@ void connected_down(struct interface *ifp, struct connected *ifc)
return;
}
- PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
+ prefix_copy(&p, CONNECTED_PREFIX(ifc));
/* Apply mask to the network. */
apply_mask(&p);
@@ -450,7 +450,7 @@ void connected_down(struct interface *ifp, struct connected *ifc)
for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
struct prefix cp;
- PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
+ prefix_copy(&cp, CONNECTED_PREFIX(c));
apply_mask(&cp);
if (prefix_same(&p, &cp) &&