• [MIT 6.1810]Lab7-networking


    Lab7 networking

    https://pdos.csail.mit.edu/6.828/2023/labs/net.html

    背景

    为E1000实现驱动,补全kernel/e1000.c中的两个空函数
    为了达成目的,需要看E1000的文档,对E1000有足够的了解。

    驱动程序

    驱动程序分为top、bottom两部分:

    • top:运行内核线程,由系统调用(例如read、write)调用,要求设备执行IO(发包)。
    • bottom:中断处理线程,硬件中断(例如网卡收到包)调用,处理中断(收包)。

    本实验中,top部分的调用链示例:

    E1000手册

    接收描述符

    网卡约定的数据格式。当收到一个数据包时,网卡填充的信息。
    在这里插入图片描述
    与之对应的代码是:
    在这里插入图片描述

    发送描述符

    在这里插入图片描述
    代码中与之对应的数据结构是tx_desc

    寄存器约定

    手册中约定了控制寄存器的地址,例如环形队列的地址…:
    在这里插入图片描述
    与之对应的宏定义在kernel/e1000_dev.h
    举例:

    1. 硬件约定好了,0x02810位置存储了接收描述符环形队列的队首指针。
    2. 内核初始化时,将接收描述符环形队列的队首指针写入0x02810
    3. 此时,当硬件收到包时,会构建一个描述符,放在0x02810中存储的指针指向的环形队列队首,并产生一个中断。
    环形队列

    以接收环形队列为例:
    为硬件所有,当网卡收到包时,会检查环形队列 head 位置的描述符。然后把数据写入 head 描述符的缓冲区。
    在这里插入图片描述
    接收功能的初始化代码,初始化了环形队列rx_ring;对应的mbuf;位于指定内存中的控制寄存器regs
    在这里插入图片描述
    所以,接收函数就是要去实现处理这个环形队列中已有的待处理包。
    此时,生产者是硬件网卡(维护head指针),消费者是需要实现的接收函数(维护tail指针)。
    生产者消费者之间的通讯方式是:网卡收到包时产生中断,中断处理程序去调用接收函数。

    代码实现

    发送

    作为生产者将入参mbuf打包发送到发送环形队列中,这样硬件作为消费者会自己处理(发出去)。

    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_tx);
      // 在环形队列中获取发送描述符位置
      uint idx = regs[E1000_TDT] % TX_RING_SIZE;
      struct tx_desc *desc = &tx_ring[idx];
      if (desc->status & E1000_TXD_STAT_DD) {
        // 发送描述符对应的mbuf
        if (tx_mbufs[idx]) {
          mbuffree(tx_mbufs[idx]);
        }
        desc->addr = (uint64)m->head;
        desc->length = m->len;
        desc->cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
        tx_mbufs[idx] = m;
        regs[E1000_TDT] = (idx + 1) % TX_RING_SIZE;
      } else {
        goto fail;
      }
      release(&e1000_lock_tx);
      return 0;
    fail:
      release(&e1000_lock_tx);
      printf("e1000 tx error.\n");
      return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    接收

    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()).
      //
      acquire(&e1000_lock_rx);
      while (1) {
        uint idx = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
        struct rx_desc *desc = &rx_ring[idx];
        if (desc->status & E1000_RXD_STAT_DD) {
          // 获取描述符对应的mbuf
          rx_mbufs[idx]->len = desc->length;
          // 将包交给处理函数,解析包头协议&路由给对应的协议栈
          net_rx(rx_mbufs[idx]);
          // 收尾
          rx_mbufs[idx] = mbufalloc(0);
          desc->addr = (uint64)rx_mbufs[idx]->head;
          desc->status = 0;
          regs[E1000_RDT] = idx;
        } else {
          goto end;
        }
      }
    
    end:
      release(&e1000_lock_rx);
      return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    • 需要使用make grade进行测试。
    • desc->addr存储的是是mbuf->head
  • 相关阅读:
    《C和指针》笔记23: 指针的指针
    一起Talk Android吧(第四百二十回:贝塞尔曲线)
    3个变化3秒区别MT4和MT5
    Docker Swarm 更新
    剖析伦敦银最新价格走势图
    muduo库的高性能日志库(二)——Logging文件
    YOLOv3 | 核心主干网络,特征图解码,多类损失函数详解
    【愚公系列】2022年07月 .NET架构班 085-微服务专题 Abp vNext微服务网关
    python自动化测试(二):xpath获取元素
    MySQL 数据库 定义参数【连接查询】
  • 原文地址:https://blog.csdn.net/sancpp/article/details/133972357