TIPC GSO is implemented in the skb frag_list way as SCTP does. We don't need to change much in the tx path, but only create a head skb and append the skbs when there are more than one skb ready to send. In the lower-layer gso_segment(), it does fragmentation by copy eth header or ip/udp header to each skb in the head_skb's frag_list and send them one by one.
This supports with both eth media and udp media. Signed-off-by: Xin Long <lucien....@gmail.com> --- net/tipc/bearer.c | 23 +++++++++++++++++++++-- net/tipc/msg.h | 1 + net/tipc/offload.c | 41 +++++++++++++++++++++++++++++++++++++++++ net/tipc/udp_media.c | 7 +++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 443f8e5b9477..b0321b21bfdc 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -570,8 +570,9 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, struct tipc_media_addr *dst, struct tipc_node *__dnode) { + struct sk_buff *head = NULL, *skb, *tmp; struct tipc_bearer *b; - struct sk_buff *skb, *tmp; + u16 segs = 0; if (skb_queue_empty(xmitq)) return; @@ -585,13 +586,31 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb)))) { #ifdef CONFIG_TIPC_CRYPTO tipc_crypto_xmit(net, &skb, b, dst, __dnode); - if (skb) + if (!skb) + continue; #endif + if (!skb->ignore_df) { /* PLPMTUD probe packet*/ b->media->send_msg(net, skb, b, dst); + continue; + } + if (!head) { + segs = 1; + head = skb; + continue; + } + if (tipc_msg_gso_append(&head, skb, segs)) { + segs++; + continue; + } + b->media->send_msg(net, head, b, dst); + segs = 1; + head = skb; } else { kfree_skb(skb); } } + if (head) + b->media->send_msg(net, head, b, dst); rcu_read_unlock(); } diff --git a/net/tipc/msg.h b/net/tipc/msg.h index d6c6231b8208..4d1ff666790c 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -1205,6 +1205,7 @@ bool __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy); void tipc_offload_init(void); void tipc_offload_exit(void); +bool tipc_msg_gso_append(struct sk_buff **p, struct sk_buff *skb, u16 segs); static inline u16 buf_seqno(struct sk_buff *skb) { diff --git a/net/tipc/offload.c b/net/tipc/offload.c index f8a81c8886f0..d137679f4db0 100644 --- a/net/tipc/offload.c +++ b/net/tipc/offload.c @@ -18,6 +18,47 @@ static struct packet_offload tipc_packet_offload __read_mostly = { }, }; +bool tipc_msg_gso_append(struct sk_buff **p, struct sk_buff *skb, u16 segs) +{ + struct sk_buff *head = *p; + struct sk_buff *nskb; + + if (head->len + skb->len >= 65535) + return false; + + if (segs == 1) { + nskb = tipc_buf_acquire(0, GFP_ATOMIC); + if (!nskb) + return false; + + nskb->ip_summed = CHECKSUM_UNNECESSARY; + nskb->truesize += head->truesize; + nskb->data_len += head->len; + nskb->len += head->len; + TIPC_SKB_CB(nskb)->tail = head; + + skb_shinfo(nskb)->frag_list = head; + skb_shinfo(nskb)->gso_segs = 1; + skb_shinfo(nskb)->gso_type = SKB_GSO_TIPC; + skb_shinfo(nskb)->gso_size = GSO_BY_FRAGS; + skb_reset_network_header(head); + + head = nskb; + *p = head; + } + + head->truesize += skb->truesize; + head->data_len += skb->len; + head->len += skb->len; + TIPC_SKB_CB(head)->tail->next = skb; + TIPC_SKB_CB(head)->tail = skb; + + skb_shinfo(head)->gso_segs++; + skb_reset_network_header(skb); + + return true; +} + void tipc_offload_init(void) { dev_add_offload(&tipc_packet_offload); diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 5078c5b19e81..7da02db6a50e 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -245,6 +245,13 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, goto out; } + if (skb_is_gso(skb)) + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; + + skb->encapsulation = 1; + skb_reset_inner_mac_header(skb); + skb_reset_inner_network_header(skb); + skb_reset_inner_transport_header(skb); skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); ub = rcu_dereference(b->media_ptr); if (!ub) { -- 2.27.0 _______________________________________________ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion