xref: /aosp_15_r20/external/libnl/lib/route/neigh.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 neigh Neighbours
9  * @brief
10  *
11  * The neighbour table establishes bindings between protocol addresses and
12  * link layer addresses for hosts sharing the same physical link. This
13  * module allows you to access and manipulate the content of these tables.
14  *
15  * @par Neighbour States
16  * @code
17  * NUD_INCOMPLETE
18  * NUD_REACHABLE
19  * NUD_STALE
20  * NUD_DELAY
21  * NUD_PROBE
22  * NUD_FAILED
23  * NUD_NOARP
24  * NUD_PERMANENT
25  * @endcode
26  *
27  * @par Neighbour Flags
28  * @code
29  * NTF_USE
30  * NTF_PROXY
31  * NTF_ROUTER
32  * NTF_SELF
33  * @endcode
34  *
35  * @par Neighbour Identification
36  * A neighbour is uniquely identified by the attributes listed below, whenever
37  * you refer to an existing neighbour all of the attributes must be set.
38  * Neighbours from caches automatically have all required attributes set.
39  *   - interface index (rtnl_neigh_set_ifindex())
40  *   - destination address (rtnl_neigh_set_dst())
41  *
42  * @par Changeable Attributes
43  * \anchor neigh_changeable
44  *  - state (rtnl_neigh_set_state())
45  *  - link layer address (rtnl_neigh_set_lladdr())
46  *
47  * @par Required Caches for Dumping
48  * In order to dump neighbour attributes you must provide the following
49  * caches via nl_cache_provide()
50  *  - link cache holding all links
51  *
52  * @par TODO
53  *   - Document proxy settings
54  *   - Document states and their influence
55  *
56  * @par 1) Retrieving information about configured neighbours
57  * @code
58  * // The first step is to retrieve a list of all available neighbour within
59  * // the kernel and put them into a cache.
60  * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
61  *
62  * // Neighbours can then be looked up by the interface and destination
63  * // address:
64  * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
65  *
66  * // After successful usage, the object must be given back to the cache
67  * rtnl_neigh_put(neigh);
68  * @endcode
69  *
70  * @par 2) Adding new neighbours
71  * @code
72  * // Allocate an empty neighbour handle to be filled out with the attributes
73  * // of the new neighbour.
74  * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
75  *
76  * // Fill out the attributes of the new neighbour
77  * rtnl_neigh_set_ifindex(neigh, ifindex);
78  * rtnl_neigh_set_dst(neigh, dst_addr);
79  * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent"));
80  *
81  * // Build the netlink message and send it to the kernel, the operation will
82  * // block until the operation has been completed. Alternatively the required
83  * // netlink message can be built using rtnl_neigh_build_add_request()
84  * // to be sent out using nl_send_auto_complete().
85  * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
86  *
87  * // Free the memory
88  * rtnl_neigh_put(neigh);
89  * @endcode
90  *
91  * @par 3) Deleting an existing neighbour
92  * @code
93  * // Allocate an empty neighbour object to be filled out with the attributes
94  * // matching the neighbour to be deleted. Alternatively a fully equipped
95  * // neighbour object out of a cache can be used instead.
96  * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
97  *
98  * // Neighbours are uniquely identified by their interface index and
99  * // destination address, you may fill out other attributes but they
100  * // will have no influence.
101  * rtnl_neigh_set_ifindex(neigh, ifindex);
102  * rtnl_neigh_set_dst(neigh, dst_addr);
103  *
104  * // Build the netlink message and send it to the kernel, the operation will
105  * // block until the operation has been completed. Alternatively the required
106  * // netlink message can be built using rtnl_neigh_build_delete_request()
107  * // to be sent out using nl_send_auto_complete().
108  * rtnl_neigh_delete(sk, neigh, 0);
109  *
110  * // Free the memory
111  * rtnl_neigh_put(neigh);
112  * @endcode
113  *
114  * @par 4) Changing neighbour attributes
115  * @code
116  * // Allocate an empty neighbour object to be filled out with the attributes
117  * // matching the neighbour to be changed and the new parameters. Alternatively
118  * // a fully equipped modified neighbour object out of a cache can be used.
119  * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
120  *
121  * // Identify the neighbour to be changed by its interface index and
122  * // destination address
123  * rtnl_neigh_set_ifindex(neigh, ifindex);
124  * rtnl_neigh_set_dst(neigh, dst_addr);
125  *
126  * // The link layer address may be modified, if so it is wise to change
127  * // its state to "permanent" in order to avoid having it overwritten.
128  * rtnl_neigh_set_lladdr(neigh, lladdr);
129  *
130  * // Secondly the state can be modified allowing normal neighbours to be
131  * // converted into permanent entries or to manually confirm a neighbour.
132  * rtnl_neigh_set_state(neigh, state);
133  *
134  * // Build the netlink message and send it to the kernel, the operation will
135  * // block until the operation has been completed. Alternatively the required
136  * // netlink message can be built using rtnl_neigh_build_change_request()
137  * // to be sent out using nl_send_auto_complete().
138  * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
139  *
140  * // Free the memory
141  * rtnl_neigh_put(neigh);
142  * @endcode
143  * @{
144  */
145 
146 #include "nl-default.h"
147 
148 #include <netlink/netlink.h>
149 #include <netlink/utils.h>
150 #include <netlink/hashtable.h>
151 #include <netlink/route/rtnl.h>
152 #include <netlink/route/neighbour.h>
153 #include <netlink/route/link.h>
154 #include <netlink/hashtable.h>
155 
156 #include "nl-route.h"
157 #include "nl-priv-dynamic-core/nl-core.h"
158 #include "nl-priv-dynamic-core/cache-api.h"
159 
160 /** @cond SKIP */
161 struct rtnl_ncacheinfo {
162 	uint32_t nci_confirmed; /**< Time since neighbour validty was last confirmed */
163 	uint32_t nci_used; /**< Time since neighbour entry was last ued */
164 	uint32_t nci_updated; /**< Time since last update */
165 	uint32_t nci_refcnt; /**< Reference counter */
166 };
167 
168 struct rtnl_neigh {
169 	NLHDR_COMMON
170 	uint32_t n_family;
171 	uint32_t n_ifindex;
172 	uint16_t n_state;
173 	uint8_t n_flags;
174 	uint8_t n_type;
175 	struct nl_addr *n_lladdr;
176 	struct nl_addr *n_dst;
177 	uint32_t n_nhid;
178 	uint32_t n_probes;
179 	struct rtnl_ncacheinfo n_cacheinfo;
180 	uint32_t n_state_mask;
181 	uint32_t n_flag_mask;
182 	uint32_t n_master;
183 	uint16_t n_vlan;
184 };
185 
186 #define NEIGH_ATTR_FLAGS        0x01
187 #define NEIGH_ATTR_STATE        0x02
188 #define NEIGH_ATTR_LLADDR       0x04
189 #define NEIGH_ATTR_DST          0x08
190 #define NEIGH_ATTR_CACHEINFO    0x10
191 #define NEIGH_ATTR_IFINDEX      0x20
192 #define NEIGH_ATTR_FAMILY       0x40
193 #define NEIGH_ATTR_TYPE         0x80
194 #define NEIGH_ATTR_PROBES       0x100
195 #define NEIGH_ATTR_MASTER       0x200
196 #define NEIGH_ATTR_VLAN         0x400
197 #define NEIGH_ATTR_NHID         0x800
198 
199 static struct nl_cache_ops rtnl_neigh_ops;
200 static struct nl_object_ops neigh_obj_ops;
201 /** @endcond */
202 
neigh_free_data(struct nl_object * c)203 static void neigh_free_data(struct nl_object *c)
204 {
205 	struct rtnl_neigh *neigh = nl_object_priv(c);
206 
207 	if (!neigh)
208 		return;
209 
210 	nl_addr_put(neigh->n_lladdr);
211 	nl_addr_put(neigh->n_dst);
212 }
213 
neigh_clone(struct nl_object * _dst,struct nl_object * _src)214 static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
215 {
216 	struct rtnl_neigh *dst = nl_object_priv(_dst);
217 	struct rtnl_neigh *src = nl_object_priv(_src);
218 
219 	dst->n_lladdr = NULL;
220 	dst->n_dst = NULL;
221 
222 	if (src->n_lladdr)
223 		if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
224 			return -NLE_NOMEM;
225 
226 	if (src->n_dst)
227 		if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
228 			return -NLE_NOMEM;
229 
230 	return 0;
231 }
232 
neigh_keygen(struct nl_object * obj,uint32_t * hashkey,uint32_t table_sz)233 static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
234 			 uint32_t table_sz)
235 {
236 	struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
237 	unsigned int nkey_sz;
238 	struct nl_addr *addr = NULL;
239 	struct neigh_hash_key {
240 		uint32_t	n_family;
241 		uint32_t	n_ifindex;
242 		uint16_t	n_vlan;
243 		char		n_addr[0];
244 	} _nl_packed *nkey;
245 	char buf[INET6_ADDRSTRLEN+5];
246 
247 	if (neigh->n_family == AF_BRIDGE) {
248 		if (neigh->n_lladdr)
249 			addr = neigh->n_lladdr;
250 	} else if (neigh->n_dst) {
251 		addr = neigh->n_dst;
252 	}
253 
254 	nkey_sz = sizeof(*nkey);
255 	if (addr)
256 		nkey_sz += nl_addr_get_len(addr);
257 
258 	nkey = calloc(1, nkey_sz);
259 	if (!nkey) {
260 		*hashkey = 0;
261 		return;
262 	}
263 	nkey->n_family = neigh->n_family;
264 	if (neigh->n_family == AF_BRIDGE) {
265 		nkey->n_vlan = neigh->n_vlan;
266 		if (neigh->n_flags & NTF_SELF)
267 			nkey->n_ifindex = neigh->n_ifindex;
268 		else
269 			nkey->n_ifindex = neigh->n_master;
270 	} else
271 		nkey->n_ifindex = neigh->n_ifindex;
272 
273 	if (addr)
274 		memcpy(nkey->n_addr,
275 			nl_addr_get_binary_addr(addr),
276 			nl_addr_get_len(addr));
277 
278 	*hashkey = nl_hash(nkey, nkey_sz, 0) % table_sz;
279 
280 	NL_DBG(5, "neigh %p key (fam %d dev %d addr %s) keysz %d hash 0x%x\n",
281 		neigh, nkey->n_family, nkey->n_ifindex,
282 		nl_addr2str(addr, buf, sizeof(buf)),
283 		nkey_sz, *hashkey);
284 
285 	free(nkey);
286 
287 	return;
288 }
289 
neigh_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)290 static uint64_t neigh_compare(struct nl_object *_a, struct nl_object *_b,
291 			      uint64_t attrs, int flags)
292 {
293 	struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
294 	struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
295 	uint64_t diff = 0;
296 
297 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
298 	diff |= _DIFF(NEIGH_ATTR_IFINDEX, a->n_ifindex != b->n_ifindex);
299 	diff |= _DIFF(NEIGH_ATTR_FAMILY, a->n_family != b->n_family);
300 	diff |= _DIFF(NEIGH_ATTR_TYPE, a->n_type != b->n_type);
301 	diff |= _DIFF(NEIGH_ATTR_LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
302 	diff |= _DIFF(NEIGH_ATTR_DST, nl_addr_cmp(a->n_dst, b->n_dst));
303 	diff |= _DIFF(NEIGH_ATTR_MASTER, a->n_master != b->n_master);
304 	diff |= _DIFF(NEIGH_ATTR_VLAN, a->n_vlan != b->n_vlan);
305 	diff |= _DIFF(NEIGH_ATTR_NHID, a->n_nhid != b->n_nhid);
306 
307 	if (flags & LOOSE_COMPARISON) {
308 		diff |= _DIFF(NEIGH_ATTR_STATE,
309 			      (a->n_state ^ b->n_state) & b->n_state_mask);
310 		diff |= _DIFF(NEIGH_ATTR_FLAGS,
311 			      (a->n_flags ^ b->n_flags) & b->n_flag_mask);
312 	} else {
313 		diff |= _DIFF(NEIGH_ATTR_STATE, a->n_state != b->n_state);
314 		diff |= _DIFF(NEIGH_ATTR_FLAGS, a->n_flags != b->n_flags);
315 	}
316 #undef _DIFF
317 
318 	return diff;
319 }
320 
321 static const struct trans_tbl neigh_attrs[] = {
322 	__ADD(NEIGH_ATTR_FLAGS, flags),
323 	__ADD(NEIGH_ATTR_STATE, state),
324 	__ADD(NEIGH_ATTR_LLADDR, lladdr),
325 	__ADD(NEIGH_ATTR_DST, dst),
326 	__ADD(NEIGH_ATTR_CACHEINFO, cacheinfo),
327 	__ADD(NEIGH_ATTR_IFINDEX, ifindex),
328 	__ADD(NEIGH_ATTR_FAMILY, family),
329 	__ADD(NEIGH_ATTR_TYPE, type),
330 	__ADD(NEIGH_ATTR_PROBES, probes),
331 	__ADD(NEIGH_ATTR_MASTER, master),
332 	__ADD(NEIGH_ATTR_VLAN, vlan),
333 	__ADD(NEIGH_ATTR_NHID, nhid),
334 };
335 
neigh_attrs2str(int attrs,char * buf,size_t len)336 static char *neigh_attrs2str(int attrs, char *buf, size_t len)
337 {
338 	return __flags2str(attrs, buf, len, neigh_attrs,
339 			   ARRAY_SIZE(neigh_attrs));
340 }
341 
neigh_id_attrs_get(struct nl_object * obj)342 static uint32_t neigh_id_attrs_get(struct nl_object *obj)
343 {
344 	struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
345 
346 	if (neigh->n_family == AF_BRIDGE) {
347 		if (neigh->n_flags & NTF_SELF)
348 			return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
349 				       ((neigh->ce_mask & NEIGH_ATTR_DST) ? NEIGH_ATTR_DST: 0) |
350 				       ((neigh->ce_mask & NEIGH_ATTR_NHID) ? NEIGH_ATTR_NHID: 0) |
351 				       ((neigh->ce_mask & NEIGH_ATTR_VLAN) ? NEIGH_ATTR_VLAN : 0));
352 		else
353 			return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER | NEIGH_ATTR_VLAN);
354 	} else
355 		return neigh_obj_ops.oo_id_attrs;
356 }
357 
358 static struct nla_policy neigh_policy[NDA_MAX+1] = {
359 	[NDA_CACHEINFO]	= { .minlen = sizeof(struct nda_cacheinfo) },
360 	[NDA_PROBES]	= { .type = NLA_U32 },
361 };
362 
neigh_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)363 static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
364 			    struct nlmsghdr *n, struct nl_parser_param *pp)
365 {
366 	struct rtnl_neigh *neigh;
367 	int err;
368 
369 	if ((err = rtnl_neigh_parse(n, &neigh)) < 0)
370 		return err;
371 
372 	err = pp->pp_cb((struct nl_object *) neigh, pp);
373 
374 	rtnl_neigh_put(neigh);
375 	return err;
376 }
377 
378 
rtnl_neigh_parse(struct nlmsghdr * n,struct rtnl_neigh ** result)379 int rtnl_neigh_parse(struct nlmsghdr *n, struct rtnl_neigh **result)
380 {
381 	struct rtnl_neigh *neigh;
382 	struct nlattr *tb[NDA_MAX + 1];
383 	struct ndmsg *nm;
384 	int err;
385 
386 	neigh = rtnl_neigh_alloc();
387 	if (!neigh) {
388 		err = -NLE_NOMEM;
389 		goto errout;
390 	}
391 
392 	neigh->ce_msgtype = n->nlmsg_type;
393 	nm = nlmsg_data(n);
394 
395 	err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
396 	if (err < 0)
397 		goto errout;
398 
399 	neigh->n_family  = nm->ndm_family;
400 	neigh->n_ifindex = nm->ndm_ifindex;
401 	neigh->n_state   = nm->ndm_state;
402 	neigh->n_flags   = nm->ndm_flags;
403 	neigh->n_type    = nm->ndm_type;
404 
405 	neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
406 			   NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
407 			   NEIGH_ATTR_TYPE);
408 
409 	if (tb[NDA_LLADDR]) {
410 		neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
411 		if (!neigh->n_lladdr) {
412 			err = -NLE_NOMEM;
413 			goto errout;
414 		}
415 		nl_addr_set_family(neigh->n_lladdr,
416 				   nl_addr_guess_family(neigh->n_lladdr));
417 		neigh->ce_mask |= NEIGH_ATTR_LLADDR;
418 	}
419 
420 	if (tb[NDA_DST]) {
421 		neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], AF_UNSPEC);
422 		if (!neigh->n_dst) {
423 			err = -NLE_NOMEM;
424 			goto errout;
425 		}
426 		nl_addr_set_family(neigh->n_dst,
427 				   nl_addr_guess_family(neigh->n_dst));
428 		neigh->ce_mask |= NEIGH_ATTR_DST;
429 	}
430 
431 	if (tb[NDA_CACHEINFO]) {
432 		struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
433 
434 		neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
435 		neigh->n_cacheinfo.nci_used = ci->ndm_used;
436 		neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
437 		neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
438 
439 		neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
440 	}
441 
442 	if (tb[NDA_PROBES]) {
443 		neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
444 		neigh->ce_mask |= NEIGH_ATTR_PROBES;
445 	}
446 
447 	if (tb[NDA_VLAN]) {
448 		neigh->n_vlan = nla_get_u16(tb[NDA_VLAN]);
449 		neigh->ce_mask |= NEIGH_ATTR_VLAN;
450 	}
451 
452 	if (tb[NDA_NH_ID]) {
453 		neigh->n_nhid = nla_get_u32(tb[NDA_NH_ID]);
454 		neigh->ce_mask |= NEIGH_ATTR_NHID;
455 	}
456 
457 	/*
458 	 * Get the bridge index for AF_BRIDGE family entries
459 	 */
460 	if (neigh->n_family == AF_BRIDGE) {
461 		if (tb[NDA_MASTER]) {
462 			neigh->n_master = nla_get_u32(tb[NDA_MASTER]);
463 			neigh->ce_mask |= NEIGH_ATTR_MASTER;
464 		} else {
465 			struct nl_cache *lcache = nl_cache_mngt_require_safe("route/link");
466 			if (lcache ) {
467 				struct rtnl_link *link = rtnl_link_get(lcache,
468 								       neigh->n_ifindex);
469 				if (link) {
470 					neigh->n_master = link->l_master;
471 					rtnl_link_put(link);
472 					neigh->ce_mask |= NEIGH_ATTR_MASTER;
473 				}
474 				nl_cache_put(lcache);
475 			}
476 		}
477 	}
478 
479 	*result = neigh;
480 	return 0;
481 
482 errout:
483 	rtnl_neigh_put(neigh);
484 	return err;
485 }
486 
neigh_request_update(struct nl_cache * c,struct nl_sock * h)487 static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
488 {
489 	int family = c->c_iarg1;
490 
491 	if (family == AF_UNSPEC) {
492 		return nl_rtgen_request(h, RTM_GETNEIGH, family, NLM_F_DUMP);
493 	} else if (family == AF_BRIDGE) {
494 		struct ifinfomsg hdr = {.ifi_family = family};
495 		struct nl_msg *msg;
496 		int err;
497 
498 		msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
499 		if (!msg)
500 			return -NLE_NOMEM;
501 
502 		err = -NLE_MSGSIZE;
503 		if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
504 			goto nla_put_failure;
505 
506 		err = nl_send_auto(h, msg);
507 		if (err > 0)
508 			err = 0;
509 
510 	nla_put_failure:
511 		nlmsg_free(msg);
512 		return err;
513 	}
514 
515 	return -NLE_INVAL;
516 }
517 
518 
neigh_dump_line(struct nl_object * a,struct nl_dump_params * p)519 static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
520 {
521 	char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
522 	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
523 	struct nl_cache *link_cache;
524 	char state[128], flags[64];
525 	char buf[128];
526 
527 	link_cache = nl_cache_mngt_require_safe("route/link");
528 
529 	if (n->n_family != AF_UNSPEC)
530 		nl_dump_line(p, "%s ", nl_af2str(n->n_family, buf, sizeof(buf)));
531 
532 	if (n->ce_mask & NEIGH_ATTR_DST)
533 		nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
534 
535 	if (link_cache)
536 		nl_dump(p, "dev %s ",
537 			rtnl_link_i2name(link_cache, n->n_ifindex,
538 					 state, sizeof(state)));
539 	else
540 		nl_dump(p, "dev %d ", n->n_ifindex);
541 
542 	if (n->ce_mask & NEIGH_ATTR_LLADDR)
543 		nl_dump(p, "lladdr %s ",
544 			nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
545 
546 	if (n->ce_mask & NEIGH_ATTR_VLAN)
547 		nl_dump(p, "vlan %d ", n->n_vlan);
548 
549 	if (n->ce_mask & NEIGH_ATTR_NHID)
550 		nl_dump(p, "nhid %u ", n->n_nhid);
551 
552 	if (n->ce_mask & NEIGH_ATTR_MASTER) {
553 		if (link_cache)
554 			nl_dump(p, "%s ", rtnl_link_i2name(link_cache, n->n_master,
555 							   state, sizeof(state)));
556 		else
557 			nl_dump(p, "%d ", n->n_master);
558 	}
559 
560 	rtnl_neigh_state2str(n->n_state, state, sizeof(state));
561 	rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
562 
563 	if (state[0])
564 		nl_dump(p, "<%s", state);
565 	if (flags[0])
566 		nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
567 	if (state[0] || flags[0])
568 		nl_dump(p, ">");
569 	nl_dump(p, "\n");
570 
571 	if (link_cache)
572 		nl_cache_put(link_cache);
573 }
574 
neigh_dump_details(struct nl_object * a,struct nl_dump_params * p)575 static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
576 {
577 	char rtn_type[32];
578 	struct rtnl_neigh *n = (struct rtnl_neigh *) a;
579 	int hz = nl_get_user_hz();
580 
581 	neigh_dump_line(a, p);
582 
583 	nl_dump_line(p, "    refcnt %u type %s confirmed %u used "
584 				"%u updated %u\n",
585 		n->n_cacheinfo.nci_refcnt,
586 		nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
587 		n->n_cacheinfo.nci_confirmed/hz,
588 		n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
589 }
590 
neigh_dump_stats(struct nl_object * a,struct nl_dump_params * p)591 static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
592 {
593 	neigh_dump_details(a, p);
594 }
595 
596 /**
597  * @name Neighbour Object Allocation/Freeage
598  * @{
599  */
600 
rtnl_neigh_alloc(void)601 struct rtnl_neigh *rtnl_neigh_alloc(void)
602 {
603 	return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
604 }
605 
rtnl_neigh_put(struct rtnl_neigh * neigh)606 void rtnl_neigh_put(struct rtnl_neigh *neigh)
607 {
608 	nl_object_put((struct nl_object *) neigh);
609 }
610 
611 /** @} */
612 
613 /**
614  * @name Neighbour Cache Managament
615  * @{
616  */
617 
618 /**
619  * Build a neighbour cache including all neighbours currently configured in the kernel.
620  * @arg sock		Netlink socket.
621  * @arg result		Pointer to store resulting cache.
622  *
623  * Allocates a new neighbour cache, initializes it properly and updates it
624  * to include all neighbours currently configured in the kernel.
625  *
626  * @return 0 on success or a negative error code.
627  */
rtnl_neigh_alloc_cache(struct nl_sock * sock,struct nl_cache ** result)628 int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
629 {
630 	return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
631 }
632 
633 /**
634  * Build a neighbour cache including all neighbours currently configured in the kernel.
635  * @arg sock		Netlink socket.
636  * @arg result		Pointer to store resulting cache.
637  * @arg flags		Flags to apply to cache before filling
638  *
639  * Allocates a new neighbour cache, initializes it properly and updates it
640  * to include all neighbours currently configured in the kernel.
641  *
642  * @return 0 on success or a negative error code.
643  */
rtnl_neigh_alloc_cache_flags(struct nl_sock * sock,struct nl_cache ** result,unsigned int flags)644 int rtnl_neigh_alloc_cache_flags(struct nl_sock *sock, struct nl_cache **result,
645 				 unsigned int flags)
646 {
647 	struct nl_cache * cache;
648 	int err;
649 
650 	cache = nl_cache_alloc(&rtnl_neigh_ops);
651 	if (!cache)
652 		return -NLE_NOMEM;
653 
654 	nl_cache_set_flags(cache, flags);
655 
656 	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
657 		nl_cache_free(cache);
658 		return err;
659 	}
660 
661 	*result = cache;
662 	return 0;
663 }
664 
665 /**
666  * Look up a neighbour by interface index and destination address
667  * @arg cache		neighbour cache
668  * @arg ifindex		interface index the neighbour is on
669  * @arg dst		destination address of the neighbour
670  *
671  * @return neighbour handle or NULL if no match was found.
672  */
rtnl_neigh_get(struct nl_cache * cache,int ifindex,struct nl_addr * dst)673 struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
674 				   struct nl_addr *dst)
675 {
676 	struct rtnl_neigh *neigh;
677 
678 	nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
679 		if (neigh->n_ifindex == ((unsigned)ifindex) &&
680 		    neigh->n_family == ((unsigned)dst->a_family) &&
681 		    !nl_addr_cmp(neigh->n_dst, dst)) {
682 			nl_object_get((struct nl_object *) neigh);
683 			return neigh;
684 		}
685 	}
686 
687 	return NULL;
688 }
689 
690 /**
691  * Look up a neighbour by interface index, link layer address and vlan id
692  * @arg cache		neighbour cache
693  * @arg ifindex 	interface index the neighbour is on
694  * @arg lladdr		link layer address of the neighbour
695  * @arg vlan		vlan id of the neighbour
696  *
697  * @return neighbour handle or NULL if no match was found.
698  */
rtnl_neigh_get_by_vlan(struct nl_cache * cache,int ifindex,struct nl_addr * lladdr,int vlan)699 struct rtnl_neigh * rtnl_neigh_get_by_vlan(struct nl_cache *cache, int ifindex,
700 					   struct nl_addr *lladdr, int vlan)
701 {
702 	struct rtnl_neigh *neigh;
703 
704 	nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
705 		if ((neigh->n_ifindex == (unsigned)ifindex) &&
706 		    neigh->n_vlan == vlan && neigh->n_lladdr &&
707 		    !nl_addr_cmp(neigh->n_lladdr, lladdr)) {
708 			nl_object_get((struct nl_object *) neigh);
709 			return neigh;
710 		}
711 	}
712 
713 	return NULL;
714 }
715 
716 /** @} */
717 
718 /**
719  * @name Neighbour Addition
720  * @{
721  */
722 
build_neigh_msg(struct rtnl_neigh * tmpl,int cmd,int flags,struct nl_msg ** result)723 static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
724 			   struct nl_msg **result)
725 {
726 	struct nl_msg *msg;
727 	struct ndmsg nhdr = {
728 		.ndm_ifindex = tmpl->n_ifindex,
729 		.ndm_state = NUD_PERMANENT,
730 	};
731 
732 	if (tmpl->n_family != AF_BRIDGE) {
733 		if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
734 			return -NLE_MISSING_ATTR;
735 		nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
736 	}
737 	else
738 		nhdr.ndm_family = AF_BRIDGE;
739 
740 	if (tmpl->ce_mask & NEIGH_ATTR_FLAGS)
741 		nhdr.ndm_flags = tmpl->n_flags;
742 
743 	if (tmpl->ce_mask & NEIGH_ATTR_STATE)
744 		nhdr.ndm_state = tmpl->n_state;
745 
746 	msg = nlmsg_alloc_simple(cmd, flags);
747 	if (!msg)
748 		return -NLE_NOMEM;
749 
750 	if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
751 		goto nla_put_failure;
752 
753 	if (tmpl->ce_mask & NEIGH_ATTR_DST)
754 		NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
755 
756 	if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
757 		NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
758 
759 	if (tmpl->ce_mask & NEIGH_ATTR_VLAN)
760 		NLA_PUT_U16(msg, NDA_VLAN, tmpl->n_vlan);
761 
762 	if (tmpl->ce_mask & NEIGH_ATTR_NHID)
763 		NLA_PUT_U32(msg, NDA_NH_ID, tmpl->n_nhid);
764 
765 	*result = msg;
766 	return 0;
767 
768 nla_put_failure:
769 	nlmsg_free(msg);
770 	return -NLE_MSGSIZE;
771 }
772 
773 /**
774  * Build netlink request message to add a new neighbour
775  * @arg tmpl		template with data of new neighbour
776  * @arg flags		additional netlink message flags
777  * @arg result		Pointer to store resulting message.
778  *
779  * Builds a new netlink message requesting a addition of a new
780  * neighbour. The netlink message header isn't fully equipped with
781  * all relevant fields and must thus be sent out via nl_send_auto_complete()
782  * or supplemented as needed. \a tmpl must contain the attributes of the new
783  * neighbour set via \c rtnl_neigh_set_* functions.
784  *
785  * The following attributes must be set in the template:
786  *  - Interface index (rtnl_neigh_set_ifindex())
787  *  - State (rtnl_neigh_set_state())
788  *  - Destination address (rtnl_neigh_set_dst())
789  *  - Link layer address (rtnl_neigh_set_lladdr())
790  *
791  * @return 0 on success or a negative error code.
792  */
rtnl_neigh_build_add_request(struct rtnl_neigh * tmpl,int flags,struct nl_msg ** result)793 int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
794 				 struct nl_msg **result)
795 {
796 	return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
797 }
798 
799 /**
800  * Add a new neighbour
801  * @arg sk		Netlink socket.
802  * @arg tmpl		template with requested changes
803  * @arg flags		additional netlink message flags
804  *
805  * Builds a netlink message by calling rtnl_neigh_build_add_request(),
806  * sends the request to the kernel and waits for the next ACK to be
807  * received and thus blocks until the request has been fullfilled.
808  *
809  * The following attributes must be set in the template:
810  *  - Interface index (rtnl_neigh_set_ifindex())
811  *  - State (rtnl_neigh_set_state())
812  *  - Destination address (rtnl_neigh_set_dst())
813  *  - Link layer address (rtnl_neigh_set_lladdr())
814  *
815  * @return 0 on success or a negative error if an error occured.
816  */
rtnl_neigh_add(struct nl_sock * sk,struct rtnl_neigh * tmpl,int flags)817 int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
818 {
819 	int err;
820 	struct nl_msg *msg;
821 
822 	if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
823 		return err;
824 
825 	err = nl_send_auto_complete(sk, msg);
826 	nlmsg_free(msg);
827 	if (err < 0)
828 		return err;
829 
830 	return wait_for_ack(sk);
831 }
832 
833 /** @} */
834 
835 /**
836  * @name Neighbour Deletion
837  * @{
838  */
839 
840 /**
841  * Build a netlink request message to delete a neighbour
842  * @arg neigh		neighbour to delete
843  * @arg flags		additional netlink message flags
844  * @arg result		Pointer to store resulting message.
845  *
846  * Builds a new netlink message requesting a deletion of a neighbour.
847  * The netlink message header isn't fully equipped with all relevant
848  * fields and must thus be sent out via nl_send_auto_complete()
849  * or supplemented as needed. \a neigh must point to an existing
850  * neighbour.
851  *
852  * @return 0 on success or a negative error code.
853  */
rtnl_neigh_build_delete_request(struct rtnl_neigh * neigh,int flags,struct nl_msg ** result)854 int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
855 				    struct nl_msg **result)
856 {
857 	return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
858 }
859 
860 /**
861  * Delete a neighbour
862  * @arg sk		Netlink socket.
863  * @arg neigh		neighbour to delete
864  * @arg flags		additional netlink message flags
865  *
866  * Builds a netlink message by calling rtnl_neigh_build_delete_request(),
867  * sends the request to the kernel and waits for the next ACK to be
868  * received and thus blocks until the request has been fullfilled.
869  *
870  * @return 0 on success or a negative error if an error occured.
871  */
rtnl_neigh_delete(struct nl_sock * sk,struct rtnl_neigh * neigh,int flags)872 int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
873 		      int flags)
874 {
875 	struct nl_msg *msg;
876 	int err;
877 
878 	if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
879 		return err;
880 
881 	err = nl_send_auto_complete(sk, msg);
882 	nlmsg_free(msg);
883 	if (err < 0)
884 		return err;
885 
886 	return wait_for_ack(sk);
887 }
888 
889 /** @} */
890 
891 /**
892  * @name Neighbour States Translations
893  * @{
894  */
895 
896 static const struct trans_tbl neigh_states[] = {
897 	__ADD(NUD_INCOMPLETE, incomplete),
898 	__ADD(NUD_REACHABLE, reachable),
899 	__ADD(NUD_STALE, stale),
900 	__ADD(NUD_DELAY, delay),
901 	__ADD(NUD_PROBE, probe),
902 	__ADD(NUD_FAILED, failed),
903 	__ADD(NUD_NOARP, noarp),
904 	__ADD(NUD_PERMANENT, permanent),
905 
906 	/* Accept this value for backward compatibility. Originally
907 	 * there was a typo in the string value. This was fixed later,
908 	 * but we still want to successfully parse "norarp". */
909 	__ADD(NUD_NOARP, norarp),
910 };
911 
rtnl_neigh_state2str(int state,char * buf,size_t len)912 char * rtnl_neigh_state2str(int state, char *buf, size_t len)
913 {
914 	return __flags2str(state, buf, len, neigh_states,
915 	    ARRAY_SIZE(neigh_states) - 1);
916 }
917 
rtnl_neigh_str2state(const char * name)918 int rtnl_neigh_str2state(const char *name)
919 {
920 	return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
921 }
922 
923 /** @} */
924 
925 /**
926  * @name Neighbour Flags Translations
927  * @{
928  */
929 
930 static const struct trans_tbl neigh_flags[] = {
931 	__ADD(NTF_USE, use),
932 	__ADD(NTF_PROXY, proxy),
933 	__ADD(NTF_ROUTER, router),
934 	__ADD(NTF_SELF, self),
935 	__ADD(NTF_MASTER, master),
936 	__ADD(NTF_EXT_LEARNED, ext_learned),
937 	__ADD(NTF_OFFLOADED, offloaded),
938 };
939 
rtnl_neigh_flags2str(int flags,char * buf,size_t len)940 char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
941 {
942 	return __flags2str(flags, buf, len, neigh_flags,
943 	    ARRAY_SIZE(neigh_flags));
944 }
945 
rtnl_neigh_str2flag(const char * name)946 int rtnl_neigh_str2flag(const char *name)
947 {
948 	return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
949 }
950 
951 /** @} */
952 
953 /**
954  * @name Attributes
955  * @{
956  */
957 
rtnl_neigh_set_state(struct rtnl_neigh * neigh,int state)958 void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
959 {
960 	neigh->n_state_mask |= state;
961 	neigh->n_state |= state;
962 	neigh->ce_mask |= NEIGH_ATTR_STATE;
963 }
964 
rtnl_neigh_get_state(struct rtnl_neigh * neigh)965 int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
966 {
967 	if (neigh->ce_mask & NEIGH_ATTR_STATE)
968 		return neigh->n_state;
969 	else
970 		return -1;
971 }
972 
rtnl_neigh_unset_state(struct rtnl_neigh * neigh,int state)973 void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
974 {
975 	neigh->n_state_mask |= state;
976 	neigh->n_state &= ~state;
977 	neigh->ce_mask |= NEIGH_ATTR_STATE;
978 }
979 
rtnl_neigh_set_flags(struct rtnl_neigh * neigh,unsigned int flags)980 void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
981 {
982 	neigh->n_flag_mask |= flags;
983 	neigh->n_flags |= flags;
984 	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
985 }
986 
rtnl_neigh_get_flags(struct rtnl_neigh * neigh)987 unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
988 {
989 	return neigh->n_flags;
990 }
991 
rtnl_neigh_unset_flags(struct rtnl_neigh * neigh,unsigned int flags)992 void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
993 {
994 	neigh->n_flag_mask |= flags;
995 	neigh->n_flags &= ~flags;
996 	neigh->ce_mask |= NEIGH_ATTR_FLAGS;
997 }
998 
rtnl_neigh_set_ifindex(struct rtnl_neigh * neigh,int ifindex)999 void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
1000 {
1001 	neigh->n_ifindex = ifindex;
1002 	neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
1003 }
1004 
rtnl_neigh_get_ifindex(struct rtnl_neigh * neigh)1005 int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
1006 {
1007 	return neigh->n_ifindex;
1008 }
1009 
__assign_addr(struct rtnl_neigh * neigh,struct nl_addr ** pos,struct nl_addr * new,int flag,int nocheck)1010 static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
1011 			        struct nl_addr *new, int flag, int nocheck)
1012 {
1013 	if (!nocheck) {
1014 		if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
1015 			if (neigh->n_family != ((unsigned)new->a_family))
1016 				return -NLE_AF_MISMATCH;
1017 		} else {
1018 			neigh->n_family = new->a_family;
1019 			neigh->ce_mask |= NEIGH_ATTR_FAMILY;
1020 		}
1021 	}
1022 
1023 	if (*pos)
1024 		nl_addr_put(*pos);
1025 
1026 	nl_addr_get(new);
1027 	*pos = new;
1028 
1029 	neigh->ce_mask |= flag;
1030 
1031 	return 0;
1032 }
1033 
rtnl_neigh_set_lladdr(struct rtnl_neigh * neigh,struct nl_addr * addr)1034 void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
1035 {
1036 	__assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
1037 }
1038 
rtnl_neigh_get_lladdr(struct rtnl_neigh * neigh)1039 struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
1040 {
1041 	if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
1042 		return neigh->n_lladdr;
1043 	else
1044 		return NULL;
1045 }
1046 
rtnl_neigh_set_dst(struct rtnl_neigh * neigh,struct nl_addr * addr)1047 int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
1048 {
1049 	return __assign_addr(neigh, &neigh->n_dst, addr,
1050 			     NEIGH_ATTR_DST, 0);
1051 }
1052 
rtnl_neigh_get_dst(struct rtnl_neigh * neigh)1053 struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
1054 {
1055 	if (neigh->ce_mask & NEIGH_ATTR_DST)
1056 		return neigh->n_dst;
1057 	else
1058 		return NULL;
1059 }
1060 
rtnl_neigh_set_family(struct rtnl_neigh * neigh,int family)1061 void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
1062 {
1063 	neigh->n_family = family;
1064 	neigh->ce_mask |= NEIGH_ATTR_FAMILY;
1065 }
1066 
rtnl_neigh_get_family(struct rtnl_neigh * neigh)1067 int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
1068 {
1069 	return neigh->n_family;
1070 }
1071 
rtnl_neigh_set_type(struct rtnl_neigh * neigh,int type)1072 void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
1073 {
1074 	neigh->n_type = type;
1075 	neigh->ce_mask = NEIGH_ATTR_TYPE;
1076 }
1077 
rtnl_neigh_get_type(struct rtnl_neigh * neigh)1078 int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
1079 {
1080 	if (neigh->ce_mask & NEIGH_ATTR_TYPE)
1081 		return neigh->n_type;
1082 	else
1083 		return -1;
1084 }
1085 
rtnl_neigh_set_vlan(struct rtnl_neigh * neigh,int vlan)1086 void rtnl_neigh_set_vlan(struct rtnl_neigh *neigh, int vlan)
1087 {
1088 	neigh->n_vlan = vlan;
1089 	neigh->ce_mask |= NEIGH_ATTR_VLAN;
1090 }
1091 
rtnl_neigh_get_vlan(struct rtnl_neigh * neigh)1092 int rtnl_neigh_get_vlan(struct rtnl_neigh *neigh)
1093 {
1094 	if (neigh->ce_mask & NEIGH_ATTR_VLAN)
1095 		return neigh->n_vlan;
1096 	else
1097 		return -1;
1098 }
1099 
rtnl_neigh_set_master(struct rtnl_neigh * neigh,int ifindex)1100 void rtnl_neigh_set_master(struct rtnl_neigh *neigh, int ifindex)
1101 {
1102 	neigh->n_master = ifindex;
1103 	neigh->ce_mask |= NEIGH_ATTR_MASTER;
1104 }
1105 
rtnl_neigh_get_master(struct rtnl_neigh * neigh)1106 int rtnl_neigh_get_master(struct rtnl_neigh *neigh) {
1107 	return neigh->n_master;
1108 }
1109 
rtnl_neigh_set_nhid(struct rtnl_neigh * neigh,uint32_t nhid)1110 void rtnl_neigh_set_nhid(struct rtnl_neigh *neigh, uint32_t nhid)
1111 {
1112 	neigh->n_nhid = nhid;
1113 	neigh->ce_mask |= NEIGH_ATTR_NHID;
1114 }
1115 
rtnl_neigh_get_nhid(struct rtnl_neigh * neigh,uint32_t * out_val)1116 int rtnl_neigh_get_nhid(struct rtnl_neigh *neigh, uint32_t *out_val) {
1117 	if (!(neigh->ce_mask & NEIGH_ATTR_NHID))
1118 		return -NLE_NOATTR;
1119 
1120 	*out_val = neigh->n_nhid;
1121 	return NLE_SUCCESS;
1122 }
1123 
1124 /** @} */
1125 
1126 static struct nl_object_ops neigh_obj_ops = {
1127 	.oo_name		= "route/neigh",
1128 	.oo_size		= sizeof(struct rtnl_neigh),
1129 	.oo_free_data		= neigh_free_data,
1130 	.oo_clone		= neigh_clone,
1131 	.oo_dump = {
1132 	    [NL_DUMP_LINE]	= neigh_dump_line,
1133 	    [NL_DUMP_DETAILS]	= neigh_dump_details,
1134 	    [NL_DUMP_STATS]	= neigh_dump_stats,
1135 	},
1136 	.oo_compare		= neigh_compare,
1137 	.oo_keygen		= neigh_keygen,
1138 	.oo_attrs2str		= neigh_attrs2str,
1139 	.oo_id_attrs		= (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
1140 	.oo_id_attrs_get	= neigh_id_attrs_get
1141 };
1142 
1143 static struct nl_af_group neigh_groups[] = {
1144 	{ AF_UNSPEC, RTNLGRP_NEIGH },
1145 	{ AF_BRIDGE, RTNLGRP_NEIGH },
1146 	{ END_OF_GROUP_LIST },
1147 };
1148 
1149 static struct nl_cache_ops rtnl_neigh_ops = {
1150 	.co_name		= "route/neigh",
1151 	.co_hdrsize		= sizeof(struct ndmsg),
1152 	.co_msgtypes		= {
1153 					{ RTM_NEWNEIGH, NL_ACT_NEW, "new" },
1154 					{ RTM_DELNEIGH, NL_ACT_DEL, "del" },
1155 					{ RTM_GETNEIGH, NL_ACT_GET, "get" },
1156 					END_OF_MSGTYPES_LIST,
1157 				  },
1158 	.co_protocol		= NETLINK_ROUTE,
1159 	.co_groups		= neigh_groups,
1160 	.co_request_update	= neigh_request_update,
1161 	.co_msg_parser		= neigh_msg_parser,
1162 	.co_obj_ops		= &neigh_obj_ops,
1163 };
1164 
neigh_init(void)1165 static void _nl_init neigh_init(void)
1166 {
1167 	nl_cache_mngt_register(&rtnl_neigh_ops);
1168 }
1169 
neigh_exit(void)1170 static void _nl_exit neigh_exit(void)
1171 {
1172 	nl_cache_mngt_unregister(&rtnl_neigh_ops);
1173 }
1174 
1175 /** @} */
1176