summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y81
-rw-r--r--filter/data.c3
-rw-r--r--filter/data.h5
-rw-r--r--filter/f-inst.c25
-rw-r--r--filter/filter.c172
-rw-r--r--filter/filter.h3
-rw-r--r--nest/attrs.h25
-rw-r--r--nest/config.Y2
-rw-r--r--nest/route.h1
9 files changed, 313 insertions, 4 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 340053ba..283badef 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -112,6 +112,69 @@ f_new_pair_set(int fa, int ta, int fb, int tb)
#define LC_ALL 0xFFFFFFFF
static struct f_tree *
+f_new_sub_tlv_item(u32 type, u32 v1)
+{
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_SUB_TLV;
+ struct tlv v;
+ v.type = type;
+ switch (type) {
+ case TLV_COLOR:
+ v.u.color = v1;
+ break;
+ 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_sub_tlv_tunnel_ep(u32 asn, ip_addr ip)
+{
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_SUB_TLV;
+ struct tlv v;
+ v.type = TLV_TUNNEL_ENDPOINT;
+ v.u.tunnel_endpoint.asn = asn;
+ v.u.tunnel_endpoint.ip = ip;
+ t->from.val.tlv = v;
+ t->to.val.tlv = v;
+ return t;
+}
+
+typedef char wg_key_b64_string[45];
+int wg_key_from_base64(u8 key[32], const wg_key_b64_string base64);
+
+static struct f_tree *
+f_new_sub_tlv_encap(u32 type, const char *v1)
+{
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_SUB_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;
+}
+
+static struct f_tree *
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
{
u64 fm, to;
@@ -178,6 +241,9 @@ f_generate_empty(struct f_dynamic_attr dyn)
case EAF_TYPE_LC_SET:
empty = f_const_empty_lclist;
break;
+ case EAF_TYPE_TUNNEL_ENCAP:
+ empty = f_const_empty_set;
+ break;
default:
cf_error("Can't empty that attribute");
}
@@ -441,7 +507,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
- BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
+ BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME,
+ TLV, TUNNEL_ENCAP, TUNNEL_ENDPOINT, UDP_DEST_PORT, COLOR, FORMAT)
%nonassoc THEN
%nonassoc ELSE
@@ -457,7 +524,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <ecs> ec_kind
%type <fret> break_command
%type <i32> cnum
-%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
+%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body sub_tlv_item
%type <trie> fprefix_set
%type <v> set_atom switch_atom fipa
%type <px> fprefix
@@ -531,6 +598,7 @@ type:
| CLIST { $$ = T_CLIST; }
| ECLIST { $$ = T_ECLIST; }
| LCLIST { $$ = T_LCLIST; }
+ | TLV { $$ = T_TLV; }
| type SET {
switch ($1) {
case T_INT:
@@ -540,6 +608,7 @@ type:
case T_LC:
case T_RD:
case T_IP:
+ case T_TLV:
$$ = T_SET;
break;
@@ -737,10 +806,17 @@ lc_item:
{ $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
;
+sub_tlv_item:
+ '(' TUNNEL_ENCAP ',' cnum ',' text ')' { $$ = f_new_sub_tlv_encap($4, $6); }
+ | '(' UDP_DEST_PORT ',' cnum ')' { $$ = f_new_sub_tlv_item(TLV_UDP_DEST_PORT, $4); }
+ | '(' COLOR ',' cnum ')' { $$ = f_new_sub_tlv_item(TLV_COLOR, $4); }
+ | '(' TUNNEL_ENDPOINT ',' NUM ',' ipa ')' { $$ = f_new_sub_tlv_tunnel_ep($4, $6); }
+
set_item:
pair_item
| ec_item
| lc_item
+ | sub_tlv_item
| set_atom { $$ = f_new_item($1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
;
@@ -749,6 +825,7 @@ switch_item:
pair_item
| ec_item
| lc_item
+ | sub_tlv_item
| switch_atom { $$ = f_new_item($1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
;
diff --git a/filter/data.c b/filter/data.c
index 62edd9e0..fd78ab6d 100644
--- a/filter/data.c
+++ b/filter/data.c
@@ -80,6 +80,9 @@ const struct f_val f_const_empty_path = {
}, f_const_empty_lclist = {
.type = T_LCLIST,
.val.ad = &null_adata,
+}, f_const_empty_set = {
+ .type = T_SET,
+ .val.t = NULL,
};
static struct adata *
diff --git a/filter/data.h b/filter/data.h
index 578ff98f..771bfc94 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -58,6 +58,8 @@ enum f_type {
T_LCLIST = 0x29, /* Large community list */
T_RD = 0x2a, /* Route distinguisher for VPN addresses */
T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */
+ T_TLV = 0x2c, /* Tunnel encapsulation TLV */
+ T_SUB_TLV = 0x2d, /* Tunnel encapsulation sub-TLV */
T_SET = 0x80,
T_PREFIX_SET = 0x81,
@@ -78,6 +80,7 @@ struct f_val {
const struct adata *ad;
const struct f_path_mask *path_mask;
struct f_path_mask_item pmi;
+ struct tlv tlv;
} val;
};
@@ -199,7 +202,7 @@ undef_value(struct f_val v)
(v.val.ad == &null_adata);
}
-extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
+extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist, f_const_empty_set;
enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 3bd0249c..7588e979 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -653,6 +653,10 @@
case EAF_TYPE_UNDEF:
RESULT_VOID;
break;
+ case EAF_TYPE_TUNNEL_ENCAP:
+ RESULT_(T_TLV, ad, e->u.ptr);
+ runtime( "Getting tunnel encap attribute is not supported" );
+ break;
default:
bug("Unknown dynamic attribute type");
}
@@ -713,6 +717,27 @@
}
break;
+ case EAF_TYPE_TUNNEL_ENCAP:
+ {
+ /* TODO remove type check? Refer to 26194bd - Filter: Improved parse-time typechecks */
+ 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( "Error tunnel encapsulation" );
+ else if (len == 0) {
+ struct adata *ad = lp_alloc(fpool, sizeof(struct adata) + len);
+ ad->length = len;
+ l->attrs[0].u.ptr = ad;
+ }
+ else if (type <= 0 || type > 65535)
+ runtime( "Invalid tunnel encapsulation type: %d (0 < type <= 65535)", type );
+ else
+ l->attrs[0].u.ptr = build_tunnel_encap(fpool, v1.val.t, type, len);
+ break;
+ }
+
default:
bug("Unknown dynamic attribute type");
}
diff --git a/filter/filter.c b/filter/filter.c
index ad9588b2..ced2975b 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -140,6 +140,178 @@ f_rta_cow(struct filter_state *fs)
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
+int
+calc_tunnel_encap(const struct f_tree *t, int *type)
+{
+ if (t == NULL)
+ return 0;
+
+ if (t->from.type == 0) {
+ return 0;
+ }
+
+ if (t->from.type != T_SUB_TLV) {
+ debug("Not tlv %d\n", t->from.type);
+ return -1;
+ }
+
+ const 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)
+ */
+ if (tlv->u.tunnel_encap.length > 0)
+ len = 4 + 2 + tlv->u.tunnel_encap.length;
+ else
+ len = 0;
+ *type = tlv->u.tunnel_encap.type;
+ break;
+ case TLV_COLOR:
+ /*
+ Sub-TLV Type (1 Octet)
+ Sub-TLV Length (1 Octet)
+ Sub-TLV Value (8 Octets)
+ */
+ len = 10;
+ 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_TUNNEL_ENDPOINT:
+ /*
+ Sub-TLV Type (1 Octet)
+ Sub-TLV Length (1 Octet)
+ Sub-TLV Value (10 or 22 Octets)
+ */
+ if (ipa_is_ip4(tlv->u.tunnel_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, const struct f_tree *t)
+{
+ if (t == NULL)
+ return p;
+
+ if (t->from.type != T_SUB_TLV) {
+ debug("Not tlv %d\n", t->from.type);
+ return p;
+ }
+
+ const 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)
+ */
+ int len = tlv->u.tunnel_encap.length;
+ if (len <= 0)
+ break;
+ put_u8(p, tlv->type); p++;
+ put_u8(p, len); p++;
+ memcpy(p, tlv->u.tunnel_encap.data, len); p+=len;
+ break;
+ }
+ case TLV_COLOR:
+ /*
+ Sub-TLV Type (1 Octet)
+ Sub-TLV Length (1 Octet)
+ Sub-TLV Value (8 Octets)
+ */
+ put_u8(p, tlv->type); p++;
+ put_u8(p, 8); p++;
+ put_u8(p, 0x03); p++;
+ put_u8(p, 0x0b); p++;
+ put_u16(p, 0x0); p+=2;
+ put_u32(p, tlv->u.color); p+=4;
+ 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_TUNNEL_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.tunnel_endpoint.ip)) {
+ put_u8(p, 10); p++;
+ put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4;
+ put_u16(p, NET_IP4); p+=2;
+ put_ip4(p, ipa_to_ip4(tlv->u.tunnel_endpoint.ip)); p+=4;
+ } else {
+ put_u8(p, 22); p++;
+ put_u32(p, tlv->u.tunnel_endpoint.asn); p+=4;
+ put_u16(p, NET_IP6); p+=2;
+ put_ip6(p, ipa_to_ip6(tlv->u.tunnel_endpoint.ip)); p+=16;
+ }
+ break;
+ default:
+ /* Ignore unknown */
+ break;
+ }
+
+ return build_tunnel_encap_rec(build_tunnel_encap_rec(p, t->left), t->right);
+}
+
+struct adata *
+build_tunnel_encap(struct linpool *pool, const struct f_tree *t, int type, int len)
+{
+ struct adata *ad = lp_alloc(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
* @fs: filter state
diff --git a/filter/filter.h b/filter/filter.h
index 9d997efb..1db4f9ee 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -66,6 +66,9 @@ void filter_commit(struct config *new, struct config *old);
void filters_dump_all(void);
+int calc_tunnel_encap(const struct f_tree *t, int *type);
+struct adata *build_tunnel_encap(struct linpool *pool, const struct f_tree *t, int type, int len);
+
#define FILTER_ACCEPT NULL
#define FILTER_REJECT ((struct filter *) 1)
#define FILTER_UNDEF ((struct filter *) 2) /* Used in BGP */
diff --git a/nest/attrs.h b/nest/attrs.h
index 3a4b0acd..c7a0c739 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -220,4 +220,29 @@ struct adata *lc_set_sort(struct linpool *pool, const struct adata *src);
void ec_set_sort_x(struct adata *set); /* Sort in place */
+/* Tunnel Encapsulation TLV types */
+#define TLV_TUNNEL_TYPE 0x00 /* Reserved. Used internally only. */
+#define TLV_ENCAPSULATION 0x01
+#define TLV_COLOR 0x04
+#define TLV_TUNNEL_ENDPOINT 0x06
+#define TLV_UDP_DEST_PORT 0x08
+
+/* Tunnel Encapsulation TLV */
+struct tlv {
+ int type;
+ union {
+ struct {
+ int type;
+ int length;
+ void *data;
+ } tunnel_encap;
+ struct {
+ u32 asn;
+ ip_addr ip;
+ } tunnel_endpoint;
+ u32 color;
+ u16 udp_dest_port;
+ } u;
+};
+
#endif
diff --git a/nest/config.Y b/nest/config.Y
index 8fe060c5..13fca2e5 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -327,7 +327,7 @@ iface_patt_node_init:
;
iface_patt_node_body:
- TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ }
+ text { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ }
| opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; }
;
diff --git a/nest/route.h b/nest/route.h
index cd4b75db..14ac9ff5 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -511,6 +511,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 0x16 /* Tunnel Encapsulation (encoding per draft-ietf-idr-tunnel-encaps-13) */
#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) */