]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Add command to prefer global ipv6 address
authorDon Slice <dslice@cumulusnetworks.com>
Wed, 3 Aug 2016 13:49:09 +0000 (06:49 -0700)
committerDon Slice <dslice@cumulusnetworks.com>
Wed, 3 Aug 2016 13:49:09 +0000 (06:49 -0700)
There are cases where customers desire the ability to override the
default behavior of installing ipv6 prefixes with a link-local next-hop
if both a link-local and global ipv6 next-op is present in the bgp table.
This fix provides this ability and will allow the global to be used as the
next-hop.  This also retains the ability to manually set the ipv6 next-hop
global value as before, and if so, this manual entry will be used for the
next-hop.

Ticket: CM-11480
Signed-off-by: Don Slice
Reviewed By: CCR-4983
Testing Done: Manual testing results attached to the ticket. bgp-min and
bgp-smoke will be completed before committing.

bgpd/bgp_attr.h
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_zebra.c

index 1117f6269d98646a0c2bdfd96c2e16ccd49486b7..a279674af280f97884eea2e1f7e7b342787f7063 100644 (file)
@@ -99,6 +99,9 @@ struct attr_extra
   /* MP Nexthop length */
   u_char mp_nexthop_len;
 
+  /* MP Nexthop preference */
+  u_char mp_nexthop_prefer_global;
+
   /* route tag */
   u_short tag;
 
index fc6db0863d407d3efb5ec4290e04d7c668d36097..f47e2f607437d9a11731e4b3488b27ebec4f78b2 100644 (file)
@@ -5873,7 +5873,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
                vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
             }
        }
-#ifdef HAVE_IPV6
+
       /* IPv6 Next Hop */
       else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
        {
@@ -5901,8 +5901,9 @@ route_vty_out (struct vty *vty, struct prefix *p,
                   json_object_string_add(json_nexthop_ll, "afi", "ipv6");
                   json_object_string_add(json_nexthop_ll, "scope", "link-local");
 
-                  if (IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global,
-                                     &attr->extra->mp_nexthop_local) != 0)
+                  if ((IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global,
+                                      &attr->extra->mp_nexthop_local) != 0) &&
+                                      !attr->extra->mp_nexthop_prefer_global)
                     json_object_boolean_true_add(json_nexthop_ll, "used");
                   else
                     json_object_boolean_true_add(json_nexthop_global, "used");
@@ -5912,7 +5913,10 @@ route_vty_out (struct vty *vty, struct prefix *p,
             }
           else
             {
-             if ((attr->extra->mp_nexthop_len == 32) || (binfo->peer->conf_if))
+              /* Display LL if LL/Global both in table unless prefer-global is set */
+             if (((attr->extra->mp_nexthop_len == 32) &&
+                   !attr->extra->mp_nexthop_prefer_global) ||
+                   (binfo->peer->conf_if))
                {
                  if (binfo->peer->conf_if)
                    {
@@ -5954,7 +5958,6 @@ route_vty_out (struct vty *vty, struct prefix *p,
                }
             }
        }
-#endif /* HAVE_IPV6 */
 
       /* MED/Metric */
       if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
@@ -6635,7 +6638,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
           if (json_paths)
             json_object_string_add(json_nexthop_global, "afi", "ipv4");
        }
-#ifdef HAVE_IPV6
       else
        {
          assert (attr->extra);
@@ -6654,8 +6656,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
                                  buf, INET6_ADDRSTRLEN));
             }
        }
-#endif /* HAVE_IPV6 */
-
 
       /* Display the IGP cost or 'inaccessible' */
       if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
@@ -6761,7 +6761,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (!json_paths)
         vty_out (vty, "%s", VTY_NEWLINE);
 
-#ifdef HAVE_IPV6
       /* display the link-local nexthop */
       if (attr->extra && attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
        {
@@ -6775,13 +6774,19 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
               json_object_string_add(json_nexthop_ll, "scope", "link-local");
 
               json_object_boolean_true_add(json_nexthop_ll, "accessible");
-              json_object_boolean_true_add(json_nexthop_ll, "used");
+
+              if (!attr->extra->mp_nexthop_prefer_global)
+                json_object_boolean_true_add(json_nexthop_ll, "used");
+              else
+                json_object_boolean_true_add(json_nexthop_global, "used");
             }
           else
             {
-             vty_out (vty, "    (%s) (used)%s",
-                      inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
+             vty_out (vty, "    (%s) %s%s",
+                       inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
                                  buf, INET6_ADDRSTRLEN),
+                       attr->extra->mp_nexthop_prefer_global ?
+                                   "(prefer-global)" : "(used)",
                       VTY_NEWLINE);
             }
        }
@@ -6791,7 +6796,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
           if (json_paths)
             json_object_boolean_true_add(json_nexthop_global, "used");
         }
-#endif /* HAVE_IPV6 */
 
       /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */
       if (json_paths)
index 3018d074fc5b67eac24fa61cf380d937f09877cc..2a4d41663382492b4b1d42f09f3fcacf42effbc7 100644 (file)
@@ -103,6 +103,7 @@ o Cisco route-map
 o Local extensions
 
   set ipv6 next-hop global: Done
+  set ipv6 next-hop prefer-global: Done
   set ipv6 next-hop local : Done
   set as-path exclude     : Done
 
@@ -2192,6 +2193,61 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd =
   route_set_ipv6_nexthop_global_free
 };
 
+/* Set next-hop preference value. */
+static route_map_result_t
+route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix,
+                                     route_map_object_t type, void *object)
+{
+  struct bgp_info *bgp_info;
+  struct peer *peer;
+
+  if (type == RMAP_BGP)
+    {
+      /* Fetch routemap's rule information. */
+      bgp_info = object;
+      peer = bgp_info->peer;
+
+      if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) ||
+           CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
+         && peer->su_remote
+         && sockunion_family (peer->su_remote) == AF_INET6)
+       {
+          /* Set next hop preference to global */
+          bgp_info->attr->extra->mp_nexthop_prefer_global = TRUE;
+          SET_FLAG(bgp_info->attr->rmap_change_flags,
+                   BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED);
+       }
+    }
+ return RMAP_OKAY;
+}
+
+static void *
+route_set_ipv6_nexthop_prefer_global_compile (const char *arg)
+{
+  int *rins = NULL;
+
+  rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int));
+  *rins = 1;
+
+  return rins;
+}
+
+/* Free route map's compiled `ip next-hop' value. */
+static void
+route_set_ipv6_nexthop_prefer_global_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set preferred. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd =
+{
+  "ipv6 next-hop prefer-global",
+  route_set_ipv6_nexthop_prefer_global,
+  route_set_ipv6_nexthop_prefer_global_compile,
+  route_set_ipv6_nexthop_prefer_global_free
+};
+
 /* `set ipv6 nexthop local IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
@@ -4366,11 +4422,34 @@ DEFUN (no_set_ipv6_nexthop_peer,
        SET_STR
        IPV6_STR
        "IPv6 next-hop address\n"
-       )
+       "Use peer address (for BGP only)\n")
 {
   return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop peer-address", NULL);
 }
 
+DEFUN (set_ipv6_nexthop_prefer_global,
+       set_ipv6_nexthop_prefer_global_cmd,
+       "set ipv6 next-hop prefer-global",
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "Prefer global over link-local if both exist\n")
+{
+  return bgp_route_set_add (vty, vty->index, "ipv6 next-hop prefer-global", NULL);;
+}
+
+DEFUN (no_set_ipv6_nexthop_prefer_global,
+       no_set_ipv6_nexthop_prefer_global_cmd,
+       "no set ipv6 next-hop prefer-global",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "Prefer global over link-local if both exist\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop prefer-global", NULL);
+}
+
 DEFUN (set_ipv6_nexthop_global,
        set_ipv6_nexthop_global_cmd,
        "set ipv6 next-hop global X:X::X:X",
@@ -4704,6 +4783,7 @@ bgp_route_map_init (void)
   route_map_install_match (&route_match_ipv6_next_hop_cmd);
   route_map_install_match (&route_match_ipv6_address_prefix_list_cmd);
   route_map_install_set (&route_set_ipv6_nexthop_global_cmd);
+  route_map_install_set (&route_set_ipv6_nexthop_prefer_global_cmd);
   route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
   route_map_install_set (&route_set_ipv6_nexthop_peer_cmd);
 
@@ -4716,6 +4796,8 @@ bgp_route_map_init (void)
   install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd);
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd);
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd);
+  install_element (RMAP_NODE, &set_ipv6_nexthop_prefer_global_cmd);
+  install_element (RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd);
   install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
index 68f6cede8b09f31297e6493a00bb4512dc709657..3df63d5ba7af0335e81dfc8037c4a2e2021b1ba2 100644 (file)
@@ -1136,12 +1136,18 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info)
   /* If both global and link-local address present. */
   if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
     {
-      /* Workaround for Cisco's nexthop bug.  */
-      if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
-          && info->peer->su_remote->sa.sa_family == AF_INET6)
-        nexthop = &info->peer->su_remote->sin6.sin6_addr;
+      /* Check if route-map is set to prefer global over link-local */
+      if (info->attr->extra->mp_nexthop_prefer_global)
+        nexthop = &info->attr->extra->mp_nexthop_global;
       else
-        nexthop = &info->attr->extra->mp_nexthop_local;
+        {
+          /* Workaround for Cisco's nexthop bug.  */
+          if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+              && info->peer->su_remote->sa.sa_family == AF_INET6)
+            nexthop = &info->peer->su_remote->sin6.sin6_addr;
+          else
+            nexthop = &info->attr->extra->mp_nexthop_local;
+        }
     }
 
   return nexthop;