Commit e4a38c0c authored by Patrick Ruddy's avatar Patrick Ruddy Committed by David S. Miller

ipv6: add vrf table handling code for ipv6 mcast

The code to obtain the correct table for the incoming interface was
missing for IPv6. This has been added along with the table creation
notification to fib rules for the RTNL_FAMILY_IP6MR address family.
Signed-off-by: default avatarPatrick Ruddy <pruddy@vyatta.att-mail.com>
Signed-off-by: default avatarMike Manning <mmanning@vyatta.att-mail.com>
Reviewed-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 854da991
...@@ -1215,8 +1215,19 @@ static int vrf_add_fib_rules(const struct net_device *dev) ...@@ -1215,8 +1215,19 @@ static int vrf_add_fib_rules(const struct net_device *dev)
goto ipmr_err; goto ipmr_err;
#endif #endif
#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
err = vrf_fib_rule(dev, RTNL_FAMILY_IP6MR, true);
if (err < 0)
goto ip6mr_err;
#endif
return 0; return 0;
#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
ip6mr_err:
vrf_fib_rule(dev, RTNL_FAMILY_IPMR, false);
#endif
#if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES) #if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)
ipmr_err: ipmr_err:
vrf_fib_rule(dev, AF_INET6, false); vrf_fib_rule(dev, AF_INET6, false);
......
...@@ -85,7 +85,8 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id); ...@@ -85,7 +85,8 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id);
static void ip6mr_free_table(struct mr_table *mrt); static void ip6mr_free_table(struct mr_table *mrt);
static void ip6_mr_forward(struct net *net, struct mr_table *mrt, static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
struct sk_buff *skb, struct mfc6_cache *cache); struct net_device *dev, struct sk_buff *skb,
struct mfc6_cache *cache);
static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
mifi_t mifi, int assert); mifi_t mifi, int assert);
static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
...@@ -138,6 +139,9 @@ static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, ...@@ -138,6 +139,9 @@ static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
.flags = FIB_LOOKUP_NOREF, .flags = FIB_LOOKUP_NOREF,
}; };
/* update flow if oif or iif point to device enslaved to l3mdev */
l3mdev_update_flow(net, flowi6_to_flowi(flp6));
err = fib_rules_lookup(net->ipv6.mr6_rules_ops, err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
flowi6_to_flowi(flp6), 0, &arg); flowi6_to_flowi(flp6), 0, &arg);
if (err < 0) if (err < 0)
...@@ -164,7 +168,9 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, ...@@ -164,7 +168,9 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
return -EINVAL; return -EINVAL;
} }
mrt = ip6mr_get_table(rule->fr_net, rule->table); arg->table = fib_rule_get_table(rule, arg);
mrt = ip6mr_get_table(rule->fr_net, arg->table);
if (!mrt) if (!mrt)
return -EAGAIN; return -EAGAIN;
res->mrt = mrt; res->mrt = mrt;
...@@ -1014,7 +1020,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -1014,7 +1020,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
} }
rtnl_unicast(skb, net, NETLINK_CB(skb).portid); rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
} else } else
ip6_mr_forward(net, mrt, skb, c); ip6_mr_forward(net, mrt, skb->dev, skb, c);
} }
} }
...@@ -1120,7 +1126,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1120,7 +1126,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
/* Queue a packet for resolution. It gets locked cache entry! */ /* Queue a packet for resolution. It gets locked cache entry! */
static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
struct sk_buff *skb) struct sk_buff *skb, struct net_device *dev)
{ {
struct mfc6_cache *c; struct mfc6_cache *c;
bool found = false; bool found = false;
...@@ -1180,6 +1186,10 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, ...@@ -1180,6 +1186,10 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
kfree_skb(skb); kfree_skb(skb);
err = -ENOBUFS; err = -ENOBUFS;
} else { } else {
if (dev) {
skb->dev = dev;
skb->skb_iif = dev->ifindex;
}
skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
err = 0; err = 0;
} }
...@@ -2043,11 +2053,12 @@ static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev) ...@@ -2043,11 +2053,12 @@ static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
} }
static void ip6_mr_forward(struct net *net, struct mr_table *mrt, static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
struct sk_buff *skb, struct mfc6_cache *c) struct net_device *dev, struct sk_buff *skb,
struct mfc6_cache *c)
{ {
int psend = -1; int psend = -1;
int vif, ct; int vif, ct;
int true_vifi = ip6mr_find_vif(mrt, skb->dev); int true_vifi = ip6mr_find_vif(mrt, dev);
vif = c->_c.mfc_parent; vif = c->_c.mfc_parent;
c->_c.mfc_un.res.pkt++; c->_c.mfc_un.res.pkt++;
...@@ -2073,7 +2084,7 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt, ...@@ -2073,7 +2084,7 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
/* /*
* Wrong interface: drop packet and (maybe) send PIM assert. * Wrong interface: drop packet and (maybe) send PIM assert.
*/ */
if (mrt->vif_table[vif].dev != skb->dev) { if (mrt->vif_table[vif].dev != dev) {
c->_c.mfc_un.res.wrong_if++; c->_c.mfc_un.res.wrong_if++;
if (true_vifi >= 0 && mrt->mroute_do_assert && if (true_vifi >= 0 && mrt->mroute_do_assert &&
...@@ -2154,6 +2165,19 @@ int ip6_mr_input(struct sk_buff *skb) ...@@ -2154,6 +2165,19 @@ int ip6_mr_input(struct sk_buff *skb)
.flowi6_mark = skb->mark, .flowi6_mark = skb->mark,
}; };
int err; int err;
struct net_device *dev;
/* skb->dev passed in is the master dev for vrfs.
* 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;
}
}
err = ip6mr_fib_lookup(net, &fl6, &mrt); err = ip6mr_fib_lookup(net, &fl6, &mrt);
if (err < 0) { if (err < 0) {
...@@ -2165,7 +2189,7 @@ int ip6_mr_input(struct sk_buff *skb) ...@@ -2165,7 +2189,7 @@ int ip6_mr_input(struct sk_buff *skb)
cache = ip6mr_cache_find(mrt, cache = ip6mr_cache_find(mrt,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
if (!cache) { if (!cache) {
int vif = ip6mr_find_vif(mrt, skb->dev); int vif = ip6mr_find_vif(mrt, dev);
if (vif >= 0) if (vif >= 0)
cache = ip6mr_cache_find_any(mrt, cache = ip6mr_cache_find_any(mrt,
...@@ -2179,9 +2203,9 @@ int ip6_mr_input(struct sk_buff *skb) ...@@ -2179,9 +2203,9 @@ int ip6_mr_input(struct sk_buff *skb)
if (!cache) { if (!cache) {
int vif; int vif;
vif = ip6mr_find_vif(mrt, skb->dev); vif = ip6mr_find_vif(mrt, dev);
if (vif >= 0) { if (vif >= 0) {
int err = ip6mr_cache_unresolved(mrt, vif, skb); int err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
read_unlock(&mrt_lock); read_unlock(&mrt_lock);
return err; return err;
...@@ -2191,7 +2215,7 @@ int ip6_mr_input(struct sk_buff *skb) ...@@ -2191,7 +2215,7 @@ int ip6_mr_input(struct sk_buff *skb)
return -ENODEV; return -ENODEV;
} }
ip6_mr_forward(net, mrt, skb, cache); ip6_mr_forward(net, mrt, dev, skb, cache);
read_unlock(&mrt_lock); read_unlock(&mrt_lock);
...@@ -2257,7 +2281,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm, ...@@ -2257,7 +2281,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
iph->saddr = rt->rt6i_src.addr; iph->saddr = rt->rt6i_src.addr;
iph->daddr = rt->rt6i_dst.addr; iph->daddr = rt->rt6i_dst.addr;
err = ip6mr_cache_unresolved(mrt, vif, skb2); err = ip6mr_cache_unresolved(mrt, vif, skb2, dev);
read_unlock(&mrt_lock); read_unlock(&mrt_lock);
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment