diff options
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r-- | proto/bgp/packets.c | 362 |
1 files changed, 185 insertions, 177 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 5819965d..e11be197 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -760,7 +760,8 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll) if (ipa_zero(gw)) WITHDRAW(BAD_NEXT_HOP); - s->hostentry = rt_get_hostentry(c->igp_table, gw, ll, c->c.table); + rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6; + s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table); if (!s->mpls) rta_apply_hostentry(a, s->hostentry, NULL); @@ -887,18 +888,181 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to) ip_addr peer = s->proto->cf->remote_ip; uint len = a->u.ptr->length; + /* Forbid zero next hop */ if (ipa_zero(nh[0]) && ((len != 32) || ipa_zero(nh[1]))) WITHDRAW(BAD_NEXT_HOP); + /* Forbid next hop equal to neighbor IP */ if (ipa_equal(peer, nh[0]) || ((len == 32) && ipa_equal(peer, nh[1]))) WITHDRAW(BAD_NEXT_HOP); + /* Forbid next hop with non-matching AF */ + if ((ipa_is_ip4(nh[0]) != bgp_channel_is_ipv4(s->channel)) && + !s->channel->ext_next_hop) + WITHDRAW(BAD_NEXT_HOP); + /* Just check if MPLS stack */ if (s->mpls && !bgp_find_attr(*to, BA_MPLS_LABEL_STACK)) WITHDRAW(NO_LABEL_STACK); } static uint +bgp_encode_next_hop_ip(struct bgp_write_state *s, eattr *a, byte *buf, uint size UNUSED) +{ + /* This function is used only for MP-BGP, see bgp_encode_next_hop() for IPv4 BGP */ + ip_addr *nh = (void *) a->u.ptr->data; + uint len = a->u.ptr->length; + + ASSERT((len == 16) || (len == 32)); + + /* + * Both IPv4 and IPv6 next hops can be used (with ext_next_hop enabled). This + * is specified in RFC 5549 for IPv4 and in RFC 4798 for IPv6. The difference + * is that IPv4 address is directly encoded with IPv4 NLRI, but as IPv4-mapped + * IPv6 address with IPv6 NLRI. + */ + + if (bgp_channel_is_ipv4(s->channel) && ipa_is_ip4(nh[0])) + { + put_ip4(buf, ipa_to_ip4(nh[0])); + return 4; + } + + put_ip6(buf, ipa_to_ip6(nh[0])); + + if (len == 32) + put_ip6(buf+16, ipa_to_ip6(nh[1])); + + return len; +} + +static void +bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a) +{ + struct bgp_channel *c = s->channel; + struct adata *ad = lp_alloc_adata(s->pool, 32); + ip_addr *nh = (void *) ad->data; + + if (len == 4) + { + nh[0] = ipa_from_ip4(get_ip4(data)); + nh[1] = IPA_NONE; + } + else if (len == 16) + { + nh[0] = ipa_from_ip6(get_ip6(data)); + nh[1] = IPA_NONE; + + if (ipa_is_link_local(nh[0])) + { nh[1] = nh[0]; nh[0] = IPA_NONE; } + } + else if (len == 32) + { + nh[0] = ipa_from_ip6(get_ip6(data)); + nh[1] = ipa_from_ip6(get_ip6(data+16)); + + if (ipa_is_ip4(nh[0]) || !ip6_is_link_local(nh[1])) + nh[1] = IPA_NONE; + } + else + bgp_parse_error(s, 9); + + if (ipa_zero(nh[1])) + ad->length = 16; + + if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) + WITHDRAW(BAD_NEXT_HOP); + + // XXXX validate next hop + + bgp_set_attr_ptr(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, ad); + bgp_apply_next_hop(s, a, nh[0], nh[1]); +} + +static uint +bgp_encode_next_hop_vpn(struct bgp_write_state *s, eattr *a, byte *buf, uint size UNUSED) +{ + ip_addr *nh = (void *) a->u.ptr->data; + uint len = a->u.ptr->length; + + ASSERT((len == 16) || (len == 32)); + + /* + * Both IPv4 and IPv6 next hops can be used (with ext_next_hop enabled). This + * is specified in RFC 5549 for VPNv4 and in RFC 4659 for VPNv6. The difference + * is that IPv4 address is directly encoded with VPNv4 NLRI, but as IPv4-mapped + * IPv6 address with VPNv6 NLRI. + */ + + if (bgp_channel_is_ipv4(s->channel) && ipa_is_ip4(nh[0])) + { + put_u64(buf, 0); /* VPN RD is 0 */ + put_ip4(buf+8, ipa_to_ip4(nh[0])); + return 12; + } + + put_u64(buf, 0); /* VPN RD is 0 */ + put_ip6(buf+8, ipa_to_ip6(nh[0])); + + if (len == 16) + return 24; + + put_u64(buf+24, 0); /* VPN RD is 0 */ + put_ip6(buf+32, ipa_to_ip6(nh[1])); + + return 48; +} + +static void +bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a) +{ + struct bgp_channel *c = s->channel; + struct adata *ad = lp_alloc_adata(s->pool, 32); + ip_addr *nh = (void *) ad->data; + + if (len == 12) + { + nh[0] = ipa_from_ip4(get_ip4(data+8)); + nh[1] = IPA_NONE; + } + else if (len == 24) + { + nh[0] = ipa_from_ip6(get_ip6(data+8)); + nh[1] = IPA_NONE; + + if (ipa_is_link_local(nh[0])) + { nh[1] = nh[0]; nh[0] = IPA_NONE; } + } + else if (len == 48) + { + nh[0] = ipa_from_ip6(get_ip6(data+8)); + nh[1] = ipa_from_ip6(get_ip6(data+32)); + + if (ipa_is_ip4(nh[0]) || !ip6_is_link_local(nh[1])) + nh[1] = IPA_NONE; + } + else + bgp_parse_error(s, 9); + + if (ipa_zero(nh[1])) + ad->length = 16; + + /* XXXX which error */ + if ((get_u64(data) != 0) || ((len == 48) && (get_u64(data+24) != 0))) + bgp_parse_error(s, 9); + + if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop) + WITHDRAW(BAD_NEXT_HOP); + + // XXXX validate next hop + + bgp_set_attr_ptr(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, ad); + bgp_apply_next_hop(s, a, nh[0], nh[1]); +} + + + +static uint bgp_encode_next_hop_none(struct bgp_write_state *s UNUSED, eattr *a UNUSED, byte *buf UNUSED, uint size UNUSED) { return 0; @@ -1115,32 +1279,6 @@ bgp_decode_nlri_ip4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) } } -static uint -bgp_encode_next_hop_ip4(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size UNUSED) -{ - /* This function is used only for MP-BGP, see bgp_encode_next_hop() for IPv4 BGP */ - - ASSERT(a->u.ptr->length == sizeof(ip_addr)); - - put_ip4(buf, ipa_to_ip4( *(ip_addr *) a->u.ptr->data )); - - return 4; -} - -static void -bgp_decode_next_hop_ip4(struct bgp_parse_state *s, byte *data, uint len, rta *a) -{ - if (len != 4) - bgp_parse_error(s, 9); - - ip_addr nh = ipa_from_ip4(get_ip4(data)); - - // XXXX validate next hop - - bgp_set_attr_data(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, &nh, sizeof(nh)); - bgp_apply_next_hop(s, a, nh, IPA_NONE); -} - static uint bgp_encode_nlri_ip6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) @@ -1227,53 +1365,6 @@ bgp_decode_nlri_ip6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) } static uint -bgp_encode_next_hop_ip6(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size UNUSED) -{ - ip_addr *nh = (void *) a->u.ptr->data; - uint len = a->u.ptr->length; - - ASSERT((len == 16) || (len == 32)); - - put_ip6(buf, ipa_to_ip6(nh[0])); - - if (len == 32) - put_ip6(buf+16, ipa_to_ip6(nh[1])); - - return len; -} - -static void -bgp_decode_next_hop_ip6(struct bgp_parse_state *s, byte *data, uint len, rta *a) -{ - struct adata *ad = lp_alloc_adata(s->pool, 32); - ip_addr *nh = (void *) ad->data; - - if ((len != 16) && (len != 32)) - bgp_parse_error(s, 9); - - nh[0] = ipa_from_ip6(get_ip6(data)); - nh[1] = (len == 32) ? ipa_from_ip6(get_ip6(data+16)) : IPA_NONE; - - if (ip6_is_link_local(nh[0])) - { - nh[1] = nh[0]; - nh[0] = IPA_NONE; - } - - if (!ip6_is_link_local(nh[1])) - nh[1] = IPA_NONE; - - if (ipa_zero(nh[1])) - ad->length = 16; - - // XXXX validate next hop - - bgp_set_attr_ptr(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, ad); - bgp_apply_next_hop(s, a, nh[0], nh[1]); -} - - -static uint bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) { byte *pos = buf; @@ -1367,37 +1458,6 @@ bgp_decode_nlri_vpn4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) } } -static uint -bgp_encode_next_hop_vpn4(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size UNUSED) -{ - /* This function is used only for MP-BGP, see bgp_encode_next_hop() for IPv4 BGP */ - - ASSERT(a->u.ptr->length == sizeof(ip_addr)); - - put_u64(buf, 0); /* VPN RD is 0 */ - put_ip4(buf+8, ipa_to_ip4( *(ip_addr *) a->u.ptr->data )); - - return 12; -} - -static void -bgp_decode_next_hop_vpn4(struct bgp_parse_state *s, byte *data, uint len, rta *a) -{ - if (len != 12) - bgp_parse_error(s, 9); - - /* XXXX which error */ - if (get_u64(data) != 0) - bgp_parse_error(s, 9); - - ip_addr nh = ipa_from_ip4(get_ip4(data+8)); - - // XXXX validate next hop - - bgp_set_attr_data(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, &nh, sizeof(nh)); - bgp_apply_next_hop(s, a, nh, IPA_NONE); -} - static uint bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) @@ -1494,60 +1554,6 @@ bgp_decode_nlri_vpn6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) } } -static uint -bgp_encode_next_hop_vpn6(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size UNUSED) -{ - ip_addr *nh = (void *) a->u.ptr->data; - uint len = a->u.ptr->length; - - ASSERT((len == 16) || (len == 32)); - - put_u64(buf, 0); /* VPN RD is 0 */ - put_ip6(buf+8, ipa_to_ip6(nh[0])); - - if (len == 16) - return 24; - - put_u64(buf+24, 0); /* VPN RD is 0 */ - put_ip6(buf+32, ipa_to_ip6(nh[1])); - - return 48; -} - -static void -bgp_decode_next_hop_vpn6(struct bgp_parse_state *s, byte *data, uint len, rta *a) -{ - struct adata *ad = lp_alloc_adata(s->pool, 32); - ip_addr *nh = (void *) ad->data; - - if ((len != 24) && (len != 48)) - bgp_parse_error(s, 9); - - /* XXXX which error */ - if ((get_u64(data) != 0) || ((len == 48) && (get_u64(data+24) != 0))) - bgp_parse_error(s, 9); - - nh[0] = ipa_from_ip6(get_ip6(data+8)); - nh[1] = (len == 48) ? ipa_from_ip6(get_ip6(data+32)) : IPA_NONE; - - if (ip6_is_link_local(nh[0])) - { - nh[1] = nh[0]; - nh[0] = IPA_NONE; - } - - if (!ip6_is_link_local(nh[1])) - nh[1] = IPA_NONE; - - if (ipa_zero(nh[1])) - ad->length = 16; - - // XXXX validate next hop - - bgp_set_attr_ptr(&(a->eattrs), s->pool, BA_NEXT_HOP, 0, ad); - bgp_apply_next_hop(s, a, nh[0], nh[1]); -} - static uint bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) @@ -1740,8 +1746,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv4", .encode_nlri = bgp_encode_nlri_ip4, .decode_nlri = bgp_decode_nlri_ip4, - .encode_next_hop = bgp_encode_next_hop_ip4, - .decode_next_hop = bgp_decode_next_hop_ip4, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1750,8 +1756,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv4-mc", .encode_nlri = bgp_encode_nlri_ip4, .decode_nlri = bgp_decode_nlri_ip4, - .encode_next_hop = bgp_encode_next_hop_ip4, - .decode_next_hop = bgp_decode_next_hop_ip4, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1761,8 +1767,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv4-mpls", .encode_nlri = bgp_encode_nlri_ip4, .decode_nlri = bgp_decode_nlri_ip4, - .encode_next_hop = bgp_encode_next_hop_ip4, - .decode_next_hop = bgp_decode_next_hop_ip4, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1771,8 +1777,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv6", .encode_nlri = bgp_encode_nlri_ip6, .decode_nlri = bgp_decode_nlri_ip6, - .encode_next_hop = bgp_encode_next_hop_ip6, - .decode_next_hop = bgp_decode_next_hop_ip6, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1781,8 +1787,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv6-mc", .encode_nlri = bgp_encode_nlri_ip6, .decode_nlri = bgp_decode_nlri_ip6, - .encode_next_hop = bgp_encode_next_hop_ip6, - .decode_next_hop = bgp_decode_next_hop_ip6, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1792,8 +1798,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "ipv6-mpls", .encode_nlri = bgp_encode_nlri_ip6, .decode_nlri = bgp_decode_nlri_ip6, - .encode_next_hop = bgp_encode_next_hop_ip6, - .decode_next_hop = bgp_decode_next_hop_ip6, + .encode_next_hop = bgp_encode_next_hop_ip, + .decode_next_hop = bgp_decode_next_hop_ip, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1803,8 +1809,8 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "vpn4-mpls", .encode_nlri = bgp_encode_nlri_vpn4, .decode_nlri = bgp_decode_nlri_vpn4, - .encode_next_hop = bgp_encode_next_hop_vpn4, - .decode_next_hop = bgp_decode_next_hop_vpn4, + .encode_next_hop = bgp_encode_next_hop_vpn, + .decode_next_hop = bgp_decode_next_hop_vpn, .update_next_hop = bgp_update_next_hop_ip, }, { @@ -1814,13 +1820,14 @@ static const struct bgp_af_desc bgp_af_table[] = { .name = "vpn6-mpls", .encode_nlri = bgp_encode_nlri_vpn6, .decode_nlri = bgp_decode_nlri_vpn6, - .encode_next_hop = bgp_encode_next_hop_vpn6, - .decode_next_hop = bgp_decode_next_hop_vpn6, + .encode_next_hop = bgp_encode_next_hop_vpn, + .decode_next_hop = bgp_decode_next_hop_vpn, .update_next_hop = bgp_update_next_hop_ip, }, { .afi = BGP_AF_FLOW4, .net = NET_FLOW4, + .no_igp = 1, .name = "flow4", .encode_nlri = bgp_encode_nlri_flow4, .decode_nlri = bgp_decode_nlri_flow4, @@ -1831,6 +1838,7 @@ static const struct bgp_af_desc bgp_af_table[] = { { .afi = BGP_AF_FLOW6, .net = NET_FLOW6, + .no_igp = 1, .name = "flow6", .encode_nlri = bgp_encode_nlri_flow6, .decode_nlri = bgp_decode_nlri_flow6, @@ -2039,7 +2047,7 @@ again: ; /* Try unreachable bucket */ if ((buck = c->withdraw_bucket) && !EMPTY_LIST(buck->prefixes)) { - res = (c->afi == BGP_AF_IPV4) ? + res = (c->afi == BGP_AF_IPV4) && !c->ext_next_hop ? bgp_create_ip_unreach(&s, buck, buf, end): bgp_create_mp_unreach(&s, buck, buf, end); @@ -2058,7 +2066,7 @@ again: ; goto again; } - res = (c->afi == BGP_AF_IPV4) ? + res = (c->afi == BGP_AF_IPV4) && !c->ext_next_hop ? bgp_create_ip_reach(&s, buck, buf, end): bgp_create_mp_reach(&s, buck, buf, end); |