Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How bonding driver takes RX packets from enslave interfaces

I have a question regarding how to bonding driver takes RX packets from enslaved interfaces. I found that bonding use dev_add_pack() to set handlers for LACPDU and ARP packets, but I didn't found other handlers (for other packets types).

Could you please help me to solve this problem?

like image 712
Alexey Bureev Avatar asked Oct 22 '22 16:10

Alexey Bureev


2 Answers

Bonding drivers registers its own Rx handler, when a slave interface is enslaved to a bond master, in bond_enslave() you can see:

res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
                                 new_slave);

So in bond_handle_frame(), it will hijack the packets received by the slave interface, so that the bond master will receive the packets instead:

static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
{
        struct sk_buff *skb = *pskb;
        struct slave *slave;
        struct bonding *bond;
        int (*recv_probe)(const struct sk_buff *, struct bonding *,
                          struct slave *);
        int ret = RX_HANDLER_ANOTHER;

        skb = skb_share_check(skb, GFP_ATOMIC);
        if (unlikely(!skb))
                return RX_HANDLER_CONSUMED;

        *pskb = skb;

        slave = bond_slave_get_rcu(skb->dev);
        bond = slave->bond;

        if (bond->params.arp_interval)
                slave->dev->last_rx = jiffies;

        recv_probe = ACCESS_ONCE(bond->recv_probe);
        if (recv_probe) {
                ret = recv_probe(skb, bond, slave);
                if (ret == RX_HANDLER_CONSUMED) {
                        consume_skb(skb);
                        return ret;
                }
        }

        if (bond_should_deliver_exact_match(skb, slave, bond)) {
                return RX_HANDLER_EXACT;
        }

        skb->dev = bond->dev;

        if (bond->params.mode == BOND_MODE_ALB &&
            bond->dev->priv_flags & IFF_BRIDGE_PORT &&
            skb->pkt_type == PACKET_HOST) {

                if (unlikely(skb_cow_head(skb,
                                          skb->data - skb_mac_header(skb)))) {
                        kfree_skb(skb);
                        return RX_HANDLER_CONSUMED;
                }
                memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN);
        }

        return ret;
}
like image 133
Cong Wang Avatar answered Nov 15 '22 03:11

Cong Wang


I checked code of bonding and found that driver didn't inspect incoming RX packets without some of types (LACPDU, ARP) in cases, when driver works in these modes. Driver set handlers for this packets with use of dev_add_pack() function.

For set global hook in practic you can use nf_register_hook(), which provide interface for setup own net filter procedure for intercept packets. Seems that nf_register_hook() is more powerful than dev_add_pack(), but I think that need more care when working nf_register_hook(), because it can drop a lot of packets in case of wrong conditions in hook.

like image 22
Alexey Bureev Avatar answered Nov 15 '22 04:11

Alexey Bureev