1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
From: Stephen Hemminger <stephen@networkplumber.org>
Date: Mon, 29 Apr 2013 18:50:15 -0700
Subject: [PATCH] VyOS: Add linkstate IP device attribute
Backport of earlier Vyatta patch.
(cherry picked from commit 7c5a851086686be14ae937c80d6cee34814dbefc)
Refreshed against Linux 6.18.x:
* include/uapi/linux/ipv6.h gained DEVCONF_FORCE_FORWARDING; insert
DEVCONF_LINK_FILTER after it so the new sentinel keeps a stable value.
* include/linux/ipv6.h grew ra_honor_pio_life / ra_honor_pio_pflag
members before sysctl_header.
* net/ipv6/addrconf.c::ipv6_store_devconf() now uses READ_ONCE() and
publishes DEVCONF_FORCE_FORWARDING; use READ_ONCE() for link_filter
and append after force_forwarding.
* net/ipv6/route.c context shifted; rt6_link_filter() unchanged.
---
Documentation/networking/ip-sysctl.rst | 11 +++++++++++
include/linux/inetdevice.h | 1 +
include/linux/ipv6.h | 1 +
include/uapi/linux/ip.h | 1 +
include/uapi/linux/ipv6.h | 1 +
net/ipv4/devinet.c | 1 +
net/ipv6/addrconf.c | 8 ++++++++
net/ipv6/route.c | 10 ++++++++++
8 files changed, 34 insertions(+)
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -2042,6 +2042,17 @@ src_valid_mark - BOOLEAN
Default value is 0.
+link_filter - INTEGER
+ 0 - Allow packets to be received for the address on this interface
+ even if interface is disabled or no carrier.
+ 1 - Ignore packets received if interface associated with the incoming
+ address is down.
+ 2 - Ignore packets received if interface associated with the incoming
+ address is down or has no carrier.
+
+ Default value is 0. Note that some distributions enable it
+ in startup scripts.
+
arp_filter - BOOLEAN
- 1 - Allows you to have multiple network interfaces on the same
subnet, and have the ARPs for each interface be answered
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -139,6 +139,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
#define IN_DEV_ARP_EVICT_NOCARRIER(in_dev) IN_DEV_ANDCONF((in_dev), \
ARP_EVICT_NOCARRIER)
+#define IN_DEV_LINKFILTER(in_dev) IN_DEV_MAXCONF((in_dev), LINKFILTER)
struct in_ifaddr {
struct hlist_node addr_lst;
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -91,6 +91,7 @@ struct ipv6_devconf {
__u8 ndisc_evict_nocarrier;
__u8 ra_honor_pio_life;
__u8 ra_honor_pio_pflag;
+ __s32 link_filter;
struct ctl_table_header *sysctl_header;
};
diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
--- a/include/uapi/linux/ip.h
+++ b/include/uapi/linux/ip.h
@@ -189,6 +189,7 @@ enum
IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
IPV4_DEVCONF_BC_FORWARDING,
IPV4_DEVCONF_ARP_EVICT_NOCARRIER,
+ IPV4_DEVCONF_LINKFILTER,
__IPV4_DEVCONF_MAX
};
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -200,6 +200,7 @@ enum {
DEVCONF_ACCEPT_UNTRACKED_NA,
DEVCONF_ACCEPT_RA_MIN_LFT,
DEVCONF_FORCE_FORWARDING,
+ DEVCONF_LINK_FILTER,
DEVCONF_MAX
};
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2652,6 +2652,7 @@ static struct devinet_sysctl_table {
"route_localnet"),
DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
"drop_unicast_in_l2_multicast"),
+ DEVINET_SYSCTL_RW_ENTRY(LINKFILTER, "link_filter"),
},
};
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5716,6 +5716,7 @@ static void ipv6_store_devconf(const struct ipv6_devconf *cnf,
READ_ONCE(cnf->accept_untracked_na);
array[DEVCONF_ACCEPT_RA_MIN_LFT] = READ_ONCE(cnf->accept_ra_min_lft);
array[DEVCONF_FORCE_FORWARDING] = READ_ONCE(cnf->force_forwarding);
+ array[DEVCONF_LINK_FILTER] = READ_ONCE(cnf->link_filter);
}
static inline size_t inet6_ifla6_size(void)
@@ -7251,6 +7252,13 @@ static const struct ctl_table addrconf_sysctl[] = {
.extra1 = (void *)SYSCTL_ZERO,
.extra2 = (void *)SYSCTL_ONE,
},
+ {
+ .procname = "link_filter",
+ .data = &ipv6_devconf.link_filter,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{
.procname = "ioam6_id",
.data = &ipv6_devconf.ioam6_id,
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -714,6 +714,14 @@ static inline void rt6_probe(struct fib6_nh *fib6_nh)
}
#endif
+static inline int rt6_link_filter(const struct fib6_nh *nh)
+{
+ const struct net_device *dev = nh->fib_nh_dev;
+ int linkf = __in6_dev_get(dev)->cnf.link_filter;
+ return (linkf && !netif_running(dev))
+ || (linkf > 1 && !netif_carrier_ok(dev));
+}
+
/*
* Default Router Selection (RFC 2461 6.3.6)
*/
@@ -755,6 +763,8 @@ static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
if (!m && (strict & RT6_LOOKUP_F_IFACE))
return RT6_NUD_FAIL_HARD;
+ if (rt6_link_filter(nh))
+ return -1;
#ifdef CONFIG_IPV6_ROUTER_PREF
m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(fib6_flags)) << 2;
#endif
--
2.39.5
|