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))
{
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");
}
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)
{
}
}
}
-#endif /* HAVE_IPV6 */
/* MED/Metric */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
if (json_paths)
json_object_string_add(json_nexthop_global, "afi", "ipv4");
}
-#ifdef HAVE_IPV6
else
{
assert (attr->extra);
buf, INET6_ADDRSTRLEN));
}
}
-#endif /* HAVE_IPV6 */
-
/* Display the IGP cost or 'inaccessible' */
if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
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)
{
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);
}
}
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)
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
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. */
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",
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);
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);
/* 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;