bgpd: store and send bgp link-state attributes

Add the ability to store a raw copy of the incoming BGP Link-State
attributes and to redistribute them as is to other routes.

New types of data BGP_ATTR_LS and BGP_ATTR_LS_DATA are defined.

Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
This commit is contained in:
Louis Scalbert 2023-01-11 13:24:47 +01:00
parent 115f4f1ddd
commit 8b531b1107
6 changed files with 1350 additions and 5 deletions

View File

@ -43,6 +43,9 @@
#include "bgp_linkstate_tlv.h"
#include "bgp_mac.h"
DEFINE_MTYPE_STATIC(BGPD, BGP_ATTR_LS, "BGP Attribute Link-State");
DEFINE_MTYPE_STATIC(BGPD, BGP_ATTR_LS_DATA, "BGP Attribute Link-State Data");
/* Attribute strings for logging. */
static const struct message attr_str[] = {
{BGP_ATTR_ORIGIN, "ORIGIN"},
@ -66,6 +69,7 @@ static const struct message attr_str[] = {
#ifdef ENABLE_BGP_VNC_ATTR
{BGP_ATTR_VNC, "VNC"},
#endif
{BGP_ATTR_LINK_STATE, "LINK_STATE"},
{BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
{BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
@ -200,6 +204,8 @@ static struct hash *vnc_hash = NULL;
static struct hash *srv6_l3vpn_hash;
static struct hash *srv6_vpn_hash;
static struct hash *link_state_hash;
struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
{
struct bgp_attr_encap_subtlv *new;
@ -717,6 +723,99 @@ static void srv6_finish(void)
hash_clean_and_free(&srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
}
static void *link_state_hash_alloc(void *p)
{
return p;
}
static void link_state_free(struct bgp_attr_ls *link_state)
{
XFREE(MTYPE_BGP_ATTR_LS_DATA, link_state->data);
XFREE(MTYPE_BGP_ATTR_LS, link_state);
}
static struct bgp_attr_ls *link_state_intern(struct bgp_attr_ls *link_state)
{
struct bgp_attr_ls *find;
find = hash_get(link_state_hash, link_state, link_state_hash_alloc);
if (find != link_state)
link_state_free(link_state);
find->refcnt++;
return find;
}
static void link_state_unintern(struct bgp_attr_ls **link_statep)
{
struct bgp_attr_ls *link_state = *link_statep;
if (!*link_statep)
return;
if (link_state->refcnt)
link_state->refcnt--;
if (link_state->refcnt == 0) {
hash_release(link_state_hash, link_state);
link_state_free(link_state);
*link_statep = NULL;
}
}
static uint32_t link_state_hash_key_make(const void *p)
{
const struct bgp_attr_ls *link_state = p;
uint32_t key = 0;
key = jhash_1word(link_state->length, key);
key = jhash(link_state->data, link_state->length, key);
return key;
}
static bool link_state_hash_cmp(const void *p1, const void *p2)
{
const struct bgp_attr_ls *link_state1 = p1;
const struct bgp_attr_ls *link_state2 = p2;
if (!link_state1 && link_state2)
return false;
if (!link_state1 && link_state2)
return false;
if (!link_state1 && !link_state2)
return true;
if (link_state1->length != link_state2->length)
return false;
return !memcmp(link_state1->data, link_state2->data,
link_state1->length);
}
static bool link_state_same(const struct bgp_attr_ls *h1,
const struct bgp_attr_ls *h2)
{
if (h1 == h2)
return true;
else if (h1 == NULL || h2 == NULL)
return false;
else
return link_state_hash_cmp((const void *)h1, (const void *)h2);
}
static void link_state_init(void)
{
link_state_hash =
hash_create(link_state_hash_key_make, link_state_hash_cmp,
"BGP Link-State Attributes TLVs");
}
static void link_state_finish(void)
{
hash_clean_and_free(&link_state_hash,
(void (*)(void *))link_state_free);
}
static unsigned int transit_hash_key_make(const void *p)
{
const struct transit *transit = p;
@ -806,6 +905,8 @@ unsigned int attrhash_key_make(const void *p)
MIX(attr->bh_type);
MIX(attr->otc);
MIX(bgp_attr_get_aigp_metric(attr));
if (attr->link_state)
MIX(link_state_hash_key_make(attr->link_state));
return key;
}
@ -871,7 +972,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
attr1->srte_color == attr2->srte_color &&
attr1->nh_type == attr2->nh_type &&
attr1->bh_type == attr2->bh_type &&
attr1->otc == attr2->otc)
attr1->otc == attr2->otc &&
link_state_same(attr1->link_state, attr2->link_state))
return true;
}
@ -1031,6 +1133,12 @@ struct attr *bgp_attr_intern(struct attr *attr)
else
attr->srv6_vpn->refcnt++;
}
if (attr->link_state) {
if (!attr->link_state->refcnt)
attr->link_state = link_state_intern(attr->link_state);
else
attr->link_state->refcnt++;
}
#ifdef ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs =
bgp_attr_get_vnc_subtlvs(attr);
@ -1249,6 +1357,8 @@ void bgp_attr_unintern_sub(struct attr *attr)
srv6_l3vpn_unintern(&attr->srv6_l3vpn);
srv6_vpn_unintern(&attr->srv6_vpn);
link_state_unintern(&attr->link_state);
}
/* Free bgp attribute and aspath. */
@ -1412,6 +1522,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
case BGP_ATTR_ENCAP:
case BGP_ATTR_OTC:
return BGP_ATTR_PARSE_WITHDRAW;
case BGP_ATTR_LINK_STATE:
case BGP_ATTR_MP_REACH_NLRI:
case BGP_ATTR_MP_UNREACH_NLRI:
bgp_notify_send_with_data(peer->connection,
@ -1498,6 +1609,7 @@ const uint8_t attr_flags_values[] = {
[BGP_ATTR_IPV6_EXT_COMMUNITIES] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL,
[BGP_ATTR_LINK_STATE] = BGP_ATTR_FLAG_OPTIONAL,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@ -3291,6 +3403,32 @@ aigp_ignore:
return bgp_attr_ignore(peer, args->type);
}
/* Link-State (rfc7752) */
static enum bgp_attr_parse_ret
bgp_attr_linkstate(struct bgp_attr_parser_args *args)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
struct stream *s = peer->curr;
struct bgp_attr_ls *bgp_attr_ls;
void *bgp_attr_ls_data;
if (STREAM_READABLE(s) == 0)
return BGP_ATTR_PARSE_PROCEED;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LINK_STATE);
bgp_attr_ls = XCALLOC(MTYPE_BGP_ATTR_LS, sizeof(struct bgp_attr_ls));
bgp_attr_ls->length = length;
bgp_attr_ls_data = XCALLOC(MTYPE_BGP_ATTR_LS_DATA, length);
bgp_attr_ls->data = bgp_attr_ls_data;
stream_get(bgp_attr_ls_data, s, length);
attr->link_state = link_state_intern(bgp_attr_ls);
return BGP_ATTR_PARSE_PROCEED;
}
/* OTC attribute. */
static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
{
@ -3748,6 +3886,9 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
case BGP_ATTR_AIGP:
ret = bgp_attr_aigp(&attr_args);
break;
case BGP_ATTR_LINK_STATE:
ret = bgp_attr_linkstate(&attr_args);
break;
default:
ret = bgp_attr_unknown(&attr_args);
break;
@ -4840,6 +4981,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
#endif
}
/* BGP Link-State */
if (attr && attr->link_state) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_LINK_STATE);
stream_putc(s, attr->link_state->length);
stream_put(s, attr->link_state->data, attr->link_state->length);
}
/* PMSI Tunnel */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
@ -4944,6 +5093,7 @@ void bgp_attr_init(void)
transit_init();
encap_init();
srv6_init();
link_state_init();
}
void bgp_attr_finish(void)
@ -4957,6 +5107,7 @@ void bgp_attr_finish(void)
transit_finish();
encap_finish();
srv6_finish();
link_state_finish();
}
/* Make attribute packet. */

View File

@ -136,6 +136,13 @@ struct bgp_attr_srv6_l3vpn {
uint8_t transposition_offset;
};
struct bgp_attr_ls {
unsigned long refcnt;
uint8_t length;
void *data;
};
/* BGP core attribute structure. */
struct attr {
/* AS Path structure */
@ -159,6 +166,8 @@ struct attr {
/* Path origin attribute */
uint8_t origin;
struct bgp_attr_ls *link_state; /* BGP Link State attribute */
/* PMSI tunnel type (RFC 6514). */
enum pta_type pmsi_tnl_type;

File diff suppressed because it is too large Load Diff

View File

@ -219,5 +219,8 @@ extern char *bgp_linkstate_nlri_prefix_display(char *buf, size_t size,
extern void bgp_linkstate_nlri_prefix_json(json_object *json,
uint16_t nlri_type, uintptr_t prefix,
uint16_t len);
extern void bgp_linkstate_tlv_attribute_display(struct vty *vty,
struct bgp_attr_ls *attr_ls,
int indent, json_object *json);
#endif /* BGP_LINKSTATE_TLV_H */

View File

@ -10112,6 +10112,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_peer = NULL;
json_object *json_string = NULL;
json_object *json_adv_to = NULL;
json_object *json_bgp_ls_attr = NULL;
int first = 0;
struct listnode *node, *nnode;
struct peer *peer;
@ -11045,10 +11046,28 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
" Time until Long-lived stale route deleted: %lu\n",
llgr_remaining);
}
if (safi == SAFI_LINKSTATE && json_paths)
bgp_linkstate_nlri_prefix_json(
json_path, bn->rn->p.u.prefix_linkstate.nlri_type,
bn->rn->p.u.prefix_linkstate.ptr, bn->rn->p.prefixlen);
if (safi == SAFI_LINKSTATE) {
/* BGP Link-State NLRI */
if (json_paths)
bgp_linkstate_nlri_prefix_json(
json_path, bn->rn->p.u.prefix_linkstate.nlri_type,
bn->rn->p.u.prefix_linkstate.ptr, bn->rn->p.prefixlen);
/* BGP Link-State Attributes */
if (attr->link_state) {
if (json_paths) {
json_bgp_ls_attr = json_object_new_object();
json_object_object_add(json_path,
"linkStateAttributes",
json_bgp_ls_attr);
} else {
vty_out(vty, " BGP-LS attributes:\n");
}
bgp_linkstate_tlv_attribute_display(
vty, attr->link_state, 4, json_bgp_ls_attr);
}
}
/* Output some debug about internal state of the dest flags */
if (json_paths) {

View File

@ -1926,6 +1926,7 @@ struct bgp_nlri {
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
#define BGP_ATTR_AIGP 26
#define BGP_ATTR_LINK_STATE 29
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_OTC 35
#define BGP_ATTR_PREFIX_SID 40