7. Lab: networking

https://pdos.csail.mit.edu/6.S081/2021/labs/net.html

1. 要求

lab 要求簡單來說就是實現網卡驅動的 transmitrecv 功能。其實只要跟着 lab 的 hints 做就可以了,難度較低。

2. 實現

首先是 transmit 功能,這裏比較麻煩的是確定 tx_desc.cmd 的值,查閱下文檔即可。文檔中標註:

VLE, IFCS, and IC are qualified by EOP. That is, hardware interprets these bits ONLY when
EOP is set.
Hardware only sets the DD bit for descriptors with RS set.

因此設置 DD bit 和 EOP bit 即可。其實頭文件中關於 cmd 也只定義了這 2 個 bit。

int e1000_transmit(struct mbuf *m)
{
  //
  // Your code here.
  //
  // the mbuf contains an ethernet frame; program it into
  // the TX descriptor ring so that the e1000 sends it. Stash
  // a pointer so that it can be freed after sending.
  //
  acquire(&e1000_lock);
  uint32 tail = regs[E1000_TDT];
  struct tx_desc* txdesc = &tx_ring[tail];
  if ((txdesc->status & E1000_TXD_STAT_DD) == 0){
    release(&e1000_lock);
    return -1;    // the E1000 hasn't finished the corresponding previous transmission request, so return an error.
  }
  
  if (tx_mbufs[tail])
    mbuffree(tx_mbufs[tail]);

  tx_mbufs[tail] = m;
  txdesc->addr = (uint64)m->head;
  txdesc->length = m->len;
  // VLE, IFCS, and IC are qualified by EOP. That is, hardware interprets these bits ONLY when
  // EOP is set.
  // Hardware only sets the DD bit for descriptors with RS set.
  txdesc->cmd = (E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS);
  regs[E1000_TDT] = (tail + 1) % TX_RING_SIZE;
  release(&e1000_lock);
  return 0;
}

接着實現 recv 功能,這裏需要注意的是,recv 在一次中斷可能收到多個 packet。因此我們需要從 tail 處開始,依次遍歷,檢查 DD bit 是否爲 1,爲 1 表示該描述符可以進行 net_rx 操作。
其次需要注意要在 net_rx 前釋放鎖,否則會引起 panic。

static void
e1000_recv(void)
{
  //
  // Your code here.
  //
  // Check for packets that have arrived from the e1000
  // Create and deliver an mbuf for each packet (using net_rx()).
  //
  uint32 tail = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
  struct rx_desc* rxdesc = &rx_ring[tail];

  while(rxdesc->status & E1000_RXD_STAT_DD){
    acquire(&e1000_lock);

    struct mbuf* buf = rx_mbufs[tail];
    mbufput(buf, rxdesc->length);

    struct mbuf* m = mbufalloc(0);
    rxdesc->addr = (uint64)m->head; 
    rxdesc->status = 0;
    rx_mbufs[tail] = m;
    regs[E1000_RDT] = tail;
    release(&e1000_lock);

    net_rx(buf);
    tail = (tail + 1) % RX_RING_SIZE;
    rxdesc = &rx_ring[tail];
  }
}

3. 小結

該 lab 實現的思路都在 hint 中,關於 recv 和 transmit 的 ring 數組,其結構圖大致如下:
image.png
image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章