Linux 和下一代互联网
我们的 Diffserv 实现相对简单,但突出了 Linux 的许多优势和灵活性,我们认为这在以互联网为中心的计算时代尤为重要。为了更完整地描述与“区分服务”相关的几种技术,我们包含了一些关于 Diffserv 的目的和结构的背景材料,以及其他更复杂的 Diffserv 环境实现的亮点,这些实现得益于 Linux 内核的复杂性。
尽管我们实现的 Diffserv 环境相当简单,但我们认为它也因以下原因而有趣
我们使用一种方法,允许从“网络管理工作站”即时按需重新配置整个网络。这是我们环境的关键组成部分,因为我们的主要目标之一是使用实时应用程序,为非技术受众简洁地演示启用 Diffserv 网络的“前后”效果。
我们开发此环境的部分支持来自主要的区域贝尔运营公司 (RBOC) 之一,以及国家科学基金会通过对现有 NSF 拨款的“本科生研究经验” (REU) 补充。因此,系统配置、软件和大部分架构主要由我们大学的本科工程专业学生开发。
我们的演示环境已在两次大型区域会议上用于现场动手演示:东南大学研究协会 (SURA) 应用研讨会(1999 年 9 月)和贝尔南方科学与技术 创新展示(1999 年 10 月)。
互联网中“服务区分”(或服务质量,QoS)的关键在于路由器处理(或可以轻松修改为处理)具有不同传输要求的多种流量类别的方式。“Diffserv”是指一种实现此类功能的方法,该方法正在(通过构建互联网标准的常用方法)被定义为与全球互联网的范围和风格广泛兼容(参见资源 1)。
Diffserv 的架构可以从互联网“转发节点”(路由器)中相对简单的功能单元来看待(参见资源 2)。Diffserv 的简单性很重要,因为从理论上讲,它有可能在不同类型的互联网流量之间提供粗略的区分,而无需对当前互联网的配置进行根本性更改。
Diffserv 描述的功能单元之一是一组“每跳行为” (PHB)。PHB 背后的想法是让每个路由器根据嵌入在数据包报头中的“标签”轻松快速地将数据包分类到不同的输出队列中。方形标签进入“方形”队列。圆形标签进入“圆形”队列。“方形”队列中的数据包的处理方式与“圆形”队列中的数据包不同。
该方案的工作方式与航空公司允许乘客托运行李或登机的方式非常相似:“头等舱”先走,“经济舱”其次,“候补”最后,如果有足够的空间。Diffserv 中还有其他功能单元,通常称为 数据包分类 和 流量调节。与航空公司的类比一致,数据包分类类似于购买机票类型(或根据某些规则为您分配机票类型)的行为,而流量调节就像航班取消或延误时一群乘客经历的干扰(例如,颠簸和改道)。对于我们的演示环境,我们主要关注 PHB 以及网络拥塞时特定流量分类之间的差异。换句话说,我们主要问以下问题:“头等舱 真的 比经济舱好吗?”以及“我如何判断?”
在 Diffserv 中,“头等舱”的名称称为 加速转发 (EF)(参见资源 3)。EF 的想法是通过确保沿传输路径的每个路由器内的数据包排队最少来模拟“虚拟租用线路”。因此,EF 类希望提供关于延迟和抖动的 保证,这对于等时数据流(即视频和音频)非常重要。这是我们认为 Diffserv 的弱点之一。由于明确设计为无法区分单个流量流,因此 聚合 EF 流会获得所需的待遇。除非 极少 有 EF 流,否则无法对单个流做出“硬性承诺”。许多出版物都指出了这一结果,并感到遗憾(参见资源 4)。EF 分类的效果是单个流中后续数据包之间存在大量抖动。由于 Diffserv 的既定目标和架构,最大限度减少这些影响的唯一方法是实行“过度配置”,即只有一小部分可用带宽提供给 EF 类,并且只允许少量 EF 流。在航空公司的类比中,任何航班上的头等舱乘客数量都必须严格限制在可用座位的极小比例内。否则,空乘人员将无法 保证 良好的服务。
Diffserv 中的“经济舱”名称称为 保证转发 (AF)(参见资源 5),它比 EF 稍微复杂一些。AF 的复杂性主要是由于 AF 有四种不同的类别,每种类别有三种子类型。AF 类别之间的区别与不同级别的“转发保证”有关。每个 AF 类别中子类型之间的区别与不同级别的“丢弃优先级”或类别内的相对重要性有关(即,低、中、高)。
“类别”和“丢弃优先级”之间的关系很微妙。每个类别在每个转发节点(路由器)分配资源(例如缓冲区空间、带宽等)。这些资源构成了每个类别的数据包将按需转发的“保证”级别。传输可以 超出 这些资源,风险自负,由“丢弃优先级”描述。因此,在 AF 名称中,转发取决于路由器上的瞬时流量负载、“可用”资源与“所需”资源之间的关系以及每个数据包的丢弃优先级。
Diffserv 中的“候补舱”名称是当前互联网众所周知的 尽力而为 (BE) 行为。因此,服务级别之间的粗略区分是通过将数据包分类为 BE(差)、AF(较好,但有条件)或 EF(最佳)来实现的。
由于 Diffserv 的功能单元架构,并且为了将每流复杂性推送到网络的 边缘,Diffserv 域中实际上至少有两种不同类型的路由/转发节点。根据 Diffserv 规范,“边缘”路由器使用(可能很复杂的)一组规则将标签插入到每个 IP 数据包的报头中。这些标签称为“Diffserv 代码点”或 DSCP(参见资源 6)。一旦数据包被标记并被允许进入 Diffserv 域的内部,“核心”路由器只需检查每个数据包的 DSCP 并将其分配到相应的输出队列,以便转发到下一个节点。通过适当的网络架构,每个数据包都应该能够消耗其需要的和有权获得的转发资源,这是其“标签”的结果。
使用 Linux 实现高级路由行为(包括 Diffserv 提出的行为)的能力由 Linux 内核中存在的一组丰富的流量控制功能提供。Alexey Kuznetsov 是这些内核功能和用于控制它们的用户空间程序的作者。Almesberger 很好地描述了 Linux 流量控制功能的架构(参见资源 7),Hadi-Salim 在一篇优秀的 LJ 文章中也总结了这些功能的动机和控制(参见资源 8)。为了清楚起见,我们简要回顾一下我们的实现中使用的 Linux 流量控制功能以及我们配置这些功能的方法。一般来说,要为 Linux 启用“区分服务”,首先 Linux 机器必须能够正确路由 IP 数据包,然后必须设置几个流量控制规则。
为了准备用作 Diffserv 路由器,必须配置 Linux 路由器的内核以允许使用高级路由功能。为了有效地实现 Diffserv 类型行为,内核的几个“子系统”必须可用。这些子系统包括内核的路由功能、数据包调度功能和用于配置流量控制模块的 netlink 功能。流量控制功能可以编译到单内核中或作为模块加载。
列表 1 和列表 2 显示了编译到我们的 Diffserv 路由器中的相关功能的摘要。给出的所有位置都代表在 make menuconfig 期间给出的选项列表。您现在可能正在检查您的内核配置菜单,并对自己说:“嗯...我没有看到这些选项!” 那是因为您还没有获得必要的内核补丁。“Linux 上的区分服务”网站由瑞士联邦理工学院的 Werner Almesberger 维护(参见资源 9)。您可以在这里找到“Linux 的 Diffserv”发行版(截至撰写本文时,当前版本为 ds-6)。该发行版附带一组用于内核的补丁和用于配置流量控制内核功能的用户空间应用程序(称为“tc”)。该发行版还包含一组示例脚本和一些文档。此时获取 iproute2+tc 包是一个好主意(参见资源 10)。来自 Linux Diffserv 发行版的补丁对 iproute2+tc 版本敏感,并且由于我们的项目主要发生在 1999 年夏天,因此我们使用了 iproute2+tc 的 ss990630 版本。
一旦您的 Linux 路由器配置正确(取决于您的路由器的工作),您就可以配置您的机器进行流量控制。
要在 Linux 路由器上启用区分服务,必须配置流量控制功能。此配置是通过用户级程序实现的,该程序被恰当地命名为 tc(流量控制)。tc 的命令行语法非常长且复杂,因此通常使用脚本进行配置。列表 3 显示了一个示例 tc 配置脚本。在列表中,tc 用于配置我们的 Diffserv 应用程序中核心路由器的内核流量控制。这需要将父排队规则附加到适用的接口,然后为不同的流量类别创建队列。最后,创建过滤器以将数据包分类到适当的类别中。
从列表 3 可以看出,启用 Diffserv 的 Linux 路由器的 tc 配置脚本的结构可以分解为以下几个部分
创建根排队规则。这使用语法 tc qdisc add,后跟几个参数。这些参数描述了此排队规则的属性。这些参数包括排队规则附加到的网络接口 (dev eth3)、qdisc 的标识符 (handle 1:0)、在 qdisc 层级结构中插入此 qdisc 的位置 (root) 以及要使用的排队规则 (tcindex)。其余参数特定于特定的排队规则。Diffserv 自然地映射到基于类的排队方案。因此,每个 Diffserv 路由器(无论工作如何)都将采用基于类的排队 (CONFIG_NET_SCH_CBQ) 来容纳其各种每跳行为。
为每种类型的每跳行为创建类。这使用语法 tc class add,后跟几个参数。这些参数类似于 tc qdisc add 语法。这些参数将标识类所属的排队规则,其他参数定义类的行为。我们的演示广泛使用了两种每跳行为:尽力而为 (BE) 和加速转发 (EF)。列表 3 中的配置清楚地显示了定义 BE 和 EF PHB 的两个部分。
为每个类创建排队规则。每个类都必须有一个排队规则来确定如何对数据包进行排队和出队。此步骤的语法与步骤 1 的语法相同。EF PHB 类对其排队规则使用简单的 FIFO(先进先出),因为我们希望流量尽快进出该类。BE PHB 类使用令牌桶过滤器,试图在极端拥塞时限制流量生成机器。
创建过滤器(分类器)以将标记的流量分配给适当的类。这使用语法 tc filter add,后跟几个参数,用于描述哪些数据包绑定到哪些类。我们的示例脚本来自核心路由器。到达此接口的数据包已被边缘路由器标记。在此步骤对数据包进行分类需要将 IP 报头中的 TOS(服务类型)位与 IETF(互联网工程任务组)区分服务工作组为各种每跳行为建议的值进行匹配(由“mask”参数后面的值表示)。过滤器的创建因路由器执行的工作而异。核心路由器仅使用 Diffserv 发行版附带的 tcindex 数据包分类器 (CONFIG_NET_CLS_TCINDEX)。边缘路由器将防火墙数据包分类器 (CONFIG_NET_CLS_FW) 与 ipchains 一起使用。
完整的 Diffserv 功能实际上假定两种不同类型的路由功能:“核心”路由器和“边缘”路由器。使用基于 Linux 的 Diffserv 实现,“边缘”路由器使用 ipchains 来处理其任务。ipchains 取代了早期内核中的应用程序 ipfwadm,是一个用户空间程序,用于配置 Linux 内核 2.1.x 及更高版本的防火墙功能。本杂志(参见资源 11)和其他领域已充分记录了 ipchains 的配置,这超出了本文档的范围。我们的 Linux Diffserv 测试平台使用 ipchains 根据 IP 地址规则为传入流量分配句柄。然后,tc(用户空间应用程序)安装的过滤器(分类器)使用这些句柄来替换当前的 IP TOS 字节字段设置,并使用适当的 Diffserv 字段标记 (DSCP)。事实证明,这种方法非常有效。动态配置很容易实现,并且 ipchains 的速度能够满足非常高的需求。即使 ipchains 将在未来版本的 Linux 内核中被 iptables 取代(参见资源 12),但功能将非常相似。因此,我们使用的方法仍然适用。
用于在我们的测试平台环境中提供 Diffserv 功能的特定脚本可在 ftp://cter.eng.uab.edu/Diffserv/ 获取。
在我们的“演示环境”中,动态更改路由器配置的能力是通过基于 Web 的网络管理控制台实现的,该控制台使用与动态 HTML 捆绑在一起的 JavaScript。网络管理员可以与此界面交互以启动各种流量优先级级别。我们使用它来模拟网络提供商和最终用户之间的服务级别协议 (SLA)。
除了简洁地演示区分服务的效果外,我们的演示环境的目标还在于证明 Linux Diffserv 实现中的排队机制足够强大,可以在我们的整个 Diffserv 域中强制执行各种 SLA。如图 1 所示,该域由三个路由器(一个核心路由器,两个叶子路由器)、两个 Litton CAMVision-2 MPEG-2 编解码器(高达 15Mbps)或两个 Vbrick MPEG-1 编解码器(高达 3Mbps)、两个客户端工作站、一台 Web 服务器和一个网络管理工作站 (NMS) 组成。
在图中,流量分类由叶子路由器“obiwan”和“nimitz”执行,核心路由器“quigon”配置为相应的基于 DSCP 的转发和排队。流量流被颜色编码以对应于特定类型的 PHB(蓝色=BE,红色=EF 等)。从图中注意到,quigon 和 nimitz 之间的链路是 10 MBps 以太网,并且始终 超额订阅 了多服务流量。这是 SLA 之间的区分至关重要的情况。为了确保 SLA 之间的瞬时变化对普通观察者清晰可见,我们使用了 MPEG 视频流以及一些交互式、基于 Web 的流媒体(RealAudio、RealVideo 等)。
为了模拟网络管理员和每个路由器之间信令的动态特性,我们决定使用套接字交互。当网络管理员希望配置某个服务级别时,他通过 NMS 访问 Web 界面。通过在页面中使用 JavaScript、DHTML 和带有透明部分的 GIF,我们能够在实际提交之前向管理员呈现所需 SLA 的可视化表示。如图 1 的屏幕截图所示,这是端点之间颜色编码的流量流的集合。
如表 1 和图 1 所示,我们能够通过我们的方法配置多个服务级别,每个服务级别都可以通过单击鼠标来获得。请注意,表 1 和图 1 中显示的值和配置反映了一组特定的 SLA,这些 SLA 仅使用 BE 和 EF 流量类别。当用户单击所需 SLA 图标时,HTML 表单字段中的值通过 HTTP POST 操作传递到 Web 服务器。表单值通过 CGI 传递到 Perl 脚本,该脚本处理 POST,然后重新配置域中的每个路由器。路由器逐个联系,并调用管理员选择的 SLA。列表 4 显示了路由器控制的客户端部分的示例 Perl 伪代码,列表 5 显示了服务器部分。从列表 4 中的 Perl 客户端代码可以看出,NMS(或其他 Web 服务器)可以根据网络管理员的输入轻松地将“当前 SLA”传递给域中的所有路由器。此“控制通道”接口在所有网络配置中都受到高优先级、低速率排队配置的保护,如图 1 中的黑线所示。
为了在 NMS 上提供积极的用户反馈,当每个路由器开始其独特的网络设置时,Web 界面会为管理员刷新。域中的每个启用 Diffserv 的路由器都会接收所需的 SLA,并且必须根据其在域中的位置和静态定义的 SLA 集合来相应地设置其规则。这是通过对 ipchains-restore 的 system 调用根据新的 SLA 动态完成的。当 ipchains-restore 命令完成时,网络设置完成。列表 5 显示了典型核心路由器的此操作的 Perl 伪代码。根据我们的系统定义,我们基本上在预先存储的 ipchains 映射中维护一个简单的网络/SLA 配置“数据库”。
为了尝试模拟一些典型的最终用户流量以及恒定的 MPEG 流,我们使用了许多 FTP 下载、一些流式音频/视频源以及整个网络中的小洪泛 ping。由于我们的演示环境的交互性质,这些基于网络的数据源也可以通过基于 Web 的 GUI“按需”获得。
特别是在任何开源开发方面,忽略提及相关工作或为本文中描述的系统做出贡献的工作是不合适的。我们认为卡尔斯鲁厄大学(参见资源 13)和堪萨斯大学(参见资源 14)正在进行的两个基于 Linux 的 Diffserv 项目特别有趣和成熟。通过这些项目提供的许多结论和见解与我们自己的观察结果相符,它们是进一步了解 Linux 下的 Diffserv 和区分服务的优秀来源。我们强烈推荐给感兴趣的读者。
特别是,我们要提请注意本文中描述的演示环境与堪萨斯大学正在构建的 DiffSpec 工具之间的差异。Diffserv 为每个服务类别分配资源的方法非常明确地要求外部干预,形式为所谓的“带宽代理” (BB)。DiffSpec 工具包含比此处讨论的演示环境更宏大的系统概念。例如,DiffSpec 包括用于管理队列/类/过滤器组合的 API、用于自动配置 DS 参数的基于 CORBA 的系统调用以及 Linux 流量控制功能的一般 Web 用户界面。
相比之下,为了我们的演示环境的目的,我们无意中遵循了政治学学生熟知的“权力分立”哲学。我们将 BB 的“服务级别定义”(或“立法部门”)功能仔细地隔离到一个手动制作的、允许配置的静态数据库中。与此同时,我们将 BB 的“网络实例化”(或“行政部门”)功能放置在巧妙分布的 ipchains 规则排列上。通过这种方式,我们能够通过操作员的输入或通过自动化方式将整个网络立即重新配置为几种预定义的“外观”之一。这种方法在某些情况下可能具有可扩展性,并且可能为网络资源的便捷“治理”提供便利,但它并非专门用于大众消费。
此外,卡尔斯鲁厄 Diffserv 实现的结构似乎与洛桑瑞士联邦理工学院 Werner Almesberger 维护的实现略有不同。对于我们的项目,我们使用了 Almesberger 的发行版,因此我们没有卡尔斯鲁厄发行版的具体经验,也没有两种实现之间的差异。
Michael Stricklen (goose@uab.edu) 是 UAB 电信教育与研究中心的助理研究员。他喜欢摆弄 Linux 项目和网络设备。当不面对电脑时,Michael 更喜欢滑雪。
Bob Cummings (bahb@uab.edu) 是 UAB 电信教育与研究中心的助理研究员。在他的业余时间,他喜欢与朋友共度时光、玩 RPG 并磨练他的 Perl 技能。
Stan McClellan (smcclell@uab.edu) 是一位 Linux 爱好者,恰好受雇于 UAB 电气和计算机工程系。当他不通过拉研究经费或教课来“扮演教授”时,他可以在周围闲逛,缠着学生要“有趣的结果”