(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 小时前
K8S学习之基础二十:k8s的coredns
学习·容器·kubernetes
c7_ln3 小时前
编程视界:C++命名空间
开发语言·c++·笔记
mercyT4 小时前
Kotlin学习笔记之类与对象
笔记·学习·kotlin
四夕白告木贞4 小时前
stm32week6
stm32·单片机·嵌入式硬件·学习
慕容魏4 小时前
入门到入土,Java学习 day16(算法1)
java·学习·算法
啥都想学的又啥都不会的研究生4 小时前
Redis设计与实现-服务器中的数据库
运维·服务器·数据库·redis·笔记·缓存·性能优化
charlie1145141915 小时前
从0开始的操作系统手搓教程27:下一步,实现我们的用户进程
学习·架构·系统架构·操作系统·教程·手搓教程·用户线程
瑶光守护者6 小时前
并行计算编程模型的发展方向与RISC-V的机遇
人工智能·笔记·学习·架构·risc-v
半夏知半秋6 小时前
linux下的网络抓包(tcpdump)介绍
linux·运维·服务器·网络·笔记·学习·tcpdump
Cools06137 小时前
[从零开始学习JAVA] 新版本idea的数据库图形化界面
学习