Skip to content

Commit d39d938

Browse files
vyasevichdavem330
authored andcommitted
ipv6: Introduce udpv6_send_skb()
Now that we can individually construct IPv6 skbs to send, add a udpv6_send_skb() function to populate the udp header and send the skb. This allows udp_v6_push_pending_frames() to re-use this function as well as enables us to add lockless sendmsg() support. Signed-off-by: Vladislav Yasevich <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6422398 commit d39d938

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

net/ipv6/udp.c

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
990990
{
991991
unsigned int offset;
992992
struct udphdr *uh = udp_hdr(skb);
993+
struct sk_buff *frags = skb_shinfo(skb)->frag_list;
993994
__wsum csum = 0;
994995

995-
if (skb_queue_len(&sk->sk_write_queue) == 1) {
996+
if (!frags) {
996997
/* Only one fragment on the socket. */
997998
skb->csum_start = skb_transport_header(skb) - skb->head;
998999
skb->csum_offset = offsetof(struct udphdr, check);
@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
10081009

10091010
skb->ip_summed = CHECKSUM_NONE;
10101011

1011-
skb_queue_walk(&sk->sk_write_queue, skb) {
1012-
csum = csum_add(csum, skb->csum);
1013-
}
1012+
do {
1013+
csum = csum_add(csum, frags->csum);
1014+
} while ((frags = frags->next));
10141015

10151016
uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
10161017
csum);
@@ -1023,56 +1024,44 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
10231024
* Sending
10241025
*/
10251026

1026-
static int udp_v6_push_pending_frames(struct sock *sk)
1027+
static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6)
10271028
{
1028-
struct sk_buff *skb;
1029+
struct sock *sk = skb->sk;
10291030
struct udphdr *uh;
1030-
struct udp_sock *up = udp_sk(sk);
1031-
struct inet_sock *inet = inet_sk(sk);
1032-
struct flowi6 *fl6;
10331031
int err = 0;
10341032
int is_udplite = IS_UDPLITE(sk);
10351033
__wsum csum = 0;
1036-
1037-
if (up->pending == AF_INET)
1038-
return udp_push_pending_frames(sk);
1039-
1040-
fl6 = &inet->cork.fl.u.ip6;
1041-
1042-
/* Grab the skbuff where UDP header space exists. */
1043-
skb = skb_peek(&sk->sk_write_queue);
1044-
if (skb == NULL)
1045-
goto out;
1034+
int offset = skb_transport_offset(skb);
1035+
int len = skb->len - offset;
10461036

10471037
/*
10481038
* Create a UDP header
10491039
*/
10501040
uh = udp_hdr(skb);
10511041
uh->source = fl6->fl6_sport;
10521042
uh->dest = fl6->fl6_dport;
1053-
uh->len = htons(up->len);
1043+
uh->len = htons(len);
10541044
uh->check = 0;
10551045

10561046
if (is_udplite)
1057-
csum = udplite_csum_outgoing(sk, skb);
1058-
else if (up->no_check6_tx) { /* UDP csum disabled */
1047+
csum = udplite_csum(skb);
1048+
else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */
10591049
skb->ip_summed = CHECKSUM_NONE;
10601050
goto send;
10611051
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
1062-
udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr,
1063-
up->len);
1052+
udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len);
10641053
goto send;
10651054
} else
1066-
csum = udp_csum_outgoing(sk, skb);
1055+
csum = udp_csum(skb);
10671056

10681057
/* add protocol-dependent pseudo-header */
10691058
uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
1070-
up->len, fl6->flowi6_proto, csum);
1059+
len, fl6->flowi6_proto, csum);
10711060
if (uh->check == 0)
10721061
uh->check = CSUM_MANGLED_0;
10731062

10741063
send:
1075-
err = ip6_push_pending_frames(sk);
1064+
err = ip6_send_skb(skb);
10761065
if (err) {
10771066
if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
10781067
UDP6_INC_STATS_USER(sock_net(sk),
@@ -1082,6 +1071,30 @@ static int udp_v6_push_pending_frames(struct sock *sk)
10821071
} else
10831072
UDP6_INC_STATS_USER(sock_net(sk),
10841073
UDP_MIB_OUTDATAGRAMS, is_udplite);
1074+
return err;
1075+
}
1076+
1077+
static int udp_v6_push_pending_frames(struct sock *sk)
1078+
{
1079+
struct sk_buff *skb;
1080+
struct udp_sock *up = udp_sk(sk);
1081+
struct flowi6 fl6;
1082+
int err = 0;
1083+
1084+
if (up->pending == AF_INET)
1085+
return udp_push_pending_frames(sk);
1086+
1087+
/* ip6_finish_skb will release the cork, so make a copy of
1088+
* fl6 here.
1089+
*/
1090+
fl6 = inet_sk(sk)->cork.fl.u.ip6;
1091+
1092+
skb = ip6_finish_skb(sk);
1093+
if (!skb)
1094+
goto out;
1095+
1096+
err = udp_v6_send_skb(skb, &fl6);
1097+
10851098
out:
10861099
up->len = 0;
10871100
up->pending = 0;

0 commit comments

Comments
 (0)