149dad902SMatan Azrad /* SPDX-License-Identifier: BSD-3-Clause
249dad902SMatan Azrad * Copyright 2018 Mellanox Technologies, Ltd
349dad902SMatan Azrad */
449dad902SMatan Azrad
581b750c7SAdrien Mazarguil #include <stddef.h>
681b750c7SAdrien Mazarguil #include <string.h>
749dad902SMatan Azrad #include <sys/queue.h>
849dad902SMatan Azrad
981b750c7SAdrien Mazarguil #include <rte_errno.h>
1049dad902SMatan Azrad #include <rte_malloc.h>
1149dad902SMatan Azrad #include <rte_tailq.h>
1249dad902SMatan Azrad #include <rte_flow.h>
1349dad902SMatan Azrad
14b28f28aeSDharmik Thakkar #include "eth_bond_private.h"
1549dad902SMatan Azrad
1649dad902SMatan Azrad static struct rte_flow *
bond_flow_alloc(int numa_node,const struct rte_flow_attr * attr,const struct rte_flow_item * items,const struct rte_flow_action * actions)1749dad902SMatan Azrad bond_flow_alloc(int numa_node, const struct rte_flow_attr *attr,
1849dad902SMatan Azrad const struct rte_flow_item *items,
1949dad902SMatan Azrad const struct rte_flow_action *actions)
2049dad902SMatan Azrad {
2149dad902SMatan Azrad struct rte_flow *flow;
2281b750c7SAdrien Mazarguil const struct rte_flow_conv_rule rule = {
2381b750c7SAdrien Mazarguil .attr_ro = attr,
2481b750c7SAdrien Mazarguil .pattern_ro = items,
2581b750c7SAdrien Mazarguil .actions_ro = actions,
2681b750c7SAdrien Mazarguil };
2781b750c7SAdrien Mazarguil struct rte_flow_error error;
2881b750c7SAdrien Mazarguil int ret;
2949dad902SMatan Azrad
3081b750c7SAdrien Mazarguil ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error);
3181b750c7SAdrien Mazarguil if (ret < 0) {
3281b750c7SAdrien Mazarguil RTE_BOND_LOG(ERR, "Unable to process flow rule (%s): %s",
3381b750c7SAdrien Mazarguil error.message ? error.message : "unspecified",
3481b750c7SAdrien Mazarguil strerror(rte_errno));
3581b750c7SAdrien Mazarguil return NULL;
3681b750c7SAdrien Mazarguil }
3781b750c7SAdrien Mazarguil flow = rte_zmalloc_socket(NULL, offsetof(struct rte_flow, rule) + ret,
3849dad902SMatan Azrad RTE_CACHE_LINE_SIZE, numa_node);
3949dad902SMatan Azrad if (unlikely(flow == NULL)) {
4049dad902SMatan Azrad RTE_BOND_LOG(ERR, "Could not allocate new flow");
4149dad902SMatan Azrad return NULL;
4249dad902SMatan Azrad }
4381b750c7SAdrien Mazarguil ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->rule, ret, &rule,
4481b750c7SAdrien Mazarguil &error);
4581b750c7SAdrien Mazarguil if (ret < 0) {
4681b750c7SAdrien Mazarguil RTE_BOND_LOG(ERR, "Failed to copy flow rule (%s): %s",
4781b750c7SAdrien Mazarguil error.message ? error.message : "unspecified",
4881b750c7SAdrien Mazarguil strerror(rte_errno));
4949dad902SMatan Azrad rte_free(flow);
5049dad902SMatan Azrad return NULL;
5149dad902SMatan Azrad }
5249dad902SMatan Azrad return flow;
5349dad902SMatan Azrad }
5449dad902SMatan Azrad
5549dad902SMatan Azrad static void
bond_flow_release(struct rte_flow ** flow)5649dad902SMatan Azrad bond_flow_release(struct rte_flow **flow)
5749dad902SMatan Azrad {
5849dad902SMatan Azrad rte_free(*flow);
5949dad902SMatan Azrad *flow = NULL;
6049dad902SMatan Azrad }
6149dad902SMatan Azrad
6249dad902SMatan Azrad static int
bond_flow_validate(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item patterns[],const struct rte_flow_action actions[],struct rte_flow_error * err)6349dad902SMatan Azrad bond_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6449dad902SMatan Azrad const struct rte_flow_item patterns[],
6549dad902SMatan Azrad const struct rte_flow_action actions[],
6649dad902SMatan Azrad struct rte_flow_error *err)
6749dad902SMatan Azrad {
6849dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
6949dad902SMatan Azrad int i;
7049dad902SMatan Azrad int ret;
7149dad902SMatan Azrad
7215e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
7315e34522SLong Wu ret = rte_flow_validate(internals->members[i].port_id, attr,
7449dad902SMatan Azrad patterns, actions, err);
7549dad902SMatan Azrad if (ret) {
7649dad902SMatan Azrad RTE_BOND_LOG(ERR, "Operation rte_flow_validate failed"
7715e34522SLong Wu " for member %d with error %d", i, ret);
7849dad902SMatan Azrad return ret;
7949dad902SMatan Azrad }
8049dad902SMatan Azrad }
8149dad902SMatan Azrad return 0;
8249dad902SMatan Azrad }
8349dad902SMatan Azrad
8449dad902SMatan Azrad static struct rte_flow *
bond_flow_create(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item patterns[],const struct rte_flow_action actions[],struct rte_flow_error * err)8549dad902SMatan Azrad bond_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
8649dad902SMatan Azrad const struct rte_flow_item patterns[],
8749dad902SMatan Azrad const struct rte_flow_action actions[],
8849dad902SMatan Azrad struct rte_flow_error *err)
8949dad902SMatan Azrad {
9049dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
9149dad902SMatan Azrad struct rte_flow *flow;
9249dad902SMatan Azrad int i;
9349dad902SMatan Azrad
9449dad902SMatan Azrad flow = bond_flow_alloc(dev->data->numa_node, attr, patterns, actions);
9549dad902SMatan Azrad if (unlikely(flow == NULL)) {
9649dad902SMatan Azrad rte_flow_error_set(err, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9749dad902SMatan Azrad NULL, rte_strerror(ENOMEM));
9849dad902SMatan Azrad return NULL;
9949dad902SMatan Azrad }
10015e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
10115e34522SLong Wu flow->flows[i] = rte_flow_create(internals->members[i].port_id,
10249dad902SMatan Azrad attr, patterns, actions, err);
10349dad902SMatan Azrad if (unlikely(flow->flows[i] == NULL)) {
10415e34522SLong Wu RTE_BOND_LOG(ERR, "Failed to create flow on member %d",
10549dad902SMatan Azrad i);
10649dad902SMatan Azrad goto err;
10749dad902SMatan Azrad }
10849dad902SMatan Azrad }
10949dad902SMatan Azrad TAILQ_INSERT_TAIL(&internals->flow_list, flow, next);
11049dad902SMatan Azrad return flow;
11149dad902SMatan Azrad err:
11215e34522SLong Wu /* Destroy all members flows. */
11315e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
11449dad902SMatan Azrad if (flow->flows[i] != NULL)
11515e34522SLong Wu rte_flow_destroy(internals->members[i].port_id,
11649dad902SMatan Azrad flow->flows[i], err);
11749dad902SMatan Azrad }
11849dad902SMatan Azrad bond_flow_release(&flow);
11949dad902SMatan Azrad return NULL;
12049dad902SMatan Azrad }
12149dad902SMatan Azrad
12249dad902SMatan Azrad static int
bond_flow_destroy(struct rte_eth_dev * dev,struct rte_flow * flow,struct rte_flow_error * err)12349dad902SMatan Azrad bond_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
12449dad902SMatan Azrad struct rte_flow_error *err)
12549dad902SMatan Azrad {
12649dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
12749dad902SMatan Azrad int i;
12849dad902SMatan Azrad int ret = 0;
12949dad902SMatan Azrad
13015e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
13149dad902SMatan Azrad int lret;
13249dad902SMatan Azrad
13349dad902SMatan Azrad if (unlikely(flow->flows[i] == NULL))
13449dad902SMatan Azrad continue;
13515e34522SLong Wu lret = rte_flow_destroy(internals->members[i].port_id,
13649dad902SMatan Azrad flow->flows[i], err);
13749dad902SMatan Azrad if (unlikely(lret != 0)) {
13815e34522SLong Wu RTE_BOND_LOG(ERR, "Failed to destroy flow on member %d:"
13949dad902SMatan Azrad " %d", i, lret);
14049dad902SMatan Azrad ret = lret;
14149dad902SMatan Azrad }
14249dad902SMatan Azrad }
14349dad902SMatan Azrad TAILQ_REMOVE(&internals->flow_list, flow, next);
14449dad902SMatan Azrad bond_flow_release(&flow);
14549dad902SMatan Azrad return ret;
14649dad902SMatan Azrad }
14749dad902SMatan Azrad
14849dad902SMatan Azrad static int
bond_flow_flush(struct rte_eth_dev * dev,struct rte_flow_error * err)14949dad902SMatan Azrad bond_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *err)
15049dad902SMatan Azrad {
15149dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
15249dad902SMatan Azrad struct rte_flow *flow;
15349dad902SMatan Azrad void *tmp;
15449dad902SMatan Azrad int ret = 0;
15549dad902SMatan Azrad int lret;
15649dad902SMatan Azrad
15715e34522SLong Wu /* Destroy all bond flows from its members instead of flushing them to
15849dad902SMatan Azrad * keep the LACP flow or any other external flows.
15949dad902SMatan Azrad */
160f1f6ebc0SWilliam Tu RTE_TAILQ_FOREACH_SAFE(flow, &internals->flow_list, next, tmp) {
16149dad902SMatan Azrad lret = bond_flow_destroy(dev, flow, err);
16249dad902SMatan Azrad if (unlikely(lret != 0))
16349dad902SMatan Azrad ret = lret;
16449dad902SMatan Azrad }
16549dad902SMatan Azrad if (unlikely(ret != 0))
16615e34522SLong Wu RTE_BOND_LOG(ERR, "Failed to flush flow in all members");
16749dad902SMatan Azrad return ret;
16849dad902SMatan Azrad }
16949dad902SMatan Azrad
17049dad902SMatan Azrad static int
bond_flow_query_count(struct rte_eth_dev * dev,struct rte_flow * flow,const struct rte_flow_action * action,struct rte_flow_query_count * count,struct rte_flow_error * err)17149dad902SMatan Azrad bond_flow_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
172fb8fd96dSDeclan Doherty const struct rte_flow_action *action,
17349dad902SMatan Azrad struct rte_flow_query_count *count,
17449dad902SMatan Azrad struct rte_flow_error *err)
17549dad902SMatan Azrad {
17649dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
17715e34522SLong Wu struct rte_flow_query_count member_count;
17849dad902SMatan Azrad int i;
17949dad902SMatan Azrad int ret;
18049dad902SMatan Azrad
18149dad902SMatan Azrad count->bytes = 0;
18249dad902SMatan Azrad count->hits = 0;
183*02a2accbSMário Kuka count->bytes_set = 0;
184*02a2accbSMário Kuka count->hits_set = 0;
18515e34522SLong Wu rte_memcpy(&member_count, count, sizeof(member_count));
18615e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
18715e34522SLong Wu ret = rte_flow_query(internals->members[i].port_id,
188fb8fd96dSDeclan Doherty flow->flows[i], action,
18915e34522SLong Wu &member_count, err);
19049dad902SMatan Azrad if (unlikely(ret != 0)) {
19149dad902SMatan Azrad RTE_BOND_LOG(ERR, "Failed to query flow on"
19215e34522SLong Wu " member %d: %d", i, ret);
19349dad902SMatan Azrad return ret;
19449dad902SMatan Azrad }
19515e34522SLong Wu count->bytes += member_count.bytes;
19615e34522SLong Wu count->hits += member_count.hits;
197*02a2accbSMário Kuka count->bytes_set |= member_count.bytes_set;
198*02a2accbSMário Kuka count->hits_set |= member_count.hits_set;
19915e34522SLong Wu member_count.bytes = 0;
20015e34522SLong Wu member_count.hits = 0;
201*02a2accbSMário Kuka member_count.bytes_set = 0;
202*02a2accbSMário Kuka member_count.hits_set = 0;
20349dad902SMatan Azrad }
20449dad902SMatan Azrad return 0;
20549dad902SMatan Azrad }
20649dad902SMatan Azrad
20749dad902SMatan Azrad static int
bond_flow_query(struct rte_eth_dev * dev,struct rte_flow * flow,const struct rte_flow_action * action,void * arg,struct rte_flow_error * err)20849dad902SMatan Azrad bond_flow_query(struct rte_eth_dev *dev, struct rte_flow *flow,
209fb8fd96dSDeclan Doherty const struct rte_flow_action *action, void *arg,
21049dad902SMatan Azrad struct rte_flow_error *err)
21149dad902SMatan Azrad {
212fb8fd96dSDeclan Doherty switch (action->type) {
21349dad902SMatan Azrad case RTE_FLOW_ACTION_TYPE_COUNT:
214fb8fd96dSDeclan Doherty return bond_flow_query_count(dev, flow, action, arg, err);
21549dad902SMatan Azrad default:
21649dad902SMatan Azrad return rte_flow_error_set(err, ENOTSUP,
21749dad902SMatan Azrad RTE_FLOW_ERROR_TYPE_ACTION, arg,
21849dad902SMatan Azrad rte_strerror(ENOTSUP));
21949dad902SMatan Azrad }
22049dad902SMatan Azrad }
22149dad902SMatan Azrad
22249dad902SMatan Azrad static int
bond_flow_isolate(struct rte_eth_dev * dev,int set,struct rte_flow_error * err)22349dad902SMatan Azrad bond_flow_isolate(struct rte_eth_dev *dev, int set,
22449dad902SMatan Azrad struct rte_flow_error *err)
22549dad902SMatan Azrad {
22649dad902SMatan Azrad struct bond_dev_private *internals = dev->data->dev_private;
22749dad902SMatan Azrad int i;
22849dad902SMatan Azrad int ret;
22949dad902SMatan Azrad
23015e34522SLong Wu for (i = 0; i < internals->member_count; i++) {
23115e34522SLong Wu ret = rte_flow_isolate(internals->members[i].port_id, set, err);
23249dad902SMatan Azrad if (unlikely(ret != 0)) {
23349dad902SMatan Azrad RTE_BOND_LOG(ERR, "Operation rte_flow_isolate failed"
23415e34522SLong Wu " for member %d with error %d", i, ret);
23549dad902SMatan Azrad internals->flow_isolated_valid = 0;
23649dad902SMatan Azrad return ret;
23749dad902SMatan Azrad }
23849dad902SMatan Azrad }
23949dad902SMatan Azrad internals->flow_isolated = set;
24049dad902SMatan Azrad internals->flow_isolated_valid = 1;
24149dad902SMatan Azrad return 0;
24249dad902SMatan Azrad }
24349dad902SMatan Azrad
24449dad902SMatan Azrad const struct rte_flow_ops bond_flow_ops = {
24549dad902SMatan Azrad .validate = bond_flow_validate,
24649dad902SMatan Azrad .create = bond_flow_create,
24749dad902SMatan Azrad .destroy = bond_flow_destroy,
24849dad902SMatan Azrad .flush = bond_flow_flush,
24949dad902SMatan Azrad .query = bond_flow_query,
25049dad902SMatan Azrad .isolate = bond_flow_isolate,
25149dad902SMatan Azrad };
252