summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/bgp.c123
-rw-r--r--proto/bgp/bgp.h17
-rw-r--r--proto/bgp/config.Y8
-rw-r--r--proto/bgp/packets.c362
4 files changed, 307 insertions, 203 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 976fbd90..7d974d17 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1066,7 +1066,6 @@ bgp_start_neighbor(struct bgp_proto *p)
{
/* Find some link-local address for given iface */
struct ifa *a;
- p->link_addr = IPA_NONE;
WALK_LIST(a, p->neigh->iface->addrs)
if (a->scope == SCOPE_LINK)
{
@@ -1294,6 +1293,7 @@ bgp_start(struct proto *P)
p->remote_id = 0;
p->source_addr = p->cf->local_ip;
+ p->link_addr = IPA_NONE;
/* XXXX */
if (p->p.gr_recovery && p->cf->gr_mode)
@@ -1415,12 +1415,6 @@ bgp_init(struct proto_config *CF)
return P;
}
-static inline rtable *
-get_igp_table(struct bgp_channel_config *cf)
-{
- return cf->igp_table ? cf->igp_table->table : cf->c.table->table;
-}
-
static void
bgp_channel_init(struct channel *C, struct channel_config *CF)
{
@@ -1429,8 +1423,13 @@ bgp_channel_init(struct channel *C, struct channel_config *CF)
c->cf = cf;
c->afi = cf->afi;
- c->desc = bgp_get_af_desc(c->afi);
- c->igp_table = get_igp_table(cf);
+ c->desc = cf->desc;
+
+ if (cf->igp_table_ip4)
+ c->igp_table_ip4 = cf->igp_table_ip4->table;
+
+ if (cf->igp_table_ip6)
+ c->igp_table_ip6 = cf->igp_table_ip6->table;
}
static int
@@ -1440,7 +1439,11 @@ bgp_channel_start(struct channel *C)
struct bgp_channel *c = (void *) C;
ip_addr src = p->source_addr;
- rt_lock_table(c->igp_table);
+ if (c->igp_table_ip4)
+ rt_lock_table(c->igp_table_ip4);
+
+ if (c->igp_table_ip6)
+ rt_lock_table(c->igp_table_ip6);
c->pool = p->p.pool; // XXXX
bgp_init_bucket_table(c);
@@ -1453,15 +1456,22 @@ bgp_channel_start(struct channel *C)
/* Try to use source address as next hop address */
if (ipa_zero(c->next_hop_addr))
{
- if (bgp_channel_is_ipv4(c) && ipa_is_ip4(src))
+ if (bgp_channel_is_ipv4(c) && (ipa_is_ip4(src) || c->ext_next_hop))
c->next_hop_addr = src;
- if (bgp_channel_is_ipv6(c) && ipa_is_ip6(src) && !ipa_is_link_local(src))
+ if (bgp_channel_is_ipv6(c) && (ipa_is_ip6(src) || c->ext_next_hop))
c->next_hop_addr = src;
}
+ /* Exit if no feasible next hop address is found */
+ if (ipa_zero(c->next_hop_addr))
+ {
+ log(L_WARN "%s: Missing next hop address", p->p.name);
+ return 0;
+ }
+
/* Set link-local address for IPv6 single-hop BGP */
- if (bgp_channel_is_ipv6(c) && p->neigh)
+ if (ipa_is_ip6(c->next_hop_addr) && p->neigh)
{
c->link_addr = p->link_addr;
@@ -1469,9 +1479,9 @@ bgp_channel_start(struct channel *C)
log(L_WARN "%s: Missing link-local address", p->p.name);
}
- /* No next hop address is valid on IPv6 link-local BGP */
- if (ipa_zero(c->next_hop_addr) && !ipa_is_link_local(src))
- log(L_WARN "%s: Missing next hop address", p->p.name);
+ /* Link local address is already in c->link_addr */
+ if (ipa_is_link_local(c->next_hop_addr))
+ c->next_hop_addr = IPA_NONE;
return 0; /* XXXX: Currently undefined */
}
@@ -1492,9 +1502,55 @@ bgp_channel_cleanup(struct channel *C)
{
struct bgp_channel *c = (void *) C;
- rt_unlock_table(c->igp_table);
+ if (c->igp_table_ip4)
+ rt_unlock_table(c->igp_table_ip4);
+
+ if (c->igp_table_ip6)
+ rt_unlock_table(c->igp_table_ip6);
+}
+
+static inline struct bgp_channel_config *
+bgp_find_channel_config(struct bgp_config *cf, u32 afi)
+{
+ struct bgp_channel_config *cc;
+
+ WALK_LIST(cc, cf->c.channels)
+ if (cc->afi == afi)
+ return cc;
+
+ return NULL;
}
+struct rtable_config *
+bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32 type)
+{
+ struct bgp_channel_config *cc2;
+ struct rtable_config *tab;
+
+ /* First, try table connected by the channel */
+ if (cc->c.table->addr_type == type)
+ return cc->c.table;
+
+ /* Find paired channel with the same SAFI but the other AFI */
+ u32 afi2 = cc->afi ^ 0x30000;
+ cc2 = bgp_find_channel_config(cf, afi2);
+
+ /* Second, try IGP table configured in the paired channel */
+ if (cc2 && (tab = (type == NET_IP4) ? cc2->igp_table_ip4 : cc2->igp_table_ip6))
+ return tab;
+
+ /* Third, try table connected by the paired channel */
+ if (cc2 && (cc2->c.table->addr_type == type))
+ return cc2->c.table;
+
+ /* Last, try default table of given type */
+ if (tab = cf->c.global->def_tables[type])
+ return tab;
+
+ cf_error("Undefined IGP table");
+}
+
+
void
bgp_postconfig(struct proto_config *CF)
{
@@ -1568,6 +1624,15 @@ bgp_postconfig(struct proto_config *CF)
if (cc->gr_able == 0xff)
cc->gr_able = (cf->gr_mode == BGP_GR_ABLE);
+ if ((cc->gw_mode == GW_RECURSIVE) && !cc->desc->no_igp)
+ {
+ if (!cc->igp_table_ip4 && (bgp_cc_is_ipv4(cc) || cc->ext_next_hop))
+ cc->igp_table_ip4 = bgp_default_igp_table(cf, cc, NET_IP4);
+
+ if (!cc->igp_table_ip6 && (bgp_cc_is_ipv6(cc) || cc->ext_next_hop))
+ cc->igp_table_ip6 = bgp_default_igp_table(cf, cc, NET_IP6);
+ }
+
if (cf->multihop && (cc->gw_mode == GW_DIRECT))
cf_error("Multihop BGP cannot use direct gateway mode");
@@ -1637,11 +1702,17 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC)
if (memcmp(((byte *) old) + sizeof(struct channel_config),
((byte *) new) + sizeof(struct channel_config),
- /* igp_table item is last and must be checked separately */
- OFFSETOF(struct bgp_channel_config, igp_table) - sizeof(struct channel_config)))
+ /* Remaining items must be checked separately */
+ OFFSETOF(struct bgp_channel_config, rest) - sizeof(struct channel_config)))
return 0;
- if (get_igp_table(old) != get_igp_table(new))
+ /* Check change in IGP tables */
+ rtable *old4 = old->igp_table_ip4 ? old->igp_table_ip4->table : NULL;
+ rtable *old6 = old->igp_table_ip6 ? old->igp_table_ip6->table : NULL;
+ rtable *new4 = new->igp_table_ip4 ? new->igp_table_ip4->table : NULL;
+ rtable *new6 = new->igp_table_ip6 ? new->igp_table_ip6->table : NULL;
+
+ if ((old4 != new4) || (old6 != new6))
return 0;
c->cf = new;
@@ -1956,9 +2027,17 @@ bgp_show_proto_info(struct proto *P)
{
/* XXXX ?? */
- struct channel *c;
+ struct bgp_channel *c;
WALK_LIST(c, p->p.channels)
- channel_show_info(c);
+ {
+ channel_show_info(&c->c);
+
+ if (c->igp_table_ip4)
+ cli_msg(-1006, " IGP IPv4 table: %s", c->igp_table_ip4->name);
+
+ if (c->igp_table_ip6)
+ cli_msg(-1006, " IGP IPv6 table: %s", c->igp_table_ip6->name);
+ }
}
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 36fd39e8..6511680d 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -61,7 +61,8 @@ struct bgp_bucket;
struct bgp_af_desc {
u32 afi;
u32 net;
- int mpls;
+ u8 mpls;
+ u8 no_igp;
const char *name;
uint (*encode_nlri)(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size);
void (*decode_nlri)(struct bgp_parse_state *s, byte *pos, uint len, rta *a);
@@ -122,6 +123,7 @@ struct bgp_channel_config {
struct channel_config c;
u32 afi;
+ const struct bgp_af_desc *desc;
ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */
u8 next_hop_self; /* Always set next hop to local IP address */
@@ -133,7 +135,9 @@ struct bgp_channel_config {
u8 ext_next_hop; /* Allow both IPv4 and IPv6 next hops */
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
- struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
+ uint rest[0]; /* Remaining items are reconfigured separately */
+ struct rtable_config *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
+ struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
};
#define MLL_SELF 1
@@ -274,7 +278,8 @@ struct bgp_channel {
HASH(struct bgp_prefix) prefix_hash; /* Prefixes to be sent */
slab *prefix_slab; /* Slab holding prefix nodes */
- rtable *igp_table; /* Table used for recursive next hop lookups */
+ rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
+ rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */
ip_addr link_addr; /* Link-local version of next_hop_addr */
@@ -393,6 +398,12 @@ static inline int bgp_channel_is_ipv4(struct bgp_channel *c)
static inline int bgp_channel_is_ipv6(struct bgp_channel *c)
{ return BGP_AFI(c->afi) == BGP_AFI_IPV6; }
+static inline int bgp_cc_is_ipv4(struct bgp_channel_config *c)
+{ return BGP_AFI(c->afi) == BGP_AFI_IPV4; }
+
+static inline int bgp_cc_is_ipv6(struct bgp_channel_config *c)
+{ return BGP_AFI(c->afi) == BGP_AFI_IPV6; }
+
static inline uint bgp_max_packet_length(struct bgp_conn *conn)
{ return conn->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; }
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index e23c5b3b..1678256b 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -158,6 +158,7 @@ bgp_channel_start: bgp_afi
BGP_CC->c.name = desc->name;
BGP_CC->c.ra_mode = RA_UNDEF;
BGP_CC->afi = $1;
+ BGP_CC->desc = desc;
BGP_CC->gr_able = 0xff; /* undefined */
};
@@ -177,7 +178,12 @@ bgp_channel_item:
| ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
- | IGP TABLE rtable { BGP_CC->igp_table = $3; }
+ | IGP TABLE rtable {
+ if (bgp_cc_is_ipv4(BGP_CC)) BGP_CC->igp_table_ip4 = $3;
+ if (bgp_cc_is_ipv6(BGP_CC)) BGP_CC->igp_table_ip6 = $3;
+ }
+ | IGP TABLE IPV4 rtable { BGP_CC->igp_table_ip4 = $4; }
+ | IGP TABLE IPV6 rtable { BGP_CC->igp_table_ip6 = $4; }
;
bgp_channel_opts:
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);