1 // SPDX-License-Identifier: GPL-2.0-only 2 /**************************************************************************** 3 * Driver for Solarflare network controllers and boards 4 * Copyright 2022 Xilinx Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation, incorporated herein by reference. 9 */ 10 11 #include "tc_bindings.h" 12 #include "tc.h" 13 #include "tc_encap_actions.h" 14 15 struct efx_tc_block_binding { 16 struct list_head list; 17 struct efx_nic *efx; 18 struct efx_rep *efv; 19 struct net_device *otherdev; /* may actually be us */ 20 struct flow_block *block; 21 }; 22 23 static struct efx_tc_block_binding *efx_tc_find_binding(struct efx_nic *efx, 24 struct net_device *otherdev) 25 { 26 struct efx_tc_block_binding *binding; 27 28 ASSERT_RTNL(); 29 list_for_each_entry(binding, &efx->tc->block_list, list) 30 if (binding->otherdev == otherdev) 31 return binding; 32 return NULL; 33 } 34 35 static int efx_tc_block_cb(enum tc_setup_type type, void *type_data, 36 void *cb_priv) 37 { 38 struct efx_tc_block_binding *binding = cb_priv; 39 struct flow_cls_offload *tcf = type_data; 40 41 switch (type) { 42 case TC_SETUP_CLSFLOWER: 43 return efx_tc_flower(binding->efx, binding->otherdev, 44 tcf, binding->efv); 45 default: 46 return -EOPNOTSUPP; 47 } 48 } 49 50 void efx_tc_block_unbind(void *cb_priv) 51 { 52 struct efx_tc_block_binding *binding = cb_priv; 53 54 list_del(&binding->list); 55 kfree(binding); 56 } 57 58 static struct efx_tc_block_binding *efx_tc_create_binding( 59 struct efx_nic *efx, struct efx_rep *efv, 60 struct net_device *otherdev, struct flow_block *block) 61 { 62 struct efx_tc_block_binding *binding = kmalloc(sizeof(*binding), GFP_KERNEL); 63 64 if (!binding) 65 return ERR_PTR(-ENOMEM); 66 binding->efx = efx; 67 binding->efv = efv; 68 binding->otherdev = otherdev; 69 binding->block = block; 70 list_add(&binding->list, &efx->tc->block_list); 71 return binding; 72 } 73 74 int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx, 75 struct flow_block_offload *tcb, struct efx_rep *efv) 76 { 77 struct efx_tc_block_binding *binding; 78 struct flow_block_cb *block_cb; 79 int rc; 80 81 if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 82 return -EOPNOTSUPP; 83 84 if (WARN_ON(!efx->tc)) 85 return -ENETDOWN; 86 87 switch (tcb->command) { 88 case FLOW_BLOCK_BIND: 89 binding = efx_tc_create_binding(efx, efv, net_dev, tcb->block); 90 if (IS_ERR(binding)) 91 return PTR_ERR(binding); 92 block_cb = flow_block_cb_alloc(efx_tc_block_cb, binding, 93 binding, efx_tc_block_unbind); 94 rc = PTR_ERR_OR_ZERO(block_cb); 95 netif_dbg(efx, drv, efx->net_dev, 96 "bind %sdirect block for device %s, rc %d\n", 97 net_dev == efx->net_dev ? "" : 98 efv ? "semi" : "in", 99 net_dev ? net_dev->name : NULL, rc); 100 if (rc) { 101 list_del(&binding->list); 102 kfree(binding); 103 } else { 104 flow_block_cb_add(block_cb, tcb); 105 } 106 return rc; 107 case FLOW_BLOCK_UNBIND: 108 binding = efx_tc_find_binding(efx, net_dev); 109 if (binding) { 110 block_cb = flow_block_cb_lookup(tcb->block, 111 efx_tc_block_cb, 112 binding); 113 if (block_cb) { 114 flow_block_cb_remove(block_cb, tcb); 115 netif_dbg(efx, drv, efx->net_dev, 116 "unbound %sdirect block for device %s\n", 117 net_dev == efx->net_dev ? "" : 118 binding->efv ? "semi" : "in", 119 net_dev ? net_dev->name : NULL); 120 return 0; 121 } 122 } 123 /* If we're in driver teardown, then we expect to have 124 * already unbound all our blocks (we did it early while 125 * we still had MCDI to remove the filters), so getting 126 * unbind callbacks now isn't a problem. 127 */ 128 netif_cond_dbg(efx, drv, efx->net_dev, 129 !efx->tc->up, warn, 130 "%sdirect block unbind for device %s, was never bound\n", 131 net_dev == efx->net_dev ? "" : "in", 132 net_dev ? net_dev->name : NULL); 133 return -ENOENT; 134 default: 135 return -EOPNOTSUPP; 136 } 137 } 138 139 int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch, 140 void *cb_priv, enum tc_setup_type type, 141 void *type_data, void *data, 142 void (*cleanup)(struct flow_block_cb *block_cb)) 143 { 144 struct flow_block_offload *tcb = type_data; 145 struct efx_tc_block_binding *binding; 146 struct flow_block_cb *block_cb; 147 struct efx_nic *efx = cb_priv; 148 bool is_ovs_int_port; 149 int rc; 150 151 if (!net_dev) 152 return -EOPNOTSUPP; 153 154 if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS && 155 tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) 156 return -EOPNOTSUPP; 157 158 is_ovs_int_port = netif_is_ovs_master(net_dev); 159 if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS && 160 !is_ovs_int_port) 161 return -EOPNOTSUPP; 162 163 if (is_ovs_int_port) 164 return -EOPNOTSUPP; 165 166 switch (type) { 167 case TC_SETUP_BLOCK: 168 switch (tcb->command) { 169 case FLOW_BLOCK_BIND: 170 binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block); 171 if (IS_ERR(binding)) 172 return PTR_ERR(binding); 173 block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding, 174 binding, efx_tc_block_unbind, 175 tcb, net_dev, sch, data, binding, 176 cleanup); 177 rc = PTR_ERR_OR_ZERO(block_cb); 178 netif_dbg(efx, drv, efx->net_dev, 179 "bind indr block for device %s, rc %d\n", 180 net_dev ? net_dev->name : NULL, rc); 181 if (rc) { 182 list_del(&binding->list); 183 kfree(binding); 184 } else { 185 flow_block_cb_add(block_cb, tcb); 186 } 187 return rc; 188 case FLOW_BLOCK_UNBIND: 189 binding = efx_tc_find_binding(efx, net_dev); 190 if (!binding) 191 return -ENOENT; 192 block_cb = flow_block_cb_lookup(tcb->block, 193 efx_tc_block_cb, 194 binding); 195 if (!block_cb) 196 return -ENOENT; 197 flow_indr_block_cb_remove(block_cb, tcb); 198 netif_dbg(efx, drv, efx->net_dev, 199 "unbind indr block for device %s\n", 200 net_dev ? net_dev->name : NULL); 201 return 0; 202 default: 203 return -EOPNOTSUPP; 204 } 205 default: 206 return -EOPNOTSUPP; 207 } 208 } 209 210 /* .ndo_setup_tc implementation 211 * Entry point for flower block and filter management. 212 */ 213 int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type, 214 void *type_data) 215 { 216 struct efx_nic *efx = efx_netdev_priv(net_dev); 217 218 if (efx->type->is_vf) 219 return -EOPNOTSUPP; 220 if (!efx->tc) 221 return -EOPNOTSUPP; 222 223 if (type == TC_SETUP_CLSFLOWER) 224 return efx_tc_flower(efx, net_dev, type_data, NULL); 225 if (type == TC_SETUP_BLOCK) 226 return efx_tc_setup_block(net_dev, efx, type_data, NULL); 227 228 return -EOPNOTSUPP; 229 } 230 231 int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event, 232 struct net_device *net_dev) 233 { 234 if (efx->type->is_vf) 235 return NOTIFY_DONE; 236 237 if (event == NETDEV_UNREGISTER) 238 efx_tc_unregister_egdev(efx, net_dev); 239 240 return NOTIFY_OK; 241 } 242