net/enic: support flow counter action
Support counter action for 1400 series adapters. The adapter API for allocating and freeing counters is independent of the adapter match/action API. If the filter action is requested, a counter is first allocated and then assigned to the filter, and when the filter is deleted, the counter must also be deleted. Counters are DMAd to pre-allocated consistent memory periodically, controlled by the define VNIC_FLOW_COUNTER_UPDATE_MSECS. The default is 100 milliseconds. Signed-off-by: John Daley <johndale@cisco.com> Reviewed-by: Hyong Youb Kim <hyonkim@cisco.com>
This commit is contained in:
parent
85b0ccec38
commit
86df6c4e2f
@ -260,6 +260,12 @@ Generic Flow API is supported. The baseline support is:
|
||||
- Selectors: 'is', 'spec' and 'mask'. 'last' is not supported
|
||||
- In total, up to 64 bytes of mask is allowed across all headers
|
||||
|
||||
- **1400 and later series VICS with advanced filters enabled**
|
||||
|
||||
All the above plus:
|
||||
|
||||
- Action: count
|
||||
|
||||
More features may be added in future firmware and new versions of the VIC.
|
||||
Please refer to the release notes.
|
||||
|
||||
|
@ -57,6 +57,8 @@ struct vnic_dev {
|
||||
void (*free_consistent)(void *priv,
|
||||
size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle);
|
||||
struct vnic_counter_counts *flow_counters;
|
||||
dma_addr_t flow_counters_pa;
|
||||
};
|
||||
|
||||
#define VNIC_MAX_RES_HDR_SIZE \
|
||||
@ -64,6 +66,8 @@ struct vnic_dev {
|
||||
sizeof(struct vnic_resource) * RES_TYPE_MAX)
|
||||
#define VNIC_RES_STRIDE 128
|
||||
|
||||
#define VNIC_MAX_FLOW_COUNTERS 2048
|
||||
|
||||
void *vnic_dev_priv(struct vnic_dev *vdev)
|
||||
{
|
||||
return vdev->priv;
|
||||
@ -611,6 +615,23 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
|
||||
return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure counter DMA
|
||||
*/
|
||||
int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period, u32 counter_idx)
|
||||
{
|
||||
u64 args[3];
|
||||
int wait = 1000;
|
||||
|
||||
if (!vdev->flow_counters || counter_idx >= VNIC_MAX_FLOW_COUNTERS)
|
||||
return -ENOMEM;
|
||||
|
||||
args[0] = counter_idx + 1;
|
||||
args[1] = vdev->flow_counters_pa;
|
||||
args[2] = period;
|
||||
return vnic_dev_cmd_args(vdev, CMD_COUNTER_DMA_CONFIG, args, 3, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_close(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
@ -939,6 +960,23 @@ int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
|
||||
return vdev->stats == NULL ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize for up to VNIC_MAX_FLOW_COUNTERS
|
||||
*/
|
||||
int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev)
|
||||
{
|
||||
char name[NAME_MAX];
|
||||
static u32 instance;
|
||||
|
||||
snprintf((char *)name, sizeof(name), "vnic_flow_ctrs-%u", instance++);
|
||||
vdev->flow_counters = vdev->alloc_consistent(vdev->priv,
|
||||
sizeof(struct vnic_counter_counts)
|
||||
* VNIC_MAX_FLOW_COUNTERS,
|
||||
&vdev->flow_counters_pa,
|
||||
(u8 *)name);
|
||||
return vdev->flow_counters == NULL ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
void vnic_dev_unregister(struct vnic_dev *vdev)
|
||||
{
|
||||
if (vdev) {
|
||||
@ -951,6 +989,15 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_stats),
|
||||
vdev->stats, vdev->stats_pa);
|
||||
if (vdev->flow_counters) {
|
||||
/* turn off counter DMAs before freeing memory */
|
||||
vnic_dev_counter_dma_cfg(vdev, 0, 0);
|
||||
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_counter_counts)
|
||||
* VNIC_MAX_FLOW_COUNTERS,
|
||||
vdev->flow_counters, vdev->flow_counters_pa);
|
||||
}
|
||||
if (vdev->fw_info)
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_devcmd_fw_info),
|
||||
@ -1094,3 +1141,49 @@ int vnic_dev_capable_vxlan(struct vnic_dev *vdev)
|
||||
(a1 & (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ)) ==
|
||||
(FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ);
|
||||
}
|
||||
|
||||
bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx)
|
||||
{
|
||||
u64 a0 = 0;
|
||||
u64 a1 = 0;
|
||||
int wait = 1000;
|
||||
|
||||
if (vnic_dev_cmd(vdev, CMD_COUNTER_ALLOC, &a0, &a1, wait))
|
||||
return false;
|
||||
*idx = (uint32_t)a0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx)
|
||||
{
|
||||
u64 a0 = idx;
|
||||
u64 a1 = 0;
|
||||
int wait = 1000;
|
||||
|
||||
return vnic_dev_cmd(vdev, CMD_COUNTER_FREE, &a0, &a1,
|
||||
wait) == 0;
|
||||
}
|
||||
|
||||
bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx,
|
||||
bool reset, uint64_t *packets, uint64_t *bytes)
|
||||
{
|
||||
u64 a0 = idx;
|
||||
u64 a1 = reset ? 1 : 0;
|
||||
int wait = 1000;
|
||||
|
||||
if (vdev->flow_counters) {
|
||||
/* Using counter DMA API, so counters avail in host memory */
|
||||
*packets = vdev->flow_counters[idx].vcc_packets;
|
||||
*bytes = vdev->flow_counters[idx].vcc_bytes;
|
||||
if (reset)
|
||||
if (vnic_dev_cmd(vdev, CMD_COUNTER_QUERY, &a0, &a1,
|
||||
wait))
|
||||
return false;
|
||||
} else {
|
||||
if (vnic_dev_cmd(vdev, CMD_COUNTER_QUERY, &a0, &a1, wait))
|
||||
return false;
|
||||
*packets = a0;
|
||||
*bytes = a1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size,
|
||||
void *value);
|
||||
int vnic_dev_stats_clear(struct vnic_dev *vdev);
|
||||
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
|
||||
int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period,
|
||||
u32 counter_idx);
|
||||
int vnic_dev_hang_notify(struct vnic_dev *vdev);
|
||||
int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti);
|
||||
@ -170,6 +172,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
||||
unsigned int num_bars);
|
||||
struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
|
||||
int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
|
||||
int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev);
|
||||
int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
|
||||
int vnic_dev_get_size(void);
|
||||
int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
|
||||
@ -187,4 +190,9 @@ int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev,
|
||||
int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
|
||||
u16 vxlan_udp_port_number);
|
||||
int vnic_dev_capable_vxlan(struct vnic_dev *vdev);
|
||||
bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx);
|
||||
bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx);
|
||||
bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx,
|
||||
bool reset, uint64_t *packets, uint64_t *bytes);
|
||||
|
||||
#endif /* _VNIC_DEV_H_ */
|
||||
|
@ -598,6 +598,47 @@ enum vnic_devcmd_cmd {
|
||||
* a3 = bitmask of supported actions
|
||||
*/
|
||||
CMD_ADD_ADV_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 77),
|
||||
|
||||
/*
|
||||
* Allocate a counter for use with CMD_ADD_FILTER
|
||||
* out:(u32) a0 = counter index
|
||||
*/
|
||||
CMD_COUNTER_ALLOC = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ENET, 85),
|
||||
|
||||
/*
|
||||
* Free a counter
|
||||
* in: (u32) a0 = counter_id
|
||||
*/
|
||||
CMD_COUNTER_FREE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 86),
|
||||
|
||||
/*
|
||||
* Read a counter
|
||||
* in: (u32) a0 = counter_id
|
||||
* (u32) a1 = clear counter if non-zero
|
||||
* out:(u64) a0 = packet count
|
||||
* (u64) a1 = byte count
|
||||
*/
|
||||
CMD_COUNTER_QUERY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 87),
|
||||
|
||||
/*
|
||||
* Configure periodic counter DMA. This will trigger an immediate
|
||||
* DMA of the counters (unless period == 0), and then schedule a DMA
|
||||
* of the counters every <period> seconds until disdabled.
|
||||
* Each new COUNTER_DMA_CONFIG will override all previous commands on
|
||||
* this vnic.
|
||||
* Setting a2 (period) = 0 will disable periodic DMAs
|
||||
* If a0 (num_counters) != 0, an immediate DMA will always be done,
|
||||
* irrespective of the value in a2.
|
||||
* in: (u32) a0 = number of counters to DMA
|
||||
* (u64) a1 = host target DMA address
|
||||
* (u32) a2 = DMA period in milliseconds (0 to disable)
|
||||
*/
|
||||
CMD_COUNTER_DMA_CONFIG = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 88),
|
||||
|
||||
/*
|
||||
* Clear all counters on a vnic
|
||||
*/
|
||||
CMD_COUNTER_CLEAR_ALL = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ENET, 89),
|
||||
};
|
||||
|
||||
/* Modes for exchanging advanced filter capabilities. The modes supported by
|
||||
@ -863,9 +904,11 @@ struct filter_action {
|
||||
#define FILTER_ACTION_RQ_STEERING_FLAG (1 << 0)
|
||||
#define FILTER_ACTION_FILTER_ID_FLAG (1 << 1)
|
||||
#define FILTER_ACTION_DROP_FLAG (1 << 2)
|
||||
#define FILTER_ACTION_COUNTER_FLAG (1 << 3)
|
||||
#define FILTER_ACTION_V2_ALL (FILTER_ACTION_RQ_STEERING_FLAG \
|
||||
| FILTER_ACTION_FILTER_ID_FLAG \
|
||||
| FILTER_ACTION_DROP_FLAG \
|
||||
| FILTER_ACTION_FILTER_ID_FLAG)
|
||||
| FILTER_ACTION_COUNTER_FLAG)
|
||||
|
||||
/* Version 2 of filter action must be a strict extension of struct filter_action
|
||||
* where the first fields exactly match in size and meaning.
|
||||
@ -875,7 +918,8 @@ struct filter_action_v2 {
|
||||
u32 rq_idx;
|
||||
u32 flags; /* use FILTER_ACTION_XXX_FLAG defines */
|
||||
u16 filter_id;
|
||||
uint8_t reserved[32]; /* for future expansion */
|
||||
u32 counter_index;
|
||||
uint8_t reserved[28]; /* for future expansion */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Specifies the filter type. */
|
||||
@ -1122,4 +1166,13 @@ typedef enum {
|
||||
GRPINTR_UPD_VECT,
|
||||
} grpintr_subcmd_t;
|
||||
|
||||
/*
|
||||
* Structure for counter DMA
|
||||
* (DMAed by CMD_COUNTER_DMA_CONFIG)
|
||||
*/
|
||||
struct vnic_counter_counts {
|
||||
u64 vcc_packets;
|
||||
u64 vcc_bytes;
|
||||
};
|
||||
|
||||
#endif /* _VNIC_DEVCMD_H_ */
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define ENIC_PAGE_SIZE 4096
|
||||
#define PAGE_ROUND_UP(x) \
|
||||
((((unsigned long)(x)) + ENIC_PAGE_SIZE-1) & (~(ENIC_PAGE_SIZE-1)))
|
||||
#define VNIC_FLOW_COUNTER_UPDATE_MSECS 100
|
||||
|
||||
#define ENICPMD_VFIO_PATH "/dev/vfio/vfio"
|
||||
/*#define ENIC_DESC_COUNT_MAKE_ODD (x) do{if ((~(x)) & 1) { (x)--; } }while(0)*/
|
||||
@ -94,6 +95,7 @@ struct rte_flow {
|
||||
LIST_ENTRY(rte_flow) next;
|
||||
u16 enic_filter_id;
|
||||
struct filter_v2 enic_filter;
|
||||
int counter_idx; /* NIC allocated counter index (-1 = invalid) */
|
||||
};
|
||||
|
||||
/* Per-instance private data structure */
|
||||
@ -165,6 +167,7 @@ struct enic {
|
||||
rte_spinlock_t mtu_lock;
|
||||
|
||||
LIST_HEAD(enic_flows, rte_flow) flows;
|
||||
int max_flow_counter;
|
||||
rte_spinlock_t flows_lock;
|
||||
|
||||
/* RSS */
|
||||
|
@ -289,6 +289,15 @@ static const enum rte_flow_action_type enic_supported_actions_v2_drop[] = {
|
||||
RTE_FLOW_ACTION_TYPE_END,
|
||||
};
|
||||
|
||||
static const enum rte_flow_action_type enic_supported_actions_v2_count[] = {
|
||||
RTE_FLOW_ACTION_TYPE_QUEUE,
|
||||
RTE_FLOW_ACTION_TYPE_MARK,
|
||||
RTE_FLOW_ACTION_TYPE_FLAG,
|
||||
RTE_FLOW_ACTION_TYPE_DROP,
|
||||
RTE_FLOW_ACTION_TYPE_COUNT,
|
||||
RTE_FLOW_ACTION_TYPE_END,
|
||||
};
|
||||
|
||||
/** Action capabilities indexed by NIC version information */
|
||||
static const struct enic_action_cap enic_action_cap[] = {
|
||||
[FILTER_ACTION_RQ_STEERING_FLAG] = {
|
||||
@ -303,6 +312,10 @@ static const struct enic_action_cap enic_action_cap[] = {
|
||||
.actions = enic_supported_actions_v2_drop,
|
||||
.copy_fn = enic_copy_action_v2,
|
||||
},
|
||||
[FILTER_ACTION_COUNTER_FLAG] = {
|
||||
.actions = enic_supported_actions_v2_count,
|
||||
.copy_fn = enic_copy_action_v2,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
@ -1068,6 +1081,10 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
|
||||
enic_action->flags |= FILTER_ACTION_DROP_FLAG;
|
||||
break;
|
||||
}
|
||||
case RTE_FLOW_ACTION_TYPE_COUNT: {
|
||||
enic_action->flags |= FILTER_ACTION_COUNTER_FLAG;
|
||||
break;
|
||||
}
|
||||
case RTE_FLOW_ACTION_TYPE_VOID:
|
||||
continue;
|
||||
default:
|
||||
@ -1112,7 +1129,9 @@ enic_get_action_cap(struct enic *enic)
|
||||
uint8_t actions;
|
||||
|
||||
actions = enic->filter_actions;
|
||||
if (actions & FILTER_ACTION_DROP_FLAG)
|
||||
if (actions & FILTER_ACTION_COUNTER_FLAG)
|
||||
ea = &enic_action_cap[FILTER_ACTION_COUNTER_FLAG];
|
||||
else if (actions & FILTER_ACTION_DROP_FLAG)
|
||||
ea = &enic_action_cap[FILTER_ACTION_DROP_FLAG];
|
||||
else if (actions & FILTER_ACTION_FILTER_ID_FLAG)
|
||||
ea = &enic_action_cap[FILTER_ACTION_FILTER_ID_FLAG];
|
||||
@ -1395,8 +1414,10 @@ enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct rte_flow *flow;
|
||||
int ret;
|
||||
u16 entry;
|
||||
int err;
|
||||
uint16_t entry;
|
||||
int ctr_idx;
|
||||
int last_max_flow_ctr;
|
||||
|
||||
FLOW_TRACE();
|
||||
|
||||
@ -1407,20 +1428,64 @@ enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flow->counter_idx = -1;
|
||||
last_max_flow_ctr = -1;
|
||||
if (enic_action->flags & FILTER_ACTION_COUNTER_FLAG) {
|
||||
if (!vnic_dev_counter_alloc(enic->vdev, (uint32_t *)&ctr_idx)) {
|
||||
rte_flow_error_set(error, ENOMEM,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION_CONF,
|
||||
NULL, "cannot allocate counter");
|
||||
goto unwind_flow_alloc;
|
||||
}
|
||||
flow->counter_idx = ctr_idx;
|
||||
enic_action->counter_index = ctr_idx;
|
||||
|
||||
/* If index is the largest, increase the counter DMA size */
|
||||
if (ctr_idx > enic->max_flow_counter) {
|
||||
err = vnic_dev_counter_dma_cfg(enic->vdev,
|
||||
VNIC_FLOW_COUNTER_UPDATE_MSECS,
|
||||
ctr_idx);
|
||||
if (err) {
|
||||
rte_flow_error_set(error, -err,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION_CONF,
|
||||
NULL, "counter DMA config failed");
|
||||
goto unwind_ctr_alloc;
|
||||
}
|
||||
last_max_flow_ctr = enic->max_flow_counter;
|
||||
enic->max_flow_counter = ctr_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/* entry[in] is the queue id, entry[out] is the filter Id for delete */
|
||||
entry = enic_action->rq_idx;
|
||||
ret = vnic_dev_classifier(enic->vdev, CLSF_ADD, &entry, enic_filter,
|
||||
err = vnic_dev_classifier(enic->vdev, CLSF_ADD, &entry, enic_filter,
|
||||
enic_action);
|
||||
if (!ret) {
|
||||
flow->enic_filter_id = entry;
|
||||
flow->enic_filter = *enic_filter;
|
||||
} else {
|
||||
rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
if (err) {
|
||||
rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
NULL, "vnic_dev_classifier error");
|
||||
rte_free(flow);
|
||||
return NULL;
|
||||
goto unwind_ctr_dma_cfg;
|
||||
}
|
||||
|
||||
flow->enic_filter_id = entry;
|
||||
flow->enic_filter = *enic_filter;
|
||||
|
||||
return flow;
|
||||
|
||||
/* unwind if there are errors */
|
||||
unwind_ctr_dma_cfg:
|
||||
if (last_max_flow_ctr != -1) {
|
||||
/* reduce counter DMA size */
|
||||
vnic_dev_counter_dma_cfg(enic->vdev,
|
||||
VNIC_FLOW_COUNTER_UPDATE_MSECS,
|
||||
last_max_flow_ctr);
|
||||
enic->max_flow_counter = last_max_flow_ctr;
|
||||
}
|
||||
unwind_ctr_alloc:
|
||||
if (flow->counter_idx != -1)
|
||||
vnic_dev_counter_free(enic->vdev, ctr_idx);
|
||||
unwind_flow_alloc:
|
||||
rte_free(flow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1435,18 +1500,29 @@ enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter,
|
||||
* @param error[out]
|
||||
*/
|
||||
static int
|
||||
enic_flow_del_filter(struct enic *enic, u16 filter_id,
|
||||
enic_flow_del_filter(struct enic *enic, struct rte_flow *flow,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
int ret;
|
||||
u16 filter_id;
|
||||
int err;
|
||||
|
||||
FLOW_TRACE();
|
||||
|
||||
ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL, NULL);
|
||||
if (!ret)
|
||||
rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
filter_id = flow->enic_filter_id;
|
||||
err = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL, NULL);
|
||||
if (err) {
|
||||
rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
NULL, "vnic_dev_classifier failed");
|
||||
return ret;
|
||||
return -err;
|
||||
}
|
||||
|
||||
if (flow->counter_idx != -1) {
|
||||
if (!vnic_dev_counter_free(enic->vdev, flow->counter_idx))
|
||||
dev_err(enic, "counter free failed, idx: %d\n",
|
||||
flow->counter_idx);
|
||||
flow->counter_idx = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1529,7 +1605,7 @@ enic_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
|
||||
FLOW_TRACE();
|
||||
|
||||
rte_spinlock_lock(&enic->flows_lock);
|
||||
enic_flow_del_filter(enic, flow->enic_filter_id, error);
|
||||
enic_flow_del_filter(enic, flow, error);
|
||||
LIST_REMOVE(flow, next);
|
||||
rte_spinlock_unlock(&enic->flows_lock);
|
||||
rte_free(flow);
|
||||
@ -1554,7 +1630,7 @@ enic_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
|
||||
|
||||
while (!LIST_EMPTY(&enic->flows)) {
|
||||
flow = LIST_FIRST(&enic->flows);
|
||||
enic_flow_del_filter(enic, flow->enic_filter_id, error);
|
||||
enic_flow_del_filter(enic, flow, error);
|
||||
LIST_REMOVE(flow, next);
|
||||
rte_free(flow);
|
||||
}
|
||||
@ -1562,6 +1638,69 @@ enic_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
enic_flow_query_count(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow, void *data,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct enic *enic = pmd_priv(dev);
|
||||
struct rte_flow_query_count *query;
|
||||
uint64_t packets, bytes;
|
||||
|
||||
FLOW_TRACE();
|
||||
|
||||
if (flow->counter_idx == -1) {
|
||||
return rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"flow does not have counter");
|
||||
}
|
||||
query = (struct rte_flow_query_count *)data;
|
||||
if (!vnic_dev_counter_query(enic->vdev, flow->counter_idx,
|
||||
!!query->reset, &packets, &bytes)) {
|
||||
return rte_flow_error_set
|
||||
(error, EINVAL,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"cannot read counter");
|
||||
}
|
||||
query->hits_set = 1;
|
||||
query->bytes_set = 1;
|
||||
query->hits = packets;
|
||||
query->bytes = bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
enic_flow_query(struct rte_eth_dev *dev,
|
||||
struct rte_flow *flow,
|
||||
const struct rte_flow_action *actions,
|
||||
void *data,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
FLOW_TRACE();
|
||||
|
||||
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
|
||||
switch (actions->type) {
|
||||
case RTE_FLOW_ACTION_TYPE_VOID:
|
||||
break;
|
||||
case RTE_FLOW_ACTION_TYPE_COUNT:
|
||||
ret = enic_flow_query_count(dev, flow, data, error);
|
||||
break;
|
||||
default:
|
||||
return rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
actions,
|
||||
"action not supported");
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow callback registration.
|
||||
*
|
||||
@ -1572,4 +1711,5 @@ const struct rte_flow_ops enic_flow_ops = {
|
||||
.create = enic_flow_create,
|
||||
.destroy = enic_flow_destroy,
|
||||
.flush = enic_flow_flush,
|
||||
.query = enic_flow_query,
|
||||
};
|
||||
|
@ -1647,6 +1647,7 @@ static int enic_dev_init(struct enic *enic)
|
||||
|
||||
LIST_INIT(&enic->flows);
|
||||
rte_spinlock_init(&enic->flows_lock);
|
||||
enic->max_flow_counter = -1;
|
||||
|
||||
/* set up link status checking */
|
||||
vnic_dev_notify_set(enic->vdev, -1); /* No Intr for notify */
|
||||
@ -1729,14 +1730,20 @@ int enic_probe(struct enic *enic)
|
||||
enic_free_consistent);
|
||||
|
||||
/*
|
||||
* Allocate the consistent memory for stats upfront so both primary and
|
||||
* secondary processes can dump stats.
|
||||
* Allocate the consistent memory for stats and counters upfront so
|
||||
* both primary and secondary processes can dump stats.
|
||||
*/
|
||||
err = vnic_dev_alloc_stats_mem(enic->vdev);
|
||||
if (err) {
|
||||
dev_err(enic, "Failed to allocate cmd memory, aborting\n");
|
||||
goto err_out_unregister;
|
||||
}
|
||||
err = vnic_dev_alloc_counter_mem(enic->vdev);
|
||||
if (err) {
|
||||
dev_err(enic, "Failed to allocate counter memory, aborting\n");
|
||||
goto err_out_unregister;
|
||||
}
|
||||
|
||||
/* Issue device open to get device in known state */
|
||||
err = enic_dev_open(enic);
|
||||
if (err) {
|
||||
|
@ -85,7 +85,7 @@ int enic_get_vnic_config(struct enic *enic)
|
||||
vnic_dev_capable_udp_rss_weak(enic->vdev, &enic->nic_cfg_chk,
|
||||
&enic->udp_rss_weak);
|
||||
|
||||
dev_info(enic, "Flow api filter mode: %s Actions: %s%s%s\n",
|
||||
dev_info(enic, "Flow api filter mode: %s Actions: %s%s%s%s\n",
|
||||
((enic->flow_filter_mode == FILTER_DPDK_1) ? "DPDK" :
|
||||
((enic->flow_filter_mode == FILTER_USNIC_IP) ? "USNIC" :
|
||||
((enic->flow_filter_mode == FILTER_IPV4_5TUPLE) ? "5TUPLE" :
|
||||
@ -95,7 +95,9 @@ int enic_get_vnic_config(struct enic *enic)
|
||||
((enic->filter_actions & FILTER_ACTION_FILTER_ID_FLAG) ?
|
||||
"tag " : ""),
|
||||
((enic->filter_actions & FILTER_ACTION_DROP_FLAG) ?
|
||||
"drop " : ""));
|
||||
"drop " : ""),
|
||||
((enic->filter_actions & FILTER_ACTION_COUNTER_FLAG) ?
|
||||
"count " : ""));
|
||||
|
||||
c->wq_desc_count =
|
||||
min_t(u32, ENIC_MAX_WQ_DESCS,
|
||||
|
Loading…
Reference in New Issue
Block a user