Skip to content

Commit b66a804

Browse files
committed
Merge branch 'enic-vxlan-offload'
Govindarajulu Varadarajan says: ==================== enic: add vxlan offload support This series adds vxlan offload support for enic driver. The first patch adds vxlan devcmd for configuring vxland offload parameters. Second patch adds ndo_udp_tunnel_add/del and offload on rx path. There are to modes in which fw supports vxlan offload. mode 0: fcoe bit is set for encapsulated packet. fcoe_fc_crc_ok is set if checksum of csum is ok. This bit is or of ip_csum_ok and tcp_udp_csum_ok mode 2: BIT(0) in rss_hash is set if it is encapsulated packet. BIT(1) is set if outer_ip_csum_ok/ BIT(2) is set if outer_tcp_csum_ok Some hw supports only mode 0, some support mode 0 and 2. Driver gets the supported modes bitmap using get_supported_feature_ver devcmd and selects the highest mode both driver and fw supports. Third patch adds offload support on tx path by adding enic_features_check(). v2: Order local variable declarations from longest to shortest line, on all three patches. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents c0e4dad + 9c744d1 commit b66a804

File tree

6 files changed

+364
-15
lines changed

6 files changed

+364
-15
lines changed

drivers/net/ethernet/cisco/enic/enic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ struct enic_rfs_flw_tbl {
135135
struct timer_list rfs_may_expire;
136136
};
137137

138+
struct vxlan_offload {
139+
u16 vxlan_udp_port_number;
140+
u8 patch_level;
141+
};
142+
138143
/* Per-instance private data structure */
139144
struct enic {
140145
struct net_device *netdev;
@@ -175,6 +180,7 @@ struct enic {
175180
/* receive queue cache line section */
176181
____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
177182
unsigned int rq_count;
183+
struct vxlan_offload vxlan;
178184
u64 rq_truncated_pkts;
179185
u64 rq_bad_fcs;
180186
struct napi_struct napi[ENIC_RQ_MAX + ENIC_WQ_MAX];

drivers/net/ethernet/cisco/enic/enic_main.c

Lines changed: 267 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#endif
4646
#include <linux/crash_dump.h>
4747
#include <net/busy_poll.h>
48+
#include <net/vxlan.h>
4849

4950
#include "cq_enet_desc.h"
5051
#include "vnic_dev.h"
@@ -176,6 +177,134 @@ static void enic_unset_affinity_hint(struct enic *enic)
176177
irq_set_affinity_hint(enic->msix_entry[i].vector, NULL);
177178
}
178179

180+
static void enic_udp_tunnel_add(struct net_device *netdev,
181+
struct udp_tunnel_info *ti)
182+
{
183+
struct enic *enic = netdev_priv(netdev);
184+
__be16 port = ti->port;
185+
int err;
186+
187+
spin_lock_bh(&enic->devcmd_lock);
188+
189+
if (ti->type != UDP_TUNNEL_TYPE_VXLAN) {
190+
netdev_info(netdev, "udp_tnl: only vxlan tunnel offload supported");
191+
goto error;
192+
}
193+
194+
if (ti->sa_family != AF_INET) {
195+
netdev_info(netdev, "vxlan: only IPv4 offload supported");
196+
goto error;
197+
}
198+
199+
if (enic->vxlan.vxlan_udp_port_number) {
200+
if (ntohs(port) == enic->vxlan.vxlan_udp_port_number)
201+
netdev_warn(netdev, "vxlan: udp port already offloaded");
202+
else
203+
netdev_info(netdev, "vxlan: offload supported for only one UDP port");
204+
205+
goto error;
206+
}
207+
208+
err = vnic_dev_overlay_offload_cfg(enic->vdev,
209+
OVERLAY_CFG_VXLAN_PORT_UPDATE,
210+
ntohs(port));
211+
if (err)
212+
goto error;
213+
214+
err = vnic_dev_overlay_offload_ctrl(enic->vdev, OVERLAY_FEATURE_VXLAN,
215+
enic->vxlan.patch_level);
216+
if (err)
217+
goto error;
218+
219+
enic->vxlan.vxlan_udp_port_number = ntohs(port);
220+
221+
netdev_info(netdev, "vxlan fw-vers-%d: offload enabled for udp port: %d, sa_family: %d ",
222+
(int)enic->vxlan.patch_level, ntohs(port), ti->sa_family);
223+
224+
goto unlock;
225+
226+
error:
227+
netdev_info(netdev, "failed to offload udp port: %d, sa_family: %d, type: %d",
228+
ntohs(port), ti->sa_family, ti->type);
229+
unlock:
230+
spin_unlock_bh(&enic->devcmd_lock);
231+
}
232+
233+
static void enic_udp_tunnel_del(struct net_device *netdev,
234+
struct udp_tunnel_info *ti)
235+
{
236+
struct enic *enic = netdev_priv(netdev);
237+
int err;
238+
239+
spin_lock_bh(&enic->devcmd_lock);
240+
241+
if ((ti->sa_family != AF_INET) ||
242+
((ntohs(ti->port) != enic->vxlan.vxlan_udp_port_number)) ||
243+
(ti->type != UDP_TUNNEL_TYPE_VXLAN)) {
244+
netdev_info(netdev, "udp_tnl: port:%d, sa_family: %d, type: %d not offloaded",
245+
ntohs(ti->port), ti->sa_family, ti->type);
246+
goto unlock;
247+
}
248+
249+
err = vnic_dev_overlay_offload_ctrl(enic->vdev, OVERLAY_FEATURE_VXLAN,
250+
OVERLAY_OFFLOAD_DISABLE);
251+
if (err) {
252+
netdev_err(netdev, "vxlan: del offload udp port: %d failed",
253+
ntohs(ti->port));
254+
goto unlock;
255+
}
256+
257+
enic->vxlan.vxlan_udp_port_number = 0;
258+
259+
netdev_info(netdev, "vxlan: del offload udp port %d, family %d\n",
260+
ntohs(ti->port), ti->sa_family);
261+
262+
unlock:
263+
spin_unlock_bh(&enic->devcmd_lock);
264+
}
265+
266+
static netdev_features_t enic_features_check(struct sk_buff *skb,
267+
struct net_device *dev,
268+
netdev_features_t features)
269+
{
270+
const struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb);
271+
struct enic *enic = netdev_priv(dev);
272+
struct udphdr *udph;
273+
u16 port = 0;
274+
u16 proto;
275+
276+
if (!skb->encapsulation)
277+
return features;
278+
279+
features = vxlan_features_check(skb, features);
280+
281+
/* hardware only supports IPv4 vxlan tunnel */
282+
if (vlan_get_protocol(skb) != htons(ETH_P_IP))
283+
goto out;
284+
285+
/* hardware does not support offload of ipv6 inner pkt */
286+
if (eth->h_proto != ntohs(ETH_P_IP))
287+
goto out;
288+
289+
proto = ip_hdr(skb)->protocol;
290+
291+
if (proto == IPPROTO_UDP) {
292+
udph = udp_hdr(skb);
293+
port = be16_to_cpu(udph->dest);
294+
}
295+
296+
/* HW supports offload of only one UDP port. Remove CSUM and GSO MASK
297+
* for other UDP port tunnels
298+
*/
299+
if (port != enic->vxlan.vxlan_udp_port_number)
300+
goto out;
301+
302+
return features;
303+
304+
out:
305+
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
306+
}
307+
179308
int enic_is_dynamic(struct enic *enic)
180309
{
181310
return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
@@ -504,20 +633,19 @@ static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
504633
return err;
505634
}
506635

507-
static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
508-
struct sk_buff *skb, unsigned int mss,
509-
int vlan_tag_insert, unsigned int vlan_tag,
510-
int loopback)
636+
static void enic_preload_tcp_csum_encap(struct sk_buff *skb)
511637
{
512-
unsigned int frag_len_left = skb_headlen(skb);
513-
unsigned int len_left = skb->len - frag_len_left;
514-
unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
515-
int eop = (len_left == 0);
516-
unsigned int len;
517-
dma_addr_t dma_addr;
518-
unsigned int offset = 0;
519-
skb_frag_t *frag;
638+
if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
639+
inner_ip_hdr(skb)->check = 0;
640+
inner_tcp_hdr(skb)->check =
641+
~csum_tcpudp_magic(inner_ip_hdr(skb)->saddr,
642+
inner_ip_hdr(skb)->daddr, 0,
643+
IPPROTO_TCP, 0);
644+
}
645+
}
520646

647+
static void enic_preload_tcp_csum(struct sk_buff *skb)
648+
{
521649
/* Preload TCP csum field with IP pseudo hdr calculated
522650
* with IP length set to zero. HW will later add in length
523651
* to each TCP segment resulting from the TSO.
@@ -531,6 +659,30 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
531659
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
532660
&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
533661
}
662+
}
663+
664+
static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
665+
struct sk_buff *skb, unsigned int mss,
666+
int vlan_tag_insert, unsigned int vlan_tag,
667+
int loopback)
668+
{
669+
unsigned int frag_len_left = skb_headlen(skb);
670+
unsigned int len_left = skb->len - frag_len_left;
671+
int eop = (len_left == 0);
672+
unsigned int offset = 0;
673+
unsigned int hdr_len;
674+
dma_addr_t dma_addr;
675+
unsigned int len;
676+
skb_frag_t *frag;
677+
678+
if (skb->encapsulation) {
679+
hdr_len = skb_inner_transport_header(skb) - skb->data;
680+
hdr_len += inner_tcp_hdrlen(skb);
681+
enic_preload_tcp_csum_encap(skb);
682+
} else {
683+
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
684+
enic_preload_tcp_csum(skb);
685+
}
534686

535687
/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
536688
* for the main skb fragment
@@ -579,6 +731,38 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
579731
return 0;
580732
}
581733

734+
static inline int enic_queue_wq_skb_encap(struct enic *enic, struct vnic_wq *wq,
735+
struct sk_buff *skb,
736+
int vlan_tag_insert,
737+
unsigned int vlan_tag, int loopback)
738+
{
739+
unsigned int head_len = skb_headlen(skb);
740+
unsigned int len_left = skb->len - head_len;
741+
/* Hardware will overwrite the checksum fields, calculating from
742+
* scratch and ignoring the value placed by software.
743+
* Offload mode = 00
744+
* mss[2], mss[1], mss[0] bits are set
745+
*/
746+
unsigned int mss_or_csum = 7;
747+
int eop = (len_left == 0);
748+
dma_addr_t dma_addr;
749+
int err = 0;
750+
751+
dma_addr = pci_map_single(enic->pdev, skb->data, head_len,
752+
PCI_DMA_TODEVICE);
753+
if (unlikely(enic_dma_map_check(enic, dma_addr)))
754+
return -ENOMEM;
755+
756+
enic_queue_wq_desc_ex(wq, skb, dma_addr, head_len, mss_or_csum, 0,
757+
vlan_tag_insert, vlan_tag,
758+
WQ_ENET_OFFLOAD_MODE_CSUM, eop, 1 /* SOP */, eop,
759+
loopback);
760+
if (!eop)
761+
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
762+
763+
return err;
764+
}
765+
582766
static inline void enic_queue_wq_skb(struct enic *enic,
583767
struct vnic_wq *wq, struct sk_buff *skb)
584768
{
@@ -601,6 +785,9 @@ static inline void enic_queue_wq_skb(struct enic *enic,
601785
err = enic_queue_wq_skb_tso(enic, wq, skb, mss,
602786
vlan_tag_insert, vlan_tag,
603787
loopback);
788+
else if (skb->encapsulation)
789+
err = enic_queue_wq_skb_encap(enic, wq, skb, vlan_tag_insert,
790+
vlan_tag, loopback);
604791
else if (skb->ip_summed == CHECKSUM_PARTIAL)
605792
err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert,
606793
vlan_tag, loopback);
@@ -1113,6 +1300,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
11131300
u8 packet_error;
11141301
u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
11151302
u32 rss_hash;
1303+
bool outer_csum_ok = true, encap = false;
11161304

11171305
if (skipped)
11181306
return;
@@ -1161,7 +1349,8 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
11611349
skb_put(skb, bytes_written);
11621350
skb->protocol = eth_type_trans(skb, netdev);
11631351
skb_record_rx_queue(skb, q_number);
1164-
if (netdev->features & NETIF_F_RXHASH) {
1352+
if ((netdev->features & NETIF_F_RXHASH) && rss_hash &&
1353+
(type == 3)) {
11651354
switch (rss_type) {
11661355
case CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4:
11671356
case CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6:
@@ -1175,15 +1364,39 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
11751364
break;
11761365
}
11771366
}
1367+
if (enic->vxlan.vxlan_udp_port_number) {
1368+
switch (enic->vxlan.patch_level) {
1369+
case 0:
1370+
if (fcoe) {
1371+
encap = true;
1372+
outer_csum_ok = fcoe_fc_crc_ok;
1373+
}
1374+
break;
1375+
case 2:
1376+
if ((type == 7) &&
1377+
(rss_hash & BIT(0))) {
1378+
encap = true;
1379+
outer_csum_ok = (rss_hash & BIT(1)) &&
1380+
(rss_hash & BIT(2));
1381+
}
1382+
break;
1383+
}
1384+
}
11781385

11791386
/* Hardware does not provide whole packet checksum. It only
11801387
* provides pseudo checksum. Since hw validates the packet
11811388
* checksum but not provide us the checksum value. use
11821389
* CHECSUM_UNNECESSARY.
1390+
*
1391+
* In case of encap pkt tcp_udp_csum_ok/tcp_udp_csum_ok is
1392+
* inner csum_ok. outer_csum_ok is set by hw when outer udp
1393+
* csum is correct or is zero.
11831394
*/
1184-
if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok &&
1185-
ipv4_csum_ok)
1395+
if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc &&
1396+
tcp_udp_csum_ok && ipv4_csum_ok && outer_csum_ok) {
11861397
skb->ip_summed = CHECKSUM_UNNECESSARY;
1398+
skb->csum_level = encap;
1399+
}
11871400

11881401
if (vlan_stripped)
11891402
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
@@ -2285,6 +2498,9 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {
22852498
#ifdef CONFIG_RFS_ACCEL
22862499
.ndo_rx_flow_steer = enic_rx_flow_steer,
22872500
#endif
2501+
.ndo_udp_tunnel_add = enic_udp_tunnel_add,
2502+
.ndo_udp_tunnel_del = enic_udp_tunnel_del,
2503+
.ndo_features_check = enic_features_check,
22882504
};
22892505

22902506
static const struct net_device_ops enic_netdev_ops = {
@@ -2308,6 +2524,9 @@ static const struct net_device_ops enic_netdev_ops = {
23082524
#ifdef CONFIG_RFS_ACCEL
23092525
.ndo_rx_flow_steer = enic_rx_flow_steer,
23102526
#endif
2527+
.ndo_udp_tunnel_add = enic_udp_tunnel_add,
2528+
.ndo_udp_tunnel_del = enic_udp_tunnel_del,
2529+
.ndo_features_check = enic_features_check,
23112530
};
23122531

23132532
static void enic_dev_deinit(struct enic *enic)
@@ -2683,6 +2902,39 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
26832902
netdev->hw_features |= NETIF_F_RXHASH;
26842903
if (ENIC_SETTING(enic, RXCSUM))
26852904
netdev->hw_features |= NETIF_F_RXCSUM;
2905+
if (ENIC_SETTING(enic, VXLAN)) {
2906+
u64 patch_level;
2907+
2908+
netdev->hw_enc_features |= NETIF_F_RXCSUM |
2909+
NETIF_F_TSO |
2910+
NETIF_F_TSO_ECN |
2911+
NETIF_F_GSO_UDP_TUNNEL |
2912+
NETIF_F_HW_CSUM |
2913+
NETIF_F_GSO_UDP_TUNNEL_CSUM;
2914+
netdev->hw_features |= netdev->hw_enc_features;
2915+
/* get bit mask from hw about supported offload bit level
2916+
* BIT(0) = fw supports patch_level 0
2917+
* fcoe bit = encap
2918+
* fcoe_fc_crc_ok = outer csum ok
2919+
* BIT(1) = always set by fw
2920+
* BIT(2) = fw supports patch_level 2
2921+
* BIT(0) in rss_hash = encap
2922+
* BIT(1,2) in rss_hash = outer_ip_csum_ok/
2923+
* outer_tcp_csum_ok
2924+
* used in enic_rq_indicate_buf
2925+
*/
2926+
err = vnic_dev_get_supported_feature_ver(enic->vdev,
2927+
VIC_FEATURE_VXLAN,
2928+
&patch_level);
2929+
if (err)
2930+
patch_level = 0;
2931+
/* mask bits that are supported by driver
2932+
*/
2933+
patch_level &= BIT_ULL(0) | BIT_ULL(2);
2934+
patch_level = fls(patch_level);
2935+
patch_level = patch_level ? patch_level - 1 : 0;
2936+
enic->vxlan.patch_level = patch_level;
2937+
}
26862938

26872939
netdev->features |= netdev->hw_features;
26882940
netdev->vlan_features |= netdev->features;

0 commit comments

Comments
 (0)