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:
John Daley 2018-09-27 20:08:37 -07:00 committed by Ferruh Yigit
parent 85b0ccec38
commit 86df6c4e2f
8 changed files with 337 additions and 25 deletions

View File

@ -260,6 +260,12 @@ Generic Flow API is supported. The baseline support is:
- Selectors: 'is', 'spec' and 'mask'. 'last' is not supported - Selectors: 'is', 'spec' and 'mask'. 'last' is not supported
- In total, up to 64 bytes of mask is allowed across all headers - 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. More features may be added in future firmware and new versions of the VIC.
Please refer to the release notes. Please refer to the release notes.

View File

@ -57,6 +57,8 @@ struct vnic_dev {
void (*free_consistent)(void *priv, void (*free_consistent)(void *priv,
size_t size, void *vaddr, size_t size, void *vaddr,
dma_addr_t dma_handle); dma_addr_t dma_handle);
struct vnic_counter_counts *flow_counters;
dma_addr_t flow_counters_pa;
}; };
#define VNIC_MAX_RES_HDR_SIZE \ #define VNIC_MAX_RES_HDR_SIZE \
@ -64,6 +66,8 @@ struct vnic_dev {
sizeof(struct vnic_resource) * RES_TYPE_MAX) sizeof(struct vnic_resource) * RES_TYPE_MAX)
#define VNIC_RES_STRIDE 128 #define VNIC_RES_STRIDE 128
#define VNIC_MAX_FLOW_COUNTERS 2048
void *vnic_dev_priv(struct vnic_dev *vdev) void *vnic_dev_priv(struct vnic_dev *vdev)
{ {
return vdev->priv; 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); 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) int vnic_dev_close(struct vnic_dev *vdev)
{ {
u64 a0 = 0, a1 = 0; 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; 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) void vnic_dev_unregister(struct vnic_dev *vdev)
{ {
if (vdev) { if (vdev) {
@ -951,6 +989,15 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
vdev->free_consistent(vdev->priv, vdev->free_consistent(vdev->priv,
sizeof(struct vnic_stats), sizeof(struct vnic_stats),
vdev->stats, vdev->stats_pa); 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) if (vdev->fw_info)
vdev->free_consistent(vdev->priv, vdev->free_consistent(vdev->priv,
sizeof(struct vnic_devcmd_fw_info), 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)) == (a1 & (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ)) ==
(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;
}

View File

@ -118,6 +118,8 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size,
void *value); void *value);
int vnic_dev_stats_clear(struct vnic_dev *vdev); 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_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_hang_notify(struct vnic_dev *vdev);
int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti); int broadcast, int promisc, int allmulti);
@ -170,6 +172,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
unsigned int num_bars); unsigned int num_bars);
struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev); 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_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_cmd_init(struct vnic_dev *vdev, int fallback);
int vnic_dev_get_size(void); int vnic_dev_get_size(void);
int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op); 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, int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
u16 vxlan_udp_port_number); u16 vxlan_udp_port_number);
int vnic_dev_capable_vxlan(struct vnic_dev *vdev); 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_ */ #endif /* _VNIC_DEV_H_ */

View File

@ -598,6 +598,47 @@ enum vnic_devcmd_cmd {
* a3 = bitmask of supported actions * a3 = bitmask of supported actions
*/ */
CMD_ADD_ADV_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 77), 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 /* 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_RQ_STEERING_FLAG (1 << 0)
#define FILTER_ACTION_FILTER_ID_FLAG (1 << 1) #define FILTER_ACTION_FILTER_ID_FLAG (1 << 1)
#define FILTER_ACTION_DROP_FLAG (1 << 2) #define FILTER_ACTION_DROP_FLAG (1 << 2)
#define FILTER_ACTION_COUNTER_FLAG (1 << 3)
#define FILTER_ACTION_V2_ALL (FILTER_ACTION_RQ_STEERING_FLAG \ #define FILTER_ACTION_V2_ALL (FILTER_ACTION_RQ_STEERING_FLAG \
| FILTER_ACTION_FILTER_ID_FLAG \
| FILTER_ACTION_DROP_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 /* Version 2 of filter action must be a strict extension of struct filter_action
* where the first fields exactly match in size and meaning. * where the first fields exactly match in size and meaning.
@ -875,7 +918,8 @@ struct filter_action_v2 {
u32 rq_idx; u32 rq_idx;
u32 flags; /* use FILTER_ACTION_XXX_FLAG defines */ u32 flags; /* use FILTER_ACTION_XXX_FLAG defines */
u16 filter_id; u16 filter_id;
uint8_t reserved[32]; /* for future expansion */ u32 counter_index;
uint8_t reserved[28]; /* for future expansion */
} __attribute__((packed)); } __attribute__((packed));
/* Specifies the filter type. */ /* Specifies the filter type. */
@ -1122,4 +1166,13 @@ typedef enum {
GRPINTR_UPD_VECT, GRPINTR_UPD_VECT,
} grpintr_subcmd_t; } 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_ */ #endif /* _VNIC_DEVCMD_H_ */

View File

@ -38,6 +38,7 @@
#define ENIC_PAGE_SIZE 4096 #define ENIC_PAGE_SIZE 4096
#define PAGE_ROUND_UP(x) \ #define PAGE_ROUND_UP(x) \
((((unsigned long)(x)) + ENIC_PAGE_SIZE-1) & (~(ENIC_PAGE_SIZE-1))) ((((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 ENICPMD_VFIO_PATH "/dev/vfio/vfio"
/*#define ENIC_DESC_COUNT_MAKE_ODD (x) do{if ((~(x)) & 1) { (x)--; } }while(0)*/ /*#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; LIST_ENTRY(rte_flow) next;
u16 enic_filter_id; u16 enic_filter_id;
struct filter_v2 enic_filter; struct filter_v2 enic_filter;
int counter_idx; /* NIC allocated counter index (-1 = invalid) */
}; };
/* Per-instance private data structure */ /* Per-instance private data structure */
@ -165,6 +167,7 @@ struct enic {
rte_spinlock_t mtu_lock; rte_spinlock_t mtu_lock;
LIST_HEAD(enic_flows, rte_flow) flows; LIST_HEAD(enic_flows, rte_flow) flows;
int max_flow_counter;
rte_spinlock_t flows_lock; rte_spinlock_t flows_lock;
/* RSS */ /* RSS */

View File

@ -289,6 +289,15 @@ static const enum rte_flow_action_type enic_supported_actions_v2_drop[] = {
RTE_FLOW_ACTION_TYPE_END, 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 */ /** Action capabilities indexed by NIC version information */
static const struct enic_action_cap enic_action_cap[] = { static const struct enic_action_cap enic_action_cap[] = {
[FILTER_ACTION_RQ_STEERING_FLAG] = { [FILTER_ACTION_RQ_STEERING_FLAG] = {
@ -303,6 +312,10 @@ static const struct enic_action_cap enic_action_cap[] = {
.actions = enic_supported_actions_v2_drop, .actions = enic_supported_actions_v2_drop,
.copy_fn = enic_copy_action_v2, .copy_fn = enic_copy_action_v2,
}, },
[FILTER_ACTION_COUNTER_FLAG] = {
.actions = enic_supported_actions_v2_count,
.copy_fn = enic_copy_action_v2,
},
}; };
static int static int
@ -1068,6 +1081,10 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
enic_action->flags |= FILTER_ACTION_DROP_FLAG; enic_action->flags |= FILTER_ACTION_DROP_FLAG;
break; break;
} }
case RTE_FLOW_ACTION_TYPE_COUNT: {
enic_action->flags |= FILTER_ACTION_COUNTER_FLAG;
break;
}
case RTE_FLOW_ACTION_TYPE_VOID: case RTE_FLOW_ACTION_TYPE_VOID:
continue; continue;
default: default:
@ -1112,7 +1129,9 @@ enic_get_action_cap(struct enic *enic)
uint8_t actions; uint8_t actions;
actions = enic->filter_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]; ea = &enic_action_cap[FILTER_ACTION_DROP_FLAG];
else if (actions & FILTER_ACTION_FILTER_ID_FLAG) else if (actions & FILTER_ACTION_FILTER_ID_FLAG)
ea = &enic_action_cap[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_error *error)
{ {
struct rte_flow *flow; struct rte_flow *flow;
int ret; int err;
u16 entry; uint16_t entry;
int ctr_idx;
int last_max_flow_ctr;
FLOW_TRACE(); FLOW_TRACE();
@ -1407,20 +1428,64 @@ enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter,
return NULL; 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[in] is the queue id, entry[out] is the filter Id for delete */
entry = enic_action->rq_idx; 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); enic_action);
if (!ret) { if (err) {
rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE,
NULL, "vnic_dev_classifier error");
goto unwind_ctr_dma_cfg;
}
flow->enic_filter_id = entry; flow->enic_filter_id = entry;
flow->enic_filter = *enic_filter; flow->enic_filter = *enic_filter;
} else {
rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE, return flow;
NULL, "vnic_dev_classifier error");
/* 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); rte_free(flow);
return NULL; return NULL;
}
return flow;
} }
/** /**
@ -1435,18 +1500,29 @@ enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter,
* @param error[out] * @param error[out]
*/ */
static int 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) struct rte_flow_error *error)
{ {
int ret; u16 filter_id;
int err;
FLOW_TRACE(); FLOW_TRACE();
ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL, NULL); filter_id = flow->enic_filter_id;
if (!ret) err = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL, NULL);
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 failed"); 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(); FLOW_TRACE();
rte_spinlock_lock(&enic->flows_lock); 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); LIST_REMOVE(flow, next);
rte_spinlock_unlock(&enic->flows_lock); rte_spinlock_unlock(&enic->flows_lock);
rte_free(flow); 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)) { while (!LIST_EMPTY(&enic->flows)) {
flow = LIST_FIRST(&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); LIST_REMOVE(flow, next);
rte_free(flow); rte_free(flow);
} }
@ -1562,6 +1638,69 @@ enic_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
return 0; 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. * Flow callback registration.
* *
@ -1572,4 +1711,5 @@ const struct rte_flow_ops enic_flow_ops = {
.create = enic_flow_create, .create = enic_flow_create,
.destroy = enic_flow_destroy, .destroy = enic_flow_destroy,
.flush = enic_flow_flush, .flush = enic_flow_flush,
.query = enic_flow_query,
}; };

View File

@ -1647,6 +1647,7 @@ static int enic_dev_init(struct enic *enic)
LIST_INIT(&enic->flows); LIST_INIT(&enic->flows);
rte_spinlock_init(&enic->flows_lock); rte_spinlock_init(&enic->flows_lock);
enic->max_flow_counter = -1;
/* set up link status checking */ /* set up link status checking */
vnic_dev_notify_set(enic->vdev, -1); /* No Intr for notify */ vnic_dev_notify_set(enic->vdev, -1); /* No Intr for notify */
@ -1729,14 +1730,20 @@ int enic_probe(struct enic *enic)
enic_free_consistent); enic_free_consistent);
/* /*
* Allocate the consistent memory for stats upfront so both primary and * Allocate the consistent memory for stats and counters upfront so
* secondary processes can dump stats. * both primary and secondary processes can dump stats.
*/ */
err = vnic_dev_alloc_stats_mem(enic->vdev); err = vnic_dev_alloc_stats_mem(enic->vdev);
if (err) { if (err) {
dev_err(enic, "Failed to allocate cmd memory, aborting\n"); dev_err(enic, "Failed to allocate cmd memory, aborting\n");
goto err_out_unregister; 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 */ /* Issue device open to get device in known state */
err = enic_dev_open(enic); err = enic_dev_open(enic);
if (err) { if (err) {

View File

@ -85,7 +85,7 @@ int enic_get_vnic_config(struct enic *enic)
vnic_dev_capable_udp_rss_weak(enic->vdev, &enic->nic_cfg_chk, vnic_dev_capable_udp_rss_weak(enic->vdev, &enic->nic_cfg_chk,
&enic->udp_rss_weak); &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_DPDK_1) ? "DPDK" :
((enic->flow_filter_mode == FILTER_USNIC_IP) ? "USNIC" : ((enic->flow_filter_mode == FILTER_USNIC_IP) ? "USNIC" :
((enic->flow_filter_mode == FILTER_IPV4_5TUPLE) ? "5TUPLE" : ((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) ? ((enic->filter_actions & FILTER_ACTION_FILTER_ID_FLAG) ?
"tag " : ""), "tag " : ""),
((enic->filter_actions & FILTER_ACTION_DROP_FLAG) ? ((enic->filter_actions & FILTER_ACTION_DROP_FLAG) ?
"drop " : "")); "drop " : ""),
((enic->filter_actions & FILTER_ACTION_COUNTER_FLAG) ?
"count " : ""));
c->wq_desc_count = c->wq_desc_count =
min_t(u32, ENIC_MAX_WQ_DESCS, min_t(u32, ENIC_MAX_WQ_DESCS,