summaryrefslogtreecommitdiff
path: root/filter/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'filter/filter.c')
-rw-r--r--filter/filter.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/filter/filter.c b/filter/filter.c
index e505d570..90673865 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -141,6 +141,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) {
+ DBG("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) {
+ DBG("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