net: add sysctl accept_ra_min_rtr_lft
authorPatrick Rohr <prohr@google.com>
Wed, 19 Jul 2023 14:52:13 +0000 (07:52 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Oct 2023 20:00:36 +0000 (22:00 +0200)
commit 1671bcfd76fdc0b9e65153cf759153083755fe4c upstream.

This change adds a new sysctl accept_ra_min_rtr_lft to specify the
minimum acceptable router lifetime in an RA. If the received RA router
lifetime is less than the configured value (and not 0), the RA is
ignored.
This is useful for mobile devices, whose battery life can be impacted
by networks that configure RAs with a short lifetime. On such networks,
the device should never gain IPv6 provisioning and should attempt to
drop RAs via hardware offload, if available.

Signed-off-by: Patrick Rohr <prohr@google.com>
Cc: Maciej Żenczykowski <maze@google.com>
Cc: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/networking/ip-sysctl.rst
include/linux/ipv6.h
include/uapi/linux/ipv6.h
net/ipv6/addrconf.c
net/ipv6/ndisc.c

index 3301288a7c692592be06168f490268b862d8583a..b0e9210f7a28d6952b6fb4143e95c4b90fbe7a2f 100644 (file)
@@ -2148,6 +2148,14 @@ accept_ra_min_hop_limit - INTEGER
 
        Default: 1
 
+accept_ra_min_rtr_lft - INTEGER
+       Minimum acceptable router lifetime in Router Advertisement.
+
+       RAs with a router lifetime less than this value shall be
+       ignored. RAs with a router lifetime of 0 are unaffected.
+
+       Default: 0
+
 accept_ra_pinfo - BOOLEAN
        Learn Prefix Information in Router Advertisement.
 
index 15d7529ac95348efb2edcbf2c6379bd6545ee42a..a4b35f4c89d77363c72c390eb3199eb1d164813a 100644 (file)
@@ -33,6 +33,7 @@ struct ipv6_devconf {
        __s32           accept_ra_defrtr;
        __u32           ra_defrtr_metric;
        __s32           accept_ra_min_hop_limit;
+       __s32           accept_ra_min_rtr_lft;
        __s32           accept_ra_pinfo;
        __s32           ignore_routes_with_linkdown;
 #ifdef CONFIG_IPV6_ROUTER_PREF
index 53326dfc59ecb70013a84328197629acb2205e40..2038eff9b63f9f56fe48f78152b33855124c99fa 100644 (file)
@@ -198,6 +198,7 @@ enum {
        DEVCONF_IOAM6_ID_WIDE,
        DEVCONF_NDISC_EVICT_NOCARRIER,
        DEVCONF_ACCEPT_UNTRACKED_NA,
+       DEVCONF_ACCEPT_RA_MIN_RTR_LFT,
        DEVCONF_MAX
 };
 
index 83be842198244be5680cd64b547fd8fc2593cba6..c7e939c619c965bfe77bc12f675bd9ef6f8b9276 100644 (file)
@@ -202,6 +202,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .ra_defrtr_metric       = IP6_RT_PRIO_USER,
        .accept_ra_from_local   = 0,
        .accept_ra_min_hop_limit= 1,
+       .accept_ra_min_rtr_lft  = 0,
        .accept_ra_pinfo        = 1,
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@ -262,6 +263,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .ra_defrtr_metric       = IP6_RT_PRIO_USER,
        .accept_ra_from_local   = 0,
        .accept_ra_min_hop_limit= 1,
+       .accept_ra_min_rtr_lft  = 0,
        .accept_ra_pinfo        = 1,
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@ -5601,6 +5603,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
        array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
        array[DEVCONF_ACCEPT_UNTRACKED_NA] = cnf->accept_untracked_na;
+       array[DEVCONF_ACCEPT_RA_MIN_RTR_LFT] = cnf->accept_ra_min_rtr_lft;
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -6794,6 +6797,13 @@ static const struct ctl_table addrconf_sysctl[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "accept_ra_min_rtr_lft",
+               .data           = &ipv6_devconf.accept_ra_min_rtr_lft,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {
                .procname       = "accept_ra_pinfo",
                .data           = &ipv6_devconf.accept_ra_pinfo,
index a4d43eb45a9de5117ea72d9449e050d4eaa6d6ed..c2a6cda4be2895f62dfdb19fe473a6be9db421b5 100644 (file)
@@ -1284,6 +1284,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                return;
        }
 
+       lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
+
        if (!ipv6_accept_ra(in6_dev)) {
                ND_PRINTK(2, info,
                          "RA: %s, did not accept ra for dev: %s\n",
@@ -1291,6 +1293,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                goto skip_linkparms;
        }
 
+       if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) {
+               ND_PRINTK(2, info,
+                         "RA: router lifetime (%ds) is too short: %s\n",
+                         lifetime, skb->dev->name);
+               goto skip_linkparms;
+       }
+
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        /* skip link-specific parameters from interior routers */
        if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
@@ -1343,8 +1352,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                goto skip_defrtr;
        }
 
-       lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
-
 #ifdef CONFIG_IPV6_ROUTER_PREF
        pref = ra_msg->icmph.icmp6_router_pref;
        /* 10b is handled as if it were 00b (medium) */
@@ -1495,6 +1502,13 @@ skip_linkparms:
                goto out;
        }
 
+       if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) {
+               ND_PRINTK(2, info,
+                         "RA: router lifetime (%ds) is too short: %s\n",
+                         lifetime, skb->dev->name);
+               goto out;
+       }
+
 #ifdef CONFIG_IPV6_ROUTE_INFO
        if (!in6_dev->cnf.accept_ra_from_local &&
            ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,