summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y126
-rw-r--r--filter/filter.c160
-rw-r--r--nest/attrs.h11
-rw-r--r--nest/route.h2
-rw-r--r--proto/bgp/attrs.c9
-rw-r--r--proto/bgp/config.Y4
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)); } ;