也谈课改——以网原为例

 

引子

“课改”,是这两年在贵系很热门的一个议题。字面意义上,课改就是课程改革,似乎并非什么大事,毕竟没有什么会是一成不变的。但实际上,这个词早已经被赋予了太多的含义。一千个贵系同学心中,对课改就有一千种定义,而评价自然也是根据个人的认识与体验褒贬不一。我本人作为贵系本科生,自然是这股“课改”大潮的亲历者,也勉强可以算得上半个参与者。在经历了各种各样的风波之后,我一直想谈一谈自己的经历,还有对于课改的看法。然而由于种种原因(主要是摸🐟),“写一篇博客”这一项却在我的 TODO 里面躺了整整一个学期。恰好最近系里的公众号想要征集大家对本科生活的回顾,某不愿意透露姓名的 L 姓学姐也反复催促;再加这两天恰逢毕业,虽然无法回校和同学们拍毕业照非常令人伤感,倒是也有了一点点自己的时间。总之,不能再鸽了。

声明:本文所有内容仅代表个人观点。感谢为本文提供了图片素材的各位同学,尤其感谢李山山老师的两次出镜。

造路由器:1.0

理想

最早接触到“课改”这个词,其实来源于“课改先锋”的称号。而这一切又要起源于 2017 年的一个冬天,某位五字班的 C 姓学长(下面简称为“C 学长“)在网原课上,提出了一个开天辟地的建议:

wan-e-zhi-yuan

众所周知,贵系有“奋战三星期,造台计算机”的传统。在这三星期中,同学们废寝忘食,没日没夜地埋头苦干。其他课的老师们虽然会受点委屈(比如出勤率明显下降),但也纷纷表示理解。不过,吴老板显然不满足于此:计算机网络原理课作为计算机学科的核心课程之一,向来理论居多,缺乏像计原那么硬核而又给人带来成就感的实验。网原现有的 NetRiver 实验系统也使用了多年,被同学们诟病颇深。那么,既然有同学提出了这个建议,亲手造一台路由器确实是一件听起来振奋人心的事情。

于是,在 2018 年的秋季学期,第一节网原课上,老师就拿出了这样一张 PPT:

fang-wei-xing

这也宣告着网原实验改革的正式开始,这张 PPT 的截图,与右下角的来自负责计原实验的李山山老师的著名采访片段一样,占据了当天无数贵系学生的朋友圈。这四点实验目标的具体解释为:

  • 实验一:使用著名的 Quagga 路由工具,进行简单的 RIP 和 OSPF 路由器协议配置,并利用 Linux 自带的路由能力进行转发;
  • 实验二:基于 raw socket 实现一个转发引擎,从 Quagga 获取路由表项目,替换 Linux 网络栈进行转发;
  • 实验三:实现一个简化版的 RIP Daemon,能够进行简单的路由学习与分发;
  • 实验四:使用自己的 RIP Daemon 替换掉 Quagga,与转发引擎进行集成,完全使用自己编写的软件进行路由学习和包转发。

客观来说,实验的设计思想确实不错:首先使用现有的成熟解决方案,而后逐步实现并替换其中的转发与路由两个模块,最终就得到了属于自己的软件路由器。

现实

实验是从期中之后开始的。我们首先得到了一份实验指导书,语焉不详,但大家都觉得在实验中或许助教能给出更多的指导,就没有太过关注。

进入真正的试验阶段,虽然 Quagga 的 Cisco 式命令行确实需要一段时间适应,实验一并没有给大家带来什么大的困难,操作也算是比较直观。然而在验收时有部分助教似乎对于实验内容并不了解,只是要求大家敲对应的命令,也不能给出什么解释,引起了部分同学的不满。

如果说实验一勉强说得过去,当实验二的所谓“框架”发下来时,我整个人都震惊了:这哪里是什么实验框架,这明明就是一堆屎山。如果说代码风格一塌糊涂还能容忍,Makefile 里面还有诡异的错,根本编译不出可执行文件,就让我非常困惑了。处于强迫症,我花了相当长的时间,才把代码整理成了能用的版本。这就直接引出了一个严重的问题:

为什么助教没有发现这些问题?

当天我就在课程群里提出了质疑,语气比较气愤。当天我并没有得到及时的回复,听说晚上老师和助教们开了一晚上的会,然而后来给出的答复也模棱两可。不过至少我们得知了一个事实:实验框架是课程委托某公司 B 代为外包开发的,助教并没有进行完善的测试就发布了实验。

不管怎么说,有编译错误也不是什么不可饶恕的事情。于是我开始尝试着实现功能。但是发现难度其实相当大。转发引擎所需的各种功能都必须通过 Linux 提供的底层网络 API 来实现,而 Linux 系统编程和调试对于未曾接触过类似范式的同学来说,是相当大的挑战。我在此并无意阐述过多的技术细节,但必须要强调其中存在大量繁琐细碎的细节和坑点,而实验文档和代码中几乎没有任何说明,这给同学们带来了巨大的困难。

我是当时整个年级(或许也是整门课程)第一个完成了转发引擎实验的人。在体会完其中的艰辛后,我就向助教提出了一些列建议,包括改进重写框架,延长实验时间等。毕竟,当时也恰好是著名的“三星期”的阶段,同学们原本就无法匀出太多的精力,何况是和 Linux 系统做这些无意义的搏斗呢?当然,重写框架大概是不可能的,但是延长时间成了一个被迫之举——因为原本的验收时间即将到来之际,只有屈指可数的同学完成了任务。

当我意识到问题的严重性之后,也做出了一些尝试。其中最重要的可能是写了这个名为 hint.pdf 的文件,把整个实验二的流程用更简明的方式阐述了一遍,包括各个步骤需要使用的头文件、函数调用方式等,以及实验框架中现存的错误和隐患。我也在我们班开了一个中厅讲座,给大家讲了讲具体的实现方式。不夸张地说,我相信六字班的不少同学得到了我这些提示的帮助(或许是因为其中的代码基本上可以直接使用),从而更顺利地完成了实验。

接下来的实验三和四的剧情和实验二相当类似,同样是错误多多的文档和遍地是坑的框架。当然,此时的我已经不再相信和使用粗制滥造的框架,而是选择自己重写。当然,由于后两个实验涉及较少的 Linux API 相关内容,因此工程复杂度也下降了,同学们遇到的困难更多来自于实验文档的歧义。我也向助教提出了部分改进建议,基本都得到了采纳。

终于到了验收的日子,除了个人验收外,还有组队验收,即要求几个人的路由器能够顺利协同工作。当然,考虑到同学们的现状,最早吴老板提出的“十个人插一个环”基本上是绝无可能实现的,于是要求降低到了三个人的链状链路。我找了几位完成实验比较快的同学和我一起组队,但也在验收前的联合调试环节花费了一小时左右的时间(这里不得不吐槽某人用空气当网线)。很多同学的组队验收可以说是相当痛苦,毕竟三个人只要有一个出错,就完全无法通过。据我所知,有好几组同学从午后一直调试到深夜实验室关门都没能顺利通过,只能第二天继续。

自然,同学们对于这一年网原的实验是不可能满意的。除了实验本身存在的问题,比如难度过大,文档不详之外,部分助教的不专业、不负责也是很重要的因素。某位助教在验收时间放同学鸽子,把同学关在实验室门外;专业知识匮乏,无法回答与实验有关的问题,甚至对基本的网络知识也是一问三不知;在验收时,打分随意,态度也极其糟糕。这让同学们感到非常失望,自然也会对实验本身产生不好的印象。

造路由器:2.0

动机

尽管改革第一年网原实验没有给我带来太大的困难,但我深知这是不可行的。这样的实验并不能起到设计的初衷,同学们学不到真正的知识,也无法感受到趣味和成就感,反而会产生厌恶的情绪,适得其反。主要原因有两个,一是实验本身的设计糟糕;二是助教并没有很好地参与到实验指导中来。于是我决定,从这两个方面入手改善问题。

此外,在 2019 年春季学期的数设课程中,杰哥基于 FPGA 实现了一款硬件路由器,可以实现硬件的包转发,并且通过软件实现了路由协议和配置功能。这让我和老师们都感觉十分惊喜,因为这的确是比起软件转发引擎更接近于真实“路由器”的存在,同时也可以很好地与大三上的“造机”结合起来。

于是在开学前,全老师组织我、杰哥、宇翔进行了几次讨论,最后确定了这一年网原课程实验的改革方向:软件与硬件并进,软件依旧是必选的,硬件则自愿组队参加。

软件实验

在前一年有过切身的十分糟糕的体验后,我自然不可能再采用原有的实验框架。同时,我们还需要兼顾到软件与硬件实验的兼容性。因此,宇翔牵头,我们设计了一套新的 HAL 框架(可见 Router-Lab),抽象出几个简单易用的接口(如发送一个包、接收一个包、查询 ARP 等),而隐藏不同底层(如 Linux、macOS、FPGA 等)的细节实现。同学们只需要基于这些接口,就可以实现转发与路由功能,而不需要关注 Linux API 等问题。基于这一接口,我们设计了以下的实验阶段:

  • 在线评测:此部分要求同学们实现几个简单的模块,如 IP 包解析、路由表查询、RIP 协议处理等,并通过在线评测平台进行黑盒测试,提供输入,输出与标准答案对比。这些是软件路由器中的重要组成部分,提交代码进行黑盒测试可以有效帮助同学们发现实现中的明显错误,当然也有助于我们进行代码查重和审阅。
  • 单人实验:这一部分实际上是转发引擎与路由部分的整合。我们提供了一份代码模板,基于 HAL 实现,其中包含了完整的注释与大量提示,告知同学们需要填入的内容(即第一部分的代码)。此部分的测试是在真实设备上运行的。
  • 组队实验:与原有类似,多人组队使用自己的路由软件在真实设备上进行功能与性能测试。

由于同学们需要在自己的设备以及下发的树莓派上进行测试(最终验收需要使用树莓派),除了框架本身的文档外,我们还事先撰写了大量的辅助性说明,包括树莓派的使用、Linux 各种网络工具的使用、详细的测试流程、评分标准等,保证同学们能够顺利地进行实验。同时,对于同学在课程群等途径提出的各类问题,我们也及时收录与更新在文档中。当然,不可避免地,框架中也会存在部分错误,我们也迅速地修复并告知同学进行更新。在学期末,最终我们得到了一份完善的实验文档,目前已经以在线形式发布在 这里

总体来看,对于我们重新设计的软件实验,七字班的同学们反响相当不错。由于黑盒测试能够帮助同学们解决大部分问题,因此最终将各部分集成起来工作量并不大。而在组队实验上,同学们能够发挥自己的动手能力,有同学选择了难度较高的五人组网,也有同学进行了环状组网的尝试,结果也非常成功。同时,由于我们设计的评分规则也较为友好,重在实现基础功能,几乎没有出现所谓的“内卷”现象,大家多是基于自己的兴趣进行的额外工作。不过这一年的验收依旧是手动进行的,助教的工作量非常大,也非常辛苦。

不可避免地,实验过程中也发生了一些令人遗憾的情况。我们在对第一阶段的黑盒代码进行查重时,发现并证实了几例抄袭现象,也有同学对于框架同样表示不适应。这些例子并不意味着我们的设计是失败的,但也提醒我们要继续加以改进,进一步降低无意义工作量,提高“性价比”;当然,防人之心不可无,我们也会继续严格进行查重,杜绝抄袭。

硬件实验

相比于比较顺利的软件实验,硬件实验的过程确实比较曲折。由于没有任何先例,并且硬件实验相比软件实验需要更大工作量和更扎实的技术,我们只能以摸着石头过河的形式来进行第一年的尝试。硬件实验组招募的工作从暑假前就开始了。直到开学前,我总共招募了五组,每组三人,再加已经完成的杰哥总共是 16 人。使用的实验板就是宇翔基于计原的 ThinPad 专门设计的,增加了四个网口,使用一块交换芯片来控制。

硬件实验事实上从开学前一周就开始了。整个学期中我们几乎每一周都会开会(除了三星期阶段),汇报当前进展,规划下一阶段工作。除了全老师、杰哥、宇翔之外,还有谭院士、wrj、松等同学也会来旁听我们的会议,徐明伟老师也参与过两次。下图中为硬件组的第一次会议,在东主楼 9-320 召开(桌上还有宇翔带来的一盒月饼),之后整个学期的会议都是在这里进行的。

first-meeting

第一阶段,各个组的主要工作是熟悉 FPGA,并将交换芯片驱动起来,能够在 FPGA 中实现解析 IP 包,实现简单的回送(loopback)等功能。由于大家对于相关技术经验不足,比如 AXI Stream 协议、流水线设计、FPGA 的时序分析等。各组出现了一系列比较同质的问题,但基本能够比较及时地解决。

第二阶段是硬件路由器的核心,即整个路由流水线的实现。其中最关键的部分是路由表的硬件实现,涉及存储与查询两个关键点。这一部分事实上是最为困难的部分,也直接决定了路由器的性能与配置灵活性等指标。所有组都不满足于最基本的线性查表,而是选择了高级的数据结构,如使用硬件实现 Trie、Cuckoo 哈希,以及著名的 Luleå 查表算法等。虽然我们没有要求使用硬件实现 RIP 路由协议,依然有的组完成了这一目标。作为并没有真正写过硬件路由器的助教,我对于同学们的能力深表佩服。我们在这一阶段完成后对同学们的转发和路由表实现进行了简单的性能测试和估计,大家的表现基本都很好。

第三阶段即“三星期”阶段。由于硬件路由器需要运行软件进行控制,因此需要实现一个 MIPS CPU。这一部分的实验内容,也将作为各个组的计原实验的内容。我们比较欣喜地看到,由于各个组事先已经对 FPGA 有了一定程度的熟悉,在计原实验方面也进行得比较顺利。

第四部分,要将 CPU 与硬件路由部分整合起来,并编写软件进行控制。这一部分理论上是工作量最小的部分,但实际上也是最艰难的部分。几乎每一组都有这样那样的 bug,从硬件到软件,从路由到转发,总是会出现莫名其妙的问题。预定的展示在十六周,展示前几天,各个组都进行了艰苦卓绝的调试工作,基本都熬过了通宵:9-320、8-500、2#308,到处都有调硬件路由器的同学的身影。我尽力帮助各个队伍解答遇到的问题,但最终的调试工作基本还是只能靠组员自身完成。杰哥尤其辛苦,陪着几个组一起熬夜。甚至还有组的成员为了调试,睡过了软工的考试,让我感到非常愧疚。

硬件实验(也称为计网联合实验)的验收要求相较软件组更为复杂,我们模拟了真实的网络场景和拓扑,进行了规模较大的压力测试,如最多向硬件路由器分发 5000 条路由,并同时从两个方向(四个网络接口)进行全双工的性能测试。杰哥为这些测试分别写了脚本,都能够在专门的测试服务器上一键运行。为了鼓励硬件组的开创性工作,我们的评分标准同样也是侧重于基础功能的。不过事实上,最终所有组都通过了测试,所有组的单路单工、大部分组的双路单工性能都能够打满 100Mbps 的线速,各组的小包转发性能也很接近理论值(148.8 Kpps)。总体来说,各组都非常出色地完成了任务。

在完成了实验后,我们同样也整理了实验过程中的文档,公开地发布在 这里。我们向各组收集了反馈,大家纷纷表示还是很有成就感很开心的,这让我们感到非常开心。但是大家也提到了一个不可忽视的问题:由于是第一年进行,学生、助教、老师都没有经验,最初对于进度的规划并不是非常科学,也没能避免重复造轮子的问题。这些在今后的实验设计中,也需要进一步地改进。

造路由器:3.0

转瞬间,2020 年秋季学期就要到来了。在今年疫情防控的新形势下,除了常规改进外,课程实验还不得不考虑更 多的因素,比如如何在线进行。

就在我着手写这篇文章的前两天,新的网原助教团队(包括 gyc、杰哥、谭院士、喵喵,还有最摸鱼的我)刚刚召开了一次线上会议,规划了今年的实验设计。总体来说,软件与硬件的两个方向不会改变。在软件实验上,我们在原有实验的计划开发一套在线实验平台,允许同学们提交自己的完整代码,在真实的环境中进行自动化的功能验证与性能测试,进一步减少助教的负担改善同学们的课程体验。在硬件实验方面,我们也将设计新的实验开发板,并提供一些现有的 IP 组件供同学们使用;同时也将基于去年各组的尝试,给出一些参考设计,以尽量减少大家走的弯路。

希望等三个月后,呈现给同学的网原实验,是另一副全新的面貌。

碎碎念

上面这些流水账,就是我亲身经历与参与,目前还在进行中的一次“课改”。到底什么是课改?在我的心目中,就是让课程变得更有趣、更贴近核心,能够让同学们从动手中获得乐趣、学习理论知识,不用浪费时间在环境配置或者毫无用处的细节中,也不会产生单纯为分数而“内卷”的趋势。

这些目标谁都会说,但落到实处又是何其困难呢!最重要的一点是,课程的教师需要有意识地推动与支持这些工作,即便他们不一定会亲自参与其中,但必须重视起来。此外,也需要有能力有责任心的助教来真正地实现,毕竟纸上谈兵永远是虚的。再者,任何改变都要经过实验,因此热心与有勇气当“小白鼠”的同学们也是必不可少的。我很感激,在网原课程的改革中,我们同时集齐了天时地利人和,成功地做出了一些微小的贡献。

然而,不少同学,尤其是从七字班开始,对“课改”的认识也多了一些别的含义,被人称作“课改先锋”似乎也多了一种讽刺的含义。在我看来,同学们口中的“课改”包含以下的含义:

  • 罔顾前置知识与同学水平,一味过高要求(甚至逐年提高),导致严重的“内卷”甚至抄袭现象。例子是计算机图形学课程。
  • 贸然增加新的内容,但未经测试与实验,浪费同学时间。例子是前年的网络原理课程。
  • 改变后的工作量过大,与课程回报(如学分)不符合。例子是去年的编译原理课程。
  • 放任助教胡乱操作,在课程考核中引入与课程目标不匹配的内容。例子是去年小学期的 Java 课程。

其中的第一条,事实上也反映了贵系不少课程的现状(比如,三星期真的能从零造机吗?我还是深表怀疑的),也是亟待解决的问题。而剩下两条,在各种课程中也屡见不鲜。这样的课程给同学们徒增了压力,即便能学到的东西客观上变多了,但学的过程确是痛苦的,很多人就转向选择了“集成”的道路。即使贵系的本科生能力真的很强,但真的需要通过这样的“课改”来体现吗?这样的本科生教育,真的是与贵系的世界排名相匹配的吗?我并不这么觉得。我们必须旗帜鲜明地反对这些不负责任的做法,为各个课程设计更为科学合理的教学与实验内容。

行胜于言,光喊口号是没有用的,真正需要的是行动。除了我参与的网原课程之外,我也很高兴看到有更多的课程正在摸索与改进的路上。但这还远远不够,贵系的课程体系需要的是系统而完整的改革。去年,系里也筹划成立自己的课程咨询委员会(虽然我不知道为啥我报名以后杳无音信,或许是疫情耽搁了),今年的学生会主席在竞选纲领中也提到了关于建立直接沟通与反映渠道的措施。积跬步才能至千里,我相信这些举措能帮助贵系能在真正的课改的路上越走越远。虽然我现在已经不再是贵系的本科生了,但在接下来的时间里,我还是会努力贡献自己的力量。还是用一句老套的话结尾吧:希望在大家的共同努力下,计算机系能够变得越来越好。