Commit 4b340a5a authored by Mobashshera Rasool's avatar Mobashshera Rasool Committed by David S. Miller

net: ip6mr: add support for passing full packet on wrong mif

This patch adds support for MRT6MSG_WRMIFWHOLE which is used to pass
full packet and real vif id when the incoming interface is wrong.
While the RP and FHR are setting up state we need to be sending the
registers encapsulated with all the data inside otherwise we lose it.
The RP then decapsulates it and forwards it to the interested parties.
Currently with WRONGMIF we can only be sending empty register packets
and will lose that data.
This behaviour can be enabled by using MRT_PIM with
val == MRT6MSG_WRMIFWHOLE. This doesn't prevent MRT6MSG_WRONGMIF from
happening, it happens in addition to it, also it is controlled by the same
throttling parameters as WRONGMIF (i.e. 1 packet per 3 seconds currently).
Both messages are generated to keep backwards compatibily and avoid
breaking someone who was enabling MRT_PIM with val == 4, since any
positive val is accepted and treated the same.
Signed-off-by: default avatarMobashshera Rasool <mobash.rasool.linux@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7e1b54d0
...@@ -134,6 +134,7 @@ struct mrt6msg { ...@@ -134,6 +134,7 @@ struct mrt6msg {
#define MRT6MSG_NOCACHE 1 #define MRT6MSG_NOCACHE 1
#define MRT6MSG_WRONGMIF 2 #define MRT6MSG_WRONGMIF 2
#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */ #define MRT6MSG_WHOLEPKT 3 /* used for use level encap */
#define MRT6MSG_WRMIFWHOLE 4 /* For PIM Register and assert processing */
__u8 im6_mbz; /* must be zero */ __u8 im6_mbz; /* must be zero */
__u8 im6_msgtype; /* what type of message */ __u8 im6_msgtype; /* what type of message */
__u16 im6_mif; /* mif rec'd on */ __u16 im6_mif; /* mif rec'd on */
......
...@@ -1040,7 +1040,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1040,7 +1040,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
int ret; int ret;
#ifdef CONFIG_IPV6_PIMSM_V2 #ifdef CONFIG_IPV6_PIMSM_V2
if (assert == MRT6MSG_WHOLEPKT) if (assert == MRT6MSG_WHOLEPKT || assert == MRT6MSG_WRMIFWHOLE)
skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt) skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
+sizeof(*msg)); +sizeof(*msg));
else else
...@@ -1056,7 +1056,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1056,7 +1056,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
#ifdef CONFIG_IPV6_PIMSM_V2 #ifdef CONFIG_IPV6_PIMSM_V2
if (assert == MRT6MSG_WHOLEPKT) { if (assert == MRT6MSG_WHOLEPKT || assert == MRT6MSG_WRMIFWHOLE) {
/* Ugly, but we have no choice with this interface. /* Ugly, but we have no choice with this interface.
Duplicate old header, fix length etc. Duplicate old header, fix length etc.
And all this only to mangle msg->im6_msgtype and And all this only to mangle msg->im6_msgtype and
...@@ -1068,8 +1068,11 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1068,8 +1068,11 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
msg = (struct mrt6msg *)skb_transport_header(skb); msg = (struct mrt6msg *)skb_transport_header(skb);
msg->im6_mbz = 0; msg->im6_mbz = 0;
msg->im6_msgtype = MRT6MSG_WHOLEPKT; msg->im6_msgtype = assert;
msg->im6_mif = mrt->mroute_reg_vif_num; if (assert == MRT6MSG_WRMIFWHOLE)
msg->im6_mif = mifi;
else
msg->im6_mif = mrt->mroute_reg_vif_num;
msg->im6_pad = 0; msg->im6_pad = 0;
msg->im6_src = ipv6_hdr(pkt)->saddr; msg->im6_src = ipv6_hdr(pkt)->saddr;
msg->im6_dst = ipv6_hdr(pkt)->daddr; msg->im6_dst = ipv6_hdr(pkt)->daddr;
...@@ -1650,6 +1653,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, ...@@ -1650,6 +1653,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
mifi_t mifi; mifi_t mifi;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct mr_table *mrt; struct mr_table *mrt;
bool do_wrmifwhole;
if (sk->sk_type != SOCK_RAW || if (sk->sk_type != SOCK_RAW ||
inet_sk(sk)->inet_num != IPPROTO_ICMPV6) inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
...@@ -1763,12 +1767,15 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, ...@@ -1763,12 +1767,15 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
return -EINVAL; return -EINVAL;
if (copy_from_sockptr(&v, optval, sizeof(v))) if (copy_from_sockptr(&v, optval, sizeof(v)))
return -EFAULT; return -EFAULT;
do_wrmifwhole = (v == MRT6MSG_WRMIFWHOLE);
v = !!v; v = !!v;
rtnl_lock(); rtnl_lock();
ret = 0; ret = 0;
if (v != mrt->mroute_do_pim) { if (v != mrt->mroute_do_pim) {
mrt->mroute_do_pim = v; mrt->mroute_do_pim = v;
mrt->mroute_do_assert = v; mrt->mroute_do_assert = v;
mrt->mroute_do_wrvifwhole = do_wrmifwhole;
} }
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
...@@ -2144,6 +2151,9 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt, ...@@ -2144,6 +2151,9 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
MFC_ASSERT_THRESH)) { MFC_ASSERT_THRESH)) {
c->_c.mfc_un.res.last_assert = jiffies; c->_c.mfc_un.res.last_assert = jiffies;
ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF); ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
if (mrt->mroute_do_wrvifwhole)
ip6mr_cache_report(mrt, skb, true_vifi,
MRT6MSG_WRMIFWHOLE);
} }
goto dont_forward; goto dont_forward;
} }
......
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