ipv6: Add disable_ipv6 sysctl to disable IPv6 operaion on specific interface.
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Sat, 28 Jun 2008 05:17:11 +0000 (14:17 +0900)
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Thu, 3 Jul 2008 08:51:55 +0000 (17:51 +0900)
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Documentation/networking/ip-sysctl.txt
include/linux/ipv6.h
net/ipv6/addrconf.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c

index 71c7bea97160609f7c029a71fc9bf658772a5da5..dae980e8f1b9d32017f44ede5d602f5ef8d5cbfb 100644 (file)
@@ -1025,6 +1025,10 @@ max_addresses - INTEGER
        autoconfigured addresses.
        Default: 16
 
+disable_ipv6 - BOOLEAN
+       Disable IPv6 operation.
+       Default: FALSE (enable IPv6 operation)
+
 icmp/*:
 ratelimit - INTEGER
        Limit the maximal rates for sending ICMPv6 packets.
index cde056e0818172aeb7a5ae8d69998fb83d41796e..d9d7f9b69eb4f2c8da0e455cd9c459ceb6ef5965 100644 (file)
@@ -163,6 +163,7 @@ struct ipv6_devconf {
 #ifdef CONFIG_IPV6_MROUTE
        __s32           mc_forwarding;
 #endif
+       __s32           disable_ipv6;
        void            *sysctl;
 };
 
@@ -194,6 +195,7 @@ enum {
        DEVCONF_OPTIMISTIC_DAD,
        DEVCONF_ACCEPT_SOURCE_ROUTE,
        DEVCONF_MC_FORWARDING,
+       DEVCONF_DISABLE_IPV6,
        DEVCONF_MAX
 };
 
index 8b6875f02039df66596c0bd82deee537cdc8775a..8c5cff50bbedc92a3db6c23e7cf82443bc750bcd 100644 (file)
@@ -183,6 +183,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
 #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
+       .disable_ipv6           = 0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -215,6 +216,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
+       .disable_ipv6           = 0,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -3657,6 +3659,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 #ifdef CONFIG_IPV6_MROUTE
        array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
 #endif
+       array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
 }
 
 static inline size_t inet6_if_nlmsg_size(void)
@@ -4215,6 +4218,14 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       &proc_dointvec,
                },
 #endif
+               {
+                       .ctl_name       =       CTL_UNNUMBERED,
+                       .procname       =       "disable_ipv6",
+                       .data           =       &ipv6_devconf.disable_ipv6,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
                {
                        .ctl_name       =       0,      /* sentinel */
                }
index 34e5a96623aece79e56c80a94d16d333df310273..ea81c614dde2be1cf70c42f955ab96af3489b29e 100644 (file)
@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 
        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
 
-       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
+           !idev || unlikely(idev->cnf.disable_ipv6)) {
                IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
                rcu_read_unlock();
                goto out;
index 871bdec09edbc39b952c5102cabbfbf5229253f6..0981c1ef305797322ab0b703a4aba609efcbbfc2 100644 (file)
@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 
 int ip6_output(struct sk_buff *skb)
 {
+       struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+       if (unlikely(idev->cnf.disable_ipv6)) {
+               IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+               kfree_skb(skb);
+               return 0;
+       }
+
        if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
                                dst_allfrag(skb->dst))
                return ip6_fragment(skb, ip6_output2);