6.S081-Lab7

Lab: networking

lab 地址

还可以参考的在线课程: 21 (介绍了网络)和24(介绍了作业推荐只看前面然后做了作业可以看后面部分)
https://www.bilibili.com/video/BV19k4y1C7kA?p=20&vd_source=f390d3ec07fdc69957679b24c75ca379

还有一定要按照它的要求去看下手册:

Browse the E1000 Software Developer’s Manual. This manual covers several closely related Ethernet controllers. QEMU emulates the 82540EM. Skim Chapter 2 now to get a feel for the device. To write your driver, you’ll need to be familiar with Chapters 3 and 14, as well as 4.1 (though not 4.1’s subsections). You’ll also need to use Chapter 13 as a reference. The other chapters mostly cover components of the E1000 that your driver won’t have to interact with. Don’t worry about the details at first; just get a feel for how the document is structured so you can find things later. The E1000 has many advanced features, most of which you can ignore. Only a small set of basic features is needed to complete this lab.

手册地址:

这个课程其实只是看上去很大。但是实现起来没有那么复杂。
主要明白下面几个概念:

在这里插入图片描述

  • 对于网卡层发送和接收,它都有一个 环形的buffer 读对应 rx ring,写 tx ring 。
  • 发送:当有数据发送到网卡的缓冲区时网卡试图找到空闲的一个硬件地址(ring buffer),然后将缓冲区地址写入到该硬件地址中(寄存器中)。网卡就可以直接通过该地址直接读取要发送的数据进行发送。
  • 接收:当网卡收到数据时这个时候硬件将数据从物理层(网卡)发送到网络层。(在该作业中硬件数据已经被软件正确放置到rx_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.
  //
  
  // lock
   acquire(&e1000_lock);
  // 1. check tx ring read index from tx ring 如果E1000_TDT中有数据则E1000_TXD_STAT_DD 被设置 
  uint32 tail=    regs[E1000_TDT];
  struct tx_desc *desc= &tx_ring[tail];

  //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( ! desc->status & E1000_TXD_STAT_DD ){
       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[tail]){
      mbuffree(tx_mbufs[tail]);
    }

   //Then fill in the descriptor. 

    // m->head points to the packet's content in memory,  
     desc->addr=(uint64)m->head;
    //and m->len is the packet length
     desc->length=m->len; 
    // Set the necessary cmd flags 

    //EOP (bit 0)   
//     End Of Packet
// When set, indicates the last descriptor making up the packet. One or many
// descriptors can be used to form a packet.
    //RS (bit 3)
//     Report Status
// When set, the Ethernet controller needs to report the status information. This ability
// may be used by software that does in-memory checks of the transmit descriptors to
// determine which ones are done and packets have been buffered in the transmit
// FIFO. Software does it by looking at the descriptor status byte and checking the
// Descriptor Done (DD) bit. 
    desc->cmd= E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;


  // stash away a pointer to the mbuf for later freeing.
    tx_mbufs[tail]=0;
 
   regs[E1000_TDT]= (tail+1) % TX_RING_SIZE;


   
   release(&e1000_lock);
  


  return 0;
}

接收:


static void
e1000_recv(void)
{
  // why read don't need use lock cuz read method called by trap.  So  no concurrent condition with recv
  //
  // Your code here.
  //
  // Check for packets that have arrived from the e1000
  // Create and deliver an mbuf for each packet (using net_rx()).
  //

  //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.
  while(1){

      uint32 tail=(regs[E1000_RDT]+1) % RX_RING_SIZE;
     struct rx_desc *desc = &rx_ring[tail];
  //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(! (desc->status & E1000_RXD_STAT_DD) ){
    return;
  }
 //Otherwise, update the mbuf's m->len to the length reported in the descriptor. Deliver the mbuf to the network stack using net_rx().
   rx_mbufs[tail]->len= desc->length;
   net_rx(rx_mbufs[tail]);

  //Then allocate a new mbuf using mbufalloc() to replace the one just given to net_rx(). 
     rx_mbufs[tail] = mbufalloc(0);
       //Program its data pointer (m->head) into the descriptor.
     desc->addr= (uint64)rx_mbufs[tail]->head;
     //Clear the descriptor's status bits to zero. 
     desc->status=0;

    //Finally, update the E1000_RDT register to be the index of the last ring descriptor processed.
    regs[E1000_RDT]=(regs[E1000_RDT]+1)% RX_RING_SIZE;
  }
 
}

测试须知:

nettests 测试时 它的dns主机是 8.8.8.8
在国内的话是连不上的,可以切换它的测试源用223.5.5.5 代替


static void
dns()
{
  #define N 1000
  uint8 obuf[N];
  uint8 ibuf[N];
  uint32 dst;
  int fd;
  int len;

  memset(obuf, 0, N);
  memset(ibuf, 0, N);
  
  // 8.8.8.8: google's name server
  //223.5.5.5 
  // dst = (8 << 24) | (8 << 16) | (8 << 8) | (8 << 0);
    dst = (223 << 24) | (5 << 16) | (5 << 8) | (5 << 0);


  if((fd = connect(dst, 10000, 53)) < 0){
    fprintf(2, "ping: connect() failed\n");
    exit(1);
  }

  

结果:

$ nettests
nettests running on port 25600
testing ping: OK
testing single-process pings: OK
testing multi-process pings: OK
testing DNS
DNS arecord for pdos.csail.mit.edu. is 128.52.129.126
DNS OK
all tests passed.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值