0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-16 18:35:19 +00:00

BMP: Remove duplicate functions for update encoding

Use existing BGP functions also for BMP update encoding.
This commit is contained in:
Ondrej Zajicek (work) 2021-03-29 04:43:04 +02:00 committed by Ondrej Zajicek
parent 568fd66613
commit 4d56b70dc5
5 changed files with 101 additions and 335 deletions

View File

@ -214,8 +214,7 @@ struct proto {
void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
void (*rte_update_in_notify)(const struct proto *, const struct channel *,
const net *net, const struct rte *new, const struct rte *old, const struct rte_src *src);
void (*rte_update_in_notify)(struct channel *, const net_addr *, const struct rte *, const struct rte_src *);
void (*neigh_notify)(struct neighbor *neigh);
int (*preexport)(struct channel *, struct rte *rt);
void (*reload_routes)(struct channel *);

View File

@ -3097,7 +3097,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
c->proto->rte_update_in_notify(c, n, old, src);
return 1;
}
@ -3122,12 +3122,12 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
if (!old)
goto drop_withdraw;
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
if (!net->routes)
fib_delete(&tab->fib, net);
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c, n, NULL, src);
return 1;
}
@ -3158,7 +3158,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
tab->rt_count++;
if (c->proto->rte_update_in_notify)
c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
c->proto->rte_update_in_notify(c, n, e, src);
return 1;

View File

@ -434,6 +434,7 @@ struct bgp_write_state {
int as4_session;
int add_path;
int mpls;
int sham;
eattr *mp_next_hop;
const adata *mpls_labels;
@ -624,9 +625,7 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
int bgp_preexport(struct channel *, struct rte *);
void bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
const net *net, const struct rte *new, const struct rte *old,
const struct rte_src *src);
void bgp_rte_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *buf);
int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);

View File

@ -1566,7 +1566,10 @@ bgp_encode_nlri_ip4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -1651,7 +1654,10 @@ bgp_encode_nlri_ip6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -1739,7 +1745,10 @@ bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -1836,7 +1845,10 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -1923,7 +1935,10 @@ bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
memcpy(pos, net->data, flen);
ADVANCE(pos, size, flen);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -2015,7 +2030,10 @@ bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
memcpy(pos, net->data, flen);
ADVANCE(pos, size, flen);
bgp_free_prefix(s->channel, px);
if (!s->sham)
bgp_free_prefix(s->channel, px);
else
rem_node(&px->buck_node);
}
return pos - buf;
@ -2242,224 +2260,6 @@ bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to)
#define MAX_ATTRS_LENGTH (end-buf+BGP_HEADER_LENGTH - 1024)
/**
* Following functions starting with prefix bgp_bmp_* compose BGP UPDATE messages.
* Their implementation has been adopted from relevant function without 'bmp_' part in
* their names.
*/
// Buffer @buf should be big enough. It means that there should be available at least 19 bytes
static byte *
bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type)
{
if (!buf)
{
return NULL;
}
memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE);
put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size);
put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type);
return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE;
}
static uint
bgp_bmp_encode_nlri_ip4(struct bgp_write_state *s, const net *n,
const u32 path_id, byte *buf, uint size)
{
const struct net_addr_ip4 *naddr = (net_addr_ip4 *)n->n.addr;
byte *pos = buf;
/* Encode path ID */
if (s->add_path)
{
put_u32(pos, path_id);
ADVANCE(pos, size, 4);
}
/* Encode prefix length */
*pos = naddr->pxlen;
ADVANCE(pos, size, 1);
/* Encode MPLS labels */
if (s->mpls)
{
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
}
/* Encode prefix body */
ip4_addr a = ip4_hton(naddr->prefix);
uint b = (naddr->pxlen + 7) / 8;
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
return pos - buf;
}
static uint
bgp_bmp_encode_nlri_ip6(struct bgp_write_state *s, const net *n,
const u32 path_id, byte *buf, uint size)
{
if (size < BGP_NLRI_MAX)
{
return 0;
}
const struct net_addr_ip6 *naddr = (net_addr_ip6 *)n->n.addr;
byte *pos = buf;
/* Encode path ID */
if (s->add_path)
{
put_u32(pos, path_id);
ADVANCE(pos, size, 4);
}
/* Encode prefix length */
*pos = naddr->pxlen;
ADVANCE(pos, size, 1);
/* Encode MPLS labels */
if (s->mpls)
{
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
}
/* Encode prefix body */
ip6_addr a = ip6_hton(naddr->prefix);
uint b = (naddr->pxlen + 7) / 8;
memcpy(pos, &a, b);
ADVANCE(pos, size, b);
return pos - buf;
}
static byte *
bgp_bmp_create_ip_reach(struct bgp_write_state *s, const net *n,
const struct rte *new, const struct rte *old, const u32 path_id,
byte *buf, uint size)
{
/*
* 2 B Withdrawn Routes Length (zero)
* --- IPv4 Withdrawn Routes NLRI (unused)
* 2 B Total Path Attribute Length
* var Path Attributes
* var IPv4 Network Layer Reachability Information
*/
int lr, la; // Route length, attribute length
ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs;
bgp_fix_attr_flags(attrs);
la = bgp_encode_attrs(s, attrs, buf + 2, buf + size - 2);
if (la < 0)
{
/* Attribute list too long */
log(L_ERR "Failed to encode UPDATE msg attributes");
return NULL;
}
put_u16(buf, la);
lr = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2 + la, size - (2 + la));
return buf + 2 + la + lr;
}
static byte *
bgp_bmp_create_mp_reach(struct bgp_write_state *s, const net *n,
const struct rte *new, const struct rte *old, const u32 path_id,
byte *buf, uint size)
{
/*
* 2 B IPv4 Withdrawn Routes Length (zero)
* --- IPv4 Withdrawn Routes NLRI (unused)
* 2 B Total Path Attribute Length
* 1 B MP_REACH_NLRI hdr - Attribute Flags
* 1 B MP_REACH_NLRI hdr - Attribute Type Code
* 2 B MP_REACH_NLRI hdr - Length of Attribute Data
* 2 B MP_REACH_NLRI data - Address Family Identifier
* 1 B MP_REACH_NLRI data - Subsequent Address Family Identifier
* 1 B MP_REACH_NLRI data - Length of Next Hop Network Address
* var MP_REACH_NLRI data - Network Address of Next Hop
* 1 B MP_REACH_NLRI data - Reserved (zero)
* var MP_REACH_NLRI data - Network Layer Reachability Information
* var Rest of Path Attributes
* --- IPv4 Network Layer Reachability Information (unused)
*/
int lh, lr, la; /* Lengths of next hop, NLRI and attributes */
/* Begin of MP_REACH_NLRI atribute */
buf[4] = BAF_OPTIONAL | BAF_EXT_LEN;
buf[5] = BA_MP_REACH_NLRI;
put_u16(buf+6, 0); /* Will be fixed later */
put_af3(buf+8, s->channel->afi);
byte *pos = buf+11;
byte *end = buf + size;
/* Encode attributes to temporary buffer */
byte *abuf = alloca(MAX_ATTRS_LENGTH);
ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs;
bgp_fix_attr_flags(attrs);
la = bgp_encode_attrs(s, attrs, abuf, abuf + MAX_ATTRS_LENGTH);
if (la < 0)
{
/* Attribute list too long */
log(L_ERR "Failed to encode UPDATE msg attributes");
return NULL;
}
/* Encode the next hop */
lh = bgp_encode_next_hop(s, s->mp_next_hop, pos+1);
*pos = lh;
pos += 1+lh;
/* Reserved field */
*pos++ = 0;
/* Encode the NLRI */
lr = bgp_bmp_encode_nlri_ip6(s, n, path_id, pos, end - (buf + la));
pos += lr;
/* End of MP_REACH_NLRI atribute, update data length */
put_u16(buf+6, pos-buf-8);
/* Copy remaining attributes */
memcpy(pos, abuf, la);
pos += la;
/* Initial UPDATE fields */
put_u16(buf+0, 0);
put_u16(buf+2, pos-buf-4);
return pos;
}
static byte *
bgp_bmp_create_ip_unreach(struct bgp_write_state *s, const net *n,
const struct rte *new, const struct rte *old, const u32 path_id,
byte *buf, uint size)
{
/*
* 2 B Withdrawn Routes Length
* var IPv4 Withdrawn Routes NLRI
* 2 B Total Path Attribute Length (zero)
* --- Path Attributes (unused)
* --- IPv4 Network Layer Reachability Information (unused)
*/
uint len = 0;
bool is_withdrawn = !new && old;
if (is_withdrawn)
{
len = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2, size - 2);
}
put_u16(buf, len);
return buf + 2 + len;
}
static byte *
bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, byte *end)
{
@ -2477,7 +2277,8 @@ bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
if (la < 0)
{
/* Attribute list too long */
bgp_withdraw_bucket(s->channel, buck);
if (!s->sham)
bgp_withdraw_bucket(s->channel, buck);
return NULL;
}
@ -2524,7 +2325,8 @@ bgp_create_mp_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
if (la < 0)
{
/* Attribute list too long */
bgp_withdraw_bucket(s->channel, buck);
if (!s->sham)
bgp_withdraw_bucket(s->channel, buck);
return NULL;
}
@ -2606,53 +2408,11 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
}
static byte *
bgp_bmp_create_mp_unreach(struct bgp_write_state *s, const net *n,
const struct rte *new, const struct rte *old, const u32 path_id,
byte *buf, uint size)
bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, bool update)
{
/*
* 2 B Withdrawn Routes Length (zero)
* --- IPv4 Withdrawn Routes NLRI (unused)
* 2 B Total Path Attribute Length
* 1 B MP_UNREACH_NLRI hdr - Attribute Flags
* 1 B MP_UNREACH_NLRI hdr - Attribute Type Code
* 2 B MP_UNREACH_NLRI hdr - Length of Attribute Data
* 2 B MP_UNREACH_NLRI data - Address Family Identifier
* 1 B MP_UNREACH_NLRI data - Subsequent Address Family Identifier
* var MP_UNREACH_NLRI data - Network Layer Reachability Information
* --- IPv4 Network Layer Reachability Information (unused)
*/
uint len = 0;
bool is_withdrawn = !new && old;
if (is_withdrawn)
{
len = bgp_bmp_encode_nlri_ip6(s, n, path_id, buf + 11, size);
}
put_u16(buf+0, 0);
put_u16(buf+2, 7+len);
/* Begin of MP_UNREACH_NLRI atribute */
buf[4] = BAF_OPTIONAL | BAF_EXT_LEN;
buf[5] = BA_MP_UNREACH_NLRI;
put_u16(buf+6, 3+len);
put_af3(buf+8, s->channel->afi);
return buf+11+len;
}
void
bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
const net *n, const struct rte *new, const struct rte *old,
const struct rte_src *src)
{
struct bgp_proto *p = (struct bgp_proto *)P;
struct bgp_channel *c = (struct bgp_channel *)C;
byte buf[BGP_MAX_EXT_MSG_LENGTH] = { 0x00 };
byte *pkt = buf + BGP_HEADER_LENGTH;
byte *end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH);
struct bgp_proto *p = (void *) c->c.proto;
byte *end = buf + (BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH);
/* FIXME: must be a bit shorter */
struct bgp_caps *peer = p->conn->remote_caps;
const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi);
@ -2660,65 +2420,73 @@ bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
.proto = p,
.channel = c,
.pool = tmp_linpool,
.mp_reach = (bgp_channel_is_ipv6(c) || rem->ext_next_hop),
.as4_session = peer->as4_support,
.mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop,
.as4_session = 1,
.add_path = c->add_path_rx,
.mpls = c->desc->mpls,
.sham = 1,
};
const u32 path_id = c->add_path_rx ? src->private_id : 0;
byte *pos = pkt;
if (!s.mp_reach)
if (!update)
{
pos = bgp_bmp_create_ip_unreach(&s, n, new, old, path_id, pkt, end - pkt);
if (!pos)
{
log(L_ERR "Failed to create unreachable field in UPDATE message");
return;
}
pos = bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos);
if (!pos)
{
log(L_ERR "Failed to create reachable field in UPDATE message");
return;
}
bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
return !s.mp_reach ?
bgp_create_ip_unreach(&s, buck, buf, end):
bgp_create_mp_unreach(&s, buck, buf, end);
}
else if (new) // && s.mp_reach
else
{
pos = s.mp_reach
? bgp_bmp_create_mp_reach(&s, n, new, old, path_id, pos, end - pos)
: bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos);
if (!pos)
{
log(L_ERR "Failed to create reachable field in UPDATE message");
return;
}
bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
return !s.mp_reach ?
bgp_create_ip_reach(&s, buck, buf, end):
bgp_create_mp_reach(&s, buck, buf, end);
}
}
if (!new && old)
{
bmp_route_monitor_update_in_pre_commit(p);
bmp_route_monitor_update_in_pre_end();
bmp_route_monitor_update_in_pre_begin();
pkt = buf + BGP_HEADER_LENGTH;
end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH);
pos = bgp_bmp_create_mp_unreach(&s, n, new, old, path_id, pkt, end - pkt);
if (!pos)
{
log(L_ERR "Failed to create unreachable field in UPDATE message");
return;
}
static byte *
bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type)
{
memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE);
put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size);
put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type);
bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
}
return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE;
}
void
bgp_rte_update_in_notify(struct channel *C, const net_addr *n,
const struct rte *new, const struct rte_src *src)
{
// struct bgp_proto *p = (void *) C->proto;
struct bgp_channel *c = (void *) C;
byte buf[BGP_MAX_EXT_MSG_LENGTH];
byte *pkt = buf + BGP_HEADER_LENGTH;
ea_list *attrs = new ? new->attrs->eattrs : NULL;
uint ea_size = new ? (sizeof(ea_list) + attrs->count * sizeof(eattr)) : 0;
uint bucket_size = sizeof(struct bgp_bucket) + ea_size;
uint prefix_size = sizeof(struct bgp_prefix) + n->length;
/* Sham bucket */
struct bgp_bucket *b = alloca(bucket_size);
*b = (struct bgp_bucket) { };
init_list(&b->prefixes);
if (attrs)
memcpy(b->eattrs, attrs, ea_size);
/* Sham prefix */
struct bgp_prefix *px = alloca(prefix_size);
*px = (struct bgp_prefix) { };
px->path_id = src->private_id;
net_copy(px->net, n);
add_tail(&b->prefixes, &px->buck_node);
byte *end = bgp_create_update_bmp(c, pkt, b, !!new);
if (!end)
return;
bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE);
bmp_route_monitor_put_update_in_pre_msg(buf, end - buf);
}
static byte *

View File

@ -210,7 +210,7 @@ struct bmp_data_node {
};
static void
bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C);
bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C);
static void
bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size)
@ -881,8 +881,8 @@ bmp_route_monitor_update_in_pre_end()
}
}
void
bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C)
static void
bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C)
{
struct bmp_proto *p = g_bmp;
@ -915,7 +915,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C)
rte *e;
for (e = n->routes; e; e = e->next)
{
bgp_rte_update_in_notify(P, C, n, e, NULL, e->src);
bgp_rte_update_in_notify(C, n->n.addr, e, e->src);
}
bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P);