diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 120 | 
1 files changed, 68 insertions, 52 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index b24ab0e98eb..4040673f806 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -200,7 +200,7 @@ static inline void rps_unlock(struct softnet_data *sd)  }  /* Device list insertion */ -static int list_netdevice(struct net_device *dev) +static void list_netdevice(struct net_device *dev)  {  	struct net *net = dev_net(dev); @@ -214,8 +214,6 @@ static int list_netdevice(struct net_device *dev)  	write_unlock_bh(&dev_base_lock);  	dev_base_seq_inc(net); - -	return 0;  }  /* Device list removal @@ -2210,30 +2208,40 @@ out:  }  EXPORT_SYMBOL(skb_checksum_help); -/** - *	skb_mac_gso_segment - mac layer segmentation handler. - *	@skb: buffer to segment - *	@features: features for the output path (see dev->features) - */ -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, -				    netdev_features_t features) +__be16 skb_network_protocol(struct sk_buff *skb)  { -	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); -	struct packet_offload *ptype;  	__be16 type = skb->protocol;  	int vlan_depth = ETH_HLEN; -	while (type == htons(ETH_P_8021Q)) { +	while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {  		struct vlan_hdr *vh;  		if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) -			return ERR_PTR(-EINVAL); +			return 0;  		vh = (struct vlan_hdr *)(skb->data + vlan_depth);  		type = vh->h_vlan_encapsulated_proto;  		vlan_depth += VLAN_HLEN;  	} +	return type; +} + +/** + *	skb_mac_gso_segment - mac layer segmentation handler. + *	@skb: buffer to segment + *	@features: features for the output path (see dev->features) + */ +struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, +				    netdev_features_t features) +{ +	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); +	struct packet_offload *ptype; +	__be16 type = skb_network_protocol(skb); + +	if (unlikely(!type)) +		return ERR_PTR(-EINVAL); +  	__skb_pull(skb, skb->mac_len);  	rcu_read_lock(); @@ -2400,24 +2408,12 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)  	return 0;  } -static bool can_checksum_protocol(netdev_features_t features, __be16 protocol) -{ -	return ((features & NETIF_F_GEN_CSUM) || -		((features & NETIF_F_V4_CSUM) && -		 protocol == htons(ETH_P_IP)) || -		((features & NETIF_F_V6_CSUM) && -		 protocol == htons(ETH_P_IPV6)) || -		((features & NETIF_F_FCOE_CRC) && -		 protocol == htons(ETH_P_FCOE))); -} -  static netdev_features_t harmonize_features(struct sk_buff *skb,  	__be16 protocol, netdev_features_t features)  {  	if (skb->ip_summed != CHECKSUM_NONE &&  	    !can_checksum_protocol(features, protocol)) {  		features &= ~NETIF_F_ALL_CSUM; -		features &= ~NETIF_F_SG;  	} else if (illegal_highdma(skb->dev, skb)) {  		features &= ~NETIF_F_SG;  	} @@ -2433,20 +2429,22 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)  	if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)  		features &= ~NETIF_F_GSO_MASK; -	if (protocol == htons(ETH_P_8021Q)) { +	if (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 if (!vlan_tx_tag_present(skb)) {  		return harmonize_features(skb, protocol, features);  	} -	features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX); +	features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | +					       NETIF_F_HW_VLAN_STAG_TX); -	if (protocol != htons(ETH_P_8021Q)) { +	if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) {  		return harmonize_features(skb, protocol, features);  	} else {  		features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | -				NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX; +				NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | +				NETIF_F_HW_VLAN_STAG_TX;  		return harmonize_features(skb, protocol, features);  	}  } @@ -2487,8 +2485,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,  		features = netif_skb_features(skb);  		if (vlan_tx_tag_present(skb) && -		    !(features & NETIF_F_HW_VLAN_TX)) { -			skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); +		    !vlan_hw_offload_capable(features, skb->vlan_proto)) { +			skb = __vlan_put_tag(skb, skb->vlan_proto, +					     vlan_tx_tag_get(skb));  			if (unlikely(!skb))  				goto out; @@ -2547,13 +2546,6 @@ gso:  		skb->next = nskb->next;  		nskb->next = NULL; -		/* -		 * If device doesn't need nskb->dst, release it right now while -		 * its hot in this cpu cache -		 */ -		if (dev->priv_flags & IFF_XMIT_DST_RELEASE) -			skb_dst_drop(nskb); -  		if (!list_empty(&ptype_all))  			dev_queue_xmit_nit(nskb, dev); @@ -2573,8 +2565,11 @@ gso:  	} while (skb->next);  out_kfree_gso_skb: -	if (likely(skb->next == NULL)) +	if (likely(skb->next == NULL)) {  		skb->destructor = DEV_GSO_CB(skb)->destructor; +		consume_skb(skb); +		return rc; +	}  out_kfree_skb:  	kfree_skb(skb);  out: @@ -2592,6 +2587,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)  	 */  	if (shinfo->gso_size)  {  		unsigned int hdr_len; +		u16 gso_segs = shinfo->gso_segs;  		/* mac layer + network layer */  		hdr_len = skb_transport_header(skb) - skb_mac_header(skb); @@ -2601,7 +2597,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)  			hdr_len += tcp_hdrlen(skb);  		else  			hdr_len += sizeof(struct udphdr); -		qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len; + +		if (shinfo->gso_type & SKB_GSO_DODGY) +			gso_segs = DIV_ROUND_UP(skb->len - hdr_len, +						shinfo->gso_size); + +		qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;  	}  } @@ -3329,7 +3330,7 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_register);   *	netdev_rx_handler_unregister - unregister receive handler   *	@dev: device to unregister a handler from   * - *	Unregister a receive hander from a device. + *	Unregister a receive handler from a device.   *   *	The caller must hold the rtnl_mutex.   */ @@ -3358,6 +3359,7 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb)  	case __constant_htons(ETH_P_IP):  	case __constant_htons(ETH_P_IPV6):  	case __constant_htons(ETH_P_8021Q): +	case __constant_htons(ETH_P_8021AD):  		return true;  	default:  		return false; @@ -3398,7 +3400,8 @@ another_round:  	__this_cpu_inc(softnet_data.processed); -	if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { +	if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || +	    skb->protocol == cpu_to_be16(ETH_P_8021AD)) {  		skb = vlan_untag(skb);  		if (unlikely(!skb))  			goto unlock; @@ -4066,6 +4069,9 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,  	napi->gro_list = NULL;  	napi->skb = NULL;  	napi->poll = poll; +	if (weight > NAPI_POLL_WEIGHT) +		pr_err_once("netif_napi_add() called with weight %d on device %s\n", +			    weight, dev->name);  	napi->weight = weight;  	list_add(&napi->dev_list, &dev->napi_list);  	napi->dev = dev; @@ -4927,20 +4933,25 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,  		features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);  	} -	/* Fix illegal SG+CSUM combinations. */ -	if ((features & NETIF_F_SG) && -	    !(features & NETIF_F_ALL_CSUM)) { -		netdev_dbg(dev, -			"Dropping NETIF_F_SG since no checksum feature.\n"); -		features &= ~NETIF_F_SG; -	} -  	/* TSO requires that SG is present as well. */  	if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {  		netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");  		features &= ~NETIF_F_ALL_TSO;  	} +	if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) && +					!(features & NETIF_F_IP_CSUM)) { +		netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n"); +		features &= ~NETIF_F_TSO; +		features &= ~NETIF_F_TSO_ECN; +	} + +	if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) && +					 !(features & NETIF_F_IPV6_CSUM)) { +		netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n"); +		features &= ~NETIF_F_TSO6; +	} +  	/* TSO ECN requires that TSO is present as well. */  	if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)  		features &= ~NETIF_F_TSO_ECN; @@ -5171,7 +5182,8 @@ int register_netdevice(struct net_device *dev)  		}  	} -	if (((dev->hw_features | dev->features) & NETIF_F_HW_VLAN_FILTER) && +	if (((dev->hw_features | dev->features) & +	     NETIF_F_HW_VLAN_CTAG_FILTER) &&  	    (!dev->netdev_ops->ndo_vlan_rx_add_vid ||  	     !dev->netdev_ops->ndo_vlan_rx_kill_vid)) {  		netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n"); @@ -5208,6 +5220,10 @@ int register_netdevice(struct net_device *dev)  	 */  	dev->vlan_features |= NETIF_F_HIGHDMA; +	/* Make NETIF_F_SG inheritable to tunnel devices. +	 */ +	dev->hw_enc_features |= NETIF_F_SG; +  	ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);  	ret = notifier_to_errno(ret);  	if (ret)  |