Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: felix: perform switch setup for tag_8021q

Unlike sja1105, the only other user of the software-defined tag_8021q.c
tagger format, the implementation we choose for the Felix DSA switch
driver preserves full functionality under a vlan_filtering bridge
(i.e. IP termination works through the DSA user ports under all
circumstances).

The tag_8021q protocol just wants:
- Identifying the ingress switch port based on the RX VLAN ID, as seen
by the CPU. We achieve this by using the TCAM engines (which are also
used for tc-flower offload) to push the RX VLAN as a second, outer
tag, on egress towards the CPU port.
- Steering traffic injected into the switch from the network stack
towards the correct front port based on the TX VLAN, and consuming
(popping) that header on the switch's egress.

A tc-flower pseudocode of the static configuration done by the driver
would look like this:

$ tc qdisc add dev <cpu-port> clsact
$ for eth in swp0 swp1 swp2 swp3; do \
tc filter add dev <cpu-port> egress flower indev ${eth} \
action vlan push id <rxvlan> protocol 802.1ad; \
tc filter add dev <cpu-port> ingress protocol 802.1Q flower
vlan_id <txvlan> action vlan pop \
action mirred egress redirect dev ${eth}; \
done

but of course since DSA does not register network interfaces for the CPU
port, this configuration would be impossible for the user to do. Also,
due to the same reason, it is impossible for the user to inadvertently
delete these rules using tc. These rules do not collide in any way with
tc-flower, they just consume some TCAM space, which is something we can
live with.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vladimir Oltean and committed by
Jakub Kicinski
e21268ef 7c83a7c5

+396 -12
+336 -1
drivers/net/dsa/ocelot/felix.c
··· 13 13 #include <soc/mscc/ocelot_ana.h> 14 14 #include <soc/mscc/ocelot_ptp.h> 15 15 #include <soc/mscc/ocelot.h> 16 + #include <linux/dsa/8021q.h> 16 17 #include <linux/platform_device.h> 17 18 #include <linux/packing.h> 18 19 #include <linux/module.h> ··· 24 23 #include <net/pkt_sched.h> 25 24 #include <net/dsa.h> 26 25 #include "felix.h" 26 + 27 + static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid, 28 + bool pvid, bool untagged) 29 + { 30 + struct ocelot_vcap_filter *outer_tagging_rule; 31 + struct ocelot *ocelot = &felix->ocelot; 32 + struct dsa_switch *ds = felix->ds; 33 + int key_length, upstream, err; 34 + 35 + /* We don't need to install the rxvlan into the other ports' filtering 36 + * tables, because we're just pushing the rxvlan when sending towards 37 + * the CPU 38 + */ 39 + if (!pvid) 40 + return 0; 41 + 42 + key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length; 43 + upstream = dsa_upstream_port(ds, port); 44 + 45 + outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), 46 + GFP_KERNEL); 47 + if (!outer_tagging_rule) 48 + return -ENOMEM; 49 + 50 + outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 51 + outer_tagging_rule->prio = 1; 52 + outer_tagging_rule->id.cookie = port; 53 + outer_tagging_rule->id.tc_offload = false; 54 + outer_tagging_rule->block_id = VCAP_ES0; 55 + outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 56 + outer_tagging_rule->lookup = 0; 57 + outer_tagging_rule->ingress_port.value = port; 58 + outer_tagging_rule->ingress_port.mask = GENMASK(key_length - 1, 0); 59 + outer_tagging_rule->egress_port.value = upstream; 60 + outer_tagging_rule->egress_port.mask = GENMASK(key_length - 1, 0); 61 + outer_tagging_rule->action.push_outer_tag = OCELOT_ES0_TAG; 62 + outer_tagging_rule->action.tag_a_tpid_sel = OCELOT_TAG_TPID_SEL_8021AD; 63 + outer_tagging_rule->action.tag_a_vid_sel = 1; 64 + outer_tagging_rule->action.vid_a_val = vid; 65 + 66 + err = ocelot_vcap_filter_add(ocelot, outer_tagging_rule, NULL); 67 + if (err) 68 + kfree(outer_tagging_rule); 69 + 70 + return err; 71 + } 72 + 73 + static int felix_tag_8021q_txvlan_add(struct felix *felix, int port, u16 vid, 74 + bool pvid, bool untagged) 75 + { 76 + struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 77 + struct ocelot *ocelot = &felix->ocelot; 78 + struct dsa_switch *ds = felix->ds; 79 + int upstream, err; 80 + 81 + /* tag_8021q.c assumes we are implementing this via port VLAN 82 + * membership, which we aren't. So we don't need to add any VCAP filter 83 + * for the CPU port. 84 + */ 85 + if (ocelot->ports[port]->is_dsa_8021q_cpu) 86 + return 0; 87 + 88 + untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 89 + if (!untagging_rule) 90 + return -ENOMEM; 91 + 92 + redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 93 + if (!redirect_rule) { 94 + kfree(untagging_rule); 95 + return -ENOMEM; 96 + } 97 + 98 + upstream = dsa_upstream_port(ds, port); 99 + 100 + untagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 101 + untagging_rule->ingress_port_mask = BIT(upstream); 102 + untagging_rule->vlan.vid.value = vid; 103 + untagging_rule->vlan.vid.mask = VLAN_VID_MASK; 104 + untagging_rule->prio = 1; 105 + untagging_rule->id.cookie = port; 106 + untagging_rule->id.tc_offload = false; 107 + untagging_rule->block_id = VCAP_IS1; 108 + untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 109 + untagging_rule->lookup = 0; 110 + untagging_rule->action.vlan_pop_cnt_ena = true; 111 + untagging_rule->action.vlan_pop_cnt = 1; 112 + untagging_rule->action.pag_override_mask = 0xff; 113 + untagging_rule->action.pag_val = port; 114 + 115 + err = ocelot_vcap_filter_add(ocelot, untagging_rule, NULL); 116 + if (err) { 117 + kfree(untagging_rule); 118 + kfree(redirect_rule); 119 + return err; 120 + } 121 + 122 + redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; 123 + redirect_rule->ingress_port_mask = BIT(upstream); 124 + redirect_rule->pag = port; 125 + redirect_rule->prio = 1; 126 + redirect_rule->id.cookie = port; 127 + redirect_rule->id.tc_offload = false; 128 + redirect_rule->block_id = VCAP_IS2; 129 + redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 130 + redirect_rule->lookup = 0; 131 + redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 132 + redirect_rule->action.port_mask = BIT(port); 133 + 134 + err = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); 135 + if (err) { 136 + ocelot_vcap_filter_del(ocelot, untagging_rule); 137 + kfree(redirect_rule); 138 + return err; 139 + } 140 + 141 + return 0; 142 + } 143 + 144 + static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, 145 + u16 flags) 146 + { 147 + bool untagged = flags & BRIDGE_VLAN_INFO_UNTAGGED; 148 + bool pvid = flags & BRIDGE_VLAN_INFO_PVID; 149 + struct ocelot *ocelot = ds->priv; 150 + 151 + if (vid_is_dsa_8021q_rxvlan(vid)) 152 + return felix_tag_8021q_rxvlan_add(ocelot_to_felix(ocelot), 153 + port, vid, pvid, untagged); 154 + 155 + if (vid_is_dsa_8021q_txvlan(vid)) 156 + return felix_tag_8021q_txvlan_add(ocelot_to_felix(ocelot), 157 + port, vid, pvid, untagged); 158 + 159 + return 0; 160 + } 161 + 162 + static int felix_tag_8021q_rxvlan_del(struct felix *felix, int port, u16 vid) 163 + { 164 + struct ocelot_vcap_filter *outer_tagging_rule; 165 + struct ocelot_vcap_block *block_vcap_es0; 166 + struct ocelot *ocelot = &felix->ocelot; 167 + 168 + block_vcap_es0 = &ocelot->block[VCAP_ES0]; 169 + 170 + outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0, 171 + port, false); 172 + /* In rxvlan_add, we had the "if (!pvid) return 0" logic to avoid 173 + * installing outer tagging ES0 rules where they weren't needed. 174 + * But in rxvlan_del, the API doesn't give us the "flags" anymore, 175 + * so that forces us to be slightly sloppy here, and just assume that 176 + * if we didn't find an outer_tagging_rule it means that there was 177 + * none in the first place, i.e. rxvlan_del is called on a non-pvid 178 + * port. This is most probably true though. 179 + */ 180 + if (!outer_tagging_rule) 181 + return 0; 182 + 183 + return ocelot_vcap_filter_del(ocelot, outer_tagging_rule); 184 + } 185 + 186 + static int felix_tag_8021q_txvlan_del(struct felix *felix, int port, u16 vid) 187 + { 188 + struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 189 + struct ocelot_vcap_block *block_vcap_is1; 190 + struct ocelot_vcap_block *block_vcap_is2; 191 + struct ocelot *ocelot = &felix->ocelot; 192 + int err; 193 + 194 + if (ocelot->ports[port]->is_dsa_8021q_cpu) 195 + return 0; 196 + 197 + block_vcap_is1 = &ocelot->block[VCAP_IS1]; 198 + block_vcap_is2 = &ocelot->block[VCAP_IS2]; 199 + 200 + untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, 201 + port, false); 202 + if (!untagging_rule) 203 + return 0; 204 + 205 + err = ocelot_vcap_filter_del(ocelot, untagging_rule); 206 + if (err) 207 + return err; 208 + 209 + redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, 210 + port, false); 211 + if (!redirect_rule) 212 + return 0; 213 + 214 + return ocelot_vcap_filter_del(ocelot, redirect_rule); 215 + } 216 + 217 + static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) 218 + { 219 + struct ocelot *ocelot = ds->priv; 220 + 221 + if (vid_is_dsa_8021q_rxvlan(vid)) 222 + return felix_tag_8021q_rxvlan_del(ocelot_to_felix(ocelot), 223 + port, vid); 224 + 225 + if (vid_is_dsa_8021q_txvlan(vid)) 226 + return felix_tag_8021q_txvlan_del(ocelot_to_felix(ocelot), 227 + port, vid); 228 + 229 + return 0; 230 + } 231 + 232 + static const struct dsa_8021q_ops felix_tag_8021q_ops = { 233 + .vlan_add = felix_tag_8021q_vlan_add, 234 + .vlan_del = felix_tag_8021q_vlan_del, 235 + }; 236 + 237 + /* Alternatively to using the NPI functionality, that same hardware MAC 238 + * connected internally to the enetc or fman DSA master can be configured to 239 + * use the software-defined tag_8021q frame format. As far as the hardware is 240 + * concerned, it thinks it is a "dumb switch" - the queues of the CPU port 241 + * module are now disconnected from it, but can still be accessed through 242 + * register-based MMIO. 243 + */ 244 + static void felix_8021q_cpu_port_init(struct ocelot *ocelot, int port) 245 + { 246 + ocelot->ports[port]->is_dsa_8021q_cpu = true; 247 + ocelot->npi = -1; 248 + 249 + /* Overwrite PGID_CPU with the non-tagging port */ 250 + ocelot_write_rix(ocelot, BIT(port), ANA_PGID_PGID, PGID_CPU); 251 + 252 + ocelot_apply_bridge_fwd_mask(ocelot); 253 + } 254 + 255 + static void felix_8021q_cpu_port_deinit(struct ocelot *ocelot, int port) 256 + { 257 + ocelot->ports[port]->is_dsa_8021q_cpu = false; 258 + 259 + /* Restore PGID_CPU */ 260 + ocelot_write_rix(ocelot, BIT(ocelot->num_phys_ports), ANA_PGID_PGID, 261 + PGID_CPU); 262 + 263 + ocelot_apply_bridge_fwd_mask(ocelot); 264 + } 265 + 266 + static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) 267 + { 268 + struct ocelot *ocelot = ds->priv; 269 + struct felix *felix = ocelot_to_felix(ocelot); 270 + unsigned long cpu_flood; 271 + int port, err; 272 + 273 + felix_8021q_cpu_port_init(ocelot, cpu); 274 + 275 + for (port = 0; port < ds->num_ports; port++) { 276 + if (dsa_is_unused_port(ds, port)) 277 + continue; 278 + 279 + /* This overwrites ocelot_init(): 280 + * Do not forward BPDU frames to the CPU port module, 281 + * for 2 reasons: 282 + * - When these packets are injected from the tag_8021q 283 + * CPU port, we want them to go out, not loop back 284 + * into the system. 285 + * - STP traffic ingressing on a user port should go to 286 + * the tag_8021q CPU port, not to the hardware CPU 287 + * port module. 288 + */ 289 + ocelot_write_gix(ocelot, 290 + ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0), 291 + ANA_PORT_CPU_FWD_BPDU_CFG, port); 292 + } 293 + 294 + /* In tag_8021q mode, the CPU port module is unused. So we 295 + * want to disable flooding of any kind to the CPU port module, 296 + * since packets going there will end in a black hole. 297 + */ 298 + cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 299 + ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_UC); 300 + ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_MC); 301 + 302 + felix->dsa_8021q_ctx = kzalloc(sizeof(*felix->dsa_8021q_ctx), 303 + GFP_KERNEL); 304 + if (!felix->dsa_8021q_ctx) 305 + return -ENOMEM; 306 + 307 + felix->dsa_8021q_ctx->ops = &felix_tag_8021q_ops; 308 + felix->dsa_8021q_ctx->proto = htons(ETH_P_8021AD); 309 + felix->dsa_8021q_ctx->ds = ds; 310 + 311 + err = dsa_8021q_setup(felix->dsa_8021q_ctx, true); 312 + if (err) 313 + goto out_free_dsa_8021_ctx; 314 + 315 + return 0; 316 + 317 + out_free_dsa_8021_ctx: 318 + kfree(felix->dsa_8021q_ctx); 319 + return err; 320 + } 321 + 322 + static void felix_teardown_tag_8021q(struct dsa_switch *ds, int cpu) 323 + { 324 + struct ocelot *ocelot = ds->priv; 325 + struct felix *felix = ocelot_to_felix(ocelot); 326 + int err, port; 327 + 328 + err = dsa_8021q_setup(felix->dsa_8021q_ctx, false); 329 + if (err) 330 + dev_err(ds->dev, "dsa_8021q_setup returned %d", err); 331 + 332 + kfree(felix->dsa_8021q_ctx); 333 + 334 + for (port = 0; port < ds->num_ports; port++) { 335 + if (dsa_is_unused_port(ds, port)) 336 + continue; 337 + 338 + /* Restore the logic from ocelot_init: 339 + * do not forward BPDU frames to the front ports. 340 + */ 341 + ocelot_write_gix(ocelot, 342 + ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), 343 + ANA_PORT_CPU_FWD_BPDU_CFG, 344 + port); 345 + } 346 + 347 + felix_8021q_cpu_port_deinit(ocelot, cpu); 348 + } 27 349 28 350 /* The CPU port module is connected to the Node Processor Interface (NPI). This 29 351 * is the mode through which frames can be injected from and extracted to an ··· 431 107 case DSA_TAG_PROTO_OCELOT: 432 108 err = felix_setup_tag_npi(ds, cpu); 433 109 break; 110 + case DSA_TAG_PROTO_OCELOT_8021Q: 111 + err = felix_setup_tag_8021q(ds, cpu); 112 + break; 434 113 default: 435 114 err = -EPROTONOSUPPORT; 436 115 } ··· 448 121 case DSA_TAG_PROTO_OCELOT: 449 122 felix_teardown_tag_npi(ds, cpu); 450 123 break; 124 + case DSA_TAG_PROTO_OCELOT_8021Q: 125 + felix_teardown_tag_8021q(ds, cpu); 126 + break; 451 127 default: 452 128 break; 453 129 } 454 130 } 455 131 132 + /* This always leaves the switch in a consistent state, because although the 133 + * tag_8021q setup can fail, the NPI setup can't. So either the change is made, 134 + * or the restoration is guaranteed to work. 135 + */ 456 136 static int felix_change_tag_protocol(struct dsa_switch *ds, int cpu, 457 137 enum dsa_tag_protocol proto) 458 138 { ··· 468 134 enum dsa_tag_protocol old_proto = felix->tag_proto; 469 135 int err; 470 136 471 - if (proto != DSA_TAG_PROTO_OCELOT) 137 + if (proto != DSA_TAG_PROTO_OCELOT && 138 + proto != DSA_TAG_PROTO_OCELOT_8021Q) 472 139 return -EPROTONOSUPPORT; 473 140 474 141 felix_del_tag_protocol(ds, cpu, old_proto);
+1
drivers/net/dsa/ocelot/felix.h
··· 48 48 struct lynx_pcs **pcs; 49 49 resource_size_t switch_base; 50 50 resource_size_t imdio_base; 51 + struct dsa_8021q_context *dsa_8021q_ctx; 51 52 enum dsa_tag_protocol tag_proto; 52 53 }; 53 54
+53 -8
drivers/net/ethernet/mscc/ocelot.c
··· 889 889 } 890 890 EXPORT_SYMBOL(ocelot_get_ts_info); 891 891 892 - static void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot) 892 + static u32 ocelot_get_dsa_8021q_cpu_mask(struct ocelot *ocelot) 893 893 { 894 + u32 mask = 0; 894 895 int port; 896 + 897 + for (port = 0; port < ocelot->num_phys_ports; port++) { 898 + struct ocelot_port *ocelot_port = ocelot->ports[port]; 899 + 900 + if (!ocelot_port) 901 + continue; 902 + 903 + if (ocelot_port->is_dsa_8021q_cpu) 904 + mask |= BIT(port); 905 + } 906 + 907 + return mask; 908 + } 909 + 910 + void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot) 911 + { 912 + unsigned long cpu_fwd_mask; 913 + int port; 914 + 915 + /* If a DSA tag_8021q CPU exists, it needs to be included in the 916 + * regular forwarding path of the front ports regardless of whether 917 + * those are bridged or standalone. 918 + * If DSA tag_8021q is not used, this returns 0, which is fine because 919 + * the hardware-based CPU port module can be a destination for packets 920 + * even if it isn't part of PGID_SRC. 921 + */ 922 + cpu_fwd_mask = ocelot_get_dsa_8021q_cpu_mask(ocelot); 895 923 896 924 /* Apply FWD mask. The loop is needed to add/remove the current port as 897 925 * a source for the other ports. 898 926 */ 899 927 for (port = 0; port < ocelot->num_phys_ports; port++) { 900 - if (ocelot->bridge_fwd_mask & BIT(port)) { 901 - unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(port); 928 + struct ocelot_port *ocelot_port = ocelot->ports[port]; 929 + unsigned long mask; 930 + 931 + if (!ocelot_port) { 932 + /* Unused ports can't send anywhere */ 933 + mask = 0; 934 + } else if (ocelot_port->is_dsa_8021q_cpu) { 935 + /* The DSA tag_8021q CPU ports need to be able to 936 + * forward packets to all other ports except for 937 + * themselves 938 + */ 939 + mask = GENMASK(ocelot->num_phys_ports - 1, 0); 940 + mask &= ~cpu_fwd_mask; 941 + } else if (ocelot->bridge_fwd_mask & BIT(port)) { 902 942 int lag; 943 + 944 + mask = ocelot->bridge_fwd_mask & ~BIT(port); 903 945 904 946 for (lag = 0; lag < ocelot->num_phys_ports; lag++) { 905 947 unsigned long bond_mask = ocelot->lags[lag]; ··· 954 912 break; 955 913 } 956 914 } 957 - 958 - ocelot_write_rix(ocelot, mask, 959 - ANA_PGID_PGID, PGID_SRC + port); 960 915 } else { 961 - ocelot_write_rix(ocelot, 0, 962 - ANA_PGID_PGID, PGID_SRC + port); 916 + /* Standalone ports forward only to DSA tag_8021q CPU 917 + * ports (if those exist), or to the hardware CPU port 918 + * module otherwise. 919 + */ 920 + mask = cpu_fwd_mask; 963 921 } 922 + 923 + ocelot_write_rix(ocelot, mask, ANA_PGID_PGID, PGID_SRC + port); 964 924 } 965 925 } 926 + EXPORT_SYMBOL(ocelot_apply_bridge_fwd_mask); 966 927 967 928 void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) 968 929 {
+1
drivers/net/ethernet/mscc/ocelot_vcap.c
··· 1009 1009 1010 1010 return NULL; 1011 1011 } 1012 + EXPORT_SYMBOL(ocelot_vcap_block_find_filter_by_id); 1012 1013 1013 1014 /* If @on=false, then SNAP, ARP, IP and OAM frames will not match on keys based 1014 1015 * on destination and source MAC addresses, but only on higher-level protocol
-3
drivers/net/ethernet/mscc/ocelot_vcap.h
··· 14 14 15 15 int ocelot_vcap_filter_stats_update(struct ocelot *ocelot, 16 16 struct ocelot_vcap_filter *rule); 17 - struct ocelot_vcap_filter * 18 - ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id, 19 - bool tc_offload); 20 17 21 18 void ocelot_detect_vcap_constants(struct ocelot *ocelot); 22 19 int ocelot_vcap_init(struct ocelot *ocelot);
+2
include/soc/mscc/ocelot.h
··· 610 610 phy_interface_t phy_mode; 611 611 612 612 u8 *xmit_template; 613 + bool is_dsa_8021q_cpu; 613 614 }; 614 615 615 616 struct ocelot { ··· 761 760 struct phy_device *phydev); 762 761 int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled); 763 762 void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); 763 + void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot); 764 764 int ocelot_port_bridge_join(struct ocelot *ocelot, int port, 765 765 struct net_device *bridge); 766 766 int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
+3
include/soc/mscc/ocelot_vcap.h
··· 693 693 struct netlink_ext_ack *extack); 694 694 int ocelot_vcap_filter_del(struct ocelot *ocelot, 695 695 struct ocelot_vcap_filter *rule); 696 + struct ocelot_vcap_filter * 697 + ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id, 698 + bool tc_offload); 696 699 697 700 #endif /* _OCELOT_VCAP_H_ */