diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2019-03-08 00:03:04 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2019-03-08 00:15:45 +0100 |
commit | 0171af179b9e9538fb91e9f30f51f774779d9402 (patch) | |
tree | cd07017eba0796c8028cf9d7f149d7c4f01bb544 | |
parent | 8bb0b0d7575a7f7701c44d8907381f546c001331 (diff) |
BGP: Tunnel Encapsulation attributeold/wg-tlv
Refer to draft-ietf-idr-tunnel-encaps-11
-rw-r--r-- | filter/config.Y | 126 | ||||
-rw-r--r-- | filter/filter.c | 160 | ||||
-rw-r--r-- | nest/attrs.h | 11 | ||||
-rw-r--r-- | nest/route.h | 2 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 9 | ||||
-rw-r--r-- | proto/bgp/config.Y | 4 |
6 files changed, 234 insertions, 78 deletions
diff --git a/filter/config.Y b/filter/config.Y index 84644370..8b5f01e9 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -109,12 +109,59 @@ f_new_pair_set(int fa, int ta, int fb, int tb) static struct f_tree * f_new_tlv_item(u32 type, u32 v1) { - debug("f_new_tlv_item\n"); struct f_tree *t = f_new_tree(); t->right = t; t->from.type = t->to.type = T_TLV; - // t->from.val.tlv = v1; - // t->to.val.tlv = v1; + struct tlv v; + v.type = type; + switch (type) { + case TLV_UDP_DEST_PORT: + v.u.udp_dest_port = v1; + break; + default: + // FIXME error + break; + } + t->from.val.tlv = v; + t->to.val.tlv = v; + return t; +} + +static struct f_tree * +f_new_tlv_remote_ep(u32 asn, struct f_val ep) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_TLV; + struct tlv v; + v.type = TLV_REMOTE_ENDPOINT; + v.u.remote_endpoint.asn = asn; + v.u.remote_endpoint.ip = ep.val.ip; + t->from.val.tlv = v; + t->to.val.tlv = v; + return t; +} + +int wg_key_from_base64(void *key, const char *base64); + +static struct f_tree * +f_new_tlv_encap(u32 type, const char *v1) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_TLV; + struct tlv v; + v.type = TLV_ENCAPSULATION; + v.u.tunnel_encap.type = type; + // FIXME base64 decode v1 + int len = 32; + v.u.tunnel_encap.data = cfg_alloc(len); + v.u.tunnel_encap.length = len; + // FIXME + wg_key_from_base64(v.u.tunnel_encap.data, v1); +// memcpy(v.u.tunnel_encap.data, v1, len); + t->from.val.tlv = v; + t->to.val.tlv = v; return t; } @@ -327,62 +374,6 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) } static inline struct f_inst * -f_generate_tlv(u16 kind, struct f_inst *tv) -{ - struct f_inst *rv = NULL; - struct tlv tlv; - struct f_val *val; - u32 type; - - debug("f_generate_tlv\n"); - - if (tv->fi_code != FI_CONSTANT_INDIRECT) - cf_error("Can't operate with value of non-constant type in TLV: %d", tv->fi_code); - - val = tv->a1.p; - type = val->type; - - switch (kind) { - case TLV_WIREGUARD: { - if (type == T_STRING) { - tlv.u.peer = val->val.s; - } - else - cf_error("Can't operate with value of non-string type in TLV wireguard constructor"); - break; - } - case TLV_REMOTE_ENDPOINT: { - if (type == T_IP) { - tlv.u.remote_endpoint.ip = val->val.ip; - } - else - cf_error("Can't operate with value of non-IP type in TLV remote endpoint constructor"); - break; - } - case TLV_UDP_DEST_PORT: { - if (type == T_INT) { - tlv.u.udp_dest_port = val->val.i; - } - else - cf_error("Can't operate with value of non-integer type in TLV udp dest port constructor"); - break; - } - default: - cf_error("Invalid TLV kind in constructor"); - }; - - { - NEW_F_VAL; - rv = f_new_inst(FI_CONSTANT_INDIRECT); - rv->a1.p = val; - val->type = T_TLV; - val->val.tlv = tlv; - - return rv; - } -} - -static inline struct f_inst * f_generate_path_mask(struct f_path_mask *t) { for (struct f_path_mask *tt = t; tt; tt = tt->next) { @@ -486,6 +477,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, + TLV, TUNNEL_ENCAP, REMOTE_ENDPOINT, UDP_DEST_PORT, BT_ASSERT, BT_TEST_SUITE, FORMAT) %nonassoc THEN @@ -495,7 +487,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type <fda> dynamic_attr %type <fsa> static_attr %type <f> filter filter_body where_filter -%type <i> type break_command ec_kind tlv_kind +%type <i> type break_command ec_kind %type <i32> cnum %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body tlv_item %type <trie> fprefix_set @@ -559,6 +551,7 @@ type: | CLIST { $$ = T_CLIST; } | ECLIST { $$ = T_ECLIST; } | LCLIST { $$ = T_LCLIST; } + | TLV { $$ = T_TLV; } | type SET { switch ($1) { case T_INT: @@ -568,6 +561,7 @@ type: case T_LC: case T_RD: case T_IP: + case T_TLV: $$ = T_SET; break; @@ -780,18 +774,16 @@ lc_item: { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } ; -tlv_kind: - WIREGUARD { $$ = TLV_WIREGUARD; } - tlv_item: - '(' tlv_kind ',' term ')' { $$ = f_new_tlv_item($2, $4); } - -// | tlv_item + '(' TUNNEL_ENCAP ',' cnum ',' TEXT ')' { $$ = f_new_tlv_encap($4, $6); } + | '(' UDP_DEST_PORT ',' cnum ')' { $$ = f_new_tlv_item(TLV_UDP_DEST_PORT, $4); } + | '(' REMOTE_ENDPOINT ',' NUM ',' fipa ')' { $$ = f_new_tlv_remote_ep($4, $6); } set_item: pair_item | ec_item | lc_item + | tlv_item | set_atom { $$ = f_new_item($1, $1); } | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } ; @@ -800,6 +792,7 @@ switch_item: pair_item | ec_item | lc_item + | tlv_item | switch_atom { $$ = f_new_item($1, $1); } | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } ; @@ -884,7 +877,6 @@ constructor: '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } - | '(' tlv_kind ',' term ')' { $$ = f_generate_tlv($2, $4); } | bgp_path { $$ = f_generate_path_mask($1); } ; diff --git a/filter/filter.c b/filter/filter.c index 299e616e..c2e7a44f 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -622,6 +622,147 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define BITFIELD_MASK(what) \ (1u << (what->a2.i >> 24)) + +static int +calc_tunnel_encap(struct f_tree *t, int *type) +{ + if (t == NULL) + return 0; + + if (t->from.type != T_TLV) { + debug("Not tlv %d\n", t->from.type); + return -1; + } + + struct tlv *tlv = &t->from.val.tlv; + int len = 0; + switch (tlv->type) { + case TLV_ENCAPSULATION: + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + len = 4 + 2 + tlv->u.tunnel_encap.length; + *type = tlv->u.tunnel_encap.type; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + len = 4; + break; + case TLV_REMOTE_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + if (ipa_is_ip4(tlv->u.remote_endpoint.ip)) + len = 2 + 10; + else + len = 2 + 22; + break; + default: + /* Ignore unknown */ + len = 0; + break; + } + + return len + calc_tunnel_encap(t->left, type) + calc_tunnel_encap(t->right, type); +} + +static void * +build_tunnel_encap_rec(void *p, struct f_tree *t) +{ + if (t == NULL) + return p; + + if (t->from.type != T_TLV) { + debug("Not tlv %d\n", t->from.type); + return p; + } + + struct tlv *tlv = &t->from.val.tlv; + switch (tlv->type) { + case TLV_ENCAPSULATION: + /* + TLV: + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (Variable) + */ + put_u8(p, tlv->type); p++; + int len = tlv->u.tunnel_encap.length; + put_u8(p, len); p++; + memcpy(p, tlv->u.tunnel_encap.data, len); p+=len; + break; + case TLV_UDP_DEST_PORT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (2 Octets) + */ + put_u8(p, tlv->type); p++; + put_u8(p, 2); p++; + put_u16(p, tlv->u.udp_dest_port); p+=2; + break; + case TLV_REMOTE_ENDPOINT: + /* + Sub-TLV Type (1 Octet) + Sub-TLV Length (1 Octet) + Sub-TLV Value (10 or 22 Octets) + */ + put_u8(p, tlv->type); p++; + if (ipa_is_ip4(tlv->u.remote_endpoint.ip)) { + put_u8(p, 10); p++; + put_u32(p, tlv->u.remote_endpoint.asn); p+=4; + put_u16(p, NET_IP4); p+=2; + put_ip4(p, ipa_to_ip4(tlv->u.remote_endpoint.ip)); p+=4; + } else { + put_u8(p, 22); p++; + put_u32(p, tlv->u.remote_endpoint.asn); p+=4; + put_u16(p, NET_IP6); p+=2; + put_ip6(p, ipa_to_ip6(tlv->u.remote_endpoint.ip)); p+=16; + } + break; + default: + /* Ignore unknown */ + break; + } + + return build_tunnel_encap_rec(build_tunnel_encap_rec(p, t->left), t->right); +} + +static struct adata * +build_tunnel_encap(struct f_tree *t, int type, int len) +{ + struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) + len); + ad->length = len; + void *p = ad->data; + + /* + Header: + Tunnel Type (2 Octets) + Length (2 Octets) + Value (Variable) + */ + + put_u16(p, type); p += 2; + put_u16(p, len - 4); p += 2; + build_tunnel_encap_rec(p, t); + return ad; +} + + /** * interpret * @what: filter to interpret @@ -1106,7 +1247,7 @@ interpret(struct f_inst *what) break; case EAF_TYPE_TUNNEL_ENCAP: res.type = T_TLV; - runtime("FIXME Tunnel Encapsulation in e,a"); + runtime( "Getting tunnel encap attribute is not supported" ); break; default: bug("Unknown type in e,a"); @@ -1200,11 +1341,18 @@ interpret(struct f_inst *what) l->attrs[0].u.data = 0; break; case EAF_TYPE_TUNNEL_ENCAP: - if (v1.type != T_TLV) - runtime( "Setting tunnel encap attribute to non-tlv value" ); - debug( "FIXME tunnel encapsulation in e,S" ); - l->attrs[0].u.ptr = v1.val.ad; - break; + { + if (v1.type != T_SET) + runtime( "Setting tunnel encap attribute to non-tlv value %d", v1.type ); + int type = 0; + int len = calc_tunnel_encap(v1.val.t, &type); + if (len <= 0) + runtime( "Empty tunnel encapsulation" ); + else if (type <= 0 || type > 65535) + runtime( "Invalid tunnel encapsulation type: %d (0 < type <= 65535)", type ); + l->attrs[0].u.ptr = build_tunnel_encap(v1.val.t, type, len); + break; + } default: bug("Unknown type in e,S"); } diff --git a/nest/attrs.h b/nest/attrs.h index 8f76695d..68e4c876 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -200,20 +200,25 @@ struct adata *lc_set_sort(struct linpool *pool, struct adata *src); void ec_set_sort_x(struct adata *set); /* Sort in place */ /* Tunnel Encapsulation TLV types */ -#define TLV_WIREGUARD 0xffff +#define TLV_TUNNEL_TYPE 0x00 /* Reserved. Used internally only. */ +#define TLV_ENCAPSULATION 0x01 #define TLV_REMOTE_ENDPOINT 0x06 #define TLV_UDP_DEST_PORT 0x08 /* Tunnel Encapsulation TLV */ struct tlv { + int type; union { - const char *peer; + struct { + int type; + int length; + void *data; + } tunnel_encap; struct { u32 asn; ip_addr ip; } remote_endpoint; u16 udp_dest_port; - u32 color; } u; }; diff --git a/nest/route.h b/nest/route.h index 5b7085bf..377e0915 100644 --- a/nest/route.h +++ b/nest/route.h @@ -504,7 +504,7 @@ const char *ea_custom_name(uint ea); #define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */ #define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */ #define EAF_TYPE_LC_SET 0x12 /* Set of triplets of u32's - large community list */ -#define EAF_TYPE_TUNNEL_ENCAP 0x13 /* Tunnel Encapsulation (encoding per draft-ietf-idr-tunnel-encaps-10) */ +#define EAF_TYPE_TUNNEL_ENCAP 0x14 /* Tunnel Encapsulation (encoding per draft-ietf-idr-tunnel-encaps-11) */ #define EAF_TYPE_UNDEF 0x1f /* `force undefined' entry */ #define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ #define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index dec38d5b..1b245fbd 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -888,6 +888,15 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_mpls_label_stack, .format = bgp_format_mpls_label_stack, }, + [BA_TUNNEL_ENCAP] = { + .name = "tunnel_encap", + .type = EAF_TYPE_TUNNEL_ENCAP, + .flags = BAF_OPTIONAL | BAF_TRANSITIVE, + .export = bgp_export_tunnel_encap, + .encode = bgp_encode_tunnel_encap, + .decode = bgp_decode_tunnel_encap, + .format = bgp_format_tunnel_encap, + }, }; static inline int diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index ac8d024a..8ceff39e 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -29,7 +29,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG, - LIVED, STALE, IMPORT, IBGP, EBGP) + LIVED, STALE, IMPORT, IBGP, EBGP, BGP_TUNNEL_ENCAP) %type <i> bgp_nh %type <i32> bgp_afi @@ -295,6 +295,8 @@ dynamic_attr: BGP_EXT_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; dynamic_attr: BGP_LARGE_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; +dynamic_attr: BGP_TUNNEL_ENCAP + { $$ = f_new_dynamic_attr(EAF_TYPE_TUNNEL_ENCAP, T_TLV, EA_CODE(PROTOCOL_BGP, BA_TUNNEL_ENCAP)); } ; |