mbuf-> sk_buf
/*
* RX: normal working mode
*/
static void
kni_net_rx_normal(struct kni_dev *kni)
{
unsigned ret;
uint32_t len;
unsigned i, num, num_rq, num_fq;
struct rte_kni_mbuf *kva;
struct rte_kni_mbuf *va[MBUF_BURST_SZ];
void * data_kva;
struct sk_buff *skb;
struct net_device *dev = kni->net_dev;
/* 每次收包的个数必须为rx_q和free_q的最小值且不超过MBUF_BURST_SZ */
/* Get the number of entries in rx_q */
num_rq = kni_fifo_count(kni->rx_q);
/* Get the number of free entries in free_q */
num_fq = kni_fifo_free_count(kni->free_q);
/* Calculate the number of entries to dequeue in rx_q */
num = min(num_rq, num_fq);
num = min(num, (unsigned)MBUF_BURST_SZ);
/* Return if no entry in rx_q and no free entry in free_q */
if (num == 0)
return;
/* Burst dequeue from rx_q */
ret = kni_fifo_get(kni->rx_q, (void **)va, num);
if (ret == 0)
return; /* Failing should not happen */
/* mbuf转换为skb */
/* Transfer received packets to netif */
for (i = 0; i < num; i++) {
/* mbuf kva */
kva = (void *)va[i] - kni->mbuf_va + kni->mbuf_kva;
len = kva->data_len;
/* data kva */
data_kva = kva->data - kni->mbuf_va + kni->mbuf_kva;
skb = dev_alloc_skb(len + 2);
if (!skb) {
KNI_ERR("Out of mem, dropping pkts\n");
/* Update statistics */
kni->stats.rx_dropped++;
}
else {
/* Align IP on 16B boundary */
skb_reserve(skb, 2);
memcpy(skb_put(skb, len), data_kva, len);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* 发送skb到协议栈 */
/* Call netif interface */
netif_receive_skb(skb);
/* Update statistics */
kni->stats.rx_bytes += len;
kni->stats.rx_packets++;
}
}
/* 通知用户空间释放mbuf */
/* Burst enqueue mbufs into free_q */
ret = kni_fifo_put(kni->free_q, (void **)va, num);
if (ret != num)
/* Failing should not happen */
KNI_ERR("Fail to enqueue entries into free_q\n");
}
sk_buf->mbuf
static int
kni_net_tx(struct sk_buff *skb, struct net_device *dev)
{
int len = 0;
unsigned ret;
struct kni_dev *kni = netdev_priv(dev);
struct rte_kni_mbuf *pkt_kva = NULL;
struct rte_kni_mbuf *pkt_va = NULL;
dev->trans_start = jiffies; /* save the timestamp */
/* Check if the length of skb is less than mbuf size */
if (skb->len > kni->mbuf_size)
goto drop;
/**
* Check if it has at least one free entry in tx_q and
* one entry in alloc_q.
*/
if (kni_fifo_free_count(kni->tx_q) == 0 ||
kni_fifo_count(kni->alloc_q) == 0) {
/**
* If no free entry in tx_q or no entry in alloc_q,
* drops skb and goes out.
*/
goto drop;
}
/* skb转mbuf */
/* dequeue a mbuf from alloc_q */
ret = kni_fifo_get(kni->alloc_q, (void **)&pkt_va, 1);
if (likely(ret == 1)) {
void *data_kva;
pkt_kva = (void *)pkt_va - kni->mbuf_va + kni->mbuf_kva;
data_kva = pkt_kva->data - kni->mbuf_va + kni->mbuf_kva;
len = skb->len;
memcpy(data_kva, skb->data, len);
if (unlikely(len < ETH_ZLEN)) {
memset(data_kva + len, 0, ETH_ZLEN - len);
len = ETH_ZLEN;
}
pkt_kva->pkt_len = len;
pkt_kva->data_len = len;
/* enqueue mbuf into tx_q */
ret = kni_fifo_put(kni->tx_q, (void **)&pkt_va, 1);
if (unlikely(ret != 1)) {
/* Failing should not happen */
KNI_ERR("Fail to enqueue mbuf into tx_q\n");
goto drop;
}
} else {
/* Failing should not happen */
KNI_ERR("Fail to dequeue mbuf from alloc_q\n");
goto drop;
}
/* Free skb and update statistics */
dev_kfree_skb(skb);
kni->stats.tx_bytes += len;
kni->stats.tx_packets++;
return NETDEV_TX_OK;
drop:
/* Free skb and update statistics */
dev_kfree_skb(skb);
kni->stats.tx_dropped++;
return NETDEV_TX_OK;
}