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 6b737a1eeSGaetan Rivet #include <sys/queue.h> 7b737a1eeSGaetan Rivet 8b737a1eeSGaetan Rivet #include <rte_malloc.h> 9b737a1eeSGaetan Rivet #include <rte_tailq.h> 10b737a1eeSGaetan Rivet #include <rte_flow.h> 11b737a1eeSGaetan Rivet #include <rte_flow_driver.h> 12b737a1eeSGaetan Rivet 13b737a1eeSGaetan Rivet #include "failsafe_private.h" 14b737a1eeSGaetan Rivet 15b737a1eeSGaetan Rivet static struct rte_flow * 16b737a1eeSGaetan Rivet fs_flow_allocate(const struct rte_flow_attr *attr, 17b737a1eeSGaetan Rivet const struct rte_flow_item *items, 18b737a1eeSGaetan Rivet const struct rte_flow_action *actions) 19b737a1eeSGaetan Rivet { 20b737a1eeSGaetan Rivet struct rte_flow *flow; 21b737a1eeSGaetan Rivet size_t fdsz; 22b737a1eeSGaetan Rivet 23b737a1eeSGaetan Rivet fdsz = rte_flow_copy(NULL, 0, attr, items, actions); 24b737a1eeSGaetan Rivet flow = rte_zmalloc(NULL, 25b737a1eeSGaetan Rivet sizeof(struct rte_flow) + fdsz, 26b737a1eeSGaetan Rivet RTE_CACHE_LINE_SIZE); 27b737a1eeSGaetan Rivet if (flow == NULL) { 28b737a1eeSGaetan Rivet ERROR("Could not allocate new flow"); 29b737a1eeSGaetan Rivet return NULL; 30b737a1eeSGaetan Rivet } 31b737a1eeSGaetan Rivet flow->fd = (void *)((uintptr_t)flow + sizeof(*flow)); 32b737a1eeSGaetan Rivet if (rte_flow_copy(flow->fd, fdsz, attr, items, actions) != fdsz) { 33b737a1eeSGaetan Rivet ERROR("Failed to copy flow description"); 34b737a1eeSGaetan Rivet rte_free(flow); 35b737a1eeSGaetan Rivet return NULL; 36b737a1eeSGaetan Rivet } 37b737a1eeSGaetan Rivet return flow; 38b737a1eeSGaetan Rivet } 39b737a1eeSGaetan Rivet 40b737a1eeSGaetan Rivet static void 41b737a1eeSGaetan Rivet fs_flow_release(struct rte_flow **flow) 42b737a1eeSGaetan Rivet { 43b737a1eeSGaetan Rivet rte_free(*flow); 44b737a1eeSGaetan Rivet *flow = NULL; 45b737a1eeSGaetan Rivet } 46b737a1eeSGaetan Rivet 47b737a1eeSGaetan Rivet static int 48b737a1eeSGaetan Rivet fs_flow_validate(struct rte_eth_dev *dev, 49b737a1eeSGaetan Rivet const struct rte_flow_attr *attr, 50b737a1eeSGaetan Rivet const struct rte_flow_item patterns[], 51b737a1eeSGaetan Rivet const struct rte_flow_action actions[], 52b737a1eeSGaetan Rivet struct rte_flow_error *error) 53b737a1eeSGaetan Rivet { 54b737a1eeSGaetan Rivet struct sub_device *sdev; 55b737a1eeSGaetan Rivet uint8_t i; 56b737a1eeSGaetan Rivet int ret; 57b737a1eeSGaetan Rivet 58655fcd68SMatan Azrad fs_lock(dev, 0); 59b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 60b737a1eeSGaetan Rivet DEBUG("Calling rte_flow_validate on sub_device %d", i); 61b737a1eeSGaetan Rivet ret = rte_flow_validate(PORT_ID(sdev), 62b737a1eeSGaetan Rivet attr, patterns, actions, error); 63ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 64b737a1eeSGaetan Rivet ERROR("Operation rte_flow_validate failed for sub_device %d" 65b737a1eeSGaetan Rivet " with error %d", i, ret); 66655fcd68SMatan Azrad fs_unlock(dev, 0); 67b737a1eeSGaetan Rivet return ret; 68b737a1eeSGaetan Rivet } 69b737a1eeSGaetan Rivet } 70655fcd68SMatan Azrad fs_unlock(dev, 0); 71b737a1eeSGaetan Rivet return 0; 72b737a1eeSGaetan Rivet } 73b737a1eeSGaetan Rivet 74b737a1eeSGaetan Rivet static struct rte_flow * 75b737a1eeSGaetan Rivet fs_flow_create(struct rte_eth_dev *dev, 76b737a1eeSGaetan Rivet const struct rte_flow_attr *attr, 77b737a1eeSGaetan Rivet const struct rte_flow_item patterns[], 78b737a1eeSGaetan Rivet const struct rte_flow_action actions[], 79b737a1eeSGaetan Rivet struct rte_flow_error *error) 80b737a1eeSGaetan Rivet { 81b737a1eeSGaetan Rivet struct sub_device *sdev; 82b737a1eeSGaetan Rivet struct rte_flow *flow; 83b737a1eeSGaetan Rivet uint8_t i; 84b737a1eeSGaetan Rivet 85655fcd68SMatan Azrad fs_lock(dev, 0); 86b737a1eeSGaetan Rivet flow = fs_flow_allocate(attr, patterns, actions); 87b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 88b737a1eeSGaetan Rivet flow->flows[i] = rte_flow_create(PORT_ID(sdev), 89b737a1eeSGaetan Rivet attr, patterns, actions, error); 90ae80146cSMatan Azrad if (flow->flows[i] == NULL && fs_err(sdev, -rte_errno)) { 91b737a1eeSGaetan Rivet ERROR("Failed to create flow on sub_device %d", 92b737a1eeSGaetan Rivet i); 93b737a1eeSGaetan Rivet goto err; 94b737a1eeSGaetan Rivet } 95b737a1eeSGaetan Rivet } 96b737a1eeSGaetan Rivet TAILQ_INSERT_TAIL(&PRIV(dev)->flow_list, flow, next); 97655fcd68SMatan Azrad fs_unlock(dev, 0); 98b737a1eeSGaetan Rivet return flow; 99b737a1eeSGaetan Rivet err: 100b737a1eeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 101b737a1eeSGaetan Rivet if (flow->flows[i] != NULL) 102b737a1eeSGaetan Rivet rte_flow_destroy(PORT_ID(sdev), 103b737a1eeSGaetan Rivet flow->flows[i], error); 104b737a1eeSGaetan Rivet } 105b737a1eeSGaetan Rivet fs_flow_release(&flow); 106655fcd68SMatan Azrad fs_unlock(dev, 0); 107b737a1eeSGaetan Rivet return NULL; 108b737a1eeSGaetan Rivet } 109b737a1eeSGaetan Rivet 110b737a1eeSGaetan Rivet static int 111b737a1eeSGaetan Rivet fs_flow_destroy(struct rte_eth_dev *dev, 112b737a1eeSGaetan Rivet struct rte_flow *flow, 113b737a1eeSGaetan Rivet struct rte_flow_error *error) 114b737a1eeSGaetan Rivet { 115b737a1eeSGaetan Rivet struct sub_device *sdev; 116b737a1eeSGaetan Rivet uint8_t i; 117b737a1eeSGaetan Rivet int ret; 118b737a1eeSGaetan Rivet 119b737a1eeSGaetan Rivet if (flow == NULL) { 120b737a1eeSGaetan Rivet ERROR("Invalid flow"); 121b737a1eeSGaetan Rivet return -EINVAL; 122b737a1eeSGaetan Rivet } 123b737a1eeSGaetan Rivet ret = 0; 124655fcd68SMatan Azrad fs_lock(dev, 0); 125b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 126b737a1eeSGaetan Rivet int local_ret; 127b737a1eeSGaetan Rivet 128b737a1eeSGaetan Rivet if (flow->flows[i] == NULL) 129b737a1eeSGaetan Rivet continue; 130b737a1eeSGaetan Rivet local_ret = rte_flow_destroy(PORT_ID(sdev), 131b737a1eeSGaetan Rivet flow->flows[i], error); 132ae80146cSMatan Azrad if ((local_ret = fs_err(sdev, local_ret))) { 133b737a1eeSGaetan Rivet ERROR("Failed to destroy flow on sub_device %d: %d", 134b737a1eeSGaetan Rivet i, local_ret); 135b737a1eeSGaetan Rivet if (ret == 0) 136b737a1eeSGaetan Rivet ret = local_ret; 137b737a1eeSGaetan Rivet } 138b737a1eeSGaetan Rivet } 139b737a1eeSGaetan Rivet TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); 140b737a1eeSGaetan Rivet fs_flow_release(&flow); 141655fcd68SMatan Azrad fs_unlock(dev, 0); 142b737a1eeSGaetan Rivet return ret; 143b737a1eeSGaetan Rivet } 144b737a1eeSGaetan Rivet 145b737a1eeSGaetan Rivet static int 146b737a1eeSGaetan Rivet fs_flow_flush(struct rte_eth_dev *dev, 147b737a1eeSGaetan Rivet struct rte_flow_error *error) 148b737a1eeSGaetan Rivet { 149b737a1eeSGaetan Rivet struct sub_device *sdev; 150b737a1eeSGaetan Rivet struct rte_flow *flow; 151b737a1eeSGaetan Rivet void *tmp; 152b737a1eeSGaetan Rivet uint8_t i; 153b737a1eeSGaetan Rivet int ret; 154b737a1eeSGaetan Rivet 155655fcd68SMatan Azrad fs_lock(dev, 0); 156b737a1eeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { 157b737a1eeSGaetan Rivet DEBUG("Calling rte_flow_flush on sub_device %d", i); 158b737a1eeSGaetan Rivet ret = rte_flow_flush(PORT_ID(sdev), error); 159ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 160b737a1eeSGaetan Rivet ERROR("Operation rte_flow_flush failed for sub_device %d" 161b737a1eeSGaetan Rivet " with error %d", i, ret); 162655fcd68SMatan Azrad fs_unlock(dev, 0); 163b737a1eeSGaetan Rivet return ret; 164b737a1eeSGaetan Rivet } 165b737a1eeSGaetan Rivet } 166b737a1eeSGaetan Rivet TAILQ_FOREACH_SAFE(flow, &PRIV(dev)->flow_list, next, tmp) { 167b737a1eeSGaetan Rivet TAILQ_REMOVE(&PRIV(dev)->flow_list, flow, next); 168b737a1eeSGaetan Rivet fs_flow_release(&flow); 169b737a1eeSGaetan Rivet } 170655fcd68SMatan Azrad fs_unlock(dev, 0); 171b737a1eeSGaetan Rivet return 0; 172b737a1eeSGaetan Rivet } 173b737a1eeSGaetan Rivet 174b737a1eeSGaetan Rivet static int 175b737a1eeSGaetan Rivet fs_flow_query(struct rte_eth_dev *dev, 176b737a1eeSGaetan Rivet struct rte_flow *flow, 177*fb8fd96dSDeclan Doherty const struct rte_flow_action *action, 178b737a1eeSGaetan Rivet void *arg, 179b737a1eeSGaetan Rivet struct rte_flow_error *error) 180b737a1eeSGaetan Rivet { 181b737a1eeSGaetan Rivet struct sub_device *sdev; 182b737a1eeSGaetan Rivet 183655fcd68SMatan Azrad fs_lock(dev, 0); 184b737a1eeSGaetan Rivet sdev = TX_SUBDEV(dev); 185b737a1eeSGaetan Rivet if (sdev != NULL) { 186ae80146cSMatan Azrad int ret = rte_flow_query(PORT_ID(sdev), 187ae80146cSMatan Azrad flow->flows[SUB_ID(sdev)], 188*fb8fd96dSDeclan Doherty action, arg, error); 189ae80146cSMatan Azrad 190655fcd68SMatan Azrad if ((ret = fs_err(sdev, ret))) { 191655fcd68SMatan Azrad fs_unlock(dev, 0); 192ae80146cSMatan Azrad return ret; 193b737a1eeSGaetan Rivet } 194655fcd68SMatan Azrad } 195655fcd68SMatan Azrad fs_unlock(dev, 0); 196b737a1eeSGaetan Rivet WARN("No active sub_device to query about its flow"); 197b737a1eeSGaetan Rivet return -1; 198b737a1eeSGaetan Rivet } 199b737a1eeSGaetan Rivet 2002cc52cd7SGaetan Rivet static int 2012cc52cd7SGaetan Rivet fs_flow_isolate(struct rte_eth_dev *dev, 2022cc52cd7SGaetan Rivet int set, 2032cc52cd7SGaetan Rivet struct rte_flow_error *error) 2042cc52cd7SGaetan Rivet { 2052cc52cd7SGaetan Rivet struct sub_device *sdev; 2062cc52cd7SGaetan Rivet uint8_t i; 2072cc52cd7SGaetan Rivet int ret; 2082cc52cd7SGaetan Rivet 209655fcd68SMatan Azrad fs_lock(dev, 0); 2102cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 2112cc52cd7SGaetan Rivet if (sdev->state < DEV_PROBED) 2122cc52cd7SGaetan Rivet continue; 2132cc52cd7SGaetan Rivet DEBUG("Calling rte_flow_isolate on sub_device %d", i); 2142cc52cd7SGaetan Rivet if (PRIV(dev)->flow_isolated != sdev->flow_isolated) 2152cc52cd7SGaetan Rivet WARN("flow isolation mode of sub_device %d in incoherent state.", 2162cc52cd7SGaetan Rivet i); 2172cc52cd7SGaetan Rivet ret = rte_flow_isolate(PORT_ID(sdev), set, error); 218ae80146cSMatan Azrad if ((ret = fs_err(sdev, ret))) { 2192cc52cd7SGaetan Rivet ERROR("Operation rte_flow_isolate failed for sub_device %d" 2202cc52cd7SGaetan Rivet " with error %d", i, ret); 221655fcd68SMatan Azrad fs_unlock(dev, 0); 2222cc52cd7SGaetan Rivet return ret; 2232cc52cd7SGaetan Rivet } 2242cc52cd7SGaetan Rivet sdev->flow_isolated = set; 2252cc52cd7SGaetan Rivet } 2262cc52cd7SGaetan Rivet PRIV(dev)->flow_isolated = set; 227655fcd68SMatan Azrad fs_unlock(dev, 0); 2282cc52cd7SGaetan Rivet return 0; 2292cc52cd7SGaetan Rivet } 2302cc52cd7SGaetan Rivet 231b737a1eeSGaetan Rivet const struct rte_flow_ops fs_flow_ops = { 232b737a1eeSGaetan Rivet .validate = fs_flow_validate, 233b737a1eeSGaetan Rivet .create = fs_flow_create, 234b737a1eeSGaetan Rivet .destroy = fs_flow_destroy, 235b737a1eeSGaetan Rivet .flush = fs_flow_flush, 236b737a1eeSGaetan Rivet .query = fs_flow_query, 2372cc52cd7SGaetan Rivet .isolate = fs_flow_isolate, 238b737a1eeSGaetan Rivet }; 239