summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/rib.h17
-rw-r--r--zebra/zebra_rib.c75
-rw-r--r--zebra/zebra_vty.c72
-rw-r--r--zebra/zserv.c20
4 files changed, 166 insertions, 18 deletions
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, ...)
@@ -802,6 +805,78 @@ rib_match_ipv4 (struct in_addr addr, safi_t safi, vrf_id_t vrf_id,
}
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)
{
struct route_table *table;
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. */