diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 158 | 
1 files changed, 103 insertions, 55 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 8f9710c62e20..1796cef55ab5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -660,6 +660,27 @@ __setup("netdev=", netdev_boot_setup);  *******************************************************************************/  /** + *	dev_get_iflink	- get 'iflink' value of a interface + *	@dev: targeted interface + * + *	Indicates the ifindex the interface is linked to. + *	Physical interfaces have the same 'ifindex' and 'iflink' values. + */ + +int dev_get_iflink(const struct net_device *dev) +{ +	if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) +		return dev->netdev_ops->ndo_get_iflink(dev); + +	/* If dev->rtnl_link_ops is set, it's a virtual interface. */ +	if (dev->rtnl_link_ops) +		return 0; + +	return dev->ifindex; +} +EXPORT_SYMBOL(dev_get_iflink); + +/**   *	__dev_get_by_name	- find a device by its name   *	@net: the applicable net namespace   *	@name: name to find @@ -946,7 +967,7 @@ bool dev_valid_name(const char *name)  		return false;  	while (*name) { -		if (*name == '/' || isspace(*name)) +		if (*name == '/' || *name == ':' || isspace(*name))  			return false;  		name++;  	} @@ -1385,7 +1406,7 @@ static int __dev_close(struct net_device *dev)  	return retval;  } -static int dev_close_many(struct list_head *head) +int dev_close_many(struct list_head *head, bool unlink)  {  	struct net_device *dev, *tmp; @@ -1399,11 +1420,13 @@ static int dev_close_many(struct list_head *head)  	list_for_each_entry_safe(dev, tmp, head, close_list) {  		rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL);  		call_netdevice_notifiers(NETDEV_DOWN, dev); -		list_del_init(&dev->close_list); +		if (unlink) +			list_del_init(&dev->close_list);  	}  	return 0;  } +EXPORT_SYMBOL(dev_close_many);  /**   *	dev_close - shutdown an interface. @@ -1420,7 +1443,7 @@ int dev_close(struct net_device *dev)  		LIST_HEAD(single);  		list_add(&dev->close_list, &single); -		dev_close_many(&single); +		dev_close_many(&single, true);  		list_del(&single);  	}  	return 0; @@ -1607,6 +1630,22 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev)  }  EXPORT_SYMBOL(call_netdevice_notifiers); +#ifdef CONFIG_NET_CLS_ACT +static struct static_key ingress_needed __read_mostly; + +void net_inc_ingress_queue(void) +{ +	static_key_slow_inc(&ingress_needed); +} +EXPORT_SYMBOL_GPL(net_inc_ingress_queue); + +void net_dec_ingress_queue(void) +{ +	static_key_slow_dec(&ingress_needed); +} +EXPORT_SYMBOL_GPL(net_dec_ingress_queue); +#endif +  static struct static_key netstamp_needed __read_mostly;  #ifdef HAVE_JUMP_LABEL  /* We are not allowed to call static_key_slow_dec() from irq context @@ -1694,6 +1733,7 @@ int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)  	}  	skb_scrub_packet(skb, true); +	skb->priority = 0;  	skb->protocol = eth_type_trans(skb, dev);  	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); @@ -1737,7 +1777,8 @@ static inline int deliver_skb(struct sk_buff *skb,  static inline void deliver_ptype_list_skb(struct sk_buff *skb,  					  struct packet_type **pt, -					  struct net_device *dev, __be16 type, +					  struct net_device *orig_dev, +					  __be16 type,  					  struct list_head *ptype_list)  {  	struct packet_type *ptype, *pt_prev = *pt; @@ -1746,7 +1787,7 @@ static inline void deliver_ptype_list_skb(struct sk_buff *skb,  		if (ptype->type != type)  			continue;  		if (pt_prev) -			deliver_skb(skb, pt_prev, dev); +			deliver_skb(skb, pt_prev, orig_dev);  		pt_prev = ptype;  	}  	*pt = pt_prev; @@ -2559,12 +2600,26 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,  	return features;  } +netdev_features_t passthru_features_check(struct sk_buff *skb, +					  struct net_device *dev, +					  netdev_features_t features) +{ +	return features; +} +EXPORT_SYMBOL(passthru_features_check); + +static netdev_features_t dflt_features_check(const struct sk_buff *skb, +					     struct net_device *dev, +					     netdev_features_t features) +{ +	return vlan_features_check(skb, features); +} +  netdev_features_t netif_skb_features(struct sk_buff *skb)  {  	struct net_device *dev = skb->dev;  	netdev_features_t features = dev->features;  	u16 gso_segs = skb_shinfo(skb)->gso_segs; -	__be16 protocol = skb->protocol;  	if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)  		features &= ~NETIF_F_GSO_MASK; @@ -2576,34 +2631,17 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)  	if (skb->encapsulation)  		features &= dev->hw_enc_features; -	if (!skb_vlan_tag_present(skb)) { -		if (unlikely(protocol == htons(ETH_P_8021Q) || -			     protocol == htons(ETH_P_8021AD))) { -			struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; -			protocol = veh->h_vlan_encapsulated_proto; -		} else { -			goto finalize; -		} -	} - -	features = netdev_intersect_features(features, -					     dev->vlan_features | -					     NETIF_F_HW_VLAN_CTAG_TX | -					     NETIF_F_HW_VLAN_STAG_TX); - -	if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) +	if (skb_vlan_tagged(skb))  		features = netdev_intersect_features(features, -						     NETIF_F_SG | -						     NETIF_F_HIGHDMA | -						     NETIF_F_FRAGLIST | -						     NETIF_F_GEN_CSUM | +						     dev->vlan_features |  						     NETIF_F_HW_VLAN_CTAG_TX |  						     NETIF_F_HW_VLAN_STAG_TX); -finalize:  	if (dev->netdev_ops->ndo_features_check)  		features &= dev->netdev_ops->ndo_features_check(skb, dev,  								features); +	else +		features &= dflt_features_check(skb, dev, features);  	return harmonize_features(skb, features);  } @@ -2675,7 +2713,7 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device  	if (unlikely(!skb))  		goto out_null; -	if (netif_needs_gso(dev, skb, features)) { +	if (netif_needs_gso(skb, features)) {  		struct sk_buff *segs;  		segs = skb_gso_segment(skb, features); @@ -2848,14 +2886,16 @@ static void skb_update_prio(struct sk_buff *skb)  #define skb_update_prio(skb)  #endif -static DEFINE_PER_CPU(int, xmit_recursion); +DEFINE_PER_CPU(int, xmit_recursion); +EXPORT_SYMBOL(xmit_recursion); +  #define RECURSION_LIMIT 10  /**   *	dev_loopback_xmit - loop back @skb   *	@skb: buffer to transmit   */ -int dev_loopback_xmit(struct sk_buff *skb) +int dev_loopback_xmit(struct sock *sk, struct sk_buff *skb)  {  	skb_reset_mac_header(skb);  	__skb_pull(skb, skb_network_offset(skb)); @@ -2993,11 +3033,11 @@ out:  	return rc;  } -int dev_queue_xmit(struct sk_buff *skb) +int dev_queue_xmit_sk(struct sock *sk, struct sk_buff *skb)  {  	return __dev_queue_xmit(skb, NULL);  } -EXPORT_SYMBOL(dev_queue_xmit); +EXPORT_SYMBOL(dev_queue_xmit_sk);  int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv)  { @@ -3523,7 +3563,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,  	struct netdev_queue *rxq = rcu_dereference(skb->dev->ingress_queue);  	if (!rxq || rcu_access_pointer(rxq->qdisc) == &noop_qdisc) -		goto out; +		return skb;  	if (*pt_prev) {  		*ret = deliver_skb(skb, *pt_prev, orig_dev); @@ -3537,8 +3577,6 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,  		return NULL;  	} -out: -	skb->tc_verd = 0;  	return skb;  }  #endif @@ -3674,12 +3712,15 @@ another_round:  skip_taps:  #ifdef CONFIG_NET_CLS_ACT -	skb = handle_ing(skb, &pt_prev, &ret, orig_dev); -	if (!skb) -		goto unlock; +	if (static_key_false(&ingress_needed)) { +		skb = handle_ing(skb, &pt_prev, &ret, orig_dev); +		if (!skb) +			goto unlock; +	} + +	skb->tc_verd = 0;  ncls:  #endif -  	if (pfmemalloc && !skb_pfmemalloc_protocol(skb))  		goto drop; @@ -3829,13 +3870,13 @@ static int netif_receive_skb_internal(struct sk_buff *skb)   *	NET_RX_SUCCESS: no congestion   *	NET_RX_DROP: packet was dropped   */ -int netif_receive_skb(struct sk_buff *skb) +int netif_receive_skb_sk(struct sock *sk, struct sk_buff *skb)  {  	trace_netif_receive_skb_entry(skb);  	return netif_receive_skb_internal(skb);  } -EXPORT_SYMBOL(netif_receive_skb); +EXPORT_SYMBOL(netif_receive_skb_sk);  /* Network device is going away, flush any packets still pending   * Called with irqs disabled. @@ -5912,6 +5953,24 @@ int dev_get_phys_port_id(struct net_device *dev,  EXPORT_SYMBOL(dev_get_phys_port_id);  /** + *	dev_get_phys_port_name - Get device physical port name + *	@dev: device + *	@name: port name + * + *	Get device physical port name + */ +int dev_get_phys_port_name(struct net_device *dev, +			   char *name, size_t len) +{ +	const struct net_device_ops *ops = dev->netdev_ops; + +	if (!ops->ndo_get_phys_port_name) +		return -EOPNOTSUPP; +	return ops->ndo_get_phys_port_name(dev, name, len); +} +EXPORT_SYMBOL(dev_get_phys_port_name); + +/**   *	dev_new_index	-	allocate an ifindex   *	@net: the applicable net namespace   * @@ -5968,7 +6027,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(&close_head, true);  	list_for_each_entry(dev, head, unreg_list) {  		/* And unlink it from device chain. */ @@ -6295,8 +6354,6 @@ int register_netdevice(struct net_device *dev)  	spin_lock_init(&dev->addr_list_lock);  	netdev_set_addr_lockdep_class(dev); -	dev->iflink = -1; -  	ret = dev_get_valid_name(net, dev, dev->name);  	if (ret < 0)  		goto out; @@ -6326,9 +6383,6 @@ int register_netdevice(struct net_device *dev)  	else if (__dev_get_by_index(net, dev->ifindex))  		goto err_uninit; -	if (dev->iflink == -1) -		dev->iflink = dev->ifindex; -  	/* Transfer changeable features to wanted_features and enable  	 * software offloads (GSO and GRO).  	 */ @@ -6841,8 +6895,6 @@ void free_netdev(struct net_device *dev)  {  	struct napi_struct *p, *n; -	release_net(dev_net(dev)); -  	netif_free_tx_queues(dev);  #ifdef CONFIG_SYSFS  	kvfree(dev->_rx); @@ -7043,12 +7095,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  	dev_net_set(dev, net);  	/* If there is an ifindex conflict assign a new one */ -	if (__dev_get_by_index(net, dev->ifindex)) { -		int iflink = (dev->iflink == dev->ifindex); +	if (__dev_get_by_index(net, dev->ifindex))  		dev->ifindex = dev_new_index(net); -		if (iflink) -			dev->iflink = dev->ifindex; -	}  	/* Send a netdev-add uevent to the new namespace */  	kobject_uevent(&dev->dev.kobj, KOBJ_ADD);  |