1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2b737a1eeSGaetan Rivet * Copyright 2017 6WIND S.A. 35feecc57SShahaf Shuler * Copyright 2017 Mellanox Technologies, Ltd 4b737a1eeSGaetan Rivet */ 5b737a1eeSGaetan Rivet 6*33fcf207SAdrien Mazarguil #include <stddef.h> 7*33fcf207SAdrien Mazarguil #include <string.h> 8b737a1eeSGaetan Rivet #include <sys/queue.h> 9b737a1eeSGaetan Rivet 10*33fcf207SAdrien Mazarguil #include <rte_errno.h> 11b737a1eeSGaetan Rivet #include <rte_malloc.h> 12b737a1eeSGaetan Rivet #include <rte_tailq.h> 13b737a1eeSGaetan Rivet #include <rte_flow.h> 14b737a1eeSGaetan Rivet #include <rte_flow_driver.h> 15b737a1eeSGaetan Rivet 16b737a1eeSGaetan Rivet #include "failsafe_private.h" 17b737a1eeSGaetan Rivet 18b737a1eeSGaetan Rivet static struct rte_flow * 19b737a1eeSGaetan Rivet fs_flow_allocate(const struct rte_flow_attr *attr, 20b737a1eeSGaetan Rivet const struct rte_flow_item *items, 21b737a1eeSGaetan Rivet const struct rte_flow_action *actions) 22b737a1eeSGaetan Rivet { 23b737a1eeSGaetan Rivet struct rte_flow *flow; 24*33fcf207SAdrien Mazarguil const struct rte_flow_conv_rule rule = { 25*33fcf207SAdrien Mazarguil .attr_ro = attr, 26*33fcf207SAdrien Mazarguil .pattern_ro = items, 27*33fcf207SAdrien Mazarguil .actions_ro = actions, 28*33fcf207SAdrien Mazarguil }; 29*33fcf207SAdrien Mazarguil struct rte_flow_error error; 30*33fcf207SAdrien Mazarguil int ret; 31b737a1eeSGaetan Rivet 32*33fcf207SAdrien Mazarguil ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, &error); 33*33fcf207SAdrien Mazarguil if (ret < 0) { 34*33fcf207SAdrien Mazarguil ERROR("Unable to process flow rule (%s): %s", 35*33fcf207SAdrien Mazarguil error.message ? error.message : "unspecified", 36*33fcf207SAdrien Mazarguil strerror(rte_errno)); 37*33fcf207SAdrien Mazarguil return NULL; 38*33fcf207SAdrien Mazarguil } 39*33fcf207SAdrien Mazarguil flow = rte_zmalloc(NULL, offsetof(struct rte_flow, rule) + ret, 40b737a1eeSGaetan Rivet RTE_CACHE_LINE_SIZE); 41b737a1eeSGaetan Rivet if (flow == NULL) { 42b737a1eeSGaetan Rivet ERROR("Could not allocate new flow"); 43b737a1eeSGaetan Rivet return NULL; 44b737a1eeSGaetan Rivet } 45*33fcf207SAdrien Mazarguil ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &flow->rule, ret, &rule, 46*33fcf207SAdrien Mazarguil &error); 47*33fcf207SAdrien Mazarguil if (ret < 0) { 48*33fcf207SAdrien Mazarguil ERROR("Failed to copy flow rule (%s): %s", 49*33fcf207SAdrien Mazarguil error.message ? error.message : "unspecified", 50*33fcf207SAdrien Mazarguil strerror(rte_errno)); 51b737a1eeSGaetan Rivet rte_free(flow); 52b737a1eeSGaetan Rivet return NULL; 53b737a1eeSGaetan Rivet } 54b737a1eeSGaetan Rivet return flow; 55b737a1eeSGaetan Rivet } 56b737a1eeSGaetan Rivet 57b737a1eeSGaetan Rivet static void 58b737a1eeSGaetan Rivet fs_flow_release(struct rte_flow **flow) 59b737a1eeSGaetan Rivet { 60b737a1eeSGaetan Rivet rte_free(*flow); 61b737a1eeSGaetan Rivet *flow = NULL; 62b737a1eeSGaetan Rivet } 63b737a1eeSGaetan Rivet 64b737a1eeSGaetan Rivet static int 65b737a1eeSGaetan Rivet fs_flow_validate(struct rte_eth_dev *dev, 66b737a1eeSGaetan Rivet const struct rte_flow_attr *attr, 67b737a1eeSGaetan Rivet const struct rte_flow_item patterns[], 68b737a1eeSGaetan Rivet const struct rte_flow_action actions[], 69b737a1eeSGaetan Rivet struct rte_flow_error *error) 70b737a1eeSGaetan Rivet { 71b737a1eeSGaetan Rivet struct sub_device *sdev; 72b737a1eeSGaetan Rivet uint8_t i; 73b737a1eeSGaetan Rivet int ret; 74b737a1eeSGaetan Rivet 75655fcd68SMatan Azrad fs_lock(dev, 0); 76b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 77b737a1eeSGaetan Rivet DEBUG("Calling rte_flow_validate on sub_device %d", i); 78b737a1eeSGaetan Rivet ret = rte_flow_validate(PORT_ID(sdev), 79b737a1eeSGaetan Rivet attr, patterns, actions, error); 80ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 81b737a1eeSGaetan Rivet ERROR("Operation rte_flow_validate failed for sub_device %d" 82b737a1eeSGaetan Rivet " with error %d", i, ret); 83655fcd68SMatan Azrad fs_unlock(dev, 0); 84b737a1eeSGaetan Rivet return ret; 85b737a1eeSGaetan Rivet } 86b737a1eeSGaetan Rivet } 87655fcd68SMatan Azrad fs_unlock(dev, 0); 88b737a1eeSGaetan Rivet return 0; 89b737a1eeSGaetan Rivet } 90b737a1eeSGaetan Rivet 91b737a1eeSGaetan Rivet static struct rte_flow * 92b737a1eeSGaetan Rivet fs_flow_create(struct rte_eth_dev *dev, 93b737a1eeSGaetan Rivet const struct rte_flow_attr *attr, 94b737a1eeSGaetan Rivet const struct rte_flow_item patterns[], 95b737a1eeSGaetan Rivet const struct rte_flow_action actions[], 96b737a1eeSGaetan Rivet struct rte_flow_error *error) 97b737a1eeSGaetan Rivet { 98b737a1eeSGaetan Rivet struct sub_device *sdev; 99b737a1eeSGaetan Rivet struct rte_flow *flow; 100b737a1eeSGaetan Rivet uint8_t i; 101b737a1eeSGaetan Rivet 102655fcd68SMatan Azrad fs_lock(dev, 0); 103b737a1eeSGaetan Rivet flow = fs_flow_allocate(attr, patterns, actions); 104b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 105b737a1eeSGaetan Rivet flow->flows[i] = rte_flow_create(PORT_ID(sdev), 106b737a1eeSGaetan Rivet attr, patterns, actions, error); 107ae80146cSMatan Azrad if (flow->flows[i] == NULL && fs_err(sdev, -rte_errno)) { 108b737a1eeSGaetan Rivet ERROR("Failed to create flow on sub_device %d", 109b737a1eeSGaetan Rivet i); 110b737a1eeSGaetan Rivet goto err; 111b737a1eeSGaetan Rivet } 112b737a1eeSGaetan Rivet } 113b737a1eeSGaetan Rivet TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next); 114655fcd68SMatan Azrad fs_unlock(dev, 0); 115b737a1eeSGaetan Rivet return flow; 116b737a1eeSGaetan Rivet err: 117b737a1eeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 118b737a1eeSGaetan Rivet if (flow->flows[i] != NULL) 119b737a1eeSGaetan Rivet rte_flow_destroy(PORT_ID(sdev), 120b737a1eeSGaetan Rivet flow->flows[i], error); 121b737a1eeSGaetan Rivet } 122b737a1eeSGaetan Rivet fs_flow_release(&flow); 123655fcd68SMatan Azrad fs_unlock(dev, 0); 124b737a1eeSGaetan Rivet return NULL; 125b737a1eeSGaetan Rivet } 126b737a1eeSGaetan Rivet 127b737a1eeSGaetan Rivet static int 128b737a1eeSGaetan Rivet fs_flow_destroy(struct rte_eth_dev *dev, 129b737a1eeSGaetan Rivet struct rte_flow *flow, 130b737a1eeSGaetan Rivet struct rte_flow_error *error) 131b737a1eeSGaetan Rivet { 132b737a1eeSGaetan Rivet struct sub_device *sdev; 133b737a1eeSGaetan Rivet uint8_t i; 134b737a1eeSGaetan Rivet int ret; 135b737a1eeSGaetan Rivet 136b737a1eeSGaetan Rivet if (flow == NULL) { 137b737a1eeSGaetan Rivet ERROR("Invalid flow"); 138b737a1eeSGaetan Rivet return -EINVAL; 139b737a1eeSGaetan Rivet } 140b737a1eeSGaetan Rivet ret = 0; 141655fcd68SMatan Azrad fs_lock(dev, 0); 142b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 143b737a1eeSGaetan Rivet int local_ret; 144b737a1eeSGaetan Rivet 145b737a1eeSGaetan Rivet if (flow->flows[i] == NULL) 146b737a1eeSGaetan Rivet continue; 147b737a1eeSGaetan Rivet local_ret = rte_flow_destroy(PORT_ID(sdev), 148b737a1eeSGaetan Rivet flow->flows[i], error); 149ae80146cSMatan Azrad if ((local_ret = fs_err(sdev, local_ret))) { 150b737a1eeSGaetan Rivet ERROR("Failed to destroy flow on sub_device %d: %d", 151b737a1eeSGaetan Rivet i, local_ret); 152b737a1eeSGaetan Rivet if (ret == 0) 153b737a1eeSGaetan Rivet ret = local_ret; 154b737a1eeSGaetan Rivet } 155b737a1eeSGaetan Rivet } 156b737a1eeSGaetan Rivet TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); 157b737a1eeSGaetan Rivet fs_flow_release(&flow); 158655fcd68SMatan Azrad fs_unlock(dev, 0); 159b737a1eeSGaetan Rivet return ret; 160b737a1eeSGaetan Rivet } 161b737a1eeSGaetan Rivet 162b737a1eeSGaetan Rivet static int 163b737a1eeSGaetan Rivet fs_flow_flush(struct rte_eth_dev *dev, 164b737a1eeSGaetan Rivet struct rte_flow_error *error) 165b737a1eeSGaetan Rivet { 166b737a1eeSGaetan Rivet struct sub_device *sdev; 167b737a1eeSGaetan Rivet struct rte_flow *flow; 168b737a1eeSGaetan Rivet void *tmp; 169b737a1eeSGaetan Rivet uint8_t i; 170b737a1eeSGaetan Rivet int ret; 171b737a1eeSGaetan Rivet 172655fcd68SMatan Azrad fs_lock(dev, 0); 173b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 174b737a1eeSGaetan Rivet DEBUG("Calling rte_flow_flush on sub_device %d", i); 175b737a1eeSGaetan Rivet ret = rte_flow_flush(PORT_ID(sdev), error); 176ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 177b737a1eeSGaetan Rivet ERROR("Operation rte_flow_flush failed for sub_device %d" 178b737a1eeSGaetan Rivet " with error %d", i, ret); 179655fcd68SMatan Azrad fs_unlock(dev, 0); 180b737a1eeSGaetan Rivet return ret; 181b737a1eeSGaetan Rivet } 182b737a1eeSGaetan Rivet } 183b737a1eeSGaetan Rivet TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) { 184b737a1eeSGaetan Rivet TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); 185b737a1eeSGaetan Rivet fs_flow_release(&flow); 186b737a1eeSGaetan Rivet } 187655fcd68SMatan Azrad fs_unlock(dev, 0); 188b737a1eeSGaetan Rivet return 0; 189b737a1eeSGaetan Rivet } 190b737a1eeSGaetan Rivet 191b737a1eeSGaetan Rivet static int 192b737a1eeSGaetan Rivet fs_flow_query(struct rte_eth_dev *dev, 193b737a1eeSGaetan Rivet struct rte_flow *flow, 194fb8fd96dSDeclan Doherty const struct rte_flow_action *action, 195b737a1eeSGaetan Rivet void *arg, 196b737a1eeSGaetan Rivet struct rte_flow_error *error) 197b737a1eeSGaetan Rivet { 198b737a1eeSGaetan Rivet struct sub_device *sdev; 199b737a1eeSGaetan Rivet 200655fcd68SMatan Azrad fs_lock(dev, 0); 201b737a1eeSGaetan Rivet sdev = TX_SUBDEV(dev); 202b737a1eeSGaetan Rivet if (sdev != NULL) { 203ae80146cSMatan Azrad int ret = rte_flow_query(PORT_ID(sdev), 204ae80146cSMatan Azrad flow->flows[SUB_ID(sdev)], 205fb8fd96dSDeclan Doherty action, arg, error); 206ae80146cSMatan Azrad 207655fcd68SMatan Azrad if ((ret = fs_err(sdev, ret))) { 208655fcd68SMatan Azrad fs_unlock(dev, 0); 209ae80146cSMatan Azrad return ret; 210b737a1eeSGaetan Rivet } 211655fcd68SMatan Azrad } 212655fcd68SMatan Azrad fs_unlock(dev, 0); 213b737a1eeSGaetan Rivet WARN("No active sub_device to query about its flow"); 214b737a1eeSGaetan Rivet return -1; 215b737a1eeSGaetan Rivet } 216b737a1eeSGaetan Rivet 2172cc52cd7SGaetan Rivet static int 2182cc52cd7SGaetan Rivet fs_flow_isolate(struct rte_eth_dev *dev, 2192cc52cd7SGaetan Rivet int set, 2202cc52cd7SGaetan Rivet struct rte_flow_error *error) 2212cc52cd7SGaetan Rivet { 2222cc52cd7SGaetan Rivet struct sub_device *sdev; 2232cc52cd7SGaetan Rivet uint8_t i; 2242cc52cd7SGaetan Rivet int ret; 2252cc52cd7SGaetan Rivet 226655fcd68SMatan Azrad fs_lock(dev, 0); 2272cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 2282cc52cd7SGaetan Rivet if (sdev->state < DEV_PROBED) 2292cc52cd7SGaetan Rivet continue; 2302cc52cd7SGaetan Rivet DEBUG("Calling rte_flow_isolate on sub_device %d", i); 2312cc52cd7SGaetan Rivet if (PRIV(dev)->flow_isolated != sdev->flow_isolated) 2322cc52cd7SGaetan Rivet WARN("flow isolation mode of sub_device %d in incoherent state.", 2332cc52cd7SGaetan Rivet i); 2342cc52cd7SGaetan Rivet ret = rte_flow_isolate(PORT_ID(sdev), set, error); 235ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 2362cc52cd7SGaetan Rivet ERROR("Operation rte_flow_isolate failed for sub_device %d" 2372cc52cd7SGaetan Rivet " with error %d", i, ret); 238655fcd68SMatan Azrad fs_unlock(dev, 0); 2392cc52cd7SGaetan Rivet return ret; 2402cc52cd7SGaetan Rivet } 2412cc52cd7SGaetan Rivet sdev->flow_isolated = set; 2422cc52cd7SGaetan Rivet } 2432cc52cd7SGaetan Rivet PRIV(dev)->flow_isolated = set; 244655fcd68SMatan Azrad fs_unlock(dev, 0); 2452cc52cd7SGaetan Rivet return 0; 2462cc52cd7SGaetan Rivet } 2472cc52cd7SGaetan Rivet 248b737a1eeSGaetan Rivet const struct rte_flow_ops fs_flow_ops = { 249b737a1eeSGaetan Rivet .validate = fs_flow_validate, 250b737a1eeSGaetan Rivet .create = fs_flow_create, 251b737a1eeSGaetan Rivet .destroy = fs_flow_destroy, 252b737a1eeSGaetan Rivet .flush = fs_flow_flush, 253b737a1eeSGaetan Rivet .query = fs_flow_query, 2542cc52cd7SGaetan Rivet .isolate = fs_flow_isolate, 255b737a1eeSGaetan Rivet }; 256