bgpd, zebra: rfc-5549-generic.patch

This adds support for BGP RFC 5549 (Extended Next Hop Encoding capability)

     * send and receive of the capability
     * processing of IPv4->IPv6 next-hops
     * for resolving these IPv6 next-hops, itsworks with the current
       next-hop-tracking support
     * added a new message type between BGP and Zebra for such route
       install/uninstall
     * zserv side of changes to process IPv4 prefix ->IPv6 next-hops
     * required show command changes for IPv4 prefix having IPv6 next-hops

Few points to note about the implementation:

     * It does an implicit next-hop-self when a [IPv4 prefix -> IPv6 LL next-hop]
       is to be considered for advertisement to IPv4 peering (or IPv6 peering
       without Extended next-hop capability negotiated)

     * Currently feature is off by default, enable it by configuring
       'neighbor <> capability extended-nexthop'

     * Current support is for IPv4 Unicast prefixes only.

IMPORTANT NOTE:

     This patch alone isn't enough to have IPv4->IPv6 routes installed into
     the kernel. A separate patch is needed for that to work for the netlink
     interface.

Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Reviewed-by: Daniel Walton <dwalton@cumulusnetworks.com>
             Vivek Venkatraman <vivek@cumulusnetworks.com>
             Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2015-06-11 09:19:12 -07:00
parent 2d627ff50c
commit 8a92a8a00c
20 changed files with 528 additions and 74 deletions

View File

@ -2137,7 +2137,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
int stream_put_prefix (struct stream *, struct prefix *); int stream_put_prefix (struct stream *, struct prefix *);
size_t size_t
bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
struct bpacket_attr_vec_arr *vecarr, struct bpacket_attr_vec_arr *vecarr,
struct attr *attr) struct attr *attr)
{ {
@ -2152,7 +2152,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
stream_putc (s, safi); /* SAFI */ stream_putc (s, safi); /* SAFI */
/* Nexthop */ /* Nexthop */
switch (afi) switch (nh_afi)
{ {
case AFI_IP: case AFI_IP:
switch (safi) switch (safi)
@ -2255,9 +2255,12 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* Remember current pointer. */ /* Remember current pointer. */
cp = stream_get_endp (s); cp = stream_get_endp (s);
if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) if (p && !((afi == AFI_IP && safi == SAFI_UNICAST) &&
!peer_cap_enhe(peer)))
{ {
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, vecarr, attr); mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi,
(peer_cap_enhe(peer) ? AFI_IP6 : afi),
vecarr, attr);
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
bgp_packet_mpattr_end(s, mpattrlen_pos); bgp_packet_mpattr_end(s, mpattrlen_pos);
} }
@ -2330,13 +2333,31 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
send_as4_path = 1; /* we'll do this later, at the correct place */ send_as4_path = 1; /* we'll do this later, at the correct place */
/* Nexthop attribute. */ /* Nexthop attribute. */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) if (afi == AFI_IP && !peer_cap_enhe(peer))
{ {
stream_putc (s, BGP_ATTR_FLAG_TRANS); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
stream_putc (s, BGP_ATTR_NEXT_HOP); {
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); stream_putc (s, BGP_ATTR_FLAG_TRANS);
stream_putc (s, 4); stream_putc (s, BGP_ATTR_NEXT_HOP);
stream_put_ipv4 (s, attr->nexthop.s_addr); bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, 4);
stream_put_ipv4 (s, attr->nexthop.s_addr);
}
else if (safi == SAFI_UNICAST && peer_cap_enhe(from))
{
/*
* Likely this is the case when an IPv4 prefix was received with
* Extended Next-hop capability and now being advertised to
* non-ENHE peers.
* Setting the mandatory (ipv4) next-hop attribute here to enable
* implicit next-hop self with correct (ipv4 address family).
*/
stream_putc (s, BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_NEXT_HOP);
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, NULL);
stream_putc (s, 4);
stream_put_ipv4 (s, 0);
}
} }
/* MED attribute. */ /* MED attribute. */

View File

@ -232,7 +232,8 @@ extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
* finally the _end() function. * finally the _end() function.
*/ */
extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
struct bpacket_attr_vec_arr *vecarr, afi_t nh_afi,
struct bpacket_attr_vec_arr *vecarr,
struct attr *attr); struct attr *attr);
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd, struct prefix *p, struct prefix_rd *prd,

View File

@ -103,11 +103,17 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
if (ri) if (ri)
{ {
is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
(ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
/* Since Extended Next-hop Encoding (RFC5549) support, we want to derive
address-family from the next-hop. */
if (!is_bgp_static_route)
afi = BGP_ATTR_NEXTHOP_AFI_IP6(ri->attr) ? AFI_IP6 : AFI_IP;
/* This will return TRUE if the global IPv6 NH is a link local addr */ /* This will return TRUE if the global IPv6 NH is a link local addr */
if (make_prefix(afi, ri, &p) < 0) if (make_prefix(afi, ri, &p) < 0)
return 1; return 1;
is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
(ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
} }
else if (peer) else if (peer)
{ {

View File

@ -530,6 +530,48 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
return 0; return 0;
} }
static int
bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
{
struct stream *s = BGP_INPUT (peer);
size_t end = stream_get_getp (s) + hdr->length;
while (stream_get_getp (s) + 6 <= end)
{
afi_t afi = stream_getw (s);
safi_t safi = stream_getw (s);
afi_t nh_afi = stream_getw (s);
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Received with value triple (afi/safi/next-hop afi): %u/%u/%u",
peer->host, afi, safi, nh_afi);
if (!bgp_afi_safi_valid_indices (afi, &safi))
return -1;
if (afi != AFI_IP || nh_afi != AFI_IP6)
{
zlog_warn ("%s Extended Next-hop capability, wrong afi/next-hop afi: %u/%u",
peer->host, afi, nh_afi);
return -1;
}
/* Until SAFIs other than SAFI_UNICAST are supported */
if (safi != SAFI_UNICAST)
zlog_warn ("%s Extended Next-hop capability came with unsupported SAFI: %u",
peer->host, safi);
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_RCV);
if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_ADV))
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_NEGO);
}
SET_FLAG (peer->cap, PEER_CAP_ENHE_RCV);
return 0;
}
static const struct message capcode_str[] = static const struct message capcode_str[] =
{ {
{ CAPABILITY_CODE_MP, "MultiProtocol Extensions" }, { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
@ -539,6 +581,7 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
{ CAPABILITY_CODE_AS4, "4-octet AS number" }, { CAPABILITY_CODE_AS4, "4-octet AS number" },
{ CAPABILITY_CODE_ADDPATH, "AddPath" }, { CAPABILITY_CODE_ADDPATH, "AddPath" },
{ CAPABILITY_CODE_DYNAMIC, "Dynamic" }, { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
{ CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding" },
{ CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)" }, { CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)" },
{ CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
{ CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
@ -557,6 +600,7 @@ static const size_t cap_minsizes[] =
[CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
[CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
[CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN,
[CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
[CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
[CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
[CAPABILITY_CODE_HOSTNAME] = CAPABILITY_CODE_MIN_HOSTNAME_LEN, [CAPABILITY_CODE_HOSTNAME] = CAPABILITY_CODE_MIN_HOSTNAME_LEN,
@ -624,6 +668,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ADDPATH:
case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD: case CAPABILITY_CODE_DYNAMIC_OLD:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_HOSTNAME: case CAPABILITY_CODE_HOSTNAME:
/* Check length. */ /* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code]) if (caphdr.length < cap_minsizes[caphdr.code])
@ -703,6 +748,10 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
if (bgp_capability_hostname (peer, &caphdr)) if (bgp_capability_hostname (peer, &caphdr))
return -1; return -1;
break; break;
case CAPABILITY_CODE_ENHE:
if (bgp_capability_enhe (peer, &caphdr))
return -1;
break;
default: default:
if (caphdr.code > 128) if (caphdr.code > 128)
{ {
@ -1087,6 +1136,26 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, SAFI_MPLS_LABELED_VPN); stream_putc (s, SAFI_MPLS_LABELED_VPN);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
/* Currently supporting RFC-5549 for Link-Local peering only */
if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
peer->su.sa.sa_family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
{
/* RFC 5549 Extended Next Hop Encoding */
SET_FLAG (peer->cap, PEER_CAP_ENHE_ADV);
stream_putc (s, BGP_OPEN_OPT_CAP);
stream_putc (s, CAPABILITY_CODE_ENHE_LEN + 2);
stream_putc (s, CAPABILITY_CODE_ENHE);
stream_putc (s, CAPABILITY_CODE_ENHE_LEN);
/* Currently supporting for SAFI_UNICAST only */
SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_ADV);
stream_putw (s, AFI_IP);
stream_putw (s, SAFI_UNICAST);
stream_putw (s, AFI_IP6);
if (CHECK_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_RCV))
SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO);
}
/* IPv6 unicast. */ /* IPv6 unicast. */
if (peer->afc[AFI_IP6][SAFI_UNICAST]) if (peer->afc[AFI_IP6][SAFI_UNICAST])
{ {

View File

@ -77,6 +77,7 @@ struct capability_gr
#define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */ #define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */
#define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */ #define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */
#define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */ #define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
#define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */
#define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */
#define CAPABILITY_CODE_HOSTNAME 131 /* Advertise hostname capabilty */ #define CAPABILITY_CODE_HOSTNAME 131 /* Advertise hostname capabilty */
@ -89,6 +90,7 @@ struct capability_gr
#define CAPABILITY_CODE_AS4_LEN 4 #define CAPABILITY_CODE_AS4_LEN 4
#define CAPABILITY_CODE_ADDPATH_LEN 4 #define CAPABILITY_CODE_ADDPATH_LEN 4
#define CAPABILITY_CODE_MIN_HOSTNAME_LEN 2 #define CAPABILITY_CODE_MIN_HOSTNAME_LEN 2
#define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
/* Cooperative Route Filtering Capability. */ /* Cooperative Route Filtering Capability. */

View File

@ -1396,7 +1396,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
* Of course, the operator can always set it through the route-map, if * Of course, the operator can always set it through the route-map, if
* so desired. * so desired.
*/ */
if (p->family == AF_INET6) if (p->family == AF_INET6 || peer_cap_enhe(peer))
{ {
attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if (!reflect) if (!reflect)
@ -1481,7 +1481,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
if (!reflect || if (!reflect ||
CHECK_FLAG (peer->af_flags[afi][safi], CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_SELF_ALL)) PEER_FLAG_NEXTHOP_SELF_ALL))
subgroup_announce_reset_nhop (p->family, attr); subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ? AF_INET6 : p->family), attr);
} }
else if (peer->sort == BGP_PEER_EBGP) else if (peer->sort == BGP_PEER_EBGP)
{ {
@ -1491,7 +1491,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
break; break;
} }
if (!paf) if (!paf)
subgroup_announce_reset_nhop (p->family, attr); subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ? AF_INET6 : p->family), attr);
} }
} }
@ -1600,9 +1600,10 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
bgp_attr_dup (attr, riattr); bgp_attr_dup (attr, riattr);
/* next-hop-set */ /* next-hop-set */
if ((p->family == AF_INET && attr->nexthop.s_addr == 0) if ((p->family == AF_INET && !peer_cap_enhe(rsclient)
&& attr->nexthop.s_addr == 0)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
|| (p->family == AF_INET6 && || ((p->family == AF_INET6 || peer_cap_enhe(rsclient)) &&
IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
) )
@ -1613,12 +1614,12 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
if (safi == SAFI_MPLS_VPN) if (safi == SAFI_MPLS_VPN)
memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4,
IPV4_MAX_BYTELEN); IPV4_MAX_BYTELEN);
else else if (!peer_cap_enhe(rsclient))
memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
/* Set IPv6 nexthop. */ /* Set IPv6 nexthop. */
if (p->family == AF_INET6) if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
{ {
/* IPv6 global nexthop must be included. */ /* IPv6 global nexthop must be included. */
memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global, memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global,
@ -1629,7 +1630,7 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (p->family == AF_INET6) if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
{ {
struct attr_extra *attre = attr->extra; struct attr_extra *attre = attr->extra;
@ -2471,7 +2472,8 @@ bgp_update_rsclient (struct peer *rsclient, u_int32_t addpath_id,
bgp_attr_unintern (&attr_new2); bgp_attr_unintern (&attr_new2);
/* IPv4 unicast next hop check. */ /* IPv4 unicast next hop check. */
if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST)) if ((afi == AFI_IP) && ((safi == SAFI_UNICAST && !peer_cap_enhe(peer))
|| safi == SAFI_MULTICAST))
{ {
/* Next hop must not be 0.0.0.0 nor Class D/E address. */ /* Next hop must not be 0.0.0.0 nor Class D/E address. */
if (new_attr.nexthop.s_addr == 0 if (new_attr.nexthop.s_addr == 0
@ -2720,7 +2722,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
} }
/* IPv4 unicast next hop check. */ /* IPv4 unicast next hop check. */
if (afi == AFI_IP && safi == SAFI_UNICAST) if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer))
{ {
/* Next hop must not be 0.0.0.0 nor Class D/E address. */ /* Next hop must not be 0.0.0.0 nor Class D/E address. */
if (new_attr.nexthop.s_addr == 0 if (new_attr.nexthop.s_addr == 0
@ -6553,7 +6555,8 @@ route_vty_out (struct vty *vty, struct prefix *p,
{ {
/* IPv4 Next Hop */ /* IPv4 Next Hop */
if (p->family == AF_INET) if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{ {
if (json_paths) if (json_paths)
{ {
@ -6580,7 +6583,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
/* IPv6 Next Hop */ /* IPv6 Next Hop */
else if (p->family == AF_INET6) else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{ {
int len; int len;
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -6691,7 +6694,8 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
/* Print attribute */ /* Print attribute */
if (attr) if (attr)
{ {
if (p->family == AF_INET) if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{ {
if (safi == SAFI_MPLS_VPN) if (safi == SAFI_MPLS_VPN)
vty_out (vty, "%-16s", vty_out (vty, "%-16s",
@ -6700,7 +6704,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (p->family == AF_INET6) else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{ {
int len; int len;
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -6764,7 +6768,8 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
attr = binfo->attr; attr = binfo->attr;
if (attr) if (attr)
{ {
if (p->family == AF_INET) if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{ {
if (safi == SAFI_MPLS_VPN) if (safi == SAFI_MPLS_VPN)
vty_out (vty, "%-16s", vty_out (vty, "%-16s",
@ -6773,7 +6778,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (p->family == AF_INET6) else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{ {
assert (attr->extra); assert (attr->extra);
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -7026,7 +7031,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE);
/* Line2 display Next-hop, Neighbor, Router-id */ /* Line2 display Next-hop, Neighbor, Router-id */
if (p->family == AF_INET) if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{ {
if (safi == SAFI_MPLS_VPN) if (safi == SAFI_MPLS_VPN)
{ {
@ -7068,7 +7074,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->peer == bgp->peer_self) if (binfo->peer == bgp->peer_self)
{ {
if (p->family == AF_INET) if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{ {
if (json_paths) if (json_paths)
json_string = json_object_new_string("0.0.0.0"); json_string = json_object_new_string("0.0.0.0");

View File

@ -150,6 +150,10 @@ struct bgp_static
u_char tag[3]; u_char tag[3];
}; };
#define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \
(! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && \
(attr)->extra && ((attr)->extra->mp_nexthop_len == 16 || \
(attr)->extra->mp_nexthop_len == 32))
#define BGP_INFO_COUNTABLE(BI) \ #define BGP_INFO_COUNTABLE(BI) \
(! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \
&& ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED)) && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED))

View File

@ -52,7 +52,8 @@
#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV) #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
#define PEER_UPDGRP_AF_CAP_FLAGS (PEER_CAP_ORF_PREFIX_SM_RCV | \ #define PEER_UPDGRP_AF_CAP_FLAGS (PEER_CAP_ORF_PREFIX_SM_RCV | \
PEER_CAP_ORF_PREFIX_SM_OLD_RCV) PEER_CAP_ORF_PREFIX_SM_OLD_RCV |\
PEER_CAP_ENHE_AF_NEGO)
typedef enum typedef enum
{ {

View File

@ -421,7 +421,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
route_map_sets_nh = CHECK_FLAG (vec->flags, route_map_sets_nh = CHECK_FLAG (vec->flags,
BPACKET_ATTRVEC_FLAGS_RMAP_CHANGED); BPACKET_ATTRVEC_FLAGS_RMAP_CHANGED);
if (paf->afi == AFI_IP) if (paf->afi == AFI_IP && !peer_cap_enhe(paf->peer))
{ {
struct in_addr v4nh; struct in_addr v4nh;
@ -501,7 +501,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
#endif #endif
} }
else if (paf->afi == AFI_IP6) else if (paf->afi == AFI_IP6 || peer_cap_enhe(paf->peer))
{ {
struct in6_addr v6nhglobal; struct in6_addr v6nhglobal;
struct in6_addr v6nhlocal; struct in6_addr v6nhlocal;
@ -698,7 +698,8 @@ subgroup_update_packet (struct update_subgroup *subgrp)
} }
} }
if (afi == AFI_IP && safi == SAFI_UNICAST) if ((afi == AFI_IP && safi == SAFI_UNICAST) &&
!peer_cap_enhe(peer))
stream_put_prefix (s, &rn->p); stream_put_prefix (s, &rn->p);
else else
{ {
@ -713,7 +714,8 @@ subgroup_update_packet (struct update_subgroup *subgrp)
if (stream_empty (snlri)) if (stream_empty (snlri))
mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi, mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
&vecarr, adv->baa->attr); (peer_cap_enhe(peer) ? AFI_IP6 : afi),
&vecarr, adv->baa->attr);
bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag); bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag);
} }
@ -795,6 +797,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
struct stream *s; struct stream *s;
struct bgp_adj_out *adj; struct bgp_adj_out *adj;
struct bgp_advertise *adv; struct bgp_advertise *adv;
struct peer *peer;
struct bgp_node *rn; struct bgp_node *rn;
bgp_size_t unfeasible_len; bgp_size_t unfeasible_len;
bgp_size_t total_attr_len; bgp_size_t total_attr_len;
@ -814,6 +817,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp))) if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp)))
return NULL; return NULL;
peer = SUBGRP_PEER (subgrp);
afi = SUBGRP_AFI (subgrp); afi = SUBGRP_AFI (subgrp);
safi = SUBGRP_SAFI (subgrp); safi = SUBGRP_SAFI (subgrp);
s = subgrp->work; s = subgrp->work;
@ -841,7 +845,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
else else
first_time = 0; first_time = 0;
if (afi == AFI_IP && safi == SAFI_UNICAST) if (afi == AFI_IP && safi == SAFI_UNICAST &&
!peer_cap_enhe(peer))
stream_put_prefix (s, &rn->p); stream_put_prefix (s, &rn->p);
else else
{ {
@ -883,7 +888,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
if (!stream_empty (s)) if (!stream_empty (s))
{ {
if (afi == AFI_IP && safi == SAFI_UNICAST) if (afi == AFI_IP && safi == SAFI_UNICAST &&
!peer_cap_enhe(peer))
{ {
unfeasible_len unfeasible_len
= stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
@ -976,7 +982,8 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
stream_putw_at (s, pos, total_attr_len); stream_putw_at (s, pos, total_attr_len);
/* NLRI set. */ /* NLRI set. */
if (p.family == AF_INET && safi == SAFI_UNICAST) if (p.family == AF_INET && safi == SAFI_UNICAST &&
!peer_cap_enhe(peer))
stream_put_prefix (s, &p); stream_put_prefix (s, &p);
/* Set size. */ /* Set size. */
@ -991,6 +998,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
void void
subgroup_default_withdraw_packet (struct update_subgroup *subgrp) subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
{ {
struct peer *peer;
struct stream *s; struct stream *s;
struct stream *packet; struct stream *packet;
struct prefix p; struct prefix p;
@ -1006,6 +1014,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
if (DISABLE_BGP_ANNOUNCE) if (DISABLE_BGP_ANNOUNCE)
return; return;
peer = SUBGRP_PEER (subgrp);
afi = SUBGRP_AFI (subgrp); afi = SUBGRP_AFI (subgrp);
safi = SUBGRP_SAFI (subgrp); safi = SUBGRP_SAFI (subgrp);
@ -1041,7 +1050,8 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
stream_putw (s, 0); stream_putw (s, 0);
/* Withdrawn Routes. */ /* Withdrawn Routes. */
if (p.family == AF_INET && safi == SAFI_UNICAST) if (p.family == AF_INET && safi == SAFI_UNICAST &&
!peer_cap_enhe(peer))
{ {
stream_put_prefix (s, &p); stream_put_prefix (s, &p);

View File

@ -3328,6 +3328,30 @@ DEFUN (no_neighbor_dont_capability_negotiate,
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY);
} }
/* neighbor capability extended next hop encoding */
DEFUN (neighbor_capability_enhe,
neighbor_capability_enhe_cmd,
NEIGHBOR_CMD2 "capability extended-nexthop",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Advertise capability to the peer\n"
"Advertise extended next-hop capability to the peer\n")
{
return peer_flag_set_vty (vty, argv[0], PEER_FLAG_CAPABILITY_ENHE);
}
DEFUN (no_neighbor_capability_enhe,
no_neighbor_capability_enhe_cmd,
NO_NEIGHBOR_CMD2 "capability extended-nexthop",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Advertise capability to the peer\n"
"Advertise extended next-hop capability to the peer\n")
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CAPABILITY_ENHE);
}
static int static int
peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi, peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag, int set) safi_t safi, u_int32_t flag, int set)
@ -9546,6 +9570,28 @@ bgp_show_peer (struct vty *vty, struct peer *p)
vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE);
} }
/* Extended nexthop */
if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV)
|| CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV))
{
vty_out (vty, " Extended nexthop:");
if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV))
vty_out (vty, " advertised");
if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV))
vty_out (vty, " %sreceived",
CHECK_FLAG (p->cap, PEER_CAP_ENHE_ADV) ? "and " : "");
vty_out (vty, "%s", VTY_NEWLINE);
if (CHECK_FLAG (p->cap, PEER_CAP_ENHE_RCV))
{
vty_out (vty, " Address families by peer:%s ", VTY_NEWLINE);
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
if (CHECK_FLAG (p->af_cap[AFI_IP][safi], PEER_CAP_ENHE_AF_RCV))
vty_out (vty, " %s%s",
afi_safi_print (AFI_IP, safi), VTY_NEWLINE);
}
}
/* Route Refresh */ /* Route Refresh */
if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)
|| CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)
@ -12242,6 +12288,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd); install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd);
install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd); install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd);
/* "neighbor capability extended-nexthop" commands.*/
install_element (BGP_NODE, &neighbor_capability_enhe_cmd);
install_element (BGP_NODE, &no_neighbor_capability_enhe_cmd);
/* "neighbor capability orf prefix-list" commands.*/ /* "neighbor capability orf prefix-list" commands.*/
install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd);

View File

@ -1020,7 +1020,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
nhcount = 1 + bgp_info_mpath_count (info); nhcount = 1 + bgp_info_mpath_count (info);
if (p->family == AF_INET) if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))
{ {
struct zapi_ipv4 api; struct zapi_ipv4 api;
struct in_addr *nexthop; struct in_addr *nexthop;
@ -1153,7 +1153,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
/* We have to think about a IPv6 link-local address curse. */ /* We have to think about a IPv6 link-local address curse. */
if (p->family == AF_INET6) if (p->family == AF_INET6 ||
(p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
{ {
unsigned int ifindex; unsigned int ifindex;
struct in6_addr *nexthop; struct in6_addr *nexthop;
@ -1310,20 +1311,45 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
api.tag = tag; api.tag = tag;
} }
if (bgp_debug_zebra(p)) if (p->family == AF_INET)
{ {
int i; if (bgp_debug_zebra(p))
zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d", {
valid_nh_count ? "add" : "delete", int i;
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d",
p->prefixlen, api.metric, api.tag); valid_nh_count ? "add" : "delete",
for (i = 0; i < api.nexthop_num; i++) inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
zlog_debug(" IPv6 [nexthop %d] %s", i+1, p->prefixlen, api.metric, api.tag);
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1]))); for (i = 0; i < api.nexthop_num; i++)
} zlog_debug(" IPv6 [nexthop %d] %s", i+1,
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
}
zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, if (valid_nh_count)
zclient, (struct prefix_ipv6 *) p, &api); zapi_ipv4_route_ipv6_nexthop (ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD,
zclient, (struct prefix_ipv4 *) p, &api);
else
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE,
zclient, (struct prefix_ipv4 *) p, &api);
}
else
{
if (bgp_debug_zebra(p))
{
int i;
zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
valid_nh_count ? "add" : "delete",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++)
zlog_debug(" IPv6 [nexthop %d] %s", i+1,
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
}
zapi_ipv6_route (valid_nh_count ?
ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
zclient, (struct prefix_ipv6 *) p, &api);
}
} }
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }

View File

@ -3157,6 +3157,7 @@ static const struct peer_flag_action peer_flag_action_list[] =
{ PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none }, { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none },
{ PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset }, { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset },
{ PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset }, { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset },
{ PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset },
{ PEER_FLAG_BFD, 0, peer_change_none }, { PEER_FLAG_BFD, 0, peer_change_none },
{ 0, 0, 0 } { 0, 0, 0 }
}; };
@ -6090,6 +6091,13 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
vty_out (vty, " neighbor %s capability dynamic%s", addr, vty_out (vty, " neighbor %s capability dynamic%s", addr,
VTY_NEWLINE); VTY_NEWLINE);
/* Extended next-hop capability. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE))
if (! peer_group_active (peer) ||
! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE))
vty_out (vty, " neighbor %s capability extended-nexthop%s", addr,
VTY_NEWLINE);
/* dont capability negotiation. */ /* dont capability negotiation. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
if (! peer_group_active (peer) || if (! peer_group_active (peer) ||

View File

@ -581,6 +581,8 @@ struct peer
#define PEER_CAP_ADDPATH_RCV (1 << 12) /* addpath received */ #define PEER_CAP_ADDPATH_RCV (1 << 12) /* addpath received */
#define PEER_CAP_HOSTNAME_ADV (1 << 13) /* hostname advertised */ #define PEER_CAP_HOSTNAME_ADV (1 << 13) /* hostname advertised */
#define PEER_CAP_HOSTNAME_RCV (1 << 14) /* hostname received */ #define PEER_CAP_HOSTNAME_RCV (1 << 14) /* hostname received */
#define PEER_CAP_ENHE_ADV (1 << 15) /* Extended nexthop advertised */
#define PEER_CAP_ENHE_RCV (1 << 16) /* Extended nexthop received */
/* Capability flags (reset in bgp_stop) */ /* Capability flags (reset in bgp_stop) */
u_int16_t af_cap[AFI_MAX][SAFI_MAX]; u_int16_t af_cap[AFI_MAX][SAFI_MAX];
@ -596,6 +598,9 @@ struct peer
#define PEER_CAP_ADDPATH_AF_TX_RCV (1 << 9) /* addpath tx received */ #define PEER_CAP_ADDPATH_AF_TX_RCV (1 << 9) /* addpath tx received */
#define PEER_CAP_ADDPATH_AF_RX_ADV (1 << 10) /* addpath rx advertised */ #define PEER_CAP_ADDPATH_AF_RX_ADV (1 << 10) /* addpath rx advertised */
#define PEER_CAP_ADDPATH_AF_RX_RCV (1 << 11) /* addpath rx received */ #define PEER_CAP_ADDPATH_AF_RX_RCV (1 << 11) /* addpath rx received */
#define PEER_CAP_ENHE_AF_ADV (1 << 12) /* Extended nexthopi afi/safi advertised */
#define PEER_CAP_ENHE_AF_RCV (1 << 13) /* Extended nexthop afi/safi received */
#define PEER_CAP_ENHE_AF_NEGO (1 << 14) /* Extended nexthop afi/safi negotiated */
/* Global configuration flags. */ /* Global configuration flags. */
u_int32_t flags; u_int32_t flags;
@ -613,6 +618,7 @@ struct peer
#define PEER_FLAG_BFD (1 << 11) /* bfd */ #define PEER_FLAG_BFD (1 << 11) /* bfd */
#define PEER_FLAG_LONESOUL (1 << 12) #define PEER_FLAG_LONESOUL (1 << 12)
#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 13) /* dynamic neighbor */ #define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 13) /* dynamic neighbor */
#define PEER_FLAG_CAPABILITY_ENHE (1 << 14) /* Extended next-hop (rfc 5549)*/
/* NSF mode (graceful restart) */ /* NSF mode (graceful restart) */
u_char nsf[AFI_MAX][SAFI_MAX]; u_char nsf[AFI_MAX][SAFI_MAX];
@ -1393,4 +1399,16 @@ peer_dynamic_neighbor (struct peer *peer)
return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0; return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0;
} }
/*
* Currently supporting RFC 5549 for AFI_IP/SAFI_UNICAST only.
*
* Note: When other RFC-5549 applicable SAFIs to be supported, that should
* come as an argument to this routine.
*/
static inline int
peer_cap_enhe (struct peer *peer)
{
return (CHECK_FLAG(peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO));
}
#endif /* _QUAGGA_BGPD_H */ #endif /* _QUAGGA_BGPD_H */

View File

@ -629,6 +629,70 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
int
zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
struct prefix_ipv4 *p, struct zapi_ipv6 *api)
{
int i;
int psize;
struct stream *s;
/* Reset stream. */
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, cmd);
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
stream_putc (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
/* Put prefix information. */
psize = PSIZE (p->prefixlen);
stream_putc (s, p->prefixlen);
stream_write (s, (u_char *) & p->prefix, psize);
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
else
stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
}
for (i = 0; i < api->ifindex_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc (s, api->distance);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
int int
zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
struct zapi_ipv6 *api) struct zapi_ipv6 *api)

View File

@ -212,6 +212,8 @@ struct zapi_ipv6
extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient,
struct prefix_ipv6 *p, struct zapi_ipv6 *api); struct prefix_ipv6 *p, struct zapi_ipv6 *api);
extern int zapi_ipv4_route_ipv6_nexthop (u_char, struct zclient *,
struct prefix_ipv4 *, struct zapi_ipv6 *);
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
#endif /* _ZEBRA_ZCLIENT_H */ #endif /* _ZEBRA_ZCLIENT_H */

View File

@ -433,7 +433,8 @@ struct in_pktinfo
#define ZEBRA_IMPORT_ROUTE_REGISTER 30 #define ZEBRA_IMPORT_ROUTE_REGISTER 30
#define ZEBRA_IMPORT_ROUTE_UNREGISTER 31 #define ZEBRA_IMPORT_ROUTE_UNREGISTER 31
#define ZEBRA_IMPORT_CHECK_UPDATE 32 #define ZEBRA_IMPORT_CHECK_UPDATE 32
#define ZEBRA_MESSAGE_MAX 33 #define ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD 33
#define ZEBRA_MESSAGE_MAX 34
/* Marker value used in new Zserv, in the byte location corresponding /* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new * the command value in the old zserv header. To allow old and new

View File

@ -452,7 +452,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
u_char distance, u_int32_t vrf_id); u_char distance, u_int32_t vrf_id);
extern int extern int
rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t, rib_add_ipv6_multipath (struct prefix *, struct rib *, safi_t,
unsigned long); unsigned long);
extern int extern int

View File

@ -3221,7 +3221,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
} }
int int
rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi, rib_add_ipv6_multipath (struct prefix *p, struct rib *rib, safi_t safi,
unsigned long ifindex) unsigned long ifindex)
{ {
struct route_table *table; struct route_table *table;
@ -3231,27 +3231,42 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi,
int ret = 0; int ret = 0;
unsigned int table_id = 0; unsigned int table_id = 0;
if (rib) if (p->family == AF_INET)
table_id = rib->table;
else
return 0; /* why are we getting called with NULL rib */
/* Lookup table. */
if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))
{ {
table = vrf_table (AFI_IP6, safi, 0); if (!rib)
return 0;
table = vrf_table (AFI_IP, safi, 0);
if (!table)
return 0;
/* Make it sure prefixlen is applied to the prefix. */
apply_mask_ipv4 (p);
} }
else else
{ {
table = vrf_other_route_table(AFI_IP6, table_id, 0); if (rib)
table_id = rib->table;
else
return 0; /* why are we getting called with NULL rib */
/* Lookup table. */
if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))
{
table = vrf_table (AFI_IP6, safi, 0);
}
else
{
table = vrf_other_route_table(AFI_IP6, table_id, 0);
}
if (! table)
return 0;
/* Make sure mask is applied. */
apply_mask_ipv6 (p);
} }
if (! table)
return 0;
/* Make sure mask is applied. */
apply_mask_ipv6 (p);
/* Set default distance by route type. */ /* Set default distance by route type. */
if (rib->distance == 0) if (rib->distance == 0)
{ {

View File

@ -888,6 +888,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
struct rib *rib; struct rib *rib;
struct nexthop *nexthop, *tnexthop; struct nexthop *nexthop, *tnexthop;
int recursing; int recursing;
char buf[BUFSIZ];
RNODE_FOREACH_RIB (rn, rib) RNODE_FOREACH_RIB (rn, rib)
{ {
@ -958,6 +959,18 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
if (nexthop->ifindex) if (nexthop->ifindex)
vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
break; break;
#ifdef HAVE_IPV6
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFNAME:
vty_out (vty, " %s",
inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
vty_out (vty, ", %s", nexthop->ifname);
else if (nexthop->ifindex)
vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
break;
#endif /* HAVE_IPV6 */
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " directly connected, %s", vty_out (vty, " directly connected, %s",
ifindex2ifname (nexthop->ifindex)); ifindex2ifname (nexthop->ifindex));
@ -1058,6 +1071,19 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
if (nexthop->ifindex) if (nexthop->ifindex)
vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
break; break;
#ifdef HAVE_IPV6
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFNAME:
vty_out (vty, " via %s",
inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
vty_out (vty, ", %s", nexthop->ifname);
else if (nexthop->ifindex)
vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
break;
#endif /* HAVE_IPV6 */
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " is directly connected, %s", vty_out (vty, " is directly connected, %s",
ifindex2ifname (nexthop->ifindex)); ifindex2ifname (nexthop->ifindex));
@ -1168,7 +1194,7 @@ DEFUN (show_ip_route,
vty_out (vty, SHOW_ROUTE_V4_HEADER); vty_out (vty, SHOW_ROUTE_V4_HEADER);
first = 0; first = 0;
} }
vty_show_ip_route (vty, rn, rib); vty_show_ip_route (vty, rn, rib);
} }
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View File

@ -1266,6 +1266,127 @@ zread_ipv4_import_lookup (struct zserv *client, u_short length)
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
/* Zebra server IPv6 prefix add function. */
static int
zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length)
{
int i;
struct stream *s;
struct in6_addr nexthop;
struct rib *rib;
u_char message;
u_char nexthop_num;
u_char nexthop_type;
unsigned long ifindex;
struct prefix_ipv4 p;
u_char ifname_len;
safi_t safi;
static struct in6_addr nexthops[MULTIPATH_NUM];
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
/* Get input stream. */
s = client->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in6_addr));
/* Allocate new rib. */
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
/* Type, flags, message. */
rib->type = stream_getc (s);
rib->instance = stream_getw (s);
rib->flags = stream_getc (s);
message = stream_getc (s);
safi = stream_getw (s);
rib->uptime = time (NULL);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET;
p.prefixlen = stream_getc (s);
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* We need to give nh-addr, nh-ifindex with the same next-hop object
* to the rib to ensure that IPv6 multipathing works; need to coalesce
* these. Clients should send the same number of paired set of
* next-hop-addr/next-hop-ifindices. */
if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
{
int nh_count = 0;
int if_count = 0;
int max_nh_if = 0;
nexthop_num = stream_getc (s);
for (i = 0; i < nexthop_num; i++)
{
nexthop_type = stream_getc (s);
switch (nexthop_type)
{
case ZEBRA_NEXTHOP_IPV6:
stream_get (&nexthop, s, 16);
if (nh_count < MULTIPATH_NUM) {
nexthops[nh_count++] = nexthop;
}
break;
case ZEBRA_NEXTHOP_IFINDEX:
if (if_count < MULTIPATH_NUM) {
ifindices[if_count++] = stream_getl (s);
}
break;
case ZEBRA_NEXTHOP_BLACKHOLE:
nexthop_blackhole_add (rib);
break;
}
}
max_nh_if = (nh_count > if_count) ? nh_count : if_count;
for (i = 0; i < max_nh_if; i++)
{
if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
if ((i < if_count) && ifindices[i]) {
nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
}
else {
nexthop_ipv6_add (rib, &nexthops[i]);
}
}
else {
if ((i < if_count) && ifindices[i]) {
nexthop_ifindex_add (rib, ifindices[i]);
}
}
}
}
/* Distance. */
if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
rib->distance = stream_getc (s);
/* Metric. */
if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
rib->metric = stream_getl (s);
/* Tag */
if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
rib->tag = stream_getw (s);
else
rib->tag = 0;
/* Table */
rib->table=zebrad.rtm_table_default;
ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
/* Stats */
if (ret > 0)
client->v4_route_add_cnt++;
else if (ret < 0)
client->v4_route_upd8_cnt++;
return 0;
}
/* Zebra server IPv6 prefix add function. */ /* Zebra server IPv6 prefix add function. */
static int static int
zread_ipv6_add (struct zserv *client, u_short length) zread_ipv6_add (struct zserv *client, u_short length)
@ -1385,7 +1506,7 @@ zread_ipv6_add (struct zserv *client, u_short length)
/* Table */ /* Table */
rib->table=zebrad.rtm_table_default; rib->table=zebrad.rtm_table_default;
ret = rib_add_ipv6_multipath (&p, rib, safi, ifindex); ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
/* Stats */ /* Stats */
if (ret > 0) if (ret > 0)
client->v6_route_add_cnt++; client->v6_route_add_cnt++;
@ -1731,6 +1852,9 @@ zebra_client_read (struct thread *thread)
zread_ipv4_delete (client, length); zread_ipv4_delete (client, length);
break; break;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD:
zread_ipv4_route_ipv6_nexthop_add (client, length);
break;
case ZEBRA_IPV6_ROUTE_ADD: case ZEBRA_IPV6_ROUTE_ADD:
zread_ipv6_add (client, length); zread_ipv6_add (client, length);
break; break;