+
+ /* Adjust the flow type */
+ switch (flow_class)
+ {
+ case FLOW_ETHERNET_CLASS:
+ type = VNET_FLOW_TYPE_ETHERNET;
+ break;
+
+ case FLOW_IPV4_CLASS:
+ if (gtpc_set)
+ {
+ type = VNET_FLOW_TYPE_IP4_GTPC;
+ protocol.prot = IP_PROTOCOL_UDP;
+ }
+ else if (gtpu_set)
+ {
+ type = VNET_FLOW_TYPE_IP4_GTPU;
+ protocol.prot = IP_PROTOCOL_UDP;
+ }
+ else if (vni_set)
+ {
+ type = VNET_FLOW_TYPE_IP4_VXLAN;
+ protocol.prot = IP_PROTOCOL_UDP;
+ }
+ else if (l2tpv3oip_set)
+ type = VNET_FLOW_TYPE_IP4_L2TPV3OIP;
+ else if (ipsec_esp_set)
+ type = VNET_FLOW_TYPE_IP4_IPSEC_ESP;
+ else if (ipsec_ah_set)
+ type = VNET_FLOW_TYPE_IP4_IPSEC_AH;
+ else if (tcp_udp_port_set)
+ type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+ else
+ type = VNET_FLOW_TYPE_IP4;
+ break;
+ case FLOW_IPV6_CLASS:
+ if (tcp_udp_port_set)
+ type = VNET_FLOW_TYPE_IP6_N_TUPLE;
+ else if (vni_set)
+ type = VNET_FLOW_TYPE_IP6_VXLAN;
+ else
+ type = VNET_FLOW_TYPE_IP6;
+ break;
+
+ default:
+ if (spec && mask)
+ {
+ type = VNET_FLOW_TYPE_GENERIC;
+ break;
+ }
+ return clib_error_return (0,
+ "Please specify a supported flow type");
+ }
+
+ /* Assign specific field values per flow type */
+ if (flow_class == FLOW_ETHERNET_CLASS)
+ {
+ flow.ethernet.eth_hdr.type = eth_type;
+ }
+ else if (flow_class == FLOW_IPV4_CLASS)
+ {
+ vnet_flow_ip4_t *ip4_ptr = &flow.ip4;
+
+ clib_memcpy (&ip4_ptr->src_addr, &ip4s,
+ sizeof (ip4_address_and_mask_t));
+ clib_memcpy (&ip4_ptr->dst_addr, &ip4d,
+ sizeof (ip4_address_and_mask_t));
+ ip4_ptr->protocol.prot = protocol.prot;
+
+ /* In this cli, we use the protocol.mask only when the flow type is
+ * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
+ * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
+ */
+ if (type == VNET_FLOW_TYPE_IP4)
+ ip4_ptr->protocol.mask = protocol.mask;
+
+ switch (protocol.prot)
+ {
+ /* ip4-n-tuple */
+ case IP_PROTOCOL_TCP:
+ case IP_PROTOCOL_UDP:
+ flow.ip4_n_tuple.src_port = sport;
+ flow.ip4_n_tuple.dst_port = dport;
+
+ if (type == VNET_FLOW_TYPE_IP4_GTPC)
+ flow.ip4_gtpc.teid = teid;
+ else if (type == VNET_FLOW_TYPE_IP4_GTPU)
+ flow.ip4_gtpu.teid = teid;
+ else if (type == VNET_FLOW_TYPE_IP4_VXLAN)
+ flow.ip4_vxlan.vni = vni;
+ break;
+ case IP_PROTOCOL_L2TP:
+ flow.ip4_l2tpv3oip.session_id = session_id;
+ break;
+ case IP_PROTOCOL_IPSEC_ESP:
+ flow.ip4_ipsec_esp.spi = spi;
+ break;
+ case IP_PROTOCOL_IPSEC_AH:
+ flow.ip4_ipsec_esp.spi = spi;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (flow_class == FLOW_IPV6_CLASS)
+ {
+ vnet_flow_ip6_t *ip6_ptr = &flow.ip6;
+
+ clib_memcpy (&flow.ip6_n_tuple.src_addr, &ip6s,
+ sizeof (ip6_address_and_mask_t));
+ clib_memcpy (&flow.ip6_n_tuple.dst_addr, &ip6d,
+ sizeof (ip6_address_and_mask_t));
+
+ ip6_ptr->protocol.prot = protocol.prot;
+
+ /* In this cli, we use the protocol.mask only when the flow type is
+ * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
+ * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
+ */
+ if (type == VNET_FLOW_TYPE_IP6)
+ ip6_ptr->protocol.mask = protocol.mask;
+
+ switch (protocol.prot)
+ {
+ /* ip6-n-tuple */
+ case IP_PROTOCOL_TCP:
+ case IP_PROTOCOL_UDP:
+ flow.ip6_n_tuple.src_port = sport;
+ flow.ip6_n_tuple.dst_port = dport;
+
+ if (type == VNET_FLOW_TYPE_IP6_VXLAN)
+ flow.ip6_vxlan.vni = vni;
+ break;
+ default:
+ break;
+ }
+ }
+ if (type == VNET_FLOW_TYPE_GENERIC)
+ {
+ clib_memcpy (flow.generic.pattern.spec, spec,
+ sizeof (flow.generic.pattern.spec));
+ clib_memcpy (flow.generic.pattern.mask, mask,
+ sizeof (flow.generic.pattern.mask));
+ }
+
+ flow.type = type;