0

我正在研究一个内核模块代码,我需要在其中查看路由表以获取我的 ARP 表条目daddr

       |--------------------------------------------------|
-------+ enp0s1 192.168.2.0/24      192.168.3.0/24 enp0s2 +-----
       |--------------------------------------------------|

例如,我需要获取neighbour192.168.3.111 的条目,并且该条目已永久添加到表中:

% ip neigh  add 192.168.3.111 lladdr 00:11:22:33:44:55 dev enp0s2 nud permanent
% ip neigh sh
...
192.168.3.111 dev enp0s2 lladdr 00:11:22:33:44:55 PERMANENT
% ip route show
...
192.168.3.0/24 dev enp0s2 proto kernel scope link src 192.168.3.2

我想出了以下代码:

struct rtable *rt;
struct flowi4 fl4;
struct dst_entry dst;
struct neighbour *neigh;
u8 mac[ETH_ALEN];

...
memset(&fl4, 0, sizeof fl4);
fl4.daddr = daddr;
fl4.flowi4_proto = IPPROTO_UDP;

rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
    goto err;

...
dst = rt->dst;
neigh = dst_neigh_lookup(&dst, &fl4.daddr);
if (!neigh) {
   ...
}

neigh_ha_snapshot(mac, neigh, neigh->dev);
neigh_release(neigh);
ip_rt_put(rt);

但是neigh_ha_snapshot不返回正确MAC的地址,实际上我认为它返回垃圾,有时ff:ff:ff:ff:ff:ff,有时是多播01:xx:xx:xx:xx:xx

我究竟做错了什么?

4

1 回答 1

0

问题修复如下:

neigh = dst_neigh_lookup(&rt->dst, &fl4.daddr);

因此,无需将struct dst_entry对象放在堆栈上,而是从 中分配值rt并传递指向它的指针dst_neigh_lookup(),只需将指针传递给dst当前rt对象中的成员即可。

原因在于以下代码:

static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
{
        struct neighbour *n = dst->ops->neigh_lookup(dst, NULL, daddr);
        return IS_ERR(n) ? NULL : n;
}

whereneigh_lookup被初始化为ipv4_neigh_lookup()在 中定义的函数net/ipv4/route.c

static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
                                           struct sk_buff *skb,
                                           const void *daddr)
{
        struct net_device *dev = dst->dev;
        const __be32 *pkey = daddr;
        const struct rtable *rt;
        struct neighbour *n;

        rt = (const struct rtable *) dst;
        ...
}

从这一点开始rt是假的,其余的也是如此。

于 2018-07-10T17:14:06.400 回答