IP 带宽管理
互联网的成功主要归功于将其连接在一起的协议 IP(互联网协议)的简单性和稳健性。最近,每个人都希望在 IP 上运行。主要驱动因素包括希望用 IP 网络承载语音来取代传统电路交换语音网络的电话公司,以及希望用共享 IP 网络上的虚拟专用网络 (VPN) 来取代其专用连接的多站点公司。
然而,IP 有一个小小的缺点。与 ATM 等协议不同,它对每个人都一视同仁。所有通过 IP 网络的数据都以尽力而为的方式平等转发。如果我愿意每月多付 2 美元,以便客户能够更快半秒钟加载我的网页呢?如果我愿意多付一点钱,以便我可以通过互联网与大西洋彼岸的人进行连贯的音频对话呢?在这两种情况下,那些特别愿意多付费的数据包都必须得到更公平的对待才能实现这一点,因此,IP 对所有人的平等性就失败了。现在,新的流行语来了:服务质量 (QoS),即尝试简化 IP 以满足这些新要求。虽然 QoS 本身并不是一个新概念,但由于大型公司对使用 IP 的兴趣,QoS 近来获得了更大的发展势头。
QoS 对不同的人意味着不同的事物。在麦当劳订购汉堡和薯条比在高级餐厅便宜,在那里您在订单到达之前会得到一杯水和许多礼遇。您在餐厅支付更多费用是为了获得QoS。有人可能会争辩说,麦当劳的 QoS 更好,因为您得到服务的速度更快。另一个类比是航空公司的模式,同一架飞机上有经济舱和头等舱客户。简单来说,可以将 QoS 定义为支付更多以获得更好的服务。因此,这是网络自我维持的好方法。
其中隐含的一个含义是,互联网的社会主义时代已经结束。从社会角度来看,IP-QoS 的出现已经被指责为在互联网上引入了等级制度:“比特富人”和“比特穷人”正在成为现实。
服务提供商为 QoS 划分带宽的能力被称为“带宽管理”。多年来,已经提出并实施了几种技术。互联网工程任务组 (IETF) 过去曾通过 RSVP 提出集成服务,这是主机驱动的。RSVP 未能成为广泛部署的标准,主要是由于可扩展性问题。目前,IETF 正在推行一种称为区分服务 (diffserv) 的新解决方案,该解决方案将带宽管理的更多控制权交给网络所有者。本文将不深入探讨这两种技术的细节。好消息是 Linux 目前都支持这两种技术。
新的 2.1.x Linux 流量控制 (TC) 代码(以及更多内容)的无名英雄是 Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)。Alexey 在设计中投入了大量思考,使其极其灵活和可扩展。
我所描述的只是 Linux 流量控制所呈现的可能性的冰山一角,而没有深入细节。预期的范围是通过一个简单的示例来展示如何释放 Linux 流量控制的力量。
TC 功能使 ISP 能够根据自己的意愿管理(或划分)其带宽。过去,还有其他不太有组织的方式来做到这一点。ISP 可以通过根据接口能力销售服务来限制客户的访问速率,例如,28.8 与 56Kbps 调制解调器或 1 与 3Mbps xDSL 调制解调器。
另一种更具创新性但野心较小(相对于 TC)的速率限制带宽的方法是使用 Alan Cox 的整形器设备。整形器设备首先使用 shapecfg 实用程序附加到已配置的网络设备(例如,以太网),该实用程序也用于配置整形器的速度。下一步是使用 ifconfig 实用程序将整形器配置为与附加到的设备具有相同的 IP 地址。最后一步是映射要由整形器处理的数据包;这被称为分类。这是使用常见的 route 命令完成的,该命令将数据包要被调节的路由指向整形器。整形器的优点是它也可以在 2.0.x 内核上运行(从 2.0.36 开始包含,并且可以作为早期内核的补丁使用)。在 2.0.x 内核中,整形器有限的分类能力可以通过使用 Mike McLagan (mmclagan@linux.org) 的补丁来增强,以允许通过源/目标对指定路由。新的 TC 功能涵盖了整形以及更多内容。
启用带宽管理的另一种技术是使用 Alexey Kuznetsov 实现的多路由表功能。Linux 2.2 有一个新功能,允许单个 Linux 机器拥有多个路由表。本质上,可以为付费更高的客户设置一个特殊的路由表,并通过更高带宽或不太拥塞的设备(例如,到 T3 而不是 ISDN 线路,两者都朝同一个方向)重定向他们的流量。Linux 带宽管理中也许最保守的秘密是 Apache Web 服务器有一个带宽限制模块 mod_throttle,用于根据配置文件中定义的速率限制单个用户。有关详细信息,请参阅 http://www.bigrock.com/~mlovell/throttle/。
Linux TC 在确定下一个跃点之后,即在转发代码决定数据包将从哪个接口发出之后,对数据包进行调节。这意味着只有传出的数据包才会受到 TC 的影响。TC 由三个构建块组成。
排队规则可以被认为是设备的流量/数据包管理器。它在其内部封装了另外两个主要的 TC 组件,并控制数据流经它们的方式。只有一个这样的管理组件可以附加到一个设备。目前,有几个设备排队规则可用于管理设备,包括基于类的排队 (CBQ)、优先级和 CSZ (Clark-Shenker-Zhang)。稍后将展示一个使用 CBQ 的示例配置。
类由设备排队规则管理。一个类由管理该类拥有的数据消息的规则组成。例如,一个类中的所有数据包都可能受到 1Mbps 的速率限制,并允许在午夜到凌晨 6 点之间超速到 3Mbps。几个排队规则可以附加到类,包括 FIFO(先进先出)、RED(随机早期检测)、SFQ(随机公平排队)和令牌桶。如果设备上未附加任何排队规则,则使用基本 FIFO。在稍后显示的示例中,未附加特定的类排队规则,因此默认为简单的 FIFO。CBQ、CSZ 和优先级也可以用于类,并允许在一个类中进行子类化。这表明使用 TC 可以多么容易地构建非常复杂的场景。管理类的排队规则称为类排队规则。通常,类排队规则管理该类的数据和队列,并且可以决定延迟、丢弃或重新分类它管理的数据包。
分类器或过滤器描述数据包并将它们映射到由排队规则管理的类中。这些通常提供简单的描述语言来指定如何选择数据包并将它们映射到类。目前,有几个过滤器(取决于您的需求)可以与 TC 结合使用,包括基于路由的分类器、RSVP 分类器(IPV4 和 IPV6 各一个)和 u32 分类器。所有防火墙过滤器都可以使用,但受其内部过滤标签的限制。例如,ipchains 可以用于分类数据包。
TC 代码驻留在内核中,不同的块可以编译为模块或直接编译到内核中。内核代码或模块的通信和配置是通过用户级程序 tc 实现的,该程序由 Alexey 编写。交互如图 1 所示。tc 程序可以从 ftp://linux.wauug.org/pub/net/ip-routing/iproute2-current.tar.gz 下载。如果您使用的是仅 glibc 系统,则需要为其打 glibc 补丁。补丁在同一目录中可用。请注意,该软件包还包括 ip 和 rtmon 工具。
TC 非常灵活:您决定要将什么配置为服务。提供具有不同 QoS 级别的虚拟服务器的 ISP 是 Linux 流量控制强大功能的良好示例。请注意,类似的服务可以应用于企业内部网。当 ISP 销售虚拟 Web 服务器托管服务时,传统的差异化因素是磁盘空间。每月多付 5 美元,您可以为托管的 Web 服务器获得额外的 100 兆字节磁盘空间。其他 ISP 根据对其他服务的访问进行服务差异化,例如从您的网页访问 Realvideo 和 SSL。还有一些 ISP 根据您的网页获得的点击次数等来区分服务。通过 Linux 流量控制,为区分服务增加了一个新的维度。这为区分向客户提供的服务提供了许多新的机会。例如,如果您提供虚拟 Web 托管,您可以提供四种不同的套餐
服务级别协议 (SLA) 1:费用 5 美元/月 - 访问客户虚拟服务器的访客可以获得高达 250Kbps 的服务器出口带宽。
SLA2:费用 7 美元/月 - 250Kbps,可以在午夜到凌晨 6 点之间超速到 1Mbps。
SLA3:费用 9 美元/月 - 250Kbps,可以在一天中的任何时间带宽可用时超速到 1Mbps。
SLA4:费用 50 美元/月 - 高达 1Mbps 的高优先级、低延迟带宽,适用于视频和音频传输(以及 IP 电话),带有额外的过滤器,为低优先级访客提供非常低的带宽(例如,那些获得免费服务的人)。
可以提供各种各样的创新服务。通过使用 crontab 激活的脚本来更改配置,可以轻松添加时间段功能。
以下是一个 Linux 机器的示例,该机器具有两个虚拟服务器(Web、FTP 等),以及 ISP 如何根据访问这两个虚拟服务器时获得的最大带宽将它们作为两个单独的套餐出售。
内核编译
我假设您知道如何编译内核并添加网络和别名支持。在撰写本文时,我使用了内核 2.1.129 和其他一些补丁。Linux 2.2 pre1 刚刚发布,但补丁尚未包含在内。在您阅读本文时,2.2 将会发布,我使用的所有内容都将包含在内。
第一个挑战是时钟源。为了准确确定带宽测量,您需要一个非常精细的时钟。在 Linux 中,时钟以 HZ 的频率运行,ix86 定义为 100,即每秒 100 个时钟滴答,这转化为每个时钟滴答 10 毫秒的粒度。在 Alpha 上,HZ 定义为 1000,粒度为 1 毫秒。我不建议更改代码中 HZ 的值。TC 时钟源通过编辑内核树下的文件 /include/net/pkt_sched.h 并修改定义 PSCHED_CLOCK_SOURCE 的行来调整。首先,我建议让时钟源保持原样,直到您习惯运行其他内容。默认时钟源 PSCHED_JIFFIES 在所有架构上都能正常工作。在高端奔腾和 Alpha 上使用 PSCHED_CPU。最精确和最昂贵的时钟源是 PSCHED_GETTIMEOFDAY。如果您有真正高端的奔腾 II 或 Alpha,请使用它。不要尝试在 486 上使用它。
接下来,编译内核。选择 Kernel/User netlink socket 和 Netlink device emulation 以允许使用 netlink,以便 tc 可以与内核通信。第二个选项是向后兼容性选项,现在 2.2 已经发布,它可能已经过时,所以如果您看不到它,请不要担心。接下来,编译所有排队规则和分类器。虽然每个都可以选择作为模块,但我将它们直接编译进去了。选择项为 QoS 或公平排队、CBQ 数据包调度器、CSZ 数据包调度器、最简单的 PRIO 伪调度器、RED 队列、SFQ 队列、TBF 队列、QoS 支持、速率估计器、数据包分类器 API、基于路由表的分类器、U32 分类器、特殊 RSVP 分类器和 IPv6 的特殊 RSVP 分类器。
完成编译和安装内核的正常步骤。
编译和设置 TC
如果您像我一样使用 glibc (Red Hat 5.2),您将需要应用 glibc 补丁。包含了一个 glibc 补丁的 tc 源代码 (tc-glibc-patched.tgz)。主要的注意事项是更改 Makefile 以指向内核包含文件的位置。然后键入 make 应该可以为您干净地编译 tc 和 ip。ip-routing 目录包含名称为 iproute2-*.glibc2.patch.gz 的补丁。获取最新的补丁以匹配当前的 tc。在撰写本文时,我下载了 iproute2-2.1.99-now-ss981101.glibc.patch.gz。

图 2. CBQ 树状图
图 2 显示了我们将要设置的简单场景。两个叶节点从根节点发出。IP 地址 10.0.0.10(classid 1:1)和 10.0.0.11(classid 1:2)是设备 eth0 上的别名。它们都共享同一个父节点 - classid 1:0(根节点)。同样,目的是展示一个人可以做什么,而无需深入细节或构建复杂的 TC 设置。通过一些修改,可以构建具有多个设备的更有趣的设置。
设置 QoS 功能的一般方法是首先将 qdisc 附加到设备。在示例脚本中,这是通过以下行实现的
qdisc add dev eth0 root handle 1: ...
接下来,定义您的类。这使您可以区分不同的传出流量类型。在示例脚本中,这是通过以以下内容开头的行实现的
tc class add dev eth0 parent 1:0 classid X:Y ...在示例脚本中,显示了一个单层树。但是,可以构建多深度树。基本上,子节点(如图 2 所示)从父节点继承,然后通过类定义进一步限制资源。例如,根类 1:0 拥有设备的带宽。子节点 1:1 不能分配超过 10Mbits 的带宽,但限制为 1Mbps。最终,叶节点根据将数据包映射到它们的分类器获得发送给它们的数据包。这与 UNIX 目录和文件树结构非常相似。您可以将非叶节点视为目录,将叶节点视为文件。
最后,定义您的数据包到类的映射,以告诉您的分类器将哪些数据包发送到哪个类。您必须定义类才能使其有意义。首先,将分类器附加到正确的类。在示例脚本中,这是通过以以下行开头的构造实现的
filter add dev eth0 parent 1:0 protocol ip ...
接下来,定义将要使用的数据包到类的映射。在示例脚本中,这在定义匹配标准(例如 match ip src ...)的构造中定义。始终将数据包映射到叶类。
如果您遵循此方法并为不同的排队规则和过滤器替换正确的语法,您将得到正确的结果。适当的详细信息在选项中。
在我们的设置中,我们在单个 Linux 机器上有两个虚拟 Web 服务器。设置脚本(列表 1)包括一些使用提供的 ip 实用程序的注释掉的示例 IP 别名。ip 实用程序功能丰富,不在本文的范围之内。在示例中,IP 地址 10.0.0.10 和 10.0.0.11 附加(别名于)到设备 eth0。
要进行测试,请使用 ftp 连接到网络上的另一台机器。首先,使用 ftp 连接到 IP 地址 10.0.0.10,您应该观察到大约 1Mbps 的速率。退出该 ftp 会话并启动另一个到 10.0.0.11 的会话,您应该观察到大约 3Mbps 的吞吐量。
对于 Linux 来说,这是一个非常激动人心的时代。据我所知,Linux 是当今可用的最先进的启用 QoS 的操作系统。最接近的第二名可能是 BSD 的 ALTQ,它在 Linux TC 中发现的复杂性、灵活性和可扩展性方面落后很多。我不知道 Microsoft 产品中有任何此类功能(如果存在,也许有人可以提供指针)。Sun Solaris 的确有一个 CBQ 和 RSVP 组合,他们作为单独的产品出售。我预测,由于 TC 的许多可用功能,Linux 服务器的使用量将大幅增加。Alexey 已将 Linux 提升到一个新的水平。
Linux 中也支持 IETF diffserv 功能。这项工作扩展了 TC,以添加当今已知的最灵活的 diffserv 支持。Diffserv 支持的实现得益于 Werner Almesberger(他也编写了 LILO、Linux-ATM 等)和我自己的努力。有关更多详细信息,请参阅 http://lrcwww.epfl.ch/linux-diffserv/。
本文中引用的所有列表都可以通过匿名下载文件 ftp.linuxjournal.com/pub/lj/listings/issue62/3369.tgz 获得。
Jamal Hadi Salim (hadi@cyberus.ca) 是一个黑客 wannabe。他花费了大量的空闲时间盯着 Linux 网络代码。Jamal 是 Sendmail-UUCP HOWTO 的原始作者,也是 CASIO 数字日记串行驱动程序/应用程序的作者,他仍然维护它。他还向许多东西发送了偶尔的补丁,包括内核,偏向于网络问题。目前,他的努力主要集中在网络调度代码上,他在那里与 Werner Almesberger 共同编写了 Linux diffserv 代码。