Skip to content

Commit f6b9664

Browse files
herbertxdavem330
authored andcommitted
udp: Switch to ip_finish_skb
This patch converts UDP to use the new ip_finish_skb API. This would then allows us to more easily use ip_make_skb which allows UDP to run without a socket lock. Signed-off-by: Herbert Xu <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1c32c5a commit f6b9664

File tree

3 files changed

+73
-33
lines changed

3 files changed

+73
-33
lines changed

include/net/udp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,17 @@ static inline __wsum udp_csum_outgoing(struct sock *sk, struct sk_buff *skb)
144144
return csum;
145145
}
146146

147+
static inline __wsum udp_csum(struct sk_buff *skb)
148+
{
149+
__wsum csum = csum_partial(skb_transport_header(skb),
150+
sizeof(struct udphdr), skb->csum);
151+
152+
for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) {
153+
csum = csum_add(csum, skb->csum);
154+
}
155+
return csum;
156+
}
157+
147158
/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
148159
static inline void udp_lib_hash(struct sock *sk)
149160
{

include/net/udplite.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
115115
return csum;
116116
}
117117

118+
static inline __wsum udplite_csum(struct sk_buff *skb)
119+
{
120+
struct sock *sk = skb->sk;
121+
int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
122+
const int off = skb_transport_offset(skb);
123+
const int len = skb->len - off;
124+
125+
skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
126+
127+
return skb_checksum(skb, off, min(cscov, len), 0);
128+
}
129+
118130
extern void udplite4_register(void);
119131
extern int udplite_get_port(struct sock *sk, unsigned short snum,
120132
int (*scmp)(const struct sock *, const struct sock *));

net/ipv4/udp.c

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -663,75 +663,72 @@ void udp_flush_pending_frames(struct sock *sk)
663663
EXPORT_SYMBOL(udp_flush_pending_frames);
664664

665665
/**
666-
* udp4_hwcsum_outgoing - handle outgoing HW checksumming
667-
* @sk: socket we are sending on
666+
* udp4_hwcsum - handle outgoing HW checksumming
668667
* @skb: sk_buff containing the filled-in UDP header
669668
* (checksum field must be zeroed out)
669+
* @src: source IP address
670+
* @dst: destination IP address
670671
*/
671-
static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
672-
__be32 src, __be32 dst, int len)
672+
static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
673673
{
674-
unsigned int offset;
675674
struct udphdr *uh = udp_hdr(skb);
675+
struct sk_buff *frags = skb_shinfo(skb)->frag_list;
676+
int offset = skb_transport_offset(skb);
677+
int len = skb->len - offset;
678+
int hlen = len;
676679
__wsum csum = 0;
677680

678-
if (skb_queue_len(&sk->sk_write_queue) == 1) {
681+
if (!frags) {
679682
/*
680683
* Only one fragment on the socket.
681684
*/
682685
skb->csum_start = skb_transport_header(skb) - skb->head;
683686
skb->csum_offset = offsetof(struct udphdr, check);
684-
uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0);
687+
uh->check = ~csum_tcpudp_magic(src, dst, len,
688+
IPPROTO_UDP, 0);
685689
} else {
686690
/*
687691
* HW-checksum won't work as there are two or more
688692
* fragments on the socket so that all csums of sk_buffs
689693
* should be together
690694
*/
691-
offset = skb_transport_offset(skb);
692-
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
695+
do {
696+
csum = csum_add(csum, frags->csum);
697+
hlen -= frags->len;
698+
} while ((frags = frags->next));
693699

700+
csum = skb_checksum(skb, offset, hlen, csum);
694701
skb->ip_summed = CHECKSUM_NONE;
695702

696-
skb_queue_walk(&sk->sk_write_queue, skb) {
697-
csum = csum_add(csum, skb->csum);
698-
}
699-
700703
uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum);
701704
if (uh->check == 0)
702705
uh->check = CSUM_MANGLED_0;
703706
}
704707
}
705708

706-
/*
707-
* Push out all pending data as one UDP datagram. Socket is locked.
708-
*/
709-
static int udp_push_pending_frames(struct sock *sk)
709+
static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport)
710710
{
711-
struct udp_sock *up = udp_sk(sk);
711+
struct sock *sk = skb->sk;
712712
struct inet_sock *inet = inet_sk(sk);
713-
struct flowi *fl = &inet->cork.fl;
714-
struct sk_buff *skb;
715713
struct udphdr *uh;
714+
struct rtable *rt = (struct rtable *)skb_dst(skb);
716715
int err = 0;
717716
int is_udplite = IS_UDPLITE(sk);
717+
int offset = skb_transport_offset(skb);
718+
int len = skb->len - offset;
718719
__wsum csum = 0;
719720

720-
/* Grab the skbuff where UDP header space exists. */
721-
if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
722-
goto out;
723-
724721
/*
725722
* Create a UDP header
726723
*/
727724
uh = udp_hdr(skb);
728-
uh->source = fl->fl_ip_sport;
729-
uh->dest = fl->fl_ip_dport;
730-
uh->len = htons(up->len);
725+
uh->source = inet->inet_sport;
726+
uh->dest = dport;
727+
uh->len = htons(len);
731728
uh->check = 0;
732729

733730
if (is_udplite) /* UDP-Lite */
734-
csum = udplite_csum_outgoing(sk, skb);
731+
csum = udplite_csum(skb);
735732

736733
else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */
737734

@@ -740,20 +737,20 @@ static int udp_push_pending_frames(struct sock *sk)
740737

741738
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
742739

743-
udp4_hwcsum_outgoing(sk, skb, fl->fl4_src, fl->fl4_dst, up->len);
740+
udp4_hwcsum(skb, rt->rt_src, daddr);
744741
goto send;
745742

746-
} else /* `normal' UDP */
747-
csum = udp_csum_outgoing(sk, skb);
743+
} else
744+
csum = udp_csum(skb);
748745

749746
/* add protocol-dependent pseudo-header */
750-
uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len,
747+
uh->check = csum_tcpudp_magic(rt->rt_src, daddr, len,
751748
sk->sk_protocol, csum);
752749
if (uh->check == 0)
753750
uh->check = CSUM_MANGLED_0;
754751

755752
send:
756-
err = ip_push_pending_frames(sk);
753+
err = ip_send_skb(skb);
757754
if (err) {
758755
if (err == -ENOBUFS && !inet->recverr) {
759756
UDP_INC_STATS_USER(sock_net(sk),
@@ -763,6 +760,26 @@ static int udp_push_pending_frames(struct sock *sk)
763760
} else
764761
UDP_INC_STATS_USER(sock_net(sk),
765762
UDP_MIB_OUTDATAGRAMS, is_udplite);
763+
return err;
764+
}
765+
766+
/*
767+
* Push out all pending data as one UDP datagram. Socket is locked.
768+
*/
769+
static int udp_push_pending_frames(struct sock *sk)
770+
{
771+
struct udp_sock *up = udp_sk(sk);
772+
struct inet_sock *inet = inet_sk(sk);
773+
struct flowi *fl = &inet->cork.fl;
774+
struct sk_buff *skb;
775+
int err = 0;
776+
777+
skb = ip_finish_skb(sk);
778+
if (!skb)
779+
goto out;
780+
781+
err = udp_send_skb(skb, fl->fl4_dst, fl->fl_ip_dport);
782+
766783
out:
767784
up->len = 0;
768785
up->pending = 0;

0 commit comments

Comments
 (0)