Skip to content

Commit e24b267

Browse files
author
Praveen Chaudhary
committed
Later Linux kernel community path
Signed-off-by: Praveen Chaudhary<[email protected]>
1 parent 79ab859 commit e24b267

File tree

2 files changed

+277
-0
lines changed

2 files changed

+277
-0
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
commit f27953bfdfdaa182a7740c0c79392e55e24f0cac
2+
Author: pchaudha <[email protected]>
3+
Date: Tue Dec 29 05:05:01 2020 +0000
4+
5+
Allow user to set metric on default route learned via 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 fix adds sysctl for the same.
13+
14+
Signed-off-by: Praveen Chaudhary <[email protected]>
15+
Signed-off-by: Zhenggen Xu <[email protected]>
16+
17+
Changes in v1.
18+
1.) Correct the call to rt6_add_dflt_router.
19+
20+
Changes in v2.
21+
1.) Replace accept_ra_defrtr_metric to ra_defrtr_metric.
22+
2.) Change Type to __u32 instead of __s32.
23+
3.) Change description in Documentation/networking/ip-sysctl.rst.
24+
4.) Use proc_douintvec instead of proc_dointvec.
25+
5.) Code style in ndisc_router_discovery().
26+
6.) Change Type to u32 instead of unsigned int.
27+
28+
Changes in v3:
29+
1.) Removed '---' and '```' from description.
30+
2.) Remove stray ' after accept_ra_defrtr.
31+
3.) Fix tab in net/ipv6/addrconf.c.
32+
Logs:
33+
34+
For IPv4:
35+
36+
Config in etc/network/interfaces:
37+
auto eth0
38+
iface eth0 inet dhcp
39+
metric 4261413864
40+
41+
IPv4 Kernel Route Table:
42+
$ ip route list
43+
default via 172.21.47.1 dev eth0 metric 4261413864
44+
45+
FRR Table, if a static route is configured:
46+
[In real scenario, it is useful to prefer BGP learned default route over DHCPv4 default route.]
47+
Codes: K - kernel route, C - connected, S - static, R - RIP,
48+
O - OSPF, I - IS-IS, B - BGP, P - PIM, E - EIGRP, N - NHRP,
49+
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
50+
> - selected route, * - FIB route
51+
52+
S>* 0.0.0.0/0 [20/0] is directly connected, eth0, 00:00:03
53+
K 0.0.0.0/0 [254/1000] via 172.21.47.1, eth0, 6d08h51m
54+
55+
i.e. User can prefer Default Router learned via Routing Protocol in IPv4.
56+
Similar behavior is not possible for IPv6, without this fix.
57+
58+
After fix [for IPv6]:
59+
sudo sysctl -w net.ipv6.conf.eth0.net.ipv6.conf.eth0.ra_defrtr_metric=1996489705
60+
61+
IP monitor: [When IPv6 RA is received]
62+
default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489705 pref high
63+
64+
Kernel IPv6 routing table
65+
$ ip -6 route list
66+
default via fe80::be16:65ff:feb3:ce8e dev eth0 proto ra metric 1996489705 expires 21sec hoplimit 64 pref high
67+
68+
FRR Table, if a static route is configured:
69+
[In real scenario, it is useful to prefer BGP learned default route over IPv6 RA default route.]
70+
Codes: K - kernel route, C - connected, S - static, R - RIPng,
71+
O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table,
72+
v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
73+
> - selected route, * - FIB route
74+
75+
S>* ::/0 [20/0] is directly connected, eth0, 00:00:06
76+
K ::/0 [119/1001] via fe80::xx16:xxxx:feb3:ce8e, eth0, 6d07h43m
77+
78+
If the metric is changed later, the effect will be seen only when next IPv6
79+
RA is received, because the default route must be fully controlled by RA msg.
80+
Below metric is changed from 1996489705 to 1996489704.
81+
82+
$ sudo sysctl -w net.ipv6.conf.eth0.ra_defrtr_metric=1996489704
83+
net.ipv6.conf.eth0.ra_defrtr_metric = 1996489704
84+
85+
IP monitor:
86+
[On next IPv6 RA msg, Kernel deletes prev route and installs new route with updated metric]
87+
88+
Deleted default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489705  expires 3sec hoplimit 64 pref high
89+
default via fe80::xx16:xxxx:feb3:ce8e dev eth0 proto ra metric 1996489704  pref high
90+
91+
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
92+
index 7eb9366..4b09fca 100644
93+
--- a/Documentation/networking/ip-sysctl.txt
94+
+++ b/Documentation/networking/ip-sysctl.txt
95+
@@ -1537,6 +1537,24 @@ accept_ra_defrtr - BOOLEAN
96+
Functional default: enabled if accept_ra is enabled.
97+
disabled if accept_ra is disabled.
98+
99+
+ra_defrtr_metric - INTEGER
100+
+ Route metric for default route learned in Router Advertisement. This value
101+
+ will be assigned as metric for the default route learned via IPv6 Router
102+
+ Advertisement. Takes affect only if accept_ra_defrtr is enabled.
103+
+
104+
+ Possible values are:
105+
+ 0:
106+
+ default value will be used for route metric
107+
+ i.e. IP6_RT_PRIO_USER 1024.
108+
+ 1 to 0xFFFFFFFF:
109+
+ current value will be used for route metric.
110+
+
111+
accept_ra_from_local - BOOLEAN
112+
Accept RA with source-address that is found on local machine
113+
if the RA is otherwise proper and able to be accepted.
114+
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
115+
index 8415bf1..0add3f6 100644
116+
--- a/include/linux/ipv6.h
117+
+++ b/include/linux/ipv6.h
118+
@@ -31,6 +31,7 @@ struct ipv6_devconf {
119+
__s32 max_desync_factor;
120+
__s32 max_addresses;
121+
__s32 accept_ra_defrtr;
122+
+ __u32 ra_defrtr_metric;
123+
__s32 accept_ra_min_hop_limit;
124+
__s32 accept_ra_pinfo;
125+
__s32 ignore_routes_with_linkdown;
126+
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
127+
index 5e26d61..031cc8c 100644
128+
--- a/include/net/ip6_route.h
129+
+++ b/include/net/ip6_route.h
130+
@@ -153,7 +153,8 @@ struct fib6_info *rt6_get_dflt_router(struct net *net,
131+
struct net_device *dev);
132+
struct fib6_info *rt6_add_dflt_router(struct net *net,
133+
const struct in6_addr *gwaddr,
134+
- struct net_device *dev, unsigned int pref);
135+
+ struct net_device *dev, unsigned int pref,
136+
+ u32 defrtr_usr_metric);
137+
138+
void rt6_purge_dflt_routers(struct net *net);
139+
140+
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
141+
index 9c0f4a9..93449ac 100644
142+
--- a/include/uapi/linux/ipv6.h
143+
+++ b/include/uapi/linux/ipv6.h
144+
@@ -187,6 +187,7 @@ enum {
145+
DEVCONF_DISABLE_POLICY,
146+
DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
147+
DEVCONF_NDISC_TCLASS,
148+
+ DEVCONF_RA_DEFRTR_METRIC,
149+
DEVCONF_MAX
150+
};
151+
152+
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
153+
index d71013f..f1f37ab 100644
154+
--- a/include/uapi/linux/sysctl.h
155+
+++ b/include/uapi/linux/sysctl.h
156+
@@ -570,6 +570,7 @@ enum {
157+
NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
158+
NET_IPV6_ACCEPT_RA_FROM_LOCAL=26,
159+
NET_IPV6_ACCEPT_RA_RT_INFO_MIN_PLEN=27,
160+
+ NET_IPV6_RA_DEFRTR_METRIC=28,
161+
__NET_IPV6_MAX
162+
};
163+
164+
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
165+
index 07148b4..d8990f8 100644
166+
--- a/kernel/sysctl_binary.c
167+
+++ b/kernel/sysctl_binary.c
168+
@@ -525,6 +525,7 @@ static const struct bin_table bin_net_ipv6_conf_var_table[] = {
169+
{ CTL_INT, NET_IPV6_PROXY_NDP, "proxy_ndp" },
170+
{ CTL_INT, NET_IPV6_ACCEPT_SOURCE_ROUTE, "accept_source_route" },
171+
{ CTL_INT, NET_IPV6_ACCEPT_RA_FROM_LOCAL, "accept_ra_from_local" },
172+
+ { CTL_INT, NET_IPV6_RA_DEFRTR_METRIC, "ra_defrtr_metric" },
173+
{}
174+
};
175+
176+
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
177+
index 627cd24..2dfc9d9 100644
178+
--- a/net/ipv6/addrconf.c
179+
+++ b/net/ipv6/addrconf.c
180+
@@ -209,6 +209,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
181+
.max_desync_factor = MAX_DESYNC_FACTOR,
182+
.max_addresses = IPV6_MAX_ADDRESSES,
183+
.accept_ra_defrtr = 1,
184+
+ .ra_defrtr_metric = 0,
185+
.accept_ra_from_local = 0,
186+
.accept_ra_min_hop_limit= 1,
187+
.accept_ra_pinfo = 1,
188+
@@ -263,6 +264,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
189+
.max_desync_factor = MAX_DESYNC_FACTOR,
190+
.max_addresses = IPV6_MAX_ADDRESSES,
191+
.accept_ra_defrtr = 1,
192+
+ .ra_defrtr_metric = 0,
193+
.accept_ra_from_local = 0,
194+
.accept_ra_min_hop_limit= 1,
195+
.accept_ra_pinfo = 1,
196+
@@ -5199,6 +5201,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
197+
array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
198+
array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
199+
array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
200+
+ array[DEVCONF_RA_DEFRTR_METRIC] = cnf->ra_defrtr_metric;
201+
array[DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT] = cnf->accept_ra_min_hop_limit;
202+
array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
203+
#ifdef CONFIG_IPV6_ROUTER_PREF
204+
@@ -6348,6 +6351,13 @@ static const struct ctl_table addrconf_sysctl[] = {
205+
.proc_handler = proc_dointvec,
206+
},
207+
{
208+
+ .procname = "ra_defrtr_metric",
209+
+ .data = &ipv6_devconf.ra_defrtr_metric,
210+
+ .maxlen = sizeof(u32),
211+
+ .mode = 0644,
212+
+ .proc_handler = proc_douintvec,
213+
+ },
214+
+ {
215+
.procname = "accept_ra_min_hop_limit",
216+
.data = &ipv6_devconf.accept_ra_min_hop_limit,
217+
.maxlen = sizeof(int),
218+
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
219+
index 673a4a9..30738344 100644
220+
--- a/net/ipv6/ndisc.c
221+
+++ b/net/ipv6/ndisc.c
222+
@@ -1156,6 +1156,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
223+
struct neighbour *neigh = NULL;
224+
struct inet6_dev *in6_dev;
225+
struct fib6_info *rt = NULL;
226+
+ u32 defrtr_usr_metric;
227+
struct net *net;
228+
int lifetime;
229+
struct ndisc_options ndopts;
230+
@@ -1287,18 +1288,23 @@ static void ndisc_router_discovery(struct sk_buff *skb)
231+
return;
232+
}
233+
}
234+
- if (rt && lifetime == 0) {
235+
+ /* Set default route metric if specified by user */
236+
+ defrtr_usr_metric = in6_dev->cnf.ra_defrtr_metric;
237+
+ if (defrtr_usr_metric == 0)
238+
+ defrtr_usr_metric = IP6_RT_PRIO_USER;
239+
+ /* delete the route if lifetime is 0 or if metric needs change */
240+
+ if (rt && ((lifetime == 0) || (rt->fib6_metric != defrtr_usr_metric))) {
241+
ip6_del_rt(net, rt);
242+
rt = NULL;
243+
}
244+
245+
- ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n",
246+
- rt, lifetime, skb->dev->name);
247+
+ ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, metric: %d, for dev: %s\n",
248+
+ rt, lifetime, defrtr_usr_metric, skb->dev->name);
249+
if (!rt && lifetime) {
250+
ND_PRINTK(3, info, "RA: adding default router\n");
251+
252+
rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr,
253+
- skb->dev, pref);
254+
+ skb->dev, pref, defrtr_usr_metric);
255+
if (!rt) {
256+
ND_PRINTK(0, err,
257+
"RA: %s failed to add default route\n",
258+
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
259+
index 9c36a74..1dc2ba5 100644
260+
--- a/net/ipv6/route.c
261+
+++ b/net/ipv6/route.c
262+
@@ -3608,11 +3608,12 @@ struct fib6_info *rt6_get_dflt_router(struct net *net,
263+
struct fib6_info *rt6_add_dflt_router(struct net *net,
264+
const struct in6_addr *gwaddr,
265+
struct net_device *dev,
266+
- unsigned int pref)
267+
+ unsigned int pref,
268+
+ u32 defrtr_usr_metric)
269+
{
270+
struct fib6_config cfg = {
271+
.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
272+
- .fc_metric = IP6_RT_PRIO_USER,
273+
+ .fc_metric = defrtr_usr_metric ? : IP6_RT_PRIO_USER,
274+
.fc_ifindex = dev->ifindex,
275+
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
276+
RTF_UP | RTF_EXPIRES | RTF_PREF(pref),

patch/series

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ e1000-Do-not-perform-reset-in-reset_task-if-we-are-a.patch
3636
macsec-Support-XPN-frame-handling-IEEE-802.1AEbw.patch
3737
netlink-add-NLA_MIN_LEN.patch
3838
macsec-Netlink-support-of-XPN-cipher-suites-IEEE-802.patch
39+
kernel-ipv6-ra-metric-sysctl.patch
3940
Support-for-fullcone-nat.patch
4041
driver-ixgbe-external-phy.patch
4142
#

0 commit comments

Comments
 (0)