Skip to content

Commit 5b18f12

Browse files
ssuryaextrdavem330
authored andcommitted
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 <[email protected]> Reviewed-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ee42974 commit 5b18f12

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

include/net/route.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
221221
struct rtable *rt_dst_alloc(struct net_device *dev,
222222
unsigned int flags, u16 type,
223223
bool nopolicy, bool noxfrm, bool will_cache);
224+
struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
224225

225226
struct in_ifaddr;
226227
void fib_add_ifaddr(struct in_ifaddr *);

net/ipv4/ip_output.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
318318
static int ip_mc_finish_output(struct net *net, struct sock *sk,
319319
struct sk_buff *skb)
320320
{
321+
struct rtable *new_rt;
321322
int ret;
322323

323324
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,
326327
return ret;
327328
}
328329

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+
329341
return dev_loopback_xmit(net, sk, skb);
330342
}
331343

net/ipv4/route.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,39 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
16471647
}
16481648
EXPORT_SYMBOL(rt_dst_alloc);
16491649

1650+
struct 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+
}
1681+
EXPORT_SYMBOL(rt_dst_clone);
1682+
16501683
/* called in rcu_read_lock() section */
16511684
int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
16521685
u8 tos, struct net_device *dev,

0 commit comments

Comments
 (0)