| From foo@baz Mon Apr 9 17:09:24 CEST 2018 |
| From: Thomas Winter <Thomas.Winter@alliedtelesis.co.nz> |
| Date: Tue, 16 May 2017 10:14:44 +1200 |
| Subject: ipmr: vrf: Find VIFs using the actual device |
| |
| From: Thomas Winter <Thomas.Winter@alliedtelesis.co.nz> |
| |
| |
| [ Upstream commit bcfc7d33110b0f33069d74138eeb7ca9acbb3c85 ] |
| |
| The skb->dev that is passed into ip_mr_input is |
| the loX device for VRFs. When we lookup a vif |
| for this dev, none is found as we do not create |
| vifs for loopbacks. Instead lookup a vif for the |
| actual device that the packet was received on, |
| eg the vlan. |
| |
| Signed-off-by: Thomas Winter <Thomas.Winter@alliedtelesis.co.nz> |
| cc: David Ahern <dsa@cumulusnetworks.com> |
| cc: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| cc: roopa <roopa@cumulusnetworks.com> |
| Acked-by: David Ahern <dsahern@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/ipmr.c | 18 ++++++++++++++++-- |
| 1 file changed, 16 insertions(+), 2 deletions(-) |
| |
| --- a/net/ipv4/ipmr.c |
| +++ b/net/ipv4/ipmr.c |
| @@ -1929,6 +1929,20 @@ int ip_mr_input(struct sk_buff *skb) |
| struct net *net = dev_net(skb->dev); |
| int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; |
| struct mr_table *mrt; |
| + struct net_device *dev; |
| + |
| + /* skb->dev passed in is the loX master dev for vrfs. |
| + * As there are no vifs associated with loopback devices, |
| + * get the proper interface that does have a vif associated with it. |
| + */ |
| + dev = skb->dev; |
| + if (netif_is_l3_master(skb->dev)) { |
| + dev = dev_get_by_index_rcu(net, IPCB(skb)->iif); |
| + if (!dev) { |
| + kfree_skb(skb); |
| + return -ENODEV; |
| + } |
| + } |
| |
| /* Packet is looped back after forward, it should not be |
| * forwarded second time, but still can be delivered locally. |
| @@ -1966,7 +1980,7 @@ int ip_mr_input(struct sk_buff *skb) |
| /* already under rcu_read_lock() */ |
| cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); |
| if (!cache) { |
| - int vif = ipmr_find_vif(mrt, skb->dev); |
| + int vif = ipmr_find_vif(mrt, dev); |
| |
| if (vif >= 0) |
| cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr, |
| @@ -1986,7 +2000,7 @@ int ip_mr_input(struct sk_buff *skb) |
| } |
| |
| read_lock(&mrt_lock); |
| - vif = ipmr_find_vif(mrt, skb->dev); |
| + vif = ipmr_find_vif(mrt, dev); |
| if (vif >= 0) { |
| int err2 = ipmr_cache_unresolved(mrt, vif, skb); |
| read_unlock(&mrt_lock); |