0
votes

I currently write a network driver, and in the transmit function I want to modify the socket buffer queue. Therefore I need to get the lock of sk_buff_head, but the link to the head from a socket buffer was removed years ago.

How can I access sk_buff_head from ndo_start_xmit(struct sk_buff *skb, net_device *dev)?

I am using current linux kernel 4.15.3.

Background

I modify an existing driver for a virtual network device to implement fragmentation which relies on the order of frames, so the second fragment must be sent directly after the first fragment. It works on layer 2 frames.

Therefore I hook up in the start_xmitfunction, simplified it looks like this:

static spinlock_t xmit_lock;
start_xmit(struct sk_buff *skb, struct net_device *dev)
{

    [...]

    if(skb->len > TRESHHOLD) {
        second_skb = do_fragmentation(skb);
    }

    [...]

    spin_lock_bh(&xmit_lock);

    if(second_skb) {
         second_skb->next = skb->next;
         second_skb->prev = skb;
         skb->next = second_skb;
    }

    ret = dev_queue_xmit(skb);

    spin_lock_bh(&xmit_lock);
}

So I want to reach that both skbs are sent in exactly this order, there should not be a frame sent in between which passes this driver. This works, when using ping flood mode oder iperf with UDP but sometimes it messes up with iperf using a TCP connection. Then, there are some cases where the order is messed up.

To solve this, I thought I need the "real" queue lock for the skb and so I need sk_buff_head for this.

1
are you using v4 kernel? - Ahmed Masud
Yes, sorry, added this information - Eknoes
Can you clarify exactly what it is you're implementing, preferably with some code? e.g. are you trying to re-implement sth to the effect of __dev_queue_xmit or netpoll_send_skb_on_dev? - Michael Foukarakis
Sorry for the confusion, I think now it is much more understandable what I want to reach. - Eknoes

1 Answers

1
votes

To do this correctly you need to set up a local lock in a private data structure:

e.g.

struct my_protocol {
    spinlock_t lock;
}

set it up during the dev->open (usually done in an allocation routine) using alloc_netdev() and then you can access the structure using netdev_priv and hold your lock.