From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from alln-iport-4.cisco.com (alln-iport-4.cisco.com [173.37.142.91]) by dpdk.org (Postfix) with ESMTP id BA28C1B157 for ; Fri, 28 Sep 2018 03:58:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=20944; q=dns/txt; s=iport; t=1538099939; x=1539309539; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=U4cy05hYvvy8pdeSo/Xr2InMSVAxxR+/lZH0NEO33bo=; b=cBK8EByjdV7tVpyAY/KCJPmduOs1ThAfwkTn+GRtzH59wkJUpaQPqf8W 4ebruvDZkgk0aqRG/befcZcvHbqHwf3sHCmM2J93L01hWviTBCkefxYnd oMjX2pAVWPtJT7nBg9S2UE5z1xUn+3r24V77aZEZeEKYcRm7EAn2Ysxm/ s=; X-IronPort-AV: E=Sophos;i="5.54,313,1534809600"; d="scan'208";a="177844636" Received: from rcdn-core-12.cisco.com ([173.37.93.148]) by alln-iport-4.cisco.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Sep 2018 01:58:58 +0000 Received: from cisco.com (savbu-usnic-a.cisco.com [10.193.184.48]) by rcdn-core-12.cisco.com (8.15.2/8.15.2) with ESMTP id w8S1ww9G017019; Fri, 28 Sep 2018 01:58:58 GMT Received: by cisco.com (Postfix, from userid 392789) id 74C8320F2001; Thu, 27 Sep 2018 18:58:58 -0700 (PDT) From: John Daley To: ferruh.yigit@intel.com Cc: dev@dpdk.org, John Daley Date: Thu, 27 Sep 2018 18:58:26 -0700 Message-Id: <20180928015827.25786-2-johndale@cisco.com> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180928015827.25786-1-johndale@cisco.com> References: <20180928015827.25786-1-johndale@cisco.com> X-Outbound-SMTP-Client: 10.193.184.48, savbu-usnic-a.cisco.com X-Outbound-Node: rcdn-core-12.cisco.com Subject: [dpdk-dev] [PATCH 2/3] net/enic: support for flow counter action X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Sep 2018 01:59:00 -0000 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 Reviewed-by: Hyong Youb Kim --- drivers/net/enic/base/vnic_dev.c | 93 +++++++++++++++++++ drivers/net/enic/base/vnic_dev.h | 8 ++ drivers/net/enic/base/vnic_devcmd.h | 57 +++++++++++- drivers/net/enic/enic.h | 3 + drivers/net/enic/enic_flow.c | 178 ++++++++++++++++++++++++++++++++---- drivers/net/enic/enic_main.c | 11 ++- drivers/net/enic/enic_res.c | 6 +- 7 files changed, 331 insertions(+), 25 deletions(-) diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c index 16e8814a6..04285b68b 100644 --- a/drivers/net/enic/base/vnic_dev.c +++ b/drivers/net/enic/base/vnic_dev.c @@ -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; +} diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h index 270a47bd2..63751d8c5 100644 --- a/drivers/net/enic/base/vnic_dev.h +++ b/drivers/net/enic/base/vnic_dev.h @@ -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_ */ diff --git a/drivers/net/enic/base/vnic_devcmd.h b/drivers/net/enic/base/vnic_devcmd.h index fffe307e0..0efcee2ff 100644 --- a/drivers/net/enic/base/vnic_devcmd.h +++ b/drivers/net/enic/base/vnic_devcmd.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 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_ */ diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 7c27bd513..775cd5d55 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.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 */ diff --git a/drivers/net/enic/enic_flow.c b/drivers/net/enic/enic_flow.c index 9b612f1d5..04fc351b3 100644 --- a/drivers/net/enic/enic_flow.c +++ b/drivers/net/enic/enic_flow.c @@ -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, }; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index af29f9d90..ea6cddbd3 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -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) { diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 84486cace..28ae823f4 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -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, -- 2.16.2