From 425fd200c92392c4614b07c5ea416fddb495f792 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Apr 2022 14:29:38 +0200 Subject: [PATCH 1/4] zebra: add rib_match_ipv6_multicast variant ... for IPv6, analogous to v4. Signed-off-by: David Lamparter --- zebra/rib.h | 3 +++ zebra/zebra_rib.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/zebra/rib.h b/zebra/rib.h index c8abfaf023..281791d1f8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -424,6 +424,9 @@ extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id, struct in_addr addr, struct route_node **rn_out); +extern struct route_entry *rib_match_ipv6_multicast(vrf_id_t vrf_id, + struct in6_addr addr, + struct route_node **rn_out); extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c6840a503c..2732967ee6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -487,6 +487,62 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id, return re; } +struct route_entry *rib_match_ipv6_multicast(vrf_id_t vrf_id, + struct in6_addr addr, + struct route_node **rn_out) +{ + struct route_entry *re = NULL, *mre = NULL, *ure = NULL; + struct route_node *m_rn = NULL, *u_rn = NULL; + union g_addr gaddr = {.ipv6 = addr}; + + switch (zrouter.ipv4_multicast_mode) { + case MCAST_MRIB_ONLY: + return rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, + rn_out); + case MCAST_URIB_ONLY: + return rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, rn_out); + case MCAST_NO_CONFIG: + case MCAST_MIX_MRIB_FIRST: + re = mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, + &m_rn); + if (!mre) + re = ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, + &gaddr, &u_rn); + break; + case MCAST_MIX_DISTANCE: + mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn); + ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, &u_rn); + if (mre && ure) + re = ure->distance < mre->distance ? ure : mre; + else if (mre) + re = mre; + else if (ure) + re = ure; + break; + case MCAST_MIX_PFXLEN: + mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn); + ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, &u_rn); + if (mre && ure) + re = u_rn->p.prefixlen > m_rn->p.prefixlen ? ure : mre; + else if (mre) + re = mre; + else if (ure) + re = ure; + break; + } + + if (rn_out) + *rn_out = (re == mre) ? m_rn : u_rn; + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: %pI6: vrf: %s(%u) found %s, using %s", __func__, + &addr, vrf_id_to_name(vrf_id), vrf_id, + mre ? (ure ? "MRIB+URIB" : "MRIB") + : ure ? "URIB" : "nothing", + re == ure ? "URIB" : re == mre ? "MRIB" : "none"); + return re; +} + struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) { struct route_table *table; From 34ee41c6c94193c5392bd5fda3f469c62dd127ad Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Apr 2022 14:52:53 +0200 Subject: [PATCH 2/4] zebra, pimd: add AF param on NEXTHOP_LOOKUP_MRIB By changing this API call to use a `struct ipaddr`, which encodes the type of IP address with it. (And rename/remove the `IPV4` from the command name.) Also add a comment explaining that this function call is going to be obsolete in the long run since pimd needs to move to proper MRIB NHT. Signed-off-by: David Lamparter --- doc/developer/zebra.rst | 2 +- lib/log.c | 2 +- lib/zclient.h | 2 +- pimd/pim_zlookup.c | 29 ++++++++++++------------- zebra/zapi_msg.c | 47 +++++++++++++++++++++++++++++------------ 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index d51cbc9a14..cef53f1cbe 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -250,7 +250,7 @@ Zebra Protocol Commands +------------------------------------+-------+ | ZEBRA_INTERFACE_DISABLE_RADV | 43 | +------------------------------------+-------+ -| ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB | 44 | +| ZEBRA_NEXTHOP_LOOKUP_MRIB | 44 | +------------------------------------+-------+ | ZEBRA_INTERFACE_LINK_PARAMS | 45 | +------------------------------------+-------+ diff --git a/lib/log.c b/lib/log.c index 5c453569ee..9548f26c1d 100644 --- a/lib/log.c +++ b/lib/log.c @@ -370,7 +370,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV), - DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB), + DESC_ENTRY(ZEBRA_NEXTHOP_LOOKUP_MRIB), DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS), DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD), DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE), diff --git a/lib/zclient.h b/lib/zclient.h index 7e1283d830..78eb73c530 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -143,7 +143,7 @@ typedef enum { ZEBRA_BFD_CLIENT_DEREGISTER, ZEBRA_INTERFACE_ENABLE_RADV, ZEBRA_INTERFACE_DISABLE_RADV, - ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, + ZEBRA_NEXTHOP_LOOKUP_MRIB, ZEBRA_INTERFACE_LINK_PARAMS, ZEBRA_MPLS_LABELS_ADD, ZEBRA_MPLS_LABELS_DELETE, diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index c3f0b44431..79969ce9f0 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -165,7 +165,7 @@ static int zclient_read_nexthop(struct pim_instance *pim, uint8_t version; vrf_id_t vrf_id; uint16_t command = 0; - pim_addr raddr; + struct ipaddr raddr; uint8_t distance; uint32_t metric; int nexthop_num; @@ -177,7 +177,7 @@ static int zclient_read_nexthop(struct pim_instance *pim, s = zlookup->ibuf; - while (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { + while (command != ZEBRA_NEXTHOP_LOOKUP_MRIB) { stream_reset(s); err = zclient_read_header(s, zlookup->sock, &length, &marker, &version, &vrf_id, &command); @@ -197,13 +197,11 @@ static int zclient_read_nexthop(struct pim_instance *pim, } } -#if PIM_IPV == 4 - raddr.s_addr = stream_get_ipv4(s); -#else - stream_get(&raddr, s, sizeof(struct in6_addr)); -#endif - if (pim_addr_cmp(raddr, addr)) - zlog_warn("%s: address mismatch: addr=%pPAs(%s) raddr=%pPAs", + stream_get_ipaddr(s, &raddr); + + if (raddr.ipa_type != IPADDR_V4 || + raddr.ipaddr_v4.s_addr != addr.s_addr) + zlog_warn("%s: address mismatch: addr=%pPA(%s) raddr=%pIA", __func__, &addr, pim->vrf->name, &raddr); /* warning only */ @@ -308,6 +306,7 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim, { struct stream *s; int ret; + struct ipaddr ipaddr; if (PIM_DEBUG_PIM_NHT_DETAIL) zlog_debug("%s: addr=%pPAs(%s)", __func__, &addr, @@ -329,15 +328,13 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim, return -1; } + ipaddr.ipa_type = IPADDR_V4; + ipaddr.ipaddr_v4 = addr; + s = zlookup->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, - pim->vrf->vrf_id); -#if PIM_IPV == 4 - stream_put_in_addr(s, &addr); -#else - stream_write(s, (uint8_t *)&addr, 16); -#endif + zclient_create_header(s, ZEBRA_NEXTHOP_LOOKUP_MRIB, pim->vrf->vrf_id); + stream_put_ipaddr(s, &ipaddr); stream_putw_at(s, 0, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s)); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index fd475e4cee..e996f6c956 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -659,11 +659,18 @@ int zsend_redistribute_route(int cmd, struct zserv *client, * Modified version of zsend_ipv4_nexthop_lookup(): Query unicast rib if * nexthop is not found on mrib. Returns both route metric and protocol * distance. + * + * *XXX* this ZAPI call is slated to be removed at some point in the future + * since MRIB support in PIM is hopelessly broken in its interactions with NHT. + * The plan is to make pimd use NHT to receive URIB and MRIB in parallel and + * make the decision there, which will obsolete this ZAPI op. + * (Otherwise we would need to implement sending NHT updates for the result of + * this "URIB-MRIB-combined" table, but we only decide that here on the fly, + * so it'd be rather complex to do NHT for.) */ -static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, - struct in_addr addr, - struct route_entry *re, - struct zebra_vrf *zvrf) +static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, + struct route_entry *re, + struct zebra_vrf *zvrf) { struct stream *s; unsigned long nump; @@ -675,8 +682,8 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, stream_reset(s); /* Fill in result. */ - zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); - stream_put_in_addr(s, &addr); + zclient_create_header(s, ZEBRA_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); + stream_put_ipaddr(s, addr); if (re) { struct nexthop_group *nhg; @@ -2229,14 +2236,28 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) } /* MRIB Nexthop lookup for IPv4. */ -static void zread_ipv4_nexthop_lookup_mrib(ZAPI_HANDLER_ARGS) +static void zread_nexthop_lookup_mrib(ZAPI_HANDLER_ARGS) { - struct in_addr addr; - struct route_entry *re; + struct ipaddr addr; + struct route_entry *re = NULL; - STREAM_GET(&addr.s_addr, msg, IPV4_MAX_BYTELEN); - re = rib_match_ipv4_multicast(zvrf_id(zvrf), addr, NULL); - zsend_ipv4_nexthop_lookup_mrib(client, addr, re, zvrf); + STREAM_GET_IPADDR(msg, &addr); + + switch (addr.ipa_type) { + case IPADDR_V4: + re = rib_match_ipv4_multicast(zvrf_id(zvrf), addr.ipaddr_v4, + NULL); + break; + case IPADDR_V6: + re = rib_match_ipv6_multicast(zvrf_id(zvrf), addr.ipaddr_v6, + NULL); + break; + case IPADDR_NONE: + /* ??? */ + goto stream_failure; + } + + zsend_nexthop_lookup_mrib(client, &addr, re, zvrf); stream_failure: return; @@ -3685,7 +3706,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_REDISTRIBUTE_DELETE] = zebra_redistribute_delete, [ZEBRA_REDISTRIBUTE_DEFAULT_ADD] = zebra_redistribute_default_add, [ZEBRA_REDISTRIBUTE_DEFAULT_DELETE] = zebra_redistribute_default_delete, - [ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB] = zread_ipv4_nexthop_lookup_mrib, + [ZEBRA_NEXTHOP_LOOKUP_MRIB] = zread_nexthop_lookup_mrib, [ZEBRA_HELLO] = zread_hello, [ZEBRA_NEXTHOP_REGISTER] = zread_rnh_register, [ZEBRA_NEXTHOP_UNREGISTER] = zread_rnh_unregister, From dea337dc571811cec0091ccef74444ff37e02cd4 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 10 Mar 2022 15:38:59 +0100 Subject: [PATCH 3/4] pim6d: implement/un-stub MRIB lookup Signed-off-by: David Lamparter --- pimd/pim6_stubs.c | 16 ---------------- pimd/pim_addr.h | 4 ++++ pimd/pim_zlookup.c | 13 ++++++++----- pimd/subdir.am | 2 +- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/pimd/pim6_stubs.c b/pimd/pim6_stubs.c index 818b137abf..cf61685fb1 100644 --- a/pimd/pim6_stubs.c +++ b/pimd/pim6_stubs.c @@ -37,22 +37,6 @@ void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr) { } -int zclient_lookup_nexthop(struct pim_instance *pim, - struct pim_zlookup_nexthop nexthop_tab[], - const int tab_size, pim_addr addr, - int max_lookup) -{ - return -1; -} - -void zclient_lookup_new(void) -{ -} - -void zclient_lookup_free(void) -{ -} - /* * PIM register */ diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index eca907da37..90862520af 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -31,6 +31,8 @@ typedef struct in_addr pim_addr; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP +#define PIM_IPADDR IPADDR_V4 +#define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" @@ -52,6 +54,8 @@ typedef struct in6_addr pim_addr; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 +#define PIM_IPADDR IPADDR_V6 +#define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 79969ce9f0..0df7e4235e 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -199,11 +199,12 @@ static int zclient_read_nexthop(struct pim_instance *pim, stream_get_ipaddr(s, &raddr); - if (raddr.ipa_type != IPADDR_V4 || - raddr.ipaddr_v4.s_addr != addr.s_addr) + if (raddr.ipa_type != PIM_IPADDR || + pim_addr_cmp(raddr.ipaddr_pim, addr)) { zlog_warn("%s: address mismatch: addr=%pPA(%s) raddr=%pIA", __func__, &addr, pim->vrf->name, &raddr); - /* warning only */ + /* warning only */ + } distance = stream_getc(s); metric = stream_getl(s); @@ -328,8 +329,8 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim, return -1; } - ipaddr.ipa_type = IPADDR_V4; - ipaddr.ipaddr_v4 = addr; + ipaddr.ipa_type = PIM_IPADDR; + ipaddr.ipaddr_pim = addr; s = zlookup->obuf; stream_reset(s); @@ -480,6 +481,7 @@ void pim_zlookup_show_ip_multicast(struct vty *vty) } } +#if PIM_IPV == 4 int pim_zlookup_sg_statistics(struct channel_oil *c_oil) { struct stream *s = zlookup->obuf; @@ -568,3 +570,4 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) return 0; } +#endif diff --git a/pimd/subdir.am b/pimd/subdir.am index ba7bdb3493..41fc6dc632 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -55,6 +55,7 @@ pim_common = \ pimd/pim_util.c \ pimd/pim_vty.c \ pimd/pim_zebra.c \ + pimd/pim_zlookup.c \ pimd/pim_vxlan.c \ pimd/pimd.c \ # end @@ -75,7 +76,6 @@ pimd_pimd_SOURCES = \ pimd/pim_msdp_socket.c \ pimd/pim_register.c \ pimd/pim_signals.c \ - pimd/pim_zlookup.c \ pimd/pim_zpthread.c \ pimd/pim_mroute_msg.c \ # end From 6f4ce28aa5fc5d986db742168ff6200d6d884676 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Apr 2022 16:10:15 +0200 Subject: [PATCH 4/4] pimd: clean up zlookup nexthop handling Signed-off-by: David Lamparter --- pimd/pim_zlookup.c | 68 ++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 0df7e4235e..9e8e9cac39 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -220,8 +220,9 @@ static int zclient_read_nexthop(struct pim_instance *pim, for (i = 0; i < nexthop_num; ++i) { vrf_id_t nexthop_vrf_id; enum nexthop_types_t nexthop_type; - struct pim_neighbor *nbr; - struct prefix p; + struct in_addr nh_ip4; + struct in6_addr nh_ip6; + ifindex_t nh_ifi; nexthop_vrf_id = stream_getl(s); nexthop_type = stream_getc(s); @@ -249,21 +250,27 @@ static int zclient_read_nexthop(struct pim_instance *pim, break; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: - nexthop_tab[num_ifindex].nexthop_addr.s_addr = - stream_get_ipv4(s); - nexthop_tab[num_ifindex].ifindex = stream_getl(s); + nh_ip4.s_addr = stream_get_ipv4(s); + nh_ifi = stream_getl(s); +#if PIM_IPV == 4 + nexthop_tab[num_ifindex].nexthop_addr = nh_ip4; + nexthop_tab[num_ifindex].ifindex = nh_ifi; ++num_ifindex; +#else + zlog_warn("cannot use IPv4 nexthop %pI4 for IPv6 %pPA", + &nh_ip4, &addr); +#endif break; case NEXTHOP_TYPE_IPV6_IFINDEX: - stream_get(&nexthop_tab[num_ifindex].nexthop_addr, s, - sizeof(struct in6_addr)); - nexthop_tab[num_ifindex].ifindex = stream_getl(s); + stream_get(&nh_ip6, s, sizeof(nh_ip6)); + nh_ifi = stream_getl(s); - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_BITLEN; - memcpy(&p.u.prefix6, - &nexthop_tab[num_ifindex].nexthop_addr, - sizeof(struct in6_addr)); +#if PIM_IPV == 6 + nexthop_tab[num_ifindex].nexthop_addr = nh_ip6; + nexthop_tab[num_ifindex].ifindex = nh_ifi; + ++num_ifindex; +#else + /* RFC 5549 v4-over-v6 nexthop handling */ /* * If we are sending v6 secondary assume we receive v6 @@ -274,26 +281,35 @@ static int zclient_read_nexthop(struct pim_instance *pim, nexthop_vrf_id); if (!ifp) - nbr = NULL; - else if (pim->send_v6_secondary) + break; + + struct pim_neighbor *nbr; + + if (pim->send_v6_secondary) { + struct prefix p; + + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = nh_ip6; + nbr = pim_neighbor_find_by_secondary(ifp, &p); - else + } else nbr = pim_neighbor_find_if(ifp); - if (nbr) { - nexthop_tab[num_ifindex].nexthop_addr = - nbr->source_addr; - } + if (!nbr) + break; + + nexthop_tab[num_ifindex].nexthop_addr = + nbr->source_addr; + nexthop_tab[num_ifindex].ifindex = nh_ifi; ++num_ifindex; +#endif break; default: /* do nothing */ - { - zlog_warn( - "%s: found non-ifindex nexthop type=%d for address %pPAs(%s)", - __func__, nexthop_type, &addr, - pim->vrf->name); - } + zlog_warn( + "%s: found non-ifindex nexthop type=%d for address %pPAs(%s)", + __func__, nexthop_type, &addr, pim->vrf->name); break; } }