diff --git a/zebra/rib.h b/zebra/rib.h index 8f23c57c17..5e0bce4461 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -332,6 +332,21 @@ extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nh); +/* RPF lookup behaviour */ +enum multicast_mode +{ + MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */ + MCAST_MRIB_ONLY, /* MRIB only */ + MCAST_URIB_ONLY, /* URIB only */ + MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */ + MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */ + MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */ + /* on equal value, MRIB wins for last 2 */ +}; + +extern void multicast_mode_ipv4_set (enum multicast_mode mode); +extern enum multicast_mode multicast_mode_ipv4_get (void); + extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t); extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t); @@ -371,6 +386,8 @@ extern int rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix extern struct rib *rib_match_ipv4 (struct in_addr, safi_t safi, vrf_id_t, struct route_node **rn_out); +extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, + struct route_node **rn_out); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *, vrf_id_t); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 87b0ebd79a..04ec3adacc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -79,6 +79,9 @@ static const struct /* no entry/default: 150 */ }; +/* RPF lookup behaviour */ +static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; + static void _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int priority, const char *msgfmt, ...) @@ -801,6 +804,78 @@ rib_match_ipv4 (struct in_addr addr, safi_t safi, vrf_id_t vrf_id, return NULL; } +struct rib * +rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out) +{ + struct rib *rib = NULL, *mrib = NULL, *urib = NULL; + struct route_node *m_rn = NULL, *u_rn = NULL; + int skip_bgp = 0; /* bool */ + + switch (ipv4_multicast_mode) + { + case MCAST_MRIB_ONLY: + return rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, rn_out); + case MCAST_URIB_ONLY: + return rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, rn_out); + case MCAST_NO_CONFIG: + case MCAST_MIX_MRIB_FIRST: + rib = mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + if (!mrib) + rib = urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + break; + case MCAST_MIX_DISTANCE: + mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = urib->distance < mrib->distance ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + case MCAST_MIX_PFXLEN: + mrib = rib_match_ipv4 (addr, SAFI_MULTICAST, skip_bgp, &m_rn); + urib = rib_match_ipv4 (addr, SAFI_UNICAST, skip_bgp, &u_rn); + if (mrib && urib) + rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; + else if (mrib) + rib = mrib; + else if (urib) + rib = urib; + break; + } + + if (rn_out) + *rn_out = (rib == mrib) ? m_rn : u_rn; + + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[BUFSIZ]; + inet_ntop (AF_INET, &addr, buf, BUFSIZ); + + zlog_debug("%s: %s: found %s, using %s", + __func__, buf, + mrib ? (urib ? "MRIB+URIB" : "MRIB") : + urib ? "URIB" : "nothing", + rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); + } + return rib; +} + +void +multicast_mode_ipv4_set (enum multicast_mode mode) +{ + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode); + ipv4_multicast_mode = mode; +} + +enum multicast_mode +multicast_mode_ipv4_get (void) +{ + return ipv4_multicast_mode; +} + struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 597476296d..6c0c5a5efd 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -212,6 +212,62 @@ ALIAS (no_ip_mroute_dist, "Nexthop address\n" "Nexthop interface name\n") +DEFUN (ip_multicast_mode, + ip_multicast_mode_cmd, + "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + if (!strncmp (argv[0], "u", 1)) + multicast_mode_ipv4_set (MCAST_URIB_ONLY); + else if (!strncmp (argv[0], "mrib-o", 6)) + multicast_mode_ipv4_set (MCAST_MRIB_ONLY); + else if (!strncmp (argv[0], "mrib-t", 6)) + multicast_mode_ipv4_set (MCAST_MIX_MRIB_FIRST); + else if (!strncmp (argv[0], "low", 3)) + multicast_mode_ipv4_set (MCAST_MIX_DISTANCE); + else if (!strncmp (argv[0], "lon", 3)) + multicast_mode_ipv4_set (MCAST_MIX_PFXLEN); + else + { + vty_out (vty, "Invalid mode specified%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_multicast_mode, + no_ip_multicast_mode_cmd, + "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + multicast_mode_ipv4_set (MCAST_NO_CONFIG); + return CMD_SUCCESS; +} + +ALIAS (no_ip_multicast_mode, + no_ip_multicast_mode_noarg_cmd, + "no ip multicast rpf-lookup-mode", + NO_STR + IP_STR + "Multicast options\n" + "RPF lookup behavior\n") + DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", @@ -5825,6 +5881,17 @@ config_write_protocol (struct vty *vty) if (zebra_rnh_ipv6_default_route) vty_out(vty, "ipv6 nht resolve-via-default%s", VTY_NEWLINE); + enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get (); + + if (ipv4_multicast_mode != MCAST_NO_CONFIG) + vty_out (vty, "ip multicast rpf-lookup-mode %s%s", + ipv4_multicast_mode == MCAST_URIB_ONLY ? "urib-only" : + ipv4_multicast_mode == MCAST_MRIB_ONLY ? "mrib-only" : + ipv4_multicast_mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib" : + ipv4_multicast_mode == MCAST_MIX_DISTANCE ? "lower-distance" : + "longer-prefix", + VTY_NEWLINE); + zebra_routemap_config_write_protocol(vty); return 1; @@ -5834,8 +5901,6 @@ config_write_protocol (struct vty *vty) static struct cmd_node ip_node = { IP_NODE, "", 1 }; static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 }; - - /* Route VTY. */ void zebra_vty_init (void) @@ -5849,6 +5914,9 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &ip_mroute_dist_cmd); install_element (CONFIG_NODE, &no_ip_mroute_cmd); install_element (CONFIG_NODE, &no_ip_mroute_dist_cmd); + install_element (CONFIG_NODE, &ip_multicast_mode_cmd); + install_element (CONFIG_NODE, &no_ip_multicast_mode_cmd); + install_element (CONFIG_NODE, &no_ip_multicast_mode_noarg_cmd); install_element (CONFIG_NODE, &ip_route_cmd); install_element (CONFIG_NODE, &ip_route_tag_cmd); install_element (CONFIG_NODE, &ip_route_flags_cmd); diff --git a/zebra/zserv.c b/zebra/zserv.c index 79da6ba7ab..70a53931fc 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -965,27 +965,13 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length, Returns both route metric and protocol distance. */ static int -zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, struct zebra_vrf *zvrf) +zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, struct rib *rib, struct zebra_vrf *zvrf) { struct stream *s; - struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; - /* Lookup nexthop. */ - rib = rib_match_ipv4 (addr, SAFI_MULTICAST, zvrf->vrf_id, NULL); - - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: %s mrib entry found.", __func__, rib ? "Matching" : "No matching"); - - if (!rib) { - /* Retry lookup with unicast rib */ - rib = rib_match_ipv4 (addr, SAFI_UNICAST, zvrf->vrf_id, NULL); - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: %s rib entry found.", __func__, rib ? "Matching" : "No matching"); - } - /* Get output stream. */ s = client->obuf; stream_reset (s); @@ -1399,9 +1385,11 @@ static int zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { struct in_addr addr; + struct rib *rib; addr.s_addr = stream_get_ipv4 (client->ibuf); - return zsend_ipv4_nexthop_lookup_mrib (client, addr, zvrf); + rib = rib_match_ipv4_multicast (addr, NULL); + return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib, zvrf); } /* Nexthop lookup for IPv4. */