diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-06-11 18:19:12 +0200 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-06-11 18:19:12 +0200 |
commit | 8a92a8a00ca49ad801dbcfcd02bfb65ea1f4b83e (patch) | |
tree | a33248e6de30e1c443af56b792d4a26b258e742f | |
parent | zebra, bgpd, ospfd: 'redistribute table' to 'redistribute table <table-id>' (diff) | |
download | frr-8a92a8a00ca49ad801dbcfcd02bfb65ea1f4b83e.tar.xz frr-8a92a8a00ca49ad801dbcfcd02bfb65ea1f4b83e.zip |
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>
-rw-r--r-- | bgpd/bgp_attr.c | 41 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_nht.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_open.c | 69 | ||||
-rw-r--r-- | bgpd/bgp_open.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 42 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_updgrp.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_updgrp_packet.c | 26 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 50 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 52 | ||||
-rw-r--r-- | bgpd/bgpd.c | 8 | ||||
-rw-r--r-- | bgpd/bgpd.h | 18 | ||||
-rw-r--r-- | lib/zclient.c | 64 | ||||
-rw-r--r-- | lib/zclient.h | 2 | ||||
-rw-r--r-- | lib/zebra.h | 3 | ||||
-rw-r--r-- | zebra/rib.h | 2 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 45 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 28 | ||||
-rw-r--r-- | zebra/zserv.c | 126 |
20 files changed, 526 insertions, 72 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 3a63cd224..de4c6c79f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.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. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 4fbfcb900..8c36ce0be 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -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, diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index da52064ae..397b379fa 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -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) { diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 9fcd64bd2..ddc8f9e8a 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -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]) { diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index a818141fc..6ef857284 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -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. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b1061e96f..5a93410bc 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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"); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index b6c5a2511..124ac4ea1 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -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)) diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 7a980f061..e2a59e324 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -52,7 +52,8 @@ #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_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 { diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 3174da530..d2fce799a 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -421,7 +421,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) route_map_sets_nh = CHECK_FLAG (vec->flags, BPACKET_ATTRVEC_FLAGS_RMAP_CHANGED); - if (paf->afi == AFI_IP) + if (paf->afi == AFI_IP && !peer_cap_enhe(paf->peer)) { struct in_addr v4nh; @@ -501,7 +501,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) #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 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); else { @@ -713,7 +714,8 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (stream_empty (snlri)) 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); } @@ -795,6 +797,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) struct stream *s; struct bgp_adj_out *adj; struct bgp_advertise *adv; + struct peer *peer; struct bgp_node *rn; bgp_size_t unfeasible_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))) return NULL; + peer = SUBGRP_PEER (subgrp); afi = SUBGRP_AFI (subgrp); safi = SUBGRP_SAFI (subgrp); s = subgrp->work; @@ -841,7 +845,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) else 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); else { @@ -883,7 +888,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) if (!stream_empty (s)) { - if (afi == AFI_IP && safi == SAFI_UNICAST) + if (afi == AFI_IP && safi == SAFI_UNICAST && + !peer_cap_enhe(peer)) { 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); /* 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); /* Set size. */ @@ -991,6 +998,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp, void subgroup_default_withdraw_packet (struct update_subgroup *subgrp) { + struct peer *peer; struct stream *s; struct stream *packet; struct prefix p; @@ -1006,6 +1014,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp) if (DISABLE_BGP_ANNOUNCE) return; + peer = SUBGRP_PEER (subgrp); afi = SUBGRP_AFI (subgrp); safi = SUBGRP_SAFI (subgrp); @@ -1041,7 +1050,8 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp) stream_putw (s, 0); /* 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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 28643419b..2491cc4c5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3328,6 +3328,30 @@ DEFUN (no_neighbor_dont_capability_negotiate, 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 peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi, 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); } + /* 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 */ if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) || 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, &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.*/ install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d482d9b38..c91a25679 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1020,7 +1020,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, 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 in_addr *nexthop; @@ -1153,7 +1153,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, #ifdef HAVE_IPV6 /* 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; struct in6_addr *nexthop; @@ -1310,20 +1311,45 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.tag = tag; } - if (bgp_debug_zebra(p)) + if (p->family == AF_INET) { - 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]))); + if (bgp_debug_zebra(p)) + { + int i; + zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d", + valid_nh_count ? "add" : "delete", + inet_ntop(AF_INET, &p->u.prefix4, 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]))); + } + + if (valid_nh_count) + 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); + zapi_ipv6_route (valid_nh_count ? + ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, + zclient, (struct prefix_ipv6 *) p, &api); + } } #endif /* HAVE_IPV6 */ } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0f99fcc45..e8bb2eb44 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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_DYNAMIC_CAPABILITY, 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 }, { 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_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. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) if (! peer_group_active (peer) || diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7bdd3e1f3..e0deec730 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -581,6 +581,8 @@ struct peer #define PEER_CAP_ADDPATH_RCV (1 << 12) /* addpath received */ #define PEER_CAP_HOSTNAME_ADV (1 << 13) /* hostname advertised */ #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) */ 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_RX_ADV (1 << 10) /* addpath rx advertised */ #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. */ u_int32_t flags; @@ -613,6 +618,7 @@ struct peer #define PEER_FLAG_BFD (1 << 11) /* bfd */ #define PEER_FLAG_LONESOUL (1 << 12) #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) */ 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; } +/* + * 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 */ diff --git a/lib/zclient.c b/lib/zclient.c index a848df1ec..722075ada 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -630,6 +630,70 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, #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 zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, struct zapi_ipv6 *api) { diff --git a/lib/zclient.h b/lib/zclient.h index bb8a87b14..bd4d06647 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -212,6 +212,8 @@ struct zapi_ipv6 extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, 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 /* _ZEBRA_ZCLIENT_H */ diff --git a/lib/zebra.h b/lib/zebra.h index 05e7013c5..c1231e4c8 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -433,7 +433,8 @@ struct in_pktinfo #define ZEBRA_IMPORT_ROUTE_REGISTER 30 #define ZEBRA_IMPORT_ROUTE_UNREGISTER 31 #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 * the command value in the old zserv header. To allow old and new diff --git a/zebra/rib.h b/zebra/rib.h index a05bd8c19..45daad0fe 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -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); 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); extern int diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index db679e857..7adbcbe53 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3221,7 +3221,7 @@ rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p, } 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) { struct route_table *table; @@ -3231,26 +3231,41 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi, int ret = 0; unsigned int 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)) + if (p->family == AF_INET) { - 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 { - 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 */ - if (! table) - return 0; + /* 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); + } - /* 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. */ if (rib->distance == 0) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a36f8600b..c95322a56 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -888,6 +888,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) struct rib *rib; struct nexthop *nexthop, *tnexthop; int recursing; + char buf[BUFSIZ]; RNODE_FOREACH_RIB (rn, rib) { @@ -958,6 +959,18 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) if (nexthop->ifindex) vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); 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: vty_out (vty, " directly connected, %s", ifindex2ifname (nexthop->ifindex)); @@ -1058,6 +1071,19 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) if (nexthop->ifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); 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: vty_out (vty, " is directly connected, %s", ifindex2ifname (nexthop->ifindex)); @@ -1168,7 +1194,7 @@ DEFUN (show_ip_route, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } diff --git a/zebra/zserv.c b/zebra/zserv.c index 79c469cfc..61d3a0a55 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1268,6 +1268,127 @@ zread_ipv4_import_lookup (struct zserv *client, u_short length) #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. */ +static int zread_ipv6_add (struct zserv *client, u_short length) { int i; @@ -1385,7 +1506,7 @@ zread_ipv6_add (struct zserv *client, u_short length) /* Table */ 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 */ if (ret > 0) client->v6_route_add_cnt++; @@ -1731,6 +1852,9 @@ zebra_client_read (struct thread *thread) zread_ipv4_delete (client, length); break; #ifdef HAVE_IPV6 + case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD: + zread_ipv4_route_ipv6_nexthop_add (client, length); + break; case ZEBRA_IPV6_ROUTE_ADD: zread_ipv6_add (client, length); break; |