【MTI 6.S081 Lab】networking

news2024/11/16 15:45:27

【MTI 6.S081 Lab】networking

  • Backgroud
  • Your Job (hard)
    • 实验任务
  • 解决方案

这个实验中,在dns解析时,去请求其dns服务器失败,所以将nettest中的dns服务器改为我自己的。修改的位置大概在nettest.c的235行。

这个实验的设备的具体使用就没去看了,因为我的背景是电子信息工程,玩过51和32,当年也看过很多可编程芯片的数据手册。对很多外设的操作是比较熟悉的,就命令字,然后数据字,都类似,所以就没去看文档了,所有命令字网上的答案中找的。整个实验差不多也是网上答案,把它看懂改了错。

// // 8.8.8.8: google's name server
// dst = (8 << 24) | (8 << 16) | (8 << 8) | (8 << 0);
// 127.0.0.53 是在我的机器上运行nslookup baidu.com 出现的dns服务器地址
dst = (127 << 24) | 53;

在这个实验室中,您将为网络接口卡(NIC)编写一个xv6设备驱动程序。

Backgroud

在写代码前,复习"Chapter 5: Interrupts and device drivers"会是很有帮助的。

您将使用一种名为E1000的网络设备来处理网络通信。对于xv6(以及您编写的驱动程序)来说,E1000看起来像是连接到真正的以太网局域网(LAN)的一块真正的硬件。事实上,您的驱动程序将与之交谈的E1000是由qemu提供的模拟,它连接到一个局域网,该局域网也由qemu模拟。在这个模拟局域网上,xv6(“guest”)的IP地址为10.0.12.15。Qemu还安排运行Qemu的计算机出现在IP地址为10.0.2.2的局域网上。当xv6使用E1000向10.0.2.2发送数据包时,qemu会将数据包传递到运行qemu的(实际)计算机(“host”)上的相应应用程序。

您将使用QEMU的“用户模式网络堆栈”(user-mode network stack)。QEMU的文档中有更多关于用户模式堆栈的内容。我们已经更新了Makefile,以启用QEMU的用户模式网络堆栈和E1000网卡。

Makefile将QEMU配置为将所有传入和传出的数据包记录到实验目录中的packets.pcap文件中。查看这些记录以确认xv6正在发送和接收您期望的数据包可能会有所帮助。要显示记录的数据包:

tcpdump -XXnr packets.pcap

我们已经为该实验的xv6存储库添加了一些文件。文件kernel/e1000.c包含e1000的初始化代码以及用于发送和接收数据包的空函数,您将填写这些代码。kernel/e000_dev.h包含e1000定义的寄存器和标志位的定义,如Intel E1000 Software Developer’s Manual中所述。kernel/net.c和kernel/ne.h包含一个简单的网络堆栈,用于实现 IP, UDP, and ARP协议。这些文件还包含用于保存数据包的灵活数据结构的代码,称为mbuf。最后,kernel/pci.c包含在xv6启动时在pci总线上搜索E1000卡的代码。

Your Job (hard)

实验任务

你的工作是完成在kernel/e1000.c中的两个函数e1000_transmit()e1000_recv(),以便于驱动能发送和接收包。当make grade说你的解决方案通过了所有的测试你就完成了这个工作。

当你写代码时,你将发现阅读 E1000 Software Developer’s Manual会是很有用的。以下几节可能是特别有帮助的:

  • 第2节非常重要,它概述了整个设备。
  • 第3.2节概述了数据包接收。
  • 第3.3节与第3.4节一起概述了分组传输。
  • 第13节概述了E1000使用的寄存器。
  • 第14节可能会帮助您理解我们提供的init代码。

浏览E1000 Software Developer’s Manual。本手册涵盖了几个密切相关的以太网控制器。QEMU模拟82540EM。现在浏览第 2 章来感受一下该设备。 要编写驱动程序,您需要熟悉第 3 章和第 14 章以及 4.1(尽管不是 4.1 的小节)。 您还需要使用第 13 章作为参考。 其他章节主要介绍驱动程序无需与之交互的 E1000 组件。 一开始不要担心细节; 只需感受一下文档的结构,以便稍后查找。 E1000 有许多高级功能,其中大部分您可以忽略。 完成本实验只需要一小组基本功能。

我们在e1000.c中为您提供的e1000_init()函数将e1000配置为读取要从RAM传输的数据包,并将接收到的数据包写入RAM。这种技术被称为DMA,用于直接存储器访问,指的是E1000硬件直接向RAM写入数据包和从RAM读取数据包。

由于数据包的突发到达速度可能快于驱动程序处理它们的速度,e1000_init()为e1000提供了多个缓冲区,e1000可以将数据包写入其中。E1000要求通过RAM中的一组“描述符”来描述这些缓冲区;每个描述符包含RAM中的一个地址,E1000可以在该地址写入接收到的数据包。struct rx_desc描述描述符格式。描述符数组称为接收环或接收队列。它是一个圆环,当卡或驱动程序到达阵列的末端时,它会回到起点。e1000_init()使用mbufalloc()为要DMA的e1000分配mbuf数据包缓冲区。还有一个传输环,驱动程序应该将它希望E1000发送的数据包放入其中。e1000_init()将两个环的大小配置为RX_RING_size和TX_RING_size。

当net.c中的网络堆栈需要发送数据包时,它会调用e1000_transmit(),其中包含一个保存要发送的数据包的mbuf。您的传输代码必须在TX(传输)环的描述符中放置指向数据包数据的指针。struct tx_desc描述描述符格式。您需要确保每个mbuf最终都被释放,但只有在E1000完成数据包传输之后(E1000在描述符中设置E1000_TXD_STAT_DD位来指示这一点)。

当E1000从以太网接收到每个数据包时,它将数据包DMA到下一个RX(接收)环描述符中addr指向的存储器。如果E1000中断尚未挂起,则E1000会要求PLIC在启用中断后立即发送一个中断。e1000_recv()代码必须扫描RX环,并通过调用net_RX()将每个新数据包的mbuf传递到网络堆栈(在net.c中)。然后,您需要分配一个新的mbuf并将其放入描述符中,这样当E1000再次到达RX环中的那个点时,它就会找到一个新缓冲区,将新数据包DMA到其中。

除了读取和写入RAM中的描述符环外,您的驱动程序还需要通过其内存映射的控制寄存器与E1000进行交互,以检测接收到的数据包何时可用,并通知E1000驱动程序已用要发送的数据包填充了一些TX描述符。全局变量regs保存指向E1000的第一控制寄存器的指针;您的驱动程序可以通过将regs作为数组进行索引来访问其他寄存器。您需要特别使用索引E1000_RDT和E1000_TDT。

要测试驱动程序,请在一个窗口中运行make server,在另一个窗口运行make qemu,然后在xv6中运行nettest。nettests中的第一个测试尝试向主机操作系统发送UDP数据包,该数据包寻址到使服务器运行的程序。如果你还没有完成实验,E1000驱动程序实际上不会发送数据包,也不会发生什么事情。

在你完成实验室后,E1000驱动程序将发送数据包,qemu将把它发送到你的主机,让服务器看到它,它将发送一个响应数据包,E1000驱动器和网络测试将看到响应数据包。然而,在主机发送回复之前,它会向xv6发送一个“ARP”请求包,以找出其48位以太网地址,并期望xv6以ARP回复进行响应。一旦您完成了E1000驱动程序的工作,kernel/net.c就会处理这个问题。如果一切顺利,nettests将打印测试ping:OK,make server将打印来自xv6的消息!。

在这里插入图片描述

您的输出看起来会有所不同,但它应该包含字符串“ARP,Request”、“ARP,Reply”、“UDP”、“a.message.from.xv6”和“this.is.host”。

nettests执行一些其他测试,最终通过(真实的)互联网向谷歌的一个名称服务器发送DNS请求。您应该确保您的代码通过所有这些测试,然后您应该看到以下输出:

$ nettests
nettests running on port 25603
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.

您应该确保make grade同意您的解决方案通过。

Hints:

首先,将print语句添加到e1000_transmit()和e1000_recv()中,并运行make-server和(在xv6中)nettest。您应该从打印语句中看到,nettest生成了对e1000_transmit的调用。

实现e1000_transmit的一些提示:

  • 首先,通过读取E1000_TDT控制寄存器,向E1000询问它期望下一个数据包的TX ring索引。
  • 然后检查环是否溢出。如果E1000_TDT索引的描述符中没有设置E1000_TXD_STAT_DD,则E1000没有完成相应的上一次传输请求,因此返回错误。
  • 否则,使用mbuffree()释放从该描述符传输的最后一个mbuf(如果有的话)。
  • 然后填写描述符。m->head指向内存中数据包的内容,m->len是数据包的长度。设置必要的cmd标志(请参阅E1000手册中的第3.3节),并隐藏一个指向mbuf的指针,以便稍后释放。
  • 最后,通过在E1000_TDT模TX_ring_SIZE上加一来更新环位置。
  • 如果e1000_transmit()将mbuf成功添加到环中,则返回0。失败时(例如,没有可用于传输mbuf的描述符),返回-1,以便调用者知道释放mbuf。

实现e1000_recv的一些提示:

  • 首先,通过获取E1000_RDT控制寄存器并加一模RX_ring_SIZE,向E1000询问下一个等待接收的数据包(如果有的话)所在的环索引。
  • 然后通过检查描述符的状态部分中的E1000_RXD_STAT_DD比特来检查新分组是否可用。如果没有,请停止。
  • 否则,将mbuf的m->len更新为描述符中报告的长度。使用net_rx()将mbuf传递到网络堆栈。
  • 然后使用mbufalloc()分配一个新的mbuf,以替换刚刚给net_rx()的mbuf。将其数据指针(m->head)编程到描述符中。将描述符的状态位清除为零。
  • 最后,将E1000_RDT寄存器更新为处理的最后一个环形描述符的索引。
  • e1000_init()使用mbufs初始化RX环,您需要了解它是如何做到这一点的,也许还需要借用代码。
  • 在某个时刻,曾经到达的分组的总数将超过环大小(16);请确保您的代码能够处理此问题。

您需要锁来应对xv6可能使用来自多个进程的E1000,或者在中断到达时可能在内核线程中使用E1000的可能性。

解决方案

个人觉得这个lab的难度应该就是看文档了。代码量很少。

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.
  //
  acquire(&e1000_lock);
  uint32 i = regs[E1000_TDT];
  // i %= TX_RING_SIZE;     // 在上一次结束位置已经模了,所以这里不需要在模了
  if ((tx_ring[i].status & 0x01) != E1000_TXD_STAT_DD) {
    release(&e1000_lock);
    return -1;
  }
  if (tx_mbufs[i]) {
    mbuffree(tx_mbufs[i]);
  }
  tx_mbufs[i] = m;
  tx_ring[i].addr = (uint64)m->head;
  tx_ring[i].length = m->len;
  tx_ring[i].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
  tx_ring[i].status = 0;

  regs[E1000_TDT] = (i + 1) % TX_RING_SIZE;
  release(&e1000_lock);
  return 0;
}

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()).
  //
  uint32 i = regs[E1000_RDT];
  i = (i + 1) % RX_RING_SIZE;
  while ((rx_ring[i].status &0x01) == E1000_RXD_STAT_DD) {
    mbufput(rx_mbufs[i], rx_ring[i].length);
    net_rx(rx_mbufs[i]);
    rx_mbufs[i] = mbufalloc(0);
    rx_ring[i].addr = (uint64)rx_mbufs[i]->head;
    rx_ring[i].status = 0;
    i = (i + 1) % RX_RING_SIZE;
  }
  regs[E1000_RDT] = i - 1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/810480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

行为型:迭代器模式

定义 迭代器模式提供一种方法按顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露该对象的内部表示。迭代器模式是目的性极强的模式&#xff0c;它主要是用来解决遍历问题。 es6 中的迭代器 JS原生的集合类型数据结构&#xff0c;有Array&#xff08;数组&#xff09;和…

【算法基础:动态规划】5.2 线性DP

文章目录 例题列表898. 数字三角形895. 最长上升子序列&#xff08;n^2两重循环dp&#xff09;896. 最长上升子序列 II&#xff08;贪心二分查找&#xff09;897. 最长公共子序列902. 最短编辑距离899. 编辑距离⭐⭐⭐⭐⭐ 例题列表 898. 数字三角形 每个数字可以从它上面的左…

【雕爷学编程】MicroPython动手做(15)——掌控板之AB按键

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

怎么查看gcc的安装路径

2023年7月29日 很简单&#xff0c;通过在命令行输入如下命令就可以了&#xff1a; gcc -print-search-dirs在Windows中 在Linux中 ​​​

Github Copilot在JetBrains软件中登录Github失败的解决方案

背景 我在成功通过了Github Copilot的学生认证之后&#xff0c;在VS Code和PyCharm中安装了Github Copilot插件&#xff0c;但在PyCharm中插件出现了问题&#xff0c;在登录Github时会一直Retrieving Github Device Code&#xff0c;最终登录失败。 我尝试了网上修改DNS&…

❤️创意网页:能量棒页面 - 可爱版(加载进度条)

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

电动汽车集群并网的分布式鲁棒优化调度模型(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 文献来源&#xff1a; 随着可再生能源&#xff08;Renewable Energy Source, RES&#xff09;的渗透率不断提高&#xff0c;RES 固有的间歇性对…

【RabbitMQ】Linux系统服务器安装RabbitMQ

一、下载 首先应该下载erlang&#xff0c;rabbitmq运行需要有erland环境。 官网地址&#xff1a;https://www.erlang.org/downloads 下载rabbitmq 官网环境&#xff1a;https://www.rabbitmq.com/download.html 注意&#xff1a;el7对应centos7&#xff0c;el8对应centos8…

机器学习:混合高斯聚类GMM(求聚类标签)+PCA降维(3维降2维)习题

使用混合高斯模型 GMM&#xff0c;计算如下数据点的聚类过程&#xff1a; Datanp.array([1,2,6,7]) 均值初值为: μ1,μ21,5 权重初值为: w1,w20.5,0.5 方差: std1,std21,1 K2 10 次迭代后数据的聚类标签是多少&#xff1f; 采用python代码实现&#xff1a; from scipy import…

iOS开发-CABasicAnimation实现小球左右摆动动画效果

iOS开发-CABasicAnimation实现小球左右摆动动画效果 之前开发中遇到需要实现小球左右摆动动画效果&#xff0c;这里作下记录。 一、效果图 二、实现代码 2.1 CABasicAnimation CABasicAnimation基础动画&#xff0c;包括duration、repeatCount、repeatDuration、beginTime、…

Java中对Redis的常用操作

目录 数据类型五种常用数据类型介绍各种数据类型特点 常用命令字符串操作命令哈希操作命令列表操作命令集合操作命令有序集合操作命令通用命令 在Java中操作RedisRedis的Java客户端Spring Data Redis使用方式介绍环境搭建配置Redis数据源编写配置类&#xff0c;创建RedisTempla…

JavaEE—— Callable接口、JUC的常见类、线程按安全的集合类(八股)

文章目录 一、Callable 接口二、JUC的常见类1. ReentrantLock2. 原子类(简单知晓)3.信号量 Semaphore4.CountDownLatch(简单了解) 三、线程安全的集合类1.多线程环境使用 ArrayList2.多线程使用哈希表 一、Callable 接口 Callable 接口类似于 Runnable 接口 Runnable 接口用来…

当阿里面试官问什么是hash?什么是布隆过滤器?什么是一致性hash?看这一篇就够了,很肝!也很干!

算法拾遗三十六hash 哈希函数特点hash表设计布隆过滤器布隆过滤器三大公式最终求解公式 一致性哈希经典数据存储经典hash缺点及解决方案虚拟节点 哈希函数特点 输入&#xff1a;任意长度字符串&#xff08;输入域无穷大&#xff09; 输出&#xff1a;相对有限 哈希函数无任何随…

前端,js , Error in created hook: TypeError ,有bug了

怎么兄弟&#xff0c;遇到bug了&#xff1f;&#xff1f;&#xff1f;你开心吗&#xff0c;哈哈哈哈

Linux操作系统1-命令篇

不同领域的主流操作系统 桌面操作系统 Windos Mac os Linux服务器操作系统 Unix Linux(免费、稳定、占有率高) Windows Server移动设备操作系统 Android(基于Linux,开源) ios嵌入式操作系统 Linux(机顶盒、路由器、交换机) Linux 特点&#xff1a;免费、开源、多用户、多任务…

【C/C++】#include<xxx.h>和#include“xxx.h“之间的区别以及寻找gcc和g++的系统头文件目录和系统库文件目录的方法

2023年7月29日&#xff0c;周六晚上 今天下午和晚上花了不少时间去研究这个C/C的头文件以及#include<xxx.h>和#include"xxx.h"之间的区别&#xff0c;收获到了很多的很有用的知识。非常值得花时间来以博客的形式总结这些学习成果。 说实话&#xff0c;我挺想…

python美化图形化界面设计,pythontkinter界面美化

大家好&#xff0c;本文将围绕python美化图形化界面设计展开说明&#xff0c;pythontkinter界面美化是一个很多人都想弄明白的事情&#xff0c;想搞清楚python美化输出模块需要先了解以下几个事情。 1、python如何做界面 PyQt&#xff0c;一个基于Qt的Python接口包&#xff0c…

网络框架重构之路plain2.0(c++23 without module) 综述

原因 plain1.1rc的不足 &#xff11;、命名空间问题 如果看过或者接触过plain的朋友&#xff0c;不难发现命名空间都是以pf_*开头。说起这个的时候&#xff0c;还是要从plain的前身plainserver&#xff08;GitHub - viticm/plainserver: A plain server, simple but stronger.&…

SpringBoot超级详解

1.父工程的父工程 在父工程的父工程中的核心依赖&#xff0c;专门用来版本管理的 版本管理。 2.父工程 资源过滤问题&#xff0c;都帮解决了&#xff0c;什么配置文件&#xff0c;都已经配置好了&#xff0c;资源过滤问题是帮助&#xff0c;过滤解决让静态资源文件能够过滤到…

HCIP OSPF链路状态类型总结

OSPF的LSA OSPF是典型的链路状态路由协议&#xff0c;使用LAS&#xff08;链路状态通告&#xff09;来承载链路状态信息。LSA是OSPF的一个核心内容&#xff0c;如果没有LSA&#xff0c;OSPF 是无法描述网络的拓扑结构及网段信息的&#xff0c;也无法传递路由信息&#xff0c;更…