Skip to content

Commit

Permalink
Lib: Data type for VPN route distinguishers
Browse files Browse the repository at this point in the history
Use a distinct data structure for VPN route distinguishers instead
of just u64.
  • Loading branch information
Ondrej Zajicek committed Dec 16, 2024
1 parent e0ed978 commit 34b7d77
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 71 deletions.
28 changes: 16 additions & 12 deletions conf/cf-lex.l
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ WHITE [ \t]

{DIGIT}+:{DIGIT}+ {
uint len1 UNUSED, len2;
u64 l;
u64 l, v;
char *e;

errno = 0;
Expand All @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion conf/confbase.Y
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ CF_DECLS
uint i;
u32 i32;
u64 i64;
vpn_rd rd;
ip_addr a;
ip4_addr ip4;
ip6_addr ip6;
Expand Down Expand Up @@ -109,7 +110,7 @@ CF_DECLS
%token <i> NUM ENUM_TOKEN
%token <ip4> IP4
%token <ip6> IP6
%token <i64> VPN_RD
%token <rd> VPN_RD
%token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS
%token <t> TEXT
%token <bs> BYTETEXT
Expand Down
4 changes: 2 additions & 2 deletions filter/config.Y
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 ']' {
Expand Down
2 changes: 1 addition & 1 deletion filter/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions filter/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion filter/f-inst.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
110 changes: 80 additions & 30 deletions lib/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<MPLS_MAX_LABEL_STACK) && (i*4+3 < buflen); i++)
{
u32 s = get_u32(buf + i*4);
stack[i] = s >> 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<len; i++)
put_u32(buf + i*4, stack[i] << 12 | (i+1 == len ? 0x100 : 0));

return len*4;
}

/*
* Unaligned data access (in network order)
Expand Down Expand Up @@ -481,4 +451,84 @@ int ip6_pton(const char *a, ip6_addr *o);

char *ip_scope_text(uint);


/*
* MPLS labels
*/

#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<MPLS_MAX_LABEL_STACK) && (i*4+3 < buflen); i++)
{
u32 s = get_u32(buf + i*4);
stack[i] = s >> 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<len; i++)
put_u32(buf + i*4, stack[i] << 12 | (i+1 == len ? 0x100 : 0));

return len*4;
}


/*
* VPN route distinguishers
*/

/* Using 2x u32 to avoid u64 alignment */
typedef struct vpn_rd {
u32 hi;
u32 lo;
} vpn_rd;

#define RD_NONE (vpn_rd){}

static inline vpn_rd rd_from_u64(u64 val)
{ return (vpn_rd){.hi = val >> 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
4 changes: 3 additions & 1 deletion lib/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 13 additions & 13 deletions lib/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}


Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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); }
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))); }
Expand Down
Loading

0 comments on commit 34b7d77

Please sign in to comment.