diff options
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) && |
