Skip to content
Permalink
Browse files

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>
  • Loading branch information...
donaldsharp committed Jun 11, 2015
1 parent 2d627ff commit 8a92a8a00ca49ad801dbcfcd02bfb65ea1f4b83e
Showing with 526 additions and 72 deletions.
  1. +31 −10 bgpd/bgp_attr.c
  2. +2 −1 bgpd/bgp_attr.h
  3. +8 −2 bgpd/bgp_nht.c
  4. +69 −0 bgpd/bgp_open.c
  5. +2 −0 bgpd/bgp_open.h
  6. +24 −18 bgpd/bgp_route.c
  7. +4 −0 bgpd/bgp_route.h
  8. +2 −1 bgpd/bgp_updgrp.h
  9. +18 −8 bgpd/bgp_updgrp_packet.c
  10. +50 −0 bgpd/bgp_vty.c
  11. +39 −13 bgpd/bgp_zebra.c
  12. +8 −0 bgpd/bgpd.c
  13. +18 −0 bgpd/bgpd.h
  14. +64 −0 lib/zclient.c
  15. +2 −0 lib/zclient.h
  16. +2 −1 lib/zebra.h
  17. +1 −1 zebra/rib.h
  18. +30 −15 zebra/zebra_rib.c
  19. +27 −1 zebra/zebra_vty.c
  20. +125 −1 zebra/zserv.c
@@ -2137,7 +2137,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
int stream_put_prefix (struct stream *, struct prefix *);

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 attr *attr)
{
@@ -2152,7 +2152,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
stream_putc (s, safi); /* SAFI */

/* Nexthop */
switch (afi)
switch (nh_afi)
{
case AFI_IP:
switch (safi)
@@ -2255,9 +2255,12 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* Remember current pointer. */
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_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 */

/* 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);
stream_putc (s, BGP_ATTR_NEXT_HOP);
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);
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
{
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, 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. */
@@ -232,7 +232,8 @@ extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
* finally the _end() function.
*/
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);
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,
@@ -103,11 +103,17 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *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 */
if (make_prefix(afi, ri, &p) < 0)
return 1;
is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
(ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
}
else if (peer)
{
@@ -530,6 +530,48 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
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[] =
{
{ 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_ADDPATH, "AddPath" },
{ CAPABILITY_CODE_DYNAMIC, "Dynamic" },
{ CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding" },
{ CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)" },
{ CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (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_DYNAMIC] = 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_ORF_OLD] = sizeof (struct capability_orf_entry),
[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_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_HOSTNAME:
/* Check length. */
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))
return -1;
break;
case CAPABILITY_CODE_ENHE:
if (bgp_capability_enhe (peer, &caphdr))
return -1;
break;
default:
if (caphdr.code > 128)
{
@@ -1087,6 +1136,26 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, SAFI_MPLS_LABELED_VPN);
}
#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. */
if (peer->afc[AFI_IP6][SAFI_UNICAST])
{
@@ -77,6 +77,7 @@ struct capability_gr
#define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */
#define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic 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_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */
#define CAPABILITY_CODE_HOSTNAME 131 /* Advertise hostname capabilty */
@@ -89,6 +90,7 @@ struct capability_gr
#define CAPABILITY_CODE_AS4_LEN 4
#define CAPABILITY_CODE_ADDPATH_LEN 4
#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. */

@@ -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
* 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;
if (!reflect)
@@ -1481,7 +1481,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
if (!reflect ||
CHECK_FLAG (peer->af_flags[afi][safi],
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)
{
@@ -1491,7 +1491,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
break;
}
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);

/* 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
|| (p->family == AF_INET6 &&
|| ((p->family == AF_INET6 || peer_cap_enhe(rsclient)) &&
IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
)
@@ -1613,12 +1614,12 @@ subgroup_announce_check_rsclient (struct bgp_info *ri,
if (safi == SAFI_MPLS_VPN)
memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4,
IPV4_MAX_BYTELEN);
else
else if (!peer_cap_enhe(rsclient))
memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN);
}
#ifdef HAVE_IPV6
/* Set IPv6 nexthop. */
if (p->family == AF_INET6)
if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
{
/* IPv6 global nexthop must be included. */
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
if (p->family == AF_INET6)
if (p->family == AF_INET6 || peer_cap_enhe(rsclient))
{
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);

/* 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. */
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. */
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. */
if (new_attr.nexthop.s_addr == 0
@@ -6553,7 +6555,8 @@ route_vty_out (struct vty *vty, struct prefix *p,
{

/* 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)
{
@@ -6580,7 +6583,7 @@ route_vty_out (struct vty *vty, struct prefix *p,

#ifdef HAVE_IPV6
/* IPv6 Next Hop */
else if (p->family == AF_INET6)
else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{
int len;
char buf[BUFSIZ];
@@ -6691,7 +6694,8 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
/* Print attribute */
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)
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));
}
#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{
int len;
char buf[BUFSIZ];
@@ -6764,7 +6768,8 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
attr = binfo->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)
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));
}
#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{
assert (attr->extra);
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);

/* 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)
{
@@ -7068,7 +7074,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
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)
json_string = json_object_new_string("0.0.0.0");
@@ -150,6 +150,10 @@ struct bgp_static
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) \
(! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \
&& ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED))

0 comments on commit 8a92a8a

Please sign in to comment.
You can’t perform that action at this time.