From 34b7d77e06f7fa2756a68fa4b1ebdce509dfe277 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 16 Dec 2024 18:27:42 +0100 Subject: [PATCH] Lib: Data type for VPN route distinguishers Use a distinct data structure for VPN route distinguishers instead of just u64. --- conf/cf-lex.l | 28 ++++++----- conf/confbase.Y | 3 +- filter/config.Y | 4 +- filter/data.c | 2 +- filter/data.h | 1 + filter/f-inst.c | 2 +- lib/ip.h | 110 ++++++++++++++++++++++++++++++++------------ lib/net.c | 4 +- lib/net.h | 26 +++++------ proto/bgp/packets.c | 8 ++-- proto/l3vpn/l3vpn.c | 8 ++-- proto/l3vpn/l3vpn.h | 4 +- 12 files changed, 129 insertions(+), 71 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 637a5d38..0119e1f5 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -151,7 +151,7 @@ WHITE [ \t] {DIGIT}+:{DIGIT}+ { uint len1 UNUSED, len2; - u64 l; + u64 l, v; char *e; errno = 0; @@ -163,76 +163,80 @@ WHITE [ \t] { len1 = 32; len2 = 16; - cf_lval.i64 = (2ULL << 48) | (((u64) l) << len2); + v = (2ULL << 48) | (((u64) l) << len2); } else { len1 = 16; len2 = 32; - cf_lval.i64 = 0 | (((u64) l) << len2); + v = 0 | (((u64) l) << len2); } errno = 0; l = bstrtoul10(e+1, &e); if (!e || *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); - cf_lval.i64 |= l; + v |= l; + cf_lval.rd = rd_from_u64(v); return VPN_RD; } [02]:{DIGIT}+:{DIGIT}+ { uint len1, len2; - u64 l; + u64 l, v; char *e; if (yytext[0] == '0') { - cf_lval.i64 = 0; len1 = 16; len2 = 32; + v = 0; } else { - cf_lval.i64 = 2ULL << 48; len1 = 32; len2 = 16; + v = 2ULL << 48; } errno = 0; l = bstrtoul10(yytext+2, &e); if (!e || (*e != ':') || (errno == ERANGE) || (l >> len1)) cf_error("ASN out of range"); - cf_lval.i64 |= ((u64) l) << len2; + v |= ((u64) l) << len2; errno = 0; l = bstrtoul10(e+1, &e); if (!e || *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); - cf_lval.i64 |= l; + v |= l; + cf_lval.rd = rd_from_u64(v); return VPN_RD; } {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ { unsigned long int l; ip4_addr ip4; + u64 v; char *e; - cf_lval.i64 = 1ULL << 48; + v = 1ULL << 48; e = strchr(yytext, ':'); *e++ = '\0'; if (!ip4_pton(yytext, &ip4)) cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext); - cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16; + v |= ((u64) ip4_to_u32(ip4)) << 16; errno = 0; l = bstrtoul10(e, &e); if (!e || *e || (errno == ERANGE) || (l >> 16)) cf_error("Number out of range"); - cf_lval.i64 |= l; + v |= l; + cf_lval.rd = rd_from_u64(v); return VPN_RD; } diff --git a/conf/confbase.Y b/conf/confbase.Y index 5b00937f..af64e3ff 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -57,6 +57,7 @@ CF_DECLS uint i; u32 i32; u64 i64; + vpn_rd rd; ip_addr a; ip4_addr ip4; ip6_addr ip6; @@ -109,7 +110,7 @@ CF_DECLS %token NUM ENUM_TOKEN %token IP4 %token IP6 -%token VPN_RD +%token VPN_RD %token CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS %token TEXT %token BYTETEXT diff --git a/filter/config.Y b/filter/config.Y index 72996850..4340d5e0 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -641,7 +641,7 @@ fipa: set_atom0: NUM { $$.type = T_INT; $$.val.i = $1; } | fipa { $$ = $1; } - | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } + | VPN_RD { $$.type = T_RD; $$.val.rd = $1; } | ENUM_TOKEN { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { $$ = cf_eval($2, T_VOID); @@ -801,7 +801,7 @@ constant: | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); } | BYTETEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BYTESTRING, .val.bs = $1, }); } | fipa { $$ = f_new_inst(FI_CONSTANT, $1); } - | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); } + | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.rd = $1, }); } | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); } | '[' ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = NULL, }); } | '[' set_items ']' { diff --git a/filter/data.c b/filter/data.c index 98e9a25a..f5a9e5ee 100644 --- a/filter/data.c +++ b/filter/data.c @@ -633,7 +633,7 @@ val_format(const struct f_val *v, buffer *buf) case T_QUAD: buffer_print(buf, "%R", v->val.i); return; case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return; case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return; - case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return; + case T_RD: rd_format(v->val.rd, buf2, 1024); buffer_print(buf, "%s", buf2); return; case T_PREFIX_SET: trie_format(v->val.ti, buf); return; case T_SET: tree_format(v->val.t, buf); return; case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return; diff --git a/filter/data.h b/filter/data.h index 811c4a80..f36820cb 100644 --- a/filter/data.h +++ b/filter/data.h @@ -85,6 +85,7 @@ struct f_val { uint i; u64 ec; lcomm lc; + vpn_rd rd; ip_addr ip; const net_addr *net; const char *s; diff --git a/filter/f-inst.c b/filter/f-inst.c index efc82d2f..f94580a6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -1102,7 +1102,7 @@ METHOD_CONSTRUCTOR("rd"); if (!net_is_vpn(v1.val.net)) runtime( "VPN address expected" ); - RESULT(T_RD, ec, net_rd(v1.val.net)); + RESULT(T_RD, rd, net_rd(v1.val.net)); } /* Get first ASN from AS PATH */ diff --git a/lib/ip.h b/lib/ip.h index 661331ec..bae05261 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -392,36 +392,6 @@ static inline ip6_addr ip6_hton(ip6_addr a) static inline ip6_addr ip6_ntoh(ip6_addr a) { return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } -#define MPLS_MAX_LABEL 0x100000 - -#define MPLS_MAX_LABEL_STACK 8 -#define MPLS_MAX_LABEL_STRING MPLS_MAX_LABEL_STACK*12 + 5 -typedef struct mpls_label_stack { - uint len; - u32 stack[MPLS_MAX_LABEL_STACK]; -} mpls_label_stack; - -static inline int ACCESS_READ(1, 2) -mpls_get(const char *buf, int buflen, u32 *stack) -{ - for (int i=0; (i> 12; - if (s & 0x100) - return i+1; - } - return -1; -} - -static inline int -mpls_put(char *buf, int len, u32 *stack) -{ - for (int i=0; i> 12; + if (s & 0x100) + return i+1; + } + return -1; +} + +static inline int +mpls_put(char *buf, int len, u32 *stack) +{ + for (int i=0; i> 32, .lo = val }; } + +static inline u64 rd_to_u64(vpn_rd rd) +{ return (((u64) rd.hi) << 32) | rd.lo; } + +static inline int rd_equal(vpn_rd a, vpn_rd b) +{ return a.hi == b.hi && a.lo == b.lo; } + +static inline int rd_zero(vpn_rd a) +{ return !a.hi && !a.lo; } + +static inline int rd_nonzero(vpn_rd a) +{ return a.hi || a.lo; } + +static inline int rd_compare(vpn_rd a, vpn_rd b) +{ return uint_cmp(a.hi, b.hi) ?: uint_cmp(a.lo, b.lo); } + +static inline u64 rd_hash0(vpn_rd rd, u32 p, u64 acc) +{ return u32_hash0(rd.hi, p, u32_hash0(rd.lo, p, acc)); } + +static inline vpn_rd get_rd(const void *buf) +{ return (vpn_rd) { .hi = get_u32(buf), .lo = get_u32(buf + 4) }; } + +static inline void * put_rd(void *buf, vpn_rd rd) +{ + put_u32(buf, rd.hi); + put_u32(buf+4, rd.lo); + return buf+8; +} + #endif diff --git a/lib/net.c b/lib/net.c index 3bd7bc67..e83cdce7 100644 --- a/lib/net.c +++ b/lib/net.c @@ -77,8 +77,10 @@ STATIC_ASSERT(sizeof(net_addr_aspa) == 8); int -rd_format(const u64 rd, char *buf, int buflen) +rd_format(const vpn_rd rd_, char *buf, int buflen) { + u64 rd = rd_to_u64(rd_); + switch (rd >> 48) { case 0: return bsnprintf(buf, buflen, "%u:%u", (u32) (rd >> 32), (u32) rd); diff --git a/lib/net.h b/lib/net.h index 61ed37ba..fe5c0d8c 100644 --- a/lib/net.h +++ b/lib/net.h @@ -73,7 +73,7 @@ typedef struct net_addr_vpn4 { u8 pxlen; u16 length; ip4_addr prefix; - u64 rd; + vpn_rd rd; } net_addr_vpn4; typedef struct net_addr_vpn6 { @@ -82,7 +82,7 @@ typedef struct net_addr_vpn6 { u16 length; ip6_addr prefix; u32 padding; - u64 rd; + vpn_rd rd; } net_addr_vpn6; typedef struct net_addr_roa4 { @@ -206,10 +206,10 @@ static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen) static inline void net_fill_ip6(net_addr *a, ip6_addr prefix, uint pxlen) { *(net_addr_ip6 *)a = NET_ADDR_IP6(prefix, pxlen); } -static inline void net_fill_vpn4(net_addr *a, ip4_addr prefix, uint pxlen, u64 rd) +static inline void net_fill_vpn4(net_addr *a, ip4_addr prefix, uint pxlen, vpn_rd rd) { *(net_addr_vpn4 *)a = NET_ADDR_VPN4(prefix, pxlen, rd); } -static inline void net_fill_vpn6(net_addr *a, ip6_addr prefix, uint pxlen, u64 rd) +static inline void net_fill_vpn6(net_addr *a, ip6_addr prefix, uint pxlen, vpn_rd rd) { *(net_addr_vpn6 *)a = NET_ADDR_VPN6(prefix, pxlen, rd); } static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint max_pxlen, u32 asn) @@ -340,7 +340,7 @@ static inline uint net_pxlen(const net_addr *a) ip_addr net_pxmask(const net_addr *a); -static inline u64 net_rd(const net_addr *a) +static inline vpn_rd net_rd(const net_addr *a) { switch (a->type) { @@ -349,7 +349,7 @@ static inline u64 net_rd(const net_addr *a) case NET_VPN6: return ((net_addr_vpn6 *)a)->rd; } - return 0; + return RD_NONE; } @@ -410,10 +410,10 @@ static inline int net_zero_ip6(const net_addr_ip6 *a) { return !a->pxlen && ip6_zero(a->prefix); } static inline int net_zero_vpn4(const net_addr_vpn4 *a) -{ return !a->pxlen && ip4_zero(a->prefix) && !a->rd; } +{ return !a->pxlen && ip4_zero(a->prefix) && rd_zero(a->rd); } static inline int net_zero_vpn6(const net_addr_vpn6 *a) -{ return !a->pxlen && ip6_zero(a->prefix) && !a->rd; } +{ return !a->pxlen && ip6_zero(a->prefix) && rd_zero(a->rd); } static inline int net_zero_roa4(const net_addr_roa4 *a) { return !a->pxlen && ip4_zero(a->prefix) && !a->max_pxlen && !a->asn; } @@ -441,10 +441,10 @@ static inline int net_compare_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b) { return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } static inline int net_compare_vpn4(const net_addr_vpn4 *a, const net_addr_vpn4 *b) -{ return u64_cmp(a->rd, b->rd) ?: ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } +{ return rd_compare(a->rd, b->rd) ?: ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } static inline int net_compare_vpn6(const net_addr_vpn6 *a, const net_addr_vpn6 *b) -{ return u64_cmp(a->rd, b->rd) ?: ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } +{ return rd_compare(a->rd, b->rd) ?: ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b) { return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); } @@ -526,13 +526,13 @@ static inline u32 net_hash_ip6(const net_addr_ip6 *n) static inline u32 net_hash_vpn4(const net_addr_vpn4 *n) { u64 acc = ip4_hash0(n->prefix, HASH_PARAM, 0) ^ (n->pxlen << 26); - return hash_value(u64_hash0(n->rd, HASH_PARAM, acc)); + return hash_value(rd_hash0(n->rd, HASH_PARAM, acc)); } static inline u32 net_hash_vpn6(const net_addr_vpn6 *n) { u64 acc = ip6_hash0(n->prefix, HASH_PARAM, 0) ^ (n->pxlen << 26); - return hash_value(u64_hash0(n->rd, HASH_PARAM, acc)); + return hash_value(rd_hash0(n->rd, HASH_PARAM, acc)); } static inline u32 net_hash_roa4(const net_addr_roa4 *n) @@ -637,7 +637,7 @@ void net_normalize(net_addr *N); int net_classify(const net_addr *N); int net_format(const net_addr *N, char *buf, int buflen) ACCESS_WRITE(2, 3); -int rd_format(const u64 rd, char *buf, int buflen) ACCESS_WRITE(2, 3); +int rd_format(const vpn_rd rd, char *buf, int buflen) ACCESS_WRITE(2, 3); static inline int ipa_in_px4(ip4_addr a, ip4_addr prefix, uint pxlen) { return ip4_zero(ip4_and(ip4_xor(a, prefix), ip4_mkmask(pxlen))); } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 02bce7e7..8b78cc13 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1807,7 +1807,7 @@ bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); /* Encode route distinguisher */ - put_u64(pos, net->rd); + put_rd(pos, net->rd); ADVANCE(pos, size, 8); /* Encode prefix body */ @@ -1858,7 +1858,7 @@ bgp_decode_nlri_vpn4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) if (l < 64) bgp_parse_error(s, 1); - u64 rd = get_u64(pos); + vpn_rd rd = get_rd(pos); ADVANCE(pos, len, 8); l -= 64; @@ -1907,7 +1907,7 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1); /* Encode route distinguisher */ - put_u64(pos, net->rd); + put_rd(pos, net->rd); ADVANCE(pos, size, 8); /* Encode prefix body */ @@ -1958,7 +1958,7 @@ bgp_decode_nlri_vpn6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) if (l < 64) bgp_parse_error(s, 1); - u64 rd = get_u64(pos); + vpn_rd rd = get_rd(pos); ADVANCE(pos, len, 8); l -= 64; diff --git a/proto/l3vpn/l3vpn.c b/proto/l3vpn/l3vpn.c index 8b56cd73..ec9eeb75 100644 --- a/proto/l3vpn/l3vpn.c +++ b/proto/l3vpn/l3vpn.c @@ -177,14 +177,14 @@ l3vpn_rt_notify(struct proto *P, struct channel *c0, net *net, rte *new, rte *ol case NET_VPN4: net_fill_ip4(n, net4_prefix(n0), net4_pxlen(n0)); - src = rt_get_source(&p->p, ((const net_addr_vpn4 *) n0)->rd); + src = rt_get_source(&p->p, rd_to_u64(((const net_addr_vpn4 *) n0)->rd)); dst = p->ip4_channel; export = 0; break; case NET_VPN6: net_fill_ip6(n, net6_prefix(n0), net6_pxlen(n0)); - src = rt_get_source(&p->p, ((const net_addr_vpn6 *) n0)->rd); + src = rt_get_source(&p->p, rd_to_u64(((const net_addr_vpn6 *) n0)->rd)); dst = p->ip6_channel; export = 0; break; @@ -331,7 +331,7 @@ l3vpn_postconfig(struct proto_config *CF) if (!proto_cf_find_channel(CF, NET_MPLS)) cf_error("MPLS channel not specified"); - if (!cf->rd) + if (rd_zero(cf->rd)) cf_error("Route distinguisher not specified"); if (!cf->import_target && !cf->export_target) @@ -410,7 +410,7 @@ l3vpn_reconfigure(struct proto *P, struct proto_config *CF) !proto_configure_channel(P, &P->mpls_channel, proto_cf_find_channel(CF, NET_MPLS))) return 0; - if (p->rd != cf->rd) + if (!rd_equal(p->rd, cf->rd)) return 0; int import_changed = !same_tree(p->import_target, cf->import_target); diff --git a/proto/l3vpn/l3vpn.h b/proto/l3vpn/l3vpn.h index 52a9f36d..1cce28fa 100644 --- a/proto/l3vpn/l3vpn.h +++ b/proto/l3vpn/l3vpn.h @@ -13,7 +13,7 @@ struct l3vpn_config { struct proto_config c; - u64 rd; + vpn_rd rd; struct f_tree *import_target; struct f_tree *export_target; }; @@ -25,7 +25,7 @@ struct l3vpn_proto { struct channel *vpn4_channel; struct channel *vpn6_channel; - u64 rd; + vpn_rd rd; struct f_tree *import_target; struct f_tree *export_target; u32 *export_target_data;