Commit 0fb9fbab authored by David S. Miller's avatar David S. Miller

Merge branch 'net-tso-expand-to-UDP-support'

Eric Dumazet says:

====================
net: tso: expand to UDP support

With QUIC getting more attention these days, it is worth
implementing UDP direct segmentation, the same we did for TCP.

Drivers will need to advertize NETIF_F_GSO_UDP_L4 so that
GSO stack does not do the (more expensive) segmentation.

Note the two first patches are stable candidates, after
tests confirm they do not add regressions.

v2: addressed Jakub feedback :
   1) Added a prep patch for octeontx2-af
   2) calls tso_start() earlier in otx2_sq_append_tso()
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1b055409 3d5b459b
...@@ -1489,9 +1489,10 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq, ...@@ -1489,9 +1489,10 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
int seg_subdescs = 0, desc_cnt = 0; int seg_subdescs = 0, desc_cnt = 0;
int seg_len, total_len, data_left; int seg_len, total_len, data_left;
int hdr_qentry = qentry; int hdr_qentry = qentry;
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int hdr_len;
hdr_len = tso_start(skb, &tso);
tso_start(skb, &tso);
total_len = skb->len - hdr_len; total_len = skb->len - hdr_len;
while (total_len > 0) { while (total_len > 0) {
char *hdr; char *hdr;
......
...@@ -710,8 +710,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, ...@@ -710,8 +710,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct net_device *ndev) struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(ndev); struct fec_enet_private *fep = netdev_priv(ndev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int hdr_len, total_len, data_left;
int total_len, data_left;
struct bufdesc *bdp = txq->bd.cur; struct bufdesc *bdp = txq->bd.cur;
struct tso_t tso; struct tso_t tso;
unsigned int index = 0; unsigned int index = 0;
...@@ -731,7 +730,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, ...@@ -731,7 +730,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
} }
/* Initialize the TSO handler, and prepare the first payload */ /* Initialize the TSO handler, and prepare the first payload */
tso_start(skb, &tso); hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len; total_len = skb->len - hdr_len;
while (total_len > 0) { while (total_len > 0) {
......
...@@ -816,10 +816,9 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb, ...@@ -816,10 +816,9 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct mv643xx_eth_private *mp = txq_to_mp(txq); struct mv643xx_eth_private *mp = txq_to_mp(txq);
int total_len, data_left, ret; int hdr_len, total_len, data_left, ret;
int desc_count = 0; int desc_count = 0;
struct tso_t tso; struct tso_t tso;
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct tx_desc *first_tx_desc; struct tx_desc *first_tx_desc;
u32 first_cmd_sts = 0; u32 first_cmd_sts = 0;
...@@ -832,7 +831,7 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb, ...@@ -832,7 +831,7 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
first_tx_desc = &txq->tx_desc_area[txq->tx_curr_desc]; first_tx_desc = &txq->tx_desc_area[txq->tx_curr_desc];
/* Initialize the TSO handler, and prepare the first payload */ /* Initialize the TSO handler, and prepare the first payload */
tso_start(skb, &tso); hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len; total_len = skb->len - hdr_len;
while (total_len > 0) { while (total_len > 0) {
......
...@@ -2604,11 +2604,10 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, ...@@ -2604,11 +2604,10 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq,
static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev, static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
struct mvneta_tx_queue *txq) struct mvneta_tx_queue *txq)
{ {
int total_len, data_left; int hdr_len, total_len, data_left;
int desc_count = 0; int desc_count = 0;
struct mvneta_port *pp = netdev_priv(dev); struct mvneta_port *pp = netdev_priv(dev);
struct tso_t tso; struct tso_t tso;
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
int i; int i;
/* Count needed descriptors */ /* Count needed descriptors */
...@@ -2621,7 +2620,7 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev, ...@@ -2621,7 +2620,7 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
} }
/* Initialize the TSO handler, and prepare the first payload */ /* Initialize the TSO handler, and prepare the first payload */
tso_start(skb, &tso); hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len; total_len = skb->len - hdr_len;
while (total_len > 0) { while (total_len > 0) {
......
...@@ -3160,9 +3160,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev, ...@@ -3160,9 +3160,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
struct mvpp2_txq_pcpu *txq_pcpu) struct mvpp2_txq_pcpu *txq_pcpu)
{ {
struct mvpp2_port *port = netdev_priv(dev); struct mvpp2_port *port = netdev_priv(dev);
int hdr_sz, i, len, descs = 0;
struct tso_t tso; struct tso_t tso;
int hdr_sz = skb_transport_offset(skb) + tcp_hdrlen(skb);
int i, len, descs = 0;
/* Check number of available descriptors */ /* Check number of available descriptors */
if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) || if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) ||
...@@ -3170,7 +3169,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev, ...@@ -3170,7 +3169,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
tso_count_descs(skb))) tso_count_descs(skb)))
return 0; return 0;
tso_start(skb, &tso); hdr_sz = tso_start(skb, &tso);
len = skb->len - hdr_sz; len = skb->len - hdr_sz;
while (len > 0) { while (len > 0) {
int left = min_t(int, skb_shinfo(skb)->gso_size, len); int left = min_t(int, skb_shinfo(skb)->gso_size, len);
......
...@@ -43,7 +43,7 @@ struct qmem { ...@@ -43,7 +43,7 @@ struct qmem {
void *base; void *base;
dma_addr_t iova; dma_addr_t iova;
int alloc_sz; int alloc_sz;
u8 entry_sz; u16 entry_sz;
u8 align; u8 align;
u32 qsize; u32 qsize;
}; };
......
...@@ -619,13 +619,14 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, ...@@ -619,13 +619,14 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
struct sk_buff *skb, u16 qidx) struct sk_buff *skb, u16 qidx)
{ {
struct netdev_queue *txq = netdev_get_tx_queue(pfvf->netdev, qidx); struct netdev_queue *txq = netdev_get_tx_queue(pfvf->netdev, qidx);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int hdr_len, tcp_data, seg_len, pkt_len, offset;
int tcp_data, seg_len, pkt_len, offset;
struct nix_sqe_hdr_s *sqe_hdr; struct nix_sqe_hdr_s *sqe_hdr;
int first_sqe = sq->head; int first_sqe = sq->head;
struct sg_list list; struct sg_list list;
struct tso_t tso; struct tso_t tso;
hdr_len = tso_start(skb, &tso);
/* Map SKB's fragments to DMA. /* Map SKB's fragments to DMA.
* It's done here to avoid mapping for every TSO segment's packet. * It's done here to avoid mapping for every TSO segment's packet.
*/ */
...@@ -636,7 +637,6 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, ...@@ -636,7 +637,6 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
netdev_tx_sent_queue(txq, skb->len); netdev_tx_sent_queue(txq, skb->len);
tso_start(skb, &tso);
tcp_data = skb->len - hdr_len; tcp_data = skb->len - hdr_len;
while (tcp_data > 0) { while (tcp_data > 0) {
char *hdr; char *hdr;
......
...@@ -4,21 +4,22 @@ ...@@ -4,21 +4,22 @@
#include <net/ip.h> #include <net/ip.h>
#define TSO_HEADER_SIZE 128 #define TSO_HEADER_SIZE 256
struct tso_t { struct tso_t {
int next_frag_idx; int next_frag_idx;
void *data; int size;
size_t size; void *data;
u16 ip_id; u16 ip_id;
bool ipv6; u8 tlen; /* transport header len */
u32 tcp_seq; bool ipv6;
u32 tcp_seq;
}; };
int tso_count_descs(struct sk_buff *skb); int tso_count_descs(const struct sk_buff *skb);
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last); int size, bool is_last);
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size); void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size);
void tso_start(struct sk_buff *skb, struct tso_t *tso); int tso_start(struct sk_buff *skb, struct tso_t *tso);
#endif /* _TSO_H */ #endif /* _TSO_H */
...@@ -6,18 +6,17 @@ ...@@ -6,18 +6,17 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
/* Calculate expected number of TX descriptors */ /* Calculate expected number of TX descriptors */
int tso_count_descs(struct sk_buff *skb) int tso_count_descs(const struct sk_buff *skb)
{ {
/* The Marvell Way */ /* The Marvell Way */
return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags;
} }
EXPORT_SYMBOL(tso_count_descs); EXPORT_SYMBOL(tso_count_descs);
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last) int size, bool is_last)
{ {
struct tcphdr *tcph; int hdr_len = skb_transport_offset(skb) + tso->tlen;
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
int mac_hdr_len = skb_network_offset(skb); int mac_hdr_len = skb_network_offset(skb);
memcpy(hdr, skb->data, hdr_len); memcpy(hdr, skb->data, hdr_len);
...@@ -30,23 +29,31 @@ void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, ...@@ -30,23 +29,31 @@ void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
} else { } else {
struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len); struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len);
iph->payload_len = htons(size + tcp_hdrlen(skb)); iph->payload_len = htons(size + tso->tlen);
} }
tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); hdr += skb_transport_offset(skb);
put_unaligned_be32(tso->tcp_seq, &tcph->seq); if (tso->tlen != sizeof(struct udphdr)) {
struct tcphdr *tcph = (struct tcphdr *)hdr;
if (!is_last) { put_unaligned_be32(tso->tcp_seq, &tcph->seq);
/* Clear all special flags for not last packet */
tcph->psh = 0; if (!is_last) {
tcph->fin = 0; /* Clear all special flags for not last packet */
tcph->rst = 0; tcph->psh = 0;
tcph->fin = 0;
tcph->rst = 0;
}
} else {
struct udphdr *uh = (struct udphdr *)hdr;
uh->len = htons(sizeof(*uh) + size);
} }
} }
EXPORT_SYMBOL(tso_build_hdr); EXPORT_SYMBOL(tso_build_hdr);
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size)
{ {
tso->tcp_seq += size; tso->tcp_seq += size; /* not worth avoiding this operation for UDP */
tso->size -= size; tso->size -= size;
tso->data += size; tso->data += size;
...@@ -62,12 +69,14 @@ void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) ...@@ -62,12 +69,14 @@ void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size)
} }
EXPORT_SYMBOL(tso_build_data); EXPORT_SYMBOL(tso_build_data);
void tso_start(struct sk_buff *skb, struct tso_t *tso) int tso_start(struct sk_buff *skb, struct tso_t *tso)
{ {
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int tlen = skb_is_gso_tcp(skb) ? tcp_hdrlen(skb) : sizeof(struct udphdr);
int hdr_len = skb_transport_offset(skb) + tlen;
tso->tlen = tlen;
tso->ip_id = ntohs(ip_hdr(skb)->id); tso->ip_id = ntohs(ip_hdr(skb)->id);
tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); tso->tcp_seq = (tlen != sizeof(struct udphdr)) ? ntohl(tcp_hdr(skb)->seq) : 0;
tso->next_frag_idx = 0; tso->next_frag_idx = 0;
tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6); tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6);
...@@ -83,5 +92,6 @@ void tso_start(struct sk_buff *skb, struct tso_t *tso) ...@@ -83,5 +92,6 @@ void tso_start(struct sk_buff *skb, struct tso_t *tso)
tso->data = skb_frag_address(frag); tso->data = skb_frag_address(frag);
tso->next_frag_idx++; tso->next_frag_idx++;
} }
return hdr_len;
} }
EXPORT_SYMBOL(tso_start); EXPORT_SYMBOL(tso_start);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment