flow: add ethernet flow
[vpp.git] / src / vnet / flow / flow_cli.c
index 11f3bcf..500f16b 100644 (file)
@@ -90,6 +90,30 @@ format_flow_actions (u8 * s, va_list * args)
   return s;
 }
 
+u8 *
+format_flow_enabled_hw (u8 * s, va_list * args)
+{
+  u32 flow_index = va_arg (*args, u32);
+  vnet_flow_t *f = vnet_get_flow (flow_index);
+  if (f == 0)
+    return format (s, "not found");
+
+  u8 *t = 0;
+  u32 hw_if_index;
+  uword private_data;
+  vnet_main_t *vnm = vnet_get_main ();
+  /* *INDENT-OFF* */
+  hash_foreach (hw_if_index, private_data, f->private_data,
+    ({
+     t = format (t, "%s%U", t ? ", " : "",
+                 format_vnet_hw_if_index_name, vnm, hw_if_index);
+     }));
+  /* *INDENT-ON* */
+  s = format (s, "%v", t);
+  vec_free (t);
+  return s;
+}
+
 static const char *flow_type_strings[] = { 0,
 #define _(a,b,c) c,
   foreach_flow_type
@@ -250,11 +274,30 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
     FLOW_ENABLE,
     FLOW_DISABLE
   } action = FLOW_UNKNOWN_ACTION;
-  u32 hw_if_index = ~0, tmp, flow_index = ~0;
+  u32 hw_if_index = ~0, flow_index = ~0;
   int rv;
-  u8 prot;
-
-  memset (&flow, 0, sizeof (vnet_flow_t));
+  u32 prot = 0, teid = 0;
+  vnet_flow_type_t type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+  bool is_gtpc_set = false;
+  bool is_gtpu_set = false;
+  vnet_flow_type_t outer_type = VNET_FLOW_TYPE_UNKNOWN;
+  vnet_flow_type_t inner_type = VNET_FLOW_TYPE_UNKNOWN;
+  bool outer_ip4_set = false, inner_ip4_set = false;
+  bool outer_ip6_set = false, inner_ip6_set = false;
+  ip4_address_and_mask_t ip4s = { };
+  ip4_address_and_mask_t ip4d = { };
+  ip4_address_and_mask_t inner_ip4s = { };
+  ip4_address_and_mask_t inner_ip4d = { };
+  ip6_address_and_mask_t ip6s = { };
+  ip6_address_and_mask_t ip6d = { };
+  ip6_address_and_mask_t inner_ip6s = { };
+  ip6_address_and_mask_t inner_ip6d = { };
+  ip_port_and_mask_t sport = { };
+  ip_port_and_mask_t dport = { };
+  u16 eth_type;
+  bool ethernet_set = false;
+
+  clib_memset (&flow, 0, sizeof (vnet_flow_t));
   flow.index = ~0;
   flow.actions = 0;
   flow.ip4_n_tuple.protocol = ~0;
@@ -271,24 +314,47 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
        action = FLOW_ENABLE;
       else if (unformat (line_input, "disable"))
        action = FLOW_DISABLE;
+      else if (unformat (line_input, "eth-type %U",
+                        unformat_ethernet_type_host_byte_order, &eth_type))
+       ethernet_set = true;
       else if (unformat (line_input, "src-ip %U",
-                        unformat_ip4_address_and_mask,
-                        &flow.ip4_n_tuple.src_addr))
-       ;
+                        unformat_ip4_address_and_mask, &ip4s))
+       outer_ip4_set = true;
       else if (unformat (line_input, "dst-ip %U",
-                        unformat_ip4_address_and_mask,
-                        &flow.ip4_n_tuple.dst_addr))
-       ;
+                        unformat_ip4_address_and_mask, &ip4d))
+       outer_ip4_set = true;
+      else if (unformat (line_input, "ip6-src-ip %U",
+                        unformat_ip6_address_and_mask, &ip6s))
+       outer_ip6_set = true;
+      else if (unformat (line_input, "ip6-dst-ip %U",
+                        unformat_ip6_address_and_mask, &ip6d))
+       outer_ip6_set = true;
+      else if (unformat (line_input, "inner-src-ip %U",
+                        unformat_ip4_address_and_mask, &inner_ip4s))
+       inner_ip4_set = true;
+      else if (unformat (line_input, "inner-dst-ip %U",
+                        unformat_ip4_address_and_mask, &inner_ip4d))
+       inner_ip4_set = true;
+      else if (unformat (line_input, "inner-ip6-src-ip %U",
+                        unformat_ip6_address_and_mask, &inner_ip6s))
+       inner_ip6_set = true;
+      else if (unformat (line_input, "inner-ip6-dst-ip %U",
+                        unformat_ip6_address_and_mask, &inner_ip6d))
+       inner_ip6_set = true;
       else if (unformat (line_input, "src-port %U", unformat_ip_port_and_mask,
-                        &flow.ip4_n_tuple.src_port))
+                        &sport))
        ;
       else if (unformat (line_input, "dst-port %U", unformat_ip_port_and_mask,
-                        &flow.ip4_n_tuple.dst_port))
+                        &dport))
        ;
       else if (unformat (line_input, "proto %U", unformat_ip_protocol, &prot))
-       flow.ip4_n_tuple.protocol = prot;
-      else if (unformat (line_input, "proto %u", &tmp))
-       flow.ip4_n_tuple.protocol = tmp;
+       ;
+      else if (unformat (line_input, "proto %u", &prot))
+       ;
+      else if (unformat (line_input, "gtpc teid %u", &teid))
+       is_gtpc_set = true;
+      else if (unformat (line_input, "gtpu teid %u", &teid))
+       is_gtpu_set = true;
       else if (unformat (line_input, "index %u", &flow_index))
        ;
       else if (unformat (line_input, "next-node %U", unformat_vlib_node, vm,
@@ -299,6 +365,11 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
       else if (unformat (line_input, "buffer-advance %d",
                         &flow.buffer_advance))
        flow.actions |= VNET_FLOW_ACTION_BUFFER_ADVANCE;
+      else if (unformat (line_input, "redirect-to-queue %d",
+                        &flow.redirect_queue))
+       flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_QUEUE;
+      else if (unformat (line_input, "drop"))
+       flow.actions |= VNET_FLOW_ACTION_DROP;
       else if (unformat (line_input, "%U", unformat_vnet_hw_interface, vnm,
                         &hw_if_index))
        ;
@@ -319,13 +390,176 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
   switch (action)
     {
     case FLOW_ADD:
-      if (flow.ip4_n_tuple.protocol == (ip_protocol_t) ~ 0)
-       return clib_error_return (0, "Please specify ip protocol");
-
       if (flow.actions == 0)
        return clib_error_return (0, "Please specify at least one action");
-      flow.type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+
+      /* Adjust the flow type */
+      if (ethernet_set == true)
+       outer_type = VNET_FLOW_TYPE_ETHERNET;
+      if (outer_ip4_set == true)
+       outer_type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+      else if (outer_ip6_set == true)
+       outer_type = VNET_FLOW_TYPE_IP6_N_TUPLE;
+      if (inner_ip4_set == true)
+       inner_type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+      else if (inner_ip6_set == true)
+       inner_type = VNET_FLOW_TYPE_IP6_N_TUPLE;
+
+      if (outer_type == VNET_FLOW_TYPE_UNKNOWN)
+       return clib_error_return (0, "Please specify a supported flow type");
+
+      if (outer_type == VNET_FLOW_TYPE_ETHERNET)
+       type = VNET_FLOW_TYPE_ETHERNET;
+      else if (outer_type == VNET_FLOW_TYPE_IP4_N_TUPLE)
+       {
+         type = VNET_FLOW_TYPE_IP4_N_TUPLE;
+
+         if (inner_type == VNET_FLOW_TYPE_UNKNOWN)
+           {
+             if (is_gtpc_set)
+               type = VNET_FLOW_TYPE_IP4_GTPC;
+             else if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP4_GTPU;
+           }
+         else if (inner_type == VNET_FLOW_TYPE_IP4_N_TUPLE)
+           {
+             if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP4_GTPU_IP4;
+           }
+         else if (inner_type == VNET_FLOW_TYPE_IP6_N_TUPLE)
+           {
+             if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP4_GTPU_IP6;
+           }
+       }
+      else if (outer_type == VNET_FLOW_TYPE_IP6_N_TUPLE)
+       {
+         type = VNET_FLOW_TYPE_IP6_N_TUPLE;
+
+         if (inner_type == VNET_FLOW_TYPE_UNKNOWN)
+           {
+             if (is_gtpc_set)
+               type = VNET_FLOW_TYPE_IP6_GTPC;
+             else if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP6_GTPU;
+           }
+         else if (inner_type == VNET_FLOW_TYPE_IP4_N_TUPLE)
+           {
+             if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP6_GTPU_IP4;
+           }
+         else if (inner_type == VNET_FLOW_TYPE_IP6_N_TUPLE)
+           {
+             if (is_gtpu_set)
+               type = VNET_FLOW_TYPE_IP6_GTPU_IP6;
+           }
+       }
+
+      //assign specific field values per flow type
+      switch (type)
+       {
+       case VNET_FLOW_TYPE_ETHERNET:
+         memset (&flow.ethernet, 0, sizeof (flow.ethernet));
+         flow.ethernet.eth_hdr.type = eth_type;
+         break;
+
+       case VNET_FLOW_TYPE_IP4_N_TUPLE:
+       case VNET_FLOW_TYPE_IP4_GTPC:
+       case VNET_FLOW_TYPE_IP4_GTPU:
+       case VNET_FLOW_TYPE_IP4_GTPU_IP4:
+       case VNET_FLOW_TYPE_IP4_GTPU_IP6:
+         clib_memcpy (&flow.ip4_n_tuple.src_addr, &ip4s,
+                      sizeof (ip4_address_and_mask_t));
+         clib_memcpy (&flow.ip4_n_tuple.dst_addr, &ip4d,
+                      sizeof (ip4_address_and_mask_t));
+         clib_memcpy (&flow.ip4_n_tuple.src_port, &sport,
+                      sizeof (ip_port_and_mask_t));
+         clib_memcpy (&flow.ip4_n_tuple.dst_port, &dport,
+                      sizeof (ip_port_and_mask_t));
+         flow.ip4_n_tuple.protocol = prot;
+
+         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_GTPU_IP4)
+           {
+             flow.ip4_gtpu_ip4.teid = teid;
+             clib_memcpy (&flow.ip4_gtpu_ip4.inner_src_addr, &inner_ip4s,
+                          sizeof (ip4_address_and_mask_t));
+             clib_memcpy (&flow.ip4_gtpu_ip4.inner_dst_addr, &inner_ip4d,
+                          sizeof (ip4_address_and_mask_t));
+           }
+         else if (type == VNET_FLOW_TYPE_IP4_GTPU_IP6)
+           {
+             flow.ip4_gtpu_ip6.teid = teid;
+             clib_memcpy (&flow.ip4_gtpu_ip6.inner_src_addr, &inner_ip6s,
+                          sizeof (ip6_address_and_mask_t));
+             clib_memcpy (&flow.ip4_gtpu_ip6.inner_dst_addr, &inner_ip6d,
+                          sizeof (ip6_address_and_mask_t));
+           }
+
+         if (flow.ip4_n_tuple.protocol == (ip_protocol_t) ~ 0)
+           return clib_error_return (0, "Please specify ip protocol");
+         if ((type != VNET_FLOW_TYPE_IP4_N_TUPLE) &&
+             (flow.ip4_n_tuple.protocol != IP_PROTOCOL_UDP))
+           return clib_error_return (0,
+                                     "For GTP related flow, ip protocol must be UDP");
+         break;
+
+       case VNET_FLOW_TYPE_IP6_N_TUPLE:
+       case VNET_FLOW_TYPE_IP6_GTPC:
+       case VNET_FLOW_TYPE_IP6_GTPU:
+       case VNET_FLOW_TYPE_IP6_GTPU_IP4:
+       case VNET_FLOW_TYPE_IP6_GTPU_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));
+         clib_memcpy (&flow.ip6_n_tuple.src_port, &sport,
+                      sizeof (ip_port_and_mask_t));
+         clib_memcpy (&flow.ip6_n_tuple.dst_port, &dport,
+                      sizeof (ip_port_and_mask_t));
+         flow.ip6_n_tuple.protocol = prot;
+
+         if (type == VNET_FLOW_TYPE_IP6_GTPC)
+           flow.ip6_gtpc.teid = teid;
+         else if (type == VNET_FLOW_TYPE_IP6_GTPU)
+           flow.ip6_gtpu.teid = teid;
+         else if (type == VNET_FLOW_TYPE_IP6_GTPU_IP4)
+           {
+             flow.ip6_gtpu_ip4.teid = teid;
+             clib_memcpy (&flow.ip6_gtpu_ip4.inner_src_addr, &inner_ip4s,
+                          sizeof (ip4_address_and_mask_t));
+             clib_memcpy (&flow.ip6_gtpu_ip4.inner_dst_addr, &inner_ip4d,
+                          sizeof (ip4_address_and_mask_t));
+           }
+         else if (type == VNET_FLOW_TYPE_IP6_GTPU_IP6)
+           {
+             flow.ip6_gtpu_ip6.teid = teid;
+             clib_memcpy (&flow.ip6_gtpu_ip6.inner_src_addr, &inner_ip6s,
+                          sizeof (ip6_address_and_mask_t));
+             clib_memcpy (&flow.ip6_gtpu_ip6.inner_dst_addr, &inner_ip6d,
+                          sizeof (ip6_address_and_mask_t));
+           }
+
+         if (flow.ip6_n_tuple.protocol == (ip_protocol_t) ~ 0)
+           return clib_error_return (0, "Please specify ip protocol");
+         if ((type != VNET_FLOW_TYPE_IP4_N_TUPLE) &&
+             (flow.ip6_n_tuple.protocol != IP_PROTOCOL_UDP))
+           return clib_error_return (0,
+                                     "For GTP related flow, ip protocol must be UDP");
+         break;
+
+       default:
+         break;
+       }
+
+      flow.type = type;
       rv = vnet_flow_add (vnm, &flow, &flow_index);
+      if (!rv)
+       printf ("flow %u added\n", flow_index);
+
       break;
     case FLOW_DEL:
       rv = vnet_flow_del (vnm, flow_index);