我有同样的问题。
我需要获取与特定 IP 关联的邻居的 MAC 地址。此外,在我的情况下,可能 IP<->MAC 映射没有出现在 ARP 缓存中。所以在这种情况下,我需要先发送 ARP 请求。
这是我目前得到的一个肮脏的解决方案:
struct mac_addr {
uint8_t addr[ETH_ALEN];
};
static int resolve_neighbour(__be32 const src_ip, __be32 const dst_ip, struct mac_addr* const mac) {
int rc = 0;
struct neighbour *neigh;
struct rtable* const rt = ip_route_output(&init_net, dst_ip, src_ip, 0, 0);
if (IS_ERR(rt)) {
LOG(KERN_ERR, "Failed to find ip route"); // TODO: add dst and src ip
return PTR_ERR(rt);
}
rcu_read_lock();
neigh = dst_neigh_lookup(&rt->dst, &dst_ip);
if (neigh) {
if (neigh->nud_state & NUD_VALID) {
neigh_ha_snapshot(mac->addr, neigh, rt->dst.dev);
} else {
PDEBUG("neigh is not valid. Sending ARP");
if ((rc = neigh_resolve_output(neigh, NULL))) {
LOG(KERN_ERR, "Failed to resolve neighbour");
} else {
rc = -EAGAIN;
}
}
neigh_release(neigh);
} else {
LOG(KERN_ERR, "Failed to get neighbour"); // TODO: add dst ip
rc = -ENONET;
}
rcu_read_unlock();
return rc;
}
static int foobar(void) {
int rc = 0;
__be32 const dst_ip = 0x0a01000a; // FIXME: TODO: get it from register or from tre user
__be32 const src_ip = htonl(0); // FIXME: TODO: get it from register or from the user
struct mac_addr mac;
size_t i;
enum {RESOLVE_TRIES = 3, RESOLVE_TIMEOUT_MS = 100};
for (i = 0; i < RESOLVE_TRIES; ++i) {
if ((rc = resolve_neighbour(src_ip, dst_ip, &mac)) == -EAGAIN) {
msleep(RESOLVE_TIMEOUT_MS);
} else {
break;
}
}
if (rc) {
LOG(KERN_ERR, "Failed to get neighbour MAC address");
return rc;
}
PDEBUG("DST MAC %02X:%02X:%02X:%02X:%02X:%02X",
mac.addr[0], mac.addr[1], mac.addr[2],
mac.addr[3], mac.addr[4], mac.addr[5]);
return rc;
}