* [patch net-next] ipv4: introduce address lifetime
From: Jiri Pirko @ 2013-01-24 19:41 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, stephen, kuznet, jmorris, yoshfuji, kaber,
psimerda, tgraf, nicolas.dichtel, nhorman, dcbw
There are some usecase when lifetime of ipv4 addresses might be helpful.
For example:
1) initramfs networkmanager uses a DHCP daemon to learn network
configuration parameters
2) initramfs networkmanager addresses, routes and DNS configuration
3) initramfs networkmanager is requested to stop
4) initramfs networkmanager stops all daemons including dhclient
5) there are addresses and routes configured but no daemon running. If
the system doesn't start networkmanager for some reason, addresses and
routes will be used forever, which violates RFC 2131.
This patch is essentially a backport of ivp6 address lifetime mechanism
for ipv4 addresses.
Current "ip" tool supports this without any patch (since it does not
distinguish between ipv4 and ipv6 addresses in this perspective.
Also, this should be back-compatible with all current netlink users.
Reported-by: Pavel Šimerda <psimerda@redhat.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
include/linux/inetdevice.h | 6 ++
include/net/addrconf.h | 4 +
net/ipv4/devinet.c | 215 +++++++++++++++++++++++++++++++++++++++++++--
net/ipv6/addrconf.c | 4 -
4 files changed, 220 insertions(+), 9 deletions(-)
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index a9d8289..ea1e3b8 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -166,6 +166,12 @@ struct in_ifaddr {
unsigned char ifa_flags;
unsigned char ifa_prefixlen;
char ifa_label[IFNAMSIZ];
+
+ /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
+ __u32 ifa_valid_lft;
+ __u32 ifa_preferred_lft;
+ unsigned long ifa_cstamp; /* created timestamp */
+ unsigned long ifa_tstamp; /* updated timestamp */
};
extern int register_inetaddr_notifier(struct notifier_block *nb);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 6c58d50..40be2a0 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -15,6 +15,10 @@
#define IPV6_MAX_ADDRESSES 16
+#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ / 50 : 1)
+#define ADDRCONF_TIMER_FUZZ (HZ / 4)
+#define ADDRCONF_TIMER_FUZZ_MAX (HZ)
+
#include <linux/in.h>
#include <linux/in6.h>
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a8e4f26..5281314 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -63,6 +63,7 @@
#include <net/ip_fib.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
+#include <net/addrconf.h>
#include "fib_lookup.h"
@@ -93,6 +94,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
[IFA_ADDRESS] = { .type = NLA_U32 },
[IFA_BROADCAST] = { .type = NLA_U32 },
[IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
+ [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
};
#define IN4_ADDR_HSIZE_SHIFT 8
@@ -417,6 +419,10 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
}
+static void check_lifetime(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
+
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
u32 portid)
{
@@ -462,6 +468,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
inet_hash_insert(dev_net(in_dev->dev), ifa);
+ cancel_delayed_work(&check_lifetime_work);
+ schedule_delayed_work(&check_lifetime_work, 0);
+
/* Send message first, then call notifier.
Notifier will trigger FIB update, so that
listeners of netlink will know about new ifaddr */
@@ -573,7 +582,107 @@ errout:
return err;
}
-static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
+#define INFINITY_LIFE_TIME 0xFFFFFFFF
+
+static void check_lifetime(struct work_struct *work)
+{
+ unsigned long now, next, next_sec, next_sched;
+ struct in_ifaddr *ifa;
+ struct hlist_node *node;
+ int i;
+
+ now = jiffies;
+ next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
+
+ rcu_read_lock();
+ for (i = 0; i < IN4_ADDR_HSIZE; i++) {
+ hlist_for_each_entry_rcu(ifa, node,
+ &inet_addr_lst[i], hash) {
+ unsigned long age;
+
+ if (ifa->ifa_flags & IFA_F_PERMANENT)
+ continue;
+
+ /* We try to batch several events at once. */
+ age = (now - ifa->ifa_tstamp +
+ ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+
+ if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
+ age >= ifa->ifa_valid_lft) {
+ struct in_ifaddr **ifap ;
+
+ rtnl_lock();
+ for (ifap = &ifa->ifa_dev->ifa_list;
+ *ifap != NULL; ifap = &ifa->ifa_next) {
+ if (*ifap == ifa)
+ inet_del_ifa(ifa->ifa_dev,
+ ifap, 1);
+ }
+ rtnl_unlock();
+ } else if (ifa->ifa_preferred_lft ==
+ INFINITY_LIFE_TIME) {
+ continue;
+ } else if (age >= ifa->ifa_preferred_lft) {
+ if (time_before(ifa->ifa_tstamp +
+ ifa->ifa_valid_lft * HZ, next))
+ next = ifa->ifa_tstamp +
+ ifa->ifa_valid_lft * HZ;
+
+ if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) {
+ ifa->ifa_flags |= IFA_F_DEPRECATED;
+ rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
+ }
+ } else if (time_before(ifa->ifa_tstamp +
+ ifa->ifa_preferred_lft * HZ,
+ next)) {
+ next = ifa->ifa_tstamp +
+ ifa->ifa_preferred_lft * HZ;
+ }
+ }
+ }
+ rcu_read_unlock();
+
+ next_sec = round_jiffies_up(next);
+ next_sched = next;
+
+ /* If rounded timeout is accurate enough, accept it. */
+ if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
+ next_sched = next_sec;
+
+ now = jiffies;
+ /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
+ if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
+ next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
+
+ schedule_delayed_work(&check_lifetime_work, next_sched - now);
+}
+
+static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
+ __u32 prefered_lft)
+{
+ unsigned long timeout;
+
+ ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
+
+ timeout = addrconf_timeout_fixup(valid_lft, HZ);
+ if (addrconf_finite_timeout(timeout))
+ ifa->ifa_valid_lft = timeout;
+ else
+ ifa->ifa_flags |= IFA_F_PERMANENT;
+
+ timeout = addrconf_timeout_fixup(prefered_lft, HZ);
+ if (addrconf_finite_timeout(timeout)) {
+ if (timeout == 0)
+ ifa->ifa_flags |= IFA_F_DEPRECATED;
+ ifa->ifa_preferred_lft = timeout;
+ }
+ ifa->ifa_tstamp = jiffies;
+ if (!ifa->ifa_cstamp)
+ ifa->ifa_cstamp = ifa->ifa_tstamp;
+}
+
+static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
+ __u32 *pvalid_lft, __u32 *pprefered_lft)
{
struct nlattr *tb[IFA_MAX+1];
struct in_ifaddr *ifa;
@@ -633,24 +742,73 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ if (tb[IFA_CACHEINFO]) {
+ struct ifa_cacheinfo *ci;
+
+ ci = nla_data(tb[IFA_CACHEINFO]);
+ if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
+ err = -EINVAL;
+ goto errout;
+ }
+ *pvalid_lft = ci->ifa_valid;
+ *pprefered_lft = ci->ifa_prefered;
+ }
+
return ifa;
errout:
return ERR_PTR(err);
}
+static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
+{
+ struct in_device *in_dev = ifa->ifa_dev;
+ struct in_ifaddr *ifa1, **ifap;
+
+ if (!ifa->ifa_local)
+ return NULL;
+
+ for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
+ ifap = &ifa1->ifa_next) {
+ if (ifa1->ifa_mask == ifa->ifa_mask &&
+ inet_ifa_match(ifa1->ifa_address, ifa) &&
+ ifa1->ifa_local == ifa->ifa_local)
+ return ifa1;
+ }
+ return NULL;
+}
+
static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct net *net = sock_net(skb->sk);
struct in_ifaddr *ifa;
+ struct in_ifaddr *ifa_existing;
+ __u32 valid_lft = INFINITY_LIFE_TIME;
+ __u32 prefered_lft = INFINITY_LIFE_TIME;
ASSERT_RTNL();
- ifa = rtm_to_ifaddr(net, nlh);
+ ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
if (IS_ERR(ifa))
return PTR_ERR(ifa);
- return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
+ ifa_existing = find_matching_ifa(ifa);
+ if (!ifa_existing) {
+ /* It would be best to check for !NLM_F_CREATE here but
+ * userspace alreay relies on not having to provide this.
+ */
+ set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+ return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
+ } else {
+ inet_free_ifa(ifa);
+
+ if (nlh->nlmsg_flags & NLM_F_EXCL ||
+ !(nlh->nlmsg_flags & NLM_F_REPLACE))
+ return -EEXIST;
+
+ set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
+ }
+ return 0;
}
/*
@@ -852,6 +1010,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
ifa->ifa_prefixlen = 32;
ifa->ifa_mask = inet_make_mask(32);
}
+ set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
ret = inet_set_ifa(dev, ifa);
break;
@@ -1190,6 +1349,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
ifa->ifa_dev = in_dev;
ifa->ifa_scope = RT_SCOPE_HOST;
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
+ INFINITY_LIFE_TIME);
inet_insert_ifa(ifa);
}
}
@@ -1246,11 +1407,30 @@ static size_t inet_nlmsg_size(void)
+ nla_total_size(IFNAMSIZ); /* IFA_LABEL */
}
+static inline u32 cstamp_delta(unsigned long cstamp)
+{
+ return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
+}
+
+static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
+ unsigned long tstamp, u32 preferred, u32 valid)
+{
+ struct ifa_cacheinfo ci;
+
+ ci.cstamp = cstamp_delta(cstamp);
+ ci.tstamp = cstamp_delta(tstamp);
+ ci.ifa_prefered = preferred;
+ ci.ifa_valid = valid;
+
+ return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+}
+
static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
u32 portid, u32 seq, int event, unsigned int flags)
{
struct ifaddrmsg *ifm;
struct nlmsghdr *nlh;
+ u32 preferred, valid;
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
if (nlh == NULL)
@@ -1259,10 +1439,31 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_INET;
ifm->ifa_prefixlen = ifa->ifa_prefixlen;
- ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
+ ifm->ifa_flags = ifa->ifa_flags;
ifm->ifa_scope = ifa->ifa_scope;
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
+ if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
+ preferred = ifa->ifa_preferred_lft;
+ valid = ifa->ifa_valid_lft;
+ if (preferred != INFINITY_LIFE_TIME) {
+ long tval = (jiffies - ifa->ifa_tstamp) / HZ;
+
+ if (preferred > tval)
+ preferred -= tval;
+ else
+ preferred = 0;
+ if (valid != INFINITY_LIFE_TIME) {
+ if (valid > tval)
+ valid -= tval;
+ else
+ valid = 0;
+ }
+ }
+ } else {
+ preferred = INFINITY_LIFE_TIME;
+ valid = INFINITY_LIFE_TIME;
+ }
if ((ifa->ifa_address &&
nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
(ifa->ifa_local &&
@@ -1270,7 +1471,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
(ifa->ifa_broadcast &&
nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
(ifa->ifa_label[0] &&
- nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
+ nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
+ put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
+ preferred, valid))
goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -1988,6 +2191,8 @@ void __init devinet_init(void)
register_gifconf(PF_INET, inet_gifconf);
register_netdevice_notifier(&ip_netdev_notifier);
+ schedule_delayed_work(&check_lifetime_work, 0);
+
rtnl_af_register(&inet_af_ops);
rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 80d5980..7f7332b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -110,10 +110,6 @@ static inline u32 cstamp_delta(unsigned long cstamp)
return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
}
-#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
-#define ADDRCONF_TIMER_FUZZ (HZ / 4)
-#define ADDRCONF_TIMER_FUZZ_MAX (HZ)
-
#ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev);
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
--
1.8.1
^ permalink raw reply related
* [patch net-next V2] bond: have random dev address by default instead of zeroes
From: Jiri Pirko @ 2013-01-24 20:01 UTC (permalink / raw)
To: netdev; +Cc: davem, fubar, andy, stephen, psimerda, dcbw
Makes more sense to have randomly generated address by default than to
have all zeroes. It also allows user to for example put the bond into
bridge without need to have any slaves in it.
Also note that this changes only behaviour of bonds with no slaves. Once
the first slave device is enslaved, its address will be used (no change
here).
Also, fix dev_assign_type values on the way.
Reported-by: Pavel Šimerda <psimerda@redhat.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
v1->v2:
- fixed assign value of bond_dev->addr_assign_type in bond_set_dev_addr()
- added note to patch description
drivers/net/bonding/bond_main.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 564cf42..1d56ac9 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1320,14 +1320,14 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
/*---------------------------------- IOCTL ----------------------------------*/
-static int bond_sethwaddr(struct net_device *bond_dev,
- struct net_device *slave_dev)
+static void bond_set_dev_addr(struct net_device *bond_dev,
+ struct net_device *slave_dev)
{
pr_debug("bond_dev=%p\n", bond_dev);
pr_debug("slave_dev=%p\n", slave_dev);
pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
- return 0;
+ bond_dev->addr_assign_type = NET_ADDR_SET;
}
static netdev_features_t bond_fix_features(struct net_device *dev,
@@ -1628,10 +1628,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* If this is the first slave, then we need to set the master's hardware
* address to be the same as the slave's. */
- if (is_zero_ether_addr(bond->dev->dev_addr))
- memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
- slave_dev->addr_len);
-
+ if (bond->dev->addr_assign_type != NET_ADDR_SET)
+ bond_set_dev_addr(bond->dev, slave_dev);
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
@@ -2049,11 +2047,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
if (bond->slave_cnt == 0) {
bond_set_carrier(bond);
- /* if the last slave was removed, zero the mac address
- * of the master so it will be set by the application
- * to the mac address of the first slave
+ /* If the last slave was removed, set random mac address
+ * of the master so it will be set by bond_enslave()
+ * to the mac address of the first slave.
*/
- memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
+ eth_hw_addr_random(bond_dev);
if (bond_vlan_used(bond)) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -3708,7 +3706,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
break;
case BOND_SETHWADDR_OLD:
case SIOCBONDSETHWADDR:
- res = bond_sethwaddr(bond_dev, slave_dev);
+ bond_set_dev_addr(bond_dev, slave_dev);
+ res = 0;
break;
case BOND_CHANGE_ACTIVE_OLD:
case SIOCBONDCHANGEACTIVE:
@@ -4858,6 +4857,11 @@ static int bond_init(struct net_device *bond_dev)
bond_debug_register(bond);
+ /* Ensure valid dev_addr */
+ if (is_zero_ether_addr(bond_dev->dev_addr) &&
+ bond_dev->addr_assign_type == NET_ADDR_PERM)
+ eth_hw_addr_random(bond_dev);
+
__hw_addr_init(&bond->mc_list);
return 0;
}
--
1.8.1
^ permalink raw reply related
* Re: 3.7.3+: Bad paging request in ip_rcv_finish while running NFS traffic.
From: Ben Greear @ 2013-01-24 20:03 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1358991906.12374.1356.camel@edumazet-glaptop>
On 01/23/2013 05:45 PM, Eric Dumazet wrote:
> On Wed, 2013-01-23 at 17:10 -0800, Eric Dumazet wrote:
>
>> Excellent, thats the bug.
>>
>> I'll send a fix asap, thanks !
>
> loopback device doesnt have a qdisc, and unsets IFF_XMIT_DST_RELEASE
>
> Its hard to believe such an old bug never hit us in the past.
>
> Probably because most of the time, the packet given to netif_rx() is
> immediately processed (and loopback device is hard wired ?)
I have not seen any crashes since this change went into my
test bed, so I believe this one is finally fixed! I'm running
with your macvlan fixes as well..and even if they did not
fix the problem I saw, they at least appear to cause no harm.
If you wish, feel free to add:
Tested-By: Ben Greear <greearb@candelatech.com>
Thanks,
Ben
>
>
> diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
> index 81f8f9e..fcbf680 100644
> --- a/drivers/net/loopback.c
> +++ b/drivers/net/loopback.c
> @@ -77,6 +77,11 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
>
> skb_orphan(skb);
>
> + /* Before queueing this packet to netif_rx(),
> + * make sure dst is refcounted.
> + */
> + skb_dst_force(skb);
> +
> skb->protocol = eth_type_trans(skb, dev);
>
> /* it's OK to use per_cpu_ptr() because BHs are off */
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: 3.7.3+: Bad paging request in ip_rcv_finish while running NFS traffic.
From: Eric Dumazet @ 2013-01-24 20:59 UTC (permalink / raw)
To: Ben Greear; +Cc: netdev
In-Reply-To: <51019397.90304@candelatech.com>
On Thu, 2013-01-24 at 12:03 -0800, Ben Greear wrote:
> iately processed (and loopback device is hard wired ?)
>
> I have not seen any crashes since this change went into my
> test bed, so I believe this one is finally fixed! I'm running
> with your macvlan fixes as well..and even if they did not
> fix the problem I saw, they at least appear to cause no harm.
>
> If you wish, feel free to add:
>
> Tested-By: Ben Greear <greearb@candelatech.com>
>
> Thanks,
> Ben
Just to make sure, you still have the
WARN_ON_ONCE(skb_dst_is_noref(skb))
in netif_rx() ?
^ permalink raw reply
* Re: 3.7.3+: Bad paging request in ip_rcv_finish while running NFS traffic.
From: Ben Greear @ 2013-01-24 21:01 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1359061140.12374.2395.camel@edumazet-glaptop>
On 01/24/2013 12:59 PM, Eric Dumazet wrote:
> On Thu, 2013-01-24 at 12:03 -0800, Ben Greear wrote:
>> iately processed (and loopback device is hard wired ?)
>>
>> I have not seen any crashes since this change went into my
>> test bed, so I believe this one is finally fixed! I'm running
>> with your macvlan fixes as well..and even if they did not
>> fix the problem I saw, they at least appear to cause no harm.
>>
>> If you wish, feel free to add:
>>
>> Tested-By: Ben Greear <greearb@candelatech.com>
>>
>> Thanks,
>> Ben
>
> Just to make sure, you still have the
>
> WARN_ON_ONCE(skb_dst_is_noref(skb))
>
> in netif_rx() ?
>
I have something similar, and I have not seen any splats:
int netif_rx(struct sk_buff *skb)
{
int ret;
WARN_ON(skb->_skb_refdst & SKB_DST_NOREF);
I'll keep this in our kernels so when we do .1q vlans and other
sorts of testing we'll get some more coverage.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH net] net: usbnet: prevent buggy devices from killing us
From: Oliver Neukum @ 2013-01-24 22:09 UTC (permalink / raw)
To: Bjørn Mork; +Cc: linux-usb, netdev
In-Reply-To: <1359055016-13603-1-git-send-email-bjorn@mork.no>
On Thursday 24 January 2013 20:16:56 Bjørn Mork wrote:
> A device sending 0 length frames as fast as it can has been
> observed killing the host system due to the resulting memory
> pressure.
>
> Temporarily disable RX skb allocation and URB submission when
> the current error ratio is high, preventing us from trying to
> allocate an infinite number of skbs. Reenable as soon as we
> are finished processing the done queue, allowing the device
> to continue working after short error bursts.
>
> Signed-off-by: Bjørn Mork <bjorn@mork.no>
> ---
> So is this starting to look OK?
It seems to me that we at least need to try some error recovery.
How about resetting the device when it is no longer used?
Regards
Oliver
^ permalink raw reply
* Re: [PATCH] SCTP: Free the per-net sysctl table on net exit.
From: Eric W. Biederman @ 2013-01-24 22:14 UTC (permalink / raw)
To: Neil Horman; +Cc: Vlad Yasevich, netdev, davem, linux-sctp, mmokrejs
In-Reply-To: <20130124164439.GB20658@hmsreliant.think-freely.org>
Neil Horman <nhorman@tuxdriver.com> writes:
> On Thu, Jan 24, 2013 at 11:02:47AM -0500, Vlad Yasevich wrote:
>> Per-net sysctl table needs to be explicitly freed at
>> net exit. Otherwise we see the following with kmemleak:
>>
>> unreferenced object 0xffff880402d08000 (size 2048):
>> comm "chrome_sandbox", pid 18437, jiffies 4310887172 (age 9097.630s)
>> hex dump (first 32 bytes):
>> b2 68 89 81 ff ff ff ff 20 04 04 f8 01 88 ff ff .h...... .......
>> 04 00 00 00 a4 01 00 00 00 00 00 00 00 00 00 00 ................
>> backtrace:
>> [<ffffffff815b4aad>] kmemleak_alloc+0x21/0x3e
>> [<ffffffff81110352>] slab_post_alloc_hook+0x28/0x2a
>> [<ffffffff81113fad>] __kmalloc_track_caller+0xf1/0x104
>> [<ffffffff810f10c2>] kmemdup+0x1b/0x30
>> [<ffffffff81571e9f>] sctp_sysctl_net_register+0x1f/0x72
>> [<ffffffff8155d305>] sctp_net_init+0x100/0x39f
>> [<ffffffff814ad53c>] ops_init+0xc6/0xf5
>> [<ffffffff814ad5b7>] setup_net+0x4c/0xd0
>> [<ffffffff814ada5e>] copy_net_ns+0x6d/0xd6
>> [<ffffffff810938b1>] create_new_namespaces+0xd7/0x147
>> [<ffffffff810939f4>] copy_namespaces+0x63/0x99
>> [<ffffffff81076733>] copy_process+0xa65/0x1233
>> [<ffffffff81077030>] do_fork+0x10b/0x271
>> [<ffffffff8100a0e9>] sys_clone+0x23/0x25
>> [<ffffffff815dda73>] stub_clone+0x13/0x20
>> [<ffffffffffffffff>] 0xffffffffffffffff
>>
>> Reported-by: Martin Mokrejs <mmokrejs@fold.natur.cuni.cz>
>> Signed-off-by: Vlad Yasevich <vyasevich@gmail.com>
>> CC: "Eric W. Biederman" <ebiederm@xmission.com>
>> ---
>> net/sctp/sysctl.c | 4 ++++
>> 1 files changed, 4 insertions(+), 0 deletions(-)
>>
>> diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
>> index 043889a..cd5712f 100644
>> --- a/net/sctp/sysctl.c
>> +++ b/net/sctp/sysctl.c
>> @@ -366,7 +366,11 @@ int sctp_sysctl_net_register(struct net *net)
>>
>> void sctp_sysctl_net_unregister(struct net *net)
>> {
>> + struct ctl_table *table;
>> +
>> + table = net->sctp.sysctl_hdr->ctl_table_arg;
>> unregister_net_sysctl_table(net->sctp.sysctl_header);
>> + kfree(table);
>> }
>>
>> static struct ctl_table_header * sctp_sysctl_header;
>> --
>> 1.7.7.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
> Acked-by: Neil Horman <nhorman@tuxdriver.com>
Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com>
Doh. I should have known better.
Eric
^ permalink raw reply
* [PATCH 0/2] GRE: segmentation offload
From: Pravin B Shelar @ 2013-01-24 22:16 UTC (permalink / raw)
To: netdev; +Cc: jesse, eric.dumazet, Pravin B Shelar
Following patch adds segmentation offload to GRE. I did performance
tests with netperf single TCP_STREAM tests, results are as follows
for GRE TAP device on 10G.
base kernel: 4043 10^6bits/sec
with patch: 4801 10^6bits/sec (+18.7)
This patch also address concerns that were raised in GRE csum discussion
(http://patchwork.ozlabs.org/patch/214665/). It avoids large skb allocation
in xmit path and improves performance as shown.
Pravin B Shelar (2):
net: Add skb_unclone() helper function.
GRE: Add segmentation offload for GRE
drivers/net/ppp/ppp_generic.c | 3 +-
include/linux/netdevice.h | 4 +-
include/linux/skbuff.h | 20 ++++++
net/core/dev.c | 59 ++++++++++-------
net/core/skbuff.c | 7 +-
net/ipv4/af_inet.c | 1 +
net/ipv4/ah4.c | 3 +-
net/ipv4/gre.c | 110 +++++++++++++++++++++++++++++++
net/ipv4/ip_fragment.c | 2 +-
net/ipv4/ip_gre.c | 94 +++++++++++++++++++++-----
net/ipv4/tcp.c | 1 +
net/ipv4/tcp_output.c | 2 +-
net/ipv4/udp.c | 3 +-
net/ipv4/xfrm4_input.c | 2 +-
net/ipv4/xfrm4_mode_tunnel.c | 3 +-
net/ipv6/ah6.c | 3 +-
net/ipv6/ip6_offload.c | 1 +
net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +-
net/ipv6/reassembly.c | 2 +-
net/ipv6/udp_offload.c | 3 +-
net/ipv6/xfrm6_mode_tunnel.c | 3 +-
net/sched/act_ipt.c | 6 +-
net/sched/act_pedit.c | 3 +-
23 files changed, 271 insertions(+), 66 deletions(-)
--
1.7.10
^ permalink raw reply
* [PATCH 1/2] net: Add skb_unclone() helper function.
From: Pravin B Shelar @ 2013-01-24 22:16 UTC (permalink / raw)
To: netdev; +Cc: jesse, eric.dumazet, Pravin B Shelar
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
drivers/net/ppp/ppp_generic.c | 3 +--
include/linux/skbuff.h | 13 +++++++++++++
net/ipv4/ah4.c | 3 +--
net/ipv4/ip_fragment.c | 2 +-
net/ipv4/tcp_output.c | 2 +-
net/ipv4/xfrm4_input.c | 2 +-
net/ipv4/xfrm4_mode_tunnel.c | 3 +--
net/ipv6/ah6.c | 3 +--
net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +-
net/ipv6/reassembly.c | 2 +-
net/ipv6/xfrm6_mode_tunnel.c | 3 +--
net/sched/act_ipt.c | 6 ++----
net/sched/act_pedit.c | 3 +--
13 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 0b2706a..4fd754e 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1805,8 +1805,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* the filter instructions are constructed assuming
a four-byte PPP header on each packet */
if (ppp->pass_filter || ppp->active_filter) {
- if (skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto err;
*skb_push(skb, 2) = 0;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 8b2256e..7c00664 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -798,6 +798,19 @@ static inline int skb_cloned(const struct sk_buff *skb)
}
/**
+ * skb_unclone - creates separate copy if skb is cloned.
+ */
+static inline bool skb_unclone(struct sk_buff *skb, gfp_t pri)
+{
+ might_sleep_if(pri & __GFP_WAIT);
+
+ if (skb_cloned(skb))
+ return pskb_expand_head(skb, 0, 0, pri);
+
+ return 0;
+}
+
+/**
* skb_header_cloned - is the header a clone
* @skb: buffer to check
*
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index a0d8392..396c823 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -317,8 +317,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
/* We are going to _remove_ AH header to keep sockets happy,
* so... Later this can change. */
- if (skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto out;
skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index f55a4e6..411ef7c 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -594,7 +594,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
goto out_oversize;
/* Head of list must not be cloned. */
- if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(head, GFP_ATOMIC))
goto out_nomem;
/* If the first fragment is fragmented itself, we split
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 667a6ad..0ecc187 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1331,7 +1331,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
/* Remove acked data from a packet in the transmit queue. */
int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
{
- if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
return -ENOMEM;
__pskb_trim_head(skb, len);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 06814b6..1f12c8b 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -132,7 +132,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
* header and optional ESP marker bytes) and then modify the
* protocol to ESP, and then call into the transform receiver.
*/
- if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto drop;
/* Now we can update and verify the packet length... */
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index ddee0a0..c1f00ef 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -142,8 +142,7 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
for_each_input_rcu(rcv_notify_handlers, handler)
handler->handler(skb);
- if (skb_cloned(skb) &&
- (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto out;
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index ecc35b9..afcf8ee 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -518,8 +518,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
/* We are going to _remove_ AH header to keep sockets happy,
* so... Later this can change. */
- if (skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto out;
skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 3dacecc..4e941dc 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -369,7 +369,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
}
/* Head of list must not be cloned. */
- if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
+ if (skb_unclone(head, GFP_ATOMIC)) {
pr_debug("skb is cloned but can't expand head");
goto out_oom;
}
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index e5253ec..c9d5d3ddfc 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -406,7 +406,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
goto out_oversize;
/* Head of list must not be cloned. */
- if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(head, GFP_ATOMIC))
goto out_oom;
/* If the first fragment is fragmented itself, we split
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 9f2095b..4b04f4e 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -69,8 +69,7 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto out;
- if (skb_cloned(skb) &&
- (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto out;
if (x->props.flags & XFRM_STATE_DECAP_DSCP)
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 0fb9e3f..e0f6de6 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -207,10 +207,8 @@ static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
struct tcf_ipt *ipt = a->priv;
struct xt_action_param par;
- if (skb_cloned(skb)) {
- if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
- return TC_ACT_UNSPEC;
- }
+ if (skb_unclone(skb, GFP_ATOMIC))
+ return TC_ACT_UNSPEC;
spin_lock(&ipt->tcf_lock);
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 0c3fadd..7ed78c9 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -131,8 +131,7 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
int i, munged = 0;
unsigned int off;
- if (skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
return p->tcf_action;
off = skb_network_offset(skb);
--
1.7.10
^ permalink raw reply related
* [PATCH 2/2] v2 GRE: Add segmentation offload for GRE
From: Pravin B Shelar @ 2013-01-24 22:16 UTC (permalink / raw)
To: netdev; +Cc: jesse, eric.dumazet, Pravin B Shelar
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
Fixed according to comments from Jesse and Eric.
- Factored a MAC layer handler out of skb_gso_segment().
- Eliminated copy operation from gre_gso_segment().
- Refresh header pointer after pskb_may_pull().
---
include/linux/netdevice.h | 4 +-
include/linux/skbuff.h | 7 +++
net/core/dev.c | 58 ++++++++++++++----------
net/core/skbuff.c | 7 ++-
net/ipv4/af_inet.c | 1 +
net/ipv4/gre.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
net/ipv4/ip_gre.c | 94 ++++++++++++++++++++++++++++++--------
net/ipv4/tcp.c | 1 +
net/ipv4/udp.c | 3 +-
net/ipv6/ip6_offload.c | 1 +
net/ipv6/udp_offload.c | 3 +-
11 files changed, 243 insertions(+), 45 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 549f5ad..109d27b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2662,8 +2662,10 @@ extern int netdev_master_upper_dev_link(struct net_device *dev,
extern void netdev_upper_dev_unlink(struct net_device *dev,
struct net_device *upper_dev);
extern int skb_checksum_help(struct sk_buff *skb);
+extern struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
+ netdev_features_t features);
extern struct sk_buff *skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features);
+ netdev_features_t features);
#ifdef CONFIG_BUG
extern void netdev_rx_csum_fault(struct net_device *dev);
#else
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7c00664..7b98ee6 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -307,6 +307,8 @@ enum {
SKB_GSO_TCPV6 = 1 << 4,
SKB_GSO_FCOE = 1 << 5,
+
+ SKB_GSO_GRE = 1 << 6,
};
#if BITS_PER_LONG > 32
@@ -2711,6 +2713,11 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
}
#endif
+struct skb_gso_cb {
+ int tnl_hoffset;
+};
+#define NAPI_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)
+
static inline bool skb_is_gso(const struct sk_buff *skb)
{
return skb_shinfo(skb)->gso_size;
diff --git a/net/core/dev.c b/net/core/dev.c
index c69cd87..208eb8b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2293,18 +2293,8 @@ out:
}
EXPORT_SYMBOL(skb_checksum_help);
-/**
- * skb_gso_segment - Perform segmentation on skb.
- * @skb: buffer to segment
- * @features: features for the output path (see dev->features)
- *
- * This function segments the given skb and returns a list of segments.
- *
- * It may return NULL if the skb requires no segmentation. This is
- * only possible when GSO is used for verifying header integrity.
- */
-struct sk_buff *skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features)
+struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
+ netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
@@ -2323,18 +2313,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb,
vlan_depth += VLAN_HLEN;
}
- skb_reset_mac_header(skb);
- skb->mac_len = skb->network_header - skb->mac_header;
__skb_pull(skb, skb->mac_len);
-
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
- skb_warn_bad_offload(skb);
-
- if (skb_header_cloned(skb) &&
- (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
- return ERR_PTR(err);
- }
-
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
if (ptype->type == type && ptype->callbacks.gso_segment) {
@@ -2356,6 +2335,39 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb,
return segs;
}
+EXPORT_SYMBOL(skb_mac_gso_segment);
+
+/**
+ * skb_gso_segment - Perform segmentation on skb.
+ * @skb: buffer to segment
+ * @features: features for the output path (see dev->features)
+ *
+ * This function segments the given skb and returns a list of segments.
+ *
+ * It may return NULL if the skb requires no segmentation. This is
+ * only possible when GSO is used for verifying header integrity.
+ */
+struct sk_buff *skb_gso_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ int err;
+
+ if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
+ skb_warn_bad_offload(skb);
+
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return ERR_PTR(err);
+ }
+ }
+ NAPI_GSO_CB(skb)->tnl_hoffset = skb_headroom(skb);
+
+ skb_reset_mac_header(skb);
+ skb->mac_len = skb->network_header - skb->mac_header;
+
+ return skb_mac_gso_segment(skb, features);
+}
EXPORT_SYMBOL(skb_gso_segment);
/* Take action when hardware reception checksum errors are detected. */
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2568c44..c12b6f3 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2752,6 +2752,8 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
unsigned int doffset = skb->data - skb_mac_header(skb);
unsigned int offset = doffset;
unsigned int headroom;
+ unsigned int tnl_hlen = (skb_mac_header(skb) - skb->head) -
+ NAPI_GSO_CB(skb)->tnl_hoffset;
unsigned int len;
int sg = !!(features & NETIF_F_SG);
int nfrags = skb_shinfo(skb)->nr_frags;
@@ -2827,7 +2829,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
skb_set_network_header(nskb, skb->mac_len);
nskb->transport_header = (nskb->network_header +
skb_network_header_len(skb));
- skb_copy_from_linear_data(skb, nskb->data, doffset);
+
+ skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+ nskb->data - tnl_hlen,
+ doffset + tnl_hlen);
if (fskb != skb_shinfo(skb)->frag_list)
continue;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 4b70539..2bd9998 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1306,6 +1306,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
+ SKB_GSO_GRE |
0)))
goto out;
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index 42a4910..1f86421 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -19,6 +19,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
+#include <linux/if_tunnel.h>
#include <linux/spinlock.h>
#include <net/protocol.h>
#include <net/gre.h>
@@ -26,6 +27,11 @@
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
static DEFINE_SPINLOCK(gre_proto_lock);
+struct gre_base_hdr {
+ __be16 flags;
+ __be16 protocol;
+};
+#define GRE_HEADER_SECTION 4
int gre_add_protocol(const struct gre_protocol *proto, u8 version)
{
@@ -112,12 +118,108 @@ static void gre_err(struct sk_buff *skb, u32 info)
rcu_read_unlock();
}
+static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ int ghl = GRE_HEADER_SECTION;
+ struct gre_base_hdr *greh;
+ int mac_len = skb->mac_len;
+ int hlen;
+ bool csum;
+
+ if (unlikely(skb_shinfo(skb)->gso_type &
+ ~(SKB_GSO_TCPV4 |
+ SKB_GSO_TCPV6 |
+ SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+ SKB_GSO_TCP_ECN |
+ SKB_GSO_GRE)))
+ goto out;
+
+ if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
+ goto out;
+
+ greh = (struct gre_base_hdr *)skb_transport_header(skb);
+
+ if (greh->flags & GRE_KEY)
+ ghl += GRE_HEADER_SECTION;
+ if (greh->flags & GRE_CSUM) {
+ ghl += GRE_HEADER_SECTION;
+ csum = true;
+ } else
+ csum = false;
+
+ /* setup inner skb. */
+ if (greh->protocol == htons(ETH_P_TEB)) {
+ struct ethhdr *eth = eth_hdr(skb);
+ skb->protocol = eth->h_proto;
+ } else {
+ skb->protocol = greh->protocol;
+ }
+
+ hlen = mac_len + sizeof(struct iphdr);
+ skb->encapsulation = 0;
+
+ if (unlikely(!pskb_may_pull(skb, ghl)))
+ goto out;
+ __skb_pull(skb, ghl);
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, skb_inner_network_offset(skb));
+ skb->mac_len = skb_inner_network_offset(skb);
+
+ /* segment inner packet. */
+ segs = skb_mac_gso_segment(skb, 0);
+ if (!segs || IS_ERR(segs))
+ goto out;
+
+ skb = segs;
+ do {
+ __skb_push(skb, ghl + hlen);
+ if (csum) {
+ __be32 *pcsum;
+
+ greh = (struct gre_base_hdr *)(skb->data + hlen);
+ pcsum = (__be32 *)(greh + 1);
+ *pcsum = 0;
+ *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, hlen,
+ skb->len - hlen, 0));
+ }
+
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, mac_len);
+ skb->mac_len = mac_len;
+ } while ((skb = skb->next));
+out:
+ return segs;
+}
+
+static int gre_gso_send_check(struct sk_buff *skb)
+{
+ struct gre_base_hdr *greh;
+
+ if (!skb->encapsulation)
+ return -EINVAL;
+
+ greh = (struct gre_base_hdr *)skb_transport_header(skb);
+ if (greh->flags & GRE_SEQ)
+ return -EINVAL;
+ return 0;
+}
+
static const struct net_protocol net_gre_protocol = {
.handler = gre_rcv,
.err_handler = gre_err,
.netns_ok = 1,
};
+static const struct net_offload gre_offload = {
+ .callbacks = {
+ .gso_send_check = gre_gso_send_check,
+ .gso_segment = gre_gso_segment,
+ },
+};
+
static int __init gre_init(void)
{
pr_info("GRE over IPv4 demultiplexor driver\n");
@@ -127,11 +229,18 @@ static int __init gre_init(void)
return -EAGAIN;
}
+ if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
+ pr_err("can't add protocol offload\n");
+ inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+ return -EAGAIN;
+ }
+
return 0;
}
static void __exit gre_exit(void)
{
+ inet_del_offload(&gre_offload, IPPROTO_GRE);
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
}
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 303012a..ac8cb5e 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -735,6 +735,42 @@ drop:
return 0;
}
+static struct sk_buff *handle_offloads(struct sk_buff *skb)
+{
+ int err;
+
+ if (skb_is_gso(skb)) {
+ err = skb_unclone(skb, GFP_ATOMIC);
+ if (unlikely(err))
+ goto error;
+ skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
+ return skb;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ /* Pages aren't locked and could change at any time.
+ * If this happens after we compute the checksum, the
+ * checksum will be wrong. We linearize now to avoid
+ * this problem.
+ */
+ if (skb_is_nonlinear(skb)) {
+ err = __skb_linearize(skb);
+ if (unlikely(err))
+ goto error;
+ }
+
+ err = skb_checksum_help(skb);
+ if (unlikely(err))
+ goto error;
+ }
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return skb;
+
+error:
+ kfree_skb(skb);
+ return ERR_PTR(err);
+}
+
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -751,10 +787,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
__be32 dst;
int mtu;
u8 ttl;
-
- if (skb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_help(skb))
- goto tx_error;
+ int pkt_len;
+ struct pcpu_tstats *tstats;
+ int err;
if (dev->type == ARPHRD_ETHER)
IPCB(skb)->flags = 0;
@@ -852,13 +887,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
if (skb->protocol == htons(ETH_P_IP)) {
df |= (old_iph->frag_off&htons(IP_DF));
-
- if ((old_iph->frag_off&htons(IP_DF)) &&
- mtu < ntohs(old_iph->tot_len)) {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
- ip_rt_put(rt);
- goto tx_error;
- }
}
#if IS_ENABLED(CONFIG_IPV6)
else if (skb->protocol == htons(ETH_P_IPV6)) {
@@ -873,11 +901,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
}
}
- if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- ip_rt_put(rt);
- goto tx_error;
- }
}
#endif
@@ -908,10 +931,19 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
skb_set_owner_w(new_skb, skb->sk);
dev_kfree_skb(skb);
skb = new_skb;
- old_iph = ip_hdr(skb);
/* Warning : tiph value might point to freed memory */
}
+ if (!skb->encapsulation) {
+ skb_reset_inner_headers(skb);
+ skb->encapsulation = 1;
+ }
+
+ skb = handle_offloads(skb);
+ if (IS_ERR(skb))
+ return NETDEV_TX_OK;
+
+ old_iph = ip_hdr(skb);
skb_push(skb, gre_hlen);
skb_reset_network_header(skb);
skb_set_transport_header(skb, sizeof(*iph));
@@ -967,8 +999,23 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
*(__sum16 *)ptr = ip_compute_csum((void *)(iph+1), skb->len - sizeof(struct iphdr));
}
}
+ pkt_len = skb->len - skb_transport_offset(skb);
+ tstats = this_cpu_ptr(dev->tstats);
+
+ nf_reset(skb);
+ ip_select_ident(iph, skb_dst(skb), NULL);
+
+ err = ip_local_out(skb);
+ if (likely(net_xmit_eval(err) == 0)) {
+ u64_stats_update_begin(&tstats->syncp);
+ tstats->tx_bytes += pkt_len;
+ tstats->tx_packets++;
+ u64_stats_update_end(&tstats->syncp);
+ } else {
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+ }
- iptunnel_xmit(skb, dev);
return NETDEV_TX_OK;
#if IS_ENABLED(CONFIG_IPV6)
@@ -1374,6 +1421,10 @@ static int ipgre_tunnel_init(struct net_device *dev)
return err;
}
+ if (!(tunnel->parms.o_flags & GRE_SEQ)) {
+ dev->features |= NETIF_F_GSO_SOFTWARE;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+ }
return 0;
}
@@ -1564,6 +1615,10 @@ static int ipgre_tap_init(struct net_device *dev)
if (!dev->tstats)
return -ENOMEM;
+ if (!(tunnel->parms.o_flags & GRE_SEQ)) {
+ dev->features |= NETIF_F_GSO_SOFTWARE;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+ }
return 0;
}
@@ -1587,6 +1642,9 @@ static void ipgre_tap_setup(struct net_device *dev)
dev->iflink = 0;
dev->features |= NETIF_F_NETNS_LOCAL;
+
+ dev->features |= GRE_FEATURES;
+ dev->hw_features |= GRE_FEATURES;
}
static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 5227194..8c47b7d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3032,6 +3032,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_TCPV6 |
+ SKB_GSO_GRE |
0) ||
!(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
goto out;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index e0610e4..6824272 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2304,7 +2304,8 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
/* Packet is from an untrusted source, reset gso_segs. */
int type = skb_shinfo(skb)->gso_type;
- if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+ if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
+ SKB_GSO_GRE) ||
!(type & (SKB_GSO_UDP))))
goto out;
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index f26f0da..8234c1d 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -99,6 +99,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
~(SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
+ SKB_GSO_GRE |
SKB_GSO_TCPV6 |
0)))
goto out;
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 0c8934a..cf05cf0 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -56,7 +56,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
/* Packet is from an untrusted source, reset gso_segs. */
int type = skb_shinfo(skb)->gso_type;
- if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+ if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
+ SKB_GSO_GRE) ||
!(type & (SKB_GSO_UDP))))
goto out;
--
1.7.10
^ permalink raw reply related
* Re: BUG: unable to handle kernel paging request at 0000000000609920 in networking code on 3.2.23.
From: Florian Westphal @ 2013-01-24 23:08 UTC (permalink / raw)
To: Rafal Kupka; +Cc: netdev, netfilter-devel
In-Reply-To: <loom.20130124T115328-292@post.gmane.org>
Rafal Kupka <rkupka@telemetry.com> wrote:
[ cc nf-devel ]
> > After upgrade to 3.2.23 (debian backports 2.6.32-45 package) from 2.6.32 I
> experience server crash.
> New round of tests on 3.2.35-2~bpo60+1. Still similar crashes.
>
> > Iptables:
> >
> > Chain INPUT (policy ACCEPT)
> > target prot opt source destination
> > dumbtcp tcp -- 0.0.0.0/0 91.217.135.0/24
> >
> > Chain OUTPUT (policy ACCEPT)
> > target prot opt source destination
> > dumbtcp tcp -- 91.217.135.0/24 0.0.0.0/0
> >
> > Chain dumbtcp (2 references)
> > target prot opt source destination
> > TCPOPTSTRIP tcp -- 0.0.0.0/0 0.0.0.0/0 tcpflags:
> 0x02/0x02 TCPOPTSTRIP options 3,4,5,8,19
> > ECN tcp -- 0.0.0.0/0 0.0.0.0/0 ECN TCP remove
>
> This Netfilter rules are causing it. Either ECN or TCPOPTSTRIP module.
I don't see any relevant changes in either TCPOPTSTRIP or ECN.
> 3.2.35 calltrace:
> [15368.854247] Call Trace:
> [15368.856749] <IRQ>
> [15368.858898] [<ffffffff812a02a8>] ? skb_release_data+0x6c/0xe4
> [15368.864791] [<ffffffff812a08b0>] ? __kfree_skb+0x11/0x73
> [15368.870254] [<ffffffff812e5c5f>] ? tcp_rcv_state_process+0x74/0x8d9
> [15368.876632] [<ffffffff812ed0b7>] ? tcp_v4_do_rcv+0x388/0x3eb
> [15368.882448] [<ffffffff812ee54e>] ? tcp_v4_rcv+0x447/0x6ed
> [15368.888007] [<ffffffff812cb746>] ? nf_hook_slow+0x68/0xfd
> [15368.893572] [<ffffffff812d197e>] ? T.1004+0x4f/0x4f
> [15368.898614] [<ffffffff812d1abb>] ? ip_local_deliver_finish+0x13d/0x1aa
> [15368.905301] [<ffffffff812aab66>] ? __netif_receive_skb+0x47d/0x4b0
> [15368.911642] [<ffffffff81013a01>] ? read_tsc+0x5/0x16
> [15368.916768] [<ffffffff812aadc7>] ? netif_receive_skb+0x67/0x6d
> [15368.922757] [<ffffffff812ab335>] ? napi_gro_receive+0x1f/0x2c
> [15368.928661] [<ffffffff812aaea1>] ? napi_skb_finish+0x1c/0x31
> [15368.934495] [<ffffffffa0049a61>] ? e1000_clean_rx_irq+0x1ea/0x29a [e1000e]
> [15368.941533] [<ffffffffa0049fa2>] ? e1000_clean+0x71/0x229 [e1000e]
> [15368.947875] [<ffffffff8103b982>] ? __wake_up+0x35/0x46
> [15368.953171] [<ffffffff812ab460>] ? net_rx_action+0xa8/0x207
> [15368.958908] [<ffffffff81046351>] ? finish_task_switch+0x50/0xc7
> [15368.964995] [<ffffffff8104f2ca>] ? __do_softirq+0xc4/0x1a0
> [15368.970636] [<ffffffff81097ec6>] ? handle_irq_event_percpu+0x163/0x181
> [15368.977324] [<ffffffff8136f8ac>] ? call_softirq+0x1c/0x30
> [15368.982884] [<ffffffff8100fa3f>] ? do_softirq+0x3f/0x79
> [15368.988266] [<ffffffff8104f09a>] ? irq_exit+0x44/0xb5
> [15368.993473] [<ffffffff8100f38a>] ? do_IRQ+0x94/0xaa
> [15368.998489] [<ffffffff8136836e>] ? common_interrupt+0x6e/0x6e
> [15369.004397] <EOI>
> [15369.006537] [<ffffffff81107e38>] ? fput+0x17a/0x1a2
> [15369.011576] [<ffffffff81046351>] ? finish_task_switch+0x50/0xc7
> [15369.017653] [<ffffffff81366b46>] ? __schedule+0x57a/0x5cd
> [15369.023209] [<ffffffff81368416>] ? retint_careful+0x14/0x32
However, it does seem to me as if both are missing a few sanity checks.
Especially TCPOPSTRIP can read/write beyond end-of-packet when
tcph->doff is bogus?
Something like this (not even compile tested):
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 4bf3dc4..a1f8a59 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -86,7 +86,7 @@ ecn_tg(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) &&
- ip_hdr(skb)->protocol == IPPROTO_TCP)
+ (ip_hdr(skb)->frag_off & htons(IP_OFFSET)) == 0)
if (!set_ect_tcp(skb, einfo))
return NF_DROP;
diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c
index 25fd1c4..ebb9451 100644
--- a/net/netfilter/xt_TCPOPTSTRIP.c
+++ b/net/netfilter/xt_TCPOPTSTRIP.c
@@ -35,10 +35,18 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
{
unsigned int optl, i, j;
struct tcphdr *tcph;
+ struct tcphdr _tcph;
u_int16_t n, o;
u_int8_t *opt;
- if (!skb_make_writable(skb, skb->len))
+ if (skb->len < minlen)
+ return XT_CONTINUE;
+
+ tcph = skb_header_pointer(skb, tcphoff, sizeof(_tcph), &_tcph);
+ if (!tcph)
+ return XT_CONTINUE; /* no options -> nothing to do */
+
+ if (!skb_make_writable(skb, tcphoff + (tcph->doff * 4)))
return NF_DROP;
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
@@ -76,6 +84,9 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
static unsigned int
tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{
+ if (ip_hdr(skb)->frag_off & htons(IP_OFFSET))
+ return XT_CONTINUE;
+
return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb),
sizeof(struct iphdr) + sizeof(struct tcphdr));
}
^ permalink raw reply related
* Re: [PATCH 2/2 net-next] doc: dt: fsl: fec: add napi optional properties
From: David Miller @ 2013-01-24 23:18 UTC (permalink / raw)
To: Frank.Li
Cc: lznuaa, shawn.guo, B38611, linux-arm-kernel, netdev, bhutchings,
s.hauer
In-Reply-To: <1359011219-8343-1-git-send-email-Frank.Li@freescale.com>
From: Frank Li <Frank.Li@freescale.com>
Date: Thu, 24 Jan 2013 15:06:59 +0800
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
For the thousandth time, you should not make NAPI run time
selectable, this is non-negotable.
^ permalink raw reply
* Re: linux-next: New trees - ipsec and ipsec-next
From: Stephen Rothwell @ 2013-01-24 23:20 UTC (permalink / raw)
To: Steffen Klassert; +Cc: David Miller, Herbert Xu, linux-kernel, netdev
In-Reply-To: <20130124061315.GI9147@secunet.com>
[-- Attachment #1: Type: text/plain, Size: 2285 bytes --]
Hi Steffen,
On Thu, 24 Jan 2013 07:13:15 +0100 Steffen Klassert <steffen.klassert@secunet.com> wrote:
>
> could you please add the ipsec and ipsec-next tree to linux-next?
>
> The ipsec tree is intended to cover fixes for the ipsec networking
> subsystem and the ipsec-next tree to cover changes for ipsec with
> linux-next as target.
>
> The trees are located at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git master
> git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git master
>
> The ipsec tree follows David Miller's net tree, the ipsec-next tree follows
> the net-next tree. So they should be merged after net and net-next.
Added from today with just you as the contact.
Thanks for adding your subsystem tree as a participant of linux-next. As
you may know, this is not a judgment of your code. The purpose of
linux-next is for integration testing and to lower the impact of
conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have
been:
* submitted under GPL v2 (or later) and include the Contributor's
Signed-off-by,
* posted to the relevant mailing list,
* reviewed by you (or another maintainer of your subsystem tree),
* successfully unit tested, and
* destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him
to fetch). It is allowed to be rebased if you deem it necessary.
--
Cheers,
Stephen Rothwell
sfr@canb.auug.org.au
Legal Stuff:
By participating in linux-next, your subsystem tree contributions are
public and will be included in the linux-next trees. You may be sent
e-mail messages indicating errors or other issues when the
patches/commits from your subsystem tree are merged and tested in
linux-next. These messages may also be cross-posted to the linux-next
mailing list, the linux-kernel mailing list, etc. The linux-next tree
project and IBM (my employer) make no warranties regarding the linux-next
project, the testing procedures, the results, the e-mails, etc. If you
don't agree to these ground rules, let me know and I'll remove your tree
from participation in linux-next.
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] v2 GRE: Add segmentation offload for GRE
From: Eric Dumazet @ 2013-01-24 23:29 UTC (permalink / raw)
To: Pravin B Shelar; +Cc: netdev, jesse
In-Reply-To: <1359065793-1796-1-git-send-email-pshelar@nicira.com>
On Thu, 2013-01-24 at 14:16 -0800, Pravin B Shelar wrote:
> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
> ---
> Fixed according to comments from Jesse and Eric.
> - Factored a MAC layer handler out of skb_gso_segment().
> - Eliminated copy operation from gre_gso_segment().
> - Refresh header pointer after pskb_may_pull().
Seems nice !
> + if (skb_is_gso(skb)) {
> + err = skb_unclone(skb, GFP_ATOMIC);
> + if (unlikely(err))
> + goto error;
> + skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
> + return skb;
> + } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
> + /* Pages aren't locked and could change at any time.
> + * If this happens after we compute the checksum, the
> + * checksum will be wrong. We linearize now to avoid
> + * this problem.
> + */
> + if (skb_is_nonlinear(skb)) {
> + err = __skb_linearize(skb);
> + if (unlikely(err))
> + goto error;
> + }
> +
> + err = skb_checksum_help(skb);
> + if (unlikely(err))
> + goto error;
> + }
> +
I really don't understand why you put chunk this in this patch.
Packet being GSO or not, the underlying problem still remains.
This must be addressed separately and at a different layer.
(in skb_checksum_help() most probably)
If the packet is GSO and we compute checksum in software,
then we also have to copy all frags that could potentially
be overwritten.
> + skb->ip_summed = CHECKSUM_NONE;
> +
> + return skb;
> +
> +error:
> + kfree_skb(skb);
> + return ERR_PTR(err);
> +}
> +
> static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct ip_tunnel *tunnel = netdev_priv(dev);
> @@ -751,10 +787,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
> __be32 dst;
> int mtu;
> u8 ttl;
> -
> - if (skb->ip_summed == CHECKSUM_PARTIAL &&
> - skb_checksum_help(skb))
> - goto tx_error;
> + int pkt_len;
> + struct pcpu_tstats *tstats;
> + int err;
>
> if (dev->type == ARPHRD_ETHER)
> IPCB(skb)->flags = 0;
> @@ -852,13 +887,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
>
> if (skb->protocol == htons(ETH_P_IP)) {
> df |= (old_iph->frag_off&htons(IP_DF));
> -
> - if ((old_iph->frag_off&htons(IP_DF)) &&
> - mtu < ntohs(old_iph->tot_len)) {
> - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
> - ip_rt_put(rt);
> - goto tx_error;
> - }
Not clear why this chunk can be safely removed, even for non GSO
packet ?
^ permalink raw reply
* Re: [PATCH net] net: usbnet: prevent buggy devices from killing us
From: Joe Perches @ 2013-01-24 23:57 UTC (permalink / raw)
To: Bjørn Mork
Cc: Oliver Neukum, linux-usb-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1359055016-13603-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
On Thu, 2013-01-24 at 20:16 +0100, Bjørn Mork wrote:
> A device sending 0 length frames as fast as it can has been
> observed killing the host system due to the resulting memory
> pressure.
[]
> diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
[]
> @@ -539,6 +545,22 @@ block:
> break;
> }
>
> + /* stop rx if packet error rate is high */
> + if (++dev->pkt_cnt > 30) {
> + dev->pkt_cnt = 0;
> + dev->pkt_err = 0;
> + } else {
> + if (state == rx_cleanup)
> + dev->pkt_err++;
> + if (dev->pkt_err > 20) {
> + set_bit(EVENT_RX_KILL, &dev->flags);
> + if (net_ratelimit())
> + netif_dbg(dev, rx_err, dev->net,
> + "rx kill: high error rate\n");
> + dev->pkt_err = 0;
> + }
> + }
Maybe use ratelimit() here?
> diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
[]
> @@ -33,6 +33,7 @@ struct usbnet {
> wait_queue_head_t *wait;
> struct mutex phy_mutex;
> unsigned char suspend_count;
> + unsigned char pkt_cnt, pkt_err;
and instead:
struct ratelimit_state errors;
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net 1/1] r8169: fix vlan tag read ordering.
From: Francois Romieu @ 2013-01-24 23:30 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Hayes Wang, Timo Teras
Control of receive descriptor must not be returned to ethernet chipset
before vlan tag processing is done.
VLAN tag receive word is now reset both in normal and error path.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Spotted-by: Timo Teras <timo.teras@iki.fi>
Cc: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/ethernet/realtek/r8169.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index c28bc31..1170232 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -1826,8 +1826,6 @@ static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
if (opts2 & RxVlanTag)
__vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
-
- desc->opts2 = 0;
}
static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -6064,8 +6062,6 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
!(status & (RxRWT | RxFOVF)) &&
(dev->features & NETIF_F_RXALL))
goto process_pkt;
-
- rtl8169_mark_to_asic(desc, rx_buf_sz);
} else {
struct sk_buff *skb;
dma_addr_t addr;
@@ -6086,16 +6082,14 @@ process_pkt:
if (unlikely(rtl8169_fragmented_frame(status))) {
dev->stats.rx_dropped++;
dev->stats.rx_length_errors++;
- rtl8169_mark_to_asic(desc, rx_buf_sz);
- continue;
+ goto release_descriptor;
}
skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
tp, pkt_size, addr);
- rtl8169_mark_to_asic(desc, rx_buf_sz);
if (!skb) {
dev->stats.rx_dropped++;
- continue;
+ goto release_descriptor;
}
rtl8169_rx_csum(skb, status);
@@ -6111,6 +6105,10 @@ process_pkt:
tp->rx_stats.bytes += pkt_size;
u64_stats_update_end(&tp->rx_stats.syncp);
}
+release_descriptor:
+ desc->opts2 = 0;
+ wmb();
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
}
count = cur_rx - tp->cur_rx;
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH 2/2] v2 GRE: Add segmentation offload for GRE
From: Pravin Shelar @ 2013-01-25 0:14 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, jesse
In-Reply-To: <1359070199.12374.2557.camel@edumazet-glaptop>
On Thu, Jan 24, 2013 at 3:29 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Thu, 2013-01-24 at 14:16 -0800, Pravin B Shelar wrote:
>> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
>> ---
>> Fixed according to comments from Jesse and Eric.
>> - Factored a MAC layer handler out of skb_gso_segment().
>> - Eliminated copy operation from gre_gso_segment().
>> - Refresh header pointer after pskb_may_pull().
>
> Seems nice !
>
>> + if (skb_is_gso(skb)) {
>> + err = skb_unclone(skb, GFP_ATOMIC);
>> + if (unlikely(err))
>> + goto error;
>> + skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
>> + return skb;
>> + } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> + /* Pages aren't locked and could change at any time.
>> + * If this happens after we compute the checksum, the
>> + * checksum will be wrong. We linearize now to avoid
>> + * this problem.
>> + */
>> + if (skb_is_nonlinear(skb)) {
>> + err = __skb_linearize(skb);
>> + if (unlikely(err))
>> + goto error;
>> + }
>> +
>> + err = skb_checksum_help(skb);
>> + if (unlikely(err))
>> + goto error;
>> + }
>> +
>
> I really don't understand why you put chunk this in this patch.
>
> Packet being GSO or not, the underlying problem still remains.
>
> This must be addressed separately and at a different layer.
>
> (in skb_checksum_help() most probably)
>
> If the packet is GSO and we compute checksum in software,
> then we also have to copy all frags that could potentially
> be overwritten.
>
I think this patch does fix csum issue without causing any performance
regression. So this patch shld be enough to solve GRE-GSO issue. Once
you have fix, this code can be optimized even more.
>
>> + skb->ip_summed = CHECKSUM_NONE;
>> +
>> + return skb;
>> +
>> +error:
>> + kfree_skb(skb);
>> + return ERR_PTR(err);
>> +}
>> +
>> static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
>> {
>> struct ip_tunnel *tunnel = netdev_priv(dev);
>> @@ -751,10 +787,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
>> __be32 dst;
>> int mtu;
>> u8 ttl;
>> -
>> - if (skb->ip_summed == CHECKSUM_PARTIAL &&
>> - skb_checksum_help(skb))
>> - goto tx_error;
>> + int pkt_len;
>> + struct pcpu_tstats *tstats;
>> + int err;
>>
>> if (dev->type == ARPHRD_ETHER)
>> IPCB(skb)->flags = 0;
>> @@ -852,13 +887,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
>>
>> if (skb->protocol == htons(ETH_P_IP)) {
>> df |= (old_iph->frag_off&htons(IP_DF));
>> -
>> - if ((old_iph->frag_off&htons(IP_DF)) &&
>> - mtu < ntohs(old_iph->tot_len)) {
>> - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
>> - ip_rt_put(rt);
>> - goto tx_error;
>> - }
>
> Not clear why this chunk can be safely removed, even for non GSO
> packet ?
>
This actually does not work specially for TAP devices since ICMP
response won't work because the tunnel endpoint is not part of that IP
network.
This was discussed in VXLAN patch thread.
(http://markmail.org/message/xmqmvdh4noljfq2n).
But I agree we shld keep it for for non tap GRE and non-gso packets.
^ permalink raw reply
* Re: BUG: unable to handle kernel paging request at 0000000000609920 in networking code on 3.2.23.
From: Jan Engelhardt @ 2013-01-25 0:36 UTC (permalink / raw)
To: Florian Westphal; +Cc: Rafal Kupka, netdev, netfilter-devel
In-Reply-To: <20130124230850.GI8541@breakpoint.cc>
On Friday 2013-01-25 00:08, Florian Westphal wrote:
>@@ -35,10 +35,18 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
> {
> unsigned int optl, i, j;
> struct tcphdr *tcph;
>+ struct tcphdr _tcph;
> u_int16_t n, o;
> u_int8_t *opt;
>
>- if (!skb_make_writable(skb, skb->len))
>+ if (skb->len < minlen)
>+ return XT_CONTINUE;
>+
>+ tcph = skb_header_pointer(skb, tcphoff, sizeof(_tcph), &_tcph);
>+ if (!tcph)
>+ return XT_CONTINUE; /* no options -> nothing to do */
To the best of my analysis, the "no options" comment is incorrect here,
because you are not even looking at the options so far, but only tcph.
The prose should probably be something like:
if (iph->frag_off & htons(IP_OFFSET)) != 0)
/* not the first fragment - lost case */
return XT_CONTINUE;
if (iph->len < iph->ihl * 4 + sizeof(_tcph))
/* fragment boundary within tcphdr */
return XT_CONTINUE;
tcph = skb_header_pointer(skb, tcphoff, sizeof(_tcph), &_tcph);
if (tcph == NULL)
/* packet way too short for some reason
(should not occur since we tested for fragment
boundary) */
return NF_DROP;
if (tcph->doff * 4 - sizeof(_tcph) == 0)
/* no options */
return XT_CONTINUE;
if (iph->len < iph->ihl * 4 + sizeof(_tcph) + tcphoff))
/* fragment boundary within tcpoptions */
return XT_CONTINUE;
skb_make_writable...
^ permalink raw reply
* Re: [PATCH 1/2] net: Add skb_unclone() helper function.
From: Eric Dumazet @ 2013-01-25 1:13 UTC (permalink / raw)
To: Pravin B Shelar; +Cc: netdev, jesse
In-Reply-To: <1359065787-1763-1-git-send-email-pshelar@nicira.com>
On Thu, 2013-01-24 at 14:16 -0800, Pravin B Shelar wrote:
> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
>
> /**
> + * skb_unclone - creates separate copy if skb is cloned.
> + */
A proper kernel doc comment is not really needed, or must be complete
* @skb: ...
* @pri: ...
> +static inline bool skb_unclone(struct sk_buff *skb, gfp_t pri)
> +{
> + might_sleep_if(pri & __GFP_WAIT);
> +
> + if (skb_cloned(skb))
> + return pskb_expand_head(skb, 0, 0, pri);
> +
> + return 0;
return false;
> +}
> +
^ permalink raw reply
* Re: [PATCH 2/2] v2 GRE: Add segmentation offload for GRE
From: Michał Mirosław @ 2013-01-25 1:14 UTC (permalink / raw)
To: Pravin B Shelar; +Cc: netdev, jesse, eric.dumazet
In-Reply-To: <1359065793-1796-1-git-send-email-pshelar@nicira.com>
2013/1/24 Pravin B Shelar <pshelar@nicira.com>:
[...]
> @@ -1374,6 +1421,10 @@ static int ipgre_tunnel_init(struct net_device *dev)
> return err;
> }
>
> + if (!(tunnel->parms.o_flags & GRE_SEQ)) {
> + dev->features |= NETIF_F_GSO_SOFTWARE;
> + dev->hw_features |= NETIF_F_GSO_SOFTWARE;
> + }
> return 0;
> }
>
Can o_flags change after tunnel creation? If so, NETIF_F_GSO_SOFTWARE
should be set in dev->hw_features always, and it should be forced zero
in ndo_fix_features when GRE_SEQ is set. ipgre_netlink_parms() should
call netdev_update_features() when o_flags changes.
> @@ -1564,6 +1615,10 @@ static int ipgre_tap_init(struct net_device *dev)
> if (!dev->tstats)
> return -ENOMEM;
>
> + if (!(tunnel->parms.o_flags & GRE_SEQ)) {
> + dev->features |= NETIF_F_GSO_SOFTWARE;
> + dev->hw_features |= NETIF_F_GSO_SOFTWARE;
> + }
> return 0;
> }
>
Same here.
Best Regards,
Michał Mirosław
^ permalink raw reply
* Re: [PATCH 1/2] net: Add skb_unclone() helper function.
From: Michał Mirosław @ 2013-01-25 1:21 UTC (permalink / raw)
To: Pravin B Shelar; +Cc: netdev, jesse, eric.dumazet
In-Reply-To: <1359065787-1763-1-git-send-email-pshelar@nicira.com>
2013/1/24 Pravin B Shelar <pshelar@nicira.com>:
[...]
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -798,6 +798,19 @@ static inline int skb_cloned(const struct sk_buff *skb)
> }
>
> /**
> + * skb_unclone - creates separate copy if skb is cloned.
> + */
> +static inline bool skb_unclone(struct sk_buff *skb, gfp_t pri)
> +{
> + might_sleep_if(pri & __GFP_WAIT);
> +
> + if (skb_cloned(skb))
> + return pskb_expand_head(skb, 0, 0, pri);
> +
> + return 0;
> +}
This should return int. pskb_expand_head() returns 0 or -ENOMEM.
[...]
> diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
> index ddee0a0..c1f00ef 100644
> --- a/net/ipv4/xfrm4_mode_tunnel.c
> +++ b/net/ipv4/xfrm4_mode_tunnel.c
> @@ -142,8 +142,7 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
> for_each_input_rcu(rcv_notify_handlers, handler)
> handler->handler(skb);
>
> - if (skb_cloned(skb) &&
> - (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
> + if (skb_unclone(skb, GFP_ATOMIC))
> goto out;
And here return -ENOMEM is replaced with return -EINVAL because of this.
Best Regards,
Michał Mirosław
^ permalink raw reply
* [PATCH v3 1/1 net-next] net: fec: add napi support to improve proformance
From: Frank Li @ 2013-01-25 1:29 UTC (permalink / raw)
To: lznuaa, shawn.guo, B38611, davem, linux-arm-kernel, netdev
Cc: s.hauer, Frank Li
Add napi support
Before this patch
iperf -s -i 1
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 10.192.242.153 port 5001 connected with 10.192.242.138 port 50004
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 41.2 MBytes 345 Mbits/sec
[ 4] 1.0- 2.0 sec 43.7 MBytes 367 Mbits/sec
[ 4] 2.0- 3.0 sec 42.8 MBytes 359 Mbits/sec
[ 4] 3.0- 4.0 sec 43.7 MBytes 367 Mbits/sec
[ 4] 4.0- 5.0 sec 42.7 MBytes 359 Mbits/sec
[ 4] 5.0- 6.0 sec 43.8 MBytes 367 Mbits/sec
[ 4] 6.0- 7.0 sec 43.0 MBytes 361 Mbits/sec
After this patch
[ 4] 2.0- 3.0 sec 51.6 MBytes 433 Mbits/sec
[ 4] 3.0- 4.0 sec 51.8 MBytes 435 Mbits/sec
[ 4] 4.0- 5.0 sec 52.2 MBytes 438 Mbits/sec
[ 4] 5.0- 6.0 sec 52.1 MBytes 437 Mbits/sec
[ 4] 6.0- 7.0 sec 52.1 MBytes 437 Mbits/sec
[ 4] 7.0- 8.0 sec 52.3 MBytes 439 Mbits/sec
Signed-off-by: Frank Li <Frank.Li@freescale.com>
Signed-off-by: Fugang Duan <B38611@freescale.com>
---
Change from v2 to v3
* replace fec_enet_rx_int_is_enabled with fec_enet_rx_int_enable
* replace spin_lock_saveirq with spin_lock in irq handle
Change from v1 to v2
* Remove use_napi and napi_weight config. Support NAPI only.
* using napi_gro_receive replace netif_rx
drivers/net/ethernet/freescale/fec.c | 55 +++++++++++++++++++++++++++++-----
drivers/net/ethernet/freescale/fec.h | 2 +
2 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index f52ba33..1d9e019 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -67,6 +67,7 @@
#endif
#define DRIVER_NAME "fec"
+#define FEC_NAPI_WEIGHT 64
/* Pause frame feild and FIFO threshold */
#define FEC_ENET_FCE (1 << 5)
@@ -565,6 +566,20 @@ fec_timeout(struct net_device *ndev)
}
static void
+fec_enet_rx_int_enable(struct net_device *ndev, bool enabled)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ uint int_events;
+
+ int_events = readl(fep->hwp + FEC_IMASK);
+ if (enabled)
+ int_events |= FEC_ENET_RXF;
+ else
+ int_events &= ~FEC_ENET_RXF;
+ writel(int_events, fep->hwp + FEC_IMASK);
+}
+
+static void
fec_enet_tx(struct net_device *ndev)
{
struct fec_enet_private *fep;
@@ -656,8 +671,8 @@ fec_enet_tx(struct net_device *ndev)
* not been given to the system, we just set the empty indicator,
* effectively tossing the packet.
*/
-static void
-fec_enet_rx(struct net_device *ndev)
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
@@ -667,13 +682,12 @@ fec_enet_rx(struct net_device *ndev)
struct sk_buff *skb;
ushort pkt_len;
__u8 *data;
+ int pkt_received = 0;
#ifdef CONFIG_M532x
flush_cache_all();
#endif
- spin_lock(&fep->hw_lock);
-
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
@@ -681,6 +695,10 @@ fec_enet_rx(struct net_device *ndev)
while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+ if (pkt_received >= budget)
+ break;
+ pkt_received++;
+
/* Since we have allocated space to hold a complete frame,
* the last indicator should be set.
*/
@@ -762,7 +780,7 @@ fec_enet_rx(struct net_device *ndev)
}
if (!skb_defer_rx_timestamp(skb))
- netif_rx(skb);
+ napi_gro_receive(&fep->napi, skb);
}
bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -796,7 +814,7 @@ rx_processing_done:
}
fep->cur_rx = bdp;
- spin_unlock(&fep->hw_lock);
+ return pkt_received;
}
static irqreturn_t
@@ -813,7 +831,14 @@ fec_enet_interrupt(int irq, void *dev_id)
if (int_events & FEC_ENET_RXF) {
ret = IRQ_HANDLED;
- fec_enet_rx(ndev);
+
+ spin_lock(&fep->hw_lock);
+ /* Disable the RX interrupt */
+ if (napi_schedule_prep(&fep->napi)) {
+ fec_enet_rx_int_enable(ndev, false);
+ __napi_schedule(&fep->napi);
+ }
+ spin_unlock(&fep->hw_lock);
}
/* Transmit OK, or non-fatal error. Update the buffer
@@ -834,7 +859,16 @@ fec_enet_interrupt(int irq, void *dev_id)
return ret;
}
-
+static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ int pkgs = fec_enet_rx(ndev, budget);
+ if (pkgs < budget) {
+ napi_complete(napi);
+ fec_enet_rx_int_enable(ndev, true);
+ }
+ return pkgs;
+}
/* ------------------------------------------------------------------------- */
static void fec_get_mac(struct net_device *ndev)
@@ -1392,6 +1426,8 @@ fec_enet_open(struct net_device *ndev)
struct fec_enet_private *fep = netdev_priv(ndev);
int ret;
+ napi_enable(&fep->napi);
+
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
@@ -1604,6 +1640,9 @@ static int fec_enet_init(struct net_device *ndev)
ndev->netdev_ops = &fec_netdev_ops;
ndev->ethtool_ops = &fec_enet_ethtool_ops;
+ fec_enet_rx_int_enable(ndev, false);
+ netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+
/* Initialize the receive buffer descriptors. */
bdp = fep->rx_bd_base;
for (i = 0; i < RX_RING_SIZE; i++) {
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 2ebedaf..01579b8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -249,6 +249,8 @@ struct fec_enet_private {
int bufdesc_ex;
int pause_flag;
+ struct napi_struct napi;
+
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
unsigned long last_overflow_check;
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 2/2] v2 GRE: Add segmentation offload for GRE
From: Eric Dumazet @ 2013-01-25 1:34 UTC (permalink / raw)
To: Pravin Shelar; +Cc: netdev, jesse
In-Reply-To: <CALnjE+rbqCgRwxr1TtFH92vKSJoTRhBP50f+jQmgWB9LanQhYw@mail.gmail.com>
On Thu, 2013-01-24 at 16:14 -0800, Pravin Shelar wrote:
> I think this patch does fix csum issue without causing any performance
> regression. So this patch shld be enough to solve GRE-GSO issue. Once
> you have fix, this code can be optimized even more.
It adds the extra copy, since you assume no SG capability so
skb_segment() _does_ a copy.
As the checksum is needed, its true the copy is almost not noticed,
but one day NIC will be able to perform the checksum for us.
(Maybe its already the case for some of them)
I would first fix the checksum issue in a generic way, then
apply this patch on top of the fix, so that we can use SG and avoid
the extra copy for the typical tcp_sendmsg()
It seems you focus on the TAP use case only, seeing you removed
code that doesn't work for TAP but do work for regular locally
terminated flows.
You did a lot of implementation choices and none of them
are described in a changelog, making future work a bit hard.
^ permalink raw reply
* Re: [patch net-next V2] bond: have random dev address by default instead of zeroes
From: Jay Vosburgh @ 2013-01-25 1:35 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, andy, stephen, psimerda, dcbw
In-Reply-To: <1359057684-6732-1-git-send-email-jiri@resnulli.us>
Jiri Pirko <jiri@resnulli.us> wrote:
>Makes more sense to have randomly generated address by default than to
>have all zeroes. It also allows user to for example put the bond into
>bridge without need to have any slaves in it.
>
>Also note that this changes only behaviour of bonds with no slaves. Once
>the first slave device is enslaved, its address will be used (no change
>here).
>
>Also, fix dev_assign_type values on the way.
>
>Reported-by: Pavel Šimerda <psimerda@redhat.com>
>Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Maybe I don't see it, but this feels like a bit of a hack just
to get a bond with no slaves into a bridge. Am I missing something
here? I just have this feeling that down the road I'm going to get
questions as to why the bond gets a MAC, and then, poof, it vanishes
when a slave is added. What's the point of the MAC address if it's only
used to fool the bridge code?
Also, when the bond's MAC changes from the random MAC to the
first slave's MAC, does a notifier call need to happen? There isn't one
now from the all zeroes to the first slave's, but that's from an invalid
MAC to a valid one. There is already a notifier when the bond goes back
to all zeroes, though.
-J
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
>
>v1->v2:
>- fixed assign value of bond_dev->addr_assign_type in bond_set_dev_addr()
>- added note to patch description
>
> drivers/net/bonding/bond_main.c | 28 ++++++++++++++++------------
> 1 file changed, 16 insertions(+), 12 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 564cf42..1d56ac9 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -1320,14 +1320,14 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
>
> /*---------------------------------- IOCTL ----------------------------------*/
>
>-static int bond_sethwaddr(struct net_device *bond_dev,
>- struct net_device *slave_dev)
>+static void bond_set_dev_addr(struct net_device *bond_dev,
>+ struct net_device *slave_dev)
> {
> pr_debug("bond_dev=%p\n", bond_dev);
> pr_debug("slave_dev=%p\n", slave_dev);
> pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
> memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
>- return 0;
>+ bond_dev->addr_assign_type = NET_ADDR_SET;
> }
>
> static netdev_features_t bond_fix_features(struct net_device *dev,
>@@ -1628,10 +1628,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
>
> /* If this is the first slave, then we need to set the master's hardware
> * address to be the same as the slave's. */
>- if (is_zero_ether_addr(bond->dev->dev_addr))
>- memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
>- slave_dev->addr_len);
>-
>+ if (bond->dev->addr_assign_type != NET_ADDR_SET)
>+ bond_set_dev_addr(bond->dev, slave_dev);
>
> new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
> if (!new_slave) {
>@@ -2049,11 +2047,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
> if (bond->slave_cnt == 0) {
> bond_set_carrier(bond);
>
>- /* if the last slave was removed, zero the mac address
>- * of the master so it will be set by the application
>- * to the mac address of the first slave
>+ /* If the last slave was removed, set random mac address
>+ * of the master so it will be set by bond_enslave()
>+ * to the mac address of the first slave.
> */
>- memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
>+ eth_hw_addr_random(bond_dev);
>
> if (bond_vlan_used(bond)) {
> pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
>@@ -3708,7 +3706,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
> break;
> case BOND_SETHWADDR_OLD:
> case SIOCBONDSETHWADDR:
>- res = bond_sethwaddr(bond_dev, slave_dev);
>+ bond_set_dev_addr(bond_dev, slave_dev);
>+ res = 0;
> break;
> case BOND_CHANGE_ACTIVE_OLD:
> case SIOCBONDCHANGEACTIVE:
>@@ -4858,6 +4857,11 @@ static int bond_init(struct net_device *bond_dev)
>
> bond_debug_register(bond);
>
>+ /* Ensure valid dev_addr */
>+ if (is_zero_ether_addr(bond_dev->dev_addr) &&
>+ bond_dev->addr_assign_type == NET_ADDR_PERM)
>+ eth_hw_addr_random(bond_dev);
>+
> __hw_addr_init(&bond->mc_list);
> return 0;
> }
>--
>1.8.1
>
^ permalink raw reply
* Re: [PATCH 1/2] net: Add skb_unclone() helper function.
From: Pravin Shelar @ 2013-01-25 1:36 UTC (permalink / raw)
To: Michał Mirosław; +Cc: netdev, jesse, eric.dumazet
In-Reply-To: <CAHXqBF+uHoGRXP3HdiL2Zm9RUhT-+7RsrRhAYZyEg-FjzH2-eQ@mail.gmail.com>
On Thu, Jan 24, 2013 at 5:21 PM, Michał Mirosław <mirqus@gmail.com> wrote:
> 2013/1/24 Pravin B Shelar <pshelar@nicira.com>:
> [...]
>> --- a/include/linux/skbuff.h
>> +++ b/include/linux/skbuff.h
>> @@ -798,6 +798,19 @@ static inline int skb_cloned(const struct sk_buff *skb)
>> }
>>
>> /**
>> + * skb_unclone - creates separate copy if skb is cloned.
>> + */
>> +static inline bool skb_unclone(struct sk_buff *skb, gfp_t pri)
>> +{
>> + might_sleep_if(pri & __GFP_WAIT);
>> +
>> + if (skb_cloned(skb))
>> + return pskb_expand_head(skb, 0, 0, pri);
>> +
>> + return 0;
>> +}
>
> This should return int. pskb_expand_head() returns 0 or -ENOMEM.
>
> [...]
>> diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
>> index ddee0a0..c1f00ef 100644
>> --- a/net/ipv4/xfrm4_mode_tunnel.c
>> +++ b/net/ipv4/xfrm4_mode_tunnel.c
>> @@ -142,8 +142,7 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
>> for_each_input_rcu(rcv_notify_handlers, handler)
>> handler->handler(skb);
>>
>> - if (skb_cloned(skb) &&
>> - (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
>> + if (skb_unclone(skb, GFP_ATOMIC))
>> goto out;
>
> And here return -ENOMEM is replaced with return -EINVAL because of this.
>
ok, I will change skb_unclone return to int.
Thanks.
^ permalink raw reply
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