net/fm10k: add flow interface and switch management

Add flow interface to support offload flow into HW.
It supports parse vlan and parse mpls, all these
data will be transferred to ffu data.
Add switch management, includes initialization,
port mapping, epl port link, LED controller, interrupt handler.
It create 3 threads. One for interrupt handler, one for
LED controller, one for statistics.

Signed-off-by: Xiaojun Liu <xiaojun.liu@silicom.co.il>
This commit is contained in:
Xiaojun Liu 2020-04-09 14:26:27 +08:00 committed by WeebDataHoarder
parent 5550889d65
commit 19cd3be04e
6 changed files with 3384 additions and 0 deletions

View file

@ -87,6 +87,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_spico_code.c
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_config.c
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ffu.c
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_stats.c
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_switch.c
endif
ifeq ($(CONFIG_RTE_ARCH_X86), y)
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR) += fm10k_rxtx_vec.c

View file

@ -717,6 +717,7 @@ struct fm10k_hw {
u16 subsystem_vendor_id;
u8 revision_id;
u32 flags;
bool switch_ready;
#define FM10K_HW_FLAG_CLOCK_OWNER BIT(0)
};

View file

@ -0,0 +1,864 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2019 Silicom Ltd. Connectivity Solutions
*/
#include <sys/queue.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_eth_ctrl.h>
#include <rte_tailq.h>
#include <rte_flow_driver.h>
#include "fm10k_flow.h"
#include "fm10k_switch.h"
#include "fm10k_ffu.h"
#include "fm10k_config.h"
static int fm10k_flow_validate(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error);
static struct rte_flow *fm10k_flow_create(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error);
static int fm10k_flow_destroy(struct rte_eth_dev *dev,
struct rte_flow *flow,
struct rte_flow_error *error);
static int fm10k_flow_flush(struct rte_eth_dev *dev,
struct rte_flow_error *error);
static int fm10k_flow_parse_attr(const struct rte_flow_attr *attr,
struct rte_flow_error *error);
const struct rte_flow_ops fm10k_flow_ops = {
.validate = fm10k_flow_validate,
.create = fm10k_flow_create,
.destroy = fm10k_flow_destroy,
.flush = fm10k_flow_flush,
};
union fm10k_filter_t cons_filter;
enum rte_filter_type fm10k_cons_filter_type = RTE_ETH_FILTER_NONE;
/**
* MPLS filter configuration.
*/
enum fm10k_mpls_type {
FM10K_MPLS_TYPE_UNI,
FM10K_MPLS_TYPE_MULTI,
};
enum fm10k_mpls_action {
FM10K_MPLS_ACTION_DROP,
FM10K_MPLS_ACTION_QUEUE,
};
struct fm10k_mpls_filter_conf {
enum fm10k_mpls_type mpls_type; /**< mandatory for MPLS */
uint32_t mpls_header; /**< MPLS header */
uint32_t mpls_header_mask; /**< MPLS header mask */
enum fm10k_mpls_action mpls_action;
uint16_t queue;
uint8_t ffu_id;
uint8_t ffu_prio;
};
/**
* VLAN filter configuration.
*/
struct fm10k_vlan_filter_conf {
int ffu_id;
uint8_t ffu_prio;
uint8_t is_ingress;
uint8_t port;
uint8_t in_ext_port;
uint8_t out_ext_port;
uint16_t in_vlan;
uint16_t out_vlan;
};
union fm10k_filter_t {
struct fm10k_mpls_filter_conf mpls_filter;
struct fm10k_vlan_filter_conf vlan_filter;
};
typedef int (*parse_filter_t)(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error,
union fm10k_filter_t *filter);
struct fm10k_valid_pattern {
enum rte_flow_item_type *items;
parse_filter_t parse_filter;
};
static enum rte_flow_item_type pattern_mpls_1[] = {
RTE_FLOW_ITEM_TYPE_ETH,
RTE_FLOW_ITEM_TYPE_MPLS,
RTE_FLOW_ITEM_TYPE_END,
};
static enum rte_flow_item_type pattern_vlan_1[] = {
RTE_FLOW_ITEM_TYPE_VLAN,
RTE_FLOW_ITEM_TYPE_PHY_PORT,
RTE_FLOW_ITEM_TYPE_END,
};
static enum rte_flow_item_type pattern_vlan_2[] = {
RTE_FLOW_ITEM_TYPE_VLAN,
RTE_FLOW_ITEM_TYPE_PHY_PORT,
RTE_FLOW_ITEM_TYPE_PHY_PORT,
RTE_FLOW_ITEM_TYPE_END,
};
static int fm10k_flow_parse_mpls_filter(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error,
union fm10k_filter_t *filter);
static int
fm10k_flow_parse_vlan_filter(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error,
union fm10k_filter_t *filter);
static struct fm10k_valid_pattern fm10k_supported_patterns[] = {
/* MPLS */
{ pattern_mpls_1, fm10k_flow_parse_mpls_filter },
/* VLAN */
{ pattern_vlan_1, fm10k_flow_parse_vlan_filter },
/* VLAN */
{ pattern_vlan_2, fm10k_flow_parse_vlan_filter },
};
static const struct rte_flow_action *
fm10k_next_item_of_action(const struct rte_flow_action *actions,
uint32_t *index)
{
static const struct rte_flow_action *act;
act = actions + *index;
while (act->type == RTE_FLOW_ACTION_TYPE_VOID) {
(*index)++;
act = actions + *index;
}
return act;
}
/* Find the first VOID or non-VOID item pointer */
static const struct rte_flow_item *
fm10k_find_first_item(const struct rte_flow_item *item, bool is_void)
{
bool is_find;
while (item->type != RTE_FLOW_ITEM_TYPE_END) {
if (is_void)
is_find = item->type == RTE_FLOW_ITEM_TYPE_VOID;
else
is_find = item->type != RTE_FLOW_ITEM_TYPE_VOID;
if (is_find)
break;
item++;
}
return item;
}
/* Skip all VOID items of the pattern */
static void
fm10k_pattern_skip_void_item(struct rte_flow_item *items,
const struct rte_flow_item *pattern)
{
uint32_t cpy_count = 0;
const struct rte_flow_item *pb = pattern, *pe = pattern;
for (;;) {
/* Find a non-void item first */
pb = fm10k_find_first_item(pb, false);
if (pb->type == RTE_FLOW_ITEM_TYPE_END) {
pe = pb;
break;
}
/* Find a void item */
pe = fm10k_find_first_item(pb + 1, true);
cpy_count = pe - pb;
rte_memcpy(items, pb, sizeof(struct rte_flow_item) * cpy_count);
items += cpy_count;
if (pe->type == RTE_FLOW_ITEM_TYPE_END) {
pb = pe;
break;
}
pb = pe + 1;
}
/* Copy the END item. */
rte_memcpy(items, pe, sizeof(struct rte_flow_item));
}
/* Check if the pattern matches a supported item type array */
static bool
fm10k_match_pattern(enum rte_flow_item_type *item_array,
struct rte_flow_item *pattern)
{
struct rte_flow_item *item = pattern;
while ((*item_array == item->type) &&
(*item_array != RTE_FLOW_ITEM_TYPE_END)) {
item_array++;
item++;
}
return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
item->type == RTE_FLOW_ITEM_TYPE_END);
}
/* Find if there's parse filter function matched */
static parse_filter_t
fm10k_find_parse_filter_func(struct rte_flow_item *pattern, uint32_t *idx)
{
parse_filter_t parse_filter = NULL;
uint8_t i = *idx;
for (; i < RTE_DIM(fm10k_supported_patterns); i++) {
if (fm10k_match_pattern(fm10k_supported_patterns[i].items,
pattern)) {
parse_filter = fm10k_supported_patterns[i].parse_filter;
break;
}
}
*idx = ++i;
return parse_filter;
}
/* Parse attributes */
static int
fm10k_flow_parse_attr(const struct rte_flow_attr *attr,
struct rte_flow_error *error)
{
/* Not supported */
if (attr->group) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
attr, "Not support group.");
return -rte_errno;
}
return 0;
}
/*
* MPLS
*/
/* 1. Last in item should be NULL as range is not supported.
* 2. Supported filter types: MPLS label.
* 3. Mask of fields which need to be matched should be
* filled with 1.
* 4. Mask of fields which needn't to be matched should be
* filled with 0.
*/
static int
fm10k_flow_parse_mpls_pattern(__rte_unused struct rte_eth_dev *dev,
const struct rte_flow_item *pattern,
struct rte_flow_error *error,
struct fm10k_mpls_filter_conf *filter)
{
const struct rte_flow_item *item = pattern;
const struct rte_flow_item_mpls *mpls_spec;
const struct rte_flow_item_mpls *mpls_mask;
const struct rte_flow_item_eth *eth_spec;
enum rte_flow_item_type item_type;
const uint8_t label_mask[3] = {0xFF, 0xFF, 0xF0};
uint32_t label_be = 0;
uint32_t be_mask = 0;
for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
if (item->last) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Not support range");
return -rte_errno;
}
item_type = item->type;
switch (item_type) {
case RTE_FLOW_ITEM_TYPE_ETH:
if (!item->spec || item->mask) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Invalid ETH item");
return -rte_errno;
}
eth_spec =
(const struct rte_flow_item_eth *)item->spec;
if (rte_be_to_cpu_16(eth_spec->type) == 0x8847) {
filter->mpls_type = FM10K_MPLS_TYPE_UNI;
} else if (rte_be_to_cpu_16(eth_spec->type) == 0x8848) {
filter->mpls_type = FM10K_MPLS_TYPE_MULTI;
} else {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item, "Invalid ETH item");
return -rte_errno;
}
break;
case RTE_FLOW_ITEM_TYPE_MPLS:
mpls_spec =
(const struct rte_flow_item_mpls *)item->spec;
mpls_mask =
(const struct rte_flow_item_mpls *)item->mask;
if (!mpls_spec || !mpls_mask) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Invalid MPLS item");
return -rte_errno;
}
if (memcmp(mpls_mask->label_tc_s, label_mask, 3)) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Invalid MPLS label mask");
return -rte_errno;
}
rte_memcpy(((uint8_t *)&label_be + 1),
mpls_spec->label_tc_s, 3);
rte_memcpy(((uint8_t *)&be_mask + 1),
mpls_mask->label_tc_s, 3);
filter->mpls_header =
rte_be_to_cpu_32(label_be) >> 4;
filter->mpls_header_mask =
rte_be_to_cpu_32(be_mask) >> 4;
fm10k_cons_filter_type = RTE_ETH_FILTER_TUNNEL;
break;
default:
break;
}
}
return 0;
}
/* MPLS action only supports QUEUE or DROP. */
static int
fm10k_flow_parse_mpls_action(const struct rte_flow_action *actions,
struct rte_flow_error *error,
struct fm10k_mpls_filter_conf *filter)
{
const struct rte_flow_action *act;
const struct rte_flow_action_queue *act_q;
uint32_t index = 0;
/* Check if the first non-void action is QUEUE or DROP. */
act = fm10k_next_item_of_action(actions, &index);
if (act->type != RTE_FLOW_ACTION_TYPE_QUEUE &&
act->type != RTE_FLOW_ACTION_TYPE_DROP) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
act, "Not supported action.");
return -rte_errno;
}
if (act->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
act_q = (const struct rte_flow_action_queue *)act->conf;
filter->mpls_action = FM10K_MPLS_ACTION_QUEUE;
filter->queue = act_q->index;
} else {
filter->mpls_action = FM10K_MPLS_ACTION_DROP;
}
/* Check if the next non-void item is END */
index++;
act = fm10k_next_item_of_action(actions, &index);
if (act->type != RTE_FLOW_ACTION_TYPE_END) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
act, "Not supported action.");
return -rte_errno;
}
return 0;
}
static int
fm10k_flow_parse_mpls_filter(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error,
union fm10k_filter_t *filter)
{
struct fm10k_mpls_filter_conf *mpls_filter =
&filter->mpls_filter;
int ret;
ret = fm10k_flow_parse_mpls_pattern(dev, pattern,
error, mpls_filter);
if (ret)
return ret;
ret = fm10k_flow_parse_mpls_action(actions, error, mpls_filter);
if (ret)
return ret;
ret = fm10k_flow_parse_attr(attr, error);
return ret;
}
/*
* VLAN
*/
static int
fm10k_flow_parse_vlan_pattern(__rte_unused struct rte_eth_dev *dev,
const struct rte_flow_item *pattern,
struct rte_flow_error *error,
struct fm10k_vlan_filter_conf *filter)
{
const struct rte_flow_item *item = pattern;
const struct rte_flow_item_vlan *vlan_spec;
const struct rte_flow_item_phy_port *pp_spec;
enum rte_flow_item_type item_type;
PMD_INIT_LOG(DEBUG, "Parse vlan pattern ffu id %d", filter->ffu_id);
for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
if (item->last) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Not support range");
return -rte_errno;
}
item_type = item->type;
switch (item_type) {
case RTE_FLOW_ITEM_TYPE_VLAN:
vlan_spec =
(const struct rte_flow_item_vlan *)item->spec;
if (!vlan_spec) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Invalid VLAN item");
return -rte_errno;
}
break;
case RTE_FLOW_ITEM_TYPE_PHY_PORT:
pp_spec =
(const struct rte_flow_item_phy_port *)item->spec;
if (!pp_spec) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
item,
"Invalid PHY PORT item");
return -rte_errno;
}
break;
default:
break;
}
}
return 0;
}
static int
fm10k_flow_parse_vlan_action(struct rte_eth_dev *dev,
const struct rte_flow_action *actions,
struct rte_flow_error *error,
struct fm10k_vlan_filter_conf *filter)
{
const struct rte_flow_action *act;
uint32_t index = 0;
PMD_INIT_LOG(DEBUG, "Parse vlan action name %s ffu id %d",
dev->device->name, filter->ffu_id);
/* Check if the first non-void action is QUEUE or DROP. */
act = fm10k_next_item_of_action(actions, &index);
if (act->type != RTE_FLOW_ACTION_TYPE_MARK) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
act, "Not supported action.");
return -rte_errno;
}
index++;
act = fm10k_next_item_of_action(actions, &index);
if (act->type != RTE_FLOW_ACTION_TYPE_MARK &&
act->type != RTE_FLOW_ACTION_TYPE_END) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
act, "Not supported action.");
return -rte_errno;
}
if (act->type == RTE_FLOW_ACTION_TYPE_END)
return 0;
index++;
/* Check if the next non-void item is END */
act = fm10k_next_item_of_action(actions, &index);
if (act->type != RTE_FLOW_ACTION_TYPE_END) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
act, "Not supported action.");
return -rte_errno;
}
return 0;
}
static int
fm10k_flow_parse_vlan_filter(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error,
union fm10k_filter_t *filter)
{
int ret;
struct fm10k_vlan_filter_conf *vlan_filter =
&filter->vlan_filter;
ret = fm10k_flow_parse_vlan_pattern(dev, pattern,
error, vlan_filter);
if (ret)
return ret;
ret = fm10k_flow_parse_vlan_action(dev, actions, error, vlan_filter);
if (ret)
return ret;
if (attr->ingress)
vlan_filter->is_ingress = 1;
else if (attr->egress)
vlan_filter->is_ingress = 0;
vlan_filter->ffu_prio = attr->priority;
ret = fm10k_flow_parse_attr(attr, error);
return ret;
}
/*
*
*/
static int
fm10k_flow_validate(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error)
{
struct rte_flow_item *items; /* internal pattern w/o VOID items */
parse_filter_t parse_filter;
uint32_t item_num = 0; /* non-void item number of pattern*/
uint32_t i = 0;
bool flag = false;
int ret = -1;
if (!pattern) {
rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
NULL, "NULL pattern.");
return -rte_errno;
}
if (!actions) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION_NUM,
NULL, "NULL action.");
return -rte_errno;
}
if (!attr) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ATTR,
NULL, "NULL attribute.");
return -rte_errno;
}
/* Get the non-void item number of pattern */
while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)
item_num++;
i++;
}
item_num++;
items = rte_zmalloc("fm10k_pattern",
item_num * sizeof(struct rte_flow_item), 0);
if (!items) {
rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
NULL, "No memory for PMD internal items.");
return -ENOMEM;
}
fm10k_pattern_skip_void_item(items, pattern);
i = 0;
do {
parse_filter = fm10k_find_parse_filter_func(items, &i);
if (!parse_filter && !flag) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM,
pattern, "Unsupported pattern");
rte_free(items);
return -rte_errno;
}
if (parse_filter)
ret = parse_filter(dev, attr, items, actions,
error, &cons_filter);
flag = true;
} while ((ret < 0) && (i < RTE_DIM(fm10k_supported_patterns)));
rte_free(items);
return ret;
}
static struct fm10k_cfg_flow *
fm10k_flow_cfg_transfer(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error)
{
int i;
u8 port_id;
int set_port_num = 0, set_vlan_num = 0;
u16 fw_port_id = 0, bp_port_id = 0;
u16 filter_vlan_id = 0, fw_vlan_id = 0, bp_vlan_id = 0;
struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct fm10k_cfg_flow *cf;
cf = rte_zmalloc("fm10k_rule", sizeof(struct fm10k_cfg_flow), 0);
if (!cf) {
rte_flow_error_set(error, ENOMEM,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to allocate memory");
return NULL;
}
memset(cf, 0, sizeof(struct fm10k_cfg_flow));
port_id = fm10k_switch_dpdk_port_no_get(hw);
for (i = 0; i < 4; i++) {
if (pattern[i].type == RTE_FLOW_ITEM_TYPE_VLAN) {
filter_vlan_id =
rte_be_to_cpu_16
(((const struct rte_flow_item_vlan *)
pattern[i].spec)->tci);
} else if (pattern[i].type == RTE_FLOW_ITEM_TYPE_PHY_PORT) {
if (set_port_num)
bp_port_id =
((const struct rte_flow_item_phy_port *)
pattern[i].spec)->index;
else
fw_port_id =
((const struct rte_flow_item_phy_port *)
pattern[i].spec)->index;
set_port_num++;
} else if (pattern[i].type == RTE_FLOW_ITEM_TYPE_END) {
break;
}
}
for (i = 0; i < 3; i++) {
if (actions[i].type == RTE_FLOW_ACTION_TYPE_MARK) {
if (set_vlan_num)
bp_vlan_id =
((const struct rte_flow_action_mark *)
actions[i].conf)->id;
else
fw_vlan_id =
((const struct rte_flow_action_mark *)
actions[i].conf)->id;
set_vlan_num++;
} else if (actions[i].type == RTE_FLOW_ACTION_TYPE_END) {
break;
}
}
if (attr->ingress && !attr->egress) {
/* this port is DPDK port and it is destination port */
cf->src_port.port_type = FM10K_CONFIG_FLOW_EXT_PORT;
cf->src_port.port_no = fw_port_id;
cf->src_port.vlan_id = filter_vlan_id;
cf->fw_port[0].port_type = FM10K_CONFIG_FLOW_DPDK_PORT;
cf->fw_port[0].port_no = port_id;
cf->fw_port[0].vlan_id = fw_vlan_id;
} else if (!attr->ingress && attr->egress) {
/* this port is DPDK port and it is source port */
cf->src_port.port_type = FM10K_CONFIG_FLOW_DPDK_PORT;
cf->src_port.port_no = port_id;
cf->src_port.vlan_id = filter_vlan_id;
cf->fw_port[0].port_type = FM10K_CONFIG_FLOW_EXT_PORT;
cf->fw_port[0].port_no = fw_port_id;
cf->fw_port[0].vlan_id = fw_vlan_id;
} else if (!attr->ingress && !attr->egress) {
/* two ports are external port */
cf->src_port.port_type = FM10K_CONFIG_FLOW_EXT_PORT;
cf->src_port.port_no = port_id;
cf->src_port.vlan_id = filter_vlan_id;
cf->fw_port[0].port_type = FM10K_CONFIG_FLOW_EXT_PORT;
cf->fw_port[0].port_no = fw_port_id;
cf->fw_port[0].vlan_id = fw_vlan_id;
} else {
/* two ports are DPDK port */
cf->src_port.port_type = FM10K_CONFIG_FLOW_DPDK_PORT;
cf->src_port.port_no = port_id;
cf->src_port.vlan_id = filter_vlan_id;
cf->fw_port[0].port_type = FM10K_CONFIG_FLOW_DPDK_PORT;
cf->fw_port[0].port_no = fw_port_id;
cf->fw_port[0].vlan_id = fw_vlan_id;
}
if (set_port_num == 2 && set_vlan_num == 2) {
cf->fw_port[1].port_type = FM10K_CONFIG_FLOW_EXT_PORT;
cf->fw_port[1].port_no = bp_port_id;
cf->fw_port[1].vlan_id = bp_vlan_id;
}
return cf;
}
static struct rte_flow *
fm10k_flow_create(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct rte_flow_error *error)
{
struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct rte_flow *flow;
struct fm10k_switch *sw = fm10k_switch_get();
struct fm10k_cfg_flow *cf;
int ret;
flow = rte_zmalloc("fm10k_flow", sizeof(struct rte_flow), 0);
if (!flow) {
rte_flow_error_set(error, ENOMEM,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to allocate memory");
return flow;
}
ret = fm10k_flow_validate(dev, attr, pattern, actions, error);
if (ret < 0)
return NULL;
cf = fm10k_flow_cfg_transfer(dev, attr, pattern, actions, error);
if (!cf)
goto free_flow;
flow->rule = cf;
fm10k_ffu_flow_enable(sw, cf);
fm10k_config_flow_list_add_tail(fm10k_config_flowset_current_get(), cf);
TAILQ_INSERT_TAIL((struct fm10k_flow_list *)
fm10k_switch_dpdk_port_flow_list_get(hw), flow, node);
return flow;
free_flow:
rte_flow_error_set(error, -ret,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to create flow.");
rte_free(flow);
return NULL;
}
static int
fm10k_flow_destroy(struct rte_eth_dev *dev,
struct rte_flow *flow,
struct rte_flow_error *error)
{
struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
int ret = 0;
struct fm10k_switch *sw = fm10k_switch_get();
if (flow->rule) {
fm10k_config_flow_list_delete
((struct fm10k_cfg_flow *)flow->rule);
fm10k_ffu_flow_disable(sw,
(struct fm10k_cfg_flow *)flow->rule);
}
if (!ret) {
TAILQ_REMOVE((struct fm10k_flow_list *)
fm10k_switch_dpdk_port_flow_list_get(hw),
flow, node);
rte_free(flow->rule);
rte_free(flow);
} else {
rte_flow_error_set(error, -ret,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to destroy flow.");
}
return ret;
}
static int
fm10k_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
{
struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct rte_flow *flow;
void *temp;
int ret = 0;
struct fm10k_cfg_flow *cf;
struct fm10k_switch *sw = fm10k_switch_get();
/* Delete flows in flow list. */
TAILQ_FOREACH_SAFE(flow,
(struct fm10k_flow_list *)
fm10k_switch_dpdk_port_flow_list_get(hw),
node, temp) {
cf = flow->rule;
if (cf) {
fm10k_config_flow_list_delete(cf);
fm10k_ffu_flow_disable(sw, cf);
} else {
rte_flow_error_set(error, -ret,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"No such rule in flow.");
}
TAILQ_REMOVE((struct fm10k_flow_list *)
fm10k_switch_dpdk_port_flow_list_get(hw),
flow, node);
rte_free(flow);
}
return ret;
}
void
fm10k_flow_list_init(void *flow_list)
{
TAILQ_INIT((struct fm10k_flow_list *)flow_list);
}
/* Flow operations */
const struct rte_flow_ops *
fm10k_flow_ops_get(void)
{
return &fm10k_flow_ops;
}

View file

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2019 Silicom Ltd. Connectivity Solutions
*/
#ifndef _FM10K_SW_FLOW_H_
#define _FM10K_SW_FLOW_H_
#include <rte_time.h>
#include <rte_kvargs.h>
#include <rte_hash.h>
#include <rte_flow.h>
#include <rte_flow_driver.h>
#include <rte_tm_driver.h>
/*
* Struct to store flow created.
*/
struct rte_flow {
TAILQ_ENTRY(rte_flow) node;
enum rte_filter_type filter_type;
void *rule;
};
TAILQ_HEAD(fm10k_flow_list, rte_flow);
#endif /* _FM10K_SW_FLOW_H_ */

View file

@ -998,6 +998,134 @@ fm10k_stats_epl_port_print(struct fm10k_switch *sw)
}
}
void
fm10k_stats_dpdk_port_print(struct fm10k_switch *sw)
{
int i, j, lport, pf_no;
struct fm10k_port_counters counters;
struct fm10k_ext_port ext_port;
static struct fm10k_stats_data last_data[FM10K_SW_PEPS_MAX];
static struct fm10k_stats_data last_queue_data[FM10K_SW_PEPS_MAX][4];
struct fm10k_stats_data data, mydata;
char pf_ports[10];
for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {
if (sw->dpdk_cfg->ports[i].hw == NULL)
continue;
if (sw->dpdk_cfg->ports[i].type != FM10K_CONFIG_DPDK_PF)
continue;
if (sw->dpdk_cfg->dpdk_port_map[i].type ==
FM10K_CONFIG_PORT_MAP_NULL)
continue;
memset(&mydata, 0, sizeof(mydata));
if (sw->dpdk_cfg->dpdk_port_map[i].type ==
FM10K_CONFIG_PORT_MAP_PFS) {
for (j = 0; j < 2; j++) {
pf_no =
sw->dpdk_cfg->dpdk_port_map[i].map_no[j];
lport = sw->pep_map[pf_no].logical_port;
memset(&ext_port, 0, sizeof(ext_port));
ext_port.portno = lport;
fm10k_get_port_counters
(sw, &ext_port, &counters);
data.rx_pkts = counters.cnt_rx_bcst_pkts +
counters.cnt_rx_ucst_pkts;
data.tx_pkts = counters.cnt_tx_bcst_pkts +
counters.cnt_tx_ucst_pkts;
data.rx_drop = counters.cnt_cmpriv_drop_pkts;
mydata.rx_pkts += data.rx_pkts -
last_data[pf_no].rx_pkts;
mydata.tx_pkts += data.tx_pkts -
last_data[pf_no].tx_pkts;
mydata.rx_drop += data.rx_drop -
last_data[pf_no].rx_drop;
last_data[pf_no] = data;
}
} else if (sw->dpdk_cfg->dpdk_port_map[i].type ==
FM10K_CONFIG_PORT_MAP_PF) {
pf_no = sw->dpdk_cfg->dpdk_port_map[i].map_no[0];
lport = sw->pep_map[pf_no].logical_port;
memset(&ext_port, 0, sizeof(ext_port));
ext_port.portno = lport;
fm10k_get_port_counters(sw, &ext_port, &counters);
data.rx_pkts = counters.cnt_rx_bcst_pkts +
counters.cnt_rx_ucst_pkts;
data.tx_pkts = counters.cnt_tx_bcst_pkts +
counters.cnt_tx_ucst_pkts;
data.rx_drop = counters.cnt_cmpriv_drop_pkts;
mydata.rx_pkts += data.rx_pkts -
last_data[pf_no].rx_pkts;
mydata.tx_pkts += data.tx_pkts -
last_data[pf_no].tx_pkts;
mydata.rx_drop += data.rx_drop -
last_data[pf_no].rx_drop;
last_data[pf_no] = data;
} else {
continue;
}
if (sw->dpdk_cfg->dpdk_port_map[i].type ==
FM10K_CONFIG_PORT_MAP_PF)
sprintf(pf_ports, "%d",
sw->dpdk_cfg->dpdk_port_map[i].map_no[0]);
else
sprintf(pf_ports, "%d/%d",
sw->dpdk_cfg->dpdk_port_map[i].map_no[0],
sw->dpdk_cfg->dpdk_port_map[i].map_no[1]);
FM10K_SW_INFO("DPDK port %-2d pf %-5s tx_pkt %-12llu "
"rx_pkt %-12llu drop_pkt %-12llu\n",
i, pf_ports,
(unsigned long long)mydata.tx_pkts,
(unsigned long long)mydata.rx_pkts,
(unsigned long long)mydata.rx_drop);
if (!fm10k_config_check_debug(sw->dpdk_cfg,
FM10K_CONFIG_DEBUG_STATS_QUEUE))
continue;
memset(&mydata, 0, sizeof(mydata));
for (j = 0;
j < sw->dpdk_cfg->ports[i].tx_queue_num;
j++) {
struct fm10k_hw *hw = sw->dpdk_cfg->ports[i].hw;
uint16_t queue_id = j, pf_no;
fm10k_switch_dpdk_hw_queue_map(hw, queue_id,
sw->dpdk_cfg->ports[i].tx_queue_num,
&hw, &queue_id);
pf_no = fm10k_switch_dpdk_pf_no_get(hw);
data.tx_pkts =
FM10K_READ_REG(hw, FM10K_QPTC(queue_id));
data.rx_pkts =
FM10K_READ_REG(hw, FM10K_QPRC(queue_id));
data.rx_drop =
FM10K_READ_REG(hw, FM10K_QPRDC(queue_id));
mydata.tx_pkts += data.tx_pkts -
last_queue_data[pf_no][queue_id].tx_pkts;
mydata.rx_pkts += data.rx_pkts -
last_queue_data[pf_no][queue_id].rx_pkts;
mydata.rx_drop += data.rx_drop -
last_queue_data[pf_no][queue_id].rx_drop;
FM10K_SW_INFO(" queue %d(%d:%d) tx_pkt %-12llu "
"rx_pkt %-12llu drop_pkt %-12llu\n", j,
pf_no, queue_id,
(unsigned long long)(data.tx_pkts -
last_queue_data[pf_no][queue_id].tx_pkts),
(unsigned long long)(data.rx_pkts -
last_queue_data[pf_no][queue_id].rx_pkts),
(unsigned long long)(data.rx_drop -
last_queue_data[pf_no][queue_id].rx_drop));
last_queue_data[pf_no][queue_id] = data;
}
FM10K_SW_INFO(" total tx_pkt %-12llu "
"rx_pkt %-12llu drop_pkt %-12llu\n",
(unsigned long long)mydata.tx_pkts,
(unsigned long long)mydata.rx_pkts,
(unsigned long long)mydata.rx_drop);
}
}
static void
fm10k_stats_port_counter_print(struct fm10k_switch *sw, int lport)
{
@ -1080,6 +1208,7 @@ fm10k_switch_process_stats(void *ctx)
FM10K_CONFIG_DEBUG_STATS_PORT)) {
FM10K_SW_INFO("--- port statistic ---\n");
fm10k_stats_epl_port_print(sw);
fm10k_stats_dpdk_port_print(sw);
}
if (fm10k_config_check_debug(sw->dpdk_cfg,
FM10K_CONFIG_DEBUG_STATS_FFU)) {

File diff suppressed because it is too large Load diff