151 #include <netlink-local.h>
152 #include <netlink/netlink.h>
153 #include <netlink/utils.h>
154 #include <netlink/route/rtnl.h>
155 #include <netlink/route/neighbour.h>
156 #include <netlink/route/link.h>
159 #define NEIGH_ATTR_FLAGS 0x01
160 #define NEIGH_ATTR_STATE 0x02
161 #define NEIGH_ATTR_LLADDR 0x04
162 #define NEIGH_ATTR_DST 0x08
163 #define NEIGH_ATTR_CACHEINFO 0x10
164 #define NEIGH_ATTR_IFINDEX 0x20
165 #define NEIGH_ATTR_FAMILY 0x40
166 #define NEIGH_ATTR_TYPE 0x80
167 #define NEIGH_ATTR_PROBES 0x100
173 static void neigh_free_data(
struct nl_object *c)
175 struct rtnl_neigh *neigh = nl_object_priv(c);
180 nl_addr_put(neigh->n_lladdr);
181 nl_addr_put(neigh->n_dst);
186 struct rtnl_neigh *dst = nl_object_priv(_dst);
187 struct rtnl_neigh *src = nl_object_priv(_src);
201 uint32_t attrs,
int flags)
203 struct rtnl_neigh *a = (
struct rtnl_neigh *) _a;
204 struct rtnl_neigh *b = (
struct rtnl_neigh *) _b;
207 #define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
209 diff |= NEIGH_DIFF(IFINDEX, a->n_ifindex != b->n_ifindex);
210 diff |= NEIGH_DIFF(FAMILY, a->n_family != b->n_family);
211 diff |= NEIGH_DIFF(TYPE, a->n_type != b->n_type);
212 diff |= NEIGH_DIFF(LLADDR,
nl_addr_cmp(a->n_lladdr, b->n_lladdr));
213 diff |= NEIGH_DIFF(DST,
nl_addr_cmp(a->n_dst, b->n_dst));
215 if (flags & LOOSE_COMPARISON) {
216 diff |= NEIGH_DIFF(STATE,
217 (a->n_state ^ b->n_state) & b->n_state_mask);
218 diff |= NEIGH_DIFF(FLAGS,
219 (a->n_flags ^ b->n_flags) & b->n_flag_mask);
221 diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
222 diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
230 static const struct trans_tbl neigh_attrs[] = {
231 __ADD(NEIGH_ATTR_FLAGS, flags)
232 __ADD(NEIGH_ATTR_STATE, state)
233 __ADD(NEIGH_ATTR_LLADDR, lladdr)
234 __ADD(NEIGH_ATTR_DST, dst)
235 __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
236 __ADD(NEIGH_ATTR_IFINDEX, ifindex)
237 __ADD(NEIGH_ATTR_FAMILY, family)
238 __ADD(NEIGH_ATTR_TYPE, type)
239 __ADD(NEIGH_ATTR_PROBES, probes)
242 static
char *neigh_attrs2str(
int attrs,
char *buf,
size_t len)
244 return __flags2str(attrs, buf, len, neigh_attrs,
245 ARRAY_SIZE(neigh_attrs));
248 static struct nla_policy neigh_policy[NDA_MAX+1] = {
249 [NDA_CACHEINFO] = { .
minlen =
sizeof(
struct nda_cacheinfo) },
250 [NDA_PROBES] = { .type =
NLA_U32 },
253 static int neigh_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
256 struct rtnl_neigh *neigh;
259 if ((err = rtnl_neigh_parse(n, &neigh)) < 0)
264 rtnl_neigh_put(neigh);
269 int rtnl_neigh_parse(
struct nlmsghdr *n,
struct rtnl_neigh **result)
271 struct rtnl_neigh *neigh;
272 struct nlattr *tb[NDA_MAX + 1];
276 neigh = rtnl_neigh_alloc();
282 neigh->ce_msgtype = n->nlmsg_type;
285 err =
nlmsg_parse(n,
sizeof(*nm), tb, NDA_MAX, neigh_policy);
289 neigh->n_family = nm->ndm_family;
290 neigh->n_ifindex = nm->ndm_ifindex;
291 neigh->n_state = nm->ndm_state;
292 neigh->n_flags = nm->ndm_flags;
293 neigh->n_type = nm->ndm_type;
295 neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
296 NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
299 if (tb[NDA_LLADDR]) {
301 if (!neigh->n_lladdr) {
305 nl_addr_set_family(neigh->n_lladdr,
307 neigh->ce_mask |= NEIGH_ATTR_LLADDR;
316 neigh->ce_mask |= NEIGH_ATTR_DST;
319 if (tb[NDA_CACHEINFO]) {
320 struct nda_cacheinfo *ci =
nla_data(tb[NDA_CACHEINFO]);
322 neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
323 neigh->n_cacheinfo.nci_used = ci->ndm_used;
324 neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
325 neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
327 neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
330 if (tb[NDA_PROBES]) {
332 neigh->ce_mask |= NEIGH_ATTR_PROBES;
339 rtnl_neigh_put(neigh);
343 static int neigh_request_update(
struct nl_cache *c,
struct nl_sock *h)
351 char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
352 struct rtnl_neigh *n = (
struct rtnl_neigh *) a;
353 struct nl_cache *link_cache;
354 char state[128], flags[64];
358 nl_dump_line(p,
"%s ",
nl_addr2str(n->n_dst, dst,
sizeof(dst)));
363 state,
sizeof(state)));
365 nl_dump(p,
"dev %d ", n->n_ifindex);
367 if (n->ce_mask & NEIGH_ATTR_LLADDR)
371 rtnl_neigh_state2str(n->n_state, state,
sizeof(state));
372 rtnl_neigh_flags2str(n->n_flags, flags,
sizeof(flags));
377 nl_dump(p,
"%s%s", state[0] ?
"," :
"<", flags);
378 if (state[0] || flags[0])
386 struct rtnl_neigh *n = (
struct rtnl_neigh *) a;
389 neigh_dump_line(a, p);
391 nl_dump_line(p,
" refcnt %u type %s confirmed %u used "
393 n->n_cacheinfo.nci_refcnt,
394 nl_rtntype2str(n->n_type, rtn_type,
sizeof(rtn_type)),
395 n->n_cacheinfo.nci_confirmed/hz,
396 n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
401 neigh_dump_details(a, p);
409 struct rtnl_neigh *rtnl_neigh_alloc(
void)
414 void rtnl_neigh_put(
struct rtnl_neigh *neigh)
451 struct rtnl_neigh *neigh;
453 nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
454 if (neigh->n_ifindex == ifindex &&
471 static int build_neigh_msg(
struct rtnl_neigh *tmpl,
int cmd,
int flags,
472 struct nl_msg **result)
475 struct ndmsg nhdr = {
476 .ndm_ifindex = tmpl->n_ifindex,
477 .ndm_state = NUD_PERMANENT,
480 if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
481 return -NLE_MISSING_ATTR;
483 nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
485 if (tmpl->ce_mask & NEIGH_ATTR_FLAGS)
486 nhdr.ndm_flags = tmpl->n_flags;
488 if (tmpl->ce_mask & NEIGH_ATTR_STATE)
489 nhdr.ndm_state = tmpl->n_state;
495 if (
nlmsg_append(msg, &nhdr,
sizeof(nhdr), NLMSG_ALIGNTO) < 0)
496 goto nla_put_failure;
500 if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
532 struct nl_msg **result)
534 return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
563 err = nl_send_auto_complete(sk, msg);
568 return wait_for_ack(sk);
593 struct nl_msg **result)
595 return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
619 err = nl_send_auto_complete(sk, msg);
624 return wait_for_ack(sk);
634 static const struct trans_tbl neigh_states[] = {
635 __ADD(NUD_INCOMPLETE, incomplete)
636 __ADD(NUD_REACHABLE, reachable)
637 __ADD(NUD_STALE, stale)
638 __ADD(NUD_DELAY, delay)
639 __ADD(NUD_PROBE, probe)
640 __ADD(NUD_FAILED, failed)
641 __ADD(NUD_NOARP, norarp)
642 __ADD(NUD_PERMANENT, permanent)
645 char * rtnl_neigh_state2str(
int state,
char *buf,
size_t len)
647 return __flags2str(state, buf, len, neigh_states,
648 ARRAY_SIZE(neigh_states));
651 int rtnl_neigh_str2state(
const char *name)
653 return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
663 static const struct trans_tbl neigh_flags[] = {
665 __ADD(NTF_PROXY, proxy)
666 __ADD(NTF_ROUTER, router)
669 char * rtnl_neigh_flags2str(
int flags,
char *buf,
size_t len)
671 return __flags2str(flags, buf, len, neigh_flags,
672 ARRAY_SIZE(neigh_flags));
675 int rtnl_neigh_str2flag(
const char *name)
677 return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
687 void rtnl_neigh_set_state(
struct rtnl_neigh *neigh,
int state)
689 neigh->n_state_mask |= state;
690 neigh->n_state |= state;
691 neigh->ce_mask |= NEIGH_ATTR_STATE;
694 int rtnl_neigh_get_state(
struct rtnl_neigh *neigh)
696 if (neigh->ce_mask & NEIGH_ATTR_STATE)
697 return neigh->n_state;
702 void rtnl_neigh_unset_state(
struct rtnl_neigh *neigh,
int state)
704 neigh->n_state_mask |= state;
705 neigh->n_state &= ~state;
706 neigh->ce_mask |= NEIGH_ATTR_STATE;
709 void rtnl_neigh_set_flags(
struct rtnl_neigh *neigh,
unsigned int flags)
711 neigh->n_flag_mask |= flags;
712 neigh->n_flags |= flags;
713 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
716 unsigned int rtnl_neigh_get_flags(
struct rtnl_neigh *neigh)
718 return neigh->n_flags;
721 void rtnl_neigh_unset_flags(
struct rtnl_neigh *neigh,
unsigned int flags)
723 neigh->n_flag_mask |= flags;
724 neigh->n_flags &= ~flags;
725 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
728 void rtnl_neigh_set_ifindex(
struct rtnl_neigh *neigh,
int ifindex)
730 neigh->n_ifindex = ifindex;
731 neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
734 int rtnl_neigh_get_ifindex(
struct rtnl_neigh *neigh)
736 return neigh->n_ifindex;
739 static inline int __assign_addr(
struct rtnl_neigh *neigh,
struct nl_addr **pos,
740 struct nl_addr *
new,
int flag,
int nocheck)
743 if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
744 if (new->a_family != neigh->n_family)
745 return -NLE_AF_MISMATCH;
747 neigh->n_family =
new->a_family;
748 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
758 neigh->ce_mask |= flag;
763 void rtnl_neigh_set_lladdr(
struct rtnl_neigh *neigh,
struct nl_addr *addr)
765 __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
768 struct nl_addr *rtnl_neigh_get_lladdr(
struct rtnl_neigh *neigh)
770 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
771 return neigh->n_lladdr;
776 int rtnl_neigh_set_dst(
struct rtnl_neigh *neigh,
struct nl_addr *addr)
778 return __assign_addr(neigh, &neigh->n_dst, addr,
782 struct nl_addr *rtnl_neigh_get_dst(
struct rtnl_neigh *neigh)
784 if (neigh->ce_mask & NEIGH_ATTR_DST)
790 void rtnl_neigh_set_family(
struct rtnl_neigh *neigh,
int family)
792 neigh->n_family = family;
793 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
796 int rtnl_neigh_get_family(
struct rtnl_neigh *neigh)
798 return neigh->n_family;
801 void rtnl_neigh_set_type(
struct rtnl_neigh *neigh,
int type)
803 neigh->n_type = type;
804 neigh->ce_mask = NEIGH_ATTR_TYPE;
807 int rtnl_neigh_get_type(
struct rtnl_neigh *neigh)
809 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
810 return neigh->n_type;
819 .oo_size =
sizeof(
struct rtnl_neigh),
820 .oo_free_data = neigh_free_data,
821 .oo_clone = neigh_clone,
827 .oo_compare = neigh_compare,
828 .oo_attrs2str = neigh_attrs2str,
829 .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
833 { AF_UNSPEC, RTNLGRP_NEIGH },
834 { END_OF_GROUP_LIST },
839 .co_hdrsize =
sizeof(
struct ndmsg),
841 { RTM_NEWNEIGH, NL_ACT_NEW,
"new" },
842 { RTM_DELNEIGH, NL_ACT_DEL,
"del" },
843 { RTM_GETNEIGH, NL_ACT_GET,
"get" },
844 END_OF_MSGTYPES_LIST,
846 .co_protocol = NETLINK_ROUTE,
847 .co_groups = neigh_groups,
848 .co_request_update = neigh_request_update,
849 .co_msg_parser = neigh_msg_parser,
850 .co_obj_ops = &neigh_obj_ops,
853 static void __init neigh_init(
void)
858 static void __exit neigh_exit(
void)