diff options
Diffstat (limited to 'drivers/net/geneve.c')
| -rw-r--r-- | drivers/net/geneve.c | 84 | 
1 files changed, 53 insertions, 31 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index da3259ce7c8d..445071c163cb 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -126,6 +126,8 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)  	__be32 addr;  	int err; +	iph = ip_hdr(skb); /* outer IP header... */ +  	if (gs->collect_md) {  		static u8 zero_vni[3]; @@ -133,7 +135,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)  		addr = 0;  	} else {  		vni = gnvh->vni; -		iph = ip_hdr(skb); /* Still outer IP header... */  		addr = iph->saddr;  	} @@ -178,7 +179,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)  	skb_reset_network_header(skb); -	iph = ip_hdr(skb); /* Now inner IP header... */  	err = IP_ECN_decapsulate(iph, skb);  	if (unlikely(err)) { @@ -594,14 +594,12 @@ static struct rtable *geneve_get_rt(struct sk_buff *skb,  	rt = ip_route_output_key(geneve->net, fl4);  	if (IS_ERR(rt)) {  		netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr); -		dev->stats.tx_carrier_errors++; -		return rt; +		return ERR_PTR(-ENETUNREACH);  	}  	if (rt->dst.dev == dev) { /* is this necessary? */  		netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr); -		dev->stats.collisions++;  		ip_rt_put(rt); -		return ERR_PTR(-EINVAL); +		return ERR_PTR(-ELOOP);  	}  	return rt;  } @@ -626,12 +624,13 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)  	struct geneve_sock *gs = geneve->sock;  	struct ip_tunnel_info *info = NULL;  	struct rtable *rt = NULL; +	const struct iphdr *iip; /* interior IP header */ +	int err = -EINVAL;  	struct flowi4 fl4;  	__u8 tos, ttl;  	__be16 sport;  	bool udp_csum;  	__be16 df; -	int err;  	if (geneve->collect_md) {  		info = skb_tunnel_info(skb); @@ -646,13 +645,15 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)  	rt = geneve_get_rt(skb, dev, &fl4, info);  	if (IS_ERR(rt)) {  		netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); -		dev->stats.tx_carrier_errors++; +		err = PTR_ERR(rt);  		goto tx_error;  	}  	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);  	skb_reset_mac_header(skb); +	iip = ip_hdr(skb); +  	if (info) {  		const struct ip_tunnel_key *key = &info->key;  		u8 *opts = NULL; @@ -668,19 +669,16 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)  		if (unlikely(err))  			goto err; -		tos = key->tos; +		tos = ip_tunnel_ecn_encap(key->tos, iip, skb);  		ttl = key->ttl;  		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;  	} else { -		const struct iphdr *iip; /* interior IP header */ -  		udp_csum = false;  		err = geneve_build_skb(rt, skb, 0, geneve->vni,  				       0, NULL, udp_csum);  		if (unlikely(err))  			goto err; -		iip = ip_hdr(skb);  		tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb);  		ttl = geneve->ttl;  		if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) @@ -699,10 +697,37 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)  tx_error:  	dev_kfree_skb(skb);  err: -	dev->stats.tx_errors++; +	if (err == -ELOOP) +		dev->stats.collisions++; +	else if (err == -ENETUNREACH) +		dev->stats.tx_carrier_errors++; +	else +		dev->stats.tx_errors++;  	return NETDEV_TX_OK;  } +static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) +{ +	struct ip_tunnel_info *info = skb_tunnel_info(skb); +	struct geneve_dev *geneve = netdev_priv(dev); +	struct rtable *rt; +	struct flowi4 fl4; + +	if (ip_tunnel_info_af(info) != AF_INET) +		return -EINVAL; + +	rt = geneve_get_rt(skb, dev, &fl4, info); +	if (IS_ERR(rt)) +		return PTR_ERR(rt); + +	ip_rt_put(rt); +	info->key.u.ipv4.src = fl4.saddr; +	info->key.tp_src = udp_flow_src_port(geneve->net, skb, +					     1, USHRT_MAX, true); +	info->key.tp_dst = geneve->dst_port; +	return 0; +} +  static const struct net_device_ops geneve_netdev_ops = {  	.ndo_init		= geneve_init,  	.ndo_uninit		= geneve_uninit, @@ -713,6 +738,7 @@ static const struct net_device_ops geneve_netdev_ops = {  	.ndo_change_mtu		= eth_change_mtu,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_mac_address	= eth_mac_addr, +	.ndo_fill_metadata_dst	= geneve_fill_metadata_dst,  };  static void geneve_get_drvinfo(struct net_device *dev, @@ -748,12 +774,8 @@ static void geneve_setup(struct net_device *dev)  	dev->features    |= NETIF_F_RXCSUM;  	dev->features    |= NETIF_F_GSO_SOFTWARE; -	dev->vlan_features = dev->features; -	dev->features    |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; -  	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;  	dev->hw_features |= NETIF_F_GSO_SOFTWARE; -	dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;  	netif_keep_dst(dev);  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; @@ -819,7 +841,7 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,  static int geneve_configure(struct net *net, struct net_device *dev,  			    __be32 rem_addr, __u32 vni, __u8 ttl, __u8 tos, -			    __u16 dst_port, bool metadata) +			    __be16 dst_port, bool metadata)  {  	struct geneve_net *gn = net_generic(net, geneve_net_id);  	struct geneve_dev *t, *geneve = netdev_priv(dev); @@ -844,10 +866,10 @@ static int geneve_configure(struct net *net, struct net_device *dev,  	geneve->ttl = ttl;  	geneve->tos = tos; -	geneve->dst_port = htons(dst_port); +	geneve->dst_port = dst_port;  	geneve->collect_md = metadata; -	t = geneve_find_dev(gn, htons(dst_port), rem_addr, geneve->vni, +	t = geneve_find_dev(gn, dst_port, rem_addr, geneve->vni,  			    &tun_on_same_port, &tun_collect_md);  	if (t)  		return -EBUSY; @@ -871,17 +893,17 @@ static int geneve_configure(struct net *net, struct net_device *dev,  static int geneve_newlink(struct net *net, struct net_device *dev,  			  struct nlattr *tb[], struct nlattr *data[])  { -	__u16 dst_port = GENEVE_UDP_PORT; +	__be16 dst_port = htons(GENEVE_UDP_PORT);  	__u8 ttl = 0, tos = 0;  	bool metadata = false; -	__be32 rem_addr; -	__u32 vni; +	__be32 rem_addr = 0; +	__u32 vni = 0; -	if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE]) -		return -EINVAL; +	if (data[IFLA_GENEVE_ID]) +		vni = nla_get_u32(data[IFLA_GENEVE_ID]); -	vni = nla_get_u32(data[IFLA_GENEVE_ID]); -	rem_addr = nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); +	if (data[IFLA_GENEVE_REMOTE]) +		rem_addr = nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);  	if (data[IFLA_GENEVE_TTL])  		ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); @@ -890,7 +912,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev,  		tos = nla_get_u8(data[IFLA_GENEVE_TOS]);  	if (data[IFLA_GENEVE_PORT]) -		dst_port = nla_get_u16(data[IFLA_GENEVE_PORT]); +		dst_port = nla_get_be16(data[IFLA_GENEVE_PORT]);  	if (data[IFLA_GENEVE_COLLECT_METADATA])  		metadata = true; @@ -913,7 +935,7 @@ static size_t geneve_get_size(const struct net_device *dev)  		nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */  		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */  		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */ -		nla_total_size(sizeof(__u16)) +  /* IFLA_GENEVE_PORT */ +		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */  		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */  		0;  } @@ -935,7 +957,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)  	    nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos))  		goto nla_put_failure; -	if (nla_put_u16(skb, IFLA_GENEVE_PORT, ntohs(geneve->dst_port))) +	if (nla_put_be16(skb, IFLA_GENEVE_PORT, geneve->dst_port))  		goto nla_put_failure;  	if (geneve->collect_md) { @@ -975,7 +997,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,  	if (IS_ERR(dev))  		return dev; -	err = geneve_configure(net, dev, 0, 0, 0, 0, dst_port, true); +	err = geneve_configure(net, dev, 0, 0, 0, 0, htons(dst_port), true);  	if (err) {  		free_netdev(dev);  		return ERR_PTR(err);  | 
