static int parse_v4_neighbor( orc_options_t * options, struct nlmsghdr * nl_msg, orc_v4_neighbor_t * neigh) { struct ndmsg * nd_msg; struct rtattr * attr; int rtattr_len; int found_l3_addr = 0; nd_msg = (struct ndmsg *) NLMSG_DATA(nl_msg); /* extract first attribute */ attr = (struct rtattr *) NDA_RTA(nd_msg); rtattr_len = NDA_PAYLOAD(nl_msg); if (nd_msg->ndm_family != AF_INET) { /* TODO: add IPv6 support */ orc_debug("Ignoring IPv6 neighbor update: IPv6 unsupported\n"); return 0; } neigh->if_index = nd_msg->ndm_ifindex; /** TODO: ignore neighbor updates on non-orc interfaces */ if (nd_msg->ndm_state != NUD_STALE && nd_msg->ndm_state != NUD_PERMANENT && nd_msg->ndm_state != NUD_FAILED && nd_msg->ndm_state != NUD_REACHABLE) { orc_trace("Ignoring irrelevant neighbor update:" " not STALE/PERM/REACHABLE/FAILED\n"); return 0; } /** note: the RTA_NEXT() macro decrements rtattr_len each time */ for(; RTA_OK(attr, rtattr_len); attr = RTA_NEXT(attr, rtattr_len)) { switch (attr->rta_type) { case NDA_DST: found_l3_addr = 1; memcpy(&neigh->ip, RTA_DATA(attr), sizeof(neigh->ip)); orc_debug("Parsed IPv4 neighbor L3 addr: " IPV4_FORMAT "\n", IPV4_ADDR_PRINT(neigh->ip)); break; case NDA_LLADDR: neigh->mac_valid = 1; memcpy(neigh->mac, RTA_DATA(attr), 6); orc_debug("Parsed IPv4 neighbor L2 addr: " ETH_FORMAT "\n", ETH_ADDR_PRINT(neigh->mac)); break; case NDA_CACHEINFO: orc_trace("Ignoring irrelevant neighbor attr NDA_CACHEINFO\n"); break; case NDA_PROBES: orc_trace("Ignoring irrelevant neighbor attr NDA_PROBES\n"); break; default: /** TODO: decide if we actually need anything from here */ orc_warn("Skipping unhandled ipv4 neighbor attr: %d\n", attr->rta_type); }; } return found_l3_addr; }
static void rtnl_print_neigh(struct nlmsghdr *hdr) { struct ndmsg *ndm = NLMSG_DATA(hdr); uint32_t attrs_len = NDA_PAYLOAD(hdr); struct rtattr *attr = NDA_RTA(ndm); struct nda_cacheinfo *ci; int hz = get_user_hz(); char addr_str[256]; char hw_addr[30]; char states[256]; char flags[256]; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ndm))) return; tprintf(" [ Neigh Family %d (%s%s%s)", ndm->ndm_family, colorize_start(bold), addr_family2str(ndm->ndm_family), colorize_end()); tprintf(", Link Index %d", ndm->ndm_ifindex); tprintf(", State %d (%s%s%s)", ndm->ndm_state, colorize_start(bold), flags2str(neigh_states, ndm->ndm_state, states, sizeof(states)), colorize_end()); tprintf(", Flags %d (%s%s%s)", ndm->ndm_flags, colorize_start(bold), flags2str(neigh_flags, ndm->ndm_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Type %d (%s%s%s)", ndm->ndm_type, colorize_start(bold), route_type2str(ndm->ndm_type), colorize_end()); tprintf(" ]\n"); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case NDA_DST: rta_fmt(attr, "Address %s", addr2str(ndm->ndm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case NDA_LLADDR: rta_fmt(attr, "HW Address %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), 0, hw_addr, sizeof(hw_addr))); break; case NDA_PROBES: rta_fmt(attr, "Probes %d", RTA_UINT32(attr)); break; case NDA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); tprintf("confirmed(%ds)", ci->ndm_confirmed / hz); tprintf(", used(%ds)", ci->ndm_used / hz); tprintf(", updated(%ds)", ci->ndm_updated / hz); tprintf(", refcnt(%d))", ci->ndm_refcnt); tprintf(", Len %d\n", RTA_LEN(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }