X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest-pmd%2Fconfig.c;h=1b1e738f8360a7e9a95167f7d2511cd1fc79c069;hb=2d8699ebb2a0638e8ae18fc0a83c56f984d0b270;hp=dde6cdcff1cb45e17628e6d62f3f5818353e8160;hpb=8e1d0547d6ed6a28c5c80c832f7b259518b89735;p=dpdk.git diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index dde6cdcff1..1b1e738f83 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,9 @@ #ifdef RTE_NET_BNXT #include #endif +#ifdef RTE_LIB_GRO #include +#endif #include #include "testpmd.h" @@ -89,7 +90,7 @@ const struct rss_type_info rss_type_table[] = { { "all", RTE_ETH_RSS_ETH | RTE_ETH_RSS_VLAN | RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_SCTP | RTE_ETH_RSS_L2_PAYLOAD | RTE_ETH_RSS_L2TPV3 | RTE_ETH_RSS_ESP | RTE_ETH_RSS_AH | RTE_ETH_RSS_PFCP | - RTE_ETH_RSS_GTPU | RTE_ETH_RSS_ECPRI | RTE_ETH_RSS_MPLS}, + RTE_ETH_RSS_GTPU | RTE_ETH_RSS_ECPRI | RTE_ETH_RSS_MPLS | RTE_ETH_RSS_L2TPV2}, { "none", 0 }, { "eth", RTE_ETH_RSS_ETH }, { "l2-src-only", RTE_ETH_RSS_L2_SRC_ONLY }, @@ -142,6 +143,7 @@ const struct rss_type_info rss_type_table[] = { { "mpls", RTE_ETH_RSS_MPLS }, { "ipv4-chksum", RTE_ETH_RSS_IPV4_CHKSUM }, { "l4-chksum", RTE_ETH_RSS_L4_CHKSUM }, + { "l2tpv2", RTE_ETH_RSS_L2TPV2 }, { NULL, 0 }, }; @@ -247,14 +249,20 @@ nic_stats_display(portid_t port_id) diff_ns; uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx; struct rte_eth_stats stats; - static const char *nic_stats_border = "########################"; + int ret; if (port_id_is_invalid(port_id, ENABLED_WARN)) { print_valid_ports(); return; } - rte_eth_stats_get(port_id, &stats); + ret = rte_eth_stats_get(port_id, &stats); + if (ret != 0) { + fprintf(stderr, + "%s: Error: failed to get stats (port %u): %d", + __func__, port_id, ret); + return; + } printf("\n %s NIC statistics for port %-2d %s\n", nic_stats_border, port_id, nic_stats_border); @@ -911,10 +919,15 @@ port_eeprom_display(portid_t port_id) return; } - char buf[len_eeprom]; einfo.offset = 0; einfo.length = len_eeprom; - einfo.data = buf; + einfo.data = calloc(1, len_eeprom); + if (!einfo.data) { + fprintf(stderr, + "Allocation of port %u eeprom data failed\n", + port_id); + return; + } ret = rte_eth_dev_get_eeprom(port_id, &einfo); if (ret != 0) { @@ -932,10 +945,12 @@ port_eeprom_display(portid_t port_id) fprintf(stderr, "Unable to get EEPROM: %d\n", ret); break; } + free(einfo.data); return; } rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); printf("Finish -- Port: %d EEPROM length: %d bytes\n", port_id, len_eeprom); + free(einfo.data); } void @@ -971,10 +986,15 @@ port_module_eeprom_display(portid_t port_id) return; } - char buf[minfo.eeprom_len]; einfo.offset = 0; einfo.length = minfo.eeprom_len; - einfo.data = buf; + einfo.data = calloc(1, minfo.eeprom_len); + if (!einfo.data) { + fprintf(stderr, + "Allocation of port %u eeprom data failed\n", + port_id); + return; + } ret = rte_eth_dev_get_module_eeprom(port_id, &einfo); if (ret != 0) { @@ -993,11 +1013,13 @@ port_module_eeprom_display(portid_t port_id) ret); break; } + free(einfo.data); return; } rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); printf("Finish -- Port: %d MODULE EEPROM length: %d bytes\n", port_id, einfo.length); + free(einfo.data); } int @@ -1232,6 +1254,57 @@ port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v) display_port_reg_value(port_id, reg_off, reg_v); } +static uint32_t +eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu) +{ + uint32_t overhead_len; + + if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu) + overhead_len = max_rx_pktlen - max_mtu; + else + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + + return overhead_len; +} + +static int +eth_dev_validate_mtu(uint16_t port_id, uint16_t mtu) +{ + struct rte_eth_dev_info dev_info; + uint32_t overhead_len; + uint32_t frame_size; + int ret; + + ret = rte_eth_dev_info_get(port_id, &dev_info); + if (ret != 0) + return ret; + + if (mtu < dev_info.min_mtu) { + fprintf(stderr, + "MTU (%u) < device min MTU (%u) for port_id %u\n", + mtu, dev_info.min_mtu, port_id); + return -EINVAL; + } + if (mtu > dev_info.max_mtu) { + fprintf(stderr, + "MTU (%u) > device max MTU (%u) for port_id %u\n", + mtu, dev_info.max_mtu, port_id); + return -EINVAL; + } + + overhead_len = eth_dev_get_overhead_len(dev_info.max_rx_pktlen, + dev_info.max_mtu); + frame_size = mtu + overhead_len; + if (frame_size > dev_info.max_rx_pktlen) { + fprintf(stderr, + "Frame size (%u) > device max frame size (%u) for port_id %u\n", + frame_size, dev_info.max_rx_pktlen, port_id); + return -EINVAL; + } + + return 0; +} + void port_mtu_set(portid_t port_id, uint16_t mtu) { @@ -1241,6 +1314,10 @@ port_mtu_set(portid_t port_id, uint16_t mtu) if (port_id_is_invalid(port_id, ENABLED_WARN)) return; + diag = eth_dev_validate_mtu(port_id, mtu); + if (diag != 0) + return; + if (port->need_reconfig == 0) { diag = rte_eth_dev_set_mtu(port_id, mtu); if (diag != 0) { @@ -1449,6 +1526,21 @@ port_flow_complain(struct rte_flow_error *error) error->cause), buf) : "", error->message ? error->message : "(no stated reason)", rte_strerror(err)); + + switch (error->type) { + case RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER: + fprintf(stderr, "The status suggests the use of \"transfer\" " + "as the possible cause of the failure. Make " + "sure that the flow in question and its " + "indirect components (if any) are managed " + "via \"transfer\" proxy port. Use command " + "\"show port (port_id) flow transfer proxy\" " + "to figure out the proxy port ID\n"); + break; + default: + break; + } + return -err; } @@ -1579,34 +1671,166 @@ action_alloc(portid_t port_id, uint32_t id, return 0; } -/** Create indirect action */ +static int +template_alloc(uint32_t id, struct port_template **template, + struct port_template **list) +{ + struct port_template *lst = *list; + struct port_template **ppt; + struct port_template *pt = NULL; + + *template = NULL; + if (id == UINT32_MAX) { + /* taking first available ID */ + if (lst) { + if (lst->id == UINT32_MAX - 1) { + printf("Highest template ID is already" + " assigned, delete it first\n"); + return -ENOMEM; + } + id = lst->id + 1; + } else { + id = 0; + } + } + pt = calloc(1, sizeof(*pt)); + if (!pt) { + printf("Allocation of port template failed\n"); + return -ENOMEM; + } + ppt = list; + while (*ppt && (*ppt)->id > id) + ppt = &(*ppt)->next; + if (*ppt && (*ppt)->id == id) { + printf("Template #%u is already assigned," + " delete it first\n", id); + free(pt); + return -EINVAL; + } + pt->next = *ppt; + pt->id = id; + *ppt = pt; + *template = pt; + return 0; +} + +static int +table_alloc(uint32_t id, struct port_table **table, + struct port_table **list) +{ + struct port_table *lst = *list; + struct port_table **ppt; + struct port_table *pt = NULL; + + *table = NULL; + if (id == UINT32_MAX) { + /* taking first available ID */ + if (lst) { + if (lst->id == UINT32_MAX - 1) { + printf("Highest table ID is already" + " assigned, delete it first\n"); + return -ENOMEM; + } + id = lst->id + 1; + } else { + id = 0; + } + } + pt = calloc(1, sizeof(*pt)); + if (!pt) { + printf("Allocation of table failed\n"); + return -ENOMEM; + } + ppt = list; + while (*ppt && (*ppt)->id > id) + ppt = &(*ppt)->next; + if (*ppt && (*ppt)->id == id) { + printf("Table #%u is already assigned," + " delete it first\n", id); + free(pt); + return -EINVAL; + } + pt->next = *ppt; + pt->id = id; + *ppt = pt; + *table = pt; + return 0; +} + +/** Get info about flow management resources. */ int -port_action_handle_create(portid_t port_id, uint32_t id, - const struct rte_flow_indir_action_conf *conf, - const struct rte_flow_action *action) +port_flow_get_info(portid_t port_id) { - struct port_indirect_action *pia; - int ret; + struct rte_flow_port_info port_info; + struct rte_flow_queue_info queue_info; struct rte_flow_error error; - struct rte_port *port; if (port_id_is_invalid(port_id, ENABLED_WARN) || port_id == (portid_t)RTE_PORT_ALL) return -EINVAL; + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x99, sizeof(error)); + memset(&port_info, 0, sizeof(port_info)); + memset(&queue_info, 0, sizeof(queue_info)); + if (rte_flow_info_get(port_id, &port_info, &queue_info, &error)) + return port_flow_complain(&error); + printf("Flow engine resources on port %u:\n" + "Number of queues: %d\n" + "Size of queues: %d\n" + "Number of counters: %d\n" + "Number of aging objects: %d\n" + "Number of meter actions: %d\n", + port_id, port_info.max_nb_queues, + queue_info.max_size, + port_info.max_nb_counters, + port_info.max_nb_aging_objects, + port_info.max_nb_meters); + return 0; +} - ret = action_alloc(port_id, id, &pia); - if (ret) - return ret; - - port = &ports[port_id]; - - if (conf->transfer) - port_id = port->flow_transfer_proxy; +/** Configure flow management resources. */ +int +port_flow_configure(portid_t port_id, + const struct rte_flow_port_attr *port_attr, + uint16_t nb_queue, + const struct rte_flow_queue_attr *queue_attr) +{ + struct rte_port *port; + struct rte_flow_error error; + const struct rte_flow_queue_attr *attr_list[nb_queue]; + int std_queue; if (port_id_is_invalid(port_id, ENABLED_WARN) || port_id == (portid_t)RTE_PORT_ALL) return -EINVAL; + port = &ports[port_id]; + port->queue_nb = nb_queue; + port->queue_sz = queue_attr->size; + for (std_queue = 0; std_queue < nb_queue; std_queue++) + attr_list[std_queue] = queue_attr; + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x66, sizeof(error)); + if (rte_flow_configure(port_id, port_attr, nb_queue, attr_list, &error)) + return port_flow_complain(&error); + printf("Configure flows on port %u: " + "number of queues %d with %d elements\n", + port_id, nb_queue, queue_attr->size); + return 0; +} + +/** Create indirect action */ +int +port_action_handle_create(portid_t port_id, uint32_t id, + const struct rte_flow_indir_action_conf *conf, + const struct rte_flow_action *action) +{ + struct port_indirect_action *pia; + int ret; + struct rte_flow_error error; + ret = action_alloc(port_id, id, &pia); + if (ret) + return ret; if (action->type == RTE_FLOW_ACTION_TYPE_AGE) { struct rte_flow_action_age *age = (struct rte_flow_action_age *)(uintptr_t)(action->conf); @@ -1629,7 +1853,6 @@ port_action_handle_create(portid_t port_id, uint32_t id, return port_flow_complain(&error); } pia->type = action->type; - pia->transfer = conf->transfer; printf("Indirect action #%u created\n", pia->id); return 0; } @@ -1656,18 +1879,9 @@ port_action_handle_destroy(portid_t port_id, for (i = 0; i != n; ++i) { struct rte_flow_error error; struct port_indirect_action *pia = *tmp; - portid_t port_id_eff = port_id; if (actions[i] != pia->id) continue; - - if (pia->transfer) - port_id_eff = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id_eff, ENABLED_WARN) || - port_id_eff == (portid_t)RTE_PORT_ALL) - return -EINVAL; - /* * Poisoning to make sure PMDs update it in case * of error. @@ -1675,7 +1889,7 @@ port_action_handle_destroy(portid_t port_id, memset(&error, 0x33, sizeof(error)); if (pia->handle && rte_flow_action_handle_destroy( - port_id_eff, pia->handle, &error)) { + port_id, pia->handle, &error)) { ret = port_flow_complain(&error); continue; } @@ -1710,15 +1924,8 @@ port_action_handle_update(portid_t port_id, uint32_t id, struct rte_flow_error error; struct rte_flow_action_handle *action_handle; struct port_indirect_action *pia; - struct rte_port *port; const void *update; - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - - port = &ports[port_id]; - action_handle = port_action_handle_get_by_id(port_id, id); if (!action_handle) return -EINVAL; @@ -1733,14 +1940,6 @@ port_action_handle_update(portid_t port_id, uint32_t id, update = action; break; } - - if (pia->transfer) - port_id = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - if (rte_flow_action_handle_update(port_id, action_handle, update, &error)) { return port_flow_complain(&error); @@ -1759,14 +1958,6 @@ port_action_handle_query(portid_t port_id, uint32_t id) struct rte_flow_query_age age; struct rte_flow_action_conntrack ct; } query; - portid_t port_id_eff = port_id; - struct rte_port *port; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - - port = &ports[port_id]; pia = action_get_by_id(port_id, id); if (!pia) @@ -1781,19 +1972,10 @@ port_action_handle_query(portid_t port_id, uint32_t id) id, pia->type, port_id); return -ENOTSUP; } - - if (pia->transfer) - port_id_eff = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id_eff, ENABLED_WARN) || - port_id_eff == (portid_t)RTE_PORT_ALL) - return -EINVAL; - /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x55, sizeof(error)); memset(&query, 0, sizeof(query)); - if (rte_flow_action_handle_query(port_id_eff, pia->handle, &query, - &error)) + if (rte_flow_action_handle_query(port_id, pia->handle, &query, &error)) return port_flow_complain(&error); switch (pia->type) { case RTE_FLOW_ACTION_TYPE_AGE: @@ -2012,20 +2194,7 @@ port_flow_validate(portid_t port_id, { struct rte_flow_error error; struct port_flow_tunnel *pft = NULL; - struct rte_port *port; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - - port = &ports[port_id]; - - if (attr->transfer) - port_id = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; + int ret; /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x11, sizeof(error)); @@ -2039,10 +2208,11 @@ port_flow_validate(portid_t port_id, if (pft->actions) actions = pft->actions; } - if (rte_flow_validate(port_id, attr, pattern, actions, &error)) - return port_flow_complain(&error); + ret = rte_flow_validate(port_id, attr, pattern, actions, &error); if (tunnel_ops->enabled) port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); + if (ret) + return port_flow_complain(&error); printf("Flow rule validated\n"); return 0; } @@ -2063,86 +2233,44 @@ age_action_get(const struct rte_flow_action *actions) return NULL; } -/** Create flow rule. */ +/** Create pattern template */ int -port_flow_create(portid_t port_id, - const struct rte_flow_attr *attr, - const struct rte_flow_item *pattern, - const struct rte_flow_action *actions, - const struct tunnel_ops *tunnel_ops) +port_flow_pattern_template_create(portid_t port_id, uint32_t id, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item *pattern) { - struct rte_flow *flow; struct rte_port *port; - struct port_flow *pf; - uint32_t id = 0; + struct port_template *pit; + int ret; struct rte_flow_error error; - struct port_flow_tunnel *pft = NULL; - struct rte_flow_action_age *age = age_action_get(actions); if (port_id_is_invalid(port_id, ENABLED_WARN) || port_id == (portid_t)RTE_PORT_ALL) return -EINVAL; - port = &ports[port_id]; - - if (attr->transfer) - port_id = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - - if (port->flow_list) { - if (port->flow_list->id == UINT32_MAX) { - fprintf(stderr, - "Highest rule ID is already assigned, delete it first"); - return -ENOMEM; - } - id = port->flow_list->id + 1; - } - if (tunnel_ops->enabled) { - pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, - actions, tunnel_ops); - if (!pft) - return -ENOENT; - if (pft->items) - pattern = pft->items; - if (pft->actions) - actions = pft->actions; - } - pf = port_flow_new(attr, pattern, actions, &error); - if (!pf) - return port_flow_complain(&error); - if (age) { - pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW; - age->context = &pf->age_type; - } + ret = template_alloc(id, &pit, &port->pattern_templ_list); + if (ret) + return ret; /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x22, sizeof(error)); - flow = rte_flow_create(port_id, attr, pattern, actions, &error); - if (!flow) { - if (tunnel_ops->enabled) - port_flow_tunnel_offload_cmd_release(port_id, - tunnel_ops, pft); - free(pf); + pit->template.pattern_template = rte_flow_pattern_template_create(port_id, + attr, pattern, &error); + if (!pit->template.pattern_template) { + uint32_t destroy_id = pit->id; + port_flow_pattern_template_destroy(port_id, 1, &destroy_id); return port_flow_complain(&error); } - pf->next = port->flow_list; - pf->id = id; - pf->flow = flow; - port->flow_list = pf; - if (tunnel_ops->enabled) - port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); - printf("Flow rule #%u created\n", pf->id); + printf("Pattern template #%u created\n", pit->id); return 0; } -/** Destroy a number of flow rules. */ +/** Destroy pattern template */ int -port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) +port_flow_pattern_template_destroy(portid_t port_id, uint32_t n, + const uint32_t *template) { struct rte_port *port; - struct port_flow **tmp; + struct port_template **tmp; uint32_t c = 0; int ret = 0; @@ -2150,16 +2278,15 @@ port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) port_id == (portid_t)RTE_PORT_ALL) return -EINVAL; port = &ports[port_id]; - tmp = &port->flow_list; + tmp = &port->pattern_templ_list; while (*tmp) { uint32_t i; for (i = 0; i != n; ++i) { - portid_t port_id_eff = port_id; struct rte_flow_error error; - struct port_flow *pf = *tmp; + struct port_template *pit = *tmp; - if (rule[i] != pf->id) + if (template[i] != pit->id) continue; /* * Poisoning to make sure PMDs update it in case @@ -2167,20 +2294,16 @@ port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) */ memset(&error, 0x33, sizeof(error)); - if (pf->rule.attr->transfer) - port_id_eff = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id_eff, ENABLED_WARN) || - port_id_eff == (portid_t)RTE_PORT_ALL) - return -EINVAL; - - if (rte_flow_destroy(port_id_eff, pf->flow, &error)) { + if (pit->template.pattern_template && + rte_flow_pattern_template_destroy(port_id, + pit->template.pattern_template, + &error)) { ret = port_flow_complain(&error); continue; } - printf("Flow rule #%u destroyed\n", pf->id); - *tmp = pf->next; - free(pf); + *tmp = pit->next; + printf("Pattern template #%u destroyed\n", pit->id); + free(pit); break; } if (i == n) @@ -2190,26 +2313,683 @@ port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) return ret; } -/** Remove all flow rules. */ +/** Create actions template */ int -port_flow_flush(portid_t port_id) +port_flow_actions_template_create(portid_t port_id, uint32_t id, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action *actions, + const struct rte_flow_action *masks) { - struct rte_flow_error error; struct rte_port *port; - int ret = 0; + struct port_template *pat; + int ret; + struct rte_flow_error error; if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) + port_id == (portid_t)RTE_PORT_ALL) return -EINVAL; - port = &ports[port_id]; - - if (port->flow_list == NULL) + ret = template_alloc(id, &pat, &port->actions_templ_list); + if (ret) return ret; - /* Poisoning to make sure PMDs update it in case of error. */ - memset(&error, 0x44, sizeof(error)); - if (rte_flow_flush(port_id, &error)) { + memset(&error, 0x22, sizeof(error)); + pat->template.actions_template = rte_flow_actions_template_create(port_id, + attr, actions, masks, &error); + if (!pat->template.actions_template) { + uint32_t destroy_id = pat->id; + port_flow_actions_template_destroy(port_id, 1, &destroy_id); + return port_flow_complain(&error); + } + printf("Actions template #%u created\n", pat->id); + return 0; +} + +/** Destroy actions template */ +int +port_flow_actions_template_destroy(portid_t port_id, uint32_t n, + const uint32_t *template) +{ + struct rte_port *port; + struct port_template **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + tmp = &port->actions_templ_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_template *pat = *tmp; + + if (template[i] != pat->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x33, sizeof(error)); + + if (pat->template.actions_template && + rte_flow_actions_template_destroy(port_id, + pat->template.actions_template, &error)) { + ret = port_flow_complain(&error); + continue; + } + *tmp = pat->next; + printf("Actions template #%u destroyed\n", pat->id); + free(pat); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Create table */ +int +port_flow_template_table_create(portid_t port_id, uint32_t id, + const struct rte_flow_template_table_attr *table_attr, + uint32_t nb_pattern_templates, uint32_t *pattern_templates, + uint32_t nb_actions_templates, uint32_t *actions_templates) +{ + struct rte_port *port; + struct port_table *pt; + struct port_template *temp = NULL; + int ret; + uint32_t i; + struct rte_flow_error error; + struct rte_flow_pattern_template + *flow_pattern_templates[nb_pattern_templates]; + struct rte_flow_actions_template + *flow_actions_templates[nb_actions_templates]; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + for (i = 0; i < nb_pattern_templates; ++i) { + bool found = false; + temp = port->pattern_templ_list; + while (temp) { + if (pattern_templates[i] == temp->id) { + flow_pattern_templates[i] = + temp->template.pattern_template; + found = true; + break; + } + temp = temp->next; + } + if (!found) { + printf("Pattern template #%u is invalid\n", + pattern_templates[i]); + return -EINVAL; + } + } + for (i = 0; i < nb_actions_templates; ++i) { + bool found = false; + temp = port->actions_templ_list; + while (temp) { + if (actions_templates[i] == temp->id) { + flow_actions_templates[i] = + temp->template.actions_template; + found = true; + break; + } + temp = temp->next; + } + if (!found) { + printf("Actions template #%u is invalid\n", + actions_templates[i]); + return -EINVAL; + } + } + ret = table_alloc(id, &pt, &port->table_list); + if (ret) + return ret; + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x22, sizeof(error)); + pt->table = rte_flow_template_table_create(port_id, table_attr, + flow_pattern_templates, nb_pattern_templates, + flow_actions_templates, nb_actions_templates, + &error); + + if (!pt->table) { + uint32_t destroy_id = pt->id; + port_flow_template_table_destroy(port_id, 1, &destroy_id); + return port_flow_complain(&error); + } + pt->nb_pattern_templates = nb_pattern_templates; + pt->nb_actions_templates = nb_actions_templates; + printf("Template table #%u created\n", pt->id); + return 0; +} + +/** Destroy table */ +int +port_flow_template_table_destroy(portid_t port_id, + uint32_t n, const uint32_t *table) +{ + struct rte_port *port; + struct port_table **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + tmp = &port->table_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_table *pt = *tmp; + + if (table[i] != pt->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x33, sizeof(error)); + + if (pt->table && + rte_flow_template_table_destroy(port_id, + pt->table, + &error)) { + ret = port_flow_complain(&error); + continue; + } + *tmp = pt->next; + printf("Template table #%u destroyed\n", pt->id); + free(pt); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Enqueue create flow rule operation. */ +int +port_queue_flow_create(portid_t port_id, queueid_t queue_id, + bool postpone, uint32_t table_id, + uint32_t pattern_idx, uint32_t actions_idx, + const struct rte_flow_item *pattern, + const struct rte_flow_action *actions) +{ + struct rte_flow_op_attr op_attr = { .postpone = postpone }; + struct rte_flow *flow; + struct rte_port *port; + struct port_flow *pf; + struct port_table *pt; + uint32_t id = 0; + bool found; + struct rte_flow_error error = { RTE_FLOW_ERROR_TYPE_NONE, NULL, NULL }; + struct rte_flow_action_age *age = age_action_get(actions); + + port = &ports[port_id]; + if (port->flow_list) { + if (port->flow_list->id == UINT32_MAX) { + printf("Highest rule ID is already assigned," + " delete it first"); + return -ENOMEM; + } + id = port->flow_list->id + 1; + } + + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + found = false; + pt = port->table_list; + while (pt) { + if (table_id == pt->id) { + found = true; + break; + } + pt = pt->next; + } + if (!found) { + printf("Table #%u is invalid\n", table_id); + return -EINVAL; + } + + if (pattern_idx >= pt->nb_pattern_templates) { + printf("Pattern template index #%u is invalid," + " %u templates present in the table\n", + pattern_idx, pt->nb_pattern_templates); + return -EINVAL; + } + if (actions_idx >= pt->nb_actions_templates) { + printf("Actions template index #%u is invalid," + " %u templates present in the table\n", + actions_idx, pt->nb_actions_templates); + return -EINVAL; + } + + pf = port_flow_new(NULL, pattern, actions, &error); + if (!pf) + return port_flow_complain(&error); + if (age) { + pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW; + age->context = &pf->age_type; + } + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x11, sizeof(error)); + flow = rte_flow_async_create(port_id, queue_id, &op_attr, pt->table, + pattern, pattern_idx, actions, actions_idx, NULL, &error); + if (!flow) { + uint32_t flow_id = pf->id; + port_queue_flow_destroy(port_id, queue_id, true, 1, &flow_id); + return port_flow_complain(&error); + } + + pf->next = port->flow_list; + pf->id = id; + pf->flow = flow; + port->flow_list = pf; + printf("Flow rule #%u creation enqueued\n", pf->id); + return 0; +} + +/** Enqueue number of destroy flow rules operations. */ +int +port_queue_flow_destroy(portid_t port_id, queueid_t queue_id, + bool postpone, uint32_t n, const uint32_t *rule) +{ + struct rte_flow_op_attr op_attr = { .postpone = postpone }; + struct rte_port *port; + struct port_flow **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + tmp = &port->flow_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_flow *pf = *tmp; + + if (rule[i] != pf->id) + continue; + /* + * Poisoning to make sure PMD + * update it in case of error. + */ + memset(&error, 0x33, sizeof(error)); + if (rte_flow_async_destroy(port_id, queue_id, &op_attr, + pf->flow, NULL, &error)) { + ret = port_flow_complain(&error); + continue; + } + printf("Flow rule #%u destruction enqueued\n", pf->id); + *tmp = pf->next; + free(pf); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Enqueue indirect action create operation. */ +int +port_queue_action_handle_create(portid_t port_id, uint32_t queue_id, + bool postpone, uint32_t id, + const struct rte_flow_indir_action_conf *conf, + const struct rte_flow_action *action) +{ + const struct rte_flow_op_attr attr = { .postpone = postpone}; + struct rte_port *port; + struct port_indirect_action *pia; + int ret; + struct rte_flow_error error; + + ret = action_alloc(port_id, id, &pia); + if (ret) + return ret; + + port = &ports[port_id]; + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + if (action->type == RTE_FLOW_ACTION_TYPE_AGE) { + struct rte_flow_action_age *age = + (struct rte_flow_action_age *)(uintptr_t)(action->conf); + + pia->age_type = ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION; + age->context = &pia->age_type; + } + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x88, sizeof(error)); + pia->handle = rte_flow_async_action_handle_create(port_id, queue_id, + &attr, conf, action, NULL, &error); + if (!pia->handle) { + uint32_t destroy_id = pia->id; + port_queue_action_handle_destroy(port_id, queue_id, + postpone, 1, &destroy_id); + return port_flow_complain(&error); + } + pia->type = action->type; + printf("Indirect action #%u creation queued\n", pia->id); + return 0; +} + +/** Enqueue indirect action destroy operation. */ +int +port_queue_action_handle_destroy(portid_t port_id, + uint32_t queue_id, bool postpone, + uint32_t n, const uint32_t *actions) +{ + const struct rte_flow_op_attr attr = { .postpone = postpone}; + struct rte_port *port; + struct port_indirect_action **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + tmp = &port->actions_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_indirect_action *pia = *tmp; + + if (actions[i] != pia->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x99, sizeof(error)); + + if (pia->handle && + rte_flow_async_action_handle_destroy(port_id, + queue_id, &attr, pia->handle, NULL, &error)) { + ret = port_flow_complain(&error); + continue; + } + *tmp = pia->next; + printf("Indirect action #%u destruction queued\n", + pia->id); + free(pia); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Enqueue indirect action update operation. */ +int +port_queue_action_handle_update(portid_t port_id, + uint32_t queue_id, bool postpone, uint32_t id, + const struct rte_flow_action *action) +{ + const struct rte_flow_op_attr attr = { .postpone = postpone}; + struct rte_port *port; + struct rte_flow_error error; + struct rte_flow_action_handle *action_handle; + + action_handle = port_action_handle_get_by_id(port_id, id); + if (!action_handle) + return -EINVAL; + + port = &ports[port_id]; + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + if (rte_flow_async_action_handle_update(port_id, queue_id, &attr, + action_handle, action, NULL, &error)) { + return port_flow_complain(&error); + } + printf("Indirect action #%u update queued\n", id); + return 0; +} + +/** Push all the queue operations in the queue to the NIC. */ +int +port_queue_flow_push(portid_t port_id, queueid_t queue_id) +{ + struct rte_port *port; + struct rte_flow_error error; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + memset(&error, 0x55, sizeof(error)); + ret = rte_flow_push(port_id, queue_id, &error); + if (ret < 0) { + printf("Failed to push operations in the queue\n"); + return -EINVAL; + } + printf("Queue #%u operations pushed\n", queue_id); + return ret; +} + +/** Pull queue operation results from the queue. */ +int +port_queue_flow_pull(portid_t port_id, queueid_t queue_id) +{ + struct rte_port *port; + struct rte_flow_op_result *res; + struct rte_flow_error error; + int ret = 0; + int success = 0; + int i; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + + if (queue_id >= port->queue_nb) { + printf("Queue #%u is invalid\n", queue_id); + return -EINVAL; + } + + res = calloc(port->queue_sz, sizeof(struct rte_flow_op_result)); + if (!res) { + printf("Failed to allocate memory for pulled results\n"); + return -ENOMEM; + } + + memset(&error, 0x66, sizeof(error)); + ret = rte_flow_pull(port_id, queue_id, res, + port->queue_sz, &error); + if (ret < 0) { + printf("Failed to pull a operation results\n"); + free(res); + return -EINVAL; + } + + for (i = 0; i < ret; i++) { + if (res[i].status == RTE_FLOW_OP_SUCCESS) + success++; + } + printf("Queue #%u pulled %u operations (%u failed, %u succeeded)\n", + queue_id, ret, ret - success, success); + free(res); + return ret; +} + +/** Create flow rule. */ +int +port_flow_create(portid_t port_id, + const struct rte_flow_attr *attr, + const struct rte_flow_item *pattern, + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) +{ + struct rte_flow *flow; + struct rte_port *port; + struct port_flow *pf; + uint32_t id = 0; + struct rte_flow_error error; + struct port_flow_tunnel *pft = NULL; + struct rte_flow_action_age *age = age_action_get(actions); + + port = &ports[port_id]; + if (port->flow_list) { + if (port->flow_list->id == UINT32_MAX) { + fprintf(stderr, + "Highest rule ID is already assigned, delete it first"); + return -ENOMEM; + } + id = port->flow_list->id + 1; + } + if (tunnel_ops->enabled) { + pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, + actions, tunnel_ops); + if (!pft) + return -ENOENT; + if (pft->items) + pattern = pft->items; + if (pft->actions) + actions = pft->actions; + } + pf = port_flow_new(attr, pattern, actions, &error); + if (!pf) + return port_flow_complain(&error); + if (age) { + pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW; + age->context = &pf->age_type; + } + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x22, sizeof(error)); + flow = rte_flow_create(port_id, attr, pattern, actions, &error); + if (!flow) { + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, + tunnel_ops, pft); + free(pf); + return port_flow_complain(&error); + } + pf->next = port->flow_list; + pf->id = id; + pf->flow = flow; + port->flow_list = pf; + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); + printf("Flow rule #%u created\n", pf->id); + return 0; +} + +/** Destroy a number of flow rules. */ +int +port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) +{ + struct rte_port *port; + struct port_flow **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + tmp = &port->flow_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_flow *pf = *tmp; + + if (rule[i] != pf->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x33, sizeof(error)); + if (rte_flow_destroy(port_id, pf->flow, &error)) { + ret = port_flow_complain(&error); + continue; + } + printf("Flow rule #%u destroyed\n", pf->id); + *tmp = pf->next; + free(pf); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Remove all flow rules. */ +int +port_flow_flush(portid_t port_id) +{ + struct rte_flow_error error; + struct rte_port *port; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + + port = &ports[port_id]; + + if (port->flow_list == NULL) + return ret; + + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x44, sizeof(error)); + if (rte_flow_flush(port_id, &error)) { port_flow_complain(&error); } @@ -2308,14 +3088,6 @@ port_flow_query(portid_t port_id, uint32_t rule, fprintf(stderr, "Flow rule #%u not found\n", rule); return -ENOENT; } - - if (pf->rule.attr->transfer) - port_id = port->flow_transfer_proxy; - - if (port_id_is_invalid(port_id, ENABLED_WARN) || - port_id == (portid_t)RTE_PORT_ALL) - return -EINVAL; - ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, &name, sizeof(name), (void *)(uintptr_t)action->type, &error); @@ -2965,7 +3737,7 @@ port_rss_reta_info(portid_t port_id, } /* - * Displays the RSS hash functions of a port, and, optionaly, the RSS hash + * Displays the RSS hash functions of a port, and, optionally, the RSS hash * key of the port. */ void @@ -3021,7 +3793,9 @@ port_rss_hash_conf_show(portid_t port_id, int show_rss_key) } printf("RSS functions:\n "); for (i = 0; rss_type_table[i].str; i++) { - if (rss_hf & rss_type_table[i].rss_type) + if (rss_type_table[i].rss_type == 0) + continue; + if ((rss_hf & rss_type_table[i].rss_type) == rss_type_table[i].rss_type) printf("%s ", rss_type_table[i].str); } printf("\n"); @@ -4190,6 +4964,7 @@ set_tx_pkt_times(unsigned int *tx_times) tx_pkt_times_intra = tx_times[1]; } +#ifdef RTE_LIB_GRO void setup_gro(const char *onoff, portid_t port_id) { @@ -4271,7 +5046,9 @@ show_gro(portid_t port_id) } else printf("Port %u doesn't enable GRO.\n", port_id); } +#endif /* RTE_LIB_GRO */ +#ifdef RTE_LIB_GSO void setup_gso(const char *mode, portid_t port_id) { @@ -4295,6 +5072,7 @@ setup_gso(const char *mode, portid_t port_id) gso_ports[port_id].enable = 0; } } +#endif /* RTE_LIB_GSO */ char* list_pkt_forwarding_modes(void) @@ -4819,11 +5597,15 @@ flowtype_to_str(uint16_t flow_type) {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP}, {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER}, {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD}, + {"ipv6-ex", RTE_ETH_FLOW_IPV6_EX}, + {"ipv6-tcp-ex", RTE_ETH_FLOW_IPV6_TCP_EX}, + {"ipv6-udp-ex", RTE_ETH_FLOW_IPV6_UDP_EX}, {"port", RTE_ETH_FLOW_PORT}, {"vxlan", RTE_ETH_FLOW_VXLAN}, {"geneve", RTE_ETH_FLOW_GENEVE}, {"nvgre", RTE_ETH_FLOW_NVGRE}, {"vxlan-gpe", RTE_ETH_FLOW_VXLAN_GPE}, + {"gtpu", RTE_ETH_FLOW_GTPU}, }; for (i = 0; i < RTE_DIM(flowtype_str_table); i++) { @@ -5244,7 +6026,7 @@ mcast_addr_pool_remove(struct rte_port *port, uint32_t addr_idx) { port->mc_addr_nb--; if (addr_idx == port->mc_addr_nb) { - /* No need to recompact the set of multicast addressses. */ + /* No need to recompact the set of multicast addresses. */ if (port->mc_addr_nb == 0) { /* free the pool of multicast addresses. */ free(port->mc_addr_pool);