【mit 6.S081】学习笔记 Lab5 Network diver

Lab5 Network diver

本实验就是实现E1000网卡对于数据包的传输和接受,其实lab的提示部分已经很详细了,只需要将文字转化为代码即可。

Transmit (moderate)
  • 首先,通过读取E1000_TDT控制寄存器,向E1000询问等待下一个数据包的TX环索引。
  • 然后检查环是否溢出。如果E1000_TXD_STAT_DD未在E1000_TDT索引的描述符中设置,则E1000尚未完成先前相应的传输请求,因此返回错误。
  • 否则,使用mbuffree()释放从该描述符传输的最后一个mbuf(如果有)。
  • 然后填写描述符。m->head指向内存中数据包的内容,m->len是数据包的长度。设置必要的cmd标志(请参阅E1000手册的第3.3节),并保存指向mbuf的指针,以便稍后释放。
  • 最后,通过将一加到E1000_TDT再对TX_RING_SIZE取模来更新环位置。
  • 如果e1000_transmit()成功地将mbuf添加到环中,则返回0。如果失败(例如,没有可用的描述符来传输mbuf),则返回-1,以便调用方知道应该释放mbuf
int e1000_transmit(struct mbuf *m)
{
  acquire(&e1000_lock);
  int index = regs[E1000_TDT];
  if ((tx_ring[index].status & E1000_TXD_STAT_DD) == 0)
  {
    release(&e1000_lock);
    return -1;
  }
  if (tx_mbufs[index])
    mbuffree(tx_mbufs[index]);
  tx_mbufs[index] = m;
  tx_ring[index].length = m->len;
  tx_ring[index].cmd = (E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP);
  tx_ring[index].addr = (uint64)m->head;
  regs[E1000_TDT] = (index + 1) % TX_RING_SIZE;
  release(&e1000_lock);
  return 0;
}

为什么要使用锁,是为了避免竞态条件,在发送数据时,由于多个线程同时访问发送环(TX_ring)中的描述符,倘若没有锁来保护对描述符的访问,可能对引发竞态条件,导致访问失败。

Recv (moderate)
  • 首先通过提取E1000_RDT控制寄存器并加一对RX_RING_SIZE取模,向E1000询问下一个等待接收数据包(如果有)所在的环索引。
  • 然后通过检查描述符status部分中的E1000_RXD_STAT_DD位来检查新数据包是否可用。如果不可用,请停止。
  • 否则,将mbufm->len更新为描述符中报告的长度。使用net_rx()mbuf传送到网络栈。
  • 然后使用mbufalloc()分配一个新的mbuf,以替换刚刚给net_rx()mbuf。将其数据指针(m->head)编程到描述符中。将描述符的状态位清除为零。
  • 最后,将E1000_RDT寄存器更新为最后处理的环描述符的索引。
  • e1000_init()使用mbufs初始化RX环,您需要通过浏览代码来了解它是如何做到这一点的。
  • 在某刻,曾经到达的数据包总数将超过环大小(16);确保你的代码可以处理这个问题。
static void
e1000_recv(void)
{
  while (1)
  {
    int index = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
    if ((rx_ring[index].status & E1000_RXD_STAT_DD) == 0)
    {
      return;
    }
    rx_mbufs[index]->len = rx_ring[index].length;
    net_rx(rx_mbufs[index]);
    rx_mbufs[index] = mbufalloc(0);
    rx_ring[index].addr = (uint64)rx_mbufs[index]->head;
    rx_ring[index].status = 0;
    regs[E1000_RDT] = index;
  }
}

接收时不使用锁的原因是,调用e1000_recv()是在e1000_intr()中进行的,而e1000_intr()是中断处理函数,所以说e1000_recv 主要在中断上下文中执行,而中断上下文是一个特殊的执行环境,它不会被抢占。在中断上下文中执行的代码是原子的,不会被其他中断打断,因此不需要额外的锁来保护。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值