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);
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);
/* 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, ...)
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)
{
"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",
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;
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)
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);
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);
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. */