diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 16 | ||||
| -rw-r--r-- | net/core/skbuff.c | 1 | ||||
| -rw-r--r-- | net/core/sock.c | 71 | 
3 files changed, 83 insertions, 5 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index c253c2aafe97..64b21f0a2048 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6008,6 +6008,19 @@ static void gro_list_prepare(const struct list_head *head,  			diffs = memcmp(skb_mac_header(p),  				       skb_mac_header(skb),  				       maclen); + +		diffs |= skb_get_nfct(p) ^ skb_get_nfct(skb); +#if IS_ENABLED(CONFIG_SKB_EXTENSIONS) && IS_ENABLED(CONFIG_NET_TC_SKB_EXT) +		if (!diffs) { +			struct tc_skb_ext *skb_ext = skb_ext_find(skb, TC_SKB_EXT); +			struct tc_skb_ext *p_ext = skb_ext_find(p, TC_SKB_EXT); + +			diffs |= (!!p_ext) ^ (!!skb_ext); +			if (!diffs && unlikely(skb_ext)) +				diffs |= p_ext->chain ^ skb_ext->chain; +		} +#endif +  		NAPI_GRO_CB(p)->same_flow = !diffs;  	}  } @@ -6221,6 +6234,8 @@ static gro_result_t napi_skb_finish(struct napi_struct *napi,  	case GRO_MERGED_FREE:  		if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)  			napi_skb_free_stolen_head(skb); +		else if (skb->fclone != SKB_FCLONE_UNAVAILABLE) +			__kfree_skb(skb);  		else  			__kfree_skb_defer(skb);  		break; @@ -6270,6 +6285,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)  	skb_shinfo(skb)->gso_type = 0;  	skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));  	skb_ext_reset(skb); +	nf_reset_ct(skb);  	napi->skb = skb;  } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 12aabcda6db2..f63de967ac25 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -943,6 +943,7 @@ void __kfree_skb_defer(struct sk_buff *skb)  void napi_skb_free_stolen_head(struct sk_buff *skb)  { +	nf_reset_ct(skb);  	skb_dst_drop(skb);  	skb_ext_put(skb);  	napi_skb_cache_put(skb); diff --git a/net/core/sock.c b/net/core/sock.c index ba1c0f75cd45..a3eea6e0b30a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -139,6 +139,8 @@  #include <net/tcp.h>  #include <net/busy_poll.h> +#include <linux/ethtool.h> +  static DEFINE_MUTEX(proto_list_mutex);  static LIST_HEAD(proto_list); @@ -810,8 +812,47 @@ void sock_set_timestamp(struct sock *sk, int optname, bool valbool)  	}  } -int sock_set_timestamping(struct sock *sk, int optname, int val) +static int sock_timestamping_bind_phc(struct sock *sk, int phc_index) +{ +	struct net *net = sock_net(sk); +	struct net_device *dev = NULL; +	bool match = false; +	int *vclock_index; +	int i, num; + +	if (sk->sk_bound_dev_if) +		dev = dev_get_by_index(net, sk->sk_bound_dev_if); + +	if (!dev) { +		pr_err("%s: sock not bind to device\n", __func__); +		return -EOPNOTSUPP; +	} + +	num = ethtool_get_phc_vclocks(dev, &vclock_index); +	for (i = 0; i < num; i++) { +		if (*(vclock_index + i) == phc_index) { +			match = true; +			break; +		} +	} + +	if (num > 0) +		kfree(vclock_index); + +	if (!match) +		return -EINVAL; + +	sk->sk_bind_phc = phc_index; + +	return 0; +} + +int sock_set_timestamping(struct sock *sk, int optname, +			  struct so_timestamping timestamping)  { +	int val = timestamping.flags; +	int ret; +  	if (val & ~SOF_TIMESTAMPING_MASK)  		return -EINVAL; @@ -832,6 +873,12 @@ int sock_set_timestamping(struct sock *sk, int optname, int val)  	    !(val & SOF_TIMESTAMPING_OPT_TSONLY))  		return -EINVAL; +	if (val & SOF_TIMESTAMPING_BIND_PHC) { +		ret = sock_timestamping_bind_phc(sk, timestamping.bind_phc); +		if (ret) +			return ret; +	} +  	sk->sk_tsflags = val;  	sock_valbool_flag(sk, SOCK_TSTAMP_NEW, optname == SO_TIMESTAMPING_NEW); @@ -907,6 +954,7 @@ EXPORT_SYMBOL(sock_set_mark);  int sock_setsockopt(struct socket *sock, int level, int optname,  		    sockptr_t optval, unsigned int optlen)  { +	struct so_timestamping timestamping;  	struct sock_txtime sk_txtime;  	struct sock *sk = sock->sk;  	int val; @@ -1068,12 +1116,22 @@ set_sndbuf:  	case SO_TIMESTAMP_NEW:  	case SO_TIMESTAMPNS_OLD:  	case SO_TIMESTAMPNS_NEW: -		sock_set_timestamp(sk, valbool, optname); +		sock_set_timestamp(sk, optname, valbool);  		break;  	case SO_TIMESTAMPING_NEW:  	case SO_TIMESTAMPING_OLD: -		ret = sock_set_timestamping(sk, optname, val); +		if (optlen == sizeof(timestamping)) { +			if (copy_from_sockptr(×tamping, optval, +					      sizeof(timestamping))) { +				ret = -EFAULT; +				break; +			} +		} else { +			memset(×tamping, 0, sizeof(timestamping)); +			timestamping.flags = val; +		} +		ret = sock_set_timestamping(sk, optname, timestamping);  		break;  	case SO_RCVLOWAT: @@ -1201,7 +1259,7 @@ set_sndbuf:  			if (val < 0)  				ret = -EINVAL;  			else -				sk->sk_ll_usec = val; +				WRITE_ONCE(sk->sk_ll_usec, val);  		}  		break;  	case SO_PREFER_BUSY_POLL: @@ -1348,6 +1406,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,  		struct __kernel_old_timeval tm;  		struct  __kernel_sock_timeval stm;  		struct sock_txtime txtime; +		struct so_timestamping timestamping;  	} v;  	int lv = sizeof(int); @@ -1451,7 +1510,9 @@ int sock_getsockopt(struct socket *sock, int level, int optname,  		break;  	case SO_TIMESTAMPING_OLD: -		v.val = sk->sk_tsflags; +		lv = sizeof(v.timestamping); +		v.timestamping.flags = sk->sk_tsflags; +		v.timestamping.bind_phc = sk->sk_bind_phc;  		break;  	case SO_RCVTIMEO_OLD: |