(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


相关推荐
网络工程小王18 分钟前
【hermes多智能体协作】个人学习笔记
笔记·学习·ai·智能体·hermes
Star Learning Python33 分钟前
20260422-《我不擅长的生活》
笔记·生活
Fanfanaas35 分钟前
Linux 系统编程 进程篇(五)
linux·服务器·c语言·网络·学习·进程
Amazing_Cacao41 分钟前
品鉴师体系闭环:拒绝刻板记忆,打磨具备强悍迁移性的底层判断语言
笔记·学习
yi.Ist1 小时前
2025CCPC郑州邀请赛
c++·学习·算法·acm
HERR_QQ1 小时前
端到端课程自用 2课 动静态感知decoder
笔记·学习·自动驾驶
是上好佳佳佳呀2 小时前
【前端(八)】CSS3 属性值笔记:渐变、自定义字体与字体图标
前端·笔记·css3
Keep Running *2 小时前
Django_学习笔记
笔记·学习·django
今天你TLE了吗2 小时前
LLM到Agent&RAG——AI概念概述 第五章:Skill
人工智能·笔记·后端·学习
不做无法实现的梦~2 小时前
显示屏和显卡驱动问题完整解决教程---ubuntu22.04安装显卡驱动解决显示屏黑屏幕问题
linux·学习