2020 MIT6.s081 Lab networking

友情链接:全部实验哟


Lec18-23: 学习笔记

  1. lec18 阅读论文《The Performance of µ-Kernel-Based Systems》
  2. lec19 阅读论文《Dune: Safe User-level Access to Privileged CPU Features》
  3. lec20 阅读论文《The benefits and costs of writing a POSIX kernel in a high-level language》
  4. lec21 阅读论文 Eliminating Receive Livelock in an Interrupt-driven Kernel
  5. lec22 阅读论文《Meltdown: Reading Kernel Memory from User Space》
  6. lec23 阅读论文《RCU Usage In the Linux Kernel: One Decade Later》

实验链接

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

实验

Lab: networking

实验的目的是为了让我们实现一个网卡驱动在数据链路层的数据收发函数,该函数的实现需要参考E1000的用户手册来完成。

不过,实验中作者给出的hint非常详细,按照hint一步一步实现即可(感觉不看用户手册和xv6代码,感兴趣的可以多看看哈)。

函数e1000_recv需要注意的地方:

  1. 不需要加锁,因为该函数会一次性读取rx_ring上所有的数据,且该函数位于数据链路层,数据链路层还不涉及进程的概念。在读取完数据之后,该函数会调用net_rx函数,将数据送给上层应用。
  2. 关于index的理解,在recv函数中,寄存器里保存的index是上次已经被处理过的位置,因此,拿到寄存器里的值后,需要加一移动至下个位置。且本次的数据被送至上层应用之后,会对其mbuf进行清理并申请新的mbuf用于保存下次接收的数据。

函数e1000_transmit需要注意的地方:

  1. 该相关寄存器中保存的index值为本次需要处理的数据索引,因此,本次处理完之后,需要对该值加一并重新放入寄存器。

具体实现如下:

  1. 文件e1000.c,函数e1000_transmit

    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.
      //
      // printf("e1000 transmit\n");
      acquire(&e1000_lock);
      // First ask the E1000 for the TX ring index at which it's expecting
      // the next packet, by reading the E1000_TDT control register.
      uint32 index = regs[E1000_TDT];
      // Then check if the the ring is overflowing. If E1000_TXD_STAT_DD is
      // not set in the descriptor indexed by E1000_TDT, the E1000 hasn't
      // finished the corresponding previous transmission request, so return an error.
      if ((tx_ring[index].status & E1000_TXD_STAT_DD) == 0) {
        release(&e1000_lock);
        return -1;
      }
    
      // Otherwise, use mbuffree() to free the last mbuf that was transmitted
      // from that descriptor (if there was one).
      if (tx_mbufs[index]) {
        mbuffree(tx_mbufs[index]);
      }
    
      // m->head points to the packet's content in memory
      tx_ring[index].addr = (uint64)(m->head);
      //  and m->len is the packet length
      tx_ring[index].length = m->len;
      // Set the necessary cmd flags (look at Section 3.3 in the E1000 manual)
      tx_ring[index].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
      // and stash away a pointer to the mbuf for later freeing.
      tx_mbufs[index] = m;
    
      // update the ring position by adding one to E1000_TDT modulo TX_RING_SIZE.
      regs[E1000_TDT] = (index + 1) % TX_RING_SIZE;
      release(&e1000_lock);
      return 0;
    }
    
  2. 文件e1000.c,函数e1000_recv

    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()).
      //
      // printf("e2000 receive\n");
      for (;;) {
        // First ask the E1000 for the ring index at which the next waiting
        // received packet (if any) is located, by fetching the E1000_RDT
        // control register and adding one modulo RX_RING_SIZE.
        uint32 index = regs[E1000_RDT];
        index = (index + 1) % RX_RING_SIZE;
    
        // Then check if a new packet is available by checking for the
        // E1000_RXD_STAT_DD bit in the status portion of the descriptor.
        // If not, stop.
        if ((rx_ring[index].status & E1000_RXD_STAT_DD) == 0) {
          return;
        }
    
        // update the mbuf's m->len to the length reported in the descriptor.
        rx_mbufs[index]->len = rx_ring[index].length;
        // rx_mbufs[index]->head = (char*)rx_ring[index].addr;
    
        // Deliver the mbuf to the network stack using net_rx()
        net_rx(rx_mbufs[index]);
        // Then allocate a new mbuf using mbufalloc() to replace the one just
        // given to net_rx().
        struct mbuf* buf = mbufalloc(0);
        rx_mbufs[index] = buf;
        // Program its data pointer (m->head) into the descriptor.
        rx_ring[index].addr = (uint64)buf->head;
        // Clear the descriptor's status bits to zero
        rx_ring[index].status = 0;
    
        // Finally, update the E1000_RDT register to be the index of the
        // last ring descriptor processed.
        regs[E1000_RDT] = index;
      }
    }
    
  3. 文件nettest.cdns函数,将8.8.8.8改为114.114.114.114

    static void
    dns()
    {
      xxx
      // 8.8.8.8: google's name server
      // dst = (8 << 24) | (8 << 16) | (8 << 8) | (8 << 0);
      dst = (114 << 24) | (114 << 16) | (114 << 8) | (114 << 0);
       xxx
    }
    
  4. 执行结果1

    在这里插入图片描述


结果

$ make grade

在这里插入图片描述


提交结果

$ git commit -m "lab network"
$ make handin

查看结果

登录网站https://6828.scripts.mit.edu/2020/handin.py/student,可以看到提交的结果。

在这里插入图片描述


参考链接

https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081

https://pdos.csail.mit.edu/6.S081/2020/schedule.html


Github

源码: https://github.com/aerfalwl/mit-xv6-labs-2020


完结撒花!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值