|
11 | 11 | #include "net_driver.h"
|
12 | 12 | #include <linux/module.h>
|
13 | 13 | #include <linux/netdevice.h>
|
| 14 | +#include <net/gre.h> |
14 | 15 | #include "efx_common.h"
|
15 | 16 | #include "efx_channels.h"
|
16 | 17 | #include "efx.h"
|
@@ -1287,6 +1288,89 @@ const struct pci_error_handlers efx_err_handlers = {
|
1287 | 1288 | .resume = efx_io_resume,
|
1288 | 1289 | };
|
1289 | 1290 |
|
| 1291 | +/* Determine whether the NIC will be able to handle TX offloads for a given |
| 1292 | + * encapsulated packet. |
| 1293 | + */ |
| 1294 | +static bool efx_can_encap_offloads(struct efx_nic *efx, struct sk_buff *skb) |
| 1295 | +{ |
| 1296 | + struct gre_base_hdr *greh; |
| 1297 | + __be16 dst_port; |
| 1298 | + u8 ipproto; |
| 1299 | + |
| 1300 | + /* Does the NIC support encap offloads? |
| 1301 | + * If not, we should never get here, because we shouldn't have |
| 1302 | + * advertised encap offload feature flags in the first place. |
| 1303 | + */ |
| 1304 | + if (WARN_ON_ONCE(!efx->type->udp_tnl_has_port)) |
| 1305 | + return false; |
| 1306 | + |
| 1307 | + /* Determine encapsulation protocol in use */ |
| 1308 | + switch (skb->protocol) { |
| 1309 | + case htons(ETH_P_IP): |
| 1310 | + ipproto = ip_hdr(skb)->protocol; |
| 1311 | + break; |
| 1312 | + case htons(ETH_P_IPV6): |
| 1313 | + /* If there are extension headers, this will cause us to |
| 1314 | + * think we can't offload something that we maybe could have. |
| 1315 | + */ |
| 1316 | + ipproto = ipv6_hdr(skb)->nexthdr; |
| 1317 | + break; |
| 1318 | + default: |
| 1319 | + /* Not IP, so can't offload it */ |
| 1320 | + return false; |
| 1321 | + } |
| 1322 | + switch (ipproto) { |
| 1323 | + case IPPROTO_GRE: |
| 1324 | + /* We support NVGRE but not IP over GRE or random gretaps. |
| 1325 | + * Specifically, the NIC will accept GRE as encapsulated if |
| 1326 | + * the inner protocol is Ethernet, but only handle it |
| 1327 | + * correctly if the GRE header is 8 bytes long. Moreover, |
| 1328 | + * it will not update the Checksum or Sequence Number fields |
| 1329 | + * if they are present. (The Routing Present flag, |
| 1330 | + * GRE_ROUTING, cannot be set else the header would be more |
| 1331 | + * than 8 bytes long; so we don't have to worry about it.) |
| 1332 | + */ |
| 1333 | + if (skb->inner_protocol_type != ENCAP_TYPE_ETHER) |
| 1334 | + return false; |
| 1335 | + if (ntohs(skb->inner_protocol) != ETH_P_TEB) |
| 1336 | + return false; |
| 1337 | + if (skb_inner_mac_header(skb) - skb_transport_header(skb) != 8) |
| 1338 | + return false; |
| 1339 | + greh = (struct gre_base_hdr *)skb_transport_header(skb); |
| 1340 | + return !(greh->flags & (GRE_CSUM | GRE_SEQ)); |
| 1341 | + case IPPROTO_UDP: |
| 1342 | + /* If the port is registered for a UDP tunnel, we assume the |
| 1343 | + * packet is for that tunnel, and the NIC will handle it as |
| 1344 | + * such. If not, the NIC won't know what to do with it. |
| 1345 | + */ |
| 1346 | + dst_port = udp_hdr(skb)->dest; |
| 1347 | + return efx->type->udp_tnl_has_port(efx, dst_port); |
| 1348 | + default: |
| 1349 | + return false; |
| 1350 | + } |
| 1351 | +} |
| 1352 | + |
| 1353 | +netdev_features_t efx_features_check(struct sk_buff *skb, struct net_device *dev, |
| 1354 | + netdev_features_t features) |
| 1355 | +{ |
| 1356 | + struct efx_nic *efx = netdev_priv(dev); |
| 1357 | + |
| 1358 | + if (skb->encapsulation) { |
| 1359 | + if (features & NETIF_F_GSO_MASK) |
| 1360 | + /* Hardware can only do TSO with at most 208 bytes |
| 1361 | + * of headers. |
| 1362 | + */ |
| 1363 | + if (skb_inner_transport_offset(skb) > |
| 1364 | + EFX_TSO2_MAX_HDRLEN) |
| 1365 | + features &= ~(NETIF_F_GSO_MASK); |
| 1366 | + if (features & (NETIF_F_GSO_MASK | NETIF_F_CSUM_MASK)) |
| 1367 | + if (!efx_can_encap_offloads(efx, skb)) |
| 1368 | + features &= ~(NETIF_F_GSO_MASK | |
| 1369 | + NETIF_F_CSUM_MASK); |
| 1370 | + } |
| 1371 | + return features; |
| 1372 | +} |
| 1373 | + |
1290 | 1374 | int efx_get_phys_port_id(struct net_device *net_dev,
|
1291 | 1375 | struct netdev_phys_item_id *ppid)
|
1292 | 1376 | {
|
|
0 commit comments