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

Merge branch 'sfc-add-basic-flower-matches-to-offload'

Edward Cree says:

====================
sfc: add basic flower matches to offload

Support offloading TC flower rules with matches on L2-L4 fields.
====================

Link: https://lore.kernel.org/r/cover.1667412458.git.ecree.xilinx@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+286 -12
+131
drivers/net/ethernet/sfc/mae.c
··· 250 250 } 251 251 } 252 252 253 + /* Validate field mask against hardware capabilities. Captures caller's 'rc' */ 254 + #define CHECK(_mcdi, _field) ({ \ 255 + enum mask_type typ = classify_mask((const u8 *)&mask->_field, \ 256 + sizeof(mask->_field)); \ 257 + \ 258 + rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 259 + typ); \ 260 + if (rc) \ 261 + NL_SET_ERR_MSG_FMT_MOD(extack, \ 262 + "No support for %s mask in field %s", \ 263 + mask_type_name(typ), #_field); \ 264 + rc; \ 265 + }) 266 + /* Booleans need special handling */ 267 + #define CHECK_BIT(_mcdi, _field) ({ \ 268 + enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \ 269 + \ 270 + rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 271 + typ); \ 272 + if (rc) \ 273 + NL_SET_ERR_MSG_FMT_MOD(extack, \ 274 + "No support for %s mask in field %s", \ 275 + mask_type_name(typ), #_field); \ 276 + rc; \ 277 + }) 278 + 253 279 int efx_mae_match_check_caps(struct efx_nic *efx, 254 280 const struct efx_tc_match_fields *mask, 255 281 struct netlink_ext_ack *extack) ··· 295 269 mask_type_name(ingress_port_mask_type)); 296 270 return rc; 297 271 } 272 + if (CHECK(ETHER_TYPE, eth_proto) || 273 + CHECK(VLAN0_TCI, vlan_tci[0]) || 274 + CHECK(VLAN0_PROTO, vlan_proto[0]) || 275 + CHECK(VLAN1_TCI, vlan_tci[1]) || 276 + CHECK(VLAN1_PROTO, vlan_proto[1]) || 277 + CHECK(ETH_SADDR, eth_saddr) || 278 + CHECK(ETH_DADDR, eth_daddr) || 279 + CHECK(IP_PROTO, ip_proto) || 280 + CHECK(IP_TOS, ip_tos) || 281 + CHECK(IP_TTL, ip_ttl) || 282 + CHECK(SRC_IP4, src_ip) || 283 + CHECK(DST_IP4, dst_ip) || 284 + #ifdef CONFIG_IPV6 285 + CHECK(SRC_IP6, src_ip6) || 286 + CHECK(DST_IP6, dst_ip6) || 287 + #endif 288 + CHECK(L4_SPORT, l4_sport) || 289 + CHECK(L4_DPORT, l4_dport) || 290 + CHECK(TCP_FLAGS, tcp_flags) || 291 + CHECK_BIT(IS_IP_FRAG, ip_frag) || 292 + CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) || 293 + CHECK(RECIRC_ID, recirc_id)) 294 + return rc; 298 295 return 0; 299 296 } 297 + #undef CHECK_BIT 298 + #undef CHECK 300 299 301 300 static bool efx_mae_asl_id(u32 id) 302 301 { ··· 490 439 } 491 440 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 492 441 match->mask.ingress_port); 442 + EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 443 + MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 444 + match->value.ip_frag, 445 + MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 446 + match->value.ip_firstfrag); 447 + EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 448 + MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 449 + match->mask.ip_frag, 450 + MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 451 + match->mask.ip_firstfrag); 493 452 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 494 453 match->value.recirc_id); 495 454 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 496 455 match->mask.recirc_id); 456 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 457 + match->value.eth_proto); 458 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 459 + match->mask.eth_proto); 460 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 461 + match->value.vlan_tci[0]); 462 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 463 + match->mask.vlan_tci[0]); 464 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 465 + match->value.vlan_proto[0]); 466 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 467 + match->mask.vlan_proto[0]); 468 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 469 + match->value.vlan_tci[1]); 470 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 471 + match->mask.vlan_tci[1]); 472 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 473 + match->value.vlan_proto[1]); 474 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 475 + match->mask.vlan_proto[1]); 476 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 477 + match->value.eth_saddr, ETH_ALEN); 478 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 479 + match->mask.eth_saddr, ETH_ALEN); 480 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 481 + match->value.eth_daddr, ETH_ALEN); 482 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 483 + match->mask.eth_daddr, ETH_ALEN); 484 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 485 + match->value.ip_proto); 486 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 487 + match->mask.ip_proto); 488 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 489 + match->value.ip_tos); 490 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 491 + match->mask.ip_tos); 492 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 493 + match->value.ip_ttl); 494 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 495 + match->mask.ip_ttl); 496 + MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 497 + match->value.src_ip); 498 + MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 499 + match->mask.src_ip); 500 + MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 501 + match->value.dst_ip); 502 + MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 503 + match->mask.dst_ip); 504 + #ifdef CONFIG_IPV6 505 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 506 + &match->value.src_ip6, sizeof(struct in6_addr)); 507 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 508 + &match->mask.src_ip6, sizeof(struct in6_addr)); 509 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 510 + &match->value.dst_ip6, sizeof(struct in6_addr)); 511 + memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 512 + &match->mask.dst_ip6, sizeof(struct in6_addr)); 513 + #endif 514 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 515 + match->value.l4_sport); 516 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 517 + match->mask.l4_sport); 518 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 519 + match->value.l4_dport); 520 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 521 + match->mask.l4_dport); 522 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 523 + match->value.tcp_flags); 524 + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 525 + match->mask.tcp_flags); 497 526 return 0; 498 527 } 499 528
+12
drivers/net/ethernet/sfc/mcdi.h
··· 224 224 #define MCDI_WORD(_buf, _field) \ 225 225 ((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \ 226 226 le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) 227 + /* Write a 16-bit field defined in the protocol as being big-endian. */ 228 + #define MCDI_STRUCT_SET_WORD_BE(_buf, _field, _value) do { \ 229 + BUILD_BUG_ON(_field ## _LEN != 2); \ 230 + BUILD_BUG_ON(_field ## _OFST & 1); \ 231 + *(__force __be16 *)MCDI_STRUCT_PTR(_buf, _field) = (_value); \ 232 + } while (0) 227 233 #define MCDI_SET_DWORD(_buf, _field, _value) \ 228 234 EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value) 229 235 #define MCDI_STRUCT_SET_DWORD(_buf, _field, _value) \ 230 236 EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value) 231 237 #define MCDI_DWORD(_buf, _field) \ 232 238 EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0) 239 + /* Write a 32-bit field defined in the protocol as being big-endian. */ 240 + #define MCDI_STRUCT_SET_DWORD_BE(_buf, _field, _value) do { \ 241 + BUILD_BUG_ON(_field ## _LEN != 4); \ 242 + BUILD_BUG_ON(_field ## _OFST & 3); \ 243 + *(__force __be32 *)MCDI_STRUCT_PTR(_buf, _field) = (_value); \ 244 + } while (0) 233 245 #define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \ 234 246 EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \ 235 247 MC_CMD_ ## _name1, _value1)
+127 -12
drivers/net/ethernet/sfc/tc.c
··· 124 124 kfree(rule); 125 125 } 126 126 127 + /* Boilerplate for the simple 'copy a field' cases */ 128 + #define _MAP_KEY_AND_MASK(_name, _type, _tcget, _tcfield, _field) \ 129 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_##_name)) { \ 130 + struct flow_match_##_type fm; \ 131 + \ 132 + flow_rule_match_##_tcget(rule, &fm); \ 133 + match->value._field = fm.key->_tcfield; \ 134 + match->mask._field = fm.mask->_tcfield; \ 135 + } 136 + #define MAP_KEY_AND_MASK(_name, _type, _tcfield, _field) \ 137 + _MAP_KEY_AND_MASK(_name, _type, _type, _tcfield, _field) 138 + #define MAP_ENC_KEY_AND_MASK(_name, _type, _tcget, _tcfield, _field) \ 139 + _MAP_KEY_AND_MASK(ENC_##_name, _type, _tcget, _tcfield, _field) 140 + 127 141 static int efx_tc_flower_parse_match(struct efx_nic *efx, 128 142 struct flow_rule *rule, 129 143 struct efx_tc_match *match, 130 144 struct netlink_ext_ack *extack) 131 145 { 132 146 struct flow_dissector *dissector = rule->match.dissector; 147 + unsigned char ipv = 0; 133 148 149 + /* Owing to internal TC infelicities, the IPV6_ADDRS key might be set 150 + * even on IPv4 filters; so rather than relying on dissector->used_keys 151 + * we check the addr_type in the CONTROL key. If we don't find it (or 152 + * it's masked, which should never happen), we treat both IPV4_ADDRS 153 + * and IPV6_ADDRS as absent. 154 + */ 134 155 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 135 156 struct flow_match_control fm; 136 157 137 158 flow_rule_match_control(rule, &fm); 159 + if (IS_ALL_ONES(fm.mask->addr_type)) 160 + switch (fm.key->addr_type) { 161 + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 162 + ipv = 4; 163 + break; 164 + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 165 + ipv = 6; 166 + break; 167 + default: 168 + break; 169 + } 138 170 139 - if (fm.mask->flags) { 171 + if (fm.mask->flags & FLOW_DIS_IS_FRAGMENT) { 172 + match->value.ip_frag = fm.key->flags & FLOW_DIS_IS_FRAGMENT; 173 + match->mask.ip_frag = true; 174 + } 175 + if (fm.mask->flags & FLOW_DIS_FIRST_FRAG) { 176 + match->value.ip_firstfrag = fm.key->flags & FLOW_DIS_FIRST_FRAG; 177 + match->mask.ip_firstfrag = true; 178 + } 179 + if (fm.mask->flags & ~(FLOW_DIS_IS_FRAGMENT | FLOW_DIS_FIRST_FRAG)) { 140 180 NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported match on control.flags %#x", 141 181 fm.mask->flags); 142 182 return -EOPNOTSUPP; ··· 184 144 } 185 145 if (dissector->used_keys & 186 146 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 187 - BIT(FLOW_DISSECTOR_KEY_BASIC))) { 147 + BIT(FLOW_DISSECTOR_KEY_BASIC) | 148 + BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 149 + BIT(FLOW_DISSECTOR_KEY_VLAN) | 150 + BIT(FLOW_DISSECTOR_KEY_CVLAN) | 151 + BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 152 + BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 153 + BIT(FLOW_DISSECTOR_KEY_PORTS) | 154 + BIT(FLOW_DISSECTOR_KEY_TCP) | 155 + BIT(FLOW_DISSECTOR_KEY_IP))) { 188 156 NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x", 189 157 dissector->used_keys); 190 158 return -EOPNOTSUPP; 191 159 } 192 160 193 - if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 194 - struct flow_match_basic fm; 195 - 196 - flow_rule_match_basic(rule, &fm); 197 - if (fm.mask->n_proto) { 198 - NL_SET_ERR_MSG_MOD(extack, "Unsupported eth_proto match"); 199 - return -EOPNOTSUPP; 161 + MAP_KEY_AND_MASK(BASIC, basic, n_proto, eth_proto); 162 + /* Make sure we're IP if any L3/L4 keys used. */ 163 + if (!IS_ALL_ONES(match->mask.eth_proto) || 164 + !(match->value.eth_proto == htons(ETH_P_IP) || 165 + match->value.eth_proto == htons(ETH_P_IPV6))) 166 + if (dissector->used_keys & 167 + (BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 168 + BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 169 + BIT(FLOW_DISSECTOR_KEY_PORTS) | 170 + BIT(FLOW_DISSECTOR_KEY_IP) | 171 + BIT(FLOW_DISSECTOR_KEY_TCP))) { 172 + NL_SET_ERR_MSG_FMT_MOD(extack, "L3/L4 flower keys %#x require protocol ipv[46]", 173 + dissector->used_keys); 174 + return -EINVAL; 200 175 } 201 - if (fm.mask->ip_proto) { 202 - NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match"); 203 - return -EOPNOTSUPP; 176 + 177 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 178 + struct flow_match_vlan fm; 179 + 180 + flow_rule_match_vlan(rule, &fm); 181 + if (fm.mask->vlan_id || fm.mask->vlan_priority || fm.mask->vlan_tpid) { 182 + match->value.vlan_proto[0] = fm.key->vlan_tpid; 183 + match->mask.vlan_proto[0] = fm.mask->vlan_tpid; 184 + match->value.vlan_tci[0] = cpu_to_be16(fm.key->vlan_priority << 13 | 185 + fm.key->vlan_id); 186 + match->mask.vlan_tci[0] = cpu_to_be16(fm.mask->vlan_priority << 13 | 187 + fm.mask->vlan_id); 204 188 } 205 189 } 190 + 191 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) { 192 + struct flow_match_vlan fm; 193 + 194 + flow_rule_match_cvlan(rule, &fm); 195 + if (fm.mask->vlan_id || fm.mask->vlan_priority || fm.mask->vlan_tpid) { 196 + match->value.vlan_proto[1] = fm.key->vlan_tpid; 197 + match->mask.vlan_proto[1] = fm.mask->vlan_tpid; 198 + match->value.vlan_tci[1] = cpu_to_be16(fm.key->vlan_priority << 13 | 199 + fm.key->vlan_id); 200 + match->mask.vlan_tci[1] = cpu_to_be16(fm.mask->vlan_priority << 13 | 201 + fm.mask->vlan_id); 202 + } 203 + } 204 + 205 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 206 + struct flow_match_eth_addrs fm; 207 + 208 + flow_rule_match_eth_addrs(rule, &fm); 209 + ether_addr_copy(match->value.eth_saddr, fm.key->src); 210 + ether_addr_copy(match->value.eth_daddr, fm.key->dst); 211 + ether_addr_copy(match->mask.eth_saddr, fm.mask->src); 212 + ether_addr_copy(match->mask.eth_daddr, fm.mask->dst); 213 + } 214 + 215 + MAP_KEY_AND_MASK(BASIC, basic, ip_proto, ip_proto); 216 + /* Make sure we're TCP/UDP if any L4 keys used. */ 217 + if ((match->value.ip_proto != IPPROTO_UDP && 218 + match->value.ip_proto != IPPROTO_TCP) || !IS_ALL_ONES(match->mask.ip_proto)) 219 + if (dissector->used_keys & 220 + (BIT(FLOW_DISSECTOR_KEY_PORTS) | 221 + BIT(FLOW_DISSECTOR_KEY_TCP))) { 222 + NL_SET_ERR_MSG_FMT_MOD(extack, "L4 flower keys %#x require ipproto udp or tcp", 223 + dissector->used_keys); 224 + return -EINVAL; 225 + } 226 + MAP_KEY_AND_MASK(IP, ip, tos, ip_tos); 227 + MAP_KEY_AND_MASK(IP, ip, ttl, ip_ttl); 228 + if (ipv == 4) { 229 + MAP_KEY_AND_MASK(IPV4_ADDRS, ipv4_addrs, src, src_ip); 230 + MAP_KEY_AND_MASK(IPV4_ADDRS, ipv4_addrs, dst, dst_ip); 231 + } 232 + #ifdef CONFIG_IPV6 233 + else if (ipv == 6) { 234 + MAP_KEY_AND_MASK(IPV6_ADDRS, ipv6_addrs, src, src_ip6); 235 + MAP_KEY_AND_MASK(IPV6_ADDRS, ipv6_addrs, dst, dst_ip6); 236 + } 237 + #endif 238 + MAP_KEY_AND_MASK(PORTS, ports, src, l4_sport); 239 + MAP_KEY_AND_MASK(PORTS, ports, dst, l4_dport); 240 + MAP_KEY_AND_MASK(TCP, tcp, flags, tcp_flags); 206 241 207 242 return 0; 208 243 }
+16
drivers/net/ethernet/sfc/tc.h
··· 15 15 #include <linux/rhashtable.h> 16 16 #include "net_driver.h" 17 17 18 + #define IS_ALL_ONES(v) (!(typeof (v))~(v)) 19 + 18 20 struct efx_tc_action_set { 19 21 u16 deliver:1; 20 22 u32 dest_mport; ··· 28 26 /* L1 */ 29 27 u32 ingress_port; 30 28 u8 recirc_id; 29 + /* L2 (inner when encap) */ 30 + __be16 eth_proto; 31 + __be16 vlan_tci[2], vlan_proto[2]; 32 + u8 eth_saddr[ETH_ALEN], eth_daddr[ETH_ALEN]; 33 + /* L3 (when IP) */ 34 + u8 ip_proto, ip_tos, ip_ttl; 35 + __be32 src_ip, dst_ip; 36 + #ifdef CONFIG_IPV6 37 + struct in6_addr src_ip6, dst_ip6; 38 + #endif 39 + bool ip_frag, ip_firstfrag; 40 + /* L4 */ 41 + __be16 l4_sport, l4_dport; /* Ports (UDP, TCP) */ 42 + __be16 tcp_flags; 31 43 }; 32 44 33 45 struct efx_tc_match {