net: ipv4: refactor ip_route_input_noref
A later patch wants access to the fib result on an input route lookup with the rcu lock held. Refactor ip_route_input_noref pushing the logic between rcu_read_lock ... rcu_read_unlock into a new helper that takes the fib_result as an input arg. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
3abd1ade67
commit
5510cdf7be
@@ -178,6 +178,9 @@ static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4
|
|||||||
|
|
||||||
int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
|
int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||||
u8 tos, struct net_device *devin);
|
u8 tos, struct net_device *devin);
|
||||||
|
int ip_route_input_rcu(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||||
|
u8 tos, struct net_device *devin,
|
||||||
|
struct fib_result *res);
|
||||||
|
|
||||||
static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
|
static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||||
u8 tos, struct net_device *devin)
|
u8 tos, struct net_device *devin)
|
||||||
|
|||||||
@@ -1852,9 +1852,9 @@ static int ip_mkroute_input(struct sk_buff *skb,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||||
u8 tos, struct net_device *dev)
|
u8 tos, struct net_device *dev,
|
||||||
|
struct fib_result *res)
|
||||||
{
|
{
|
||||||
struct fib_result res;
|
|
||||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||||
struct ip_tunnel_info *tun_info;
|
struct ip_tunnel_info *tun_info;
|
||||||
struct flowi4 fl4;
|
struct flowi4 fl4;
|
||||||
@@ -1884,8 +1884,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
|
if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
|
||||||
goto martian_source;
|
goto martian_source;
|
||||||
|
|
||||||
res.fi = NULL;
|
res->fi = NULL;
|
||||||
res.table = NULL;
|
res->table = NULL;
|
||||||
if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
|
if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
|
||||||
goto brd_input;
|
goto brd_input;
|
||||||
|
|
||||||
@@ -1921,17 +1921,17 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
fl4.daddr = daddr;
|
fl4.daddr = daddr;
|
||||||
fl4.saddr = saddr;
|
fl4.saddr = saddr;
|
||||||
fl4.flowi4_uid = sock_net_uid(net, NULL);
|
fl4.flowi4_uid = sock_net_uid(net, NULL);
|
||||||
err = fib_lookup(net, &fl4, &res, 0);
|
err = fib_lookup(net, &fl4, res, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
if (!IN_DEV_FORWARD(in_dev))
|
if (!IN_DEV_FORWARD(in_dev))
|
||||||
err = -EHOSTUNREACH;
|
err = -EHOSTUNREACH;
|
||||||
goto no_route;
|
goto no_route;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.type == RTN_BROADCAST)
|
if (res->type == RTN_BROADCAST)
|
||||||
goto brd_input;
|
goto brd_input;
|
||||||
|
|
||||||
if (res.type == RTN_LOCAL) {
|
if (res->type == RTN_LOCAL) {
|
||||||
err = fib_validate_source(skb, saddr, daddr, tos,
|
err = fib_validate_source(skb, saddr, daddr, tos,
|
||||||
0, dev, in_dev, &itag);
|
0, dev, in_dev, &itag);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -1943,10 +1943,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
err = -EHOSTUNREACH;
|
err = -EHOSTUNREACH;
|
||||||
goto no_route;
|
goto no_route;
|
||||||
}
|
}
|
||||||
if (res.type != RTN_UNICAST)
|
if (res->type != RTN_UNICAST)
|
||||||
goto martian_destination;
|
goto martian_destination;
|
||||||
|
|
||||||
err = ip_mkroute_input(skb, &res, in_dev, daddr, saddr, tos);
|
err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos);
|
||||||
out: return err;
|
out: return err;
|
||||||
|
|
||||||
brd_input:
|
brd_input:
|
||||||
@@ -1960,14 +1960,14 @@ brd_input:
|
|||||||
goto martian_source;
|
goto martian_source;
|
||||||
}
|
}
|
||||||
flags |= RTCF_BROADCAST;
|
flags |= RTCF_BROADCAST;
|
||||||
res.type = RTN_BROADCAST;
|
res->type = RTN_BROADCAST;
|
||||||
RT_CACHE_STAT_INC(in_brd);
|
RT_CACHE_STAT_INC(in_brd);
|
||||||
|
|
||||||
local_input:
|
local_input:
|
||||||
do_cache = false;
|
do_cache = false;
|
||||||
if (res.fi) {
|
if (res->fi) {
|
||||||
if (!itag) {
|
if (!itag) {
|
||||||
rth = rcu_dereference(FIB_RES_NH(res).nh_rth_input);
|
rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
|
||||||
if (rt_cache_valid(rth)) {
|
if (rt_cache_valid(rth)) {
|
||||||
skb_dst_set_noref(skb, &rth->dst);
|
skb_dst_set_noref(skb, &rth->dst);
|
||||||
err = 0;
|
err = 0;
|
||||||
@@ -1978,7 +1978,7 @@ local_input:
|
|||||||
}
|
}
|
||||||
|
|
||||||
rth = rt_dst_alloc(l3mdev_master_dev_rcu(dev) ? : net->loopback_dev,
|
rth = rt_dst_alloc(l3mdev_master_dev_rcu(dev) ? : net->loopback_dev,
|
||||||
flags | RTCF_LOCAL, res.type,
|
flags | RTCF_LOCAL, res->type,
|
||||||
IN_DEV_CONF_GET(in_dev, NOPOLICY), false, do_cache);
|
IN_DEV_CONF_GET(in_dev, NOPOLICY), false, do_cache);
|
||||||
if (!rth)
|
if (!rth)
|
||||||
goto e_nobufs;
|
goto e_nobufs;
|
||||||
@@ -1988,18 +1988,18 @@ local_input:
|
|||||||
rth->dst.tclassid = itag;
|
rth->dst.tclassid = itag;
|
||||||
#endif
|
#endif
|
||||||
rth->rt_is_input = 1;
|
rth->rt_is_input = 1;
|
||||||
if (res.table)
|
if (res->table)
|
||||||
rth->rt_table_id = res.table->tb_id;
|
rth->rt_table_id = res->table->tb_id;
|
||||||
|
|
||||||
RT_CACHE_STAT_INC(in_slow_tot);
|
RT_CACHE_STAT_INC(in_slow_tot);
|
||||||
if (res.type == RTN_UNREACHABLE) {
|
if (res->type == RTN_UNREACHABLE) {
|
||||||
rth->dst.input= ip_error;
|
rth->dst.input= ip_error;
|
||||||
rth->dst.error= -err;
|
rth->dst.error= -err;
|
||||||
rth->rt_flags &= ~RTCF_LOCAL;
|
rth->rt_flags &= ~RTCF_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_cache) {
|
if (do_cache) {
|
||||||
struct fib_nh *nh = &FIB_RES_NH(res);
|
struct fib_nh *nh = &FIB_RES_NH(*res);
|
||||||
|
|
||||||
rth->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
|
rth->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
|
||||||
if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
|
if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
|
||||||
@@ -2019,9 +2019,9 @@ local_input:
|
|||||||
|
|
||||||
no_route:
|
no_route:
|
||||||
RT_CACHE_STAT_INC(in_no_route);
|
RT_CACHE_STAT_INC(in_no_route);
|
||||||
res.type = RTN_UNREACHABLE;
|
res->type = RTN_UNREACHABLE;
|
||||||
res.fi = NULL;
|
res->fi = NULL;
|
||||||
res.table = NULL;
|
res->table = NULL;
|
||||||
goto local_input;
|
goto local_input;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2051,11 +2051,22 @@ martian_source:
|
|||||||
int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||||
u8 tos, struct net_device *dev)
|
u8 tos, struct net_device *dev)
|
||||||
{
|
{
|
||||||
int res;
|
struct fib_result res;
|
||||||
|
int err;
|
||||||
|
|
||||||
tos &= IPTOS_RT_MASK;
|
tos &= IPTOS_RT_MASK;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
err = ip_route_input_rcu(skb, daddr, saddr, tos, dev, &res);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ip_route_input_noref);
|
||||||
|
|
||||||
|
/* called with rcu_read_lock held */
|
||||||
|
int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||||
|
u8 tos, struct net_device *dev, struct fib_result *res)
|
||||||
|
{
|
||||||
/* Multicast recognition logic is moved from route cache to here.
|
/* Multicast recognition logic is moved from route cache to here.
|
||||||
The problem was that too many Ethernet cards have broken/missing
|
The problem was that too many Ethernet cards have broken/missing
|
||||||
hardware multicast filters :-( As result the host on multicasting
|
hardware multicast filters :-( As result the host on multicasting
|
||||||
@@ -2070,6 +2081,7 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
if (ipv4_is_multicast(daddr)) {
|
if (ipv4_is_multicast(daddr)) {
|
||||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||||
int our = 0;
|
int our = 0;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (in_dev)
|
if (in_dev)
|
||||||
our = ip_check_mc_rcu(in_dev, daddr, saddr,
|
our = ip_check_mc_rcu(in_dev, daddr, saddr,
|
||||||
@@ -2085,7 +2097,6 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
ip_hdr(skb)->protocol);
|
ip_hdr(skb)->protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = -EINVAL;
|
|
||||||
if (our
|
if (our
|
||||||
#ifdef CONFIG_IP_MROUTE
|
#ifdef CONFIG_IP_MROUTE
|
||||||
||
|
||
|
||||||
@@ -2093,17 +2104,14 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||||||
IN_DEV_MFORWARD(in_dev))
|
IN_DEV_MFORWARD(in_dev))
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
res = ip_route_input_mc(skb, daddr, saddr,
|
err = ip_route_input_mc(skb, daddr, saddr,
|
||||||
tos, dev, our);
|
tos, dev, our);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
return err;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
|
|
||||||
rcu_read_unlock();
|
return ip_route_input_slow(skb, daddr, saddr, tos, dev, res);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ip_route_input_noref);
|
|
||||||
|
|
||||||
/* called with rcu_read_lock() */
|
/* called with rcu_read_lock() */
|
||||||
static struct rtable *__mkroute_output(const struct fib_result *res,
|
static struct rtable *__mkroute_output(const struct fib_result *res,
|
||||||
|
|||||||
Reference in New Issue
Block a user