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: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
15be405eb2
commit
30bbaa1950
@ -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_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,
|
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
|
||||||
__be32 addr);
|
__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 *);
|
void ip_rt_multicast_event(struct in_device *);
|
||||||
int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
|
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);
|
void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
|
||||||
|
@ -119,6 +119,7 @@
|
|||||||
#ifdef CONFIG_IP_MROUTE
|
#ifdef CONFIG_IP_MROUTE
|
||||||
#include <linux/mroute.h>
|
#include <linux/mroute.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <net/vrf.h>
|
||||||
|
|
||||||
|
|
||||||
/* The inetsw table contains everything that inet_create needs to
|
/* 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);
|
struct net *net = sock_net(sk);
|
||||||
unsigned short snum;
|
unsigned short snum;
|
||||||
int chk_addr_ret;
|
int chk_addr_ret;
|
||||||
|
int tb_id = RT_TABLE_LOCAL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* If the socket has its own bind function then use it. (RAW) */
|
/* 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;
|
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
|
/* Not specified by any standard per-se, however it breaks too
|
||||||
* many applications when removed. It is unfortunate since
|
* many applications when removed. It is unfortunate since
|
||||||
|
@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)
|
|||||||
return -EINVAL;
|
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;
|
parms = in_dev->arp_parms;
|
||||||
__neigh_parms_put(neigh->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)) {
|
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
|
||||||
default:
|
default:
|
||||||
case 0: /* By default announce any local IP */
|
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)
|
ip_hdr(skb)->saddr) == RTN_LOCAL)
|
||||||
saddr = ip_hdr(skb)->saddr;
|
saddr = ip_hdr(skb)->saddr;
|
||||||
break;
|
break;
|
||||||
@ -351,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||||||
if (!skb)
|
if (!skb)
|
||||||
break;
|
break;
|
||||||
saddr = ip_hdr(skb)->saddr;
|
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 */
|
/* saddr should be known to target */
|
||||||
if (inet_addr_onlink(in_dev, target, saddr))
|
if (inet_addr_onlink(in_dev, target, saddr))
|
||||||
break;
|
break;
|
||||||
@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
|||||||
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
|
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
|
||||||
if (sip == 0) {
|
if (sip == 0) {
|
||||||
if (arp->ar_op == htons(ARPOP_REQUEST) &&
|
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_ignore(in_dev, sip, tip))
|
||||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
|
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
|
||||||
dev->dev_addr, 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);
|
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
|
||||||
|
|
||||||
if (IN_DEV_ARP_ACCEPT(in_dev)) {
|
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.
|
/* Unsolicited ARP is not accepted by default.
|
||||||
It is possible, that this option should be enabled for some
|
It is possible, that this option should be enabled for some
|
||||||
devices (strip is candidate)
|
devices (strip is candidate)
|
||||||
*/
|
*/
|
||||||
is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
|
is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
|
||||||
inet_addr_type(net, sip) == RTN_UNICAST;
|
addr_type == RTN_UNICAST;
|
||||||
|
|
||||||
if (!n &&
|
if (!n &&
|
||||||
((arp->ar_op == htons(ARPOP_REPLY) &&
|
((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);
|
n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +260,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(inet_dev_addr_type);
|
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)
|
__be32 fib_compute_spec_dst(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct net_device *dev = skb->dev;
|
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);
|
addr = sk_extract_addr(&rt->rt_gateway);
|
||||||
if (rt->rt_gateway.sa_family == AF_INET && addr) {
|
if (rt->rt_gateway.sa_family == AF_INET && addr) {
|
||||||
|
unsigned int addr_type;
|
||||||
|
|
||||||
cfg->fc_gw = addr;
|
cfg->fc_gw = addr;
|
||||||
|
addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
|
||||||
if (rt->rt_flags & RTF_GATEWAY &&
|
if (rt->rt_flags & RTF_GATEWAY &&
|
||||||
inet_addr_type(net, addr) == RTN_UNICAST)
|
addr_type == RTN_UNICAST)
|
||||||
cfg->fc_scope = RT_SCOPE_UNIVERSE;
|
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);
|
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
|
||||||
}
|
}
|
||||||
if (!(ok & LOCAL_OK)) {
|
if (!(ok & LOCAL_OK)) {
|
||||||
|
unsigned int addr_type;
|
||||||
|
|
||||||
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
|
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
|
||||||
|
|
||||||
/* Check, that this local address finally disappeared. */
|
/* Check, that this local address finally disappeared. */
|
||||||
if (gone &&
|
addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
|
||||||
inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
|
ifa->ifa_local);
|
||||||
|
if (gone && addr_type != RTN_LOCAL) {
|
||||||
/* And the last, but not the least thing.
|
/* And the last, but not the least thing.
|
||||||
* We must flush stray FIB entries.
|
* We must flush stray FIB entries.
|
||||||
*
|
*
|
||||||
|
@ -670,16 +670,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
|||||||
struct fib_result res;
|
struct fib_result res;
|
||||||
|
|
||||||
if (nh->nh_flags & RTNH_F_ONLINK) {
|
if (nh->nh_flags & RTNH_F_ONLINK) {
|
||||||
|
unsigned int addr_type;
|
||||||
|
|
||||||
if (cfg->fc_scope >= RT_SCOPE_LINK)
|
if (cfg->fc_scope >= RT_SCOPE_LINK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
|
|
||||||
return -EINVAL;
|
|
||||||
dev = __dev_get_by_index(net, nh->nh_oif);
|
dev = __dev_get_by_index(net, nh->nh_oif);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (!(dev->flags & IFF_UP))
|
if (!(dev->flags & IFF_UP))
|
||||||
return -ENETDOWN;
|
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))
|
if (!netif_carrier_ok(dev))
|
||||||
nh->nh_flags |= RTNH_F_LINKDOWN;
|
nh->nh_flags |= RTNH_F_LINKDOWN;
|
||||||
nh->nh_dev = dev;
|
nh->nh_dev = dev;
|
||||||
|
@ -484,7 +484,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
|
|||||||
if (err)
|
if (err)
|
||||||
goto relookup_failed;
|
goto relookup_failed;
|
||||||
|
|
||||||
if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) {
|
if (inet_addr_type_dev_table(net, skb_in->dev,
|
||||||
|
fl4_dec.saddr) == RTN_LOCAL) {
|
||||||
rt2 = __ip_route_output_key(net, &fl4_dec);
|
rt2 = __ip_route_output_key(net, &fl4_dec);
|
||||||
if (IS_ERR(rt2))
|
if (IS_ERR(rt2))
|
||||||
err = PTR_ERR(rt2);
|
err = PTR_ERR(rt2);
|
||||||
@ -833,7 +834,7 @@ static bool icmp_unreach(struct sk_buff *skb)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
|
if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
|
||||||
inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
|
inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
|
||||||
net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
|
net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
|
||||||
&ip_hdr(skb)->saddr,
|
&ip_hdr(skb)->saddr,
|
||||||
icmph->type, icmph->code,
|
icmph->type, icmph->code,
|
||||||
|
Loading…
Reference in New Issue
Block a user