Skip to content

Commit a2aa335

Browse files
authored
PATCH] net: allow user to set metric on default route learned via Router Advertisement (#326)
Add patch from Linux 5.12 to allow user to set metric on default route learned via Router Advertisement message for IPv6 Signed-off-by: Abhishek Dosi <[email protected]>
1 parent e72818f commit a2aa335

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
From 23d559efa7ddfccb29dfe2df772217e55402cd71 Mon Sep 17 00:00:00 2001
2+
From: Praveen Chaudhary <[email protected]>
3+
Date: Mon, 25 Jan 2021 13:44:30 -0800
4+
Subject: [PATCH] net: allow user to set metric on default route learned via
5+
Router Advertisement
6+
7+
For IPv4, default route is learned via DHCPv4 and user is allowed to change
8+
metric using config etc/network/interfaces. But for IPv6, default route can
9+
be learned via RA, for which, currently a fixed metric value 1024 is used.
10+
11+
Ideally, user should be able to configure metric on default route for IPv6
12+
similar to IPv4. This patch adds sysctl for the same.
13+
14+
Logs:
15+
16+
For IPv4:
17+
18+
Config in etc/network/interfaces:
19+
auto eth0
20+
iface eth0 inet dhcp
21+
metric 4261413864
22+
23+
IPv4 Kernel Route Table:
24+
$ ip route list
25+
default via 172.21.47.1 dev eth0 metric 4261413864
26+
27+
FRR Table, if a static route is configured:
28+
[In real scenario, it is useful to prefer BGP learned default route over DHCPv4 default route.]
29+
Codes: K - kernel route, C - connected, S - static, R - RIP,
30+
O - OSPF, I - IS-IS, B - BGP, P - PIM, E - EIGRP, N - NHRP,
31+
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
32+
> - selected route, * - FIB route
33+
34+
S>* 0.0.0.0/0 [20/0] is directly connected, eth0, 00:00:03
35+
K 0.0.0.0/0 [254/1000] via 172.21.47.1, eth0, 6d08h51m
36+
37+
i.e. User can prefer Default Router learned via Routing Protocol in IPv4.
38+
Similar behavior is not possible for IPv6, without this fix.
39+
40+
After fix [for IPv6]:
41+
sudo sysctl -w net.ipv6.conf.eth0.net.ipv6.conf.eth0.ra_defrtr_metric=1996489705
42+
43+
IP monitor: [When IPv6 RA is received]
44+
default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489705 pref high
45+
46+
Kernel IPv6 routing table
47+
$ ip -6 route list
48+
default via fe80::be16:65ff:feb3:ce8e dev eth0 proto ra metric 1996489705 expires 21sec hoplimit 64 pref high
49+
50+
FRR Table, if a static route is configured:
51+
[In real scenario, it is useful to prefer BGP learned default route over IPv6 RA default route.]
52+
Codes: K - kernel route, C - connected, S - static, R - RIPng,
53+
O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table,
54+
v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
55+
> - selected route, * - FIB route
56+
57+
S>* ::/0 [20/0] is directly connected, eth0, 00:00:06
58+
K ::/0 [119/1001] via fe80::xx16:xxxx:feb3:ce8e, eth0, 6d07h43m
59+
60+
If the metric is changed later, the effect will be seen only when next IPv6
61+
RA is received, because the default route must be fully controlled by RA msg.
62+
Below metric is changed from 1996489705 to 1996489704.
63+
64+
$ sudo sysctl -w net.ipv6.conf.eth0.ra_defrtr_metric=1996489704
65+
net.ipv6.conf.eth0.ra_defrtr_metric = 1996489704
66+
67+
IP monitor:
68+
[On next IPv6 RA msg, Kernel deletes prev route and installs new route with updated metric]
69+
70+
Deleted default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489705 expires 3sec hoplimit 64 pref high
71+
default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489704 pref high
72+
73+
Signed-off-by: Praveen Chaudhary <[email protected]>
74+
Signed-off-by: Zhenggen Xu <[email protected]>
75+
Reviewed-by: David Ahern <[email protected]>
76+
Link: https://lore.kernel.org/r/[email protected]
77+
Signed-off-by: Jakub Kicinski <[email protected]>
78+
---
79+
Documentation/networking/ip-sysctl.rst | 10 ++++++++++
80+
include/linux/ipv6.h | 1 +
81+
include/net/ip6_route.h | 3 ++-
82+
include/uapi/linux/ipv6.h | 1 +
83+
include/uapi/linux/sysctl.h | 1 +
84+
net/ipv6/addrconf.c | 11 +++++++++++
85+
net/ipv6/ndisc.c | 12 ++++++++----
86+
net/ipv6/route.c | 5 +++--
87+
8 files changed, 37 insertions(+), 7 deletions(-)
88+
89+
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
90+
index bf1f0ec9740b..e4e1216e6a7d 100644
91+
--- a/Documentation/networking/ip-sysctl.rst
92+
+++ b/Documentation/networking/ip-sysctl.rst
93+
@@ -1876,6 +1876,16 @@ accept_ra_defrtr - BOOLEAN
94+
- enabled if accept_ra is enabled.
95+
- disabled if accept_ra is disabled.
96+
97+
+ra_defrtr_metric - UNSIGNED INTEGER
98+
+ Route metric for default route learned in Router Advertisement. This value
99+
+ will be assigned as metric for the default route learned via IPv6 Router
100+
+ Advertisement. Takes affect only if accept_ra_defrtr is enabled.
101+
+
102+
+ Possible values:
103+
+ 1 to 0xFFFFFFFF
104+
+
105+
+ Default: IP6_RT_PRIO_USER i.e. 1024.
106+
+
107+
accept_ra_from_local - BOOLEAN
108+
Accept RA with source-address that is found on local machine
109+
if the RA is otherwise proper and able to be accepted.
110+
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
111+
index 7a918daa3b19..88641e3b1cc4 100644
112+
--- a/include/linux/ipv6.h
113+
+++ b/include/linux/ipv6.h
114+
@@ -31,6 +31,7 @@ struct ipv6_devconf {
115+
__s32 max_desync_factor;
116+
__s32 max_addresses;
117+
__s32 accept_ra_defrtr;
118+
+ __u32 ra_defrtr_metric;
119+
__s32 accept_ra_min_hop_limit;
120+
__s32 accept_ra_pinfo;
121+
__s32 ignore_routes_with_linkdown;
122+
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
123+
index 44969d03debf..0bf09a9bca4e 100644
124+
--- a/include/net/ip6_route.h
125+
+++ b/include/net/ip6_route.h
126+
@@ -174,7 +174,8 @@ struct fib6_info *rt6_get_dflt_router(struct net *net,
127+
struct net_device *dev);
128+
struct fib6_info *rt6_add_dflt_router(struct net *net,
129+
const struct in6_addr *gwaddr,
130+
- struct net_device *dev, unsigned int pref);
131+
+ struct net_device *dev, unsigned int pref,
132+
+ u32 defrtr_usr_metric);
133+
134+
void rt6_purge_dflt_routers(struct net *net);
135+
136+
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
137+
index 9cdbc5b04855..a5e93062315b 100644
138+
--- a/include/uapi/linux/ipv6.h
139+
+++ b/include/uapi/linux/ipv6.h
140+
@@ -190,6 +190,7 @@ enum {
141+
DEVCONF_NDISC_TCLASS,
142+
DEVCONF_RPL_SEG_ENABLED,
143+
DEVCONF_ACCEPT_UNTRACKED_NA,
144+
+ DEVCONF_RA_DEFRTR_METRIC,
145+
DEVCONF_MAX
146+
};
147+
148+
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
149+
index 09dabb76a113..6a3b194c50fe 100644
150+
--- a/include/uapi/linux/sysctl.h
151+
+++ b/include/uapi/linux/sysctl.h
152+
@@ -572,6 +572,7 @@ enum {
153+
NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
154+
NET_IPV6_ACCEPT_RA_FROM_LOCAL=26,
155+
NET_IPV6_ACCEPT_RA_RT_INFO_MIN_PLEN=27,
156+
+ NET_IPV6_RA_DEFRTR_METRIC=28,
157+
__NET_IPV6_MAX
158+
};
159+
160+
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
161+
index 038708de6ef9..cac1e63dac54 100644
162+
--- a/net/ipv6/addrconf.c
163+
+++ b/net/ipv6/addrconf.c
164+
@@ -205,6 +205,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
165+
.max_desync_factor = MAX_DESYNC_FACTOR,
166+
.max_addresses = IPV6_MAX_ADDRESSES,
167+
.accept_ra_defrtr = 1,
168+
+ .ra_defrtr_metric = IP6_RT_PRIO_USER,
169+
.accept_ra_from_local = 0,
170+
.accept_ra_min_hop_limit= 1,
171+
.accept_ra_pinfo = 1,
172+
@@ -260,6 +261,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
173+
.max_desync_factor = MAX_DESYNC_FACTOR,
174+
.max_addresses = IPV6_MAX_ADDRESSES,
175+
.accept_ra_defrtr = 1,
176+
+ .ra_defrtr_metric = IP6_RT_PRIO_USER,
177+
.accept_ra_from_local = 0,
178+
.accept_ra_min_hop_limit= 1,
179+
.accept_ra_pinfo = 1,
180+
@@ -5512,6 +5514,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
181+
array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
182+
array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
183+
array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
184+
+ array[DEVCONF_RA_DEFRTR_METRIC] = cnf->ra_defrtr_metric;
185+
array[DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT] = cnf->accept_ra_min_hop_limit;
186+
array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
187+
#ifdef CONFIG_IPV6_ROUTER_PREF
188+
@@ -6705,6 +6708,14 @@ static const struct ctl_table addrconf_sysctl[] = {
189+
.mode = 0644,
190+
.proc_handler = proc_dointvec,
191+
},
192+
+ {
193+
+ .procname = "ra_defrtr_metric",
194+
+ .data = &ipv6_devconf.ra_defrtr_metric,
195+
+ .maxlen = sizeof(u32),
196+
+ .mode = 0644,
197+
+ .proc_handler = proc_douintvec_minmax,
198+
+ .extra1 = (void *)SYSCTL_ONE,
199+
+ },
200+
{
201+
.procname = "accept_ra_min_hop_limit",
202+
.data = &ipv6_devconf.accept_ra_min_hop_limit,
203+
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
204+
index f236ed938efd..85cd34710a04 100644
205+
--- a/net/ipv6/ndisc.c
206+
+++ b/net/ipv6/ndisc.c
207+
@@ -1199,6 +1199,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
208+
struct neighbour *neigh = NULL;
209+
struct inet6_dev *in6_dev;
210+
struct fib6_info *rt = NULL;
211+
+ u32 defrtr_usr_metric;
212+
struct net *net;
213+
int lifetime;
214+
struct ndisc_options ndopts;
215+
@@ -1329,18 +1330,21 @@ static void ndisc_router_discovery(struct sk_buff *skb)
216+
return;
217+
}
218+
}
219+
- if (rt && lifetime == 0) {
220+
+ /* Set default route metric as specified by user */
221+
+ defrtr_usr_metric = in6_dev->cnf.ra_defrtr_metric;
222+
+ /* delete the route if lifetime is 0 or if metric needs change */
223+
+ if (rt && (lifetime == 0 || rt->fib6_metric != defrtr_usr_metric)) {
224+
ip6_del_rt(net, rt, false);
225+
rt = NULL;
226+
}
227+
228+
- ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
229+
- rt, lifetime, skb->dev->name);
230+
+ ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, metric: %d, for dev: %s\n",
231+
+ rt, lifetime, defrtr_usr_metric, skb->dev->name);
232+
if (!rt && lifetime) {
233+
ND_PRINTK(3, info, "RA: adding default router\n");
234+
235+
rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr,
236+
- skb->dev, pref);
237+
+ skb->dev, pref, defrtr_usr_metric);
238+
if (!rt) {
239+
ND_PRINTK(0, err,
240+
"RA: %s failed to add default route\n",
241+
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
242+
index cdf215442d37..2a32cc7db014 100644
243+
--- a/net/ipv6/route.c
244+
+++ b/net/ipv6/route.c
245+
@@ -4269,11 +4269,12 @@ struct fib6_info *rt6_get_dflt_router(struct net *net,
246+
struct fib6_info *rt6_add_dflt_router(struct net *net,
247+
const struct in6_addr *gwaddr,
248+
struct net_device *dev,
249+
- unsigned int pref)
250+
+ unsigned int pref,
251+
+ u32 defrtr_usr_metric)
252+
{
253+
struct fib6_config cfg = {
254+
.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
255+
- .fc_metric = IP6_RT_PRIO_USER,
256+
+ .fc_metric = defrtr_usr_metric,
257+
.fc_ifindex = dev->ifindex,
258+
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
259+
RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
260+
--
261+
2.25.1
262+

patch/series

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ kernel-compat-always-include-linux-compat.h-from-net-compat.patch
5050
0001-net-ipv6-Introduce-accept_unsolicited_na-knob-to-imp.patch
5151
0002-net-ipv6-Expand-and-rename-accept_unsolicited_na-to-.patch
5252

53+
# Backport from 5.12
54+
0001-net-allow-user-to-set-metric-on-default-route-learne.patch
55+
5356
#
5457
# This series applies on GIT commit 1451b36b2b0d62178e42f648d8a18131af18f7d8
5558
# Tkernel-sched-core-fix-cgroup-fork-race.patch

0 commit comments

Comments
 (0)