summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--zebra/rib.h17
-rw-r--r--zebra/zebra_rib.c75
-rw-r--r--zebra/zebra_vty.c76
-rw-r--r--zebra/zserv.c22
4 files changed, 169 insertions, 21 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index 347fadb0..94a74194 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -373,6 +373,21 @@ typedef struct rib_tables_iter_t_
rib_tables_iter_state_t state;
} rib_tables_iter_t;
+/* 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 const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
@@ -420,6 +435,8 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi,
int skip_bgp, 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 *);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index abef90fb..effe2338 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -75,6 +75,9 @@ static const struct
/* Vector for routing table. */
static vector vrf_vector;
+/* RPF lookup behaviour */
+static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG;
+
static void
_rnode_zlog(const char *_func, struct route_node *rn, int priority,
const char *msgfmt, ...)
@@ -782,6 +785,78 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
}
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_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out);
+ case MCAST_URIB_ONLY:
+ return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out);
+ case MCAST_NO_CONFIG:
+ case MCAST_MIX_MRIB_FIRST:
+ rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn);
+ if (!mrib)
+ rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn);
+ break;
+ case MCAST_MIX_DISTANCE:
+ mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn);
+ urib = rib_match_ipv4_safi (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_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn);
+ urib = rib_match_ipv4_safi (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)
{
struct route_table *table;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 69245a54..f00e35ef 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -189,6 +189,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",
@@ -2228,10 +2284,19 @@ zebra_ip_config (struct vty *vty)
return write;
}
-/* ip protocol configuration write function */
-static int config_write_protocol(struct vty *vty)
-{
+static int config_write_vty(struct vty *vty)
+{
int i;
+ 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);
for (i=0;i<ZEBRA_ROUTE_MAX;i++)
{
@@ -2257,12 +2322,15 @@ void
zebra_vty_init (void)
{
install_node (&ip_node, zebra_ip_config);
- install_node (&protocol_node, config_write_protocol);
+ install_node (&protocol_node, config_write_vty);
install_element (CONFIG_NODE, &ip_mroute_cmd);
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_protocol_cmd);
install_element (CONFIG_NODE, &no_ip_protocol_cmd);
install_element (VIEW_NODE, &show_ip_protocol_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index e678f3a3..afd722a1 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -605,27 +605,13 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
Returns both route metric and protocol distance.
*/
static int
-zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr)
+zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr,
+ struct rib *rib)
{
struct stream *s;
- struct rib *rib;
unsigned long nump;
u_char num;
struct nexthop *nexthop;
- int skip_bgp = 0; /* bool */
-
- /* Lookup nexthop. */
- rib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, 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_safi (addr, SAFI_UNICAST, skip_bgp);
- 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;
@@ -1009,9 +995,11 @@ static int
zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length)
{
struct in_addr addr;
+ struct rib *rib;
addr.s_addr = stream_get_ipv4 (client->ibuf);
- return zsend_ipv4_nexthop_lookup_mrib (client, addr);
+ rib = rib_match_ipv4_multicast (addr, NULL);
+ return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib);
}
/* Nexthop lookup for IPv4. */