Looking at Kernel source code I see that when processing ARP request the net_device is retrieved right from the skb, and then seems like the reply is sent to that device (arp.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,

But if the packet went through bridge, then skb got its device overwritten with bridge device:

static int br_pass_frame_up(struct sk_buff *skb)
    skb->dev = brdev;

Shouldn't it some how retrieve the original device and send the reply there?

1 Answer 1


If the frame arrived from a bridge port, that means now there's a fresh bridge fdb entry telling to use this same bridge port when sending a frame to this MAC address: a reply will be sent to the same bridge port the query arrived from.

So from the point of view of the ARP layer, the packet was received on the bridge interface and the answer also sent back on the bridge interface.

When the reply reaches the lower layer: bridge, that's the bridge code which does a lookup in its Forwarding Database (aka FIB) and chooses as outgoing bridge port the previous incoming bridge port instead of flooding the answer to all of its ports (since there is such a recent entry to be found):


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);

Doing the opposite as before, the skb's device bridge interface is overwritten with the bridge port:


static void __br_forward(const struct net_bridge_port *to,
           struct sk_buff *skb, bool local_orig)
      skb->dev = to->dev;
  • Shouldn't there be a similar logic to change src MAC of ARP Reply? I can see that in the same line I posted in the question arp uses dev->dev_addr to create a reply, but this is bridge MAC. Looking at br_forward() I can't find where it overwrites bridge MAC with the address of the device which actually handled the request.. Jun 20, 2021 at 8:19
  • ARP is sent from bridge interface, not from the bridge port: the MAC is from the bridge interface not port. Likewise, an IP packet sent from the bridge interface will in the end be sent as an Ethernet frame on the bridge port with the bridge interface's MAC address, not the bridge port MAC address. As the bridge interface borrows its MAC from one of its ports unless explicitly set, the difference might not have been seen.
    – A.B
    Jun 20, 2021 at 8:22
  • You can use ebtables (or nftables) if for some reason you want to NAT the Ethernet MAC address (you might have to alter the ARP content that includes the MAC address too to match the Ethernet MAC).
    – A.B
    Jun 20, 2021 at 8:26
  • Huh.. So let's say ARP req went through eth0->bridge->eth1, and we replied with Bridge MAC. Next time IP packet arrives for Bridge MAC, the Bridge will receive it, then how will it know to associate sk_buff with eth1 device? Jun 20, 2021 at 8:50
  • You probably have a problem in mind but never wrote it. Check xyproblem.info . Sorry but I can't follow all additional cases you are submitting. I stand by what I said.
    – A.B
    Jun 20, 2021 at 8:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .