summaryrefslogtreecommitdiff
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
authorLouis Scalbert <louis.scalbert@6wind.com>2023-01-11 13:24:47 +0100
committerLouis Scalbert <louis.scalbert@6wind.com>2023-09-18 15:07:32 +0200
commit8b531b110756bf8627b5716f433190a0748b5e76 (patch)
tree8e6aedafd631a05073461a8a0ea6afd4406e51be /bgpd/bgp_attr.c
parent115f4f1dddb47a05c3e9454cc0fc88f34ebeb281 (diff)
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>
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c153
1 files changed, 152 insertions, 1 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 4115224641..cc7afbe74f 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -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. */