Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30bbaa19 authored by David Ahern's avatar David Ahern Committed by David S. Miller
Browse files

net: Fix up inet_addr_type checks



Currently inet_addr_type and inet_dev_addr_type expect local addresses
to be in the local table. With the VRF device local routes for devices
associated with a VRF will be in the table associated with the VRF.
Provide an alternate inet_addr lookup to use a specific table rather
than defaulting to the local table.

inet_addr_type_dev_table keeps the same semantics as inet_addr_type but
if the passed in device is enslaved to a VRF then the table for that VRF
is used for the lookup.

Signed-off-by: default avatarDavid Ahern <dsa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15be405e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -192,6 +192,9 @@ unsigned int inet_addr_type(struct net *net, __be32 addr);
unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id);
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
				__be32 addr);
unsigned int inet_addr_type_dev_table(struct net *net,
				      const struct net_device *dev,
				      __be32 addr);
void ip_rt_multicast_event(struct in_device *);
int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
+12 −1
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
#include <net/vrf.h>


/* The inetsw table contains everything that inet_create needs to
@@ -427,6 +428,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
	struct net *net = sock_net(sk);
	unsigned short snum;
	int chk_addr_ret;
	int tb_id = RT_TABLE_LOCAL;
	int err;

	/* If the socket has its own bind function then use it. (RAW) */
@@ -448,7 +450,16 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
			goto out;
	}

	chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
	if (sk->sk_bound_dev_if) {
		struct net_device *dev;

		rcu_read_lock();
		dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
		if (dev)
			tb_id = vrf_dev_table_rcu(dev) ? : tb_id;
		rcu_read_unlock();
	}
	chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);

	/* Not specified by any standard per-se, however it breaks too
	 * many applications when removed.  It is unfortunate since
+9 −6
Original line number Diff line number Diff line
@@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)
		return -EINVAL;
	}

	neigh->type = inet_addr_type(dev_net(dev), addr);
	neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);

	parms = in_dev->arp_parms;
	__neigh_parms_put(neigh->parms);
@@ -343,7 +343,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
	default:
	case 0:		/* By default announce any local IP */
		if (skb && inet_addr_type(dev_net(dev),
		if (skb && inet_addr_type_dev_table(dev_net(dev), dev,
					  ip_hdr(skb)->saddr) == RTN_LOCAL)
			saddr = ip_hdr(skb)->saddr;
		break;
@@ -351,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
		if (!skb)
			break;
		saddr = ip_hdr(skb)->saddr;
		if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) {
		if (inet_addr_type_dev_table(dev_net(dev), dev,
					     saddr) == RTN_LOCAL) {
			/* saddr should be known to target */
			if (inet_addr_onlink(in_dev, target, saddr))
				break;
@@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
	if (sip == 0) {
		if (arp->ar_op == htons(ARPOP_REQUEST) &&
		    inet_addr_type(net, tip) == RTN_LOCAL &&
		    inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
		    !arp_ignore(in_dev, sip, tip))
			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
				 dev->dev_addr, sha);
@@ -811,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

	if (IN_DEV_ARP_ACCEPT(in_dev)) {
		unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);

		/* Unsolicited ARP is not accepted by default.
		   It is possible, that this option should be enabled for some
		   devices (strip is candidate)
		 */
		is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
			  inet_addr_type(net, sip) == RTN_UNICAST;
			  addr_type == RTN_UNICAST;

		if (!n &&
		    ((arp->ar_op == htons(ARPOP_REPLY)  &&
		      inet_addr_type(net, sip) == RTN_UNICAST) || is_garp))
				addr_type == RTN_UNICAST) || is_garp))
			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
	}

+22 −3
Original line number Diff line number Diff line
@@ -260,6 +260,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
}
EXPORT_SYMBOL(inet_dev_addr_type);

/* inet_addr_type with dev == NULL but using the table from a dev
 * if one is associated
 */
unsigned int inet_addr_type_dev_table(struct net *net,
				      const struct net_device *dev,
				      __be32 addr)
{
	int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;

	return __inet_dev_addr_type(net, NULL, addr, rt_table);
}
EXPORT_SYMBOL(inet_addr_type_dev_table);

__be32 fib_compute_spec_dst(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
@@ -510,9 +523,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,

	addr = sk_extract_addr(&rt->rt_gateway);
	if (rt->rt_gateway.sa_family == AF_INET && addr) {
		unsigned int addr_type;

		cfg->fc_gw = addr;
		addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
		if (rt->rt_flags & RTF_GATEWAY &&
		    inet_addr_type(net, addr) == RTN_UNICAST)
		    addr_type == RTN_UNICAST)
			cfg->fc_scope = RT_SCOPE_UNIVERSE;
	}

@@ -984,11 +1000,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
			fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
	}
	if (!(ok & LOCAL_OK)) {
		unsigned int addr_type;

		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);

		/* Check, that this local address finally disappeared. */
		if (gone &&
		    inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
		addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
						     ifa->ifa_local);
		if (gone && addr_type != RTN_LOCAL) {
			/* And the last, but not the least thing.
			 * We must flush stray FIB entries.
			 *
+4 −2
Original line number Diff line number Diff line
@@ -670,16 +670,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
		struct fib_result res;

		if (nh->nh_flags & RTNH_F_ONLINK) {
			unsigned int addr_type;

			if (cfg->fc_scope >= RT_SCOPE_LINK)
				return -EINVAL;
			if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
				return -EINVAL;
			dev = __dev_get_by_index(net, nh->nh_oif);
			if (!dev)
				return -ENODEV;
			if (!(dev->flags & IFF_UP))
				return -ENETDOWN;
			addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw);
			if (addr_type != RTN_UNICAST)
				return -EINVAL;
			if (!netif_carrier_ok(dev))
				nh->nh_flags |= RTNH_F_LINKDOWN;
			nh->nh_dev = dev;
Loading