xref: /aosp_15_r20/external/libnl/lib/route/neightbl.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4  */
5 
6 /**
7  * @ingroup rtnl
8  * @defgroup neightbl Neighbour Tables
9  * @brief
10  * @{
11  */
12 
13 #include "nl-default.h"
14 
15 #include <netlink/netlink.h>
16 #include <netlink/utils.h>
17 #include <netlink/route/rtnl.h>
18 #include <netlink/route/neightbl.h>
19 #include <netlink/route/link.h>
20 
21 #include "nl-route.h"
22 #include "nl-priv-dynamic-core/nl-core.h"
23 #include "nl-priv-dynamic-core/cache-api.h"
24 
25 struct rtnl_neightbl_parms {
26 	/**
27 	 * Interface index of the device this parameter set is assigned
28 	 * to or 0 for the default set.
29 	 */
30 	uint32_t ntp_ifindex;
31 
32 	/**
33 	 * Number of references to this parameter set.
34 	 */
35 	uint32_t ntp_refcnt;
36 
37 	/**
38 	 * Queue length for pending arp requests, i.e. the number of
39 	 * packets which are accepted from other layers while the
40 	 * neighbour address is still being resolved
41 	 */
42 	uint32_t ntp_queue_len;
43 
44 	/**
45 	 * Number of requests to send to the user level ARP daemon.
46 	 * Specify 0 to disable.
47 	 */
48 	uint32_t ntp_app_probes;
49 
50 	/**
51 	 * Maximum number of retries for unicast solicitation.
52 	 */
53 	uint32_t ntp_ucast_probes;
54 
55 	/**
56 	 * Maximum number of retries for multicast solicitation.
57 	 */
58 	uint32_t ntp_mcast_probes;
59 
60 	/**
61 	 * Base value in milliseconds to ompute reachable time, see RFC2461.
62 	 */
63 	uint64_t ntp_base_reachable_time;
64 
65 	/**
66 	 * Actual reachable time (read-only)
67 	 */
68 	uint64_t ntp_reachable_time; /* secs */
69 
70 	/**
71 	 * The time in milliseconds between retransmitted Neighbor
72 	 * Solicitation messages.
73 	 */
74 	uint64_t ntp_retrans_time;
75 
76 	/**
77 	 * Interval in milliseconds to check for stale neighbour
78 	 * entries.
79 	 */
80 	uint64_t ntp_gc_stale_time; /* secs */
81 
82 	/**
83 	 * Delay in milliseconds for the first time probe if
84 	 * the neighbour is reachable.
85 	 */
86 	uint64_t ntp_probe_delay; /* secs */
87 
88 	/**
89 	 * Maximum delay in milliseconds of an answer to a neighbour
90 	 * solicitation message.
91 	 */
92 	uint64_t ntp_anycast_delay;
93 
94 	/**
95 	 * Minimum age in milliseconds before a neighbour entry
96 	 * may be replaced.
97 	 */
98 	uint64_t ntp_locktime;
99 
100 	/**
101 	 * Delay in milliseconds before answering to an ARP request
102 	 * for which a proxy ARP entry exists.
103 	 */
104 	uint64_t ntp_proxy_delay;
105 
106 	/**
107 	 * Queue length for the delayed proxy arp requests.
108 	 */
109 	uint32_t ntp_proxy_qlen;
110 
111 	/**
112 	 * Mask of available parameter attributes
113 	 */
114 	uint32_t ntp_mask;
115 };
116 
117 #define NTBLNAMSIZ 32
118 
119 /**
120  * Neighbour table
121  * @ingroup neightbl
122  */
123 struct rtnl_neightbl {
124 	NLHDR_COMMON
125 
126 	char nt_name[NTBLNAMSIZ];
127 	uint32_t nt_family;
128 	uint32_t nt_gc_thresh1;
129 	uint32_t nt_gc_thresh2;
130 	uint32_t nt_gc_thresh3;
131 	uint64_t nt_gc_interval;
132 	struct ndt_config nt_config;
133 	struct rtnl_neightbl_parms nt_parms;
134 	struct ndt_stats nt_stats;
135 };
136 
137 /** @cond SKIP */
138 #define NEIGHTBL_ATTR_FAMILY 0x001
139 #define NEIGHTBL_ATTR_STATS 0x002
140 #define NEIGHTBL_ATTR_NAME 0x004
141 #define NEIGHTBL_ATTR_THRESH1 0x008
142 #define NEIGHTBL_ATTR_THRESH2 0x010
143 #define NEIGHTBL_ATTR_THRESH3 0x020
144 #define NEIGHTBL_ATTR_CONFIG 0x040
145 #define NEIGHTBL_ATTR_PARMS 0x080
146 #define NEIGHTBL_ATTR_GC_INTERVAL 0x100
147 
148 #define NEIGHTBLPARM_ATTR_IFINDEX 0x0001
149 #define NEIGHTBLPARM_ATTR_REFCNT 0x0002
150 #define NEIGHTBLPARM_ATTR_QUEUE_LEN 0x0004
151 #define NEIGHTBLPARM_ATTR_APP_PROBES 0x0008
152 #define NEIGHTBLPARM_ATTR_UCAST_PROBES 0x0010
153 #define NEIGHTBLPARM_ATTR_MCAST_PROBES 0x0020
154 #define NEIGHTBLPARM_ATTR_PROXY_QLEN 0x0040
155 #define NEIGHTBLPARM_ATTR_REACHABLE_TIME 0x0080
156 #define NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME 0x0100
157 #define NEIGHTBLPARM_ATTR_RETRANS_TIME 0x0200
158 #define NEIGHTBLPARM_ATTR_GC_STALETIME 0x0400
159 #define NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME 0x0800
160 #define NEIGHTBLPARM_ATTR_ANYCAST_DELAY 0x1000
161 #define NEIGHTBLPARM_ATTR_PROXY_DELAY 0x2000
162 #define NEIGHTBLPARM_ATTR_LOCKTIME 0x4000
163 
164 static struct nl_cache_ops rtnl_neightbl_ops;
165 static struct nl_object_ops neightbl_obj_ops;
166 /** @endcond */
167 
neightbl_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)168 static uint64_t neightbl_compare(struct nl_object *_a, struct nl_object *_b,
169 				 uint64_t attrs, int flags)
170 {
171 	struct rtnl_neightbl *a = (struct rtnl_neightbl *)_a;
172 	struct rtnl_neightbl *b = (struct rtnl_neightbl *)_b;
173 	uint64_t diff = 0;
174 
175 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
176 	diff |= _DIFF(NEIGHTBL_ATTR_FAMILY, a->nt_family != b->nt_family);
177 	diff |= _DIFF(NEIGHTBL_ATTR_NAME, strcmp(a->nt_name, b->nt_name));
178 	diff |= _DIFF(NEIGHTBL_ATTR_THRESH1,
179 		      a->nt_gc_thresh1 != b->nt_gc_thresh1);
180 	diff |= _DIFF(NEIGHTBL_ATTR_THRESH2,
181 		      a->nt_gc_thresh2 != b->nt_gc_thresh2);
182 	diff |= _DIFF(NEIGHTBL_ATTR_THRESH3,
183 		      a->nt_gc_thresh3 != b->nt_gc_thresh3);
184 	diff |= _DIFF(NEIGHTBL_ATTR_GC_INTERVAL,
185 		      a->nt_gc_interval != b->nt_gc_interval);
186 #undef _DIFF
187 
188 	if (!(a->ce_mask & NEIGHTBL_ATTR_PARMS) &&
189 	    !(b->ce_mask & NEIGHTBL_ATTR_PARMS))
190 		return diff;
191 
192 		/* XXX: FIXME: Compare parameter table */
193 
194 #if 0
195 #define REQ(F) (fp->ntp_mask & NEIGHTBLPARM_ATTR_##F)
196 #define AVAIL(F) (op->ntp_mask & NEIGHTBLPARM_ATTR_##F)
197 #define _C(F, N) (REQ(F) && (!AVAIL(F) || (op->N != fp->N)))
198 	if (_C(IFINDEX,			ntp_ifindex)			||
199 	    _C(QUEUE_LEN,		ntp_queue_len)			||
200 	    _C(APP_PROBES,		ntp_app_probes)			||
201 	    _C(UCAST_PROBES,		ntp_ucast_probes)		||
202 	    _C(MCAST_PROBES,		ntp_mcast_probes)		||
203 	    _C(PROXY_QLEN,		ntp_proxy_qlen)			||
204 	    _C(LOCKTIME,		ntp_locktime)			||
205 	    _C(RETRANS_TIME,		ntp_retrans_time)		||
206 	    _C(BASE_REACHABLE_TIME,	ntp_base_reachable_time)	||
207 	    _C(GC_STALETIME,		ntp_gc_stale_time)		||
208 	    _C(DELAY_PROBE_TIME,	ntp_probe_delay)		||
209 	    _C(ANYCAST_DELAY,		ntp_anycast_delay)		||
210 	    _C(PROXY_DELAY,		ntp_proxy_delay))
211 		return 0;
212 #undef REQ
213 #undef AVAIL
214 #undef _C
215 #endif
216 
217 	return diff;
218 }
219 
220 static struct nla_policy neightbl_policy[NDTA_MAX + 1] = {
221 	[NDTA_NAME] = { .type = NLA_STRING, .maxlen = NTBLNAMSIZ },
222 	[NDTA_THRESH1] = { .type = NLA_U32 },
223 	[NDTA_THRESH2] = { .type = NLA_U32 },
224 	[NDTA_THRESH3] = { .type = NLA_U32 },
225 	[NDTA_GC_INTERVAL] = { .type = NLA_U32 },
226 	[NDTA_CONFIG] = { .minlen = sizeof(struct ndt_config) },
227 	[NDTA_STATS] = { .minlen = sizeof(struct ndt_stats) },
228 	[NDTA_PARMS] = { .type = NLA_NESTED },
229 };
230 
neightbl_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)231 static int neightbl_msg_parser(struct nl_cache_ops *ops,
232 			       struct sockaddr_nl *who, struct nlmsghdr *n,
233 			       struct nl_parser_param *pp)
234 {
235 	struct rtnl_neightbl *ntbl;
236 	struct nlattr *tb[NDTA_MAX + 1];
237 	struct rtgenmsg *rtmsg;
238 	int err;
239 
240 	ntbl = rtnl_neightbl_alloc();
241 	if (!ntbl) {
242 		err = -NLE_NOMEM;
243 		goto errout;
244 	}
245 
246 	ntbl->ce_msgtype = n->nlmsg_type;
247 	rtmsg = nlmsg_data(n);
248 
249 	err = nlmsg_parse(n, sizeof(*rtmsg), tb, NDTA_MAX, neightbl_policy);
250 	if (err < 0)
251 		goto errout;
252 
253 	ntbl->nt_family = rtmsg->rtgen_family;
254 
255 	if (tb[NDTA_NAME] == NULL) {
256 		err = -NLE_MISSING_ATTR;
257 		goto errout;
258 	}
259 
260 	nla_strlcpy(ntbl->nt_name, tb[NDTA_NAME], NTBLNAMSIZ);
261 	ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
262 
263 	if (tb[NDTA_THRESH1]) {
264 		ntbl->nt_gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
265 		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
266 	}
267 
268 	if (tb[NDTA_THRESH2]) {
269 		ntbl->nt_gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
270 		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
271 	}
272 
273 	if (tb[NDTA_THRESH3]) {
274 		ntbl->nt_gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
275 		ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
276 	}
277 
278 	if (tb[NDTA_GC_INTERVAL]) {
279 		ntbl->nt_gc_interval = nla_get_u32(tb[NDTA_GC_INTERVAL]);
280 		ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
281 	}
282 
283 	if (tb[NDTA_CONFIG]) {
284 		nla_memcpy(&ntbl->nt_config, tb[NDTA_CONFIG],
285 			   sizeof(ntbl->nt_config));
286 		ntbl->ce_mask |= NEIGHTBL_ATTR_CONFIG;
287 	}
288 
289 	if (tb[NDTA_STATS]) {
290 		nla_memcpy(&ntbl->nt_stats, tb[NDTA_STATS],
291 			   sizeof(ntbl->nt_stats));
292 		ntbl->ce_mask |= NEIGHTBL_ATTR_STATS;
293 	}
294 
295 	if (tb[NDTA_PARMS]) {
296 		struct nlattr *tbp[NDTPA_MAX + 1];
297 		struct rtnl_neightbl_parms *p = &ntbl->nt_parms;
298 
299 		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], NULL);
300 		if (err < 0)
301 			goto errout;
302 
303 #define COPY_ENTRY(name, var)                                  \
304 	if (tbp[NDTPA_##name]) {                               \
305 		p->ntp_##var = nla_get_u32(tbp[NDTPA_##name]); \
306 		p->ntp_mask |= NEIGHTBLPARM_ATTR_##name;       \
307 	}
308 
309 		COPY_ENTRY(IFINDEX, ifindex);
310 		COPY_ENTRY(REFCNT, refcnt);
311 		COPY_ENTRY(QUEUE_LEN, queue_len);
312 		COPY_ENTRY(APP_PROBES, app_probes);
313 		COPY_ENTRY(UCAST_PROBES, ucast_probes);
314 		COPY_ENTRY(MCAST_PROBES, mcast_probes);
315 		COPY_ENTRY(PROXY_QLEN, proxy_qlen);
316 		COPY_ENTRY(PROXY_DELAY, proxy_delay);
317 		COPY_ENTRY(ANYCAST_DELAY, anycast_delay);
318 		COPY_ENTRY(LOCKTIME, locktime);
319 		COPY_ENTRY(REACHABLE_TIME, reachable_time);
320 		COPY_ENTRY(BASE_REACHABLE_TIME, base_reachable_time);
321 		COPY_ENTRY(RETRANS_TIME, retrans_time);
322 		COPY_ENTRY(GC_STALETIME, gc_stale_time);
323 		COPY_ENTRY(DELAY_PROBE_TIME, probe_delay);
324 #undef COPY_ENTRY
325 
326 		ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
327 	}
328 
329 	err = pp->pp_cb((struct nl_object *)ntbl, pp);
330 errout:
331 	rtnl_neightbl_put(ntbl);
332 	return err;
333 }
334 
neightbl_request_update(struct nl_cache * c,struct nl_sock * h)335 static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h)
336 {
337 	return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP);
338 }
339 
neightbl_dump_line(struct nl_object * arg,struct nl_dump_params * p)340 static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
341 {
342 	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
343 
344 	nl_dump_line(p, "%s", ntbl->nt_name);
345 
346 	if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) {
347 		struct nl_cache *link_cache;
348 
349 		link_cache = nl_cache_mngt_require_safe("route/link");
350 
351 		if (link_cache) {
352 			char buf[32];
353 			nl_dump(p, "<%s> ",
354 				rtnl_link_i2name(link_cache,
355 						 ntbl->nt_parms.ntp_ifindex,
356 						 buf, sizeof(buf)));
357 			nl_cache_put(link_cache);
358 		} else
359 			nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex);
360 	} else
361 		nl_dump(p, " ");
362 
363 	if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG)
364 		nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries);
365 
366 	if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
367 		char rt[32], rt2[32];
368 		struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
369 
370 		nl_dump(p, "reachable-time %s retransmit-time %s",
371 			nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)),
372 			nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2)));
373 	}
374 
375 	nl_dump(p, "\n");
376 }
377 
neightbl_dump_details(struct nl_object * arg,struct nl_dump_params * p)378 static void neightbl_dump_details(struct nl_object *arg,
379 				  struct nl_dump_params *p)
380 {
381 	char x[32], y[32], z[32];
382 	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
383 
384 	neightbl_dump_line(arg, p);
385 
386 	if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) {
387 		nl_dump_line(p, "    key-len %u entry-size %u last-flush %s\n",
388 			     ntbl->nt_config.ndtc_key_len,
389 			     ntbl->nt_config.ndtc_entry_size,
390 			     nl_msec2str(ntbl->nt_config.ndtc_last_flush, x,
391 					 sizeof(x)));
392 
393 		nl_dump_line(p,
394 			     "    gc threshold %u/%u/%u interval %s "
395 			     "chain-position %u\n",
396 			     ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
397 			     ntbl->nt_gc_thresh3,
398 			     nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
399 			     ntbl->nt_config.ndtc_hash_chain_gc);
400 
401 		nl_dump_line(p, "    hash-rand 0x%08X/0x%08X last-rand %s\n",
402 			     ntbl->nt_config.ndtc_hash_rnd,
403 			     ntbl->nt_config.ndtc_hash_mask,
404 			     nl_msec2str(ntbl->nt_config.ndtc_last_rand, x,
405 					 sizeof(x)));
406 	}
407 
408 	if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
409 		struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
410 
411 		nl_dump_line(p,
412 			     "    refcnt %u pending-queue-limit %u "
413 			     "proxy-delayed-queue-limit %u\n",
414 			     pa->ntp_refcnt, pa->ntp_queue_len,
415 			     pa->ntp_proxy_qlen);
416 
417 		nl_dump_line(p,
418 			     "    num-userspace-probes %u num-unicast-probes "
419 			     "%u num-multicast-probes %u\n",
420 			     pa->ntp_app_probes, pa->ntp_ucast_probes,
421 			     pa->ntp_mcast_probes);
422 
423 		nl_dump_line(p,
424 			     "    min-age %s base-reachable-time %s "
425 			     "stale-check-interval %s\n",
426 			     nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
427 			     nl_msec2str(pa->ntp_base_reachable_time, y,
428 					 sizeof(y)),
429 			     nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
430 
431 		nl_dump_line(p,
432 			     "    initial-probe-delay %s answer-delay %s "
433 			     "proxy-answer-delay %s\n",
434 			     nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
435 			     nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
436 			     nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
437 	}
438 }
439 
neightbl_dump_stats(struct nl_object * arg,struct nl_dump_params * p)440 static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
441 {
442 	struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *)arg;
443 
444 	neightbl_dump_details(arg, p);
445 
446 	if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS))
447 		return;
448 
449 	nl_dump_line(p,
450 		     "   "
451 		     " lookups %llu hits %llu failed %llu"
452 		     " allocations %llu destroys %llu\n",
453 		     (long long unsigned)ntbl->nt_stats.ndts_lookups,
454 		     (long long unsigned)ntbl->nt_stats.ndts_hits,
455 		     (long long unsigned)ntbl->nt_stats.ndts_res_failed,
456 		     (long long unsigned)ntbl->nt_stats.ndts_allocs,
457 		     (long long unsigned)ntbl->nt_stats.ndts_destroys);
458 
459 	nl_dump_line(p,
460 		     "   "
461 		     " hash-grows %llu forced-gc-runs %llu"
462 		     " periodic-gc-runs %llu\n",
463 		     (long long unsigned)ntbl->nt_stats.ndts_hash_grows,
464 		     (long long unsigned)ntbl->nt_stats.ndts_forced_gc_runs,
465 		     (long long unsigned)ntbl->nt_stats.ndts_periodic_gc_runs);
466 
467 	nl_dump_line(p,
468 		     "   "
469 		     " rcv-unicast-probes %llu"
470 		     " rcv-multicast-probes %llu"
471 		     "\n",
472 		     (long long unsigned)ntbl->nt_stats.ndts_rcv_probes_ucast,
473 		     (long long unsigned)ntbl->nt_stats.ndts_rcv_probes_mcast);
474 }
475 
476 /**
477  * @name Allocation/Freeing
478  * @{
479  */
480 
rtnl_neightbl_alloc(void)481 struct rtnl_neightbl *rtnl_neightbl_alloc(void)
482 {
483 	return (struct rtnl_neightbl *)nl_object_alloc(&neightbl_obj_ops);
484 }
485 
rtnl_neightbl_put(struct rtnl_neightbl * neightbl)486 void rtnl_neightbl_put(struct rtnl_neightbl *neightbl)
487 {
488 	nl_object_put((struct nl_object *)neightbl);
489 }
490 
491 /** @} */
492 
493 /**
494  * @name Neighbour Table Cache Management
495  * @{
496  */
497 
498 /**
499  * Build a neighbour table cache including all neighbour tables currently configured in the kernel.
500  * @arg sk		Netlink socket.
501  * @arg result		Pointer to store resulting cache.
502  *
503  * Allocates a new neighbour table cache, initializes it properly and
504  * updates it to include all neighbour tables currently configured in
505  * the kernel.
506  *
507  * @return 0 on success or a negative error code.
508  */
rtnl_neightbl_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)509 int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
510 {
511 	return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result);
512 }
513 
514 /**
515  * Lookup neighbour table by name and optional interface index
516  * @arg cache		neighbour table cache
517  * @arg name		name of table
518  * @arg ifindex		optional interface index
519  *
520  * Looks up the neighbour table matching the specified name and
521  * optionally the specified ifindex to retrieve device specific
522  * parameter sets.
523  *
524  * @return ptr to neighbour table inside the cache or NULL if no
525  *         match was found.
526  */
rtnl_neightbl_get(struct nl_cache * cache,const char * name,int ifindex)527 struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
528 					const char *name, int ifindex)
529 {
530 	struct rtnl_neightbl *nt;
531 
532 	if (cache->c_ops != &rtnl_neightbl_ops)
533 		return NULL;
534 
535 	nl_list_for_each_entry(nt, &cache->c_items, ce_list) {
536 		if (!strcasecmp(nt->nt_name, name) &&
537 		    ((unsigned)ifindex) == nt->nt_parms.ntp_ifindex) {
538 			nl_object_get((struct nl_object *)nt);
539 			return nt;
540 		}
541 	}
542 
543 	return NULL;
544 }
545 
546 /** @} */
547 
548 /**
549  * @name Neighbour Table Modifications
550  * @{
551  */
552 
553 /**
554  * Builds a netlink change request message to change neighbour table attributes
555  * @arg old		neighbour table to change
556  * @arg tmpl		template with requested changes
557  * @arg result		Pointer to store resulting message.
558  *
559  * Builds a new netlink message requesting a change of neighbour table
560  * attributes. The netlink message header isn't fully equipped with all
561  * relevant fields and must be sent out via nl_send_auto_complete() or
562  * supplemented as needed.
563  * \a old must point to a neighbour table currently configured in the
564  * kernel and \a tmpl must contain the attributes to be changed set via
565  * \c rtnl_neightbl_set_* functions.
566  *
567  * @return 0 on success or a negative error code.
568  */
rtnl_neightbl_build_change_request(struct rtnl_neightbl * old,struct rtnl_neightbl * tmpl,struct nl_msg ** result)569 int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
570 				       struct rtnl_neightbl *tmpl,
571 				       struct nl_msg **result)
572 {
573 	struct nl_msg *m, *parms = NULL;
574 	struct ndtmsg ndt = {
575 		.ndtm_family = old->nt_family,
576 	};
577 
578 	m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0);
579 	if (!m)
580 		return -NLE_NOMEM;
581 
582 	if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0)
583 		goto nla_put_failure;
584 
585 	NLA_PUT_STRING(m, NDTA_NAME, old->nt_name);
586 
587 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1)
588 		NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
589 
590 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
591 		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
592 
593 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
594 		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
595 
596 	if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL)
597 		NLA_PUT_U64(m, NDTA_GC_INTERVAL, tmpl->nt_gc_interval);
598 
599 	if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) {
600 		struct rtnl_neightbl_parms *p = &tmpl->nt_parms;
601 
602 		parms = nlmsg_alloc();
603 		if (!parms)
604 			goto nla_put_failure;
605 
606 		if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX)
607 			NLA_PUT_U32(parms, NDTPA_IFINDEX,
608 				    old->nt_parms.ntp_ifindex);
609 
610 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN)
611 			NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
612 
613 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES)
614 			NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
615 
616 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES)
617 			NLA_PUT_U32(parms, NDTPA_UCAST_PROBES,
618 				    p->ntp_ucast_probes);
619 
620 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES)
621 			NLA_PUT_U32(parms, NDTPA_MCAST_PROBES,
622 				    p->ntp_mcast_probes);
623 
624 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN)
625 			NLA_PUT_U32(parms, NDTPA_PROXY_QLEN, p->ntp_proxy_qlen);
626 
627 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME)
628 			NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME,
629 				    p->ntp_base_reachable_time);
630 
631 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME)
632 			NLA_PUT_U64(parms, NDTPA_RETRANS_TIME,
633 				    p->ntp_retrans_time);
634 
635 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME)
636 			NLA_PUT_U64(parms, NDTPA_GC_STALETIME,
637 				    p->ntp_gc_stale_time);
638 
639 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME)
640 			NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME,
641 				    p->ntp_proxy_delay);
642 
643 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY)
644 			NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY,
645 				    p->ntp_anycast_delay);
646 
647 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY)
648 			NLA_PUT_U64(parms, NDTPA_PROXY_DELAY,
649 				    p->ntp_proxy_delay);
650 
651 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
652 			NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
653 
654 		if (nla_put_nested(m, NDTA_PARMS, parms) < 0)
655 			goto nla_put_failure;
656 
657 		nlmsg_free(parms);
658 	}
659 
660 	*result = m;
661 	return 0;
662 
663 nla_put_failure:
664 	if (parms)
665 		nlmsg_free(parms);
666 	nlmsg_free(m);
667 	return -NLE_MSGSIZE;
668 }
669 
670 /**
671  * Change neighbour table attributes
672  * @arg sk		Netlink socket.
673  * @arg old		neighbour table to be changed
674  * @arg tmpl		template with requested changes
675  *
676  * Builds a new netlink message by calling
677  * rtnl_neightbl_build_change_request(), sends the request to the
678  * kernel and waits for the next ACK to be received, i.e. blocks
679  * until the request has been processed.
680  *
681  * @return 0 on success or a negative error code
682  */
rtnl_neightbl_change(struct nl_sock * sk,struct rtnl_neightbl * old,struct rtnl_neightbl * tmpl)683 int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old,
684 			 struct rtnl_neightbl *tmpl)
685 {
686 	struct nl_msg *msg;
687 	int err;
688 
689 	if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
690 		return err;
691 
692 	err = nl_send_auto_complete(sk, msg);
693 	nlmsg_free(msg);
694 	if (err < 0)
695 		return err;
696 
697 	return wait_for_ack(sk);
698 }
699 
700 /** @} */
701 
702 /**
703  * @name Attribute Modification
704  * @{
705  */
706 
rtnl_neightbl_set_family(struct rtnl_neightbl * ntbl,int family)707 void rtnl_neightbl_set_family(struct rtnl_neightbl *ntbl, int family)
708 {
709 	ntbl->nt_family = family;
710 	ntbl->ce_mask |= NEIGHTBL_ATTR_FAMILY;
711 }
712 
rtnl_neightbl_set_gc_interval(struct rtnl_neightbl * ntbl,uint64_t ms)713 void rtnl_neightbl_set_gc_interval(struct rtnl_neightbl *ntbl, uint64_t ms)
714 {
715 	ntbl->nt_gc_interval = ms;
716 	ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
717 }
718 
rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl * ntbl,int thresh)719 void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *ntbl, int thresh)
720 {
721 	ntbl->nt_gc_thresh1 = thresh;
722 	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
723 }
724 
rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl * ntbl,int thresh)725 void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *ntbl, int thresh)
726 {
727 	ntbl->nt_gc_thresh2 = thresh;
728 	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
729 }
730 
rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl * ntbl,int thresh)731 void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *ntbl, int thresh)
732 {
733 	ntbl->nt_gc_thresh3 = thresh;
734 	ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
735 }
736 
rtnl_neightbl_set_name(struct rtnl_neightbl * ntbl,const char * name)737 void rtnl_neightbl_set_name(struct rtnl_neightbl *ntbl, const char *name)
738 {
739 	_nl_strncpy_trunc(ntbl->nt_name, name, sizeof(ntbl->nt_name));
740 	ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
741 }
742 
rtnl_neightbl_set_dev(struct rtnl_neightbl * ntbl,int ifindex)743 void rtnl_neightbl_set_dev(struct rtnl_neightbl *ntbl, int ifindex)
744 {
745 	ntbl->nt_parms.ntp_ifindex = ifindex;
746 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_IFINDEX;
747 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
748 }
749 
750 /**
751  * Set the queue length for pending requests of a neighbour table to the specified value
752  * @arg ntbl		neighbour table to change
753  * @arg len		new queue len
754  */
rtnl_neightbl_set_queue_len(struct rtnl_neightbl * ntbl,int len)755 void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *ntbl, int len)
756 {
757 	ntbl->nt_parms.ntp_queue_len = len;
758 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_QUEUE_LEN;
759 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
760 }
761 
762 /**
763  * Set the queue length for delay proxy arp requests of a neighbour table to the specified value
764  * @arg ntbl		neighbour table to change
765  * @arg len		new queue len
766  */
rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl * ntbl,int len)767 void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *ntbl, int len)
768 {
769 	ntbl->nt_parms.ntp_proxy_qlen = len;
770 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_QLEN;
771 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
772 }
773 
774 /**
775  * Set the number of application probes of a neighbour table to the specified value
776  * @arg ntbl		neighbour table to change
777  * @arg probes		new probes value
778  */
rtnl_neightbl_set_app_probes(struct rtnl_neightbl * ntbl,int probes)779 void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *ntbl, int probes)
780 {
781 	ntbl->nt_parms.ntp_app_probes = probes;
782 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_APP_PROBES;
783 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
784 }
785 
786 /**
787  * Set the number of unicast probes of a neighbour table to the specified value
788  * @arg ntbl		neighbour table to change
789  * @arg probes		new probes value
790  */
rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl * ntbl,int probes)791 void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *ntbl, int probes)
792 {
793 	ntbl->nt_parms.ntp_ucast_probes = probes;
794 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_UCAST_PROBES;
795 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
796 }
797 
798 /**
799  * Set the number of multicast probes of a neighbour table to the specified value
800  * @arg ntbl		neighbour table to change
801  * @arg probes		new probes value
802  */
rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl * ntbl,int probes)803 void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *ntbl, int probes)
804 {
805 	ntbl->nt_parms.ntp_mcast_probes = probes;
806 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_MCAST_PROBES;
807 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
808 }
809 
810 /**
811  * Set the base reachable time of a neighbour table to the specified value
812  * @arg ntbl		neighbour table to change
813  * @arg ms		new base reachable time in milliseconds
814  */
rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl * ntbl,uint64_t ms)815 void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *ntbl,
816 					   uint64_t ms)
817 {
818 	ntbl->nt_parms.ntp_base_reachable_time = ms;
819 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME;
820 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
821 }
822 
823 /**
824  * Set the retransmit time of a neighbour table to the specified value
825  * @arg ntbl		neighbour table to change
826  * @arg ms		new retransmit time
827  */
rtnl_neightbl_set_retrans_time(struct rtnl_neightbl * ntbl,uint64_t ms)828 void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *ntbl, uint64_t ms)
829 {
830 	ntbl->nt_parms.ntp_retrans_time = ms;
831 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_RETRANS_TIME;
832 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
833 }
834 
835 /**
836  * Set the gc stale time of a neighbour table to the specified value
837  * @arg ntbl		neighbour table to change
838  * @arg ms		new gc stale time in milliseconds
839  */
rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl * ntbl,uint64_t ms)840 void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *ntbl, uint64_t ms)
841 {
842 	ntbl->nt_parms.ntp_gc_stale_time = ms;
843 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_GC_STALETIME;
844 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
845 }
846 
847 /**
848  * Set the first probe delay time of a neighbour table to the specified value
849  * @arg ntbl		neighbour table to change
850  * @arg ms		new first probe delay time in milliseconds
851  */
rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl * ntbl,uint64_t ms)852 void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *ntbl, uint64_t ms)
853 {
854 	ntbl->nt_parms.ntp_probe_delay = ms;
855 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME;
856 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
857 }
858 
859 /**
860  * Set the anycast delay of a neighbour table to the specified value
861  * @arg ntbl		neighbour table to change
862  * @arg ms		new anycast delay in milliseconds
863  */
rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl * ntbl,uint64_t ms)864 void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
865 {
866 	ntbl->nt_parms.ntp_anycast_delay = ms;
867 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_ANYCAST_DELAY;
868 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
869 }
870 
871 /**
872  * Set the proxy delay of a neighbour table to the specified value
873  * @arg ntbl		neighbour table to change
874  * @arg ms		new proxy delay in milliseconds
875  */
rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl * ntbl,uint64_t ms)876 void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
877 {
878 	ntbl->nt_parms.ntp_proxy_delay = ms;
879 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_DELAY;
880 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
881 }
882 
883 /**
884  * Set the locktime of a neighbour table to the specified value
885  * @arg ntbl		neighbour table to change
886  * @arg ms		new locktime in milliseconds
887  */
rtnl_neightbl_set_locktime(struct rtnl_neightbl * ntbl,uint64_t ms)888 void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms)
889 {
890 	ntbl->nt_parms.ntp_locktime = ms;
891 	ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_LOCKTIME;
892 	ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
893 }
894 
895 /** @} */
896 
897 static struct nl_object_ops neightbl_obj_ops = {
898 	.oo_name		= "route/neightbl",
899 	.oo_size		= sizeof(struct rtnl_neightbl),
900 	.oo_dump = {
901 	    [NL_DUMP_LINE]	= neightbl_dump_line,
902 	    [NL_DUMP_DETAILS]	= neightbl_dump_details,
903 	    [NL_DUMP_STATS]	= neightbl_dump_stats,
904 	},
905 	.oo_compare		= neightbl_compare,
906 };
907 
908 static struct nl_cache_ops rtnl_neightbl_ops = {
909 	.co_name		= "route/neightbl",
910 	.co_hdrsize		= sizeof(struct rtgenmsg),
911 	.co_msgtypes		= {
912 					{ RTM_NEWNEIGHTBL, NL_ACT_NEW, "new" },
913 					{ RTM_SETNEIGHTBL, NL_ACT_SET, "set" },
914 					{ RTM_GETNEIGHTBL, NL_ACT_GET, "get" },
915 					END_OF_MSGTYPES_LIST,
916 				  },
917 	.co_protocol		= NETLINK_ROUTE,
918 	.co_request_update	= neightbl_request_update,
919 	.co_msg_parser		= neightbl_msg_parser,
920 	.co_obj_ops		= &neightbl_obj_ops,
921 };
922 
neightbl_init(void)923 static void _nl_init neightbl_init(void)
924 {
925 	nl_cache_mngt_register(&rtnl_neightbl_ops);
926 }
927 
neightbl_exit(void)928 static void _nl_exit neightbl_exit(void)
929 {
930 	nl_cache_mngt_unregister(&rtnl_neightbl_ops);
931 }
932 
933 /** @} */
934