(undone) MIT6.S081 2023 学习笔记 (Day8: LAB7 networking)

网页:https://pdos.csail.mit.edu/6.S081/2023/labs/net.html


任务1:In this lab you will write an xv6 device driver for a network interface card (NIC). (doing)

你将使用一种名为E1000的网络设备来处理网络通信。对于xv6(以及你编写的驱动程序)来说,E1000看起来就像一块连接到真实以太局域网(LAN)的真实硬件。实际上,你的驱动程序将要与之通信的E1000是由qemu提供的模拟设备,连接到一个同样由qemu模拟的局域网。在这个模拟的局域网上,xv6("客户机")的IP地址是10.0.2.15。Qemu还安排了运行qemu的计算机在局域网上显示为IP地址10.0.2.2。当xv6使用E1000向10.0.2.2发送数据包时,qemu会将数据包传递到运行qemu的(真实)计算机("主机")上的相应应用程序。

你将使用QEMU的"用户模式网络栈"。QEMU的文档中有更多关于用户模式网络栈的信息,可以在这里找到。我们已经更新了Makefile,以启用QEMU的用户模式网络栈和E1000网卡。

Makefile 配置了 QEMU,将所有传入和传出的数据包记录到你的实验目录中的 packets.pcap 文件中。查看这些记录可能有助于确认 xv6 是否正在发送和接收你预期的数据包。要显示记录的数据包,可以使用以下命令:

bash 复制代码
tcpdump -XXnr packets.pcap

我们为本次实验向 xv6 仓库添加了一些文件。文件 kernel/e1000.c 包含了 E1000 的初始化代码以及用于发送和接收数据包的空函数,你需要填写这些函数。文件 kernel/e1000_dev.h 包含了 E1000 定义的寄存器和标志位的定义,这些内容在 Intel E1000 软件开发手册中有详细描述。文件 kernel/net.c 和 kernel/net.h 包含了一个简单的网络栈,实现了 IP、UDP 和 ARP 协议。这些文件还包含了一个用于存储数据包的灵活数据结构,称为 mbuf。最后,文件 kernel/pci.c 包含了在 xv6 启动时在 PCI 总线上搜索 E1000 网卡的代码。

这一次 LAB 讲义的内容太多了,我们直接看源码吧。

从讲义来看,这一次要通过的测试为 nettests,需要先在一个窗口运行 make server,再启动 xv6,运行 nettests

我们运行后陷入卡死状态,如下:

OK,那就先来看 nettests.c 源码,先从 main 看起:

c 复制代码
int
main(int argc, char *argv[])
{
  int i, ret;
  // 这个端口号使用 -DNET_TESTS_PORT 在编译阶段定义
  uint16 dport = NET_TESTS_PORT;

  printf("nettests running on port %d\n", dport);
  
  // 测试 ping 命令是否能运行正常
  printf("testing ping: ");
  ping(2000, dport, 1);
  printf("OK\n");
  
  // 测试单进程 100 次 ping 
  printf("testing single-process pings: ");
  for (i = 0; i < 100; i++)
    ping(2000, dport, 1);
  printf("OK\n");
  
  // 申请 10 个 子进程一起 ping
  printf("testing multi-process pings: ");
  for (i = 0; i < 10; i++){
    int pid = fork();
    if (pid == 0){
      ping(2000 + i + 1, dport, 1);
      exit(0);
    }
  }
  for (i = 0; i < 10; i++){
    wait(&ret);
    if (ret != 0)
      exit(1);
  }
  printf("OK\n");
  
  // 测试 DNS
  printf("testing DNS\n");
  dns();
  printf("DNS OK\n");
  
  // 上述都没问题,则所有测试通过 
  printf("all tests passed.\n");
  exit(0);
}

从 main 函数来看,我们需要关心的只有两个函数 ping() 和 dns()。

先来看 ping():

c 复制代码
static void
ping(uint16 sport, uint16 dport, int attempts)
{
  int fd;
  char *obuf = "a message from xv6!";
  uint32 dst;

  // 10.0.2.2, which qemu remaps to the external host,
  // i.e. the machine you're running qemu on.
  dst = (10 << 24) | (0 << 16) | (2 << 8) | (2 << 0);

  // you can send a UDP packet to any Internet address
  // by using a different dst.
  
  if((fd = connect(dst, sport, dport)) < 0){
    fprintf(2, "ping: connect() failed\n");
    exit(1);
  }

  for(int i = 0; i < attempts; i++) {
    if(write(fd, obuf, strlen(obuf)) < 0){
      fprintf(2, "ping: send() failed\n");
      exit(1);
    }
  }

  char ibuf[128];
  int cc = read(fd, ibuf, sizeof(ibuf)-1);
  if(cc < 0){
    fprintf(2, "ping: recv() failed\n");
    exit(1);
  }

  close(fd);
  ibuf[cc] = '\0';
  if(strcmp(ibuf, "this is the host!") != 0){
    fprintf(2, "ping didn't receive correct payload\n");
    exit(1);
  }
}

大致来看,就是使用 connect 系统调用去连接 localhost(outside of qemu) 的一个端口,然后发送一个消息 "a message from xv6!",再接受一个消息 "this is the host!"

TODO: here 我们来仔细研究一下,ping命令这个过程会有哪些包的来往

TODO: here DNS


相关推荐
希望奇迹很安静3 小时前
CTFSHOW-WEB入门-PHP特性89-100
学习·web安全·php·ctf
计算机-秋大田4 小时前
基于微信小程序的绘画学习平台的设计与开发
spring boot·后端·学习·微信小程序·小程序·课程设计
谢道韫6664 小时前
我的鸿蒙学习之旅:探索万物互联的新宇宙
学习·华为·harmonyos
m0_748234904 小时前
Django框架丨从零开始的Django入门学习
学习·django·sqlite
fc&&fl4 小时前
R语言速通
开发语言·学习·r语言
小王努力学编程6 小时前
【算法篇】贪心算法
学习·算法·贪心算法
兔子宇航员03016 小时前
PySpark学习笔记5-SparkSQL
笔记·学习
逆天小北鼻6 小时前
oracle 基础语法复习记录
数据库·学习·oracle