By default IPv6 socket with IPV6_ROUTER_ALERT socket option set will
receive all IPv6 RA packets from all namespaces.
IPV6_ROUTER_ALERT_ISOLATE socket option restricts packets received by
the socket to be only from the socket's namespace.

Signed-off-by: Maxim Martynov <ma...@arista.com>
Signed-off-by: Francesco Ruggeri <frugg...@arista.com>
---
 include/linux/ipv6.h     |  3 ++-
 include/uapi/linux/in6.h |  1 +
 net/ipv6/ip6_output.c    |  6 ++++++
 net/ipv6/ipv6_sockglue.c | 10 ++++++++++
 4 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 495e834c1367..26b8f45ffba3 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -275,7 +275,8 @@ struct ipv6_pinfo {
                                dontfrag:1,
                                autoflowlabel:1,
                                autoflowlabel_set:1,
-                               mc_all:1;
+                               mc_all:1,
+                               rtalert_isolate:1;
        __u8                    min_hopcount;
        __u8                    tclass;
        __be32                  rcv_flowinfo;
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 71d82fe15b03..9f2273a08356 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -178,6 +178,7 @@ struct in6_flowlabel_req {
 #define IPV6_JOIN_ANYCAST      27
 #define IPV6_LEAVE_ANYCAST     28
 #define IPV6_MULTICAST_ALL     29
+#define IPV6_ROUTER_ALERT_ISOLATE      30
 
 /* IPV6_MTU_DISCOVER values */
 #define IPV6_PMTUDISC_DONT             0
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5f9fa0302b5a..edbd12067170 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -300,6 +300,12 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
                if (sk && ra->sel == sel &&
                    (!sk->sk_bound_dev_if ||
                     sk->sk_bound_dev_if == skb->dev->ifindex)) {
+                       struct ipv6_pinfo *np = inet6_sk(sk);
+
+                       if (np && np->rtalert_isolate &&
+                           !net_eq(sock_net(sk), dev_net(skb->dev))) {
+                               continue;
+                       }
                        if (last) {
                                struct sk_buff *skb2 = skb_clone(skb, 
GFP_ATOMIC);
                                if (skb2)
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 973e215c3114..40f21fef25ff 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -787,6 +787,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, 
int optname,
                        goto e_inval;
                retv = ip6_ra_control(sk, val);
                break;
+       case IPV6_ROUTER_ALERT_ISOLATE:
+               if (optlen < sizeof(int))
+                       goto e_inval;
+               np->rtalert_isolate = valbool;
+               retv = 0;
+               break;
        case IPV6_MTU_DISCOVER:
                if (optlen < sizeof(int))
                        goto e_inval;
@@ -1358,6 +1364,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int 
level, int optname,
                val = np->rxopt.bits.recvfragsize;
                break;
 
+       case IPV6_ROUTER_ALERT_ISOLATE:
+               val = np->rtalert_isolate;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
-- 
2.19.1

Reply via email to