Skip to content

Commit

Permalink
bgpd: store and send bgp link-state attributes
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Olivier Dugeon <[email protected]>
  • Loading branch information
louis-6wind committed Sep 18, 2023
1 parent 115f4f1 commit 8b531b1
Show file tree
Hide file tree
Showing 6 changed files with 1,350 additions and 5 deletions.
153 changes: 152 additions & 1 deletion bgpd/bgp_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand All @@ -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"},
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -3291,6 +3403,32 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -4944,6 +5093,7 @@ void bgp_attr_init(void)
transit_init();
encap_init();
srv6_init();
link_state_init();
}

void bgp_attr_finish(void)
Expand All @@ -4957,6 +5107,7 @@ void bgp_attr_finish(void)
transit_finish();
encap_finish();
srv6_finish();
link_state_finish();
}

/* Make attribute packet. */
Expand Down
9 changes: 9 additions & 0 deletions bgpd/bgp_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;

Expand Down
Loading

0 comments on commit 8b531b1

Please sign in to comment.