diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5fe8ebb67f..4d5f7cab5d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2742,6 +2742,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, else if (nh_afi == AFI_MAX) nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len); /* Nexthop */ + bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); switch (nh_afi) { case AFI_IP: @@ -2754,7 +2755,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, stream_put_ipv4 (s, attr->nexthop.s_addr); break; case SAFI_MPLS_VPN: - bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); stream_putc (s, 12); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); @@ -2777,7 +2777,6 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, struct attr_extra *attre = attr->extra; assert (attr->extra); - bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); stream_putc (s, attre->mp_nexthop_len); stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN); if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 060f5afb4c..8764050b16 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -238,6 +238,42 @@ DEFUN (no_encap_network, 0, NULL, NULL, NULL); } +DEFUN (encapv6_network, + encapv6_network_cmd, + "network X:X::X:X/M rd ASN:nn_or_IP-address:nn [route-map WORD]", + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "route map\n" + "route map name\n") +{ + int idx_ipv6 = 1; + int idx_rd = 3; + int idx_rmap = 5; + const char *rmap_str = (argc == 6) ? argv[idx_rmap]->arg : NULL; + return bgp_static_set_safi (AFI_IP6, SAFI_ENCAP, vty, argv[idx_ipv6]->arg, + argv[idx_rd]->arg, NULL, rmap_str, 0, NULL, + NULL, NULL, NULL); +} + +DEFUN (no_encapv6_network, + no_encapv6_network_cmd, + "no network X:X::X:X/M rd ASN:nn_or_IP-address:nn [route-map WORD]", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "route map\n" + "route map name\n") +{ + int idx_ipv6 = 2; + int idx_rd = 4; + return bgp_static_unset_safi (AFI_IP6, SAFI_ENCAP, vty, argv[idx_ipv6]->arg, + argv[idx_rd]->arg, NULL, 0, NULL, NULL, NULL); +} + static int show_adj_route_encap (struct vty *vty, struct peer *peer, struct prefix_rd *prd) { @@ -758,6 +794,8 @@ bgp_encap_init (void) { install_element (BGP_ENCAP_NODE, &encap_network_cmd); install_element (BGP_ENCAP_NODE, &no_encap_network_cmd); + install_element (BGP_ENCAPV6_NODE, &encapv6_network_cmd); + install_element (BGP_ENCAPV6_NODE, &no_encapv6_network_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_tags_cmd); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 4a8bfed8bb..f25c00005a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -381,31 +381,6 @@ out: return lret; } -int -str2tag (const char *str, u_char *tag) -{ - unsigned long l; - char *endptr; - u_int32_t t; - - if (*str == '-') - return 0; - - errno = 0; - l = strtoul (str, &endptr, 10); - - if (*endptr != '\0' || errno || l > UINT32_MAX) - return 0; - - t = (u_int32_t) l; - - tag[0] = (u_char)(t >> 12); - tag[1] = (u_char)(t >> 4); - tag[2] = (u_char)(t << 4); - - return 1; -} - char * prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) { diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 518bf6143f..3abd818b10 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -104,7 +104,6 @@ extern void decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth); #endif extern int str2prefix_rd (const char *, struct prefix_rd *); -extern int str2tag (const char *, u_char *); extern char *prefix_rd2str (struct prefix_rd *, char *, size_t); extern int diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5c157b9539..13279f89b1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10434,10 +10434,12 @@ bgp_config_write_network_vpn (struct vty *vty, struct bgp *bgp, prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); label = decode_label (bgp_static->tag); - vty_out (vty, " network %s/%d rd %s label %d", + vty_out (vty, " network %s/%d rd %s", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, - rdbuf, label); + p->prefixlen, rdbuf); + if (safi == SAFI_MPLS_VPN) + vty_out (vty, " label %u", label); + if (bgp_static->rmap.name) vty_out (vty, " route-map %s", bgp_static->rmap.name); else diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 8839de391e..5872ca6f3f 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -427,21 +427,33 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen); if (peer_cap_enhe(peer)) nhafi = AFI_IP6; - if (paf->safi == SAFI_MPLS_VPN && /* if VPN && not global */ - nhlen != BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) - nhafi = AFI_MAX; /* no change allowed */ } if (nhafi == AFI_IP) { struct in_addr v4nh, *mod_v4nh; int nh_modified = 0; + size_t offset_nh = vec->offset + 1; route_map_sets_nh = (CHECK_FLAG (vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED) || CHECK_FLAG (vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)); - stream_get_from (&v4nh, s, vec->offset + 1, 4); + switch (nhlen) + { + case BGP_ATTR_NHLEN_IPV4: + break; + case BGP_ATTR_NHLEN_VPNV4: + offset_nh += 8; + break; + default: + /* TODO: handle IPv6 nexthops */ + zlog_warn ("%s: %s: invalid MP nexthop length (AFI IP): %u", + __func__, peer->host, nhlen); + return NULL; + } + + stream_get_from (&v4nh, s, offset_nh, IPV4_MAX_BYTELEN); mod_v4nh = &v4nh; /* @@ -482,7 +494,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) } if (nh_modified) /* allow for VPN RD */ - stream_put_in_addr_at (s, vec->offset + 1 + nhlen - 4, mod_v4nh); + stream_put_in_addr_at (s, offset_nh, mod_v4nh); if (bgp_debug_update(peer, NULL, NULL, 0)) zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s send UPDATE w/ nexthop %s%s", @@ -495,6 +507,8 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) struct in6_addr v6nhglobal, *mod_v6nhg; struct in6_addr v6nhlocal, *mod_v6nhl; int gnh_modified, lnh_modified; + size_t offset_nhglobal = vec->offset + 1; + size_t offset_nhlocal = vec->offset + 1; gnh_modified = lnh_modified = 0; mod_v6nhg = &v6nhglobal; @@ -509,7 +523,28 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) * additional work being to handle 1 or 2 nexthops. Also, 3rd * party nexthop is not propagated for EBGP right now. */ - stream_get_from (&v6nhglobal, s, vec->offset + 1, 16); + switch (nhlen) + { + case BGP_ATTR_NHLEN_IPV6_GLOBAL: + break; + case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: + offset_nhlocal += IPV6_MAX_BYTELEN; + break; + case BGP_ATTR_NHLEN_VPNV6_GLOBAL: + offset_nhglobal += 8; + break; + case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL: + offset_nhglobal += 8; + offset_nhlocal += 8 * 2 + IPV6_MAX_BYTELEN; + break; + default: + /* TODO: handle IPv4 nexthops */ + zlog_warn ("%s: %s: invalid MP nexthop length (AFI IP6): %u", + __func__, peer->host, nhlen); + return NULL; + } + + stream_get_from (&v6nhglobal, s, offset_nhglobal, IPV6_MAX_BYTELEN); if (route_map_sets_nh) { if (CHECK_FLAG(vec->flags, @@ -536,9 +571,10 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) } - if (nhlen == 32 || nhlen == 48) /* 48 == VPN */ + if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL || + nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { - stream_get_from (&v6nhlocal, s, vec->offset + 1 + (nhlen-IPV6_MAX_BYTELEN), IPV6_MAX_BYTELEN); + stream_get_from (&v6nhlocal, s, offset_nhlocal, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_UNSPECIFIED (&v6nhlocal)) { mod_v6nhl = &peer->nexthop.v6_local; @@ -547,9 +583,9 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf) } if (gnh_modified) - stream_put_in6_addr_at (s, vec->offset + 1, mod_v6nhg); + stream_put_in6_addr_at (s, offset_nhglobal, mod_v6nhg); if (lnh_modified) - stream_put_in6_addr_at (s, vec->offset + 1 + (nhlen-IPV6_MAX_BYTELEN), mod_v6nhl); + stream_put_in6_addr_at (s, offset_nhlocal, mod_v6nhl); if (bgp_debug_update(peer, NULL, NULL, 0)) {