+ /* Tunnel header match */
+ if (f->type == VNET_FLOW_TYPE_IP4_VXLAN)
+ {
+ u32 vni = f->ip4_vxlan.vni;
+ vxlan_header_t spec_hdr = {
+ .flags = VXLAN_FLAGS_I,
+ .vni_reserved = clib_host_to_net_u32 (vni << 8)
+ };
+ vxlan_header_t mask_hdr = {
+ .flags = 0xff,
+ .vni_reserved = clib_host_to_net_u32 (((u32) - 1) << 8)
+ };
+
+ clib_memset (raw, 0, sizeof raw);
+ raw[0].item.relative = 1;
+ raw[0].item.length = vxlan_hdr_sz;
+
+ clib_memcpy_fast (raw[0].val + raw_sz, &spec_hdr, vxlan_hdr_sz);
+ raw[0].item.pattern = raw[0].val + raw_sz;
+ clib_memcpy_fast (raw[1].val + raw_sz, &mask_hdr, vxlan_hdr_sz);
+ raw[1].item.pattern = raw[1].val + raw_sz;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_RAW;
+ item->spec = raw;
+ item->mask = raw + 1;
+ }
+ else if (f->type == VNET_FLOW_TYPE_IP4_GTPC)
+ {
+ vnet_flow_ip4_gtpc_t *gc = &f->ip4_gtpc;
+ gtp[0].teid = clib_host_to_net_u32 (gc->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPC;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+ }
+ else if (f->type == VNET_FLOW_TYPE_IP4_GTPU)
+ {
+ vnet_flow_ip4_gtpu_t *gu = &f->ip4_gtpu;
+ gtp[0].teid = clib_host_to_net_u32 (gu->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPU;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+ }
+ else if ((f->type == VNET_FLOW_TYPE_IP4_GTPU_IP4) ||
+ (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP6))
+ {
+ vnet_flow_ip4_gtpu_t *gu = &f->ip4_gtpu;
+ gtp[0].teid = clib_host_to_net_u32 (gu->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPU;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+
+ /* inner IP4 header */
+ if (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP4)
+ {
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_IPV4;
+
+ vnet_flow_ip4_gtpu_ip4_t *gu4 = &f->ip4_gtpu_ip4;
+ if (!gu4->inner_src_addr.mask.as_u32 &&
+ !gu4->inner_dst_addr.mask.as_u32)
+ {
+ item->spec = NULL;
+ item->mask = NULL;
+ }
+ else
+ {
+ inner_ip4[0].hdr.src_addr = gu4->inner_src_addr.addr.as_u32;
+ inner_ip4[1].hdr.src_addr = gu4->inner_src_addr.mask.as_u32;
+ inner_ip4[0].hdr.dst_addr = gu4->inner_dst_addr.addr.as_u32;
+ inner_ip4[1].hdr.dst_addr = gu4->inner_dst_addr.mask.as_u32;
+ item->spec = inner_ip4;
+ item->mask = inner_ip4 + 1;
+ }
+ }
+ else if (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP6)
+ {
+ ip6_address_t zero_addr;
+ vnet_flow_ip4_gtpu_ip6_t *gu6 = &f->ip4_gtpu_ip6;
+
+ clib_memset (&zero_addr, 0, sizeof (ip6_address_t));
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_IPV6;
+
+ if (!clib_memcmp (&gu6->inner_src_addr.mask, &zero_addr, 16) &&
+ !clib_memcmp (&gu6->inner_dst_addr.mask, &zero_addr, 16))
+ {
+ item->spec = NULL;
+ item->mask = NULL;
+ }
+ else
+ {
+ clib_memcpy_fast (inner_ip6[0].hdr.src_addr,
+ &gu6->inner_src_addr.addr, 16);
+ clib_memcpy_fast (inner_ip6[1].hdr.src_addr,
+ &gu6->inner_src_addr.mask, 16);
+ clib_memcpy_fast (inner_ip6[0].hdr.dst_addr,
+ &gu6->inner_dst_addr.addr, 16);
+ clib_memcpy_fast (inner_ip6[1].hdr.dst_addr,
+ &gu6->inner_dst_addr.mask, 16);
+ item->spec = inner_ip6;
+ item->mask = inner_ip6 + 1;
+ }
+ }
+ }
+ else if (f->type == VNET_FLOW_TYPE_IP6_GTPC)
+ {
+ vnet_flow_ip6_gtpc_t *gc = &f->ip6_gtpc;
+ gtp[0].teid = clib_host_to_net_u32 (gc->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPC;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+ }
+ else if (f->type == VNET_FLOW_TYPE_IP6_GTPU)
+ {
+ vnet_flow_ip6_gtpu_t *gu = &f->ip6_gtpu;
+ gtp[0].teid = clib_host_to_net_u32 (gu->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPU;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+ }
+ else if ((f->type == VNET_FLOW_TYPE_IP6_GTPU_IP4) ||
+ (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP6))
+ {
+ vnet_flow_ip6_gtpu_t *gu = &f->ip6_gtpu;
+ gtp[0].teid = clib_host_to_net_u32 (gu->teid);
+ gtp[1].teid = ~0;
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_GTPU;
+ item->spec = gtp;
+ item->mask = gtp + 1;
+
+ /* inner IP4 header */
+ if (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP4)
+ {
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_IPV4;
+
+ vnet_flow_ip6_gtpu_ip4_t *gu4 = &f->ip6_gtpu_ip4;
+
+ if (!gu4->inner_src_addr.mask.as_u32 &&
+ !gu4->inner_dst_addr.mask.as_u32)
+ {
+ item->spec = NULL;
+ item->mask = NULL;
+ }
+ else
+ {
+ inner_ip4[0].hdr.src_addr = gu4->inner_src_addr.addr.as_u32;
+ inner_ip4[1].hdr.src_addr = gu4->inner_src_addr.mask.as_u32;
+ inner_ip4[0].hdr.dst_addr = gu4->inner_dst_addr.addr.as_u32;
+ inner_ip4[1].hdr.dst_addr = gu4->inner_dst_addr.mask.as_u32;
+ item->spec = inner_ip4;
+ item->mask = inner_ip4 + 1;
+ }
+ }
+
+ if (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP6)
+ {
+ ip6_address_t zero_addr;
+ vnet_flow_ip6_gtpu_ip6_t *gu6 = &f->ip6_gtpu_ip6;
+
+ clib_memset (&zero_addr, 0, sizeof (ip6_address_t));
+
+ vec_add2 (items, item, 1);
+ item->type = RTE_FLOW_ITEM_TYPE_IPV6;
+
+ if (!clib_memcmp (&gu6->inner_src_addr.mask, &zero_addr, 16) &&
+ !clib_memcmp (&gu6->inner_dst_addr.mask, &zero_addr, 16))
+ {
+ item->spec = NULL;
+ item->mask = NULL;
+ }
+ else
+ {
+ clib_memcpy_fast (inner_ip6[0].hdr.src_addr,
+ &gu6->inner_src_addr.addr, 16);
+ clib_memcpy_fast (inner_ip6[1].hdr.src_addr,
+ &gu6->inner_src_addr.mask, 16);
+ clib_memcpy_fast (inner_ip6[0].hdr.dst_addr,
+ &gu6->inner_dst_addr.addr, 16);
+ clib_memcpy_fast (inner_ip6[1].hdr.dst_addr,
+ &gu6->inner_dst_addr.mask, 16);
+ item->spec = inner_ip6;
+ item->mask = inner_ip6 + 1;
+ }
+
+ }
+ }
+
+pattern_end: