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

Merge branch 'sfc-conntrack-offload'

Edward Cree says:

====================
sfc: support conntrack NAT offload

The EF100 MAE supports performing NAT (and NPT) on packets which match in
the conntrack table. This series adds that capability to the driver.
====================

Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

+101 -3
+2 -1
drivers/net/ethernet/sfc/mae.c
··· 1291 1291 size_t outlen; 1292 1292 int rc; 1293 1293 1294 - MCDI_POPULATE_DWORD_4(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1294 + MCDI_POPULATE_DWORD_5(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1295 1295 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push, 1296 1296 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, 1297 1297 MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap, 1298 + MAE_ACTION_SET_ALLOC_IN_DO_NAT, act->do_nat, 1298 1299 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1299 1300 act->do_ttl_dec); 1300 1301
+8
drivers/net/ethernet/sfc/tc.c
··· 2457 2457 NL_SET_ERR_MSG_MOD(extack, "Cannot offload tunnel decap action without tunnel device"); 2458 2458 rc = -EOPNOTSUPP; 2459 2459 goto release; 2460 + case FLOW_ACTION_CT: 2461 + if (fa->ct.action != TCA_CT_ACT_NAT) { 2462 + rc = -EOPNOTSUPP; 2463 + NL_SET_ERR_MSG_FMT_MOD(extack, "Can only offload CT 'nat' action in RHS rules, not %d", fa->ct.action); 2464 + goto release; 2465 + } 2466 + act->do_nat = 1; 2467 + break; 2460 2468 default: 2461 2469 NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled action %u", 2462 2470 fa->id);
+2
drivers/net/ethernet/sfc/tc.h
··· 48 48 * @vlan_push: the number of vlan headers to push 49 49 * @vlan_pop: the number of vlan headers to pop 50 50 * @decap: used to indicate a tunnel header decapsulation should take place 51 + * @do_nat: perform NAT/NPT with values returned by conntrack match 51 52 * @do_ttl_dec: used to indicate IP TTL / Hop Limit should be decremented 52 53 * @deliver: used to indicate a deliver action should take place 53 54 * @vlan_tci: tci fields for vlan push actions ··· 69 68 u16 vlan_push:2; 70 69 u16 vlan_pop:2; 71 70 u16 decap:1; 71 + u16 do_nat:1; 72 72 u16 do_ttl_dec:1; 73 73 u16 deliver:1; 74 74 __be16 vlan_tci[2];
+89 -2
drivers/net/ethernet/sfc/tc_conntrack.c
··· 276 276 return 0; 277 277 } 278 278 279 + /** 280 + * struct efx_tc_ct_mangler_state - tracks which fields have been pedited 281 + * 282 + * @ipv4: IP source or destination addr has been set 283 + * @tcpudp: TCP/UDP source or destination port has been set 284 + */ 285 + struct efx_tc_ct_mangler_state { 286 + u8 ipv4:1; 287 + u8 tcpudp:1; 288 + }; 289 + 290 + static int efx_tc_ct_mangle(struct efx_nic *efx, struct efx_tc_ct_entry *conn, 291 + const struct flow_action_entry *fa, 292 + struct efx_tc_ct_mangler_state *mung) 293 + { 294 + /* Is this the first mangle we've processed for this rule? */ 295 + bool first = !(mung->ipv4 || mung->tcpudp); 296 + bool dnat = false; 297 + 298 + switch (fa->mangle.htype) { 299 + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: 300 + switch (fa->mangle.offset) { 301 + case offsetof(struct iphdr, daddr): 302 + dnat = true; 303 + fallthrough; 304 + case offsetof(struct iphdr, saddr): 305 + if (fa->mangle.mask) 306 + return -EOPNOTSUPP; 307 + conn->nat_ip = htonl(fa->mangle.val); 308 + mung->ipv4 = 1; 309 + break; 310 + default: 311 + return -EOPNOTSUPP; 312 + } 313 + break; 314 + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: 315 + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: 316 + /* Both struct tcphdr and struct udphdr start with 317 + * __be16 source; 318 + * __be16 dest; 319 + * so we can use the same code for both. 320 + */ 321 + switch (fa->mangle.offset) { 322 + case offsetof(struct tcphdr, dest): 323 + BUILD_BUG_ON(offsetof(struct tcphdr, dest) != 324 + offsetof(struct udphdr, dest)); 325 + dnat = true; 326 + fallthrough; 327 + case offsetof(struct tcphdr, source): 328 + BUILD_BUG_ON(offsetof(struct tcphdr, source) != 329 + offsetof(struct udphdr, source)); 330 + if (~fa->mangle.mask != 0xffff) 331 + return -EOPNOTSUPP; 332 + conn->l4_natport = htons(fa->mangle.val); 333 + mung->tcpudp = 1; 334 + break; 335 + default: 336 + return -EOPNOTSUPP; 337 + } 338 + break; 339 + default: 340 + return -EOPNOTSUPP; 341 + } 342 + /* first mangle tells us whether this is SNAT or DNAT; 343 + * subsequent mangles must match that 344 + */ 345 + if (first) 346 + conn->dnat = dnat; 347 + else if (conn->dnat != dnat) 348 + return -EOPNOTSUPP; 349 + return 0; 350 + } 351 + 279 352 static int efx_tc_ct_replace(struct efx_tc_ct_zone *ct_zone, 280 353 struct flow_cls_offload *tc) 281 354 { 282 355 struct flow_rule *fr = flow_cls_offload_flow_rule(tc); 356 + struct efx_tc_ct_mangler_state mung = {}; 283 357 struct efx_tc_ct_entry *conn, *old; 284 358 struct efx_nic *efx = ct_zone->efx; 285 359 const struct flow_action_entry *fa; ··· 400 326 goto release; 401 327 } 402 328 break; 329 + case FLOW_ACTION_MANGLE: 330 + if (conn->eth_proto != htons(ETH_P_IP)) { 331 + netif_dbg(efx, drv, efx->net_dev, 332 + "NAT only supported for IPv4\n"); 333 + rc = -EOPNOTSUPP; 334 + goto release; 335 + } 336 + rc = efx_tc_ct_mangle(efx, conn, fa, &mung); 337 + if (rc) 338 + goto release; 339 + break; 403 340 default: 404 341 netif_dbg(efx, drv, efx->net_dev, 405 342 "Unhandled action %u for conntrack\n", fa->id); ··· 420 335 } 421 336 422 337 /* fill in defaults for unmangled values */ 423 - conn->nat_ip = conn->dnat ? conn->dst_ip : conn->src_ip; 424 - conn->l4_natport = conn->dnat ? conn->l4_dport : conn->l4_sport; 338 + if (!mung.ipv4) 339 + conn->nat_ip = conn->dnat ? conn->dst_ip : conn->src_ip; 340 + if (!mung.tcpudp) 341 + conn->l4_natport = conn->dnat ? conn->l4_dport : conn->l4_sport; 425 342 426 343 cnt = efx_tc_flower_allocate_counter(efx, EFX_TC_COUNTER_TYPE_CT); 427 344 if (IS_ERR(cnt)) {