aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Suryaputra <ssuryaextr@gmail.com>2019-06-26 02:21:16 -0400
committerDavid S. Miller <davem@davemloft.net>2019-06-26 15:40:10 -0400
commit5b18f1289808fee5d04a7e6ecf200189f41a4db6 (patch)
treec4f8ffda52e1fa30489d1eae8c7f4066c0fc2df6
parentee4297420d56a0033a8593e80b33fcc93fda8509 (diff)
ipv4: reset rt_iif for recirculated mcast/bcast out pkts
Multicast or broadcast egress packets have rt_iif set to the oif. These packets might be recirculated back as input and lookup to the raw sockets may fail because they are bound to the incoming interface (skb_iif). If rt_iif is not zero, during the lookup, inet_iif() function returns rt_iif instead of skb_iif. Hence, the lookup fails. v2: Make it non vrf specific (David Ahern). Reword the changelog to reflect it. Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com> Reviewed-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/route.h1
-rw-r--r--net/ipv4/ip_output.c12
-rw-r--r--net/ipv4/route.c33
3 files changed, 46 insertions, 0 deletions
diff --git a/include/net/route.h b/include/net/route.h
index 065b47754f05..55ff71ffb796 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -221,6 +221,7 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
221struct rtable *rt_dst_alloc(struct net_device *dev, 221struct rtable *rt_dst_alloc(struct net_device *dev,
222 unsigned int flags, u16 type, 222 unsigned int flags, u16 type,
223 bool nopolicy, bool noxfrm, bool will_cache); 223 bool nopolicy, bool noxfrm, bool will_cache);
224struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
224 225
225struct in_ifaddr; 226struct in_ifaddr;
226void fib_add_ifaddr(struct in_ifaddr *); 227void fib_add_ifaddr(struct in_ifaddr *);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 16f9159234a2..8c2ec35b6512 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -318,6 +318,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
318static int ip_mc_finish_output(struct net *net, struct sock *sk, 318static int ip_mc_finish_output(struct net *net, struct sock *sk,
319 struct sk_buff *skb) 319 struct sk_buff *skb)
320{ 320{
321 struct rtable *new_rt;
321 int ret; 322 int ret;
322 323
323 ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 324 ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
@@ -326,6 +327,17 @@ static int ip_mc_finish_output(struct net *net, struct sock *sk,
326 return ret; 327 return ret;
327 } 328 }
328 329
330 /* Reset rt_iif so that inet_iif() will return skb->skb_iif. Setting
331 * this to non-zero causes ipi_ifindex in in_pktinfo to be overwritten,
332 * see ipv4_pktinfo_prepare().
333 */
334 new_rt = rt_dst_clone(net->loopback_dev, skb_rtable(skb));
335 if (new_rt) {
336 new_rt->rt_iif = 0;
337 skb_dst_drop(skb);
338 skb_dst_set(skb, &new_rt->dst);
339 }
340
329 return dev_loopback_xmit(net, sk, skb); 341 return dev_loopback_xmit(net, sk, skb);
330} 342}
331 343
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6cb7cff22db9..8ea0735a6754 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1647,6 +1647,39 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
1647} 1647}
1648EXPORT_SYMBOL(rt_dst_alloc); 1648EXPORT_SYMBOL(rt_dst_alloc);
1649 1649
1650struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt)
1651{
1652 struct rtable *new_rt;
1653
1654 new_rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK,
1655 rt->dst.flags);
1656
1657 if (new_rt) {
1658 new_rt->rt_genid = rt_genid_ipv4(dev_net(dev));
1659 new_rt->rt_flags = rt->rt_flags;
1660 new_rt->rt_type = rt->rt_type;
1661 new_rt->rt_is_input = rt->rt_is_input;
1662 new_rt->rt_iif = rt->rt_iif;
1663 new_rt->rt_pmtu = rt->rt_pmtu;
1664 new_rt->rt_mtu_locked = rt->rt_mtu_locked;
1665 new_rt->rt_gw_family = rt->rt_gw_family;
1666 if (rt->rt_gw_family == AF_INET)
1667 new_rt->rt_gw4 = rt->rt_gw4;
1668 else if (rt->rt_gw_family == AF_INET6)
1669 new_rt->rt_gw6 = rt->rt_gw6;
1670 INIT_LIST_HEAD(&new_rt->rt_uncached);
1671
1672 new_rt->dst.flags |= DST_HOST;
1673 new_rt->dst.input = rt->dst.input;
1674 new_rt->dst.output = rt->dst.output;
1675 new_rt->dst.error = rt->dst.error;
1676 new_rt->dst.lastuse = jiffies;
1677 new_rt->dst.lwtstate = lwtstate_get(rt->dst.lwtstate);
1678 }
1679 return new_rt;
1680}
1681EXPORT_SYMBOL(rt_dst_clone);
1682
1650/* called in rcu_read_lock() section */ 1683/* called in rcu_read_lock() section */
1651int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1684int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1652 u8 tos, struct net_device *dev, 1685 u8 tos, struct net_device *dev,