智能路由器开发指南

978-7-115-43085-4
作者: 张永智 李章明
译者:
编辑: 胡俊英

图书目录:

详情

本书介绍路由器的背景知识,各种嵌入式操作系统对比,选择openwrt进行讲述,并讲述路由器的标准规范。 1.Openwrt的编译及编译框架代码分析,以案例说明如何增加一个模块,以及嵌入式操作系统的包管理系统ipkg,和GDB调试代码。 2.智能设备的防火墙,路由,upnp,无线wifi,带宽控制及流量整形及各种管理功能。 3.OpenWrt各种开源组件模块代码接口及实现。

图书摘要

版权信息

书名:智能路由器开发指南

ISBN:978-7-115-43085-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    张永智 李章明

  责任编辑 胡俊英

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


OpenWrt是在实现路由器功能方面最受欢迎的开源软件之一。本书基于OpenWrt,详细介绍了智能路由器的开发。

本书共计15章,按照认识路由器的顺序进行编写,介绍了智能路由器、开发环境及编译分析、OpenWrt包管理系统、OpenWrt配置、软件开发、GDB调试、网络基础知识、路由器基础软件模块、常用软件模块、IP路由、DNS与DHCP、iptables防火墙、UCI防火墙、UPnP、网络测试及分析工具等。丰富的理论知识和代码示例可以帮助读者深入认识和理解OpenWrt技术,并能够提升开发水平和开发效率。

本书适合软件架构师、软件开发工程师、软件测试工程师以及计算机相关专业的学生阅读。读者通过阅读本书,不仅可以掌握OpenWrt技术,还能进一步提升自己的软件开发水平。


可以实现路由器功能的开源软件很多,为什么只有OpenWrt成功了?OpenWrt软件成功的关键在于3个方面:领导者、基础设施以及实现软件的技术。通常领导者是最重要的,因为领导者决定着社区的规则和技术方向,但是每个人都是独特的而且是无法复制的,因此通常无法借鉴。基础设施和实现软件的技术则是可以借鉴的。

OpenWrt社区采用六大基础设施工具支撑整个社区的运转,这六大基础设施工具分别是代码管理工具Git、邮件列表、自动构建工具buildbot、文档管理工具WiKi、Trac和技术论坛。

代码管理工具Git可以跟踪文件和目录的历史信息,包含4个W(Who、When、Why和What),即谁做了修改,什么时间做了修改,为什么修改以及修改的内容是什么。此外,Git还支持分布式代码仓库,适合开源软件项目的跨地域开发,这个工具可以让每个人看到代码的变化过程。OpenWrt经过了12年的发展,代码仓库还保留了最初的提交记录。

邮件列表是代码审查及代码提交集成的地方,开发人员将修改代码生成补丁发送给所有的邮件订阅者,每个人都可以进行代码评审,核心开发人员看到后会将代码集成到代码仓库中。邮件内容可以永久保存到邮件列表中。邮件列表和普通邮件的主要区别在于订阅机制和存档机制,每个人都可以自由订阅并查看历史邮件。

自动构建工具buildbot的核心是一个作业调度系统,它会将任务排队,当提供了任务所需的资源时,执行任务并报告结果。buildbot不仅仅支持持续集成及自动化测试,还支持应用程序的自动化部署和软件发布的管理。同时在多个平台开发时,通常最后的编译验证都是重复的,编译机器人(buildbot)将这一部分接管过来,每日自动下载代码进行编译验证,并将安装包上传到文件服务器上,如果编译失败则将用邮件通知感兴趣的人。

文档管理工具WiKi的特点是具有开放性,可以让任何参与人员非常方便地进行编辑、访问和搜索。大多数软件公司的软件文档均保存为二进制格式,在经过一段时间和人员流动之后,这些文档就会成为固定的资料,因为它会被遗落在某个角落而无法找到,而OpenWrt社区的软件开发文档和使用手册均保存到WiKi上。WiKi是一个协同写作和分享平台,允许所有人修改页面。WiKi使用简化的语法来代替复杂的HTML语言,降低了内容维护的门槛。

Trac是一个集成WiKi和问题跟踪管理系统的项目管理平台,可以帮助开发人员更好地管理软件开发过程,从而开发出高质量的软件。任何人都可以使用该系统来提交Bug并查询当前的进展。Trac采用面向进度的项目管理模型,采用里程碑的方式来组织开发。里程碑是以ticket(问题)来组织的,所有的问题都解决了,就到达了里程碑。但社区并不完全遵从这个标准,因为其开发人员全部是志愿者,通常到了一定时间会发布一个版本。

技术论坛是一个技术讨论的平台,每个注册用户均可发帖参与讨论。在开发过程中,每个新版本的说明通过该平台发布。

社区的运转是通过以上所述的六大基础设施工具来实现的,我们通过这些工具可以理解到,开源软件和社区的精髓在于其开放性,任何人员均可以通过网络自由地获取其信息并参与其中,这样可以激励每个人贡献出自己的力量,开发人员同时也从社区获得回报。开源社区的工具大多都是相同的,掌握这些工具可以帮助你深入了解开源社区和OpenWrt。

OpenWrt技术上成功的秘诀在于:统一编译框架、统一配置接口(Unified Configuration Interface,UCI)、开放的软件包管理系统及其读写分区系统、系统总线ubus和进程管理模块procd。

所有的这些功能并不是一次性设计出来的,而是随着时间的推进,根据用户和开发进展逐步发展起来的,每一种技术都有其独特的价值。

我从写下第一行C语言代码到现在已经有近20年了,实际从事嵌入式软件开发也有12年的时间了。由于在工作中经常会分析一些开源软件,因此在接触OpenWrt的过程中,我发现它的设计和实现思路非常好。但是在实际工作中往往会受到时间进度、项目研发人员的水平以及研发人员的更迭等因素的影响,导致软件架构存在种种不足或者过度设计的问题,但并没有很好的解决方法,开发进度一再延迟,因此有了写出本书的想法。

本书可以帮助各种嵌入式设备开发工程师对OpenWrt技术有一个清晰的认识,并能够帮助他们对开源的OpenWrt进行借鉴,提高软件开发水平。

OpenWrt始终在发展,本书中所提到的系统使用OpenWrt 12.09和OpenWrt 15.05.1来介绍,大部分不区分版本,如有区分,我会特别说明。

希望大家通过学习本书能够掌握OpenWrt各种技术的应用,同时在一定程度上可以参考OpenWrt的技术框架,使自己的职业技能有一个质的提高,从而加快企业产品项目的开发,提高开发效率。

本书的读者对象如下:

本书的结构是按照通常对路由器的认识顺序来编写的,全书内容共分为15章。

第1章对路由器进行了概述,主要介绍了OpenWrt的发展历史,OpenWrt的主要功能和几种开源路由器操作系统的对比。

第2章介绍了开发环境的搭建以及如何编译代码,并对常用编译脚本和编译选项进行了分析,也讲述了VirtualBox虚拟网络环境的设置。

第3章介绍了OPKG软件包管理系统。OPKG用于管理软件包的下载、安装、升级、卸载和查询等,并处理软件包的依赖关系。

第4章介绍了统一配置接口,OpenWrt数千个软件均采取该该配置接口,它包含3个部分:配置文件、访问API和命令行工具。

第5章介绍了如何在OpenWrt中新增一个软件包,提供了一个简易模块供参考,还介绍了OpenWrt的软件启动机制和补丁文件的格式以及补丁工具的使用。

第6章介绍了GDB的使用。首先介绍了如何使用GDB启动程序调试,然后介绍了在GDB中如何设置断点以及查看程序的运行状态,最后介绍了使用GDB对运行中程序的执行流程进行修改,这样能以最快的速度定位问题所在。

第7章介绍了TCP/IP网络模型,从下到上依次讲述了数据链路层、IP层和传输层协议,并以一个综合案例来讲述报文的网络处理流程。

第8章介绍了OpenWrt路由器最近几年新增的核心模块,包括系统总线ubus、网络设备和接口管理模块netifd、进程管理模块procd等。

第9章介绍了在各种领域内的常用软件模块,例如CWMP用于远程网络管理,SSH用于用户登录,QoS用于保障服务质量,uHTTPd用于提供Web服务,SMTP用于发送邮件,NTP用于网络时间协议,PPPoE用于网络拨号服务等。

第10章介绍了路由功能,包括普通的路由及源地址路由和组播路由。

第11章介绍了域名系统和动态主机服务,并讲述了动态域名更新系统。

第12章和第13章讲述防火墙。首先介绍了iptables,它是用来设置、维护和检查Linux内核的防火墙IP报文过滤规则和网络地址转换规则。Netfilter是在内核中依据规则对报文进行处理。UCI防火墙设置了一个易用的防火墙模型来对防火墙进行管理。

第14章介绍了UPnP标准框架和UPnP工作流程,并以增加端口映射为例讲述了Internet网关如何实现广域网访问局域网提供的服务。

第15章首先介绍了网络调试和诊断的“瑞士军刀”NetCat,它可以用来进行传输文件,扫描端口等;其次介绍网络流量分析工具TcpDump,它可以输出网卡接口上的网络报文,也可以根据选项将报文保存为文件。

大家可以根据自己的需求选择阅读的侧重点,不过我还是建议你首先通读前8章,再根据自己的需求来阅读其他章节,这样可以对OpenWrt架构上有一个清晰的认识,还可以对架构中的技术有一个简单的对比。

感谢本书的第二作者李章明,他负责UPnP一章和Wi-Fi一节的编写。另外,还要感谢程晶对本书的贡献。

感谢本书编辑胡俊英对本书的仔细审读,她耐心地帮助修改了很多文字错误,使本书的写作质量有了很大的提高。

感谢OpenWrt开发社区,没有迈克·贝克和格里·罗泽马创立的OpenWrt社区,这本书就不能完成。本书的很多资料都参考了社区邮件列表、WiKi以及代码,感谢OpenWrt社区所有人员的贡献。同时,本书有一些素材来自Linux社区,也感谢林纳斯和他所创建的Linux。

最后感谢在工作和生活中曾经帮助过我的所有人,感谢你们,正是因为有了你们,才有了本书的面世。

虽然花了很多时间和精力去核对书中的文字、代码和图片,但因为时间仓促和水平有限,书中仍难免会有一些错误和纰漏,如果大家发现什么问题,恳请反馈给我,相关信息可发到我的邮箱zyz323@163.com。由于时间和技术水平有限,可能不能及时回答大家的所有问题,但我会定期将问题整理并放在网上。

如果大家对本书有任何疑问或想与我探讨OpenWrt和防火墙相关的技术,可以访问我的个人网站,网址为http://openwrt.bjbook.net。大家在编译的过程中如果遇到下载软件包失败,可以在我的镜像地址进行下载,网址为http://openwrt.bjbook.net/download。另外,我还提供了OpenWrt代码搜索引擎,网址为http://openwrt.bjbook.net/source,大家可以在学习过程中在该地址浏览并搜索代码。


近年来,智能路由器领域越来越火,但这方面的开发资料却很少,并且不成体系。因此,本书针对智能路由器领域的开发进行了详细介绍,也可以用于指导其他智能家庭设备的开发。

接入网络的家庭用户终端越来越多,路由器控制越来越复杂,因此需要一个智能网关来管理家庭的设备。另外,这个智能网关直接连在互联网上,需要隔离家庭网和互联网的连接,因此需要带有防火墙功能。智能路由器就像智能手机一样,其定义并非其字面含义所表现出的那样(可以智能地选择路由),而是其带有可扩展功能,用户自己可以安装软件进行扩充。传统的路由器仅可以升级厂商自己的操作系统版本,且未提供扩展接口。

公共场所无线接入是一个大的需求,因此无线接入市场越来越大。接入费用谁来负担?一个思路是商家提供接入费用,另外一个思路是通过广告来分担接入费用。OpenWrt就是这样一个智能路由器操作系统,它可以提供Web认证等成熟的功能给这类用户进行选择。

OpenWrt是一个针对嵌入式设备的Linux发行版,有非常高的可扩展性,可以非常容易地从零开始构建出全功能的智能路由或服务器设备。

OpenWrt是一个嵌入式设备的Linux发行版,以GPL许可协议发行。

OpenWrt项目始于2004年1月,其第一个版本采用了LinkSys的源码。在LinkSys的代码收费后,改为采用正式发布的Linux内核来集成,并将OpenWrt完全模块化,不断推出补丁和驱动。OpenWrt的主要特点在于其高扩展性,并且文件系统可写,开发者无需在每一次修改后完全重新编译,只要编译自己的软件包即可,这样就加快了开发的进度。另外OpenWrt提供了SDK,每个运行软件均能够以SDK来进行编译,以软件包形式进行安装和卸载。其主要特点有如下几个。

OpenWrt历史

OpenWrt在2004年由迈克·贝克和格里·罗泽马创立,到今天为止已经发展了12个年头了。OpenWrt定期发布版本,发行版本以代码线和日期作为版本号。它的第一个正式版为Kamikaze 7.06,第二个正式版本为Backfire 10.03。

Backfire

2010年4月7日,OpenWrt发布Backfire 10.03正式版。相对上一个稳定版本,其内核升级为Linux 2.6.32,使用了新的Web服务器uhttpd,支持了一些新的平台硬件(如TP-Link TL-WR1043ND等),增加了机器可读的版本信息/etc/openwrt_release。

2011年12月21日,OpenWrt发布了Backfire 10.03.1正式版。期间,OpenWrt发布了6个RC版本。这一版本将内核升级为Linux 2.6.32.16,修正了很多BUG,并增加了对TP-Link、TL-MR3420等的支持。

Attitude Adjustment

2013年4月25日,OpenWrt发布12.09正式版。相对于Backfire版本,Attitude Adjustment将内核更新至Linux 3.3,改进了并行编译支持;使用密文存储密码;各种防火墙功能增强;无线驱动更新及稳定性增强;新平台支持ramips、bcm2708(树莓派)等;发布镜像文件中支持网桥防火墙。

Barrier Breaker

2014年7月31日,OpenWrt发布14.07正式版。相对于Attitude Adjustment版本,内核升级到3.10,增加了原生IPv6支持,文件系统增强;UCI配置增强,支持测试配置和回滚最近工作状态机制,增加配置更改按需触发服务重启机制;网络功能增强,可以支持动态防火墙规则,增加网桥的多播传输到单播传输的转换等。

Chaos Calmer

OpenWrt于2015年9月11日发布15.05正式版。Chaos Calmer中间发布了3个RC版本。相对于 Barrier Breaker,其内核升级到了3.18;网络功能增强,添加了多个3G/4G路由器支持,改进了IPv6等功能增强,增加了自管理网络的支持;各种平台和驱动设备的支持,例如飞思卡尔i.MX23/28系列等各种品牌,增加了树莓派的支持。这个版本在64位平台的VirtualBox下运行还存在问题。

表1-1 OpenWrt最近历史版本

版  本

内核版本

发布日期

发布代码地址

Kamikaze 8.09.2

2.6.26

2010-01-10

svn://svn.openwrt.org/openwrt/tags/8.09.2

Backfire 10.03

2.6.32

2010-04-07

svn://svn.openwrt.org/openwrt tags/backfire_10.03

Backfire 10.03.1

2.6.32

2011-12-21

svn://svn.openwrt.org/openwrt/tags/backfire_10.03.1

Attitude Adjustment 12.09

3.3.8

2013-04-25

svn://svn.openwrt.org/openwrt/tags/attitude_adjustment_12.09

Barrier Breaker 14.07

3.10

2014-10-02

svn://svn.openwrt.org/openwrt/branches/barrier_breaker -r42625

Chaos Calmer 15.05

3.18

2015-09-11

svn://svn.openwrt.org/openwrt/branches/chaos_calmer -r46767

注1:对于各种硬件平台内核版本可能不一致。因为每个平台的内核版本在独立的文件中定义(target/linux/<平台>/ Makefile:LINUX_VERSION),在Barrier Breaker及以后的发布版中,内核版本定义变量改为KERNEL_PATCHVER。

注2:最新的两个发布版本没有创建标签,需要根据SVN版本号来下载代码。

注3:2016年3月,OpenWrt已经从SVN代码仓库切换到Git代码仓库了,因此不再支持SVN。

路由器的典型架构划分为管理平面、控制平面和数据转发平面,如图1-1所示。

图1-1 OpenWrt架构

管理平面是提供网络管理人员使用UCI、Web、SNMP和TR069等方式来管理路由器,以及执行这些管理功能所需的配置命令等,管理平面提供了控制平面正常运行所需的配置参数。

控制平面用于控制和管理所有网络协议的运行,例如ARP、DHCP、DNS及组播协议的管理和控制。

转发平面用于处理和转发不同网络接口上各种类型的数据,例如进行网络地址转换、路由、ACL等。典型路由器在数据转发平面占用最多的系统资源。转发平面应用控制平面提供的路由信息对数据报文的接收,进行网络地址转换,查找路由表,从出接口发出报文等工作。如果找不到路由,则发送ICMP不可达消息,我们可以使用route命令查看路由转发数据库。路由器的3平面划分仅是逻辑意义上的功能划分,在实际的功能模块并没有完全区分。

OpenWrt是一个基于Linux的智能路由器操作系统。用户可以自定义安装各种应用软件。OpenWrt提供各种功能插件,使用户可以自定义安装来管理路由器;默认内置了一些基础功能。其主要功能可以分为3个部分:网络功能、系统管理功能和状态监控功能。以下各节将分别详细介绍。

网络功能是路由器的核心功能,如图1-2所示。“Network”标签高亮显示表示正在使用网络管理功能,下一层标签是静态路由管理。主要包含以下几个功能。

图1-2 静态路由管理功能

系统管理是路由器除了网络管理之外的其他管理功能,如图1-3所示。系统管理主要包含以下几个功能。

图1-3 软件管理功能

状态监控主要用于监控路由器的当前状态,并且只能查看当前的路由器状态。如图1-4所示,“Status”标签高亮显示表示正在使用状态监控功能,下一层标签是“Overview”,用于查看路由器的系统状态和内存占用情况。状态监控主要包含以下几个功能。

图1-4 状态监控功能

此外OpenWrt还为开发人员提供了一些开发支撑功能以及代码调试工具等,例如:

开源嵌入式操作系统,其字面意思有3点,即开放源代码、嵌入式和操作系统,但实质上其流行的关键在于其可扩展性。

开源是指开放源代码,是指软件在开放源代码许可证下发布软件,保障软件用户自由查看软件源代码的权利。这同时也保障了用于修改、复制和再分发的权利,但仍需遵守开源许可协议中的一些约束。开放源代码不仅仅指开放源代码的软件,也是一种软件开发模式。

“许可证”是指授权条款,是指使用、修改、复制和再分发的条款和条件的法律文件。最常见的开源许可证有几种:GNU GPL许可证、Apache许可证等。许可证通常也称为许可协议。

“Apache许可证”是著名非盈利开源组织Apache采用的协议。该协议鼓励代码共享和尊重原作者的著作权,同样允许代码修改、再发布(作为开源或商业软件)。获得该许可证需要满足以下4个条件。

Apache许可协议是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布和销售。

GPL是著名的开源软件Linux采用的许可协议。GPL许可证和Apache许可证等鼓励代码重用的许可很不一样。GPL许可证的出发点是代码的开源使用和引用/修改/衍生代码的开源使用,但不允许修改和衍生的代码做为闭源的商业软件发布和销售。这也就是为什么我们能用使用各种商业软件公司发布各种Linux系统以及他们的源代码。

GPL许可证主要有以下两个特点。

嵌入式系统,是指嵌入到硬件系统内部,为特定应用功能而设计的专用软件系统。与个人计算机的通用操作系统不同,嵌入式系统通常只针对特殊的用途。因此可以对它进行优化,并裁剪到最小。现在通用的硬件系统发展非常迅速,因此出现了在通用硬件系统上的嵌入式操作系统。目前在嵌入式领域广泛使用的操作系统有:Linux、Windows Embedded和VxWorks等。

基于Linux内核也衍生出很多操作系统发行版本。Linux基金会负责Linux内核的开发、发行及维护工作。对于各个基于Linux内核的发行版本来说,可以选择某款Linux内核长期支持版(LFS)作为自己操作系统的内核。如果对主干版本进行修改,可以将修改反馈给上游。等到下次升级内核版本时,就会得到包含自己修改代码的内核了。

相对于专有的闭源操作系统,如Windows和Mac,开源Linux操作系统最大的特点就是其可扩展性非常好。但如果从头开始构建操作系统,则会因为使用者的技术水平、软件包的依赖关系、软件包的版本等出现很多不可预知的兼容性问题。这就要求个人和企业用户在选择操作系统时需要注意根据自己的实际情况来选择,这也是目前使用开源Linux操作系统较为困难的最主要原因。还好有些技术社区组织已经针对某些领域做了一些特殊的定制和优化。例如,针对防火墙的操作系统有IPFire;针对智能路由器领域通常使用的嵌入式操作系统有Tomato和OpenWrt等;针对个人桌面领域操作系统有Ubuntu和Fedora等;针对手机有Android和Firefox OS等。它们均是基于Linux内核的操作系统。

Android是谷歌研发的一款智能终端操作系统,是一种基于Linux的开放源代码的操作系统,主要使用于移动设备 ,如智能手机、平板计算机等,也应用于智能电视等。它由谷歌公司和开放手机联盟领导开发。Android操作系统最初由安迪·鲁宾开发,最初目的是用于数码相机的操作系统。2005年8月谷歌全资收购了Android操作系统。2007年11月,谷歌与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟,共同研发改良Android系统。随后谷歌以Apache开源许可协议的授权方式发布了Android的源代码,Android以JAVA层封装了系统层提供给应用开发者统一的API接口。第一部Android智能手机发布于2008年10月。目前,Android已逐渐扩展到平板计算机及其他领域,如电视、智能手表、数码相机和游戏机等。2015年,Android以85%的市场占有率占据移动操作系统市场之首。表1-2所示为OpenWrt和Android的比较。

Android操作系统已经演化为一个移动设备开发平台,其软件层次大体上分为4层,即操作系统内核、中间层、应用程序框架层和应用程序。应用程序框架层为应用程序开发者提供了功能强大的API,包括图形显示的各种组件,如视图、列表、文本框、按钮以及嵌入式的Web浏览器等。

表1-2 OpenWrt和Android操作系统的比较

 

Android

OpenWrt

内核

Linux内核

Linux内核

许可协议

Apache2.0

GNU License

使用场景

面向终端用户,手持设备。用户接口采用JAVA提供图形用户界面GUI

服务器、家庭路由器等,用户接口默认为UCI命令行提供,也支持通过Web方式来管理

开发主导模式

由谷歌公司主导开发

由OpenWrt.org社区主导,社区由个人组成,更开放

1.Tomato WRT

Tomato是一种小型的LinkSys的WRT54G是博通路由器的另外一种可选的替换固件。它有一个新的易于使用的GUI,一个新的带宽监控工具,更为先进的服务质量(QoS)和访问限制,使用新的无线功能,如WDS和无线客户端模式,P2P最大连接上的限制,允许你运行自定义脚本或者Telnet、SSH登录到路由器,在做各种各样的事情。例如重新编程的SES/AOSS按钮,添加无线站点调查来查看你的Wi-Fi邻居,等等。Tomato有以下特点。

它有一些明显缺点,例如仅有发布说明,没有详细修改记录;最近不再更新等。

2.DD-WRT

DD-WRT是一个基于Linux的开源固件,适合各种各样的无线路由器和嵌入式操作系统。其重点在于提供最简单的处理,同时在各种硬件平台的框架内支持大量的功能。它是另外一款路由器代码发行版,从2006年2月开始开发,没有分支稳定版本。代码库包含所有的代码,包含SVN信息共大约18GB。其代码始终在更新,2015年10月也有代码提交。有一个缺点是SVN上包含所有的代码,没有分支及标签,无法区分稳定版本。用在私人用途,DD-WRT是免费的,如果用在商业用途则需要获取软件许可。

表1-3所示为开源路由器各种发行版本的对比。

表1-3 开源路由器各种发行版本对比

路由器

Tomato Wrt

DD-WRT

OpenWrt

网站

www.polarcloud.com/tomato

www.dd-wrt.com

www.openwrt.org

历史

未知

2006年2月开始开发

2004年2月开始,平均两年发布一个稳定版本

代码管理

git://repo.or.cz/tomato.git,仅提供自己修改的代码。仅有一个可用版本

svn://svn.dd-wrt.com/DD-WRT,包含所有的代码,没有分支及标签,无法确定哪个是稳定版本

svn://svn.openwrt.org/openwrt/,diff文件进行提交管理。不同版本使用分支来管理

问题跟踪管理

采用trac管理缺陷

编译

● 代码压缩包35.4MB,仅提  供必要的代码,其他代码  需要自己手动下载
● 在编译时需要特别注意  设置环境变量,例如:  Export LC_ALL=en_US.   UTF-8
● 编译时代码有时间依赖,  复制时需要保留时间,使  用命令cp -a

● 包含所有代码,一次下载完  成后,编译构建时不用联网

● 构建时需要联网,编译时根  据选择自动下载第三方代码
● 支持编译SDK

活跃程度

Tomato1.28最后更新日期为2010-06-29

一直在更新,2015-10-6也有提交

一直在更新,2015-10-06也有提交,最新稳定版本为15.05

文档

资料较少

自己网站英文资料较多

中文资料较多

缺点

X86平台不支持,已经不再更新

无法确定稳定版本;商业版本需要获取软件许可

无明显缺点

注1:最后更新日期为2015年10月6日统计。

3.比较结果

OpenWrt相对于其他几个无线路由器操作系统来说,版本管理最为规范,社区最活跃,是最适合选为基础来进一步开发的。当然,OpenWrt也适合初学者来学习。本书中采用了OpenWrt来论述智能路由器的开发过程,非常有利于初学者快速上手。


如果你想从事智能路由器OpenWrt开发,首先必须掌握如何编译OpenWrt。本章将从搭建环境,到编译代码,再到安装部署运行以及VirtualBox虚拟网络环境的搭建,一步一步地教你如何进入到OpenWrt大门。

OpenWrt是一个针对嵌入式设备的Linux发行版。OpenWrt提供了非常方便的开发环境,使用流行的Linux操作系统Ubuntu即可搭建好编译环境。OpenWrt有非常多的平台适应性,可以运行在ARM/MIPS/X86平台上,因此我们的研发网络部署也可以在虚拟机VirtualBox上运行(这样可以降低研发中的硬件成本),待软件开发成熟后再在实际环境中进行运行。因此最后我们也会讲解VirtualBox的网络环境设置。

首先安装Linux操作系统Ubuntu 14.4。个人机器多为Windows 操作系统,为了方便使用及节省硬件资源,我们采用虚拟机VirtualBox来安装编译软件环境。如果是实体机安装Linux操作系统,则可略过安装虚拟机这一步。硬件设备只需要一台连接互联网的计算机。软件从互联网下载。建议使用VirtualBox虚拟机来搭建编译环境及开发调试。

下载和安装VirtualBox和ubuntu 14.04.3。下载地址分别为:

VirtualBox是一个跨平台的虚拟化应用程序。这意味着什么?第一,是它可以安装在你已存在的Intel或AMD兼容的机器上,无论是它运行Windows、Mac、Linux还是Solaris操作系统。第二,它可以扩展你已存在的计算机系统的能力,你可以同时运行多个操作系统(在多个虚拟机内部),例如,可以在你的Mac机上运行Windows和Linux,在Linux服务器上运行Windows Server 2008,在Windows系统上运行Linux等等,这些都在你的VirtualBox应用程序中。你可以安装运行很多虚拟机器,唯一的限制是磁盘空间和内存。

虚拟机软件VirtualBox完成安装后,在VirtualBox软件中新建计算机,并分配20GB左右的硬盘空间。然后在虚拟机中安装Ubuntu操作系统。Ubuntu操作系统及编译环境需要5GB左右硬盘空间,OpenWrt编译根据选择软件包的多少不同,编译所需空间大小不同。我这里编译完成需要7.1GB的硬盘空间,一般我们会同时编译至少两个版本进行,因此建议虚拟机预留20GB以上的磁盘空间。

安装增强功能

虚拟机和主机之间如何传递内容和文件?这就需要“安装增强功能”来在虚拟机和宿主机之间共享剪切板和共享文件目录。可在虚拟机软件上进行以下设置。

设置完成后在Ubuntu系统下进行自动挂载设置。在/etc/fstab增加如下一行:

  share      /mnt      vboxsf  rw 0    0

这样宿主机的共享目录share就可以挂载在虚拟机的/mnt目录下,虚拟机和宿主机均可以对该目录进行操作。这个就可以将编译完成后的文件从虚拟机中传递出来。

另外一种方式是通过telnet或SSH或串口来登录到Ubuntu上进行控制,使用FTP等工具来进行文件传输。

Ubuntu采用APT(Advanced Packaging Tool)来管理软件包安装、更新、升级及删除等。APT系统的配置文件为/etc/apt/sources.list和/etc/apt/sources.list.d目录。sources.list文件格式如下:

deb uri distribution [component1] [component2] [...]

首先第一列为类型,可选类型为deb或deb-src,deb表示为二进制安装包;deb-src表示源代码包。第二列为URI地址,例如,为通过HTTP访问的统一资源定位符。第三列用于指定一个发布版,例如,为trusty表示14.4发布版。最后一列为各个组件标识。

设置Ubuntu配置升级及更新路径的文件为/etc/apt/sources.list,修改为国内网易的镜像服务器,这样下载速度会比较快。为了防止修改错误,修改之前应事先进行备份,并增加以下内容(参考http://mirrors.163.com/.help/ubuntu.html)。

deb http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse

OpenWrt选择了一种自动化的方式来生成固件:编译环境检查、生成交叉编译链、下载代码包、打补丁、编译及生成固件,一切均从源代码开始,没有隐藏任何细节。我们先来安装代码管理工具Subversion及编译工具。首先输入以下命令进行更新:

sudo apt-get update

这条命令用于更新Ubuntu软件仓库中软件包的索引文件。软件仓库的地址是由/ etc/apt/sources.list文件指定的。更新之后安装编译工具,编译工具安装命令如下:

sudo apt-get install subversion
sudo apt-get install g++ flex patch
sudo apt-get install libncurses5-dev zlib1g-dev
sudo apt-get install git-core
sudo apt-get install libssl-dev
sudo apt-get install gawk
sudo apt-get install xz-util

(1)Subversion 是一个版本管理系统,可以跟踪文件和目录的历史信息,包含4个W(Who、When、Why和What),即谁做了修改、何时做了修改、为什么修改以及修改的内容。它像CVS一样保存数据源的单份复制,称为仓库,仓库包含了项目中文件的所有历史信息。

Subversion允许对源代码进行并行修改及管理,知名的Apache社区就采用Subversion来管理代码,其中最重要的是代码管理客户端工具,缩写为svn。这里我们只用到其下载代码功能。

Subversion采用集中式版本控制系统,其特点是其高可靠性,可用作一种有价值的数据安全的避风港;它的模型使用简单;它支持各种各样的用户和项目需求的能力,包括从小型单人到大型企业的管理需求,因此大多数软件研发公司均采用Subversion作为其代码管理工具。如果个人在Windows平台上使用,推荐采用“VisualSVN Server”作为服务器,其可视化安装及管理非常便于用户使用。

(2)g++是GNU工程的C/C++编译工具,用于将C语言及C++语言编译为动态链接库或二进制可执行程序。它对代码进行预处理、编译、汇编和链接。通过命令选项可以控制整个编译过程。

(3)FLEX(The Fast Lexical Analyzer)一个快速词法分析工具。

(4)patch是将diff文件应用到原始文件的工具,用于在程序开发过程中提交代码,是应用差异文件的工具。这些差异文件由diff程序按行产生。

(5)libncurses5-dev用于屏幕终端控制。这个包中包括运行那些使用ncurses编译的程序所必须的共享库,同样包含开发使用的头文件、静态库和开发使用的链接文件、文档等。

(6)zlib1g-dev是压缩及解压缩开发库。包含头文件、静态库、开发示例和文档等。

(7)git-core是设计用于大型工程的分布式版本管理工具,是另外一种代码管理工具软件。它的每一个仓库都完全保存了整个代码历史,可以脱离网络而使用,首先应用于Linux社区。这里用于下载一些以git管理的软件包。

(8)libssl-dev 是openssl开发库,用于加密解密、计算哈希和数据签名等。

(9)gawk是GNU工程实现的AWK语言工具,是文本模式扫描和处理的工具。

(10)xz-util是xz格式的压缩工具集。它有非常高的压缩比率,并且更快更容易解压缩。

OpenWrt社区同时使用Subversion和Git两种工具来管理代码。Subversion管理代码非常灵活,通常会创建tags、branches和trunk共3个目录管理代码。trunk目录用来保存开发的主线,一般最新的功能均在trunk目录提交。 branches目录存放分支,用于功能开发完成之后创建分支、修改BUG及发布版本使用,或者某些功能开发分支。tags目录保存标签复制,一个标签是一个项目在某一时间点的“快照”,用来给发布版本的代码创建快照,以便多数开发人员基于这个版本进行开发修改及测试使用,一般永远不再修改。

OpenWrt也是采用了Subversion的推荐目录配置,除此之外还增加了docs、feeds和packages这3个目录,我们采用svn list命令来查看代码仓库共有6个目录。

zhang@zhang-laptop:~$ svn list svn://svn.openwrt.org/openwrt/
branches/
docs/
feeds/
packages/
tags/
trunk/

(1)分支(branches)用于功能开发完成之后创建分支、修改bug及发布版本使用,或者某些功能开发分支。OpenWrt社区每隔两年左右会创建一个分支用于发布特定版本,最新的代码线分支为chaos_calmer。社区在2015年9月12日发布了15.05版本,但未使用SVN创建标签。最近3个分支信息地址请参见表2-1。

(2)docs保存文档,使用SVN来查看修改历史信息,得出最后修改时间为2007-10-24,现在OpenWrt已经不再使用这个目录。

(3)feeds保存一些额外扩展的软件包,最后修改时间为2012-11-14,也逐渐不再使用,其中代码已转到使用Git仓库来管理。地址为https://github.com/openwrt

(4)packages保存OpenWrt基础软件包,会被经常用到。最后修改时间为2015-06-01。

(5)标签(tags)下为发布版本代码,最近稳定版本标签有backfire_10.03.1,attitude_adjustment_12.09。以后版本未创建标签。

(6)主干(trunk)始终是最新的代码,OpenWrt社区将最新的代码线命名为“Designated Driver”。最新代码包含实验性质的代码,可能会碰到编译或运行的问题,建议新手不要采用。

注:以上修改时间均为2015年10月12日查询得出,OpenWrt的外围代码已经逐渐转到github提供的Git托管空间上。

表2-1 OpenWrt版本对比表

分支

chaos calmer 15.05(CC)

Barrier Breaker 14.07(BB)

Attitude Adjustment 12.09(AA)

内核

Linux kernel 3.18.21

Linux kernel 3.10

Linux kernel 3.3

SVN代码地址

svn://svn.openwrt.org/openwrt/branches/chaos_calmer

svn://svn.openwrt.org/openwrt/branches/barrier_breaker

svn://svn.openwrt.org/openwrt/branches/attitude_adjustment

Git代码地址

git://git.openwrt.org/15.05/openwrt.git

git://git.openwrt.org/14.07/openwrt.git

git://git.openwrt.org/12.09/openwrt.git

其他主要修改

● 增加大量的3G/4G调制  解调器支持

● Netfliter性能增强

● 网络栈多核支持

● 支持只能队列管理Qos等

● DNSSEC增强支持

● 增加自管理网络支持等

● 增加procd 新的preinit、init、热  拔插及事件通知机制

● 原生IPv6支持

● 文件系统增强

● UCI配置增强:支持测试配置和  回滚最近工作状态机制,增加配置  更改按需触发服务重启机制

● 网络功能增强:例如,支持动态  防火墙规则,增加网桥的多播传输  到单播传输的转换,等等

● 增加并行编译支持

● 使用密文密码

● 各种防火墙功能增强

● 无线驱动更新及稳定  性增强

● 新平台支持:ramips,  bcm2708 (Raspberry   Pi)等等

● 发布镜像文件中支持  网桥防火墙

发布版本

svn://svn.openwrt.org/openwrt/branches/chaos_calmer -r46767

svn://svn.openwrt.org/openwrt/branches/barrier_breaker -r42625

svn://svn.openwrt.org/openwrt/tags/attitude_adjustment_12.09

我们选择“Chaos Calmer”的发布代码进行编译,因此使用目录“cc”下载代码。OpenWrt在2016年3月将代码库由Subversion彻底转换为GIT,因此我们使用git命令来下载代码,下载命令如下所示:

git clone git://git.openwrt.org/15.05/openwrt.git cc

现在代码和编译环境准备好了,我们可以开始配置和编译了。我们进入代码目录cc下进行编译。通常分3步,第1步首先更新和安装所有可选的软件包。

./scripts/feeds update 更新最新的包定义

./scripts/feeds install -a 安装所有的包

feeds命令将安装扩展代码包编译选项。如果不运行该命令,在menuconfig配置时将没有选择这些扩展包的机会。

第2步进行编译配置。输入“make defconfig”,在这里会检查所需的编译工具是否齐备,并生成默认的编译配置文件“.config”。

输入“make menuconfig”后系统将进入配置工具选项菜单来配置编译固件的内容,如图2-1所示。配置选项和Linux内核的编译配置非常相似,使用上下左右箭头按键来在编译选项菜单上导航。按Enter键进入子菜单,连续两次按下Esc键返回上一级菜单,输入问号键将获取帮助信息,顶层配置选项含义如表2-2所示。OpenWrt提供模块化选择编译,每一个模块通常都有3个选项[Y|N|M]可供选择,输入Y该模块将包含在固件中;输入M将作为一个模块来编译,可以后续再进行安装;输入N将不编译该模块。还有一些是单选选项菜单,按空格键进行选择,再次按空格键则取消选择。

另外还有一些高级功能可以输入字符串进行配置。例如下载文件夹路径设置,可以不使用编译系统默认的源代码下载目录dl,输入系统路径“/opt/dl”来设置,这样在很多人使用同一服务器来编译代码时,不用多次下载相同的代码文件。

为了便于开发及调试,我们选择x86平台进行编译,并选择自己所需要的软件包,例如网络开发中最常用的抓包工具TcpDump、代码调试工具GDB和Web管理界面luCI等。

图2-1 OpenWrt配置选项菜单

表2-2 OpenWrt配置选项含义

编译配置选项

含  义

Target System (x86)

目标平台,例如一般Windows系统均为X86系统架构,嵌入式路由器通常有ARM、MIPS系统和博通系统等

Target Images

编译生成物控制,根据目标平台不同选项不同。例如根文件系统格式、内核空间大小和是否生成VirtualBox映像文件等

Global build settings

全局编译设置,例如是否打开内核namespace等

Advanced configuration option (for developers)

针对开发人员的高级配置选项,包含设置下载文件目录、编译log和外部编译工具目录等

Build the OpenWrt SDK

是否生成OpenWrt的软件开发包,这样就可以离开OpenWrt整体环境而进行模块编译和增加功能

Image configuration

固件生成的软件包模块,即是否打开feed.conf中的各个模块

Base system

OpenWrt基本系统。包括OpenWrt的基本文件系统base-files模块、实现DHCP和DNS代理的dnsmasq模块、软件包管理模块opkg、通用库ubox、系统总线ubus和防火墙firewall,等等

Development

开发包,例如调试工具gdb,代码检查和调优工具valgrind等

Firmware

各种硬件平台固件

Kernel modules

内核模块,运行在操作系统内部。例如加密模块、各种USB驱动和netfilter扩展模块等

Languages

不是国际化中的多语言支持模块,而是软件开发语言模块,现在可选的有perl和lua

libraries

一些动态链接库。例如XML语言解析库libxml2,和内核进行通信的 libnfnetlink库,压缩和解压缩算法库zlib,微型数据库libsqlite3等

luCI

OpenWrt管理UI模块,例如动态DNS管理模块luci-app-ddns、防火墙管理模块luci-app-firewall和QOS管理模块luci-app-qos等

Mail

邮件传输客户端模块,例如msmtp软件包

MultiMedia

多媒体模块,例如ffmpeg

Network

网络功能,OpenWrt最具特色的核心模块。例如防火墙、路由、VPN和文件传输等

Sound

音频模块

Utilities

一些不常用的实用工具模块

第3步,输入make命令就可以开始编译。编译时首先从Internet上下载软件模块代码,因为OpenWrt仅有编译及配置指令,各种依赖的代码包在上游网站及代码仓库里面。OpenWrt网站也有第三方的代码包镜像,在上游网站不可用时将使用OpenWrt自己的服务器地址,下载地址为http://downloads.openwrt.org/sources/。 根据下载速度和选择软件包的数量多少,编译所占时间不同,大约需要3小时以上。编译完成后的二进制安装文件在bin/x86下,各种可选软件安装包在packages目录下。

make V=s 可以输出编译过程中每一步的执行动作,出错后显示详细的错误信息。

make -j2 使用2个线程进行并行编译,这样编译速度将大大加快。

编译过程首先检查编译环境,然后编译host工具,再编译编译工具链,最后编译目标平台的各个软件包。编译make进入各个模块进行编译时,首先下载代码压缩包,然后解压缩,并打补丁,再根据设置选项来生成Makefile,最后根据生成的Makefile进行编译和安装。在编译时需要连接互联网,因为OpenWrt采用补丁包方式来管理代码,第三方的代码不放在它自己的代码库中,仅在编译前从第三方服务器下载。

编译过程如图2-2所示,我使用了两个进程来编译,除了下载之外花费3小时左右编译完成。

~/cc$ make -j2
make[1] world
 make[2] tools/install
 make[2] package/cleanup
 make[3] -C tools/patch compile
 make[3] -C tools/sstrip compile
 make[3] -C tools/make-ext4fs compile
 make[3] -C tools/firmware-utils compile
 make[3] -C tools/patch-image compile
 make[3] -C tools/flock compile
 make[3] -C tools/sstrip install
 make[3] -C tools/make-ext4fs install
 make[3] -C tools/firmware-utils install
 make[3] -C tools/patch-image install
 make[3] -C tools/flock install
 make[3] -C tools/patch install
 make[3] -C tools/sed compile
 make[3] -C tools/m4 compile
 make[3] -C tools/xz compile
 make[3] -C tools/yaffs2 compile
 make[3] -C tools/cmake compile
 make[3] -C tools/scons compile
 make[3] -C tools/lzma compile
 make[3] -C tools/sed install
 make[3] -C tools/m4 install
 make[3] -C tools/pkg-config compile
 make[3] -C tools/xz install
 make[3] -C tools/mkimage compile
 make[3] -C tools/yaffs2 install
 make[3] -C tools/scons install
 make[3] -C tools/lzma install
 make[3] -C tools/squashfs4 compile
 make[3] -C tools/autoconf compile
 make[3] -C tools/pkg-config install
 make[3] -C tools/mkimage install
 make[3] -C tools/squashfs4 install
 make[3] -C tools/autoconf install
 make[3] -C tools/automake compile
 make[3] -C tools/missing-macros compile
 make[3] -C tools/automake install
 make[3] -C tools/missing-macros install
 make[3] -C tools/libtool compile
 make[3] -C tools/libtool install
 make[3] -C tools/gmp compile
 make[3] -C tools/libelf compile
 make[3] -C tools/flex compile
 make[3] -C tools/mklibs compile
 make[3] -C tools/e2fsprogs compile
 make[3] -C tools/mm-macros compile
 make[3] -C tools/cmake install
 make[3] -C tools/gengetopt compile
 make[3] -C tools/patchelf compile
 make[3] -C tools/gmp install
 make[3] -C tools/libelf install
 make[3] -C tools/flex install
 make[3] -C tools/mklibs install
 make[3] -C tools/e2fsprogs install
 make[3] -C tools/mm-macros install
 make[3] -C tools/patchelf install
 make[3] -C tools/qemu compile
 make[3] -C tools/mpfr compile
 make[3] -C tools/bison compile
 make[3] -C tools/mtd-utils compile
 make[3] -C tools/gengetopt install
 make[3] -C tools/qemu install
 make[3] -C tools/mpfr install
 make[3] -C tools/mtd-utils install
 make[3] -C tools/mpc compile
 make[3] -C tools/mpc install
 make[3] -C tools/bison install
 make[3] -C tools/findutils compile
 make[3] -C tools/bc compile
 make[3] -C tools/bc install
 make[3] -C tools/findutils install
 make[3] -C tools/quilt compile
 make[3] -C tools/padjffs2 compile
 make[3] -C tools/padjffs2 install
 make[3] -C tools/quilt install
 make[2] toolchain/install
 make[3] -C toolchain/gdb prepare
 make[3] -C toolchain/binutils prepare
 make[3] -C toolchain/gcc/minimal prepare
 make[3] -C toolchain/kernel-headers prepare
 make[3] -C toolchain/uClibc/headers prepare
 make[3] -C toolchain/gcc/initial prepare
 make[3] -C toolchain/gdb compile
 make[3] -C toolchain/binutils compile
 make[3] -C toolchain/kernel-headers compile
 make[3] -C toolchain/uClibc prepare
 make[3] -C toolchain/gcc/final prepare
 make[3] -C toolchain/uClibc/utils prepare
 make[3] -C toolchain/binutils install
 make[3] -C toolchain/gcc/minimal compile
 make[3] -C toolchain/gdb install
 make[3] -C toolchain/gcc/minimal install
 make[3] -C toolchain/kernel-headers install
 make[3] -C toolchain/uClibc/headers compile
 make[3] -C toolchain/uClibc/headers install
 make[3] -C toolchain/gcc/initial compile
 make[3] -C toolchain/gcc/initial install
 make[3] -C toolchain/uClibc compile
 make[3] -C toolchain/uClibc install
 make[3] -C toolchain/gcc/final compile
 make[3] -C toolchain/gcc/final install
 make[3] -C toolchain/uClibc/utils compile
 make[3] -C toolchain/uClibc/utils install
 make[2] target/compile
 make[3] -C target/linux compile
 make[2] package/compile
 make[3] -C package/system/opkg host-compile
 make[3] -C package/libs/toolchain compile
 make[3] -C package/libs/ncurses host-compile
 make[3] -C package/system/usign host-compile
 make[3] -C package/boot/grub2 host-compile
 make[3] -C package/firmware/linux-firmware compile
 make[3] -C package/network/services/dropbear compile
 make[3] -C package/libs/libpcap compile
 make[3] -C package/network/utils/linux-atm compile
 make[3] -C package/network/utils/resolveip compile
 make[3] -C package/libs/ocf-crypto-headers compile
 make[3] -C package/utils/busybox compile
 make[3] -C package/utils/mkelfimage compile
 make[3] -C package/libs/libnl-tiny compile
 make[3] -C package/libs/libjson-c compile
 make[3] -C package/utils/lua compile
 make[3] -C package/libs/lzo compile
 make[3] -C package/libs/zlib compile
 make[3] -C package/libs/ncurses compile
 make[3] -C package/kernel/linux compile
 make[3] -C package/libs/openssl compile
 make[3] -C package/libs/libubox compile
 make[3] -C package/utils/util-linux compile
 make[3] -C package/utils/jsonfilter compile
 make[3] -C package/system/usign compile
 make[3] -C package/boot/grub2 compile
 make[3] -C package/network/utils/iptables compile
 make[3] -C package/network/ipv6/odhcp6c compile
 make[3] -C package/network/services/dnsmasq compile
 make[3] -C package/network/services/ppp compile
 make[3] -C package/system/mtd compile
 make[3] -C package/system/opkg compile
 make[3] -C package/system/ubus compile
 make[3] -C package/system/uci compile
 make[3] -C package/utils/ubi-utils compile
 make[3] -C package/network/config/firewall compile
 make[3] -C package/network/services/odhcpd compile
 make[3] -C package/network/config/netifd compile
 make[3] -C package/system/ubox compile
 make[3] -C package/system/procd compile
 make[3] -C package/system/fstools compile
 make[3] -C package/base-files compile
 make[2] package/install
 make[3] package/preconfig
 make[2] target/install
 make[3] -C target/linux install
 make[2] package/index

图2-2 OpenWrt编译过程

编译生成物位于代码目录下“bin/x86”目录下。如果想单独编译一个模块可以输入以下命令进行编译,以TcpDump模块为例:

以上编译命令都可以添加“V=s”来查看详细编译过程。还有很多全局编译命令含义如下:

OpenWrt代码有8个固定的顶层目录及6个编译时创建的临时目录,顶层的固定目录含义如表2-3所示。

表2-3 顶层目录含义

目  录

含  义

config

编译选项配置文件,包含全局编译设置、开发人员编译设置、目标文件格式设置和内核编译设置等4部分

docs

文档目录

include

包含准备环境脚本、下载补丁脚本、编译Makefile以及编译指令等

package

各种功能的软件包,软件包仅包含Makefile和修改补丁及配置文件。其中Makefile包含源代码真正的地址及MD5值。OpenWrt社区的修改代码以补丁包形式管理,package只保存一些常用的软件包

scripts

包含准备环境脚本、下载补丁脚本、编译Makefile以及编译指令等

target

指的是嵌入式平台,包括特定嵌入式平台的内容

toolchain

编译器和C库等,例如包含编译工具gcc和glibc库

tools

通用命令,用来生成固件的辅助工具,如打补丁工具patch、编译工具make及squashfs等

目录config是编译配置文件目录,是OpenWrt 15.05的新增目录,是将一些编译选项配置文件分类放在这里,包含全局编译设置、开发人员编译设置、目标文件格式设置和内核编译设置等4部分。

目录include和scripts包含各种脚本和Makefile。目录target是指目标嵌入式设备,针对不同的平台有不同的特性代码。针对这些平台特性,“target/linux”目录下按照平台进行目录划分,里面包括了针对各种平台标准内核的补丁及特殊配置等。目录tools和toolchain包含了一些通用命令,用来生成固件、编译器和C语言链接库。目录docs在编译时不需要,用于存放开发文档。目录package则用于存放各种必要的软件包。

编译生成结果会储存在以下3个目录下:“build_dir/host”是一个临时目录,用来储存不依赖于目标平台的工具;“build_dir/toolchain-<arch>”用来储存依赖于指定平台的编译工具链;“staging_dir/toolchain-<arch>”是编译工具链的最终安装位置。通常我们不需要改动编译链目录下的任何东西,除非要更新编译工具版本等。

在OpenWrt固件中,几乎所有东西都是软件包(package),可以编译为以“.ipk”结尾的安装包,这样就可以很方便地安装、升级和卸载了。注意,扩展软件包不是在主分支中维护的,但是可以使用软件包编译扩展机制(feeds)来进行扩展安装。这些包能够扩展基本系统的功能,只需要将它们链接进入主干。之后,这些软件包将会显示在编译配置菜单中。

编译工具链、目标平台的软件包等需要下载的文件都放在dl目录下。目标平台和软件包两部分都需要“build_dir/<arch>”作为编译的临时目录,并且会将目录staging_dir作为编译的临时安装目录,最终的生成文件保存在目录bin下。

目录feeds用于保存扩展软件包,可以使用软件包编译扩展机制来进行扩展安装。这些包能够扩展基本系统的功能,只需要将它们链接进入编译主目录的package目录下。之后,这些软件包将会显示在配置菜单中。编译后生成6个临时目录,其含义如表2-4所示。

表2-4 OpenWrt编译生成目录含义

目  录

含  义

dl

下载软件代码包临时目录。编译前,将原始的软件代码包下载到该目录

feeds

扩展软件包目录。将一些不常用的软件包放在其他代码库中,通过feed机制可以自定义下载及配置

bin

编译完成后的最终成果目录。例如安装映像文件及ipk安装包

build_dir

编译中间文件目录。例如生成的.o文件

staging_dir

编译安装目录。文件安装到这里,并由这里的文件生成最终的编译成果

log

如果打开了针对开发人员log选项,则将编译log保存在这个目录下,否则该目录并不会创建

目录scripts为编译工具脚本文件,例如patch-kernel.sh封装了patch命令,在编译时,首先将patches目录下的所有补丁文件打上,并且判断如果打补丁失败将退出编译过程。download.pl为下载源代码的工具脚本,封装下载工具wget的选项以及设置从哪里下载。表2-5所示为典型编译脚本功能。目录include用于保存各种makefile文件。

表2-5 典型编译脚本功能

脚 本 文 件

含  义

scripts/download.pl

下载编译软件包源代码

scripts/patch-kernel.sh

打补丁脚本,并且判断如果打补丁失败将退出编译过程

scripts/feeds

收集扩展软件包的工具,用于下载和安装编译扩展软件包工具

scripts/diffconfig.sh

收集和默认配置不同之处的工具

scripts/kconfig.pl

处理内核配置

scripts/deptest.sh

自动OpenWrt的软件包依赖项检查

scripts/metadata.pl

检查metadata

scritps/rstrp.sh

丢弃目标文件中的符号,这样就将执行文件和动态库变小

scripts/timestamp.pl

生成文件的时间戳

scripts/ipkg-make-index.sh

生成软件包的ipkg索引,在使用opkg安装软件时使用

scripts/ext-toolchain.sh

工具链

scripts/strip-kmod.sh

删除内核模块的符号信息,使文件变小

OpenWrt在构建时首先下载代码,就是使用scripts/download.pl脚本进行下载,使用方法如下:

Syntax: ./download.pl <target dir> <filename> <md5sum> [<mirror> ...]

<target dir>为下载之后的保存位置,下载代码通常均保存在dl目录下。

<filename> 待下载的文件名。

<md5sum>下载内容的MD5,用于校验下载文件是否正确。

<mirror>为可选的参数,是下载文件的镜像地址,可以有多个地址,优先选择第一个,如果下载失败则顺序选择后面的地址。

该程序由Perl语言开发出来,代码并不复杂。代码首先进行初始条件检查,判断参数是否足够,至少需要3个参数分别为下载文件保存位置、下载文件名及下载内容MD5值。 接着从命令行参数中顺序读取数据,并赋值给局部变量,最后判断md5sum或md5工具是否存在,如果不存在提示工具不存在后退出。

紧接着调用localmirrors()函数读取本地的源码镜像地址,我们可以在企业内部创建自己的代码镜像服务器,然后将镜像地址放在“scripts/localmirrors”文件中,这样我们就不用每次编译时都从互联网上去下载了。例如我这里修改如下:

zhang@zhang-laptop:~/cc/scripts$ cat localmirrors 
http://192.168.1.106:8080/openwrt/
http://mirror.bjtu.edu.cn/gnu/

紧接着遍历命令行并将代码中的镜像地址加到备选镜像中。最后使用while循环进行下载,如果下载完成就对下载文件的MD5进行对比,如果MD5值一致则退出循环,否则进入下一个镜像地址进行下载。下载成功后调用cleanup()函数来清理临时变量。

这个下载功能最重要的接口是我们可以通过“scripts/localmirrors”文件自定义软件包下载地址,方便开发人员进行设置。

最近有很多iPhone/Android编译工具爆出后门问题,就是因为使用其他第三方镜像地址文件来下载编译工具,但没有对下载的软件内容进行MD5值对比,从而导致编译的应用程序感染后门。OpenWrt的下载检查机制从源头上解决了这类问题。在我开发OpenWrt时也发现了下载的一些内容被感染的问题,但检查机制丢弃了不正确的内容,从下一个的镜像网站上继续下载。

OpenWrt的代码包中大多均有patches目录。下载代码包完成后进行打补丁,采用的就是patck-kernel.sh脚本。脚本的第一个参数为编译代码目录,第二个为补丁目录,调用脚本形式举例如下。

../scripts/patch-kernel.sh iproute2-3.3.0 ../package/iproute2/patches/

执行流程如下。

(1)首先进行参数赋值,第一个参数为代码目录,第二个参数为补丁目录。

(2)第二步判定代码目录和补丁目录是否存在,如果不存在则提示错误并退出。

(3)遍历补丁文件,根据后缀判断补丁文件类型。

(4)调用patch命令应用补丁。

(5)检查补丁应用是否正确,如果存在“*.rej”文件表示出现错误,返回“1”并退出。

(6)最后检查如果存在应用补丁后的备份文件,则删除备份文件。

传统的Linux操作系统在编译某一个软件的时候,会检查其依赖软件及头文件是否存在,如果没有安装,则会报缺少头文件或缺少链接库等错误,编译将退出。这种机制使得开发者在编译一个软件之前,需要查找该软件所需的依赖库及头文件,并手动去安装这些软件。有时候碰到比较娇贵的软件时,嵌套式的安装依赖文件,会使得开发者头昏脑胀。OpenWrt通过引入feeds机制,很好地解决了这个问题。

feeds是OpenWrt开发所需要的软件包套件的工具及更新地址集合,这些软件包通过一个统一的接口地址进行访问。这样用户可以不用关心扩展包的存储位置,可以减少扩展软件包和核心代码部分的耦合。它由两部分组成,即扩展包位置配置文件feeds.conf.default和脚本工具feeds。目前在配置文件中保存最重要的扩展软件包集合有以下4个。

当我们下载了OpenWrt对应源码之后,进行如下操作:

$> ./scripts/feeds update –a
$> ./scripts/feeds install -a

上述操作,就是利用feeds提供的接口将OpenWrt所需的全部扩展软件包进行下载并安装。在更新时,需要能够访问互联网。在下载之前可以通过查看“feeds.conf.default”文件,来检查哪些文件需要包含在编译环境中。feeds工具用法如下。

zhang@zhang-VirtualBox:~/cc$ ./scripts/feeds 
Usage: ./scripts/feeds <command> [options]

Commands:
    list [options]: List feeds, their content and revisions (if installed)
    Options:
        -n :              List of feed names.
        -s :              List of feed names and their URL.
        -r <feedname>:  List packages of specified feed.
        -d <delimiter>: Use specified delimiter to distinguish rows (default: spaces)

    install [options] <package>: Install a package
    Options:
        -a :   Install all packages from all feeds or from the specified feed using the -p option.
        -p <feedname>: Prefer this feed when installing packages.
        -d <y|m|n>:    Set default for newly installed packages.
        -f :    Install will be forced even if the package exists in core OpenWrt (override)

    search [options] <substring>: Search for a package
    Options:
        -r <feedname>: Only search in this feed

    uninstall -a|<package>: Uninstall a package
    Options:
        -a :           Uninstalls all packages.

    update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf .
    Options:
      -a : Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated.
      -i :  Recreate the index only. No feed update from repository is performed.

    clean:   Remove downloaded/generated files.

update:下载在feeds.conf或feeds.conf.default文件中的软件包列表并创建索引。-a表示更新所有的软件包。只有更新后才能进行后面的操作。

list:从创建的索引文件“feed.index”中读取列表并显示。只有进行更新之后才能查看列表。

install:安装软件包以及它所依赖的软件包,从feeds目录安装到package目录,即在“package/feeds”目录创建软件包的软链接。只有安装之后,在后面执行“make menuconfig”时,才可以对相关软件包是否编译进行选择。

例如安装luci-app-firewall:

zhang@zhang-laptop:~/openwrt$ ./scripts/feeds install luci-app-firewall
Installing package 'luci-app-firewall' from luci
Installing package 'luci-base' from luci
Installing package 'luci-lib-nixio' from luci
Installing package 'luci-lib-ip' from luci

search:按照给定的字符串来查找软件包,需要传入一个字符串参数。

uninstall:卸载软件包,但它没有处理依赖关系,仅仅删除本软件包的软链接

clean:删除update命令下载和生成的索引文件,但不会删除install创建的链接。

feeds代码处理过程是这样的:这个命令首先读取并解析feeds.conf配置文件,然后执行相应的命令,例如install时,将安装应用程序包和它所有直接或间接依赖的所有软件包。安装时将创建一个符号链接,从packages/feeds/$feed_name/$package_name指向feeds/$feed_name/$package_name, 这样在“make menuconfig”时,feeds的软件包就可以被处理到,就可以选择编译了。例如luci-app-firewall指向feeds/luci/applications/luci- app-firewall:

zhang@zhang-laptop:~/openwrt$ ls package/feeds/luci/luci-app-firewall -alht
lrwxrwxrwx 1 zhang zhang 50 2015-07-04 15:17 package/feeds/luci/luci- app-firewall -> ../../../feeds/luci/applications/luci-app-firewall

用一句话来说,编译扩展安装过程就是将feeds目录下的软件包链接到packages/feeds对应目录下。可使用的feeds列表配置为feeds.conf或者feeds.conf.default。优先选择feeds.conf文件,这个文件包含了扩展安装源列表,每一行由3部分组成,包含feed方法、feed 名字和feed源。下面是一个扩展安装源配置文件的例子。

src-git luci https://github.com/openwrt/luci.git;for-15.05
src-git routing https://github.com/openwrt-routing/packages.git;for- 15.05
src-git telephony https://github.com/openwrt/telephony.git;for-15.05
src-gitmanagement https://github.com/openwrt-management/packages.git; for-15.05

我们可以修改该文件使编译时从自己指定的位置进行下载。主要支持feed方法的类型有以下3种。

首先将编译完成的安装文件openwrt-x86-generic-combined-ext4.img.gz解压缩,然后将解压后的img文件复制出来并转换为VirtualBox支持的vdi文件。

zhang@zhang-laptop:~/cc/bin/x86$ gunzip openwrt-x86-generic-combined- ext4.img.gz  
zhang@zhang-laptop:~/cc/bin/x86$ cp openwrt-x86-generic-combined-ext4. img /mnt/

将img文件转换为Virtualbox支持的vdi文件的转换命令为:

C:\Program Files\Oracle\VirtualBox>VBoxManage.exe convertfromraw -format VDI D:\ubuntu\openwrt-x86-generic-combined-ext4.img d:\ubuntu\ openwrt15.vdi
Converting from raw image file="D:\ubuntu\openwrt-x86-generic-combined- ext4.img"
 to file="d:\ubuntu\openwrt15.vdi"...
Creating dynamic image with size 55050240 bytes (53MB)...

使用VirtualBox来安装OpenWrt时,先在Virtualbox中选择新建虚拟计算机,类型为Linux,版本选择“Linux 2.6/3.x/4.x(32-bit)”,如图2-3所示。

图2-3 选择操作系统类型

紧接着选择内存的大小,采用默认设置256MB即可。然后单击“下一步”继续进行设置。如图2-4所示。

最后选择“使用已有的虚拟硬盘文件(U)”。然后在硬盘上选择编译出来的openwrt- x86-generic-combined-ext4.vdi文件或者转换成功的openwrt15.vdi。单击“创建”,这时路由器虚拟计算机就创建完成了。如图2-5所示。

图2-4 选择内存大小

图2-5 虚拟硬盘选择

创建完成后,选择设置并且设置两个网卡接口,接口类型分别为“网络地址转换”和“Host Only”。如果在之前没有添加虚拟硬盘,可以在“设置→存储→控制器→控制器(IDE)”中添加虚拟硬盘,选择“openwrt15.vdi”即可。这时我们就可以启动OpenWrt了。启动完成后按Enter键即可登录到OpenWrt的终端中。注意某些版本在未启用串口时会启动失败。如图2-6所示,在图形用户界面下的“设置→串口→端口1”,在启用串口选项上打勾,即可成功启动。

图2-6 串口设置

通常默认编译安装的OpenWrt路由器固件没有Web管理界面,因此需要我们通过opkg命令进行安装。

opkg update
opkg install luci
/etc/init.d/uhttpd enable
/etc/init.d/uhttpd start
/etc/init.d/firewall stop

默认会不会打开HTTP管理服务?端口为80,并且防火墙会默认打开,通过外网不能访问HTTP管理页面服务。需要将防火墙关闭。

在VirtualBox中的网卡设置中NAT启动tcp端口转发,将主机端口的80端口转到子系统的80端口,这样就可以通过http://127.0.0.1来访问路由器管理页面。

1.虚拟机和Window 10之间不能访问

请查看Window 10的防火墙设置,关闭Windows 10的防火墙来解决这个问题。

2.编译grub2模块出错,提示下载失败

直接使用wget工具或浏览器来下载,如果确实下载不成功,可以替换为之前grub-2.0.0的版本来进行编译。

3.提示opkg编译失败,使用Git下载失败

使用wget直接下载即可。如果下载还失败,可以使用迅雷等下载工具来下载,如果还不行则可以替换为较低的版本来编译。

4.提示cyassl-3.2.0.zip下载失败

使用http://fossies.org/linux/misc/cyassl-3.2.0.zip,下载后放在dl目录下即可。

5.mpc-1.0.2.tar.gz下载失败

建议将北京交通大学的GNU开源镜像加入到下载列表中,这样可以加快下载速度,并且可以在国外网站下载失败时使用国内资源。加入到“scripts/localmirrors”中,或者加入到download.pl每一类的第一行,即分别为第155行及173行。

push @mirrors, "http://mirror.bjtu.edu.cn/gnu/$1";
push @mirrors, "http://mirror.bjtu.edu.cn/gnome/$1";

大部分问题为在特定网络条件下下载资源失败的问题,在其他网络条件下没有该类问题,可以更换其他网络进行下载。

6.启动失败

某些版本的OpenWrt在虚拟机下启动失败,可以将虚拟机“串口1”启用,避免OpenWrt判断串口时失败。

此外,某些系统(如Windows8或Windows10)下的VirtualBox安装15.05不能启动,但安装较低版本12.09和10.3.1可以启动。

VirtualBox提供了7种网络接入模式,最常用的网络模式有以下4种。

1.网络地址转换(Network Address Translation,NAT)模式

如果你想使用虚拟机浏览网站、下载文件和查看邮件,这个模式最适合。NAT模式是实现虚拟机上网的最简单的方式。

2.桥接模式

VirtualBox连接你的真实网卡并和真实网卡直接交换数据,这是高级网络需求,例如在虚拟机中直接对外提供服务。相当于一个网卡有两个MAC地址。

3.内部网络模式

这个模式通常用于创建不同的软件虚拟网络,这些网络可以为不同的虚拟机所使用。但这些网络不能被宿主机或外部网络所应用。

4.仅主机网络模式(Host-Only)

这个模式应用于创建包含主机和一组虚拟机之间的网络,不需要主机的物理网卡,而是创建一个虚拟网卡以提供虚拟机和宿主机之间的网络互联。

如果你想使用虚拟机浏览网站、下载文件和查看邮件,这个模式最适合。NAT模式是实现虚拟机上网的最简单的方式,不需要经过特别配置。虚拟机不占用局域网的IP地址,仅分配到连接宿主机的内部地址,如果需要上网就要经过地址转换到宿主机再去访问网络。你可以这样理解:虚拟机就相当于是家庭网络内部的一台计算机,主机就是家庭网络外部的计算机,VirtualBox就是运行中的路由器,虚拟机访问网络的所有数据都通过路由器,家庭网络内的计算机不真实存在于网络中,宿主机与网络中的任何机器都不能查看和访问到虚拟机。这种分割也最大程度地保证了虚拟机的安全。

虚拟机默认可以通过网卡访问到宿主机和网络。网络地址转换模式的最大劣势在于,虚拟机在外部网络不可访问,除非你设置端口转发规则。宿主机无法通过网络访问到虚拟机,是因为虚拟机的IP地址是私有地址,宿主机不会路由到虚拟机中。通过设置端口转发规则,宿主机就可以访问到虚拟机中的服务,例如,宿主机需要访问虚拟机中的HTTP服务,设置为80端口转发,如图2-7所示,就可以将访问宿主机127.0.0.1的请求转发到虚拟机中的80端口上。

图2-7 虚拟机端口映射设置

实际上虚拟机分配到的IP地址通常为10.0.2.15,网关地址为10.0.2.2。虚拟机将设置一个默认路由指向下一跳地址为网关地址。NAT方案的特点是,默认情况下,虚拟机即获取到IP地址,可以通过这个IP地址访问宿主机和网络。宿主机经过设置之后也可以访问虚拟机上的服务。

NAT使用受到一些限制,主要有以下3个限制。

(1)ICMP协议限制。一些经常使用的网络调试工具(如ping和traceroute等)使用ICMP发送和接收消息。ICMP支持在VirtualBox已经增加,但其他工具可能不支持。

(2)接收UDP广播不可用。虚拟机为了节省资源不接收广播。

(3)协议例如GRE不支持。TCP及UDP以外的协议不支持。这意味着一些VPN产品(例如微软的PPTP)不能使用。仅使用TCP及UDP的VPN产品可以使用。这个限制不影响标准网络的使用。

桥接网络就相当于两个网卡组织为两个交换机接口,虚拟机和宿主机同时接在一个交换机的两个网口上。它就是通过主机网卡,架设了一条桥,直接连入到网络中。因此,它使得虚拟机能被分配到一个网络中独立的IP地址,所有网络功能完全和在网络中的真实机器一样。宿主机通过网卡发送数据给虚拟机,接收数据也通过这个网卡。这意味着你可以设置虚拟机和网络之间的路由或桥接。

通过图形用户接口“设置→网络”,设置“启动网络连接”,从“连接方式”下拉框中选择“桥接网卡”,然后选择自己系统的网卡即可。注意不要选择无线网卡,因为大多数无线网卡无法设置为混杂模式。

该模式存在以下缺点:需要接入网络并分到网络中的IP地址才能相互访问;如果网络中对IP及MAC地址接入有限制,则无法分配到IP地址,不能工作。

内部网络模式在和外部通信方面和桥接网络模式相似,不过这个外部仅限于同一个主机上连接同一个内部网络的其他虚拟机。虚拟机与宿主机和外网完全断开,只实现虚拟机与虚拟机之间的网络连接模式。

在技术上内部网络模式所能完成的工作,桥接网络也可以完成,但内部网络有安全优势。在桥接网络模式中,所有流量均通过宿主机的物理接口,通过包探测器可以记录所有的网络流量。因此如果你想让自己的数据保密,就不能使用桥接模式。

内部网络在设置时会自动创建,没有也不需要中心配置。每一个内部网络根据名称来区分。一旦有一个以上的活动虚拟网卡具有相同的内部网络ID,VirtualBox支持驱动程序会自动将它们接到同一个网络交换机上。VirtualBox支持驱动程序实现了一个完整的以太网交换机,包含支持广播/组播帧和混杂模式等。通过以下方式进行设置:通过图形用户接口“设置→网络”设置“启动网络连接”,从“连接方式”下拉框中选择“内部网络”。

仅主机(Host-Only)网络模式被认为是桥接网络和内部网络模式的混合体:与桥接网络相似,虚拟机和宿主机可以互相通信,宿主机和它们通过一个物理以太网交换机连接。同样,作为内部网络,不需要存在一个物理网卡;虚拟机无法跟外面世界通信,因为它们没有连接到一个物理网络接口上。

使用这个模式,VirtualBox将在宿主机上创建一个新的软件接口。就像一个本地回环接口一样,VirtualBox在主机中模拟出一张专供虚拟机使用的网桥,所有虚拟机都是连接到该网桥上的。当实体机运行多个虚拟应用程序时,例如一个虚拟机运行Web服务,另外一个运行数据库,两个虚拟机就可以通过仅主机适配器网络相互进行通信,Web服务器再通过网桥对外提供服务,数据库服务器不能被外部访问,数据不会泄露到外部。通过以下方式进行设置:通过图形用户接口“设置→网络”设置“启动网络连接”,从“连接方式”下拉框中选择“仅主机Host-only适配器”。

虚拟机默认分到的IP为192.168.56.101,主机的IP地址为192.168.56.1,两者可以通过IP相互访问。其他虚拟机默认都分到192.168.56.X的IP地址,虚拟机之间通过IP可以相互访问。和主机本身的网卡是否启用没有关系。

每一种网络模式均有自己的使用场景,对VirtualBox的4种网络设置的比较如表2-6所示。

表2-6 VirtualBox网络设置比较

特  点

NAT

桥  接

内 部 网 络

仅 主 机

宿主机和虚拟机是否相互访问

默认不能访问虚拟机

默认可以相互访问,需要网卡外接交换机上认为网卡工作才能相关访问

不能相互访问,彼此不属于同一个网络,无法相互访问

可以相互访问

和其他虚拟机关系

完全相互独立,不能相互访问

同一桥接网卡可以访问

可以相互访问,有一个前提是在设置网络时,两台虚拟机设置同一网络名称

可以相互访问

和其他主机关系

其他主机不能访问

对等关系,可以相互访问

不能相互访问

不能相互访问

如图2-8所示,将虚拟机1当作智能路由器,安装OpenWrt软件,并创建两个网卡,NAT网卡用于连接互联网,内部网络用于连接家庭网个人计算机。虚拟机2当作家庭PC使用,自动从OpenWrt网关处分配IP地址。这样我们就可以模拟常见的路由器场景,例如上网、防火墙和DNS代理等功能,任何家庭网的数据流量均通过路由器来转发到外部网络。

图2-8 家庭路由器验证环境


相关图书

电子硬件工程师入职图解手册  硬件知识篇
电子硬件工程师入职图解手册 硬件知识篇
Altium Designer 22电路设计与仿真实战从入门到精通
Altium Designer 22电路设计与仿真实战从入门到精通
RISC-V体系结构编程与实践
RISC-V体系结构编程与实践
龙芯嵌入式系统原理与应用开发
龙芯嵌入式系统原理与应用开发
龙芯嵌入式系统软硬件平台设计
龙芯嵌入式系统软硬件平台设计
GPU编程实战(基于Python和CUDA)
GPU编程实战(基于Python和CUDA)

相关文章

相关课程