* [PATCH net-next 4/4] enic: add ethtool support for changing alloc order
From: Govindarajulu Varadarajan @ 2015-01-31 12:28 UTC (permalink / raw)
To: davem, netdev; +Cc: ssujith, benve, edumazet, ben, Govindarajulu Varadarajan
In-Reply-To: <1422707290-939-1-git-send-email-_govind@gmx.com>
Adds support for changing page order of enic frag allocator.
In case of changing mtu, if size of new mtu is greater than size of compound
page allocated in enic frag allocator, we change the order to min order required
for the new mtu. We would like to give high priority for changing mtu than order
value.
Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com>
---
drivers/net/ethernet/cisco/enic/enic_ethtool.c | 15 +++++++++++++++
drivers/net/ethernet/cisco/enic/enic_main.c | 18 ++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index 3f9d91b..e29423c 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -18,6 +18,7 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
#include "enic_res.h"
#include "enic.h"
@@ -409,6 +410,9 @@ static int enic_get_tunable(struct net_device *dev,
case ETHTOOL_RX_COPYBREAK:
*(u32 *)data = enic->rx_copybreak;
break;
+ case ETHTOOL_RX_ALLOC_ORDER:
+ *(u8 *)data = enic->alloc_order;
+ break;
default:
ret = -EINVAL;
break;
@@ -428,6 +432,17 @@ static int enic_set_tunable(struct net_device *dev,
case ETHTOOL_RX_COPYBREAK:
enic->rx_copybreak = *(u32 *)data;
break;
+ case ETHTOOL_RX_ALLOC_ORDER:
+ ret = dev->mtu + VLAN_ETH_HLEN + NET_IP_ALIGN + NET_SKB_PAD;
+ ret = SKB_DATA_ALIGN(ret) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ if (*(u8 *)data < get_order(ret)) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = 0;
+ enic->alloc_order = *(u8 *)data;
+ break;
default:
ret = -EINVAL;
break;
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index f15687d..4a759a0 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -1872,7 +1872,11 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)
{
struct enic *enic = netdev_priv(netdev);
int running = netif_running(netdev);
+ size_t len;
+ len = new_mtu + VLAN_ETH_HLEN + NET_IP_ALIGN + NET_SKB_PAD;
+ len = SKB_DATA_ALIGN(len) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU)
return -EINVAL;
@@ -1884,6 +1888,11 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
+ if (len > (PAGE_SIZE << enic->alloc_order)) {
+ enic->alloc_order = get_order(len);
+ netdev_warn(netdev, "new mtu is greater than size of rx alloc_page, resetting enic->alloc_order to :%d\n",
+ enic->alloc_order);
+ }
if (netdev->mtu > enic->port_mtu)
netdev_warn(netdev,
"interface MTU (%d) set higher than port MTU (%d)\n",
@@ -1902,8 +1911,12 @@ static void enic_change_mtu_work(struct work_struct *work)
int new_mtu = vnic_dev_mtu(enic->vdev);
int err;
unsigned int i;
+ size_t len;
new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu));
+ len = new_mtu + VLAN_ETH_HLEN + NET_IP_ALIGN + NET_SKB_PAD;
+ len = SKB_DATA_ALIGN(len) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
rtnl_lock();
@@ -1927,6 +1940,11 @@ static void enic_change_mtu_work(struct work_struct *work)
/* Fill RQ with new_mtu-sized buffers */
netdev->mtu = new_mtu;
+ if (len > (PAGE_SIZE << enic->alloc_order)) {
+ enic->alloc_order = get_order(len);
+ netdev_warn(netdev, "new mtu is greater than size of rx alloc_page, resetting enic->alloc_order to :%d\n",
+ enic->alloc_order);
+ }
vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
/* Need at least one buffer on ring to get going */
if (vnic_rq_desc_used(&enic->rq[0]) == 0) {
--
2.2.2
^ permalink raw reply related
* Re: [PATCH 2/6] rhashtable: Use a single bucket lock for sibling buckets
From: Thomas Graf @ 2015-01-31 12:50 UTC (permalink / raw)
To: Herbert Xu; +Cc: davem, netdev, ying.xue
In-Reply-To: <20150131093812.GA29240@gondor.apana.org.au>
On 01/31/15 at 08:38pm, Herbert Xu wrote:
> On Sat, Jan 31, 2015 at 08:41:27AM +0000, Thomas Graf wrote:
> > On 01/31/15 at 03:34pm, Herbert Xu wrote:
> > > Thomas, could you please hold off on these changes? They totally
> > > conflict with my rehash work, which is going to render these changes
> > > moot anyway since it'll completely change how expansion/shrinking
> > > works.
> >
> > Can you share that work?
>
> I will post it when it's ready. But if you keep moving the goal
> posts then I'll never get there.
My intent is definitely not to make it harder for you. My intent
is fix the remaining races which were reported before net-next gets
merged. I'm happy to hold off if you plan on proposing your rehashing
in the current net-next cycle.
^ permalink raw reply
* Hello B !! !!
From: Ahmed Mohammed @ 2015-01-31 13:29 UTC (permalink / raw)
To: netdev
Für Ihre Aufmerksamkeit, ich werde mich sehr freuen, wenn Sie mir helfen, eine Summe ( 69,500,000.00 Euro) auf Ihr persönliches Bankkonto zu Gunsten der uns beide und zukünftige Investitionen in Ihrem Land.
Beachten Sie, bin ich mit der Bundesregierung Rohöl Unternehmen Einrichtungen arbeiten hier, und wir sind nicht gestattet oder erlaubt, ausländisches Bankkonto haben, und wenn dieses Geld in meinem lokalen Konto zu sehen hier dann Regierung wird mich vermuten, daher brauche ich Ihre Hilfe, um die Empfangs riesige Mittel in meinem Namen, das werde ich für Ihre Unterstützung erhalten Sie 30%. Ich werde Ihnen mehr Details, sobald ich von Ihnen höre senden
Bitte senden Sie mir dringend Ihren vollständigen Namen und Ihre Adresse, Ihre Telefonnummern anruft, Ihre Handynummer und Ihre Bankverbindung für die Übertragung des Sondervermögens für mein Unternehmen Investitionen in Ihrem Land
Grüße
Ahmed Mohammed
^ permalink raw reply
* [PATCH net-next 0/6] ipv6: Add lockless UDP send path
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
This series introduces a lockless UDPv6 send path similar to
what Herbert Xu did for IPv4 a while ago.
There are some difference from IPv4. IPv6 caching for flow
label is a bit different, as well as it requires another cork
cork structure that holds the IPv6 ancillary data.
Please take a look.
Thanks
-vlad
Vladislav Yasevich (5):
ipv6: pull cork initialization into its own function.
ipv6: Append sending data to arbitrary queue
ipv6: introduce ipv6_make_skb
ipv6: Introduce udpv6_send_skb()
udpv6: Add lockless sendmsg() support
include/linux/ipv6.h | 12 +-
include/net/ipv6.h | 19 +++
net/ipv6/ip6_output.c | 349 +++++++++++++++++++++++++++++++++-----------------
net/ipv6/udp.c | 91 ++++++++-----
4 files changed, 317 insertions(+), 154 deletions(-)
--
1.9.3
^ permalink raw reply
* [PATCH net-next 1/6] ipv6: pull cork initialization into its own function.
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
Pull IPv6 cork initialization into its own function that
can be re-used. IPv6 specific cork data did not have an
explicit data structure. This patch creats eone so that
just ipv6 cork data can be as arguemts. Also, since
IPv6 tries to save the flow label into inet_cork_full
tructure, pass the full cork.
Adjust ip6_cork_release() to take cork data structures.
Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
---
include/linux/ipv6.h | 12 ++--
net/ipv6/ip6_output.c | 158 ++++++++++++++++++++++++++++----------------------
2 files changed, 96 insertions(+), 74 deletions(-)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 2805062..4d5169f 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -125,6 +125,12 @@ struct ipv6_mc_socklist;
struct ipv6_ac_socklist;
struct ipv6_fl_socklist;
+struct inet6_cork {
+ struct ipv6_txoptions *opt;
+ u8 hop_limit;
+ u8 tclass;
+};
+
/**
* struct ipv6_pinfo - ipv6 private area
*
@@ -217,11 +223,7 @@ struct ipv6_pinfo {
struct ipv6_txoptions *opt;
struct sk_buff *pktoptions;
struct sk_buff *rxpmtu;
- struct {
- struct ipv6_txoptions *opt;
- u8 hop_limit;
- u8 tclass;
- } cork;
+ struct inet6_cork cork;
};
/* WARNING: don't change the layout of the members in {raw,udp,tcp}6_sock! */
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index ce69a12..f9f08c4 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1135,6 +1135,74 @@ static void ip6_append_data_mtu(unsigned int *mtu,
}
}
+static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
+ struct inet6_cork *v6_cork,
+ int hlimit, int tclass, struct ipv6_txoptions *opt,
+ struct rt6_info *rt, struct flowi6 *fl6)
+{
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ unsigned int mtu;
+
+ /*
+ * setup for corking
+ */
+ if (opt) {
+ if (WARN_ON(v6_cork->opt))
+ return -EINVAL;
+
+ v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation);
+ if (unlikely(v6_cork->opt == NULL))
+ return -ENOBUFS;
+
+ v6_cork->opt->tot_len = opt->tot_len;
+ v6_cork->opt->opt_flen = opt->opt_flen;
+ v6_cork->opt->opt_nflen = opt->opt_nflen;
+
+ v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt,
+ sk->sk_allocation);
+ if (opt->dst0opt && !v6_cork->opt->dst0opt)
+ return -ENOBUFS;
+
+ v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt,
+ sk->sk_allocation);
+ if (opt->dst1opt && !v6_cork->opt->dst1opt)
+ return -ENOBUFS;
+
+ v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt,
+ sk->sk_allocation);
+ if (opt->hopopt && !v6_cork->opt->hopopt)
+ return -ENOBUFS;
+
+ v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt,
+ sk->sk_allocation);
+ if (opt->srcrt && !v6_cork->opt->srcrt)
+ return -ENOBUFS;
+
+ /* need source address above miyazawa*/
+ }
+ dst_hold(&rt->dst);
+ cork->base.dst = &rt->dst;
+ cork->fl.u.ip6 = *fl6;
+ v6_cork->hop_limit = hlimit;
+ v6_cork->tclass = tclass;
+ if (rt->dst.flags & DST_XFRM_TUNNEL)
+ mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
+ rt->dst.dev->mtu : dst_mtu(&rt->dst);
+ else
+ mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
+ rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+ if (np->frag_size < mtu) {
+ if (np->frag_size)
+ mtu = np->frag_size;
+ }
+ cork->base.fragsize = mtu;
+ if (dst_allfrag(rt->dst.path))
+ cork->base.flags |= IPCORK_ALLFRAG;
+ cork->base.length = 0;
+
+ return 0;
+}
+
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,
@@ -1162,59 +1230,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
/*
* setup for corking
*/
- if (opt) {
- if (WARN_ON(np->cork.opt))
- return -EINVAL;
-
- np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation);
- if (unlikely(np->cork.opt == NULL))
- return -ENOBUFS;
-
- np->cork.opt->tot_len = opt->tot_len;
- np->cork.opt->opt_flen = opt->opt_flen;
- np->cork.opt->opt_nflen = opt->opt_nflen;
-
- np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
- sk->sk_allocation);
- if (opt->dst0opt && !np->cork.opt->dst0opt)
- return -ENOBUFS;
-
- np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
- sk->sk_allocation);
- if (opt->dst1opt && !np->cork.opt->dst1opt)
- return -ENOBUFS;
-
- np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
- sk->sk_allocation);
- if (opt->hopopt && !np->cork.opt->hopopt)
- return -ENOBUFS;
-
- np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
- sk->sk_allocation);
- if (opt->srcrt && !np->cork.opt->srcrt)
- return -ENOBUFS;
-
- /* need source address above miyazawa*/
- }
- dst_hold(&rt->dst);
- cork->dst = &rt->dst;
- inet->cork.fl.u.ip6 = *fl6;
- np->cork.hop_limit = hlimit;
- np->cork.tclass = tclass;
- if (rt->dst.flags & DST_XFRM_TUNNEL)
- mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
- rt->dst.dev->mtu : dst_mtu(&rt->dst);
- else
- mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
- rt->dst.dev->mtu : dst_mtu(rt->dst.path);
- if (np->frag_size < mtu) {
- if (np->frag_size)
- mtu = np->frag_size;
- }
- cork->fragsize = mtu;
- if (dst_allfrag(rt->dst.path))
- cork->flags |= IPCORK_ALLFRAG;
- cork->length = 0;
+ 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;
@@ -1226,8 +1245,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
transhdrlen = 0;
exthdrlen = 0;
dst_exthdrlen = 0;
- mtu = cork->fragsize;
}
+ mtu = cork->fragsize;
orig_mtu = mtu;
hh_len = LL_RESERVED_SPACE(rt->dst.dev);
@@ -1503,23 +1522,24 @@ error:
}
EXPORT_SYMBOL_GPL(ip6_append_data);
-static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
+static void ip6_cork_release(struct inet_cork_full *cork,
+ struct inet6_cork *v6_cork)
{
- if (np->cork.opt) {
- kfree(np->cork.opt->dst0opt);
- kfree(np->cork.opt->dst1opt);
- kfree(np->cork.opt->hopopt);
- kfree(np->cork.opt->srcrt);
- kfree(np->cork.opt);
- np->cork.opt = NULL;
+ if (v6_cork->opt) {
+ kfree(v6_cork->opt->dst0opt);
+ kfree(v6_cork->opt->dst1opt);
+ kfree(v6_cork->opt->hopopt);
+ kfree(v6_cork->opt->srcrt);
+ kfree(v6_cork->opt);
+ v6_cork->opt = NULL;
}
- if (inet->cork.base.dst) {
- dst_release(inet->cork.base.dst);
- inet->cork.base.dst = NULL;
- inet->cork.base.flags &= ~IPCORK_ALLFRAG;
+ if (cork->base.dst) {
+ dst_release(cork->base.dst);
+ cork->base.dst = NULL;
+ cork->base.flags &= ~IPCORK_ALLFRAG;
}
- memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
+ memset(&cork->fl, 0, sizeof(cork->fl));
}
int ip6_push_pending_frames(struct sock *sk)
@@ -1599,7 +1619,7 @@ int ip6_push_pending_frames(struct sock *sk)
}
out:
- ip6_cork_release(inet, np);
+ ip6_cork_release(&inet->cork, &np->cork);
return err;
error:
IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
@@ -1618,6 +1638,6 @@ void ip6_flush_pending_frames(struct sock *sk)
kfree_skb(skb);
}
- ip6_cork_release(inet_sk(sk), inet6_sk(sk));
+ ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
}
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 2/6] ipv6: Append sending data to arbitrary queue
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
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>
---
net/ipv6/ip6_output.c | 106 +++++++++++++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 39 deletions(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index f9f08c4..1b66453 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -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);
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 odd, struct sk_buff *skb),
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
* udp datagram
*/
- skb = skb_peek_tail(&sk->sk_write_queue);
+ skb = skb_peek_tail(queue);
if (skb == NULL) {
skb = sock_alloc_send_skb(sk,
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->csum = 0;
- __skb_queue_tail(&sk->sk_write_queue, skb);
+ __skb_queue_tail(queue, skb);
} else if (skb_is_gso(skb)) {
goto append;
}
@@ -1203,49 +1204,36 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
return 0;
}
-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)
+static int __ip6_append_data(struct sock *sk,
+ struct flowi6 *fl6,
+ struct sk_buff_head *queue,
+ struct inet_cork *cork,
+ 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;
unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
- int exthdrlen;
- int dst_exthdrlen;
+ int exthdrlen = 0;
+ int dst_exthdrlen = 0;
int hh_len;
int copy;
int err;
int offset = 0;
__u8 tx_flags = 0;
u32 tskey = 0;
+ struct rt6_info *rt = (struct rt6_info *)cork->dst;
+ struct ipv6_txoptions *opt = v6_cork->opt;
- if (flags&MSG_PROBE)
- return 0;
- cork = &inet->cork.base;
- 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;
+ skb = skb_peek_tail(queue);
+ if (!skb) {
+ exthdrlen = opt ? opt->opt_flen : 0;
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;
orig_mtu = mtu;
@@ -1311,13 +1299,12 @@ emsgsize:
* --yoshfuji
*/
- skb = skb_peek_tail(&sk->sk_write_queue);
cork->length += length;
if (((length > mtu) ||
(skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(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,
transhdrlen, mtu, flags, rt);
if (err)
@@ -1458,7 +1445,7 @@ alloc_new_skb:
/*
* Put the packet on the pending queue
*/
- __skb_queue_tail(&sk->sk_write_queue, skb);
+ __skb_queue_tail(queue, skb);
continue;
}
@@ -1477,7 +1464,6 @@ alloc_new_skb:
}
} else {
int i = skb_shinfo(skb)->nr_frags;
- struct page_frag *pfrag = sk_page_frag(sk);
err = -ENOMEM;
if (!sk_page_frag_refill(sk, pfrag))
@@ -1520,6 +1506,42 @@ error:
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
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);
static void ip6_cork_release(struct inet_cork_full *cork,
@@ -1627,11 +1649,12 @@ error:
}
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;
- while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
+ while ((skb = __skb_dequeue_tail(queue)) != NULL) {
if (skb_dst(skb))
IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
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);
}
+
+void ip6_flush_pending_frames(struct sock *sk)
+{
+ __ip6_flush_pending_frames(sk, &sk->sk_write_queue);
+}
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 3/6] ipv6: introduce ipv6_make_skb
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
This commit is very similar to
commit 1c32c5ad6fac8cee1a77449f5abf211e911ff830
Author: Herbert Xu <herbert@gondor.apana.org.au>
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 <vyasevic@redhat.com>
---
include/net/ipv6.h | 19 ++++++++++
net/ipv6/ip6_output.c | 103 ++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 103 insertions(+), 19 deletions(-)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 4292929..8027ca5 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -788,6 +788,25 @@ int ip6_push_pending_frames(struct sock *sk);
void ip6_flush_pending_frames(struct sock *sk);
+int ip6_send_skb(struct sk_buff *skb);
+
+struct sk_buff *__ip6_make_skb(struct sock *sk, struct sk_buff_head *queue,
+ struct inet_cork_full *cork,
+ struct inet6_cork *v6_cork);
+struct sk_buff *ip6_make_skb(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);
+
+static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
+{
+ return __ip6_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork,
+ &inet6_sk(sk)->cork);
+}
+
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6);
struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 1b66453..b89d3c2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1564,22 +1564,23 @@ static void ip6_cork_release(struct inet_cork_full *cork,
memset(&cork->fl, 0, sizeof(cork->fl));
}
-int ip6_push_pending_frames(struct sock *sk)
+struct sk_buff *__ip6_make_skb(struct sock *sk,
+ struct sk_buff_head *queue,
+ struct inet_cork_full *cork,
+ struct inet6_cork *v6_cork)
{
struct sk_buff *skb, *tmp_skb;
struct sk_buff **tail_skb;
struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
- struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk);
struct ipv6hdr *hdr;
- struct ipv6_txoptions *opt = np->cork.opt;
- struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst;
- struct flowi6 *fl6 = &inet->cork.fl.u.ip6;
+ struct ipv6_txoptions *opt = v6_cork->opt;
+ struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
+ struct flowi6 *fl6 = &cork->fl.u.ip6;
unsigned char proto = fl6->flowi6_proto;
- int err = 0;
- skb = __skb_dequeue(&sk->sk_write_queue);
+ skb = __skb_dequeue(queue);
if (skb == NULL)
goto out;
tail_skb = &(skb_shinfo(skb)->frag_list);
@@ -1587,7 +1588,7 @@ int ip6_push_pending_frames(struct sock *sk)
/* move skb->data to ip header from ext header */
if (skb->data < skb_network_header(skb))
__skb_pull(skb, skb_network_offset(skb));
- while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
+ while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
__skb_pull(tmp_skb, skb_network_header_len(skb));
*tail_skb = tmp_skb;
tail_skb = &(tmp_skb->next);
@@ -1612,10 +1613,10 @@ int ip6_push_pending_frames(struct sock *sk)
skb_reset_network_header(skb);
hdr = ipv6_hdr(skb);
- ip6_flow_hdr(hdr, np->cork.tclass,
+ ip6_flow_hdr(hdr, v6_cork->tclass,
ip6_make_flowlabel(net, skb, fl6->flowlabel,
np->autoflowlabel));
- hdr->hop_limit = np->cork.hop_limit;
+ hdr->hop_limit = v6_cork->hop_limit;
hdr->nexthdr = proto;
hdr->saddr = fl6->saddr;
hdr->daddr = *final_dst;
@@ -1632,25 +1633,45 @@ int ip6_push_pending_frames(struct sock *sk)
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
}
+ ip6_cork_release(cork, v6_cork);
+out:
+ return skb;
+}
+
+int ip6_send_skb(struct sk_buff *skb)
+{
+ struct net *net = sock_net(skb->sk);
+ struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
+ int err;
+
err = ip6_local_out(skb);
if (err) {
if (err > 0)
err = net_xmit_errno(err);
if (err)
- goto error;
+ IP6_INC_STATS(net, rt->rt6i_idev,
+ IPSTATS_MIB_OUTDISCARDS);
}
-out:
- ip6_cork_release(&inet->cork, &np->cork);
return err;
-error:
- IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
- goto out;
+}
+
+int ip6_push_pending_frames(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ skb = ip6_finish_skb(sk);
+ if (!skb)
+ return 0;
+
+ return ip6_send_skb(skb);
}
EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
static void __ip6_flush_pending_frames(struct sock *sk,
- struct sk_buff_head *queue)
+ struct sk_buff_head *queue,
+ struct inet_cork_full *cork,
+ struct inet6_cork *v6_cork)
{
struct sk_buff *skb;
@@ -1661,11 +1682,55 @@ static void __ip6_flush_pending_frames(struct sock *sk,
kfree_skb(skb);
}
- ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
+ ip6_cork_release(cork, v6_cork);
}
void ip6_flush_pending_frames(struct sock *sk)
{
- __ip6_flush_pending_frames(sk, &sk->sk_write_queue);
+ __ip6_flush_pending_frames(sk, &sk->sk_write_queue,
+ &inet_sk(sk)->cork, &inet6_sk(sk)->cork);
}
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
+
+struct sk_buff *ip6_make_skb(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_cork_full cork;
+ struct inet6_cork v6_cork;
+ struct sk_buff_head queue;
+ int exthdrlen = (opt ? opt->opt_flen : 0);
+ int err;
+
+ if (flags & MSG_PROBE)
+ return NULL;
+
+ __skb_queue_head_init(&queue);
+
+ cork.base.flags = 0;
+ cork.base.addr = 0;
+ cork.base.opt = NULL;
+ v6_cork.opt = NULL;
+ err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6);
+ if (err)
+ return ERR_PTR(err);
+
+ if (dontfrag < 0)
+ dontfrag = inet6_sk(sk)->dontfrag;
+
+ err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork,
+ ¤t->task_frag, getfrag, from,
+ length + exthdrlen, transhdrlen + exthdrlen,
+ flags, dontfrag);
+ if (err) {
+ __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
+ return ERR_PTR(err);
+ }
+
+ return __ip6_make_skb(sk, &queue, &cork, &v6_cork);
+}
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 4/6] ipv6: Introduce udpv6_send_skb()
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
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 <vyasevic@redhat.com>
---
net/ipv6/udp.c | 67 +++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 40 insertions(+), 27 deletions(-)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index e41f017..67a3d70 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
{
unsigned int offset;
struct udphdr *uh = udp_hdr(skb);
+ struct sk_buff *frags = skb_shinfo(skb)->frag_list;
__wsum csum = 0;
- if (skb_queue_len(&sk->sk_write_queue) == 1) {
+ if (!frags) {
/* Only one fragment on the socket. */
skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct udphdr, check);
@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
skb->ip_summed = CHECKSUM_NONE;
- skb_queue_walk(&sk->sk_write_queue, skb) {
- csum = csum_add(csum, skb->csum);
- }
+ do {
+ csum = csum_add(csum, frags->csum);
+ } while ((frags = frags->next));
uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
csum);
@@ -1023,26 +1024,15 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
* Sending
*/
-static int udp_v6_push_pending_frames(struct sock *sk)
+static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6)
{
- struct sk_buff *skb;
+ struct sock *sk = skb->sk;
struct udphdr *uh;
- struct udp_sock *up = udp_sk(sk);
- struct inet_sock *inet = inet_sk(sk);
- struct flowi6 *fl6;
int err = 0;
int is_udplite = IS_UDPLITE(sk);
__wsum csum = 0;
-
- if (up->pending == AF_INET)
- return udp_push_pending_frames(sk);
-
- fl6 = &inet->cork.fl.u.ip6;
-
- /* Grab the skbuff where UDP header space exists. */
- skb = skb_peek(&sk->sk_write_queue);
- if (skb == NULL)
- goto out;
+ int offset = skb_transport_offset(skb);
+ int len = skb->len - offset;
/*
* Create a UDP header
@@ -1050,29 +1040,28 @@ static int udp_v6_push_pending_frames(struct sock *sk)
uh = udp_hdr(skb);
uh->source = fl6->fl6_sport;
uh->dest = fl6->fl6_dport;
- uh->len = htons(up->len);
+ uh->len = htons(len);
uh->check = 0;
if (is_udplite)
- csum = udplite_csum_outgoing(sk, skb);
- else if (up->no_check6_tx) { /* UDP csum disabled */
+ csum = udplite_csum(skb);
+ else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */
skb->ip_summed = CHECKSUM_NONE;
goto send;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
- udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr,
- up->len);
+ udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len);
goto send;
} else
- csum = udp_csum_outgoing(sk, skb);
+ csum = udp_csum(skb);
/* add protocol-dependent pseudo-header */
uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
- up->len, fl6->flowi6_proto, csum);
+ len, fl6->flowi6_proto, csum);
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
send:
- err = ip6_push_pending_frames(sk);
+ err = ip6_send_skb(skb);
if (err) {
if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
UDP6_INC_STATS_USER(sock_net(sk),
@@ -1082,6 +1071,30 @@ send:
} else
UDP6_INC_STATS_USER(sock_net(sk),
UDP_MIB_OUTDATAGRAMS, is_udplite);
+ return err;
+}
+
+static int udp_v6_push_pending_frames(struct sock *sk)
+{
+ struct sk_buff *skb;
+ struct udp_sock *up = udp_sk(sk);
+ struct flowi6 fl6;
+ int err = 0;
+
+ if (up->pending == AF_INET)
+ return udp_push_pending_frames(sk);
+
+ /* ip6_finish_skb will release the cork, so make a copy of
+ * fl6 here.
+ */
+ fl6 = inet_sk(sk)->cork.fl.u.ip6;
+
+ skb = ip6_finish_skb(sk);
+ if (!skb)
+ goto out;
+
+ err = udp_v6_send_skb(skb, &fl6);
+
out:
up->len = 0;
up->pending = 0;
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 5/6] udpv6: Add lockless sendmsg() support
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
This commit adds the same functionaliy to IPv6 that
commit 903ab86d195cca295379699299c5fc10beba31c7
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue Mar 1 02:36:48 2011 +0000
udp: Add lockless transmit path
added to IPv4.
UDP transmit path can now run without a socket lock,
thus allowing multiple threads to send to a single socket
more efficiently.
This is only used when corking/MSG_MORE is not used.
Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
---
net/ipv6/udp.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 67a3d70..d048d46 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1177,6 +1177,7 @@ do_udp_sendmsg:
if (len > INT_MAX - sizeof(struct udphdr))
return -EMSGSIZE;
+ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
if (up->pending) {
/*
* There are pending frames.
@@ -1307,6 +1308,20 @@ do_udp_sendmsg:
goto do_confirm;
back_from_confirm:
+ /* Lockless fast path for the non-corking case */
+ if (!corkreq) {
+ struct sk_buff *skb;
+
+ skb = ip6_make_skb(sk, getfrag, msg, ulen,
+ sizeof(struct udphdr), hlimit, tclass, opt,
+ &fl6, (struct rt6_info *)dst,
+ msg->msg_flags, dontfrag);
+ err = PTR_ERR(skb);
+ if (!IS_ERR_OR_NULL(skb))
+ err = udp_v6_send_skb(skb, &fl6);
+ goto release_dst;
+ }
+
lock_sock(sk);
if (unlikely(up->pending)) {
/* The socket is already corked while preparing it. */
@@ -1324,7 +1339,6 @@ do_append_data:
if (dontfrag < 0)
dontfrag = np->dontfrag;
up->len += ulen;
- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
err = ip6_append_data(sk, getfrag, msg, ulen,
sizeof(struct udphdr), hlimit, tclass, opt, &fl6,
(struct rt6_info *)dst,
@@ -1336,6 +1350,11 @@ do_append_data:
else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
up->pending = 0;
+ if (err > 0)
+ err = np->recverr ? net_xmit_errno(err) : 0;
+ release_sock(sk);
+
+release_dst:
if (dst) {
if (connected) {
ip6_dst_store(sk, dst,
@@ -1352,9 +1371,6 @@ do_append_data:
dst = NULL;
}
- if (err > 0)
- err = np->recverr ? net_xmit_errno(err) : 0;
- release_sock(sk);
out:
dst_release(dst);
fl6_sock_release(flowlabel);
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 6/6] ipv6: Allow for partial checksums on non-ufo packets
From: Vladislav Yasevich @ 2015-01-31 15:40 UTC (permalink / raw)
To: netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-1-git-send-email-vyasevic@redhat.com>
Currntly, if we are not doing UFO on the packet, all UDP
packets will start with CHECKSUM_NONE and thus perform full
checksum computations in software even if device support
IPv6 checksum offloading.
Let's start start with CHECKSUM_PARTIAL if the device
supports it and we are sending only a single packet at
or below mtu size.
Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
---
net/ipv6/ip6_output.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index b89d3c2..1a036f3 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1227,6 +1227,7 @@ static int __ip6_append_data(struct sock *sk,
u32 tskey = 0;
struct rt6_info *rt = (struct rt6_info *)cork->dst;
struct ipv6_txoptions *opt = v6_cork->opt;
+ int csummode = CHECKSUM_NONE;
skb = skb_peek_tail(queue);
if (!skb) {
@@ -1283,6 +1284,14 @@ emsgsize:
tskey = sk->sk_tskey++;
}
+ /* If this is the first and only packet and device
+ * supports checksum offloading, let's use it.
+ */
+ if (!skb &&
+ length + fragheaderlen < mtu &&
+ rt->dst.dev->features & NETIF_F_V6_CSUM &&
+ !exthdrlen)
+ csummode = CHECKSUM_PARTIAL;
/*
* Let's try using as much space as possible.
* Use MTU if total length of the message fits into the MTU.
@@ -1395,7 +1404,7 @@ alloc_new_skb:
* Fill in the control structures
*/
skb->protocol = htons(ETH_P_IPV6);
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = csummode;
skb->csum = 0;
/* reserve for fragmentation and ipsec header */
skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
--
1.9.3
^ permalink raw reply related
* [PATCH] net: sched: One function call less in em_meta_change() after error detection
From: SF Markus Elfring @ 2015-01-31 16:34 UTC (permalink / raw)
To: David S. Miller, Jamal Hadi Salim, netdev
Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <5317A59D.4@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Sat, 31 Jan 2015 17:18:48 +0100
The meta_delete() function could be called in four cases by the
em_meta_change() function during error handling even if the passed
variable "meta" contained still a null pointer.
* This implementation detail could be improved by adjustments for jump labels.
* Let us return immediately after the first failed function call according to
the current Linux coding style convention.
* Let us delete also unnecessary checks for the variables "err" and
"meta" there.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
net/sched/em_meta.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index b5294ce..2aa67b1 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -866,23 +866,23 @@ static int em_meta_change(struct net *net, void *data, int len,
err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy);
if (err < 0)
- goto errout;
+ return err;
err = -EINVAL;
if (tb[TCA_EM_META_HDR] == NULL)
- goto errout;
+ goto exit;
hdr = nla_data(tb[TCA_EM_META_HDR]);
if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) ||
TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX ||
TCF_META_ID(hdr->left.kind) > TCF_META_ID_MAX ||
TCF_META_ID(hdr->right.kind) > TCF_META_ID_MAX)
- goto errout;
+ goto exit;
meta = kzalloc(sizeof(*meta), GFP_KERNEL);
if (meta == NULL) {
err = -ENOMEM;
- goto errout;
+ goto exit;
}
memcpy(&meta->lvalue.hdr, &hdr->left, sizeof(hdr->left));
@@ -891,20 +891,20 @@ static int em_meta_change(struct net *net, void *data, int len,
if (!meta_is_supported(&meta->lvalue) ||
!meta_is_supported(&meta->rvalue)) {
err = -EOPNOTSUPP;
- goto errout;
+ goto delete_meta;
}
if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE]) < 0 ||
meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE]) < 0)
- goto errout;
+ goto delete_meta;
m->datalen = sizeof(*meta);
m->data = (unsigned long) meta;
- err = 0;
-errout:
- if (err && meta)
- meta_delete(meta);
+ return 0;
+delete_meta:
+ meta_delete(meta);
+exit:
return err;
}
--
2.2.2
^ permalink raw reply related
* Re: [PATCH v2 1/3] ipv6: Select fragment id during UFO segmentation if not set.
From: Michael S. Tsirkin @ 2015-01-31 17:11 UTC (permalink / raw)
To: Vladislav Yasevich; +Cc: eric.dumazet, netdev, virtualization, hannes, ben
In-Reply-To: <1422646047-13168-2-git-send-email-vyasevic@redhat.com>
On Fri, Jan 30, 2015 at 02:27:25PM -0500, Vladislav Yasevich wrote:
> If the IPv6 fragment id has not been set and we perform
> fragmentation due to UFO, select a new fragment id.
> We now consider a fragment id of 0 as unset and if id selection
> process returns 0 (after all the pertrubations), we set it to
> 0x80000000, thus giving us ample space not to create collisions
> with the next packet we may have to fragment.
>
> When doing UFO integrity checking, we also select the
> fragment id if it has not be set yet. This is stored into
s/be/been/
> the skb_shinfo() thus allowing UFO to function correclty.
>
> This patch also removes duplicate fragment id generation code
> and moves ipv6_select_ident() into the header as it may be
> used during GSO.
>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> include/net/ipv6.h | 3 +++
> net/ipv6/ip6_output.c | 10 ++++------
> net/ipv6/output_core.c | 28 ++++++++++++++++++++++------
> net/ipv6/udp_offload.c | 10 +++++++++-
> 4 files changed, 38 insertions(+), 13 deletions(-)
>
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index 4292929..9bf85d3 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -671,6 +671,9 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
> return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
> }
>
> +u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst,
> + struct in6_addr *src);
> +void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
> void ipv6_proxy_select_ident(struct sk_buff *skb);
>
> int ip6_dst_hoplimit(struct dst_entry *dst);
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index ce69a12..5dc91fe 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -537,17 +537,15 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
> skb_copy_secmark(to, from);
> }
>
> -static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
> +void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
> {
> static u32 ip6_idents_hashrnd __read_mostly;
> - u32 hash, id;
> + u32 id;
>
> net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
>
> - hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
> - hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash);
> -
> - id = ip_idents_reserve(hash, 1);
> + id = __ipv6_select_ident(ip6_idents_hashrnd, &rt->rt6i_dst.addr,
> + &rt->rt6i_src.addr);
> fhdr->identification = htonl(id);
> }
>
> diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
> index 97f41a3..ceb857d 100644
> --- a/net/ipv6/output_core.c
> +++ b/net/ipv6/output_core.c
> @@ -9,6 +9,24 @@
> #include <net/addrconf.h>
> #include <net/secure_seq.h>
>
> +u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst, struct in6_addr *src)
> +{
> + u32 hash, id;
> +
> + hash = __ipv6_addr_jhash(dst, hashrnd);
> + hash = __ipv6_addr_jhash(src, hash);
> +
> + /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
> + * set the hight order instead thus minimizing possible future
> + * collisions.
> + */
> + id = ip_idents_reserve(hash, 1);
> + if (unlikely(!id))
> + id = 1 << 31;
> +
> + return id;
> +}
> +
> /* This function exists only for tap drivers that must support broken
> * clients requesting UFO without specifying an IPv6 fragment ID.
> *
> @@ -22,7 +40,7 @@ void ipv6_proxy_select_ident(struct sk_buff *skb)
> static u32 ip6_proxy_idents_hashrnd __read_mostly;
> struct in6_addr buf[2];
> struct in6_addr *addrs;
> - u32 hash, id;
> + u32 id;
>
> addrs = skb_header_pointer(skb,
> skb_network_offset(skb) +
> @@ -34,11 +52,9 @@ void ipv6_proxy_select_ident(struct sk_buff *skb)
> net_get_random_once(&ip6_proxy_idents_hashrnd,
> sizeof(ip6_proxy_idents_hashrnd));
>
> - hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
> - hash = __ipv6_addr_jhash(&addrs[0], hash);
> -
> - id = ip_idents_reserve(hash, 1);
> - skb_shinfo(skb)->ip6_frag_id = htonl(id);
> + id = __ipv6_select_ident(ip6_proxy_idents_hashrnd,
> + &addrs[1], &addrs[0]);
> + skb_shinfo(skb)->ip6_frag_id = id;
> }
> EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
>
> diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
> index b6aa8ed..a562769 100644
> --- a/net/ipv6/udp_offload.c
> +++ b/net/ipv6/udp_offload.c
> @@ -52,6 +52,10 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
>
> skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
>
> + /* Set the IPv6 fragment id if not set yet */
> + if (!skb_shinfo(skb)->ip6_frag_id)
> + ipv6_proxy_select_ident(skb);
> +
> segs = NULL;
> goto out;
> }
> @@ -108,7 +112,11 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
> fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
> fptr->nexthdr = nexthdr;
> fptr->reserved = 0;
> - fptr->identification = skb_shinfo(skb)->ip6_frag_id;
> + if (skb_shinfo(skb)->ip6_frag_id)
> + fptr->identification = skb_shinfo(skb)->ip6_frag_id;
> + else
> + ipv6_select_ident(fptr,
> + (struct rt6_info *)skb_dst(skb));
>
> /* Fragment the skb. ipv6 header and the remaining fields of the
> * fragment header are updated in ipv6_gso_segment()
> --
> 1.9.3
^ permalink raw reply
* Re: [PATCH v2 2/3] Revert "drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO packets"
From: Michael S. Tsirkin @ 2015-01-31 17:11 UTC (permalink / raw)
To: Vladislav Yasevich; +Cc: eric.dumazet, netdev, virtualization, hannes, ben
In-Reply-To: <1422646047-13168-3-git-send-email-vyasevic@redhat.com>
On Fri, Jan 30, 2015 at 02:27:26PM -0500, Vladislav Yasevich wrote:
> This reverts commit 5188cd44c55db3e92cd9e77a40b5baa7ed4340f7.
>
> Now that GSO layer can track if fragment id has been selected
> and can allocate one if necessary, we don't need to do this in
> tap and macvtap. This reverts most of the code and only keeps
> the new ipv6 fragment id generation function that is still needed.
>
> Fixes: 3d0ad09412ff (drivers/net: Disable UFO through virtio)
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> drivers/net/macvtap.c | 3 ---
> drivers/net/tun.c | 6 +-----
> 2 files changed, 1 insertion(+), 8 deletions(-)
>
> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> index 7df2217..0b86e46 100644
> --- a/drivers/net/macvtap.c
> +++ b/drivers/net/macvtap.c
> @@ -17,7 +17,6 @@
> #include <linux/fs.h>
> #include <linux/uio.h>
>
> -#include <net/ipv6.h>
> #include <net/net_namespace.h>
> #include <net/rtnetlink.h>
> #include <net/sock.h>
> @@ -589,8 +588,6 @@ static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q,
> pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
> current->comm);
> gso_type = SKB_GSO_UDP;
> - if (skb->protocol == htons(ETH_P_IPV6))
> - ipv6_proxy_select_ident(skb);
> break;
> default:
> return -EINVAL;
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 8c8dc16..5ca42b7 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -65,7 +65,6 @@
> #include <linux/nsproxy.h>
> #include <linux/virtio_net.h>
> #include <linux/rcupdate.h>
> -#include <net/ipv6.h>
> #include <net/net_namespace.h>
> #include <net/netns/generic.h>
> #include <net/rtnetlink.h>
> @@ -1167,8 +1166,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> break;
> }
>
> - skb_reset_network_header(skb);
> -
> if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
> pr_debug("GSO!\n");
> switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
> @@ -1189,8 +1186,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> current->comm);
> }
> skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
> - if (skb->protocol == htons(ETH_P_IPV6))
> - ipv6_proxy_select_ident(skb);
> break;
> }
> default:
> @@ -1221,6 +1216,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
> }
>
> + skb_reset_network_header(skb);
> skb_probe_transport_header(skb, 0);
>
> rxhash = skb_get_hash(skb);
> --
> 1.9.3
^ permalink raw reply
* Re: [PATCH v2 3/3] Revert "drivers/net: Disable UFO through virtio"
From: Michael S. Tsirkin @ 2015-01-31 17:11 UTC (permalink / raw)
To: Vladislav Yasevich; +Cc: eric.dumazet, netdev, virtualization, hannes, ben
In-Reply-To: <1422646047-13168-4-git-send-email-vyasevic@redhat.com>
On Fri, Jan 30, 2015 at 02:27:27PM -0500, Vladislav Yasevich wrote:
> This reverts commit 3d0ad09412ffe00c9afa201d01effdb6023d09b4.
>
> Now that GSO functionality can correctly track if the fragment
> id has been selected and select a fragment id if necessary,
> we can re-enable UFO on tap/macvap and virtio devices.
>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> drivers/net/macvtap.c | 13 ++++++++-----
> drivers/net/tun.c | 19 ++++++++-----------
> drivers/net/virtio_net.c | 24 ++++++++++--------------
> 3 files changed, 26 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> index 0b86e46..919f4fc 100644
> --- a/drivers/net/macvtap.c
> +++ b/drivers/net/macvtap.c
> @@ -80,7 +80,7 @@ static struct cdev macvtap_cdev;
> static const struct proto_ops macvtap_socket_ops;
>
> #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
> - NETIF_F_TSO6)
> + NETIF_F_TSO6 | NETIF_F_UFO)
> #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
> #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
>
> @@ -585,8 +585,6 @@ static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q,
> gso_type = SKB_GSO_TCPV6;
> break;
> case VIRTIO_NET_HDR_GSO_UDP:
> - pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
> - current->comm);
> gso_type = SKB_GSO_UDP;
> break;
> default:
> @@ -633,6 +631,8 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
> vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> else if (sinfo->gso_type & SKB_GSO_TCPV6)
> vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> + else if (sinfo->gso_type & SKB_GSO_UDP)
> + vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
> else
> BUG();
> if (sinfo->gso_type & SKB_GSO_TCP_ECN)
> @@ -962,6 +962,9 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
> if (arg & TUN_F_TSO6)
> feature_mask |= NETIF_F_TSO6;
> }
> +
> + if (arg & TUN_F_UFO)
> + feature_mask |= NETIF_F_UFO;
> }
>
> /* tun/tap driver inverts the usage for TSO offloads, where
> @@ -972,7 +975,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
> * When user space turns off TSO, we turn off GSO/LRO so that
> * user-space will not receive TSO frames.
> */
> - if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6))
> + if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO))
> features |= RX_OFFLOADS;
> else
> features &= ~RX_OFFLOADS;
> @@ -1087,7 +1090,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
> case TUNSETOFFLOAD:
> /* let the user check for future flags */
> if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
> - TUN_F_TSO_ECN))
> + TUN_F_TSO_ECN | TUN_F_UFO))
> return -EINVAL;
>
> rtnl_lock();
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 5ca42b7..10f9e40 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -186,7 +186,7 @@ struct tun_struct {
> struct net_device *dev;
> netdev_features_t set_features;
> #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
> - NETIF_F_TSO6)
> + NETIF_F_TSO6|NETIF_F_UFO)
>
> int vnet_hdr_sz;
> int sndbuf;
> @@ -1176,18 +1176,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
> break;
> case VIRTIO_NET_HDR_GSO_UDP:
> - {
> - static bool warned;
> -
> - if (!warned) {
> - warned = true;
> - netdev_warn(tun->dev,
> - "%s: using disabled UFO feature; please fix this program\n",
> - current->comm);
> - }
> skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
> break;
> - }
> default:
> tun->dev->stats.rx_frame_errors++;
> kfree_skb(skb);
> @@ -1294,6 +1284,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
> gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> else if (sinfo->gso_type & SKB_GSO_TCPV6)
> gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> + else if (sinfo->gso_type & SKB_GSO_UDP)
> + gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
> else {
> pr_err("unexpected GSO type: "
> "0x%x, gso_size %d, hdr_len %d\n",
> @@ -1742,6 +1734,11 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
> features |= NETIF_F_TSO6;
> arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
> }
> +
> + if (arg & TUN_F_UFO) {
> + features |= NETIF_F_UFO;
> + arg &= ~TUN_F_UFO;
> + }
> }
>
> /* This gives the user a way to test for new features in future by
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 5ca9771..059fdf1 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -490,17 +490,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
> break;
> case VIRTIO_NET_HDR_GSO_UDP:
> - {
> - static bool warned;
> -
> - if (!warned) {
> - warned = true;
> - netdev_warn(dev,
> - "host using disabled UFO feature; please fix it\n");
> - }
> skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
> break;
> - }
> case VIRTIO_NET_HDR_GSO_TCPV6:
> skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
> break;
> @@ -888,6 +879,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
> else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
> hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
> + else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
> + hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP;
> else
> BUG();
> if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
> @@ -1748,7 +1741,7 @@ static int virtnet_probe(struct virtio_device *vdev)
> dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
>
> if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
> - dev->hw_features |= NETIF_F_TSO
> + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
> | NETIF_F_TSO_ECN | NETIF_F_TSO6;
> }
> /* Individual feature bits: what can host handle? */
> @@ -1758,9 +1751,11 @@ static int virtnet_probe(struct virtio_device *vdev)
> dev->hw_features |= NETIF_F_TSO6;
> if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
> dev->hw_features |= NETIF_F_TSO_ECN;
> + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
> + dev->hw_features |= NETIF_F_UFO;
>
> if (gso)
> - dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
> + dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
> /* (!csum && gso) case will be fixed by register_netdev() */
> }
> if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
> @@ -1798,7 +1793,8 @@ static int virtnet_probe(struct virtio_device *vdev)
> /* If we can receive ANY GSO packets, we must allocate large ones. */
> if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
> virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
> - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
> + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
> + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
> vi->big_packets = true;
>
> if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> @@ -1994,9 +1990,9 @@ static struct virtio_device_id id_table[] = {
> static unsigned int features[] = {
> VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
> VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
> - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6,
> + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
> VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
> - VIRTIO_NET_F_GUEST_ECN,
> + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
> VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
> VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
> VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
> --
> 1.9.3
^ permalink raw reply
* [PATCH] net: sctp: Deletion of an unnecessary check before the function call "kfree"
From: SF Markus Elfring @ 2015-01-31 17:15 UTC (permalink / raw)
To: David S. Miller, Neil Horman, Vlad Yasevich, linux-sctp, netdev
Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <5317A59D.4@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Sat, 31 Jan 2015 18:10:03 +0100
The kfree() function tests whether its argument is NULL and then
returns immediately. Thus the test around the call is not needed.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
net/sctp/associola.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f791edd..3c2aefc 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -391,8 +391,7 @@ void sctp_association_free(struct sctp_association *asoc)
sctp_asconf_queue_teardown(asoc);
/* Free pending address space being deleted */
- if (asoc->asconf_addr_del_pending != NULL)
- kfree(asoc->asconf_addr_del_pending);
+ kfree(asoc->asconf_addr_del_pending);
/* AUTH - Free the endpoint shared keys */
sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
--
2.2.2
^ permalink raw reply related
* Re: [PATCH v2 0/3] Restore UFO support to virtio_net devices
From: Michael S. Tsirkin @ 2015-01-31 17:17 UTC (permalink / raw)
To: Vladislav Yasevich
Cc: eric.dumazet, netdev, virtualization, hannes, ben, David Miller
In-Reply-To: <1422646047-13168-1-git-send-email-vyasevic@redhat.com>
On Fri, Jan 30, 2015 at 02:27:24PM -0500, Vladislav Yasevich wrote:
> commit 3d0ad09412ffe00c9afa201d01effdb6023d09b4
> Author: Ben Hutchings <ben@decadent.org.uk>
> Date: Thu Oct 30 18:27:12 2014 +0000
>
> drivers/net: Disable UFO through virtio
>
> Turned off UFO support to virtio-net based devices due to issues
> with IPv6 fragment id generation for UFO packets. The issue
> was that IPv6 UFO/GSO implementation expects the fragment id
> to be supplied in skb_shinfo(). However, for packets generated
> by the VMs, the fragment id is not supplied which causes all
> IPv6 fragments to have the id of 0.
>
> The problem is that turning off UFO support on tap/macvtap
> as well as virtio devices caused issues with migrations.
> Migrations would fail when moving a vm from a kernel supporting
> expecting UFO to work to the newer kernels that disabled UFO.
>
> This series provides a partial solution to address the migration
> issue. The series allows us to track whether skb_shinfo()->ip6_frag_id
> has been set by treating value of 0 as unset.
> This lets GSO code to generate fragment ids if they are necessary
> (ex: packet was generated by VM or packet socket).
>
> Since v1:
> - Removed the skb bit and use value of 0 as tracker.
> - Used Eric's suggestion to set fragment id as 0x80000000 if id
> generation procedure yeilded a 0 result.
> - Consolidated ipv6 id genration code.
Looks good to me
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Seems appropriate for stable as well.
> Vladislav Yasevich (3):
> ipv6: Select fragment id during UFO segmentation if not set.
> Revert "drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO
> packets"
> Revert "drivers/net: Disable UFO through virtio"
>
> drivers/net/macvtap.c | 16 ++++++++--------
> drivers/net/tun.c | 25 +++++++++----------------
> drivers/net/virtio_net.c | 24 ++++++++++--------------
> include/net/ipv6.h | 3 +++
> net/ipv6/ip6_output.c | 10 ++++------
> net/ipv6/output_core.c | 28 ++++++++++++++++++++++------
> net/ipv6/udp_offload.c | 10 +++++++++-
> 7 files changed, 65 insertions(+), 51 deletions(-)
>
> --
> 1.9.3
^ permalink raw reply
* Re: [PATCH] net: sched: One function call less in em_meta_change() after error detection
From: Lino Sanfilippo @ 2015-01-31 17:31 UTC (permalink / raw)
To: SF Markus Elfring, David S. Miller, Jamal Hadi Salim, netdev
Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <54CD042E.6030606@users.sourceforge.net>
Hi,
On 31.01.2015 17:34, SF Markus Elfring wrote:
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Sat, 31 Jan 2015 17:18:48 +0100
>
> The meta_delete() function could be called in four cases by the
> em_meta_change() function during error handling even if the passed
> variable "meta" contained still a null pointer.
>
> * This implementation detail could be improved by adjustments for jump labels.
>
> * Let us return immediately after the first failed function call according to
> the current Linux coding style convention.
>
> * Let us delete also unnecessary checks for the variables "err" and
> "meta" there.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
> ---
> net/sched/em_meta.c | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
> index b5294ce..2aa67b1 100644
> --- a/net/sched/em_meta.c
> +++ b/net/sched/em_meta.c
> @@ -866,23 +866,23 @@ static int em_meta_change(struct net *net, void *data, int len,
>
> err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy);
> if (err < 0)
> - goto errout;
> + return err;
>
> err = -EINVAL;
> if (tb[TCA_EM_META_HDR] == NULL)
> - goto errout;
> + goto exit;
> hdr = nla_data(tb[TCA_EM_META_HDR]);
>
> if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) ||
> TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX ||
> TCF_META_ID(hdr->left.kind) > TCF_META_ID_MAX ||
> TCF_META_ID(hdr->right.kind) > TCF_META_ID_MAX)
> - goto errout;
> + goto exit;
>
> meta = kzalloc(sizeof(*meta), GFP_KERNEL);
> if (meta == NULL) {
> err = -ENOMEM;
> - goto errout;
> + goto exit;
> }
>
> memcpy(&meta->lvalue.hdr, &hdr->left, sizeof(hdr->left));
> @@ -891,20 +891,20 @@ static int em_meta_change(struct net *net, void *data, int len,
> if (!meta_is_supported(&meta->lvalue) ||
> !meta_is_supported(&meta->rvalue)) {
> err = -EOPNOTSUPP;
> - goto errout;
> + goto delete_meta;
> }
>
> if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE]) < 0 ||
> meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE]) < 0)
> - goto errout;
> + goto delete_meta;
>
> m->datalen = sizeof(*meta);
> m->data = (unsigned long) meta;
>
> - err = 0;
> -errout:
> - if (err && meta)
> - meta_delete(meta);
> + return 0;
> +delete_meta:
> + meta_delete(meta);
> +exit:
> return err;
> }
Why do you use that exit label if it does nothing more than returning
the error value? Also if nla_parse fails you dont use it but return the
error directly. While using a label which is used only to return an
error may be a matter of taste, its at least inconsistent to do both in
a function, use such a label in one case and return immediately in
another, isnt it?
Regards,
Lino
^ permalink raw reply
* Re: [PATCH] net: sched: One function call less in em_meta_change() after error detection
From: Lino Sanfilippo @ 2015-01-31 17:50 UTC (permalink / raw)
To: SF Markus Elfring, David S. Miller, Jamal Hadi Salim, netdev
Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <54CD042E.6030606@users.sourceforge.net>
On 31.01.2015 17:34, SF Markus Elfring wrote:
> -errout:
> - if (err && meta)
> - meta_delete(meta);
Since this patch seems to be about optimization and cleanup you should
probably also remove the now unnecessary initialization of "meta" with
NULL at the beginning of the function...
Regards,
Lino
^ permalink raw reply
* Re: [PATCH] net: sctp: Deletion of an unnecessary check before the function call "kfree"
From: Neil Horman @ 2015-01-31 18:38 UTC (permalink / raw)
To: SF Markus Elfring
Cc: David S. Miller, Vlad Yasevich, linux-sctp, netdev, LKML,
kernel-janitors, Julia Lawall
In-Reply-To: <54CD0DCF.9020804@users.sourceforge.net>
On Sat, Jan 31, 2015 at 06:15:59PM +0100, SF Markus Elfring wrote:
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Sat, 31 Jan 2015 18:10:03 +0100
>
> The kfree() function tests whether its argument is NULL and then
> returns immediately. Thus the test around the call is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
> ---
> net/sctp/associola.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index f791edd..3c2aefc 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -391,8 +391,7 @@ void sctp_association_free(struct sctp_association *asoc)
> sctp_asconf_queue_teardown(asoc);
>
> /* Free pending address space being deleted */
> - if (asoc->asconf_addr_del_pending != NULL)
> - kfree(asoc->asconf_addr_del_pending);
> + kfree(asoc->asconf_addr_del_pending);
>
> /* AUTH - Free the endpoint shared keys */
> sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
> --
> 2.2.2
>
>
Sure, seems reasonable
Acked-By: Neil Horman <nhorman@tuxdriver.com>
^ permalink raw reply
* Re: [GIT PULL nf] IPVS Fixes for v3.19
From: Pablo Neira Ayuso @ 2015-01-31 20:40 UTC (permalink / raw)
To: Simon Horman
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov
In-Reply-To: <1422580938-31520-1-git-send-email-horms@verge.net.au>
On Fri, Jan 30, 2015 at 10:22:17AM +0900, Simon Horman wrote:
> Hi Pablo,
>
> please consider this fix for v3.19.
>
> It resolves a crash in xfrm reported by Florian Wiessner.
>
> I believe this problem manifests since 0a5ebb8000c5 ("ipv4: Pass explicit
> daddr arg to ip_send_reply().") which was included in v2.6.39.
>
> Julian reports that the patch has been tested on net tree (Dec 7), 3.14.25,
> 3.12.33, 3.10.61. 3.4.104 needs a modified fix that resolves rejects. It
> applies with little fuzz on 3.2.64. Please let us know if we should post
> separate 3.2 and 3.4 patches.
Pulled, thanks Simon.
^ permalink raw reply
* Re: [PATCH net-next 5/6] udpv6: Add lockless sendmsg() support
From: Sergei Shtylyov @ 2015-01-31 20:49 UTC (permalink / raw)
To: Vladislav Yasevich, netdev; +Cc: herbert, hannes, Vladislav Yasevich
In-Reply-To: <1422718818-21093-6-git-send-email-vyasevic@redhat.com>
Hello.
On 1/31/2015 6:40 PM, Vladislav Yasevich wrote:
> This commit adds the same functionaliy to IPv6 that
> commit 903ab86d195cca295379699299c5fc10beba31c7
> Author: Herbert Xu <herbert@gondor.apana.org.au>
> Date: Tue Mar 1 02:36:48 2011 +0000
> udp: Add lockless transmit path
> added to IPv4.
> UDP transmit path can now run without a socket lock,
> thus allowing multiple threads to send to a single socket
> more efficiently.
> This is only used when corking/MSG_MORE is not used.
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> net/ipv6/udp.c | 24 ++++++++++++++++++++----
> 1 file changed, 20 insertions(+), 4 deletions(-)
> diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
> index 67a3d70..d048d46 100644
> --- a/net/ipv6/udp.c
> +++ b/net/ipv6/udp.c
[...]
> @@ -1307,6 +1308,20 @@ do_udp_sendmsg:
> goto do_confirm;
> back_from_confirm:
>
> + /* Lockless fast path for the non-corking case */
> + if (!corkreq) {
> + struct sk_buff *skb;
> +
> + skb = ip6_make_skb(sk, getfrag, msg, ulen,
> + sizeof(struct udphdr), hlimit, tclass, opt,
> + &fl6, (struct rt6_info *)dst,
> + msg->msg_flags, dontfrag);
> + err = PTR_ERR(skb);
You should use PTR_ERR_OR_ZERO() here, I think.
[...]
WBR, Sergei
^ permalink raw reply
* [PATCH 2/4] netfilter: nf_tables: disable preemption when restoring chain counters
From: Pablo Neira Ayuso @ 2015-01-31 20:55 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1422737711-5169-1-git-send-email-pablo@netfilter.org>
With CONFIG_DEBUG_PREEMPT=y
[22144.496057] BUG: using smp_processor_id() in preemptible [00000000] code: iptables-compat/10406
[22144.496061] caller is debug_smp_processor_id+0x17/0x1b
[22144.496065] CPU: 2 PID: 10406 Comm: iptables-compat Not tainted 3.19.0-rc4+ #
[...]
[22144.496092] Call Trace:
[22144.496098] [<ffffffff8145b9fa>] dump_stack+0x4f/0x7b
[22144.496104] [<ffffffff81244f52>] check_preemption_disabled+0xd6/0xe8
[22144.496110] [<ffffffff81244f90>] debug_smp_processor_id+0x17/0x1b
[22144.496120] [<ffffffffa07c557e>] nft_stats_alloc+0x94/0xc7 [nf_tables]
[22144.496130] [<ffffffffa07c73d2>] nf_tables_newchain+0x471/0x6d8 [nf_tables]
[22144.496140] [<ffffffffa07c5ef6>] ? nft_trans_alloc+0x18/0x34 [nf_tables]
[22144.496154] [<ffffffffa063c8da>] nfnetlink_rcv_batch+0x2b4/0x457 [nfnetlink]
Reported-by: Andreas Schultz <aschultz@tpip.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 7e68694..b543606 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1134,9 +1134,11 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
/* Restore old counters on this cpu, no problem. Per-cpu statistics
* are not exposed to userspace.
*/
+ preempt_disable();
stats = this_cpu_ptr(newstats);
stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
+ preempt_enable();
return newstats;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 0/4] Netfilter/IPVS fixes for net
From: Pablo Neira Ayuso @ 2015-01-31 20:55 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
Hi David,
The following patchset contains Netfilter/IPVS fixes for your net tree,
they are:
1) Validate hooks for nf_tables NAT expressions, otherwise users can
crash the kernel when using them from the wrong hook. We already
got one user trapped on this when configuring masquerading.
2) Fix a BUG splat in nf_tables with CONFIG_DEBUG_PREEMPT=y. Reported
by Andreas Schultz.
3) Avoid unnecessary reroute of traffic in the local input path
in IPVS that triggers a crash in in xfrm. Reported by Florian
Wiessner and fixes by Julian Anastasov.
4) Fix memory and module refcount leak from the error path of
nf_tables_newchain().
You can pull these changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
Thanks!
----------------------------------------------------------------
The following changes since commit 2061dcd6bff8b774b4fac8b0739b6be3f87bc9f2:
net: sctp: fix race for one-to-many sockets in sendmsg's auto associate (2015-01-17 23:52:20 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git master
for you to fetch changes up to f5553c19ff9058136e7082c0b1f4268e705ea538:
netfilter: nf_tables: fix leaks in error path of nf_tables_newchain() (2015-01-30 18:42:08 +0100)
----------------------------------------------------------------
Julian Anastasov (1):
ipvs: rerouting to local clients is not needed anymore
Pablo Neira Ayuso (3):
netfilter: nf_tables: validate hooks in NAT expressions
netfilter: nf_tables: disable preemption when restoring chain counters
netfilter: nf_tables: fix leaks in error path of nf_tables_newchain()
include/net/netfilter/nf_tables.h | 2 ++
net/bridge/netfilter/nft_reject_bridge.c | 29 +++++-----------------
net/netfilter/ipvs/ip_vs_core.c | 33 ++++++++++++++++--------
net/netfilter/nf_tables_api.c | 28 +++++++++++++++++++--
net/netfilter/nft_masq.c | 26 ++++++++++++-------
net/netfilter/nft_nat.c | 40 ++++++++++++++++++++++--------
net/netfilter/nft_redir.c | 25 +++++++++++++------
7 files changed, 120 insertions(+), 63 deletions(-)
^ permalink raw reply
* [PATCH 1/4] netfilter: nf_tables: validate hooks in NAT expressions
From: Pablo Neira Ayuso @ 2015-01-31 20:55 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1422737711-5169-1-git-send-email-pablo@netfilter.org>
The user can crash the kernel if it uses any of the existing NAT
expressions from the wrong hook, so add some code to validate this
when loading the rule.
This patch introduces nft_chain_validate_hooks() which is based on
an existing function in the bridge version of the reject expression.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 2 ++
net/bridge/netfilter/nft_reject_bridge.c | 29 +++++-----------------
net/netfilter/nf_tables_api.c | 18 ++++++++++++++
net/netfilter/nft_masq.c | 26 ++++++++++++-------
net/netfilter/nft_nat.c | 40 ++++++++++++++++++++++--------
net/netfilter/nft_redir.c | 25 +++++++++++++------
6 files changed, 90 insertions(+), 50 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 3ae969e..9eaaa78 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -530,6 +530,8 @@ enum nft_chain_type {
int nft_chain_validate_dependency(const struct nft_chain *chain,
enum nft_chain_type type);
+int nft_chain_validate_hooks(const struct nft_chain *chain,
+ unsigned int hook_flags);
struct nft_stats {
u64 bytes;
diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c
index b0330ae..3244aea 100644
--- a/net/bridge/netfilter/nft_reject_bridge.c
+++ b/net/bridge/netfilter/nft_reject_bridge.c
@@ -265,22 +265,12 @@ out:
data[NFT_REG_VERDICT].verdict = NF_DROP;
}
-static int nft_reject_bridge_validate_hooks(const struct nft_chain *chain)
+static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
{
- struct nft_base_chain *basechain;
-
- if (chain->flags & NFT_BASE_CHAIN) {
- basechain = nft_base_chain(chain);
-
- switch (basechain->ops[0].hooknum) {
- case NF_BR_PRE_ROUTING:
- case NF_BR_LOCAL_IN:
- break;
- default:
- return -EOPNOTSUPP;
- }
- }
- return 0;
+ return nft_chain_validate_hooks(ctx->chain, (1 << NF_BR_PRE_ROUTING) |
+ (1 << NF_BR_LOCAL_IN));
}
static int nft_reject_bridge_init(const struct nft_ctx *ctx,
@@ -290,7 +280,7 @@ static int nft_reject_bridge_init(const struct nft_ctx *ctx,
struct nft_reject *priv = nft_expr_priv(expr);
int icmp_code, err;
- err = nft_reject_bridge_validate_hooks(ctx->chain);
+ err = nft_reject_bridge_validate(ctx, expr, NULL);
if (err < 0)
return err;
@@ -341,13 +331,6 @@ nla_put_failure:
return -1;
}
-static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nft_data **data)
-{
- return nft_reject_bridge_validate_hooks(ctx->chain);
-}
-
static struct nft_expr_type nft_reject_bridge_type;
static const struct nft_expr_ops nft_reject_bridge_ops = {
.type = &nft_reject_bridge_type,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 3b3ddb4..7e68694 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3753,6 +3753,24 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
}
EXPORT_SYMBOL_GPL(nft_chain_validate_dependency);
+int nft_chain_validate_hooks(const struct nft_chain *chain,
+ unsigned int hook_flags)
+{
+ struct nft_base_chain *basechain;
+
+ if (chain->flags & NFT_BASE_CHAIN) {
+ basechain = nft_base_chain(chain);
+
+ if ((1 << basechain->ops[0].hooknum) & hook_flags)
+ return 0;
+
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
+
/*
* Loop detection - walk through the ruleset beginning at the destination chain
* of a new jump until either the source chain is reached (loop) or all
diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c
index d1ffd5e..9aea747 100644
--- a/net/netfilter/nft_masq.c
+++ b/net/netfilter/nft_masq.c
@@ -21,6 +21,21 @@ const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
};
EXPORT_SYMBOL_GPL(nft_masq_policy);
+int nft_masq_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
+{
+ int err;
+
+ err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+ if (err < 0)
+ return err;
+
+ return nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_POST_ROUTING));
+}
+EXPORT_SYMBOL_GPL(nft_masq_validate);
+
int nft_masq_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
@@ -28,8 +43,8 @@ int nft_masq_init(const struct nft_ctx *ctx,
struct nft_masq *priv = nft_expr_priv(expr);
int err;
- err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
- if (err < 0)
+ err = nft_masq_validate(ctx, expr, NULL);
+ if (err)
return err;
if (tb[NFTA_MASQ_FLAGS] == NULL)
@@ -60,12 +75,5 @@ nla_put_failure:
}
EXPORT_SYMBOL_GPL(nft_masq_dump);
-int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nft_data **data)
-{
- return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
-}
-EXPORT_SYMBOL_GPL(nft_masq_validate);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
index aff54fb1..a0837c6 100644
--- a/net/netfilter/nft_nat.c
+++ b/net/netfilter/nft_nat.c
@@ -88,17 +88,40 @@ static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
[NFTA_NAT_FLAGS] = { .type = NLA_U32 },
};
-static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
+static int nft_nat_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
{
struct nft_nat *priv = nft_expr_priv(expr);
- u32 family;
int err;
err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
if (err < 0)
return err;
+ switch (priv->type) {
+ case NFT_NAT_SNAT:
+ err = nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_POST_ROUTING) |
+ (1 << NF_INET_LOCAL_IN));
+ break;
+ case NFT_NAT_DNAT:
+ err = nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_OUT));
+ break;
+ }
+
+ return err;
+}
+
+static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+ const struct nlattr * const tb[])
+{
+ struct nft_nat *priv = nft_expr_priv(expr);
+ u32 family;
+ int err;
+
if (tb[NFTA_NAT_TYPE] == NULL ||
(tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
@@ -115,6 +138,10 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
return -EINVAL;
}
+ err = nft_nat_validate(ctx, expr, NULL);
+ if (err < 0)
+ return err;
+
if (tb[NFTA_NAT_FAMILY] == NULL)
return -EINVAL;
@@ -219,13 +246,6 @@ nla_put_failure:
return -1;
}
-static int nft_nat_validate(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nft_data **data)
-{
- return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
-}
-
static struct nft_expr_type nft_nat_type;
static const struct nft_expr_ops nft_nat_ops = {
.type = &nft_nat_type,
diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c
index 9e8093f..d7e9e93 100644
--- a/net/netfilter/nft_redir.c
+++ b/net/netfilter/nft_redir.c
@@ -23,6 +23,22 @@ const struct nla_policy nft_redir_policy[NFTA_REDIR_MAX + 1] = {
};
EXPORT_SYMBOL_GPL(nft_redir_policy);
+int nft_redir_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
+{
+ int err;
+
+ err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+ if (err < 0)
+ return err;
+
+ return nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_OUT));
+}
+EXPORT_SYMBOL_GPL(nft_redir_validate);
+
int nft_redir_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
@@ -30,7 +46,7 @@ int nft_redir_init(const struct nft_ctx *ctx,
struct nft_redir *priv = nft_expr_priv(expr);
int err;
- err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+ err = nft_redir_validate(ctx, expr, NULL);
if (err < 0)
return err;
@@ -88,12 +104,5 @@ nla_put_failure:
}
EXPORT_SYMBOL_GPL(nft_redir_dump);
-int nft_redir_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nft_data **data)
-{
- return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
-}
-EXPORT_SYMBOL_GPL(nft_redir_validate);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
--
1.7.10.4
^ permalink raw reply related
* [PATCH 3/4] ipvs: rerouting to local clients is not needed anymore
From: Pablo Neira Ayuso @ 2015-01-31 20:55 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1422737711-5169-1-git-send-email-pablo@netfilter.org>
From: Julian Anastasov <ja@ssi.bg>
commit f5a41847acc5 ("ipvs: move ip_route_me_harder for ICMP")
from 2.6.37 introduced ip_route_me_harder() call for responses to
local clients, so that we can provide valid rt_src after SNAT.
It was used by TCP to provide valid daddr for ip_send_reply().
After commit 0a5ebb8000c5 ("ipv4: Pass explicit daddr arg to
ip_send_reply()." from 3.0 this rerouting is not needed anymore
and should be avoided, especially in LOCAL_IN.
Fixes 3.12.33 crash in xfrm reported by Florian Wiessner:
"3.12.33 - BUG xfrm_selector_match+0x25/0x2f6"
Reported-by: Smart Weblications GmbH - Florian Wiessner <f.wiessner@smart-weblications.de>
Tested-by: Smart Weblications GmbH - Florian Wiessner <f.wiessner@smart-weblications.de>
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_core.c | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 990decb..b87ca32 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -659,16 +659,24 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
return err;
}
-static int ip_vs_route_me_harder(int af, struct sk_buff *skb)
+static int ip_vs_route_me_harder(int af, struct sk_buff *skb,
+ unsigned int hooknum)
{
+ if (!sysctl_snat_reroute(skb))
+ return 0;
+ /* Reroute replies only to remote clients (FORWARD and LOCAL_OUT) */
+ if (NF_INET_LOCAL_IN == hooknum)
+ return 0;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- if (sysctl_snat_reroute(skb) && ip6_route_me_harder(skb) != 0)
+ struct dst_entry *dst = skb_dst(skb);
+
+ if (dst->dev && !(dst->dev->flags & IFF_LOOPBACK) &&
+ ip6_route_me_harder(skb) != 0)
return 1;
} else
#endif
- if ((sysctl_snat_reroute(skb) ||
- skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
+ if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
ip_route_me_harder(skb, RTN_LOCAL) != 0)
return 1;
@@ -791,7 +799,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
union nf_inet_addr *snet,
__u8 protocol, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp,
- unsigned int offset, unsigned int ihl)
+ unsigned int offset, unsigned int ihl,
+ unsigned int hooknum)
{
unsigned int verdict = NF_DROP;
@@ -821,7 +830,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
#endif
ip_vs_nat_icmp(skb, pp, cp, 1);
- if (ip_vs_route_me_harder(af, skb))
+ if (ip_vs_route_me_harder(af, skb, hooknum))
goto out;
/* do the statistics and put it back */
@@ -916,7 +925,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related,
snet.ip = iph->saddr;
return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp,
- pp, ciph.len, ihl);
+ pp, ciph.len, ihl, hooknum);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -981,7 +990,8 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
snet.in6 = ciph.saddr.in6;
writable = ciph.len;
return handle_response_icmp(AF_INET6, skb, &snet, ciph.protocol, cp,
- pp, writable, sizeof(struct ipv6hdr));
+ pp, writable, sizeof(struct ipv6hdr),
+ hooknum);
}
#endif
@@ -1040,7 +1050,8 @@ static inline bool is_new_conn(const struct sk_buff *skb,
*/
static unsigned int
handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
- struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
+ struct ip_vs_conn *cp, struct ip_vs_iphdr *iph,
+ unsigned int hooknum)
{
struct ip_vs_protocol *pp = pd->pp;
@@ -1078,7 +1089,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* if it came from this machine itself. So re-compute
* the routing information.
*/
- if (ip_vs_route_me_harder(af, skb))
+ if (ip_vs_route_me_harder(af, skb, hooknum))
goto drop;
IP_VS_DBG_PKT(10, af, pp, skb, 0, "After SNAT");
@@ -1181,7 +1192,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
cp = pp->conn_out_get(af, skb, &iph, 0);
if (likely(cp))
- return handle_response(af, skb, pd, cp, &iph);
+ return handle_response(af, skb, pd, cp, &iph, hooknum);
if (sysctl_nat_icmp_send(net) &&
(pp->protocol == IPPROTO_TCP ||
pp->protocol == IPPROTO_UDP ||
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox