Skip to content

Commit 39b6b29

Browse files
committed
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
Jesse Gross says: ==================== [GIT net-next] Open vSwitch Open vSwitch changes for net-next/3.14. Highlights are: * Performance improvements in the mechanism to get packets to userspace using memory mapped netlink and skb zero copy where appropriate. * Per-cpu flow stats in situations where flows are likely to be shared across CPUs. Standard flow stats are used in other situations to save memory and allocation time. * A handful of code cleanups and rationalization. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 56a4342 + 443cd88 commit 39b6b29

File tree

17 files changed

+483
-213
lines changed

17 files changed

+483
-213
lines changed

include/linux/skbuff.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,9 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
24452445
struct pipe_inode_info *pipe, unsigned int len,
24462446
unsigned int flags);
24472447
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
2448+
unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
2449+
void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
2450+
int len, int hlen);
24482451
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
24492452
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
24502453
void skb_scrub_packet(struct sk_buff *skb, bool xnet);

include/net/genetlink.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ struct genl_family {
7373
* @attrs: netlink attributes
7474
* @_net: network namespace
7575
* @user_ptr: user pointers
76+
* @dst_sk: destination socket
7677
*/
7778
struct genl_info {
7879
u32 snd_seq;
@@ -85,6 +86,7 @@ struct genl_info {
8586
struct net * _net;
8687
#endif
8788
void * user_ptr[2];
89+
struct sock * dst_sk;
8890
};
8991

9092
static inline struct net *genl_info_net(struct genl_info *info)
@@ -177,6 +179,8 @@ void genl_notify(struct genl_family *family,
177179
struct sk_buff *skb, struct net *net, u32 portid,
178180
u32 group, struct nlmsghdr *nlh, gfp_t flags);
179181

182+
struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info,
183+
gfp_t flags);
180184
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
181185
struct genl_family *family, int flags, u8 cmd);
182186

include/uapi/linux/openvswitch.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,15 @@ struct ovs_header {
4040

4141
#define OVS_DATAPATH_FAMILY "ovs_datapath"
4242
#define OVS_DATAPATH_MCGROUP "ovs_datapath"
43-
#define OVS_DATAPATH_VERSION 0x1
43+
44+
/* V2:
45+
* - API users are expected to provide OVS_DP_ATTR_USER_FEATURES
46+
* when creating the datapath.
47+
*/
48+
#define OVS_DATAPATH_VERSION 2
49+
50+
/* First OVS datapath version to support features */
51+
#define OVS_DP_VER_FEATURES 2
4452

4553
enum ovs_datapath_cmd {
4654
OVS_DP_CMD_UNSPEC,
@@ -75,6 +83,7 @@ enum ovs_datapath_attr {
7583
OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */
7684
OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */
7785
OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */
86+
OVS_DP_ATTR_USER_FEATURES, /* OVS_DP_F_* */
7887
__OVS_DP_ATTR_MAX
7988
};
8089

@@ -106,6 +115,9 @@ struct ovs_vport_stats {
106115
__u64 tx_dropped; /* no space available in linux */
107116
};
108117

118+
/* Allow last Netlink attribute to be unaligned */
119+
#define OVS_DP_F_UNALIGNED (1 << 0)
120+
109121
/* Fixed logical ports. */
110122
#define OVSP_LOCAL ((__u32)0)
111123

net/core/skbuff.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
21212121
}
21222122
EXPORT_SYMBOL(skb_copy_and_csum_bits);
21232123

2124+
/**
2125+
* skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
2126+
* @from: source buffer
2127+
*
2128+
* Calculates the amount of linear headroom needed in the 'to' skb passed
2129+
* into skb_zerocopy().
2130+
*/
2131+
unsigned int
2132+
skb_zerocopy_headlen(const struct sk_buff *from)
2133+
{
2134+
unsigned int hlen = 0;
2135+
2136+
if (!from->head_frag ||
2137+
skb_headlen(from) < L1_CACHE_BYTES ||
2138+
skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
2139+
hlen = skb_headlen(from);
2140+
2141+
if (skb_has_frag_list(from))
2142+
hlen = from->len;
2143+
2144+
return hlen;
2145+
}
2146+
EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
2147+
2148+
/**
2149+
* skb_zerocopy - Zero copy skb to skb
2150+
* @to: destination buffer
2151+
* @source: source buffer
2152+
* @len: number of bytes to copy from source buffer
2153+
* @hlen: size of linear headroom in destination buffer
2154+
*
2155+
* Copies up to `len` bytes from `from` to `to` by creating references
2156+
* to the frags in the source buffer.
2157+
*
2158+
* The `hlen` as calculated by skb_zerocopy_headlen() specifies the
2159+
* headroom in the `to` buffer.
2160+
*/
2161+
void
2162+
skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
2163+
{
2164+
int i, j = 0;
2165+
int plen = 0; /* length of skb->head fragment */
2166+
struct page *page;
2167+
unsigned int offset;
2168+
2169+
BUG_ON(!from->head_frag && !hlen);
2170+
2171+
/* dont bother with small payloads */
2172+
if (len <= skb_tailroom(to)) {
2173+
skb_copy_bits(from, 0, skb_put(to, len), len);
2174+
return;
2175+
}
2176+
2177+
if (hlen) {
2178+
skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
2179+
len -= hlen;
2180+
} else {
2181+
plen = min_t(int, skb_headlen(from), len);
2182+
if (plen) {
2183+
page = virt_to_head_page(from->head);
2184+
offset = from->data - (unsigned char *)page_address(page);
2185+
__skb_fill_page_desc(to, 0, page, offset, plen);
2186+
get_page(page);
2187+
j = 1;
2188+
len -= plen;
2189+
}
2190+
}
2191+
2192+
to->truesize += len + plen;
2193+
to->len += len + plen;
2194+
to->data_len += len + plen;
2195+
2196+
for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
2197+
if (!len)
2198+
break;
2199+
skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
2200+
skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
2201+
len -= skb_shinfo(to)->frags[j].size;
2202+
skb_frag_ref(to, j);
2203+
j++;
2204+
}
2205+
skb_shinfo(to)->nr_frags = j;
2206+
}
2207+
EXPORT_SYMBOL_GPL(skb_zerocopy);
2208+
21242209
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
21252210
{
21262211
__wsum csum;

net/netfilter/nfnetlink_queue_core.c

Lines changed: 4 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -236,51 +236,6 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
236236
spin_unlock_bh(&queue->lock);
237237
}
238238

239-
static void
240-
nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
241-
{
242-
int i, j = 0;
243-
int plen = 0; /* length of skb->head fragment */
244-
struct page *page;
245-
unsigned int offset;
246-
247-
/* dont bother with small payloads */
248-
if (len <= skb_tailroom(to)) {
249-
skb_copy_bits(from, 0, skb_put(to, len), len);
250-
return;
251-
}
252-
253-
if (hlen) {
254-
skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
255-
len -= hlen;
256-
} else {
257-
plen = min_t(int, skb_headlen(from), len);
258-
if (plen) {
259-
page = virt_to_head_page(from->head);
260-
offset = from->data - (unsigned char *)page_address(page);
261-
__skb_fill_page_desc(to, 0, page, offset, plen);
262-
get_page(page);
263-
j = 1;
264-
len -= plen;
265-
}
266-
}
267-
268-
to->truesize += len + plen;
269-
to->len += len + plen;
270-
to->data_len += len + plen;
271-
272-
for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
273-
if (!len)
274-
break;
275-
skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
276-
skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
277-
len -= skb_shinfo(to)->frags[j].size;
278-
skb_frag_ref(to, j);
279-
j++;
280-
}
281-
skb_shinfo(to)->nr_frags = j;
282-
}
283-
284239
static int
285240
nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
286241
bool csum_verify)
@@ -330,7 +285,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
330285
{
331286
size_t size;
332287
size_t data_len = 0, cap_len = 0;
333-
int hlen = 0;
288+
unsigned int hlen = 0;
334289
struct sk_buff *skb;
335290
struct nlattr *nla;
336291
struct nfqnl_msg_packet_hdr *pmsg;
@@ -382,14 +337,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
382337
if (data_len > entskb->len)
383338
data_len = entskb->len;
384339

385-
if (!entskb->head_frag ||
386-
skb_headlen(entskb) < L1_CACHE_BYTES ||
387-
skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS)
388-
hlen = skb_headlen(entskb);
389-
390-
if (skb_has_frag_list(entskb))
391-
hlen = entskb->len;
392-
hlen = min_t(int, data_len, hlen);
340+
hlen = skb_zerocopy_headlen(entskb);
341+
hlen = min_t(unsigned int, hlen, data_len);
393342
size += sizeof(struct nlattr) + hlen;
394343
cap_len = entskb->len;
395344
break;
@@ -539,7 +488,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
539488
nla->nla_type = NFQA_PAYLOAD;
540489
nla->nla_len = nla_attr_size(data_len);
541490

542-
nfqnl_zcopy(skb, entskb, data_len, hlen);
491+
skb_zerocopy(skb, entskb, data_len, hlen);
543492
}
544493

545494
nlh->nlmsg_len = skb->len;

net/netlink/af_netlink.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,9 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
17731773
if (ring->pg_vec == NULL)
17741774
goto out_put;
17751775

1776+
if (ring->frame_size - NL_MMAP_HDRLEN < size)
1777+
goto out_put;
1778+
17761779
skb = alloc_skb_head(gfp_mask);
17771780
if (skb == NULL)
17781781
goto err1;
@@ -1782,6 +1785,7 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
17821785
if (ring->pg_vec == NULL)
17831786
goto out_free;
17841787

1788+
/* check again under lock */
17851789
maxlen = ring->frame_size - NL_MMAP_HDRLEN;
17861790
if (maxlen < size)
17871791
goto out_free;

net/netlink/genetlink.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,26 @@ int genl_unregister_family(struct genl_family *family)
460460
}
461461
EXPORT_SYMBOL(genl_unregister_family);
462462

463+
/**
464+
* genlmsg_new_unicast - Allocate generic netlink message for unicast
465+
* @payload: size of the message payload
466+
* @info: information on destination
467+
* @flags: the type of memory to allocate
468+
*
469+
* Allocates a new sk_buff large enough to cover the specified payload
470+
* plus required Netlink headers. Will check receiving socket for
471+
* memory mapped i/o capability and use it if enabled. Will fall back
472+
* to non-mapped skb if message size exceeds the frame size of the ring.
473+
*/
474+
struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info,
475+
gfp_t flags)
476+
{
477+
size_t len = nlmsg_total_size(genlmsg_total_size(payload));
478+
479+
return netlink_alloc_skb(info->dst_sk, len, info->snd_portid, flags);
480+
}
481+
EXPORT_SYMBOL_GPL(genlmsg_new_unicast);
482+
463483
/**
464484
* genlmsg_put - Add generic netlink header to netlink message
465485
* @skb: socket buffer holding the message
@@ -600,6 +620,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
600620
info.genlhdr = nlmsg_data(nlh);
601621
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
602622
info.attrs = attrbuf;
623+
info.dst_sk = skb->sk;
603624
genl_info_net_set(&info, net);
604625
memset(&info.user_ptr, 0, sizeof(info.user_ptr));
605626

0 commit comments

Comments
 (0)