]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: make MRIB lookup behaviour switchable
authorDavid Lamparter <equinox@opensourcerouting.org>
Tue, 6 Jan 2015 18:53:24 +0000 (19:53 +0100)
committerDonald Sharp <sharpd@cumulusnetwroks.com>
Thu, 26 May 2016 00:38:31 +0000 (20:38 -0400)
depending on the usage scenario (and availability of multitopology IGP
protocols, which is currently zero in Quagga), different approaches of
Multicast RPF lookups are useful.

Reference behaviours from commercial vendors are urib-only/mrib-only
(Juniper, depending on inet.2 availability) and lowest-distance (Cisco).
As we are currently without MT IGP support, mrib-first seems the most
useful default for Quagga.

Cc: Everton Marques <everton.marques@gmail.com>
Cc: Balaji G <balajig81@gmail.com>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vty.c
zebra/zserv.c

index 8f23c57c1792b2e1d67cec0ae30f5e0d152f166c..5e0bce44617fc5c5d01c8b4c8684c8c173510447 100644 (file)
@@ -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);
 
index 87b0ebd79ad9e6a80aeb32b15b64699ec0d74489..04ec3adacc400055771daa922ab1ad0715551467 100644 (file)
@@ -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)
 {
index 597476296d78345c466b791d2086206fd56e5750..6c0c5a5efd5839cab85915788acf8af5d43f5675 100644 (file)
@@ -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);
index 79da6ba7ab38c6b488dc1841a5765f7e5f169691..70a53931fcf2361fdb10ae9e17bfdd753a48e200 100644 (file)
@@ -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. */