From 34bfa50b61f8cf454ddce9f378e3d5d29f74a72b Mon Sep 17 00:00:00 2001 From: Chenmin Sun Date: Mon, 27 Jul 2020 17:40:17 +0800 Subject: flow: code refactor This is the code refactor for vnet/flow infra and the dpdk_plugin flow implementation. The main works of the refactor are: 1. Added two base flow type: VNET_FLOW_TYPE_IP4 and VNET_FLOW_TYPE_IP6 as the base the flow type 2. All the other flows are derived from the base flow types 3. Removed some flow types that are not currently supported by the hardware, and VPP won't leverage them either: IP4_GTPU_IP4, IP4_GTPU_IP6, IP6_GTPC, IP6_GTPU, IP6_GTPU_IP4, IP6_GTPU_IP6 4. Re-implemented the vnet/flow cli as well as the dpdk_plugin implementation 5. refine cli prompt 6. refine display info in command "show flow entry" Type: refactor Signed-off-by: Chenmin Sun Change-Id: Ica5e61c5881adc73b28335fd83e36ec1cb420c96 --- src/vnet/flow/flow_cli.c | 506 +++++++++++++++++++++++++---------------------- 1 file changed, 270 insertions(+), 236 deletions(-) (limited to 'src/vnet/flow/flow_cli.c') diff --git a/src/vnet/flow/flow_cli.c b/src/vnet/flow/flow_cli.c index 98007a7723e..7dd68677c3b 100644 --- a/src/vnet/flow/flow_cli.c +++ b/src/vnet/flow/flow_cli.c @@ -12,11 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include #include #include +#include #include static format_function_t format_flow; @@ -60,6 +62,40 @@ format_ip_port_and_mask (u8 * s, va_list * args) return format (s, "%u/0x%x", pm->port, pm->mask); } +uword +unformat_ip_protocol_and_mask (unformat_input_t * input, va_list * args) +{ + ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *); + u32 prot = 0, mask = 0; + + if (unformat (input, "any")) + ; + else if (unformat (input, "%U", unformat_ip_protocol, &prot)) + mask = 0xFF; + else if (unformat (input, "%u", &prot)) + mask = 0xFF; + else + return 0; + + if (prot > 0XFF || mask > 0xFF) + return 0; + + pm->prot = prot; + pm->mask = mask; + return 1; +} + +u8 * +format_ip_protocol_and_mask (u8 * s, va_list * args) +{ + ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *); + + if (pm->prot == 0 && pm->mask == 0) + return format (s, "any"); + + return format (s, "%U", format_ip_protocol, pm->prot); +} + u8 * format_flow_error (u8 * s, va_list * args) { @@ -114,6 +150,38 @@ format_flow_enabled_hw (u8 * s, va_list * args) return s; } +u8 * +format_rss_function (u8 * s, va_list * args) +{ + vnet_rss_function_t func = va_arg (*args, vnet_rss_function_t); + + if (0) + ; +#undef _ +#define _(f, n) \ + else if (func == VNET_RSS_FUNC_##f) \ + return format (s, n); + + foreach_rss_function +#undef _ + return format (s, "unknown"); +} + +u8 * +format_rss_types (u8 * s, va_list * args) +{ + u64 type = va_arg (*args, u64); + +#undef _ +#define _(a,b,c) \ + if (type & (1UL<src_addr, &ip4s, sizeof (ip4_address_and_mask_t)); - clib_memcpy (&flow.ip4_n_tuple.dst_addr, &ip4d, + clib_memcpy (&ip4_ptr->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) + 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) { - 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)); + /* 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; - 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_IP6_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; + ip6_ptr->protocol.prot = protocol.prot; - default: - break; + /* 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; + } } flow.type = type; rv = vnet_flow_add (vnm, &flow, &flow_index); if (!rv) - printf ("flow %u added\n", flow_index); + vlib_cli_output (vm, "flow %u added", flow_index); break; case FLOW_DEL: @@ -681,20 +683,27 @@ test_flow (vlib_main_t * vm, unformat_input_t * input, if (rv < 0) return clib_error_return (0, "flow error: %U", format_flow_error, rv); + return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (test_flow_command, static) = { .path = "test flow", - .short_help = "test flow add [src-ip ] [dst-ip " - "] [src-port ] [dst-port ] " - "[proto ", + .short_help = "test flow [add|del|enable|disable] [index ] " + "[src-ip ] [dst-ip ] " + "[ip6-src-ip ] [ip6-dst-ip ] " + "[src-port ] [dst-port ] " + "[proto ] " + "[gtpc teid ] [gtpu teid ] [vxlan ] " + "[session id ] [spi ]" + "[next-node ] [mark ] [buffer-advance ] " + "[redirect-to-queue ] [drop] " + "[rss function ] [rss types ]", .function = test_flow, }; /* *INDENT-ON* */ - static u8 * format_flow_match_element (u8 * s, va_list * args) { @@ -710,6 +719,16 @@ format_flow_match_element (u8 * s, va_list * args) if (strncmp (type, "u32", 3) == 0) return format (s, "%d", *(u32 *) ptr); + if (strncmp (type, "ethernet_header_t", 13) == 0) + { + ethernet_max_header_t m; + memset (&m, 0, sizeof (m)); + m.ethernet = *(ethernet_header_t *) ptr; + /* convert the ethernet type to net order */ + m.ethernet.type = clib_host_to_net_u16 (m.ethernet.type); + return format (s, "%U", format_ethernet_header, &m); + } + if (strncmp (type, "ip4_address_t", 13) == 0) return format (s, "%U", format_ip4_address, ptr); @@ -722,8 +741,8 @@ format_flow_match_element (u8 * s, va_list * args) if (strncmp (type, "ip6_address_and_mask_t", 13) == 0) return format (s, "%U", format_ip6_address_and_mask, ptr); - if (strncmp (type, "ip_protocol_t", 13) == 0) - return format (s, "%U", format_ip_protocol, *(ip_protocol_t *) ptr); + if (strncmp (type, "ip_prot_and_mask_t", 13) == 0) + return format (s, "%U", format_ip_protocol_and_mask, ptr); if (strncmp (type, "ip_port_and_mask_t", 18) == 0) return format (s, "%U", format_ip_port_and_mask, ptr); @@ -777,9 +796,16 @@ format_flow (u8 * s, va_list * args) s = format (s, "\n%Uaction: %U", format_white_space, indent + 2, format_flow_actions, f->actions); + if (f->actions & VNET_FLOW_ACTION_DROP) + t = format (t, "%sdrop", t ? ", " : ""); + if (f->actions & VNET_FLOW_ACTION_MARK) t = format (t, "%smark %u", t ? ", " : "", f->mark_flow_id); + if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_QUEUE) + t = + format (t, "%sredirect-to-queue %u", t ? ", " : "", f->redirect_queue); + if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE) t = format (t, "%snext-node %U", t ? ", " : "", format_vlib_node_name, vm, f->redirect_node_index); @@ -787,6 +813,14 @@ format_flow (u8 * s, va_list * args) if (f->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE) t = format (t, "%sbuffer-advance %d", t ? ", " : "", f->buffer_advance); + if (f->actions & VNET_FLOW_ACTION_RSS) + { + t = format (t, "%srss function %U", t ? ", " : "", + format_rss_function, f->rss_fun); + t = format (t, "%srss types %U", t ? ", " : "", + format_rss_types, f->rss_types); + } + if (t) { s = format (s, "\n%U%v", format_white_space, indent + 4, t); -- cgit 1.2.3-korg