diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-08 01:00:49 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-08 19:58:35 (GMT) |
commit | 47d2261a3fa71cde24263559a4219a25e50d8c89 (patch) | |
tree | 28774d5b330ccf1b777a3af222d8356918328013 /net/core | |
parent | fb7f27080adc65cd5f341bdf56a1d0c14f316c1b (diff) | |
parent | 5fb9d37f27351e42f002e372074249f92cbdf815 (diff) | |
download | linux-fsl-qoriq-47d2261a3fa71cde24263559a4219a25e50d8c89.tar.xz |
Merge branch 'merge' into sdk-v1.6.x
This reverts v3.13-rc3+ (78fd82238d0e5716) to v3.12, except for
commits which I noticed which appear relevant to the SDK.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Conflicts:
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/e500mc.c
arch/powerpc/sysdev/fsl_soc.h
drivers/Kconfig
drivers/cpufreq/ppc-corenet-cpufreq.c
drivers/dma/fsldma.c
drivers/dma/s3c24xx-dma.c
drivers/misc/Makefile
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mtd/devices/m25p80.c
drivers/net/ethernet/freescale/gianfar.h
drivers/platform/Kconfig
drivers/platform/Makefile
drivers/spi/spi-fsl-espi.c
include/crypto/algapi.h
include/linux/netdev_features.h
include/linux/skbuff.h
include/net/ip.h
net/core/ethtool.c
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/datagram.c | 2 | ||||
-rw-r--r-- | net/core/dev.c | 570 | ||||
-rw-r--r-- | net/core/dev_addr_lists.c | 4 | ||||
-rw-r--r-- | net/core/drop_monitor.c | 15 | ||||
-rw-r--r-- | net/core/ethtool.c | 3 | ||||
-rw-r--r-- | net/core/fib_rules.c | 3 | ||||
-rw-r--r-- | net/core/flow_dissector.c | 81 | ||||
-rw-r--r-- | net/core/iovec.c | 5 | ||||
-rw-r--r-- | net/core/neighbour.c | 2 | ||||
-rw-r--r-- | net/core/net-sysfs.c | 16 | ||||
-rw-r--r-- | net/core/netpoll.c | 31 | ||||
-rw-r--r-- | net/core/netprio_cgroup.c | 3 | ||||
-rw-r--r-- | net/core/pktgen.c | 7 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 12 | ||||
-rw-r--r-- | net/core/secure_seq.c | 16 | ||||
-rw-r--r-- | net/core/skbuff.c | 219 | ||||
-rw-r--r-- | net/core/sock.c | 45 | ||||
-rw-r--r-- | net/core/utils.c | 49 |
18 files changed, 348 insertions, 735 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index a16ed7b..af814e7 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -577,7 +577,7 @@ EXPORT_SYMBOL(skb_copy_datagram_from_iovec); /** * zerocopy_sg_from_iovec - Build a zerocopy datagram from an iovec * @skb: buffer to copy - * @from: io vector to copy from + * @from: io vector to copy to * @offset: offset in the io vector to start copying from * @count: amount of vectors to copy to buffer from * diff --git a/net/core/dev.c b/net/core/dev.c index 4ac5786..22719ed 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -131,7 +131,6 @@ #include <linux/static_key.h> #include <linux/hashtable.h> #include <linux/vmalloc.h> -#include <linux/if_macvlan.h> #include "net-sysfs.h" @@ -1204,7 +1203,7 @@ void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { call_netdevice_notifiers(NETDEV_CHANGE, dev); - rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } EXPORT_SYMBOL(netdev_state_change); @@ -1294,7 +1293,7 @@ int dev_open(struct net_device *dev) if (ret < 0) return ret; - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); call_netdevice_notifiers(NETDEV_UP, dev); return ret; @@ -1308,7 +1307,7 @@ static int __dev_close_many(struct list_head *head) ASSERT_RTNL(); might_sleep(); - list_for_each_entry(dev, head, close_list) { + list_for_each_entry(dev, head, unreg_list) { call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); clear_bit(__LINK_STATE_START, &dev->state); @@ -1324,7 +1323,7 @@ static int __dev_close_many(struct list_head *head) dev_deactivate_many(head); - list_for_each_entry(dev, head, close_list) { + list_for_each_entry(dev, head, unreg_list) { const struct net_device_ops *ops = dev->netdev_ops; /* @@ -1352,7 +1351,7 @@ static int __dev_close(struct net_device *dev) /* Temporarily disable netpoll until the interface is down */ netpoll_rx_disable(dev); - list_add(&dev->close_list, &single); + list_add(&dev->unreg_list, &single); retval = __dev_close_many(&single); list_del(&single); @@ -1363,20 +1362,21 @@ static int __dev_close(struct net_device *dev) static int dev_close_many(struct list_head *head) { struct net_device *dev, *tmp; + LIST_HEAD(tmp_list); - /* Remove the devices that don't need to be closed */ - list_for_each_entry_safe(dev, tmp, head, close_list) + list_for_each_entry_safe(dev, tmp, head, unreg_list) if (!(dev->flags & IFF_UP)) - list_del_init(&dev->close_list); + list_move(&dev->unreg_list, &tmp_list); __dev_close_many(head); - list_for_each_entry_safe(dev, tmp, head, close_list) { - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); + list_for_each_entry(dev, head, unreg_list) { + rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); call_netdevice_notifiers(NETDEV_DOWN, dev); - list_del_init(&dev->close_list); } + /* rollback_registered_many needs the complete original list */ + list_splice(&tmp_list, head); return 0; } @@ -1397,7 +1397,7 @@ int dev_close(struct net_device *dev) /* Block netpoll rx while the interface is going down */ netpoll_rx_disable(dev); - list_add(&dev->close_list, &single); + list_add(&dev->unreg_list, &single); dev_close_many(&single); list_del(&single); @@ -1425,10 +1425,6 @@ void dev_disable_lro(struct net_device *dev) if (is_vlan_dev(dev)) dev = vlan_dev_real_dev(dev); - /* the same for macvlan devices */ - if (netif_is_macvlan(dev)) - dev = macvlan_dev_real_dev(dev); - dev->wanted_features &= ~NETIF_F_LRO; netdev_update_features(dev); @@ -1695,9 +1691,13 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) kfree_skb(skb); return NET_RX_DROP; } + skb->protocol = eth_type_trans(skb, dev); + /* eth_type_trans() can set pkt_type. + * call skb_scrub_packet() after it to clear pkt_type _after_ calling + * eth_type_trans(). + */ skb_scrub_packet(skb, true); - skb->protocol = eth_type_trans(skb, dev); return netif_rx(skb); } @@ -2378,8 +2378,6 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, } SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); - SKB_GSO_CB(skb)->encap_level = 0; - skb_reset_mac_header(skb); skb_reset_mac_len(skb); @@ -2550,7 +2548,7 @@ EXPORT_SYMBOL(asf_qos_fn_register); #endif int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, - struct netdev_queue *txq, void *accel_priv) + struct netdev_queue *txq) { const struct net_device_ops *ops = dev->netdev_ops; int rc = NETDEV_TX_OK; @@ -2616,13 +2614,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, dev_queue_xmit_nit(skb, dev); skb_len = skb->len; - if (accel_priv) - rc = ops->ndo_dfwd_start_xmit(skb, dev, accel_priv); - else - rc = ops->ndo_start_xmit(skb, dev); - + rc = ops->ndo_start_xmit(skb, dev); trace_net_dev_xmit(skb, rc, dev, skb_len); - if (rc == NETDEV_TX_OK && txq) + if (rc == NETDEV_TX_OK) txq_trans_update(txq); return rc; } @@ -2638,10 +2632,7 @@ gso: dev_queue_xmit_nit(nskb, dev); skb_len = nskb->len; - if (accel_priv) - rc = ops->ndo_dfwd_start_xmit(nskb, dev, accel_priv); - else - rc = ops->ndo_start_xmit(nskb, dev); + rc = ops->ndo_start_xmit(nskb, dev); trace_net_dev_xmit(nskb, rc, dev, skb_len); if (unlikely(rc != NETDEV_TX_OK)) { if (rc & ~NETDEV_TX_MASK) @@ -2666,7 +2657,6 @@ out_kfree_skb: out: return rc; } -EXPORT_SYMBOL_GPL(dev_hard_start_xmit); static void qdisc_pkt_len_init(struct sk_buff *skb) { @@ -2882,7 +2872,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (!netif_xmit_stopped(txq)) { __this_cpu_inc(xmit_recursion); - rc = dev_hard_start_xmit(skb, dev, txq, NULL); + rc = dev_hard_start_xmit(skb, dev, txq); __this_cpu_dec(xmit_recursion); if (dev_xmit_complete(rc)) { HARD_TX_UNLOCK(dev, txq); @@ -4403,40 +4393,42 @@ struct netdev_adjacent { /* upper master flag, there can only be one master device per list */ bool master; + /* indicates that this dev is our first-level lower/upper device */ + bool neighbour; + /* counter for the number of times this device was added to us */ u16 ref_nr; - /* private field for the users */ - void *private; - struct list_head list; struct rcu_head rcu; }; -static struct netdev_adjacent *__netdev_find_adj_rcu(struct net_device *dev, - struct net_device *adj_dev, - struct list_head *adj_list) +static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, + struct net_device *adj_dev, + bool upper) { struct netdev_adjacent *adj; + struct list_head *dev_list; - list_for_each_entry_rcu(adj, adj_list, list) { + dev_list = upper ? &dev->upper_dev_list : &dev->lower_dev_list; + + list_for_each_entry(adj, dev_list, list) { if (adj->dev == adj_dev) return adj; } return NULL; } -static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, - struct net_device *adj_dev, - struct list_head *adj_list) +static inline struct netdev_adjacent *__netdev_find_upper(struct net_device *dev, + struct net_device *udev) { - struct netdev_adjacent *adj; + return __netdev_find_adj(dev, udev, true); +} - list_for_each_entry(adj, adj_list, list) { - if (adj->dev == adj_dev) - return adj; - } - return NULL; +static inline struct netdev_adjacent *__netdev_find_lower(struct net_device *dev, + struct net_device *ldev) +{ + return __netdev_find_adj(dev, ldev, false); } /** @@ -4453,7 +4445,7 @@ bool netdev_has_upper_dev(struct net_device *dev, { ASSERT_RTNL(); - return __netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper); + return __netdev_find_upper(dev, upper_dev); } EXPORT_SYMBOL(netdev_has_upper_dev); @@ -4468,7 +4460,7 @@ bool netdev_has_any_upper_dev(struct net_device *dev) { ASSERT_RTNL(); - return !list_empty(&dev->all_adj_list.upper); + return !list_empty(&dev->upper_dev_list); } EXPORT_SYMBOL(netdev_has_any_upper_dev); @@ -4485,10 +4477,10 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) ASSERT_RTNL(); - if (list_empty(&dev->adj_list.upper)) + if (list_empty(&dev->upper_dev_list)) return NULL; - upper = list_first_entry(&dev->adj_list.upper, + upper = list_first_entry(&dev->upper_dev_list, struct netdev_adjacent, list); if (likely(upper->master)) return upper->dev; @@ -4496,26 +4488,15 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) } EXPORT_SYMBOL(netdev_master_upper_dev_get); -void *netdev_adjacent_get_private(struct list_head *adj_list) -{ - struct netdev_adjacent *adj; - - adj = list_entry(adj_list, struct netdev_adjacent, list); - - return adj->private; -} -EXPORT_SYMBOL(netdev_adjacent_get_private); - -/** - * netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list +/* netdev_upper_get_next_dev_rcu - Get the next dev from upper list * @dev: device * @iter: list_head ** of the current position * * Gets the next device from the dev's upper list, starting from iter * position. The caller must hold RCU read lock. */ -struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, - struct list_head **iter) +struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + struct list_head **iter) { struct netdev_adjacent *upper; @@ -4523,71 +4504,14 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - if (&upper->list == &dev->all_adj_list.upper) + if (&upper->list == &dev->upper_dev_list) return NULL; *iter = &upper->list; return upper->dev; } -EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu); - -/** - * netdev_lower_get_next_private - Get the next ->private from the - * lower neighbour list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent->private from the dev's lower neighbour - * list, starting from iter position. The caller must hold either hold the - * RTNL lock or its own locking that guarantees that the neighbour lower - * list will remain unchainged. - */ -void *netdev_lower_get_next_private(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *lower; - - lower = list_entry(*iter, struct netdev_adjacent, list); - - if (&lower->list == &dev->adj_list.lower) - return NULL; - - if (iter) - *iter = lower->list.next; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_get_next_private); - -/** - * netdev_lower_get_next_private_rcu - Get the next ->private from the - * lower neighbour list, RCU - * variant - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent->private from the dev's lower neighbour - * list, starting from iter position. The caller must hold RCU read lock. - */ -void *netdev_lower_get_next_private_rcu(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *lower; - - WARN_ON_ONCE(!rcu_read_lock_held()); - - lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - - if (&lower->list == &dev->adj_list.lower) - return NULL; - - if (iter) - *iter = &lower->list; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); +EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); /** * netdev_master_upper_dev_get_rcu - Get master upper device @@ -4600,7 +4524,7 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev) { struct netdev_adjacent *upper; - upper = list_first_or_null_rcu(&dev->adj_list.upper, + upper = list_first_or_null_rcu(&dev->upper_dev_list, struct netdev_adjacent, list); if (upper && likely(upper->master)) return upper->dev; @@ -4610,16 +4534,15 @@ EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu); static int __netdev_adjacent_dev_insert(struct net_device *dev, struct net_device *adj_dev, - struct list_head *dev_list, - void *private, bool master) + bool neighbour, bool master, + bool upper) { struct netdev_adjacent *adj; - char linkname[IFNAMSIZ+7]; - int ret; - adj = __netdev_find_adj(dev, adj_dev, dev_list); + adj = __netdev_find_adj(dev, adj_dev, upper); if (adj) { + BUG_ON(neighbour); adj->ref_nr++; return 0; } @@ -4630,179 +4553,124 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, adj->dev = adj_dev; adj->master = master; + adj->neighbour = neighbour; adj->ref_nr = 1; - adj->private = private; - dev_hold(adj_dev); - pr_debug("dev_hold for %s, because of link added from %s to %s\n", - adj_dev->name, dev->name, adj_dev->name); + dev_hold(adj_dev); + pr_debug("dev_hold for %s, because of %s link added from %s to %s\n", + adj_dev->name, upper ? "upper" : "lower", dev->name, + adj_dev->name); - if (dev_list == &dev->adj_list.lower) { - sprintf(linkname, "lower_%s", adj_dev->name); - ret = sysfs_create_link(&(dev->dev.kobj), - &(adj_dev->dev.kobj), linkname); - if (ret) - goto free_adj; - } else if (dev_list == &dev->adj_list.upper) { - sprintf(linkname, "upper_%s", adj_dev->name); - ret = sysfs_create_link(&(dev->dev.kobj), - &(adj_dev->dev.kobj), linkname); - if (ret) - goto free_adj; + if (!upper) { + list_add_tail_rcu(&adj->list, &dev->lower_dev_list); + return 0; } - /* Ensure that master link is always the first item in list. */ - if (master) { - ret = sysfs_create_link(&(dev->dev.kobj), - &(adj_dev->dev.kobj), "master"); - if (ret) - goto remove_symlinks; - - list_add_rcu(&adj->list, dev_list); - } else { - list_add_tail_rcu(&adj->list, dev_list); - } + /* Ensure that master upper link is always the first item in list. */ + if (master) + list_add_rcu(&adj->list, &dev->upper_dev_list); + else + list_add_tail_rcu(&adj->list, &dev->upper_dev_list); return 0; +} -remove_symlinks: - if (dev_list == &dev->adj_list.lower) { - sprintf(linkname, "lower_%s", adj_dev->name); - sysfs_remove_link(&(dev->dev.kobj), linkname); - } else if (dev_list == &dev->adj_list.upper) { - sprintf(linkname, "upper_%s", adj_dev->name); - sysfs_remove_link(&(dev->dev.kobj), linkname); - } - -free_adj: - kfree(adj); - dev_put(adj_dev); +static inline int __netdev_upper_dev_insert(struct net_device *dev, + struct net_device *udev, + bool master, bool neighbour) +{ + return __netdev_adjacent_dev_insert(dev, udev, neighbour, master, + true); +} - return ret; +static inline int __netdev_lower_dev_insert(struct net_device *dev, + struct net_device *ldev, + bool neighbour) +{ + return __netdev_adjacent_dev_insert(dev, ldev, neighbour, false, + false); } void __netdev_adjacent_dev_remove(struct net_device *dev, - struct net_device *adj_dev, - struct list_head *dev_list) + struct net_device *adj_dev, bool upper) { struct netdev_adjacent *adj; - char linkname[IFNAMSIZ+7]; - adj = __netdev_find_adj(dev, adj_dev, dev_list); + if (upper) + adj = __netdev_find_upper(dev, adj_dev); + else + adj = __netdev_find_lower(dev, adj_dev); - if (!adj) { - pr_err("tried to remove device %s from %s\n", - dev->name, adj_dev->name); + if (!adj) BUG(); - } if (adj->ref_nr > 1) { - pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name, - adj->ref_nr-1); adj->ref_nr--; return; } - if (adj->master) - sysfs_remove_link(&(dev->dev.kobj), "master"); - - if (dev_list == &dev->adj_list.lower) { - sprintf(linkname, "lower_%s", adj_dev->name); - sysfs_remove_link(&(dev->dev.kobj), linkname); - } else if (dev_list == &dev->adj_list.upper) { - sprintf(linkname, "upper_%s", adj_dev->name); - sysfs_remove_link(&(dev->dev.kobj), linkname); - } - list_del_rcu(&adj->list); - pr_debug("dev_put for %s, because link removed from %s to %s\n", - adj_dev->name, dev->name, adj_dev->name); + pr_debug("dev_put for %s, because of %s link removed from %s to %s\n", + adj_dev->name, upper ? "upper" : "lower", dev->name, + adj_dev->name); dev_put(adj_dev); kfree_rcu(adj, rcu); } -int __netdev_adjacent_dev_link_lists(struct net_device *dev, - struct net_device *upper_dev, - struct list_head *up_list, - struct list_head *down_list, - void *private, bool master) +static inline void __netdev_upper_dev_remove(struct net_device *dev, + struct net_device *udev) +{ + return __netdev_adjacent_dev_remove(dev, udev, true); +} + +static inline void __netdev_lower_dev_remove(struct net_device *dev, + struct net_device *ldev) +{ + return __netdev_adjacent_dev_remove(dev, ldev, false); +} + +int __netdev_adjacent_dev_insert_link(struct net_device *dev, + struct net_device *upper_dev, + bool master, bool neighbour) { int ret; - ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private, - master); + ret = __netdev_upper_dev_insert(dev, upper_dev, master, neighbour); if (ret) return ret; - ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private, - false); + ret = __netdev_lower_dev_insert(upper_dev, dev, neighbour); if (ret) { - __netdev_adjacent_dev_remove(dev, upper_dev, up_list); + __netdev_upper_dev_remove(dev, upper_dev); return ret; } return 0; } -int __netdev_adjacent_dev_link(struct net_device *dev, - struct net_device *upper_dev) +static inline int __netdev_adjacent_dev_link(struct net_device *dev, + struct net_device *udev) { - return __netdev_adjacent_dev_link_lists(dev, upper_dev, - &dev->all_adj_list.upper, - &upper_dev->all_adj_list.lower, - NULL, false); + return __netdev_adjacent_dev_insert_link(dev, udev, false, false); } -void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, - struct net_device *upper_dev, - struct list_head *up_list, - struct list_head *down_list) +static inline int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, + struct net_device *udev, + bool master) { - __netdev_adjacent_dev_remove(dev, upper_dev, up_list); - __netdev_adjacent_dev_remove(upper_dev, dev, down_list); + return __netdev_adjacent_dev_insert_link(dev, udev, master, true); } void __netdev_adjacent_dev_unlink(struct net_device *dev, struct net_device *upper_dev) { - __netdev_adjacent_dev_unlink_lists(dev, upper_dev, - &dev->all_adj_list.upper, - &upper_dev->all_adj_list.lower); + __netdev_upper_dev_remove(dev, upper_dev); + __netdev_lower_dev_remove(upper_dev, dev); } -int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, - struct net_device *upper_dev, - void *private, bool master) -{ - int ret = __netdev_adjacent_dev_link(dev, upper_dev); - - if (ret) - return ret; - - ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, - &dev->adj_list.upper, - &upper_dev->adj_list.lower, - private, master); - if (ret) { - __netdev_adjacent_dev_unlink(dev, upper_dev); - return ret; - } - - return 0; -} - -void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, - struct net_device *upper_dev) -{ - __netdev_adjacent_dev_unlink(dev, upper_dev); - __netdev_adjacent_dev_unlink_lists(dev, upper_dev, - &dev->adj_list.upper, - &upper_dev->adj_list.lower); -} static int __netdev_upper_dev_link(struct net_device *dev, - struct net_device *upper_dev, bool master, - void *private) + struct net_device *upper_dev, bool master) { struct netdev_adjacent *i, *j, *to_i, *to_j; int ret = 0; @@ -4813,29 +4681,26 @@ static int __netdev_upper_dev_link(struct net_device *dev, return -EBUSY; /* To prevent loops, check if dev is not upper device to upper_dev. */ - if (__netdev_find_adj(upper_dev, dev, &upper_dev->all_adj_list.upper)) + if (__netdev_find_upper(upper_dev, dev)) return -EBUSY; - if (__netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper)) + if (__netdev_find_upper(dev, upper_dev)) return -EEXIST; if (master && netdev_master_upper_dev_get(dev)) return -EBUSY; - ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, private, - master); + ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, master); if (ret) return ret; /* Now that we linked these devs, make all the upper_dev's - * all_adj_list.upper visible to every dev's all_adj_list.lower an + * upper_dev_list visible to every dev's lower_dev_list and vice * versa, and don't forget the devices itself. All of these * links are non-neighbours. */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { - pr_debug("Interlinking %s with %s, non-neighbour\n", - i->dev->name, j->dev->name); + list_for_each_entry(i, &dev->lower_dev_list, list) { + list_for_each_entry(j, &upper_dev->upper_dev_list, list) { ret = __netdev_adjacent_dev_link(i->dev, j->dev); if (ret) goto rollback_mesh; @@ -4843,18 +4708,14 @@ static int __netdev_upper_dev_link(struct net_device *dev, } /* add dev to every upper_dev's upper device */ - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { - pr_debug("linking %s's upper device %s with %s\n", - upper_dev->name, i->dev->name, dev->name); + list_for_each_entry(i, &upper_dev->upper_dev_list, list) { ret = __netdev_adjacent_dev_link(dev, i->dev); if (ret) goto rollback_upper_mesh; } /* add upper_dev to every dev's lower device */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - pr_debug("linking %s's lower device %s with %s\n", dev->name, - i->dev->name, upper_dev->name); + list_for_each_entry(i, &dev->lower_dev_list, list) { ret = __netdev_adjacent_dev_link(i->dev, upper_dev); if (ret) goto rollback_lower_mesh; @@ -4865,7 +4726,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, rollback_lower_mesh: to_i = i; - list_for_each_entry(i, &dev->all_adj_list.lower, list) { + list_for_each_entry(i, &dev->lower_dev_list, list) { if (i == to_i) break; __netdev_adjacent_dev_unlink(i->dev, upper_dev); @@ -4875,7 +4736,7 @@ rollback_lower_mesh: rollback_upper_mesh: to_i = i; - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { + list_for_each_entry(i, &upper_dev->upper_dev_list, list) { if (i == to_i) break; __netdev_adjacent_dev_unlink(dev, i->dev); @@ -4886,8 +4747,8 @@ rollback_upper_mesh: rollback_mesh: to_i = i; to_j = j; - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { + list_for_each_entry(i, &dev->lower_dev_list, list) { + list_for_each_entry(j, &upper_dev->upper_dev_list, list) { if (i == to_i && j == to_j) break; __netdev_adjacent_dev_unlink(i->dev, j->dev); @@ -4896,7 +4757,7 @@ rollback_mesh: break; } - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); + __netdev_adjacent_dev_unlink(dev, upper_dev); return ret; } @@ -4914,7 +4775,7 @@ rollback_mesh: int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev) { - return __netdev_upper_dev_link(dev, upper_dev, false, NULL); + return __netdev_upper_dev_link(dev, upper_dev, false); } EXPORT_SYMBOL(netdev_upper_dev_link); @@ -4932,18 +4793,10 @@ EXPORT_SYMBOL(netdev_upper_dev_link); int netdev_master_upper_dev_link(struct net_device *dev, struct net_device *upper_dev) { - return __netdev_upper_dev_link(dev, upper_dev, true, NULL); + return __netdev_upper_dev_link(dev, upper_dev, true); } EXPORT_SYMBOL(netdev_master_upper_dev_link); -int netdev_master_upper_dev_link_private(struct net_device *dev, - struct net_device *upper_dev, - void *private) -{ - return __netdev_upper_dev_link(dev, upper_dev, true, private); -} -EXPORT_SYMBOL(netdev_master_upper_dev_link_private); - /** * netdev_upper_dev_unlink - Removes a link to upper device * @dev: device @@ -4958,68 +4811,38 @@ void netdev_upper_dev_unlink(struct net_device *dev, struct netdev_adjacent *i, *j; ASSERT_RTNL(); - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); + __netdev_adjacent_dev_unlink(dev, upper_dev); /* Here is the tricky part. We must remove all dev's lower * devices from all upper_dev's upper devices and vice * versa, to maintain the graph relationship. */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) + list_for_each_entry(i, &dev->lower_dev_list, list) + list_for_each_entry(j, &upper_dev->upper_dev_list, list) __netdev_adjacent_dev_unlink(i->dev, j->dev); /* remove also the devices itself from lower/upper device * list */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) + list_for_each_entry(i, &dev->lower_dev_list, list) __netdev_adjacent_dev_unlink(i->dev, upper_dev); - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) + list_for_each_entry(i, &upper_dev->upper_dev_list, list) __netdev_adjacent_dev_unlink(dev, i->dev); call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); } EXPORT_SYMBOL(netdev_upper_dev_unlink); -void *netdev_lower_dev_get_private_rcu(struct net_device *dev, - struct net_device *lower_dev) -{ - struct netdev_adjacent *lower; - - if (!lower_dev) - return NULL; - lower = __netdev_find_adj_rcu(dev, lower_dev, &dev->adj_list.lower); - if (!lower) - return NULL; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_dev_get_private_rcu); - -void *netdev_lower_dev_get_private(struct net_device *dev, - struct net_device *lower_dev) -{ - struct netdev_adjacent *lower; - - if (!lower_dev) - return NULL; - lower = __netdev_find_adj(dev, lower_dev, &dev->adj_list.lower); - if (!lower) - return NULL; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_dev_get_private); - static void dev_change_rx_flags(struct net_device *dev, int flags) { const struct net_device_ops *ops = dev->netdev_ops; - if (ops->ndo_change_rx_flags) + if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags) ops->ndo_change_rx_flags(dev, flags); } -static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) +static int __dev_set_promiscuity(struct net_device *dev, int inc) { unsigned int old_flags = dev->flags; kuid_t uid; @@ -5062,8 +4885,6 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) dev_change_rx_flags(dev, IFF_PROMISC); } - if (notify) - __dev_notify_flags(dev, old_flags, IFF_PROMISC); return 0; } @@ -5083,7 +4904,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc) unsigned int old_flags = dev->flags; int err; - err = __dev_set_promiscuity(dev, inc, true); + err = __dev_set_promiscuity(dev, inc); if (err < 0) return err; if (dev->flags != old_flags) @@ -5092,9 +4913,22 @@ int dev_set_promiscuity(struct net_device *dev, int inc) } EXPORT_SYMBOL(dev_set_promiscuity); -static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify) +/** + * dev_set_allmulti - update allmulti count on a device + * @dev: device + * @inc: modifier + * + * Add or remove reception of all multicast frames to a device. While the + * count in the device remains above zero the interface remains listening + * to all interfaces. Once it hits zero the device reverts back to normal + * filtering operation. A negative @inc value is used to drop the counter + * when releasing a resource needing all multicasts. + * Return 0 if successful or a negative errno code on error. + */ + +int dev_set_allmulti(struct net_device *dev, int inc) { - unsigned int old_flags = dev->flags, old_gflags = dev->gflags; + unsigned int old_flags = dev->flags; ASSERT_RTNL(); @@ -5117,30 +4951,9 @@ static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify) if (dev->flags ^ old_flags) { dev_change_rx_flags(dev, IFF_ALLMULTI); dev_set_rx_mode(dev); - if (notify) - __dev_notify_flags(dev, old_flags, - dev->gflags ^ old_gflags); } return 0; } - -/** - * dev_set_allmulti - update allmulti count on a device - * @dev: device - * @inc: modifier - * - * Add or remove reception of all multicast frames to a device. While the - * count in the device remains above zero the interface remains listening - * to all interfaces. Once it hits zero the device reverts back to normal - * filtering operation. A negative @inc value is used to drop the counter - * when releasing a resource needing all multicasts. - * Return 0 if successful or a negative errno code on error. - */ - -int dev_set_allmulti(struct net_device *dev, int inc) -{ - return __dev_set_allmulti(dev, inc, true); -} EXPORT_SYMBOL(dev_set_allmulti); /* @@ -5165,10 +4978,10 @@ void __dev_set_rx_mode(struct net_device *dev) * therefore calling __dev_set_promiscuity here is safe. */ if (!netdev_uc_empty(dev) && !dev->uc_promisc) { - __dev_set_promiscuity(dev, 1, false); + __dev_set_promiscuity(dev, 1); dev->uc_promisc = true; } else if (netdev_uc_empty(dev) && dev->uc_promisc) { - __dev_set_promiscuity(dev, -1, false); + __dev_set_promiscuity(dev, -1); dev->uc_promisc = false; } } @@ -5257,13 +5070,9 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? 1 : -1; - unsigned int old_flags = dev->flags; dev->gflags ^= IFF_PROMISC; - - if (__dev_set_promiscuity(dev, inc, false) >= 0) - if (dev->flags != old_flags) - dev_set_rx_mode(dev); + dev_set_promiscuity(dev, inc); } /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI @@ -5274,20 +5083,16 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) int inc = (flags & IFF_ALLMULTI) ? 1 : -1; dev->gflags ^= IFF_ALLMULTI; - __dev_set_allmulti(dev, inc, false); + dev_set_allmulti(dev, inc); } return ret; } -void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, - unsigned int gchanges) +void __dev_notify_flags(struct net_device *dev, unsigned int old_flags) { unsigned int changes = dev->flags ^ old_flags; - if (gchanges) - rtmsg_ifinfo(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC); - if (changes & IFF_UP) { if (dev->flags & IFF_UP) call_netdevice_notifiers(NETDEV_UP, dev); @@ -5316,14 +5121,17 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, int dev_change_flags(struct net_device *dev, unsigned int flags) { int ret; - unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags; + unsigned int changes, old_flags = dev->flags; ret = __dev_change_flags(dev, flags); if (ret < 0) return ret; - changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags); - __dev_notify_flags(dev, old_flags, changes); + changes = old_flags ^ dev->flags; + if (changes) + rtmsg_ifinfo(RTM_NEWLINK, dev, changes); + + __dev_notify_flags(dev, old_flags); return ret; } EXPORT_SYMBOL(dev_change_flags); @@ -5470,7 +5278,6 @@ static void net_set_todo(struct net_device *dev) static void rollback_registered_many(struct list_head *head) { struct net_device *dev, *tmp; - LIST_HEAD(close_head); BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -5493,9 +5300,7 @@ static void rollback_registered_many(struct list_head *head) } /* If device is running, close it first. */ - list_for_each_entry(dev, head, unreg_list) - list_add_tail(&dev->close_list, &close_head); - dev_close_many(&close_head); + dev_close_many(head); list_for_each_entry(dev, head, unreg_list) { /* And unlink it from device chain. */ @@ -5518,7 +5323,7 @@ static void rollback_registered_many(struct list_head *head) if (!dev->rtnl_link_ops || dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); + rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); /* * Flush the unicast and multicast chains @@ -5917,7 +5722,7 @@ int register_netdevice(struct net_device *dev) */ if (!dev->rtnl_link_ops || dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); out: return ret; @@ -6224,16 +6029,6 @@ void netdev_set_default_ethtool_ops(struct net_device *dev, } EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops); -void netdev_freemem(struct net_device *dev) -{ - char *addr = (char *)dev - dev->padded; - - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} - /** * alloc_netdev_mqs - allocate network device * @sizeof_priv: size of private data to allocate space for @@ -6277,9 +6072,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, /* ensure 32-byte alignment of whole construct */ alloc_size += NETDEV_ALIGN - 1; - p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - if (!p) - p = vzalloc(alloc_size); + p = kzalloc(alloc_size, GFP_KERNEL); if (!p) return NULL; @@ -6288,7 +6081,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->pcpu_refcnt = alloc_percpu(int); if (!dev->pcpu_refcnt) - goto free_dev; + goto free_p; if (dev_addr_init(dev)) goto free_pcpu; @@ -6303,12 +6096,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); - INIT_LIST_HEAD(&dev->close_list); INIT_LIST_HEAD(&dev->link_watch_list); - INIT_LIST_HEAD(&dev->adj_list.upper); - INIT_LIST_HEAD(&dev->adj_list.lower); - INIT_LIST_HEAD(&dev->all_adj_list.upper); - INIT_LIST_HEAD(&dev->all_adj_list.lower); + INIT_LIST_HEAD(&dev->upper_dev_list); + INIT_LIST_HEAD(&dev->lower_dev_list); dev->priv_flags = IFF_XMIT_DST_RELEASE; setup(dev); @@ -6341,8 +6131,8 @@ free_pcpu: kfree(dev->_rx); #endif -free_dev: - netdev_freemem(dev); +free_p: + kfree(p); return NULL; } EXPORT_SYMBOL(alloc_netdev_mqs); @@ -6379,7 +6169,7 @@ void free_netdev(struct net_device *dev) /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { - netdev_freemem(dev); + kfree((char *)dev - dev->padded); return; } @@ -6541,7 +6331,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char call_netdevice_notifiers(NETDEV_UNREGISTER, dev); rcu_barrier(); call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); + rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); /* * Flush the unicast and multicast chains @@ -6580,7 +6370,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char * Prevent userspace races by waiting until the network * device is fully setup before sending notifications. */ - rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); synchronize_net(); err = 0; diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index ec40a84..6cda4e2 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -752,7 +752,7 @@ int dev_mc_del_global(struct net_device *dev, const unsigned char *addr) EXPORT_SYMBOL(dev_mc_del_global); /** - * dev_mc_sync - Synchronize device's multicast list to another device + * dev_mc_sync - Synchronize device's unicast list to another device * @to: destination device * @from: source device * @@ -780,7 +780,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from) EXPORT_SYMBOL(dev_mc_sync); /** - * dev_mc_sync_multiple - Synchronize device's multicast list to another + * dev_mc_sync_multiple - Synchronize device's unicast list to another * device, but allow for multiple calls to sync to multiple devices. * @to: destination device * @from: source device diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 9589718..5e78d44 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -106,10 +106,6 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data) return skb; } -static struct genl_multicast_group dropmon_mcgrps[] = { - { .name = "events", }, -}; - static void send_dm_alert(struct work_struct *work) { struct sk_buff *skb; @@ -120,8 +116,7 @@ static void send_dm_alert(struct work_struct *work) skb = reset_per_cpu_data(data); if (skb) - genlmsg_multicast(&net_drop_monitor_family, skb, 0, - 0, GFP_KERNEL); + genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL); } /* @@ -338,7 +333,7 @@ out: return NOTIFY_DONE; } -static const struct genl_ops dropmon_ops[] = { +static struct genl_ops dropmon_ops[] = { { .cmd = NET_DM_CMD_CONFIG, .doit = net_dm_cmd_config, @@ -369,13 +364,13 @@ static int __init init_net_drop_monitor(void) return -ENOSPC; } - rc = genl_register_family_with_ops_groups(&net_drop_monitor_family, - dropmon_ops, dropmon_mcgrps); + rc = genl_register_family_with_ops(&net_drop_monitor_family, + dropmon_ops, + ARRAY_SIZE(dropmon_ops)); if (rc) { pr_err("Could not create drop monitor netlink family\n"); return rc; } - WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT); rc = register_netdevice_notifier(&dropmon_net_notifier); if (rc < 0) { diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 2cd354b..1342923 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -81,8 +81,6 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation", [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", - [NETIF_F_GSO_IPIP_BIT] = "tx-ipip-segmentation", - [NETIF_F_GSO_SIT_BIT] = "tx-sit-segmentation", [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation", @@ -96,7 +94,6 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_LOOPBACK_BIT] = "loopback", [NETIF_F_RXFCS_BIT] = "rx-fcs", [NETIF_F_RXALL_BIT] = "rx-all", - [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload", /* Freescale DPA support */ [NETIF_F_HW_QDISC_BIT] = "hw-qdisc", diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index f409e0b..2e65413 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -460,8 +460,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) if (frh->action && (frh->action != rule->action)) continue; - if (frh_get_table(frh, tb) && - (frh_get_table(frh, tb) != rule->table)) + if (frh->table && (frh_get_table(frh, tb) != rule->table)) continue; if (tb[FRA_PRIORITY] && diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index d6ef173..8d7d0dd 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -25,35 +25,9 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst)); } -/** - * skb_flow_get_ports - extract the upper layer ports and return them - * @skb: buffer to extract the ports from - * @thoff: transport header offset - * @ip_proto: protocol for which to get port offset - * - * The function will try to retrieve the ports at offset thoff + poff where poff - * is the protocol port offset returned from proto_ports_offset - */ -__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto) -{ - int poff = proto_ports_offset(ip_proto); - - if (poff >= 0) { - __be32 *ports, _ports; - - ports = skb_header_pointer(skb, thoff + poff, - sizeof(_ports), &_ports); - if (ports) - return *ports; - } - - return 0; -} -EXPORT_SYMBOL(skb_flow_get_ports); - bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) { - int nhoff = skb_network_offset(skb); + int poff, nhoff = skb_network_offset(skb); u8 ip_proto; __be16 proto = skb->protocol; @@ -66,15 +40,15 @@ again: struct iphdr _iph; ip: iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); - if (!iph || iph->ihl < 5) + if (!iph) return false; - nhoff += iph->ihl * 4; - ip_proto = iph->protocol; if (ip_is_fragment(iph)) ip_proto = 0; - + else + ip_proto = iph->protocol; iph_to_flow_copy_addrs(flow, iph); + nhoff += iph->ihl * 4; break; } case __constant_htons(ETH_P_IPV6): { @@ -176,7 +150,16 @@ ipv6: } flow->ip_proto = ip_proto; - flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); + poff = proto_ports_offset(ip_proto); + if (poff >= 0) { + __be32 *ports, _ports; + + ports = skb_header_pointer(skb, nhoff + poff, + sizeof(_ports), &_ports); + if (ports) + flow->ports = *ports; + } + flow->thoff = (u16) nhoff; return true; @@ -184,22 +167,6 @@ ipv6: EXPORT_SYMBOL(skb_flow_dissect); static u32 hashrnd __read_mostly; -static __always_inline void __flow_hash_secret_init(void) -{ - net_get_random_once(&hashrnd, sizeof(hashrnd)); -} - -static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) -{ - __flow_hash_secret_init(); - return jhash_3words(a, b, c, hashrnd); -} - -static __always_inline u32 __flow_hash_1word(u32 a) -{ - __flow_hash_secret_init(); - return jhash_1word(a, hashrnd); -} /* * __skb_get_rxhash: calculate a flow hash based on src/dst addresses @@ -226,9 +193,9 @@ void __skb_get_rxhash(struct sk_buff *skb) swap(keys.port16[0], keys.port16[1]); } - hash = __flow_hash_3words((__force u32)keys.dst, - (__force u32)keys.src, - (__force u32)keys.ports); + hash = jhash_3words((__force u32)keys.dst, + (__force u32)keys.src, + (__force u32)keys.ports, hashrnd); if (!hash) hash = 1; @@ -264,7 +231,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, hash = skb->sk->sk_hash; else hash = (__force u16) skb->protocol; - hash = __flow_hash_1word(hash); + hash = jhash_1word(hash, hashrnd); return (u16) (((u64) hash * qcount) >> 32) + qoffset; } @@ -356,7 +323,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) else hash = (__force u16) skb->protocol ^ skb->rxhash; - hash = __flow_hash_1word(hash); + hash = jhash_1word(hash, hashrnd); queue_index = map->queues[ ((u64)hash * map->len) >> 32]; } @@ -411,3 +378,11 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev, skb_set_queue_mapping(skb, queue_index); return netdev_get_tx_queue(dev, queue_index); } + +static int __init initialize_hashrnd(void) +{ + get_random_bytes(&hashrnd, sizeof(hashrnd)); + return 0; +} + +late_initcall_sync(initialize_hashrnd); diff --git a/net/core/iovec.c b/net/core/iovec.c index b618694..b77eeec 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -48,8 +48,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a if (err < 0) return err; } - if (m->msg_name) - m->msg_name = address; + m->msg_name = address; } else { m->msg_name = NULL; } @@ -101,7 +100,7 @@ int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, EXPORT_SYMBOL(memcpy_toiovecend); /* - * Copy iovec to kernel. Returns -EFAULT on error. + * Copy iovec from kernel. Returns -EFAULT on error. */ int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ca15f32..6072610 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -867,7 +867,7 @@ static void neigh_invalidate(struct neighbour *neigh) static void neigh_probe(struct neighbour *neigh) __releases(neigh->lock) { - struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue); + struct sk_buff *skb = skb_peek(&neigh->arp_queue); /* keep skb alive even if arp_queue overflows */ if (skb) skb = skb_copy(skb, GFP_ATOMIC); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f3edf96..d954b56 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1263,7 +1263,7 @@ static void netdev_release(struct device *d) BUG_ON(dev->reg_state != NETREG_RELEASED); kfree(dev->ifalias); - netdev_freemem(dev); + kfree((char *)dev - dev->padded); } static const void *net_namespace(struct device *d) @@ -1344,19 +1344,17 @@ int netdev_register_kobject(struct net_device *net) return error; } -int netdev_class_create_file_ns(struct class_attribute *class_attr, - const void *ns) +int netdev_class_create_file(struct class_attribute *class_attr) { - return class_create_file_ns(&net_class, class_attr, ns); + return class_create_file(&net_class, class_attr); } -EXPORT_SYMBOL(netdev_class_create_file_ns); +EXPORT_SYMBOL(netdev_class_create_file); -void netdev_class_remove_file_ns(struct class_attribute *class_attr, - const void *ns) +void netdev_class_remove_file(struct class_attribute *class_attr) { - class_remove_file_ns(&net_class, class_attr, ns); + class_remove_file(&net_class, class_attr); } -EXPORT_SYMBOL(netdev_class_remove_file_ns); +EXPORT_SYMBOL(netdev_class_remove_file); int netdev_kobject_init(void) { diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e174949..730cfbd 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -641,9 +641,8 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo netpoll_send_skb(np, send_skb); - /* If there are several rx_skb_hooks for the same - * address we're fine by sending a single reply - */ + /* If there are several rx_hooks for the same address, + we're fine by sending a single reply */ break; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); @@ -725,9 +724,8 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo netpoll_send_skb(np, send_skb); - /* If there are several rx_skb_hooks for the same - * address, we're fine by sending a single reply - */ + /* If there are several rx_hooks for the same address, + we're fine by sending a single reply */ break; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); @@ -763,12 +761,11 @@ static bool pkt_is_ns(struct sk_buff *skb) int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) { - int proto, len, ulen, data_len; - int hits = 0, offset; + int proto, len, ulen; + int hits = 0; const struct iphdr *iph; struct udphdr *uh; struct netpoll *np, *tmp; - uint16_t source; if (list_empty(&npinfo->rx_np)) goto out; @@ -828,10 +825,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) len -= iph->ihl*4; uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); - offset = (unsigned char *)(uh + 1) - skb->data; ulen = ntohs(uh->len); - data_len = skb->len - offset; - source = ntohs(uh->source); if (ulen != len) goto out; @@ -845,7 +839,9 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) if (np->local_port && np->local_port != ntohs(uh->dest)) continue; - np->rx_skb_hook(np, source, skb, offset, data_len); + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), + ulen - sizeof(struct udphdr)); hits++; } } else { @@ -868,10 +864,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto out; uh = udp_hdr(skb); - offset = (unsigned char *)(uh + 1) - skb->data; ulen = ntohs(uh->len); - data_len = skb->len - offset; - source = ntohs(uh->source); if (ulen != skb->len) goto out; if (udp6_csum_init(skb, uh, IPPROTO_UDP)) @@ -884,7 +877,9 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) if (np->local_port && np->local_port != ntohs(uh->dest)) continue; - np->rx_skb_hook(np, source, skb, offset, data_len); + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), + ulen - sizeof(struct udphdr)); hits++; } #endif @@ -1072,7 +1067,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) npinfo->netpoll = np; - if (np->rx_skb_hook) { + if (np->rx_hook) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_flags |= NETPOLL_RX_ENABLED; list_add_tail(&np->rx, &npinfo->rx_np); diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 9b7cf6c..d9cd627 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -222,10 +222,11 @@ static void net_prio_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) { struct task_struct *p; - void *v = (void *)(unsigned long)css->cgroup->id; + void *v; cgroup_taskset_for_each(p, css, tset) { task_lock(p); + v = (void *)(unsigned long)task_netprioidx(p); iterate_fd(p->files, 0, update_netprio, v); task_unlock(p); } diff --git a/net/core/pktgen.c b/net/core/pktgen.c index a797fff..261357a 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2527,8 +2527,6 @@ static int process_ipsec(struct pktgen_dev *pkt_dev, if (x) { int ret; __u8 *eth; - struct iphdr *iph; - nhead = x->props.header_len - skb_headroom(skb); if (nhead > 0) { ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); @@ -2550,11 +2548,6 @@ static int process_ipsec(struct pktgen_dev *pkt_dev, eth = (__u8 *) skb_push(skb, ETH_HLEN); memcpy(eth, pkt_dev->hh, 12); *(u16 *) ð[12] = protocol; - - /* Update IPv4 header len as well as checksum value */ - iph = ip_hdr(skb); - iph->tot_len = htons(skb->len - ETH_HLEN); - ip_send_check(iph); } } return 1; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cf67144..2a0e21d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1647,8 +1647,9 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) } dev->rtnl_link_state = RTNL_LINK_INITIALIZED; + rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); - __dev_notify_flags(dev, old_flags, ~0U); + __dev_notify_flags(dev, old_flags); return 0; } EXPORT_SYMBOL(rtnl_configure_link); @@ -1984,15 +1985,14 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } -void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, - gfp_t flags) +void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change) { struct net *net = dev_net(dev); struct sk_buff *skb; int err = -ENOBUFS; size_t if_info_size; - skb = nlmsg_new((if_info_size = if_nlmsg_size(dev, 0)), flags); + skb = nlmsg_new((if_info_size = if_nlmsg_size(dev, 0)), GFP_KERNEL); if (skb == NULL) goto errout; @@ -2003,7 +2003,7 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, kfree_skb(skb); goto errout; } - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags); + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); return; errout: if (err < 0) @@ -2717,7 +2717,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi case NETDEV_JOIN: break; default: - rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, dev, 0); break; } return NOTIFY_DONE; diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 897da56..8d9d05e 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -7,7 +7,6 @@ #include <linux/hrtimer.h> #include <linux/ktime.h> #include <linux/string.h> -#include <linux/net.h> #include <net/secure_seq.h> @@ -16,9 +15,20 @@ static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; -static __always_inline void net_secret_init(void) +static void net_secret_init(void) { - net_get_random_once(net_secret, sizeof(net_secret)); + u32 tmp; + int i; + + if (likely(net_secret[0])) + return; + + for (i = NET_SECRET_SIZE; i > 0;) { + do { + get_random_bytes(&tmp, sizeof(tmp)); + } while (!tmp); + cmpxchg(&net_secret[--i], 0, tmp); + } } #endif diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 95294d8..0effa7b 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -476,18 +476,6 @@ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, } EXPORT_SYMBOL(skb_add_rx_frag); -void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, - unsigned int truesize) -{ - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - skb_frag_size_add(frag, size); - skb->len += size; - skb->data_len += size; - skb->truesize += truesize; -} -EXPORT_SYMBOL(skb_coalesce_rx_frag); - static void skb_drop_list(struct sk_buff **listp) { kfree_skb_list(*listp); @@ -592,6 +580,9 @@ static void skb_release_head_state(struct sk_buff *skb) #if IS_ENABLED(CONFIG_NF_CONNTRACK) nf_conntrack_put(skb->nfct); #endif +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED + nf_conntrack_put_reasm(skb->nfct_reasm); +#endif #ifdef CONFIG_BRIDGE_NETFILTER nf_bridge_put(skb->nf_bridge); #endif @@ -961,9 +952,6 @@ EXPORT_SYMBOL(skb_clone); static void skb_headers_offset_update(struct sk_buff *skb, int off) { - /* Only adjust this if it actually is csum_start rather than csum */ - if (skb->ip_summed == CHECKSUM_PARTIAL) - skb->csum_start += off; /* {transport,network,mac}_header and tail are relative to skb->head */ skb->transport_header += off; skb->network_header += off; @@ -1097,8 +1085,8 @@ EXPORT_SYMBOL(__pskb_copy); * @ntail: room to add at tail * @gfp_mask: allocation priority * - * Expands (or creates identical copy, if @nhead and @ntail are zero) - * header of @skb. &sk_buff itself is not changed. &sk_buff MUST have + * Expands (or creates identical copy, if &nhead and &ntail are zero) + * header of skb. &sk_buff itself is not changed. &sk_buff MUST have * reference count of 1. Returns zero in the case of success or error, * if expansion failed. In the last case, &sk_buff is not changed. * @@ -1170,6 +1158,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, #endif skb->tail += off; skb_headers_offset_update(skb, nhead); + /* Only adjust this if it actually is csum_start rather than csum */ + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb->csum_start += nhead; skb->cloned = 0; skb->hdr_len = 0; skb->nohdr = 0; @@ -1234,6 +1225,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, NUMA_NO_NODE); int oldheadroom = skb_headroom(skb); int head_copy_len, head_copy_off; + int off; if (!n) return NULL; @@ -1257,7 +1249,11 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, copy_skb_header(n, skb); - skb_headers_offset_update(n, newheadroom - oldheadroom); + off = newheadroom - oldheadroom; + if (n->ip_summed == CHECKSUM_PARTIAL) + n->csum_start += off; + + skb_headers_offset_update(n, off); return n; } @@ -1310,29 +1306,6 @@ free_skb: EXPORT_SYMBOL(skb_pad); /** - * pskb_put - add data to the tail of a potentially fragmented buffer - * @skb: start of the buffer to use - * @tail: tail fragment of the buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the potentially - * fragmented buffer. @tail must be the last fragment of @skb -- or - * @skb itself. If this would exceed the total buffer size the kernel - * will panic. A pointer to the first byte of the extra data is - * returned. - */ - -unsigned char *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) -{ - if (tail != skb) { - skb->data_len += len; - skb->len += len; - } - return skb_put(tail, len); -} -EXPORT_SYMBOL_GPL(pskb_put); - -/** * skb_put - add data to a buffer * @skb: buffer to use * @len: amount of data to add @@ -2009,8 +1982,9 @@ fault: EXPORT_SYMBOL(skb_store_bits); /* Checksum skb data. */ -__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, - __wsum csum, const struct skb_checksum_ops *ops) + +__wsum skb_checksum(const struct sk_buff *skb, int offset, + int len, __wsum csum) { int start = skb_headlen(skb); int i, copy = start - offset; @@ -2021,7 +1995,7 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, if (copy > 0) { if (copy > len) copy = len; - csum = ops->update(skb->data + offset, copy, csum); + csum = csum_partial(skb->data + offset, copy, csum); if ((len -= copy) == 0) return csum; offset += copy; @@ -2042,10 +2016,10 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, if (copy > len) copy = len; vaddr = kmap_atomic(skb_frag_page(frag)); - csum2 = ops->update(vaddr + frag->page_offset + - offset - start, copy, 0); + csum2 = csum_partial(vaddr + frag->page_offset + + offset - start, copy, 0); kunmap_atomic(vaddr); - csum = ops->combine(csum, csum2, pos, copy); + csum = csum_block_add(csum, csum2, pos); if (!(len -= copy)) return csum; offset += copy; @@ -2064,9 +2038,9 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum2; if (copy > len) copy = len; - csum2 = __skb_checksum(frag_iter, offset - start, - copy, 0, ops); - csum = ops->combine(csum, csum2, pos, copy); + csum2 = skb_checksum(frag_iter, offset - start, + copy, 0); + csum = csum_block_add(csum, csum2, pos); if ((len -= copy) == 0) return csum; offset += copy; @@ -2078,18 +2052,6 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, return csum; } -EXPORT_SYMBOL(__skb_checksum); - -__wsum skb_checksum(const struct sk_buff *skb, int offset, - int len, __wsum csum) -{ - const struct skb_checksum_ops ops = { - .update = csum_partial_ext, - .combine = csum_block_add_ext, - }; - - return __skb_checksum(skb, offset, len, csum, &ops); -} EXPORT_SYMBOL(skb_checksum); /* Both of above in one bottle. */ @@ -2609,14 +2571,14 @@ EXPORT_SYMBOL(skb_prepare_seq_read); * @data: destination pointer for data to be returned * @st: state variable * - * Reads a block of skb data at @consumed relative to the + * Reads a block of skb data at &consumed relative to the * lower offset specified to skb_prepare_seq_read(). Assigns - * the head of the data block to @data and returns the length + * the head of the data block to &data and returns the length * of the block or 0 if the end of the skb data or the upper * offset has been reached. * * The caller is not required to consume all of the data - * returned, i.e. @consumed is typically set to the number + * returned, i.e. &consumed is typically set to the number * of bytes already consumed and the next call to * skb_seq_read() will return the remaining part of the block. * @@ -2845,7 +2807,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; struct sk_buff *fskb = skb_shinfo(skb)->frag_list; - skb_frag_t *skb_frag = skb_shinfo(skb)->frags; unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int doffset = skb->data - skb_mac_header(skb); unsigned int offset = doffset; @@ -2885,38 +2846,16 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) if (hsize > len || !sg) hsize = len; - if (!hsize && i >= nfrags && skb_headlen(fskb) && - (skb_headlen(fskb) == len || sg)) { - BUG_ON(skb_headlen(fskb) > len); - - i = 0; - nfrags = skb_shinfo(fskb)->nr_frags; - skb_frag = skb_shinfo(fskb)->frags; - pos += skb_headlen(fskb); - - while (pos < offset + len) { - BUG_ON(i >= nfrags); - - size = skb_frag_size(skb_frag); - if (pos + size > offset + len) - break; - - i++; - pos += size; - skb_frag++; - } + if (!hsize && i >= nfrags) { + BUG_ON(fskb->len != len); + pos += len; nskb = skb_clone(fskb, GFP_ATOMIC); fskb = fskb->next; if (unlikely(!nskb)) goto err; - if (unlikely(pskb_trim(nskb, len))) { - kfree_skb(nskb); - goto err; - } - hsize = skb_end_offset(nskb); if (skb_cow_head(nskb, doffset + headroom)) { kfree_skb(nskb); @@ -2947,13 +2886,20 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) __copy_skb_header(nskb, skb); nskb->mac_len = skb->mac_len; - skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); + /* nskb and skb might have different headroom */ + if (nskb->ip_summed == CHECKSUM_PARTIAL) + nskb->csum_start += skb_headroom(nskb) - headroom; + + skb_reset_mac_header(nskb); + skb_set_network_header(nskb, skb->mac_len); + nskb->transport_header = (nskb->network_header + + skb_network_header_len(skb)); skb_copy_from_linear_data_offset(skb, -tnl_hlen, nskb->data - tnl_hlen, doffset + tnl_hlen); - if (nskb->len == len + doffset) + if (fskb != skb_shinfo(skb)->frag_list) goto perform_csum_check; if (!sg) { @@ -2971,28 +2917,8 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; - while (pos < offset + len) { - if (i >= nfrags) { - BUG_ON(skb_headlen(fskb)); - - i = 0; - nfrags = skb_shinfo(fskb)->nr_frags; - skb_frag = skb_shinfo(fskb)->frags; - - BUG_ON(!nfrags); - - fskb = fskb->next; - } - - if (unlikely(skb_shinfo(nskb)->nr_frags >= - MAX_SKB_FRAGS)) { - net_warn_ratelimited( - "skb_segment: too many frags: %u %u\n", - pos, mss); - goto err; - } - - *frag = *skb_frag; + while (pos < offset + len && i < nfrags) { + *frag = skb_shinfo(skb)->frags[i]; __skb_frag_ref(frag); size = skb_frag_size(frag); @@ -3005,7 +2931,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) if (pos + size <= offset + len) { i++; - skb_frag++; pos += size; } else { skb_frag_size_sub(frag, pos + size - (offset + len)); @@ -3015,6 +2940,25 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) frag++; } + if (pos < offset + len) { + struct sk_buff *fskb2 = fskb; + + BUG_ON(pos + fskb->len != offset + len); + + pos += fskb->len; + fskb = fskb->next; + + if (fskb2->next) { + fskb2 = skb_clone(fskb2, GFP_ATOMIC); + if (!fskb2) + goto err; + } else + skb_get(fskb2); + + SKB_FRAG_ASSERT(nskb); + skb_shinfo(nskb)->frag_list = fskb2; + } + skip_fraglist: nskb->data_len = len - hsize; nskb->len += nskb->data_len; @@ -3041,30 +2985,32 @@ EXPORT_SYMBOL_GPL(skb_segment); int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct skb_shared_info *pinfo, *skbinfo = skb_shinfo(skb); + struct sk_buff *p = *head; + struct sk_buff *nskb; + struct skb_shared_info *skbinfo = skb_shinfo(skb); + struct skb_shared_info *pinfo = skb_shinfo(p); + unsigned int headroom; + unsigned int len = skb_gro_len(skb); unsigned int offset = skb_gro_offset(skb); unsigned int headlen = skb_headlen(skb); - struct sk_buff *nskb, *lp, *p = *head; - unsigned int len = skb_gro_len(skb); unsigned int delta_truesize; - unsigned int headroom; - if (unlikely(p->len + len >= 65536)) + if (p->len + len >= 65536) return -E2BIG; - lp = NAPI_GRO_CB(p)->last ?: p; - pinfo = skb_shinfo(lp); - - if (headlen <= offset) { + if (pinfo->frag_list) + goto merge; + else if (headlen <= offset) { skb_frag_t *frag; skb_frag_t *frag2; int i = skbinfo->nr_frags; int nr_frags = pinfo->nr_frags + i; + offset -= headlen; + if (nr_frags > MAX_SKB_FRAGS) - goto merge; + return -E2BIG; - offset -= headlen; pinfo->nr_frags = nr_frags; skbinfo->nr_frags = 0; @@ -3095,7 +3041,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) unsigned int first_offset; if (nr_frags + 1 + skbinfo->nr_frags > MAX_SKB_FRAGS) - goto merge; + return -E2BIG; first_offset = skb->data - (unsigned char *)page_address(page) + @@ -3113,10 +3059,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff)); NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; goto done; - } - if (pinfo->frag_list) - goto merge; - if (skb_gro_len(p) != pinfo->gso_size) + } else if (skb_gro_len(p) != pinfo->gso_size) return -E2BIG; headroom = skb_headroom(p); @@ -3168,24 +3111,16 @@ merge: __skb_pull(skb, offset); - if (!NAPI_GRO_CB(p)->last) - skb_shinfo(p)->frag_list = skb; - else - NAPI_GRO_CB(p)->last->next = skb; + NAPI_GRO_CB(p)->last->next = skb; NAPI_GRO_CB(p)->last = skb; skb_header_release(skb); - lp = p; done: NAPI_GRO_CB(p)->count++; p->data_len += len; p->truesize += delta_truesize; p->len += len; - if (lp != p) { - lp->data_len += len; - lp->truesize += delta_truesize; - lp->len += len; - } + NAPI_GRO_CB(skb)->same_flow = 1; return 0; } diff --git a/net/core/sock.c b/net/core/sock.c index ab20ed9..0b39e7a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -475,6 +475,12 @@ discard_and_relse: } EXPORT_SYMBOL(sk_receive_skb); +void sk_reset_txq(struct sock *sk) +{ + sk_tx_queue_clear(sk); +} +EXPORT_SYMBOL(sk_reset_txq); + struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) { struct dst_entry *dst = __sk_dst_get(sk); @@ -908,13 +914,6 @@ set_rcvbuf: } break; #endif - - case SO_MAX_PACING_RATE: - sk->sk_max_pacing_rate = val; - sk->sk_pacing_rate = min(sk->sk_pacing_rate, - sk->sk_max_pacing_rate); - break; - default: ret = -ENOPROTOOPT; break; @@ -1178,10 +1177,6 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; #endif - case SO_MAX_PACING_RATE: - v.val = sk->sk_max_pacing_rate; - break; - default: return -ENOPROTOOPT; } @@ -1841,17 +1836,7 @@ EXPORT_SYMBOL(sock_alloc_send_skb); /* On 32bit arches, an skb frag is limited to 2^15 */ #define SKB_FRAG_PAGE_ORDER get_order(32768) -/** - * skb_page_frag_refill - check that a page_frag contains enough room - * @sz: minimum size of the fragment we want to get - * @pfrag: pointer to page_frag - * @prio: priority for memory allocation - * - * Note: While this allocator tries to use high order pages, there is - * no guarantee that allocations succeed. Therefore, @sz MUST be - * less or equal than PAGE_SIZE. - */ -bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio) +bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) { int order; @@ -1860,16 +1845,16 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio) pfrag->offset = 0; return true; } - if (pfrag->offset + sz <= pfrag->size) + if (pfrag->offset < pfrag->size) return true; put_page(pfrag->page); } /* We restrict high order allocations to users that can afford to wait */ - order = (prio & __GFP_WAIT) ? SKB_FRAG_PAGE_ORDER : 0; + order = (sk->sk_allocation & __GFP_WAIT) ? SKB_FRAG_PAGE_ORDER : 0; do { - gfp_t gfp = prio; + gfp_t gfp = sk->sk_allocation; if (order) gfp |= __GFP_COMP | __GFP_NOWARN; @@ -1881,15 +1866,6 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio) } } while (--order >= 0); - return false; -} -EXPORT_SYMBOL(skb_page_frag_refill); - -bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) -{ - if (likely(skb_page_frag_refill(32U, pfrag, sk->sk_allocation))) - return true; - sk_enter_memory_pressure(sk); sk_stream_moderate_sndbuf(sk); return false; @@ -2343,7 +2319,6 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_ll_usec = sysctl_net_busy_read; #endif - sk->sk_max_pacing_rate = ~0U; sk->sk_pacing_rate = ~0U; /* * Before updating sk_refcnt, we must commit prior changes to memory diff --git a/net/core/utils.c b/net/core/utils.c index 2f737bf..aa88e23 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -338,52 +338,3 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, csum_unfold(*sum))); } EXPORT_SYMBOL(inet_proto_csum_replace16); - -struct __net_random_once_work { - struct work_struct work; - struct static_key *key; -}; - -static void __net_random_once_deferred(struct work_struct *w) -{ - struct __net_random_once_work *work = - container_of(w, struct __net_random_once_work, work); - if (!static_key_enabled(work->key)) - static_key_slow_inc(work->key); - kfree(work); -} - -static void __net_random_once_disable_jump(struct static_key *key) -{ - struct __net_random_once_work *w; - - w = kmalloc(sizeof(*w), GFP_ATOMIC); - if (!w) - return; - - INIT_WORK(&w->work, __net_random_once_deferred); - w->key = key; - schedule_work(&w->work); -} - -bool __net_get_random_once(void *buf, int nbytes, bool *done, - struct static_key *done_key) -{ - static DEFINE_SPINLOCK(lock); - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - if (*done) { - spin_unlock_irqrestore(&lock, flags); - return false; - } - - get_random_bytes(buf, nbytes); - *done = true; - spin_unlock_irqrestore(&lock, flags); - - __net_random_once_disable_jump(done_key); - - return true; -} -EXPORT_SYMBOL(__net_get_random_once); |