Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: 1) Seccomp BPF filters can now be JIT'd, from Alexei Starovoitov. 2) Multiqueue support in xen-netback and xen-netfront, from Andrew J Benniston. 3) Allow tweaking of aggregation settings in cdc_ncm driver, from Bjørn Mork. 4) BPF now has a "random" opcode, from Chema Gonzalez. 5) Add more BPF documentation and improve test framework, from Daniel Borkmann. 6) Support TCP fastopen over ipv6, from Daniel Lee. 7) Add software TSO helper functions and use them to support software TSO in mvneta and mv643xx_eth drivers. From Ezequiel Garcia. 8) Support software TSO in fec driver too, from Nimrod Andy. 9) Add Broadcom SYSTEMPORT driver, from Florian Fainelli. 10) Handle broadcasts more gracefully over macvlan when there are large numbers of interfaces configured, from Herbert Xu. 11) Allow more control over fwmark used for non-socket based responses, from Lorenzo Colitti. 12) Do TCP congestion window limiting based upon measurements, from Neal Cardwell. 13) Support busy polling in SCTP, from Neal Horman. 14) Allow RSS key to be configured via ethtool, from Venkata Duvvuru. 15) Bridge promisc mode handling improvements from Vlad Yasevich. 16) Don't use inetpeer entries to implement ID generation any more, it performs poorly, from Eric Dumazet. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1522 commits) rtnetlink: fix userspace API breakage for iproute2 < v3.9.0 tcp: fixing TLP's FIN recovery net: fec: Add software TSO support net: fec: Add Scatter/gather support net: fec: Increase buffer descriptor entry number net: fec: Factorize feature setting net: fec: Enable IP header hardware checksum net: fec: Factorize the .xmit transmit function bridge: fix compile error when compiling without IPv6 support bridge: fix smatch warning / potential null pointer dereference via-rhine: fix full-duplex with autoneg disable bnx2x: Enlarge the dorq threshold for VFs bnx2x: Check for UNDI in uncommon branch bnx2x: Fix 1G-baseT link bnx2x: Fix link for KR with swapped polarity lane sctp: Fix sk_ack_backlog wrap-around problem net/core: Add VF link state control policy net/fsl: xgmac_mdio is dependent on OF_MDIO net/fsl: Make xgmac_mdio read error message useful net_sched: drr: warn when qdisc is not work conserving ...
This commit is contained in:
@@ -9,7 +9,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
|
||||
|
||||
obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
|
||||
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
|
||||
sock_diag.o dev_ioctl.o
|
||||
sock_diag.o dev_ioctl.o tso.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += flow.o
|
||||
obj-y += net-sysfs.o
|
||||
|
@@ -739,11 +739,15 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
|
||||
__sum16 sum;
|
||||
|
||||
sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
|
||||
if (likely(!sum)) {
|
||||
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
||||
netdev_rx_csum_fault(skb->dev);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum &&
|
||||
!skb->csum_complete_sw)
|
||||
netdev_rx_csum_fault(skb->dev);
|
||||
|
||||
/* Save checksum complete for later use */
|
||||
skb->csum = sum;
|
||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
||||
skb->csum_complete_sw = 1;
|
||||
|
||||
return sum;
|
||||
}
|
||||
EXPORT_SYMBOL(__skb_checksum_complete_head);
|
||||
|
@@ -1661,6 +1661,29 @@ bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(is_skb_forwardable);
|
||||
|
||||
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
|
||||
if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
|
||||
atomic_long_inc(&dev->rx_dropped);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!is_skb_forwardable(dev, skb))) {
|
||||
atomic_long_inc(&dev->rx_dropped);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
skb_scrub_packet(skb, true);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dev_forward_skb);
|
||||
|
||||
/**
|
||||
* dev_forward_skb - loopback an skb to another netif
|
||||
*
|
||||
@@ -1681,24 +1704,7 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
|
||||
*/
|
||||
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
|
||||
if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
|
||||
atomic_long_inc(&dev->rx_dropped);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!is_skb_forwardable(dev, skb))) {
|
||||
atomic_long_inc(&dev->rx_dropped);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
skb_scrub_packet(skb, true);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
|
||||
return netif_rx_internal(skb);
|
||||
return __dev_forward_skb(dev, skb) ?: netif_rx_internal(skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_forward_skb);
|
||||
|
||||
@@ -2507,13 +2513,39 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If MPLS offload request, verify we are testing hardware MPLS features
|
||||
* instead of standard features for the netdev.
|
||||
*/
|
||||
#ifdef CONFIG_NET_MPLS_GSO
|
||||
static netdev_features_t net_mpls_features(struct sk_buff *skb,
|
||||
netdev_features_t features,
|
||||
__be16 type)
|
||||
{
|
||||
if (type == htons(ETH_P_MPLS_UC) || type == htons(ETH_P_MPLS_MC))
|
||||
features &= skb->dev->mpls_features;
|
||||
|
||||
return features;
|
||||
}
|
||||
#else
|
||||
static netdev_features_t net_mpls_features(struct sk_buff *skb,
|
||||
netdev_features_t features,
|
||||
__be16 type)
|
||||
{
|
||||
return features;
|
||||
}
|
||||
#endif
|
||||
|
||||
static netdev_features_t harmonize_features(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
int tmp;
|
||||
__be16 type;
|
||||
|
||||
type = skb_network_protocol(skb, &tmp);
|
||||
features = net_mpls_features(skb, features, type);
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_NONE &&
|
||||
!can_checksum_protocol(features, skb_network_protocol(skb, &tmp))) {
|
||||
!can_checksum_protocol(features, type)) {
|
||||
features &= ~NETIF_F_ALL_CSUM;
|
||||
} else if (illegal_highdma(skb->dev, skb)) {
|
||||
features &= ~NETIF_F_SG;
|
||||
@@ -5689,10 +5721,6 @@ static void rollback_registered_many(struct list_head *head)
|
||||
*/
|
||||
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
|
||||
|
||||
if (!dev->rtnl_link_ops ||
|
||||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
|
||||
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Flush the unicast and multicast chains
|
||||
*/
|
||||
@@ -5702,6 +5730,10 @@ static void rollback_registered_many(struct list_head *head)
|
||||
if (dev->netdev_ops->ndo_uninit)
|
||||
dev->netdev_ops->ndo_uninit(dev);
|
||||
|
||||
if (!dev->rtnl_link_ops ||
|
||||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
|
||||
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL);
|
||||
|
||||
/* Notifier chain MUST detach us all upper devices. */
|
||||
WARN_ON(netdev_has_any_upper_dev(dev));
|
||||
|
||||
@@ -5927,10 +5959,7 @@ static void netdev_init_one_queue(struct net_device *dev,
|
||||
|
||||
static void netif_free_tx_queues(struct net_device *dev)
|
||||
{
|
||||
if (is_vmalloc_addr(dev->_tx))
|
||||
vfree(dev->_tx);
|
||||
else
|
||||
kfree(dev->_tx);
|
||||
kvfree(dev->_tx);
|
||||
}
|
||||
|
||||
static int netif_alloc_netdev_queues(struct net_device *dev)
|
||||
@@ -6404,10 +6433,7 @@ void netdev_freemem(struct net_device *dev)
|
||||
{
|
||||
char *addr = (char *)dev - dev->padded;
|
||||
|
||||
if (is_vmalloc_addr(addr))
|
||||
vfree(addr);
|
||||
else
|
||||
kfree(addr);
|
||||
kvfree(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6512,11 +6538,6 @@ free_all:
|
||||
|
||||
free_pcpu:
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
netif_free_tx_queues(dev);
|
||||
#ifdef CONFIG_SYSFS
|
||||
kfree(dev->_rx);
|
||||
#endif
|
||||
|
||||
free_dev:
|
||||
netdev_freemem(dev);
|
||||
return NULL;
|
||||
@@ -6613,6 +6634,9 @@ EXPORT_SYMBOL(unregister_netdevice_queue);
|
||||
/**
|
||||
* unregister_netdevice_many - unregister many devices
|
||||
* @head: list of devices
|
||||
*
|
||||
* Note: As most callers use a stack allocated list_head,
|
||||
* we force a list_del() to make sure stack wont be corrupted later.
|
||||
*/
|
||||
void unregister_netdevice_many(struct list_head *head)
|
||||
{
|
||||
@@ -6622,6 +6646,7 @@ void unregister_netdevice_many(struct list_head *head)
|
||||
rollback_registered_many(head);
|
||||
list_for_each_entry(dev, head, unreg_list)
|
||||
net_set_todo(dev);
|
||||
list_del(head);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_netdevice_many);
|
||||
@@ -7077,7 +7102,6 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
|
||||
}
|
||||
}
|
||||
unregister_netdevice_many(&dev_kill_list);
|
||||
list_del(&dev_kill_list);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
|
@@ -225,6 +225,91 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
|
||||
}
|
||||
EXPORT_SYMBOL(__hw_addr_unsync);
|
||||
|
||||
/**
|
||||
* __hw_addr_sync_dev - Synchonize device's multicast list
|
||||
* @list: address list to syncronize
|
||||
* @dev: device to sync
|
||||
* @sync: function to call if address should be added
|
||||
* @unsync: function to call if address should be removed
|
||||
*
|
||||
* This funciton is intended to be called from the ndo_set_rx_mode
|
||||
* function of devices that require explicit address add/remove
|
||||
* notifications. The unsync function may be NULL in which case
|
||||
* the addresses requiring removal will simply be removed without
|
||||
* any notification to the device.
|
||||
**/
|
||||
int __hw_addr_sync_dev(struct netdev_hw_addr_list *list,
|
||||
struct net_device *dev,
|
||||
int (*sync)(struct net_device *, const unsigned char *),
|
||||
int (*unsync)(struct net_device *,
|
||||
const unsigned char *))
|
||||
{
|
||||
struct netdev_hw_addr *ha, *tmp;
|
||||
int err;
|
||||
|
||||
/* first go through and flush out any stale entries */
|
||||
list_for_each_entry_safe(ha, tmp, &list->list, list) {
|
||||
if (!ha->sync_cnt || ha->refcount != 1)
|
||||
continue;
|
||||
|
||||
/* if unsync is defined and fails defer unsyncing address */
|
||||
if (unsync && unsync(dev, ha->addr))
|
||||
continue;
|
||||
|
||||
ha->sync_cnt--;
|
||||
__hw_addr_del_entry(list, ha, false, false);
|
||||
}
|
||||
|
||||
/* go through and sync new entries to the list */
|
||||
list_for_each_entry_safe(ha, tmp, &list->list, list) {
|
||||
if (ha->sync_cnt)
|
||||
continue;
|
||||
|
||||
err = sync(dev, ha->addr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ha->sync_cnt++;
|
||||
ha->refcount++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__hw_addr_sync_dev);
|
||||
|
||||
/**
|
||||
* __hw_addr_unsync_dev - Remove synchonized addresses from device
|
||||
* @list: address list to remove syncronized addresses from
|
||||
* @dev: device to sync
|
||||
* @unsync: function to call if address should be removed
|
||||
*
|
||||
* Remove all addresses that were added to the device by __hw_addr_sync_dev().
|
||||
* This function is intended to be called from the ndo_stop or ndo_open
|
||||
* functions on devices that require explicit address add/remove
|
||||
* notifications. If the unsync function pointer is NULL then this function
|
||||
* can be used to just reset the sync_cnt for the addresses in the list.
|
||||
**/
|
||||
void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
|
||||
struct net_device *dev,
|
||||
int (*unsync)(struct net_device *,
|
||||
const unsigned char *))
|
||||
{
|
||||
struct netdev_hw_addr *ha, *tmp;
|
||||
|
||||
list_for_each_entry_safe(ha, tmp, &list->list, list) {
|
||||
if (!ha->sync_cnt)
|
||||
continue;
|
||||
|
||||
/* if unsync is defined and fails defer unsyncing address */
|
||||
if (unsync && unsync(dev, ha->addr))
|
||||
continue;
|
||||
|
||||
ha->sync_cnt--;
|
||||
__hw_addr_del_entry(list, ha, false, false);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__hw_addr_unsync_dev);
|
||||
|
||||
static void __hw_addr_flush(struct netdev_hw_addr_list *list)
|
||||
{
|
||||
struct netdev_hw_addr *ha, *tmp;
|
||||
|
@@ -557,6 +557,23 @@ err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
|
||||
struct ethtool_rxnfc *rx_rings,
|
||||
u32 size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
|
||||
return -EFAULT;
|
||||
|
||||
/* Validate ring indices */
|
||||
for (i = 0; i < size; i++)
|
||||
if (indir[i] >= rx_rings->data)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
|
||||
void __user *useraddr)
|
||||
{
|
||||
@@ -565,7 +582,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->get_rxfh_indir_size ||
|
||||
!dev->ethtool_ops->get_rxfh_indir)
|
||||
!dev->ethtool_ops->get_rxfh)
|
||||
return -EOPNOTSUPP;
|
||||
dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
|
||||
if (dev_size == 0)
|
||||
@@ -591,7 +608,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
|
||||
if (!indir)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
|
||||
ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -613,8 +630,9 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
|
||||
u32 *indir;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
int ret;
|
||||
u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
|
||||
|
||||
if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir ||
|
||||
if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
|
||||
!ops->get_rxnfc)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -643,31 +661,187 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
|
||||
for (i = 0; i < dev_size; i++)
|
||||
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
|
||||
} else {
|
||||
if (copy_from_user(indir,
|
||||
useraddr +
|
||||
offsetof(struct ethtool_rxfh_indir,
|
||||
ring_index[0]),
|
||||
dev_size * sizeof(indir[0]))) {
|
||||
ret = -EFAULT;
|
||||
ret = ethtool_copy_validate_indir(indir,
|
||||
useraddr + ringidx_offset,
|
||||
&rx_rings,
|
||||
dev_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Validate ring indices */
|
||||
for (i = 0; i < dev_size; i++) {
|
||||
if (indir[i] >= rx_rings.data) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = ops->set_rxfh_indir(dev, indir);
|
||||
ret = ops->set_rxfh(dev, indir, NULL);
|
||||
|
||||
out:
|
||||
kfree(indir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
|
||||
void __user *useraddr)
|
||||
{
|
||||
int ret;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
u32 user_indir_size, user_key_size;
|
||||
u32 dev_indir_size = 0, dev_key_size = 0;
|
||||
struct ethtool_rxfh rxfh;
|
||||
u32 total_size;
|
||||
u32 indir_bytes;
|
||||
u32 *indir = NULL;
|
||||
u8 *hkey = NULL;
|
||||
u8 *rss_config;
|
||||
|
||||
if (!(dev->ethtool_ops->get_rxfh_indir_size ||
|
||||
dev->ethtool_ops->get_rxfh_key_size) ||
|
||||
!dev->ethtool_ops->get_rxfh)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ops->get_rxfh_indir_size)
|
||||
dev_indir_size = ops->get_rxfh_indir_size(dev);
|
||||
if (ops->get_rxfh_key_size)
|
||||
dev_key_size = ops->get_rxfh_key_size(dev);
|
||||
|
||||
if ((dev_key_size + dev_indir_size) == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
||||
return -EFAULT;
|
||||
user_indir_size = rxfh.indir_size;
|
||||
user_key_size = rxfh.key_size;
|
||||
|
||||
/* Check that reserved fields are 0 for now */
|
||||
if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
|
||||
return -EINVAL;
|
||||
|
||||
rxfh.indir_size = dev_indir_size;
|
||||
rxfh.key_size = dev_key_size;
|
||||
if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
|
||||
return -EFAULT;
|
||||
|
||||
/* If the user buffer size is 0, this is just a query for the
|
||||
* device table size and key size. Otherwise, if the User size is
|
||||
* not equal to device table size or key size it's an error.
|
||||
*/
|
||||
if (!user_indir_size && !user_key_size)
|
||||
return 0;
|
||||
|
||||
if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
|
||||
(user_key_size && (user_key_size != dev_key_size)))
|
||||
return -EINVAL;
|
||||
|
||||
indir_bytes = user_indir_size * sizeof(indir[0]);
|
||||
total_size = indir_bytes + user_key_size;
|
||||
rss_config = kzalloc(total_size, GFP_USER);
|
||||
if (!rss_config)
|
||||
return -ENOMEM;
|
||||
|
||||
if (user_indir_size)
|
||||
indir = (u32 *)rss_config;
|
||||
|
||||
if (user_key_size)
|
||||
hkey = rss_config + indir_bytes;
|
||||
|
||||
ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey);
|
||||
if (!ret) {
|
||||
if (copy_to_user(useraddr +
|
||||
offsetof(struct ethtool_rxfh, rss_config[0]),
|
||||
rss_config, total_size))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
kfree(rss_config);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
||||
void __user *useraddr)
|
||||
{
|
||||
int ret;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct ethtool_rxnfc rx_rings;
|
||||
struct ethtool_rxfh rxfh;
|
||||
u32 dev_indir_size = 0, dev_key_size = 0, i;
|
||||
u32 *indir = NULL, indir_bytes = 0;
|
||||
u8 *hkey = NULL;
|
||||
u8 *rss_config;
|
||||
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
|
||||
|
||||
if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) ||
|
||||
!ops->get_rxnfc || !ops->set_rxfh)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ops->get_rxfh_indir_size)
|
||||
dev_indir_size = ops->get_rxfh_indir_size(dev);
|
||||
if (ops->get_rxfh_key_size)
|
||||
dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
|
||||
if ((dev_key_size + dev_indir_size) == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Check that reserved fields are 0 for now */
|
||||
if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
|
||||
return -EINVAL;
|
||||
|
||||
/* If either indir or hash key is valid, proceed further.
|
||||
* It is not valid to request that both be unchanged.
|
||||
*/
|
||||
if ((rxfh.indir_size &&
|
||||
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
|
||||
rxfh.indir_size != dev_indir_size) ||
|
||||
(rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
|
||||
(rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
|
||||
rxfh.key_size == 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
|
||||
indir_bytes = dev_indir_size * sizeof(indir[0]);
|
||||
|
||||
rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
|
||||
if (!rss_config)
|
||||
return -ENOMEM;
|
||||
|
||||
rx_rings.cmd = ETHTOOL_GRXRINGS;
|
||||
ret = ops->get_rxnfc(dev, &rx_rings, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* rxfh.indir_size == 0 means reset the indir table to default.
|
||||
* rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
|
||||
*/
|
||||
if (rxfh.indir_size &&
|
||||
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
|
||||
indir = (u32 *)rss_config;
|
||||
ret = ethtool_copy_validate_indir(indir,
|
||||
useraddr + rss_cfg_offset,
|
||||
&rx_rings,
|
||||
rxfh.indir_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else if (rxfh.indir_size == 0) {
|
||||
indir = (u32 *)rss_config;
|
||||
for (i = 0; i < dev_indir_size; i++)
|
||||
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
|
||||
}
|
||||
|
||||
if (rxfh.key_size) {
|
||||
hkey = rss_config + indir_bytes;
|
||||
if (copy_from_user(hkey,
|
||||
useraddr + rss_cfg_offset + indir_bytes,
|
||||
rxfh.key_size)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ops->set_rxfh(dev, indir, hkey);
|
||||
|
||||
out:
|
||||
kfree(rss_config);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_regs regs;
|
||||
@@ -1491,6 +1665,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
||||
case ETHTOOL_GRXCLSRULE:
|
||||
case ETHTOOL_GRXCLSRLALL:
|
||||
case ETHTOOL_GRXFHINDIR:
|
||||
case ETHTOOL_GRSSH:
|
||||
case ETHTOOL_GFEATURES:
|
||||
case ETHTOOL_GCHANNELS:
|
||||
case ETHTOOL_GET_TS_INFO:
|
||||
@@ -1628,6 +1803,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
||||
case ETHTOOL_SRXFHINDIR:
|
||||
rc = ethtool_set_rxfh_indir(dev, useraddr);
|
||||
break;
|
||||
case ETHTOOL_GRSSH:
|
||||
rc = ethtool_get_rxfh(dev, useraddr);
|
||||
break;
|
||||
case ETHTOOL_SRSSH:
|
||||
rc = ethtool_set_rxfh(dev, useraddr);
|
||||
break;
|
||||
case ETHTOOL_GFEATURES:
|
||||
rc = ethtool_get_features(dev, useraddr);
|
||||
break;
|
||||
|
1290
net/core/filter.c
1290
net/core/filter.c
File diff suppressed because it is too large
Load Diff
@@ -273,7 +273,7 @@ static void cleanup_net(struct work_struct *work)
|
||||
{
|
||||
const struct pernet_operations *ops;
|
||||
struct net *net, *tmp;
|
||||
LIST_HEAD(net_kill_list);
|
||||
struct list_head net_kill_list;
|
||||
LIST_HEAD(net_exit_list);
|
||||
|
||||
/* Atomically snapshot the list of namespaces to cleanup */
|
||||
|
@@ -573,7 +573,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
||||
is_zero_ether_addr(pkt_dev->src_mac) ?
|
||||
pkt_dev->odev->dev_addr : pkt_dev->src_mac);
|
||||
|
||||
seq_printf(seq, "dst_mac: ");
|
||||
seq_puts(seq, "dst_mac: ");
|
||||
seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
|
||||
|
||||
seq_printf(seq,
|
||||
@@ -588,7 +588,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
||||
|
||||
if (pkt_dev->nr_labels) {
|
||||
unsigned int i;
|
||||
seq_printf(seq, " mpls: ");
|
||||
seq_puts(seq, " mpls: ");
|
||||
for (i = 0; i < pkt_dev->nr_labels; i++)
|
||||
seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
|
||||
i == pkt_dev->nr_labels-1 ? "\n" : ", ");
|
||||
@@ -613,67 +613,67 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
||||
if (pkt_dev->node >= 0)
|
||||
seq_printf(seq, " node: %d\n", pkt_dev->node);
|
||||
|
||||
seq_printf(seq, " Flags: ");
|
||||
seq_puts(seq, " Flags: ");
|
||||
|
||||
if (pkt_dev->flags & F_IPV6)
|
||||
seq_printf(seq, "IPV6 ");
|
||||
seq_puts(seq, "IPV6 ");
|
||||
|
||||
if (pkt_dev->flags & F_IPSRC_RND)
|
||||
seq_printf(seq, "IPSRC_RND ");
|
||||
seq_puts(seq, "IPSRC_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_IPDST_RND)
|
||||
seq_printf(seq, "IPDST_RND ");
|
||||
seq_puts(seq, "IPDST_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_TXSIZE_RND)
|
||||
seq_printf(seq, "TXSIZE_RND ");
|
||||
seq_puts(seq, "TXSIZE_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_UDPSRC_RND)
|
||||
seq_printf(seq, "UDPSRC_RND ");
|
||||
seq_puts(seq, "UDPSRC_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_UDPDST_RND)
|
||||
seq_printf(seq, "UDPDST_RND ");
|
||||
seq_puts(seq, "UDPDST_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_UDPCSUM)
|
||||
seq_printf(seq, "UDPCSUM ");
|
||||
seq_puts(seq, "UDPCSUM ");
|
||||
|
||||
if (pkt_dev->flags & F_MPLS_RND)
|
||||
seq_printf(seq, "MPLS_RND ");
|
||||
seq_puts(seq, "MPLS_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_QUEUE_MAP_RND)
|
||||
seq_printf(seq, "QUEUE_MAP_RND ");
|
||||
seq_puts(seq, "QUEUE_MAP_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_QUEUE_MAP_CPU)
|
||||
seq_printf(seq, "QUEUE_MAP_CPU ");
|
||||
seq_puts(seq, "QUEUE_MAP_CPU ");
|
||||
|
||||
if (pkt_dev->cflows) {
|
||||
if (pkt_dev->flags & F_FLOW_SEQ)
|
||||
seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/
|
||||
seq_puts(seq, "FLOW_SEQ "); /*in sequence flows*/
|
||||
else
|
||||
seq_printf(seq, "FLOW_RND ");
|
||||
seq_puts(seq, "FLOW_RND ");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
if (pkt_dev->flags & F_IPSEC_ON) {
|
||||
seq_printf(seq, "IPSEC ");
|
||||
seq_puts(seq, "IPSEC ");
|
||||
if (pkt_dev->spi)
|
||||
seq_printf(seq, "spi:%u", pkt_dev->spi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pkt_dev->flags & F_MACSRC_RND)
|
||||
seq_printf(seq, "MACSRC_RND ");
|
||||
seq_puts(seq, "MACSRC_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_MACDST_RND)
|
||||
seq_printf(seq, "MACDST_RND ");
|
||||
seq_puts(seq, "MACDST_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_VID_RND)
|
||||
seq_printf(seq, "VID_RND ");
|
||||
seq_puts(seq, "VID_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_SVID_RND)
|
||||
seq_printf(seq, "SVID_RND ");
|
||||
seq_puts(seq, "SVID_RND ");
|
||||
|
||||
if (pkt_dev->flags & F_NODE)
|
||||
seq_printf(seq, "NODE_ALLOC ");
|
||||
seq_puts(seq, "NODE_ALLOC ");
|
||||
|
||||
seq_puts(seq, "\n");
|
||||
|
||||
@@ -716,7 +716,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
||||
if (pkt_dev->result[0])
|
||||
seq_printf(seq, "Result: %s\n", pkt_dev->result);
|
||||
else
|
||||
seq_printf(seq, "Result: Idle\n");
|
||||
seq_puts(seq, "Result: Idle\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1735,14 +1735,14 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
|
||||
|
||||
BUG_ON(!t);
|
||||
|
||||
seq_printf(seq, "Running: ");
|
||||
seq_puts(seq, "Running: ");
|
||||
|
||||
if_lock(t);
|
||||
list_for_each_entry(pkt_dev, &t->if_list, list)
|
||||
if (pkt_dev->running)
|
||||
seq_printf(seq, "%s ", pkt_dev->odevname);
|
||||
|
||||
seq_printf(seq, "\nStopped: ");
|
||||
seq_puts(seq, "\nStopped: ");
|
||||
|
||||
list_for_each_entry(pkt_dev, &t->if_list, list)
|
||||
if (!pkt_dev->running)
|
||||
@@ -1751,7 +1751,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
|
||||
if (t->result[0])
|
||||
seq_printf(seq, "\nResult: %s\n", t->result);
|
||||
else
|
||||
seq_printf(seq, "\nResult: NA\n");
|
||||
seq_puts(seq, "\nResult: NA\n");
|
||||
|
||||
if_unlock(t);
|
||||
|
||||
|
@@ -88,7 +88,7 @@ EXPORT_SYMBOL_GPL(ptp_classify_raw);
|
||||
|
||||
void __init ptp_classifier_init(void)
|
||||
{
|
||||
static struct sock_filter ptp_filter[] = {
|
||||
static struct sock_filter ptp_filter[] __initdata = {
|
||||
{ 0x28, 0, 0, 0x0000000c },
|
||||
{ 0x15, 0, 12, 0x00000800 },
|
||||
{ 0x30, 0, 0, 0x00000017 },
|
||||
@@ -133,7 +133,7 @@ void __init ptp_classifier_init(void)
|
||||
{ 0x16, 0, 0, 0x00000000 },
|
||||
{ 0x06, 0, 0, 0x00000000 },
|
||||
};
|
||||
struct sock_fprog ptp_prog = {
|
||||
struct sock_fprog_kern ptp_prog = {
|
||||
.len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter,
|
||||
};
|
||||
|
||||
|
@@ -798,8 +798,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
|
||||
size += num_vfs *
|
||||
(nla_total_size(sizeof(struct ifla_vf_mac)) +
|
||||
nla_total_size(sizeof(struct ifla_vf_vlan)) +
|
||||
nla_total_size(sizeof(struct ifla_vf_tx_rate)) +
|
||||
nla_total_size(sizeof(struct ifla_vf_spoofchk)));
|
||||
nla_total_size(sizeof(struct ifla_vf_spoofchk)) +
|
||||
nla_total_size(sizeof(struct ifla_vf_rate)));
|
||||
return size;
|
||||
} else
|
||||
return 0;
|
||||
@@ -1065,6 +1065,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
struct ifla_vf_info ivi;
|
||||
struct ifla_vf_mac vf_mac;
|
||||
struct ifla_vf_vlan vf_vlan;
|
||||
struct ifla_vf_rate vf_rate;
|
||||
struct ifla_vf_tx_rate vf_tx_rate;
|
||||
struct ifla_vf_spoofchk vf_spoofchk;
|
||||
struct ifla_vf_link_state vf_linkstate;
|
||||
@@ -1085,6 +1086,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
break;
|
||||
vf_mac.vf =
|
||||
vf_vlan.vf =
|
||||
vf_rate.vf =
|
||||
vf_tx_rate.vf =
|
||||
vf_spoofchk.vf =
|
||||
vf_linkstate.vf = ivi.vf;
|
||||
@@ -1092,7 +1094,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
|
||||
vf_vlan.vlan = ivi.vlan;
|
||||
vf_vlan.qos = ivi.qos;
|
||||
vf_tx_rate.rate = ivi.tx_rate;
|
||||
vf_tx_rate.rate = ivi.max_tx_rate;
|
||||
vf_rate.min_tx_rate = ivi.min_tx_rate;
|
||||
vf_rate.max_tx_rate = ivi.max_tx_rate;
|
||||
vf_spoofchk.setting = ivi.spoofchk;
|
||||
vf_linkstate.link_state = ivi.linkstate;
|
||||
vf = nla_nest_start(skb, IFLA_VF_INFO);
|
||||
@@ -1102,6 +1106,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
}
|
||||
if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
|
||||
nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
|
||||
nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
|
||||
&vf_rate) ||
|
||||
nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
|
||||
&vf_tx_rate) ||
|
||||
nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
|
||||
@@ -1208,6 +1214,10 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
|
||||
.len = sizeof(struct ifla_vf_tx_rate) },
|
||||
[IFLA_VF_SPOOFCHK] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_spoofchk) },
|
||||
[IFLA_VF_RATE] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_rate) },
|
||||
[IFLA_VF_LINK_STATE] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_link_state) },
|
||||
};
|
||||
|
||||
static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
|
||||
@@ -1234,6 +1244,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
struct nlattr *tb[IFLA_MAX+1];
|
||||
u32 ext_filter_mask = 0;
|
||||
int err;
|
||||
int hdrlen;
|
||||
|
||||
s_h = cb->args[0];
|
||||
s_idx = cb->args[1];
|
||||
@@ -1241,8 +1252,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
rcu_read_lock();
|
||||
cb->seq = net->dev_base_seq;
|
||||
|
||||
if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
|
||||
ifla_policy) >= 0) {
|
||||
/* A hack to preserve kernel<->userspace interface.
|
||||
* The correct header is ifinfomsg. It is consistent with rtnl_getlink.
|
||||
* However, before Linux v3.9 the code here assumed rtgenmsg and that's
|
||||
* what iproute2 < v3.9.0 used.
|
||||
* We can detect the old iproute2. Even including the IFLA_EXT_MASK
|
||||
* attribute, its netlink message is shorter than struct ifinfomsg.
|
||||
*/
|
||||
hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ?
|
||||
sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
|
||||
|
||||
if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
|
||||
|
||||
if (tb[IFLA_EXT_MASK])
|
||||
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
||||
@@ -1367,11 +1387,29 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
|
||||
}
|
||||
case IFLA_VF_TX_RATE: {
|
||||
struct ifla_vf_tx_rate *ivt;
|
||||
struct ifla_vf_info ivf;
|
||||
ivt = nla_data(vf);
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_tx_rate)
|
||||
err = ops->ndo_set_vf_tx_rate(dev, ivt->vf,
|
||||
ivt->rate);
|
||||
if (ops->ndo_get_vf_config)
|
||||
err = ops->ndo_get_vf_config(dev, ivt->vf,
|
||||
&ivf);
|
||||
if (err)
|
||||
break;
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_rate)
|
||||
err = ops->ndo_set_vf_rate(dev, ivt->vf,
|
||||
ivf.min_tx_rate,
|
||||
ivt->rate);
|
||||
break;
|
||||
}
|
||||
case IFLA_VF_RATE: {
|
||||
struct ifla_vf_rate *ivt;
|
||||
ivt = nla_data(vf);
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_rate)
|
||||
err = ops->ndo_set_vf_rate(dev, ivt->vf,
|
||||
ivt->min_tx_rate,
|
||||
ivt->max_tx_rate);
|
||||
break;
|
||||
}
|
||||
case IFLA_VF_SPOOFCHK: {
|
||||
@@ -1744,7 +1782,6 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
|
||||
ops->dellink(dev, &list_kill);
|
||||
unregister_netdevice_many(&list_kill);
|
||||
list_del(&list_kill);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2019,11 +2056,15 @@ replay:
|
||||
if (ops->newlink) {
|
||||
err = ops->newlink(net, dev, tb, data);
|
||||
/* Drivers should call free_netdev() in ->destructor
|
||||
* and unregister it on failure so that device could be
|
||||
* finally freed in rtnl_unlock.
|
||||
* and unregister it on failure after registration
|
||||
* so that device could be finally freed in rtnl_unlock.
|
||||
*/
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
/* If device is not registered at all, free it now */
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED)
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0) {
|
||||
@@ -2095,9 +2136,13 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct nlattr *tb[IFLA_MAX+1];
|
||||
u32 ext_filter_mask = 0;
|
||||
u16 min_ifinfo_dump_size = 0;
|
||||
int hdrlen;
|
||||
|
||||
if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
|
||||
ifla_policy) >= 0) {
|
||||
/* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */
|
||||
hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ?
|
||||
sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
|
||||
|
||||
if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
|
||||
if (tb[IFLA_EXT_MASK])
|
||||
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
||||
}
|
||||
|
@@ -85,31 +85,6 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
__u32 secure_ip_id(__be32 daddr)
|
||||
{
|
||||
u32 hash[MD5_DIGEST_WORDS];
|
||||
|
||||
net_secret_init();
|
||||
hash[0] = (__force __u32) daddr;
|
||||
hash[1] = net_secret[13];
|
||||
hash[2] = net_secret[14];
|
||||
hash[3] = net_secret[15];
|
||||
|
||||
md5_transform(hash, net_secret);
|
||||
|
||||
return hash[0];
|
||||
}
|
||||
|
||||
__u32 secure_ipv6_id(const __be32 daddr[4])
|
||||
{
|
||||
__u32 hash[4];
|
||||
|
||||
net_secret_init();
|
||||
memcpy(hash, daddr, 16);
|
||||
md5_transform(hash, net_secret);
|
||||
|
||||
return hash[0];
|
||||
}
|
||||
|
||||
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
|
||||
__be16 sport, __be16 dport)
|
||||
|
@@ -694,7 +694,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
||||
#endif
|
||||
memcpy(new->cb, old->cb, sizeof(old->cb));
|
||||
new->csum = old->csum;
|
||||
new->local_df = old->local_df;
|
||||
new->ignore_df = old->ignore_df;
|
||||
new->pkt_type = old->pkt_type;
|
||||
new->ip_summed = old->ip_summed;
|
||||
skb_copy_queue_mapping(new, old);
|
||||
@@ -951,10 +951,13 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
|
||||
EXPORT_SYMBOL(skb_copy);
|
||||
|
||||
/**
|
||||
* __pskb_copy - create copy of an sk_buff with private head.
|
||||
* __pskb_copy_fclone - create copy of an sk_buff with private head.
|
||||
* @skb: buffer to copy
|
||||
* @headroom: headroom of new skb
|
||||
* @gfp_mask: allocation priority
|
||||
* @fclone: if true allocate the copy of the skb from the fclone
|
||||
* cache instead of the head cache; it is recommended to set this
|
||||
* to true for the cases where the copy will likely be cloned
|
||||
*
|
||||
* Make a copy of both an &sk_buff and part of its data, located
|
||||
* in header. Fragmented data remain shared. This is used when
|
||||
@@ -964,11 +967,12 @@ EXPORT_SYMBOL(skb_copy);
|
||||
* The returned buffer has a reference count of 1.
|
||||
*/
|
||||
|
||||
struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
|
||||
struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
|
||||
gfp_t gfp_mask, bool fclone)
|
||||
{
|
||||
unsigned int size = skb_headlen(skb) + headroom;
|
||||
struct sk_buff *n = __alloc_skb(size, gfp_mask,
|
||||
skb_alloc_rx_flag(skb), NUMA_NO_NODE);
|
||||
int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0);
|
||||
struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE);
|
||||
|
||||
if (!n)
|
||||
goto out;
|
||||
@@ -1008,7 +1012,7 @@ struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
|
||||
out:
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(__pskb_copy);
|
||||
EXPORT_SYMBOL(__pskb_copy_fclone);
|
||||
|
||||
/**
|
||||
* pskb_expand_head - reallocate header of &sk_buff
|
||||
@@ -2881,12 +2885,14 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
|
||||
int pos;
|
||||
int dummy;
|
||||
|
||||
__skb_push(head_skb, doffset);
|
||||
proto = skb_network_protocol(head_skb, &dummy);
|
||||
if (unlikely(!proto))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
csum = !!can_checksum_protocol(features, proto);
|
||||
__skb_push(head_skb, doffset);
|
||||
csum = !head_skb->encap_hdr_csum &&
|
||||
!!can_checksum_protocol(features, proto);
|
||||
|
||||
headroom = skb_headroom(head_skb);
|
||||
pos = skb_headlen(head_skb);
|
||||
|
||||
@@ -2983,6 +2989,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
|
||||
nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
|
||||
skb_put(nskb, len),
|
||||
len, 0);
|
||||
SKB_GSO_CB(nskb)->csum_start =
|
||||
skb_headroom(nskb) + offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3052,6 +3060,8 @@ perform_csum_check:
|
||||
nskb->csum = skb_checksum(nskb, doffset,
|
||||
nskb->len - doffset, 0);
|
||||
nskb->ip_summed = CHECKSUM_NONE;
|
||||
SKB_GSO_CB(nskb)->csum_start =
|
||||
skb_headroom(nskb) + doffset;
|
||||
}
|
||||
} while ((offset += len) < head_skb->len);
|
||||
|
||||
@@ -3913,7 +3923,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
|
||||
skb->tstamp.tv64 = 0;
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->skb_iif = 0;
|
||||
skb->local_df = 0;
|
||||
skb->ignore_df = 0;
|
||||
skb_dst_drop(skb);
|
||||
skb->mark = 0;
|
||||
secpath_reset(skb);
|
||||
|
@@ -784,7 +784,7 @@ set_rcvbuf:
|
||||
break;
|
||||
|
||||
case SO_NO_CHECK:
|
||||
sk->sk_no_check = valbool;
|
||||
sk->sk_no_check_tx = valbool;
|
||||
break;
|
||||
|
||||
case SO_PRIORITY:
|
||||
@@ -1064,7 +1064,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case SO_NO_CHECK:
|
||||
v.val = sk->sk_no_check;
|
||||
v.val = sk->sk_no_check_tx;
|
||||
break;
|
||||
|
||||
case SO_PRIORITY:
|
||||
|
77
net/core/tso.c
Normal file
77
net/core/tso.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <linux/export.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/tso.h>
|
||||
|
||||
/* Calculate expected number of TX descriptors */
|
||||
int tso_count_descs(struct sk_buff *skb)
|
||||
{
|
||||
/* The Marvell Way */
|
||||
return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags;
|
||||
}
|
||||
EXPORT_SYMBOL(tso_count_descs);
|
||||
|
||||
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
|
||||
int size, bool is_last)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
int mac_hdr_len = skb_network_offset(skb);
|
||||
|
||||
memcpy(hdr, skb->data, hdr_len);
|
||||
iph = (struct iphdr *)(hdr + mac_hdr_len);
|
||||
iph->id = htons(tso->ip_id);
|
||||
iph->tot_len = htons(size + hdr_len - mac_hdr_len);
|
||||
tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb));
|
||||
tcph->seq = htonl(tso->tcp_seq);
|
||||
tso->ip_id++;
|
||||
|
||||
if (!is_last) {
|
||||
/* Clear all special flags for not last packet */
|
||||
tcph->psh = 0;
|
||||
tcph->fin = 0;
|
||||
tcph->rst = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tso_build_hdr);
|
||||
|
||||
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size)
|
||||
{
|
||||
tso->tcp_seq += size;
|
||||
tso->size -= size;
|
||||
tso->data += size;
|
||||
|
||||
if ((tso->size == 0) &&
|
||||
(tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) {
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx];
|
||||
|
||||
/* Move to next segment */
|
||||
tso->size = frag->size;
|
||||
tso->data = page_address(frag->page.p) + frag->page_offset;
|
||||
tso->next_frag_idx++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tso_build_data);
|
||||
|
||||
void tso_start(struct sk_buff *skb, struct tso_t *tso)
|
||||
{
|
||||
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
|
||||
tso->ip_id = ntohs(ip_hdr(skb)->id);
|
||||
tso->tcp_seq = ntohl(tcp_hdr(skb)->seq);
|
||||
tso->next_frag_idx = 0;
|
||||
|
||||
/* Build first data */
|
||||
tso->size = skb_headlen(skb) - hdr_len;
|
||||
tso->data = skb->data + hdr_len;
|
||||
if ((tso->size == 0) &&
|
||||
(tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) {
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx];
|
||||
|
||||
/* Move to next segment */
|
||||
tso->size = frag->size;
|
||||
tso->data = page_address(frag->page.p) + frag->page_offset;
|
||||
tso->next_frag_idx++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tso_start);
|
Reference in New Issue
Block a user