@@ -154,11 +154,12 @@ static void neigh_update_gc_list(struct neighbour *n)
154
154
if (n -> dead )
155
155
goto out ;
156
156
157
- /* remove from the gc list if new state is permanent or if neighbor
158
- * is externally learned; otherwise entry should be on the gc list
157
+ /* remove from the gc list if new state is permanent or if neighbor is
158
+ * externally learned / validated; otherwise entry should be on the gc
159
+ * list
159
160
*/
160
161
exempt_from_gc = n -> nud_state & NUD_PERMANENT ||
161
- n -> flags & NTF_EXT_LEARNED ;
162
+ n -> flags & ( NTF_EXT_LEARNED | NTF_EXT_VALIDATED ) ;
162
163
on_gc_list = !list_empty (& n -> gc_list );
163
164
164
165
if (exempt_from_gc && on_gc_list ) {
@@ -205,6 +206,7 @@ static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
205
206
206
207
ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED ) ? NTF_EXT_LEARNED : 0 ;
207
208
ndm_flags |= (flags & NEIGH_UPDATE_F_MANAGED ) ? NTF_MANAGED : 0 ;
209
+ ndm_flags |= (flags & NEIGH_UPDATE_F_EXT_VALIDATED ) ? NTF_EXT_VALIDATED : 0 ;
208
210
209
211
if ((old_flags ^ ndm_flags ) & NTF_EXT_LEARNED ) {
210
212
if (ndm_flags & NTF_EXT_LEARNED )
@@ -222,6 +224,14 @@ static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
222
224
* notify = 1 ;
223
225
* managed_update = true;
224
226
}
227
+ if ((old_flags ^ ndm_flags ) & NTF_EXT_VALIDATED ) {
228
+ if (ndm_flags & NTF_EXT_VALIDATED )
229
+ neigh -> flags |= NTF_EXT_VALIDATED ;
230
+ else
231
+ neigh -> flags &= ~NTF_EXT_VALIDATED ;
232
+ * notify = 1 ;
233
+ * gc_update = true;
234
+ }
225
235
}
226
236
227
237
bool neigh_remove_one (struct neighbour * n )
@@ -379,7 +389,9 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
379
389
dev_head = neigh_get_dev_table (dev , tbl -> family );
380
390
381
391
hlist_for_each_entry_safe (n , tmp , dev_head , dev_list ) {
382
- if (skip_perm && n -> nud_state & NUD_PERMANENT )
392
+ if (skip_perm &&
393
+ (n -> nud_state & NUD_PERMANENT ||
394
+ n -> flags & NTF_EXT_VALIDATED ))
383
395
continue ;
384
396
385
397
hlist_del_rcu (& n -> hash );
@@ -942,7 +954,8 @@ static void neigh_periodic_work(struct work_struct *work)
942
954
943
955
state = n -> nud_state ;
944
956
if ((state & (NUD_PERMANENT | NUD_IN_TIMER )) ||
945
- (n -> flags & NTF_EXT_LEARNED )) {
957
+ (n -> flags &
958
+ (NTF_EXT_LEARNED | NTF_EXT_VALIDATED ))) {
946
959
write_unlock (& n -> lock );
947
960
continue ;
948
961
}
@@ -1095,9 +1108,15 @@ static void neigh_timer_handler(struct timer_list *t)
1095
1108
1096
1109
if ((neigh -> nud_state & (NUD_INCOMPLETE | NUD_PROBE )) &&
1097
1110
atomic_read (& neigh -> probes ) >= neigh_max_probes (neigh )) {
1098
- WRITE_ONCE (neigh -> nud_state , NUD_FAILED );
1111
+ if (neigh -> nud_state == NUD_PROBE &&
1112
+ neigh -> flags & NTF_EXT_VALIDATED ) {
1113
+ WRITE_ONCE (neigh -> nud_state , NUD_STALE );
1114
+ neigh -> updated = jiffies ;
1115
+ } else {
1116
+ WRITE_ONCE (neigh -> nud_state , NUD_FAILED );
1117
+ neigh_invalidate (neigh );
1118
+ }
1099
1119
notify = 1 ;
1100
- neigh_invalidate (neigh );
1101
1120
goto out ;
1102
1121
}
1103
1122
@@ -1245,6 +1264,8 @@ static void neigh_update_hhs(struct neighbour *neigh)
1245
1264
NTF_ROUTER flag.
1246
1265
NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1247
1266
a router.
1267
+ NEIGH_UPDATE_F_EXT_VALIDATED means that the entry will not be removed
1268
+ or invalidated.
1248
1269
1249
1270
Caller MUST hold reference count on the entry.
1250
1271
*/
@@ -1979,7 +2000,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1979
2000
if (ndm_flags & NTF_PROXY ) {
1980
2001
struct pneigh_entry * pn ;
1981
2002
1982
- if (ndm_flags & NTF_MANAGED ) {
2003
+ if (ndm_flags & ( NTF_MANAGED | NTF_EXT_VALIDATED ) ) {
1983
2004
NL_SET_ERR_MSG (extack , "Invalid NTF_* flag combination" );
1984
2005
goto out ;
1985
2006
}
@@ -2010,7 +2031,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
2010
2031
if (neigh == NULL ) {
2011
2032
bool ndm_permanent = ndm -> ndm_state & NUD_PERMANENT ;
2012
2033
bool exempt_from_gc = ndm_permanent ||
2013
- ndm_flags & NTF_EXT_LEARNED ;
2034
+ ndm_flags & (NTF_EXT_LEARNED |
2035
+ NTF_EXT_VALIDATED );
2014
2036
2015
2037
if (!(nlh -> nlmsg_flags & NLM_F_CREATE )) {
2016
2038
err = - ENOENT ;
@@ -2021,10 +2043,27 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
2021
2043
err = - EINVAL ;
2022
2044
goto out ;
2023
2045
}
2046
+ if (ndm_flags & NTF_EXT_VALIDATED ) {
2047
+ u8 state = ndm -> ndm_state ;
2048
+
2049
+ /* NTF_USE and NTF_MANAGED will result in the neighbor
2050
+ * being created with an invalid state (NUD_NONE).
2051
+ */
2052
+ if (ndm_flags & (NTF_USE | NTF_MANAGED ))
2053
+ state = NUD_NONE ;
2054
+
2055
+ if (!(state & NUD_VALID )) {
2056
+ NL_SET_ERR_MSG (extack ,
2057
+ "Cannot create externally validated neighbor with an invalid state" );
2058
+ err = - EINVAL ;
2059
+ goto out ;
2060
+ }
2061
+ }
2024
2062
2025
2063
neigh = ___neigh_create (tbl , dst , dev ,
2026
2064
ndm_flags &
2027
- (NTF_EXT_LEARNED | NTF_MANAGED ),
2065
+ (NTF_EXT_LEARNED | NTF_MANAGED |
2066
+ NTF_EXT_VALIDATED ),
2028
2067
exempt_from_gc , true);
2029
2068
if (IS_ERR (neigh )) {
2030
2069
err = PTR_ERR (neigh );
@@ -2036,6 +2075,24 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
2036
2075
neigh_release (neigh );
2037
2076
goto out ;
2038
2077
}
2078
+ if (ndm_flags & NTF_EXT_VALIDATED ) {
2079
+ u8 state = ndm -> ndm_state ;
2080
+
2081
+ /* NTF_USE and NTF_MANAGED do not update the existing
2082
+ * state other than clearing it if it was
2083
+ * NUD_PERMANENT.
2084
+ */
2085
+ if (ndm_flags & (NTF_USE | NTF_MANAGED ))
2086
+ state = READ_ONCE (neigh -> nud_state ) & ~NUD_PERMANENT ;
2087
+
2088
+ if (!(state & NUD_VALID )) {
2089
+ NL_SET_ERR_MSG (extack ,
2090
+ "Cannot mark neighbor as externally validated with an invalid state" );
2091
+ err = - EINVAL ;
2092
+ neigh_release (neigh );
2093
+ goto out ;
2094
+ }
2095
+ }
2039
2096
2040
2097
if (!(nlh -> nlmsg_flags & NLM_F_REPLACE ))
2041
2098
flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
@@ -2052,6 +2109,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
2052
2109
flags |= NEIGH_UPDATE_F_MANAGED ;
2053
2110
if (ndm_flags & NTF_USE )
2054
2111
flags |= NEIGH_UPDATE_F_USE ;
2112
+ if (ndm_flags & NTF_EXT_VALIDATED )
2113
+ flags |= NEIGH_UPDATE_F_EXT_VALIDATED ;
2055
2114
2056
2115
err = __neigh_update (neigh , lladdr , ndm -> ndm_state , flags ,
2057
2116
NETLINK_CB (skb ).portid , extack );
0 commit comments