return res;
}
- 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);
-
- return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE;
- }
-
byte *
-bgp_bmp_encode_rte(struct bgp_channel *c, byte *buf, byte *end, const net_addr *n,
- const struct rte *new, const struct rte_src *src)
-{
-// struct bgp_proto *p = (void *) c->c.proto;
- 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) { };
+bgp_bmp_encode_rte(ea_list *c, struct bgp_proto *bgp_p, byte *buf, byte *end, const struct rte *new)
+{
- byte *pkt = buf + BGP_HEADER_LENGTH;
-
+ uint ea_size = new->attrs ? (sizeof(ea_list) + new->attrs->count * sizeof(eattr)) : 0;
+ uint prefix_size = sizeof(struct bgp_prefix) + new->net->length;
+
+ struct lp_state *tmpp = lp_save(tmp_linpool);
+
+ /* Temporary bucket */
+ struct bgp_bucket *b = tmp_allocz(sizeof(struct bgp_bucket) + ea_size);
+ b->bmp = 1;
init_list(&b->prefixes);
- if (attrs)
- memcpy(b->eattrs, attrs, ea_size);
+ if (new->attrs)
+ memcpy(b->eattrs, new->attrs, ea_size);
- /* Sham prefix */
- struct bgp_prefix *px = alloca(prefix_size);
- *px = (struct bgp_prefix) { };
- px->path_id = (u32) src->private_id;
- net_copy(px->net, n);
+ /* Temporary prefix */
+ struct bgp_prefix *px = tmp_allocz(prefix_size);
+ px->src = tmp_allocz(sizeof(struct rte_src));
+ memcpy(px->src, new->src, sizeof(struct rte_src));
+ px->ni = NET_TO_INDEX(new->net);
add_tail(&b->prefixes, &px->buck_node);
- end = bgp_create_update_bmp(c, bgp_p, pkt, end, b, !!new->attrs);
-
- if (end)
- bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE);
- return bgp_create_update_bmp(c, buf, end, b, !!new);
++ end = bgp_create_update_bmp(c, bgp_p, buf, end, b, !!new->attrs);
+
+ lp_restore(tmp_linpool, tmpp);
+
+ return end;
}
#endif /* CONFIG_BMP */
};
buffer payload = bmp_default_buffer(p);
- bmp_peer_up_notif_msg_serialize(&payload, &peer, sk->saddr, sk->sport, sk->dport,
- tx_data, tx_data_size, rx_data, rx_data_size);
+ bmp_peer_up_notif_msg_serialize(&payload, &peer, sk->saddr, sk->sport, sk->dport, tx_data, rx_data);
- bmp_schedule_tx_packet(p, payload.start, payload.pos - payload.start);
- }
-
- static void
- bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, byte *data, size_t length, btime timestamp)
- {
- ea_list *bgp = bs->bgp;
-
- struct bmp_peer_hdr_info peer = {
- .address = ea_get_ip(bgp, &ea_bgp_rem_ip, IPA_NONE),
- .as = ea_get_int(bgp, &ea_bgp_rem_as, 0),
- .id = ea_get_int(bgp, &ea_bgp_rem_id, 0),
- .global = bmp_is_peer_global_instance(bgp),
- .policy = bmp_stream_policy(bs),
- .timestamp = timestamp,
- };
-
- const byte *start = bmp_route_monitor_msg_serialize(p, &peer, data, length);
- bmp_schedule_tx_packet(p, start, (data - start) + length);
+ bmp_schedule_tx_packet(p, &payload);
}
static void
-bmp_route_monitor_notify(struct bmp_proto *p, struct bmp_stream *bs,
- const net_addr *n, const struct rte *new, const struct rte_src *src)
+bmp_route_monitor_notify(struct bmp_proto *p, struct bgp_proto *bgp_p, u32 afi, bool policy, const rte *new, ea_list *old)
{
- struct bgp_proto *bgp = bs->bgp;
- struct bgp_channel *c = bs->sender;
+ /* Idempotent update */
+ if ((old == new->attrs) || old && new->attrs && ea_same(old, new->attrs))
+ return;
+
+ /* No stream, probably flushed already */
+ struct bmp_stream *bs = bmp_find_stream(p, bgp_p, afi, policy);
+ if (!bs)
+ return;
+
- byte *bufend = &p->msgbuf[sizeof p->msgbuf];
- byte *begin = bufend - BGP_MAX_EXT_MSG_LENGTH;
- byte *end = bgp_bmp_encode_rte(bs->sender, bgp_p, begin, bufend, new);
++ ea_list *bgp = bs->bgp;
++ ea_list *c = bs->sender;
- btime delta_t = new->attrs ? current_time() - new->lastmod : 0;
- btime timestamp = current_real_time() - delta_t;
+ btime delta_t = new ? current_time() - new->lastmod : 0;
- if (end)
- bmp_route_monitor_put_update(p, bs, begin, end - begin, timestamp);
- else
+ struct bmp_peer_hdr_info peer = {
- .address = bgp->remote_ip,
- .as = bgp->remote_as,
- .id = bgp->remote_id,
++ .address = ea_get_ip(bgp, &ea_bgp_rem_ip, IPA_NONE),
++ .as = ea_get_int(bgp, &ea_bgp_rem_as, 0),
++ .id = ea_get_int(bgp, &ea_bgp_rem_id, 0),
+ .global = bmp_is_peer_global_instance(bgp),
+ .policy = bmp_stream_policy(bs),
+ .timestamp = current_real_time() - delta_t,
+ };
+
+ buffer msg = bmp_default_buffer(p);
+ bmp_put_common_hdr(&msg, BMP_ROUTE_MONITOR, 0);
+ bmp_put_per_peer_hdr(&msg, &peer);
+
+ bmp_buffer_need(&msg, BGP_MAX_EXT_MSG_LENGTH);
- byte *pos = bgp_bmp_encode_rte(c, msg.pos + BGP_HEADER_LENGTH, msg.end, n, new, src);
++ byte *pos = bgp_bmp_encode_rte(c, bgp_p, msg.pos + BGP_HEADER_LENGTH, msg.end, new);
+ if (!pos)
+ {
- log(L_WARN "%s: Cannot encode update for %N", p->p.name, n);
+ log(L_WARN "%s: Cannot encode update for %N", p->p.name, new->net);
+ return;
+ }
+ bmp_put_bgp_hdr(&msg, PKT_UPDATE, pos - msg.pos);
+ msg.pos = pos;
+
+ bmp_fix_common_hdr(&msg);
+ bmp_schedule_tx_packet(p, &msg);
}
static void
bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs)
{
- TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", ea_get_adata(bs->bgp, &ea_name)->data, ea_get_adata(bs->sender, &ea_name)->data);
- struct bgp_proto *bgp = bs->bgp;
- struct bgp_channel *c = bs->sender;
++ ea_list *bgp = bs->bgp;
++ ea_list *c = bs->sender;
+
+ struct bmp_peer_hdr_info peer = {
- .address = bgp->remote_ip,
- .as = bgp->remote_as,
- .id = bgp->remote_id,
++ .address = ea_get_ip(bgp, &ea_bgp_rem_ip, IPA_NONE),
++ .as = ea_get_int(bgp, &ea_bgp_rem_as, 0),
++ .id = ea_get_int(bgp, &ea_bgp_rem_id, 0),
+ .global = bmp_is_peer_global_instance(bgp),
+ .policy = bmp_stream_policy(bs),
+ .timestamp = current_real_time(),
+ };
+
- TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", bgp->p.name, c->c.name);
++ TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", ea_get_adata(bgp, &ea_name)->data, ea_get_adata(c, &ea_name)->data);
+
+ buffer msg = bmp_default_buffer(p);
+ bmp_put_common_hdr(&msg, BMP_ROUTE_MONITOR, 0);
+ bmp_put_per_peer_hdr(&msg, &peer);
- byte *rx_end_payload = p->msgbuf + BMP_PER_PEER_HDR_SIZE + BMP_COMMON_HDR_SIZE;
- byte *pos = bgp_create_end_mark_ea_(bs->sender, rx_end_payload + BGP_HEADER_LENGTH);
- memset(rx_end_payload + BGP_MSG_HDR_MARKER_POS, 0xff,
- BGP_MSG_HDR_MARKER_SIZE); // BGP UPDATE MSG marker
- put_u16(rx_end_payload + BGP_MSG_HDR_LENGTH_POS, pos - rx_end_payload);
- put_u8(rx_end_payload + BGP_MSG_HDR_TYPE_POS, PKT_UPDATE);
+ bmp_buffer_need(&msg, BGP_MAX_EXT_MSG_LENGTH);
- byte *pos = bgp_create_end_mark_(c, msg.pos + BGP_HEADER_LENGTH);
++ byte *pos = bgp_create_end_mark_ea_(c, msg.pos + BGP_HEADER_LENGTH);
+ bmp_put_bgp_hdr(&msg, PKT_UPDATE, pos - msg.pos);
+ msg.pos = pos;
- bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload, current_real_time());
+ bmp_fix_common_hdr(&msg);
+ bmp_schedule_tx_packet(p, &msg);
}
static void
/* Send initiation message */
buffer payload = bmp_default_buffer(p);
bmp_init_msg_serialize(&payload, p->sys_descr, p->sys_name);
- bmp_schedule_tx_packet(p, payload.start, payload.pos - payload.start);
+ bmp_schedule_tx_packet(p, &payload);
/* Send Peer Up messages */
- struct proto *peer;
- WALK_LIST(peer, proto_list)
- if ((peer->proto->class == PROTOCOL_BGP) && (peer->proto_state == PS_UP))
- bmp_peer_init(p, (struct bgp_proto *) peer);
+ u32 length;
+ PST_LOCKED(ts) /* The size of protos field will never decrease, the inconsistency caused by growing is not important */
+ length = ts->length_states;
+
+ /* Subscribe to protocol state changes */
+ p->proto_state_reader = (struct lfjour_recipient) {
+ .event = &p->proto_state_changed,
+ .target = proto_event_list(&p->p),
+ };
+
+ p->proto_state_changed = (event) {
+ .hook = bmp_proto_state_changed,
+ .data = p,
+ };
+
+ proto_states_subscribe(&p->proto_state_reader);
+
+ /* Load protocol states */
+ for (u32 i = 0; i < length; i++)
+ {
+ ea_list *proto_attr = proto_get_state(i);
+ if (proto_attr == NULL)
+ continue;
+
+ struct protocol *proto = (struct protocol *) ea_get_ptr(proto_attr, &ea_protocol_type, 0);
+ const int state = ea_get_int(proto_attr, &ea_state, 0);
+
+ if (proto != &proto_bgp || state != PS_UP)
+ continue;
+
+ bmp_peer_up_inout(p, proto_attr, false);
+ }
}
/**