Skip to content

Commit 6422398

Browse files
vyasevichdavem330
authored andcommitted
ipv6: introduce ipv6_make_skb
This commit is very similar to commit 1c32c5a Author: Herbert Xu <[email protected]> Date: Tue Mar 1 02:36:47 2011 +0000 inet: Add ip_make_skb and ip_finish_skb It adds IPv6 version of the helpers ip6_make_skb and ip6_finish_skb. The job of ip6_make_skb is to collect messages into an ipv6 packet and poplulate ipv6 eader. The job of ip6_finish_skb is to transmit the generated skb. Together they replicated the job of ip6_push_pending_frames() while also provide the capability to be called independently. This will be needed to add lockless UDP sendmsg support. Signed-off-by: Vladislav Yasevich <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0bbe84a commit 6422398

File tree

2 files changed

+103
-19
lines changed

2 files changed

+103
-19
lines changed

include/net/ipv6.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,25 @@ int ip6_push_pending_frames(struct sock *sk);
788788

789789
void ip6_flush_pending_frames(struct sock *sk);
790790

791+
int ip6_send_skb(struct sk_buff *skb);
792+
793+
struct sk_buff *__ip6_make_skb(struct sock *sk, struct sk_buff_head *queue,
794+
struct inet_cork_full *cork,
795+
struct inet6_cork *v6_cork);
796+
struct sk_buff *ip6_make_skb(struct sock *sk,
797+
int getfrag(void *from, char *to, int offset,
798+
int len, int odd, struct sk_buff *skb),
799+
void *from, int length, int transhdrlen,
800+
int hlimit, int tclass, struct ipv6_txoptions *opt,
801+
struct flowi6 *fl6, struct rt6_info *rt,
802+
unsigned int flags, int dontfrag);
803+
804+
static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
805+
{
806+
return __ip6_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork,
807+
&inet6_sk(sk)->cork);
808+
}
809+
791810
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6);
792811
struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
793812
const struct in6_addr *final_dst);

net/ipv6/ip6_output.c

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,30 +1564,31 @@ static void ip6_cork_release(struct inet_cork_full *cork,
15641564
memset(&cork->fl, 0, sizeof(cork->fl));
15651565
}
15661566

1567-
int ip6_push_pending_frames(struct sock *sk)
1567+
struct sk_buff *__ip6_make_skb(struct sock *sk,
1568+
struct sk_buff_head *queue,
1569+
struct inet_cork_full *cork,
1570+
struct inet6_cork *v6_cork)
15681571
{
15691572
struct sk_buff *skb, *tmp_skb;
15701573
struct sk_buff **tail_skb;
15711574
struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
1572-
struct inet_sock *inet = inet_sk(sk);
15731575
struct ipv6_pinfo *np = inet6_sk(sk);
15741576
struct net *net = sock_net(sk);
15751577
struct ipv6hdr *hdr;
1576-
struct ipv6_txoptions *opt = np->cork.opt;
1577-
struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst;
1578-
struct flowi6 *fl6 = &inet->cork.fl.u.ip6;
1578+
struct ipv6_txoptions *opt = v6_cork->opt;
1579+
struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
1580+
struct flowi6 *fl6 = &cork->fl.u.ip6;
15791581
unsigned char proto = fl6->flowi6_proto;
1580-
int err = 0;
15811582

1582-
skb = __skb_dequeue(&sk->sk_write_queue);
1583+
skb = __skb_dequeue(queue);
15831584
if (skb == NULL)
15841585
goto out;
15851586
tail_skb = &(skb_shinfo(skb)->frag_list);
15861587

15871588
/* move skb->data to ip header from ext header */
15881589
if (skb->data < skb_network_header(skb))
15891590
__skb_pull(skb, skb_network_offset(skb));
1590-
while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
1591+
while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
15911592
__skb_pull(tmp_skb, skb_network_header_len(skb));
15921593
*tail_skb = tmp_skb;
15931594
tail_skb = &(tmp_skb->next);
@@ -1612,10 +1613,10 @@ int ip6_push_pending_frames(struct sock *sk)
16121613
skb_reset_network_header(skb);
16131614
hdr = ipv6_hdr(skb);
16141615

1615-
ip6_flow_hdr(hdr, np->cork.tclass,
1616+
ip6_flow_hdr(hdr, v6_cork->tclass,
16161617
ip6_make_flowlabel(net, skb, fl6->flowlabel,
16171618
np->autoflowlabel));
1618-
hdr->hop_limit = np->cork.hop_limit;
1619+
hdr->hop_limit = v6_cork->hop_limit;
16191620
hdr->nexthdr = proto;
16201621
hdr->saddr = fl6->saddr;
16211622
hdr->daddr = *final_dst;
@@ -1632,25 +1633,45 @@ int ip6_push_pending_frames(struct sock *sk)
16321633
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
16331634
}
16341635

1636+
ip6_cork_release(cork, v6_cork);
1637+
out:
1638+
return skb;
1639+
}
1640+
1641+
int ip6_send_skb(struct sk_buff *skb)
1642+
{
1643+
struct net *net = sock_net(skb->sk);
1644+
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
1645+
int err;
1646+
16351647
err = ip6_local_out(skb);
16361648
if (err) {
16371649
if (err > 0)
16381650
err = net_xmit_errno(err);
16391651
if (err)
1640-
goto error;
1652+
IP6_INC_STATS(net, rt->rt6i_idev,
1653+
IPSTATS_MIB_OUTDISCARDS);
16411654
}
16421655

1643-
out:
1644-
ip6_cork_release(&inet->cork, &np->cork);
16451656
return err;
1646-
error:
1647-
IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1648-
goto out;
1657+
}
1658+
1659+
int ip6_push_pending_frames(struct sock *sk)
1660+
{
1661+
struct sk_buff *skb;
1662+
1663+
skb = ip6_finish_skb(sk);
1664+
if (!skb)
1665+
return 0;
1666+
1667+
return ip6_send_skb(skb);
16491668
}
16501669
EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
16511670

16521671
static void __ip6_flush_pending_frames(struct sock *sk,
1653-
struct sk_buff_head *queue)
1672+
struct sk_buff_head *queue,
1673+
struct inet_cork_full *cork,
1674+
struct inet6_cork *v6_cork)
16541675
{
16551676
struct sk_buff *skb;
16561677

@@ -1661,11 +1682,55 @@ static void __ip6_flush_pending_frames(struct sock *sk,
16611682
kfree_skb(skb);
16621683
}
16631684

1664-
ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
1685+
ip6_cork_release(cork, v6_cork);
16651686
}
16661687

16671688
void ip6_flush_pending_frames(struct sock *sk)
16681689
{
1669-
__ip6_flush_pending_frames(sk, &sk->sk_write_queue);
1690+
__ip6_flush_pending_frames(sk, &sk->sk_write_queue,
1691+
&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
16701692
}
16711693
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
1694+
1695+
struct sk_buff *ip6_make_skb(struct sock *sk,
1696+
int getfrag(void *from, char *to, int offset,
1697+
int len, int odd, struct sk_buff *skb),
1698+
void *from, int length, int transhdrlen,
1699+
int hlimit, int tclass,
1700+
struct ipv6_txoptions *opt, struct flowi6 *fl6,
1701+
struct rt6_info *rt, unsigned int flags,
1702+
int dontfrag)
1703+
{
1704+
struct inet_cork_full cork;
1705+
struct inet6_cork v6_cork;
1706+
struct sk_buff_head queue;
1707+
int exthdrlen = (opt ? opt->opt_flen : 0);
1708+
int err;
1709+
1710+
if (flags & MSG_PROBE)
1711+
return NULL;
1712+
1713+
__skb_queue_head_init(&queue);
1714+
1715+
cork.base.flags = 0;
1716+
cork.base.addr = 0;
1717+
cork.base.opt = NULL;
1718+
v6_cork.opt = NULL;
1719+
err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6);
1720+
if (err)
1721+
return ERR_PTR(err);
1722+
1723+
if (dontfrag < 0)
1724+
dontfrag = inet6_sk(sk)->dontfrag;
1725+
1726+
err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork,
1727+
&current->task_frag, getfrag, from,
1728+
length + exthdrlen, transhdrlen + exthdrlen,
1729+
flags, dontfrag);
1730+
if (err) {
1731+
__ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
1732+
return ERR_PTR(err);
1733+
}
1734+
1735+
return __ip6_make_skb(sk, &queue, &cork, &v6_cork);
1736+
}

0 commit comments

Comments
 (0)