%20%D0%BE%D1%82%D0%B2%D0%B5%D1%87%D0%B0%D0%B5%D1%82%20%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%D0%BC%D1%83%20%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D1%83%3F.png)
Глядя на исходный код ядра, я вижу, что при обработке ARP-запроса он net_device
извлекается прямо из skb
, а затем, похоже, ответ отправляется на это устройство (арп.c#L679):
static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
...
arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
sip, dev, tip, sha,
dev->dev_addr, sha,
reply_dst);
}
Но если пакет прошел через мост, то skb
получил свое устройствоперезаписано с помощью мостового устройства:
static int br_pass_frame_up(struct sk_buff *skb)
{
...
skb->dev = brdev;
...
}
Разве не следует каким-то образом извлечь исходное устройство и отправить ответ туда?
решение1
Если кадр пришел из порта моста, это означает, что теперь естьсвежий мост fdb записьуказывает использовать этот же порт моста при отправке кадра на этот MAC-адрес: ответ будет отправлен на тот же порт моста, с которого пришел запрос.
Таким образом, с точки зрения уровня ARP, пакет был получен на интерфейсе моста, и ответ также был отправлен обратно на интерфейс моста.
Когда ответ достигает нижнего уровня: моста, это код моста, который выполняет поиск в своей базе данных пересылки (она жеФИБ) и выбирает в качестве исходящего порта моста предыдущий входящий порт моста вместо того, чтобы рассылать ответ на все его порты (поскольку существует такая недавняя запись):
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { ... } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { br_forward(dst->dst, skb, false, true); } else { br_flood(br, skb, BR_PKT_UNICAST, false, true);
Действуя наоборот, как и раньше, интерфейс моста устройства skb перезаписывается портом моста:
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb, bool local_orig) { ... skb->dev = to->dev; ...