mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
ipv6: Append sending data to arbitrary queue
Add the ability to append data to arbitrary queue. This will be needed later to implement lockless UDP sends. Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
366e41d977
commit
0bbe84a67b
@ -1041,6 +1041,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
|
|||||||
EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
|
EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
|
||||||
|
|
||||||
static inline int ip6_ufo_append_data(struct sock *sk,
|
static inline int ip6_ufo_append_data(struct sock *sk,
|
||||||
|
struct sk_buff_head *queue,
|
||||||
int getfrag(void *from, char *to, int offset, int len,
|
int getfrag(void *from, char *to, int offset, int len,
|
||||||
int odd, struct sk_buff *skb),
|
int odd, struct sk_buff *skb),
|
||||||
void *from, int length, int hh_len, int fragheaderlen,
|
void *from, int length, int hh_len, int fragheaderlen,
|
||||||
@ -1056,7 +1057,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
|
|||||||
* device, so create one single skb packet containing complete
|
* device, so create one single skb packet containing complete
|
||||||
* udp datagram
|
* udp datagram
|
||||||
*/
|
*/
|
||||||
skb = skb_peek_tail(&sk->sk_write_queue);
|
skb = skb_peek_tail(queue);
|
||||||
if (skb == NULL) {
|
if (skb == NULL) {
|
||||||
skb = sock_alloc_send_skb(sk,
|
skb = sock_alloc_send_skb(sk,
|
||||||
hh_len + fragheaderlen + transhdrlen + 20,
|
hh_len + fragheaderlen + transhdrlen + 20,
|
||||||
@ -1079,7 +1080,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
|
|||||||
skb->protocol = htons(ETH_P_IPV6);
|
skb->protocol = htons(ETH_P_IPV6);
|
||||||
skb->csum = 0;
|
skb->csum = 0;
|
||||||
|
|
||||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
__skb_queue_tail(queue, skb);
|
||||||
} else if (skb_is_gso(skb)) {
|
} else if (skb_is_gso(skb)) {
|
||||||
goto append;
|
goto append;
|
||||||
}
|
}
|
||||||
@ -1203,49 +1204,36 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
static int __ip6_append_data(struct sock *sk,
|
||||||
int offset, int len, int odd, struct sk_buff *skb),
|
struct flowi6 *fl6,
|
||||||
void *from, int length, int transhdrlen,
|
struct sk_buff_head *queue,
|
||||||
int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
|
struct inet_cork *cork,
|
||||||
struct rt6_info *rt, unsigned int flags, int dontfrag)
|
struct inet6_cork *v6_cork,
|
||||||
|
struct page_frag *pfrag,
|
||||||
|
int getfrag(void *from, char *to, int offset,
|
||||||
|
int len, int odd, struct sk_buff *skb),
|
||||||
|
void *from, int length, int transhdrlen,
|
||||||
|
unsigned int flags, int dontfrag)
|
||||||
{
|
{
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
|
||||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
||||||
struct inet_cork *cork;
|
|
||||||
struct sk_buff *skb, *skb_prev = NULL;
|
struct sk_buff *skb, *skb_prev = NULL;
|
||||||
unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
|
unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
|
||||||
int exthdrlen;
|
int exthdrlen = 0;
|
||||||
int dst_exthdrlen;
|
int dst_exthdrlen = 0;
|
||||||
int hh_len;
|
int hh_len;
|
||||||
int copy;
|
int copy;
|
||||||
int err;
|
int err;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
__u8 tx_flags = 0;
|
__u8 tx_flags = 0;
|
||||||
u32 tskey = 0;
|
u32 tskey = 0;
|
||||||
|
struct rt6_info *rt = (struct rt6_info *)cork->dst;
|
||||||
|
struct ipv6_txoptions *opt = v6_cork->opt;
|
||||||
|
|
||||||
if (flags&MSG_PROBE)
|
skb = skb_peek_tail(queue);
|
||||||
return 0;
|
if (!skb) {
|
||||||
cork = &inet->cork.base;
|
exthdrlen = opt ? opt->opt_flen : 0;
|
||||||
if (skb_queue_empty(&sk->sk_write_queue)) {
|
|
||||||
/*
|
|
||||||
* setup for corking
|
|
||||||
*/
|
|
||||||
err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
|
|
||||||
tclass, opt, rt, fl6);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
exthdrlen = (opt ? opt->opt_flen : 0);
|
|
||||||
length += exthdrlen;
|
|
||||||
transhdrlen += exthdrlen;
|
|
||||||
dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
|
dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
|
||||||
} else {
|
|
||||||
rt = (struct rt6_info *)cork->dst;
|
|
||||||
fl6 = &inet->cork.fl.u.ip6;
|
|
||||||
opt = np->cork.opt;
|
|
||||||
transhdrlen = 0;
|
|
||||||
exthdrlen = 0;
|
|
||||||
dst_exthdrlen = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtu = cork->fragsize;
|
mtu = cork->fragsize;
|
||||||
orig_mtu = mtu;
|
orig_mtu = mtu;
|
||||||
|
|
||||||
@ -1311,13 +1299,12 @@ emsgsize:
|
|||||||
* --yoshfuji
|
* --yoshfuji
|
||||||
*/
|
*/
|
||||||
|
|
||||||
skb = skb_peek_tail(&sk->sk_write_queue);
|
|
||||||
cork->length += length;
|
cork->length += length;
|
||||||
if (((length > mtu) ||
|
if (((length > mtu) ||
|
||||||
(skb && skb_is_gso(skb))) &&
|
(skb && skb_is_gso(skb))) &&
|
||||||
(sk->sk_protocol == IPPROTO_UDP) &&
|
(sk->sk_protocol == IPPROTO_UDP) &&
|
||||||
(rt->dst.dev->features & NETIF_F_UFO)) {
|
(rt->dst.dev->features & NETIF_F_UFO)) {
|
||||||
err = ip6_ufo_append_data(sk, getfrag, from, length,
|
err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
|
||||||
hh_len, fragheaderlen,
|
hh_len, fragheaderlen,
|
||||||
transhdrlen, mtu, flags, rt);
|
transhdrlen, mtu, flags, rt);
|
||||||
if (err)
|
if (err)
|
||||||
@ -1458,7 +1445,7 @@ alloc_new_skb:
|
|||||||
/*
|
/*
|
||||||
* Put the packet on the pending queue
|
* Put the packet on the pending queue
|
||||||
*/
|
*/
|
||||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
__skb_queue_tail(queue, skb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1477,7 +1464,6 @@ alloc_new_skb:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int i = skb_shinfo(skb)->nr_frags;
|
int i = skb_shinfo(skb)->nr_frags;
|
||||||
struct page_frag *pfrag = sk_page_frag(sk);
|
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
if (!sk_page_frag_refill(sk, pfrag))
|
if (!sk_page_frag_refill(sk, pfrag))
|
||||||
@ -1520,6 +1506,42 @@ error:
|
|||||||
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
|
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ip6_append_data(struct sock *sk,
|
||||||
|
int getfrag(void *from, char *to, int offset, int len,
|
||||||
|
int odd, struct sk_buff *skb),
|
||||||
|
void *from, int length, int transhdrlen, int hlimit,
|
||||||
|
int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
|
||||||
|
struct rt6_info *rt, unsigned int flags, int dontfrag)
|
||||||
|
{
|
||||||
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||||
|
int exthdrlen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (flags&MSG_PROBE)
|
||||||
|
return 0;
|
||||||
|
if (skb_queue_empty(&sk->sk_write_queue)) {
|
||||||
|
/*
|
||||||
|
* setup for corking
|
||||||
|
*/
|
||||||
|
err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
|
||||||
|
tclass, opt, rt, fl6);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
exthdrlen = (opt ? opt->opt_flen : 0);
|
||||||
|
length += exthdrlen;
|
||||||
|
transhdrlen += exthdrlen;
|
||||||
|
} else {
|
||||||
|
fl6 = &inet->cork.fl.u.ip6;
|
||||||
|
transhdrlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
|
||||||
|
&np->cork, sk_page_frag(sk), getfrag,
|
||||||
|
from, length, transhdrlen, flags, dontfrag);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(ip6_append_data);
|
EXPORT_SYMBOL_GPL(ip6_append_data);
|
||||||
|
|
||||||
static void ip6_cork_release(struct inet_cork_full *cork,
|
static void ip6_cork_release(struct inet_cork_full *cork,
|
||||||
@ -1627,11 +1649,12 @@ error:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
|
EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
|
||||||
|
|
||||||
void ip6_flush_pending_frames(struct sock *sk)
|
static void __ip6_flush_pending_frames(struct sock *sk,
|
||||||
|
struct sk_buff_head *queue)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
|
while ((skb = __skb_dequeue_tail(queue)) != NULL) {
|
||||||
if (skb_dst(skb))
|
if (skb_dst(skb))
|
||||||
IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
|
IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
|
||||||
IPSTATS_MIB_OUTDISCARDS);
|
IPSTATS_MIB_OUTDISCARDS);
|
||||||
@ -1640,4 +1663,9 @@ void ip6_flush_pending_frames(struct sock *sk)
|
|||||||
|
|
||||||
ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
|
ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ip6_flush_pending_frames(struct sock *sk)
|
||||||
|
{
|
||||||
|
__ip6_flush_pending_frames(sk, &sk->sk_write_queue);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
|
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
|
||||||
|
Loading…
Reference in New Issue
Block a user