@@ -154,11 +154,12 @@ static void neigh_update_gc_list(struct neighbour *n)
154154 if (n -> dead )
155155 goto out ;
156156
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
159160 */
160161 exempt_from_gc = n -> nud_state & NUD_PERMANENT ||
161- n -> flags & NTF_EXT_LEARNED ;
162+ n -> flags & ( NTF_EXT_LEARNED | NTF_EXT_VALIDATED ) ;
162163 on_gc_list = !list_empty (& n -> gc_list );
163164
164165 if (exempt_from_gc && on_gc_list ) {
@@ -205,6 +206,7 @@ static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
205206
206207 ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED ) ? NTF_EXT_LEARNED : 0 ;
207208 ndm_flags |= (flags & NEIGH_UPDATE_F_MANAGED ) ? NTF_MANAGED : 0 ;
209+ ndm_flags |= (flags & NEIGH_UPDATE_F_EXT_VALIDATED ) ? NTF_EXT_VALIDATED : 0 ;
208210
209211 if ((old_flags ^ ndm_flags ) & NTF_EXT_LEARNED ) {
210212 if (ndm_flags & NTF_EXT_LEARNED )
@@ -222,6 +224,14 @@ static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
222224 * notify = 1 ;
223225 * managed_update = true;
224226 }
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+ }
225235}
226236
227237bool neigh_remove_one (struct neighbour * n )
@@ -379,7 +389,9 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
379389 dev_head = neigh_get_dev_table (dev , tbl -> family );
380390
381391 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 ))
383395 continue ;
384396
385397 hlist_del_rcu (& n -> hash );
@@ -942,7 +954,8 @@ static void neigh_periodic_work(struct work_struct *work)
942954
943955 state = n -> nud_state ;
944956 if ((state & (NUD_PERMANENT | NUD_IN_TIMER )) ||
945- (n -> flags & NTF_EXT_LEARNED )) {
957+ (n -> flags &
958+ (NTF_EXT_LEARNED | NTF_EXT_VALIDATED ))) {
946959 write_unlock (& n -> lock );
947960 continue ;
948961 }
@@ -1095,9 +1108,15 @@ static void neigh_timer_handler(struct timer_list *t)
10951108
10961109 if ((neigh -> nud_state & (NUD_INCOMPLETE | NUD_PROBE )) &&
10971110 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+ }
10991119 notify = 1 ;
1100- neigh_invalidate (neigh );
11011120 goto out ;
11021121 }
11031122
@@ -1245,6 +1264,8 @@ static void neigh_update_hhs(struct neighbour *neigh)
12451264 NTF_ROUTER flag.
12461265 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
12471266 a router.
1267+ NEIGH_UPDATE_F_EXT_VALIDATED means that the entry will not be removed
1268+ or invalidated.
12481269
12491270 Caller MUST hold reference count on the entry.
12501271 */
@@ -1979,7 +2000,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
19792000 if (ndm_flags & NTF_PROXY ) {
19802001 struct pneigh_entry * pn ;
19812002
1982- if (ndm_flags & NTF_MANAGED ) {
2003+ if (ndm_flags & ( NTF_MANAGED | NTF_EXT_VALIDATED ) ) {
19832004 NL_SET_ERR_MSG (extack , "Invalid NTF_* flag combination" );
19842005 goto out ;
19852006 }
@@ -2010,7 +2031,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
20102031 if (neigh == NULL ) {
20112032 bool ndm_permanent = ndm -> ndm_state & NUD_PERMANENT ;
20122033 bool exempt_from_gc = ndm_permanent ||
2013- ndm_flags & NTF_EXT_LEARNED ;
2034+ ndm_flags & (NTF_EXT_LEARNED |
2035+ NTF_EXT_VALIDATED );
20142036
20152037 if (!(nlh -> nlmsg_flags & NLM_F_CREATE )) {
20162038 err = - ENOENT ;
@@ -2021,10 +2043,27 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
20212043 err = - EINVAL ;
20222044 goto out ;
20232045 }
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+ }
20242062
20252063 neigh = ___neigh_create (tbl , dst , dev ,
20262064 ndm_flags &
2027- (NTF_EXT_LEARNED | NTF_MANAGED ),
2065+ (NTF_EXT_LEARNED | NTF_MANAGED |
2066+ NTF_EXT_VALIDATED ),
20282067 exempt_from_gc , true);
20292068 if (IS_ERR (neigh )) {
20302069 err = PTR_ERR (neigh );
@@ -2036,6 +2075,24 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
20362075 neigh_release (neigh );
20372076 goto out ;
20382077 }
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+ }
20392096
20402097 if (!(nlh -> nlmsg_flags & NLM_F_REPLACE ))
20412098 flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
@@ -2052,6 +2109,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
20522109 flags |= NEIGH_UPDATE_F_MANAGED ;
20532110 if (ndm_flags & NTF_USE )
20542111 flags |= NEIGH_UPDATE_F_USE ;
2112+ if (ndm_flags & NTF_EXT_VALIDATED )
2113+ flags |= NEIGH_UPDATE_F_EXT_VALIDATED ;
20552114
20562115 err = __neigh_update (neigh , lladdr , ndm -> ndm_state , flags ,
20572116 NETLINK_CB (skb ).portid , extack );
0 commit comments