我们将从在网络上安装主机并能够访问其他互联网主机的基本要素开始。然而,原始的TCP/IP连接是不够的;您还需要将主机名解析为IP地址的能力,因此我们接下来将介绍这一点。然后,我们将讨论测量网络活动、性能、VLAN和聚合链接。
不过,在你做这些之前,你需要一些信息。
如果您的网络提供动态主机配置协议(DHCP),您可以作为客户端连接到网络,而无需了解网络的任何信息。但是,静态IP地址在服务器上更有意义。虽然安装程序会为您配置网络,但最终每个服务器都需要更改。IPv4和IPv6都需要以下信息:
有了这些信息,使用ifconfig(8)和route(8)将您的系统连接到网络,然后在/etc/rc.conf中使配置永久化。
ifconfig(8)程序显示计算机上的接口,并允许您对其进行配置。首先,运行ifconfig(8),不带任何参数,列出系统上的现有接口:
xxxxxxxxxx
# ifconfig
➊em0: flags=8843<➋UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=85259b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4,
LRO,WOL_MAGIC,VLAN_HWFILTER,VLAN_HWTSO>
inet ➌203.0.113.43 netmask 0xfffffff0 broadcast 198.51.100.47
inet6 ➍fe80::225:90ff:fee8:1270%em0 prefixlen 64 scopeid 0x1
inet6 ➎2001:db8::bad:c0de:cafe prefixlen 64
ether ➏00:25:90:db:d5:94
media: ➐Ethernet autoselect (1000baseTX <full-duplex>)
status: ➑active
rl0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500
options=8<VLAN_MTU>
ether 00:20:ed:72:3b:5f
media: Ethernet autoselect (10baseT/UTP)
status: ➒no carrier
➓lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
inet 127.0.0.1 netmask 0xff000000
nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
我们的第一个网络接口是em0➊,即第一个使用em(4)驱动程序的网卡。em(4)手册页显示这是一张Intel PRO/1000卡。然后,您将看到有关此卡➋的基本信息,包括它处于UP状态,这意味着它正在工作或试图工作。它被分配了IPv4地址203.0.113.43➌和网络掩码0xfffff0(或255.255.255.240,如表7-2所示)。此卡有两个IPv6地址,链路本地地址(从fe80开始)➍和全局IPv6地址➎。您还可以看到MAC地址➏和连接速度➐。最后,状态条目显示此卡处于活动状态➑:电缆已插入,我们有一个链路指示灯。 第二张卡rl0几乎没有与之相关的任何信息。一个关键事实是no carrier信号➒:它没有插入电源,也没有连接灯。此卡未被使用。 最后,我们有了lo0➓接口,即环回。此接口在每台机器上都有IPv4地址127.0.0.1和IPv6地址::1。当机器与自身对话时,会使用此环回地址。这是一个标准的软件接口,没有任何相关的物理硬件。不要试图删除环回接口,也不要更改其IP地址——如果你这样做,事情会以一种有趣的方式中断。FreeBSD支持其他软件接口,如disc(4)、tap(4)和gif(4)等等。
安装过程将配置您在安装时正在使用的任何网卡。如果在安装过程中没有为所有网卡配置网络,或者在完成安装后添加或删除网卡,则可以使用ifconfig(8)为网卡分配IP地址。您需要该卡的指定IP地址和网络掩码。命令格式如下:
xxxxxxxxxx
# ifconfig interface-name inet IP-address netmask
例如,如果网卡时em0,IP地址为203.0.113.250,网络掩码是255.255.255.0,则命令如下:
xxxxxxxxxx
# ifconfig em0 inet 203.0.113.250 255.255.255.0
如上所述,以虚线四元表示法或十六进制格式(0xffff00)指定网络掩码。也许最简单的方法是使用斜线符号,如下所示:
xxxxxxxxxx
# ifconfig em0 inet 203.0.113.250/24
要配置IPv6地址,请在接口名称和地址之间添加inet6关键字:
xxxxxxxxxx
# ifconfig em0 inet6 2001:db8::bad:c0de:cafe/64
ifconfig(8)程序还可以执行网卡所需的任何其他配置,使您能够解决各种校验和卸载等功能中的硬件错误,例如为亚千兆接口设置媒体类型和双工模式。您可以在驱动程序和ifconfig(8)的手册页中找到支持的选项。在这里,我在em0接口上禁用了校验和卸载和TCP分段卸载,即使我设置了IP地址:
xxxxxxxxxx
# ifconfig em0 inet 203.0.113.250/24 -tso -rxcsum
要使这种情况在重新启动时持续存在,请在/etc/rc.conf中添加一个条目,告诉系统在启动时配置卡(俗称“固化”)。IPv4条目的格式为ifconfig_interfacename=“ifconfig arguments”。例如,配置空闲的rl0卡需要一个类似以下的条目:
xxxxxxxxxx
ifconfig_rl0 ="inet 203.0.113.250/24"
对于IPv6地址,格式为 ifconfig_interfacename_ipv6="ifconfig arguments",比如:
xxxxxxxxxx
ifconfig_rl0_ipv6="2001:db8::bad:c0de:cafe/64"
一旦您的接口有了可用的配置,请将ifconfig(8)参数复制到/etc/rc.conf条目中。
最常用的测试方式是ping默认网关的IPv4地址(按CTRL-C停止),如果收到响应则表示已经连接到本地网络:
xxxxxxxxxx
# ping 203.0.113.1
PING 203.0.113.1 (203.0.113.1): 56 data bytes
64 bytes from 203.0.113.1: icmp_seq=0 ttl=64 time=1.701 ms
64 bytes from 203.0.113.1: icmp_seq=1 ttl=64 time=1.436 ms
^C
--- 203.0.113.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 1.436/1.569/1.701/0.133 ms
对于IPv6,使用ping6(8)取代ping(8)。如果你使用了路由发现,默认路由几乎总是链路本地地址:
xxxxxxxxxx
# ping6 2001:db8::1
PING6(56=40+8+8 bytes) 2001:db8::bad:c0de:cafe --> 2001:db8::1
16 bytes from 2001:db8::1, icmp_seq=0 hlim=64 time=0.191 ms
16 bytes from 2001:db8::1, icmp_seq=1 hlim=64 time=0.186 ms
16 bytes from 2001:db8::1, icmp_seq=2 hlim=64 time=0.197 ms
--snip--
如果没有收到任何回应,说明你的网络连接未能正常工作。要么是电缆问题、要么是网卡配置问题。
默认路由是你的系统发送所有不在本地网络上的流量的地址。如果你可以ping默认路由的IP地址,请通过route(8)进行设置:
xxxxxxxxxx
# route add default 203.0.113.1
搞定。你现在可以访问互联网上任何公网IPv4地址了。
添加默认IPv6路由大致相同,但你需要添加-6命令行标志来更改IPv6路由表:
xxxxxxxxxx
# route -6 add default 2001:db8::1
如果在系统安装过程中没有选择名称服务器,则必须使用IP地址而不是主机名。
一旦你有了一个可用的默认路由器,通过在/etc/rc.conf中添加正确的defaultrouter和ipv6_defaultrouter条目,使其在重新启动后仍然存在:
xxxxxxxxxx
defaultrouter="203.0.113.1"
ipv6_defaultrouter="2001:db8::1"
FreeBSD系统可以在一个接口上响应多个IP地址。这对jails特别有用(见第22章)。使用ifconfig(8)和关键字inet和alias为接口指定其他IPv4地址。IPv4别名上的网络掩码始终为/32,无论主地址使用的网络地址块大小如何。
xxxxxxxxxx
# ifconfig em0 inet alias 203.0.113.225/32
IPv6别名使用它们所在子网的实际前缀长度(斜线)。请确保使用inet6关键字。
xxxxxxxxxx
# ifconfig em0 inet6 alias 2001:db8::bad:c0de:caff/64
在接口中添加别名后,ifconfig(8)输出中将显示额外的IP地址。主IP始终显示在前面,别名紧随其后。
xxxxxxxxxx
# ifconfig fxp0
fxp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=b<RXCSUM,TXCSUM,VLAN_MTU>
inet6 fe80::225:90ff:fee8:1270%vtnet0 prefixlen 64 scopeid 0x1
➊ inet6 2001:db8::bad:c0de:cafe prefixlen 64
inet6 2001:db8::bad:c0de:caff prefixlen 64
inet 203.0.113.250 netmask 0xffffff00 broadcast 203.0.113.255
➋ inet 203.0.113.225 netmask 0xffffffff broadcast 203.0.113.255
ether 00:02:b3:63:e4:1d
--snip--
在这里,我们看到了我们全新的IPv4➊和IPv6➋别名。ping您的别名地址的主机将收到此服务器的响应。
一旦你让别名按你喜欢的方式工作,通过在/etc/rc.conf中添加额外的ifconfig语句,使它们在重新启动后仍然存在:
xxxxxxxxxx
ifconfig_em0_alias0="inet 203.0.113.225/32"
ifconfig_em0_alias1="inet6 2001:db8::bad:c0de:caff/64"
此条目与标准rc.conf的“这是我的IP地址”条目之间唯一真正的区别是alias0和alias1块。别名关键字告诉FreeBSD这是一个别名IP,0和1是分配给每个别名的唯一数字。/etc/rc.conf中设置的每个别名都必须有一个唯一的数字,并且这个数字必须是连续的。如果跳过一个数字,则在启动时不会安装间隙后的别名。这是我见过的最常见的接口配置错误。
许多守护进程,如inetd(8)和sshd(8),可以绑定到一个地址(见第20章),因此您可以使用多个地址在同一服务器上运行同一程序的多个实例。
FreeBSD系统的所有连接都使用系统的真实IP地址。您可能有2000个地址绑定到一个网卡,但当您从该机器进行ssh时,连接来自主IP地址。在编写防火墙规则和其他访问控制过滤器时,请记住这一点。jail会从jail IP地址启动所有连接,但我们要到第22章才会介绍jail。
FreeBSD以网卡使用的设备驱动程序命名其网络接口。这是Unix世界的优良传统,也是大多数工业操作系统的常见行为。一些操作系统根据接口类型命名其网络接口,例如,Linux称其以太网接口为eth0、eth1等。
有时,重命名接口是有意义的,要么是为了符合内部标准,要么是使其功能更加明显。例如,我有一台设备有12个网络接口,每个接口都插入不同的网络。每个网络都有一个名称,如test、QA等。重命名这些网络接口以匹配连接的网络是有意义的。
虽然FreeBSD在接口名称上很灵活,但有些软件却不然——它假设网络接口名称是一个简短的单词,后跟一个数字。这在不久的将来不太可能改变,因此最好使用以数字结尾的短接口名称。使用ifconfig(8)的name关键字重命名接口。例如,要将em1重命名为test1,您可以运行:
xxxxxxxxxx
# ifconfig em1 name test1
运行不带参数的ifconfig(8)表示您已重命名该接口:
xxxxxxxxxx
--snip--
test1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=b<RXCSUM,TXCSUM,VLAN_MTU>
--snip--
使用/etc/rc.conf中的ifconfig_interface_name选项使此更改永久生效。
xxxxxxxxxx
ifconfig_em1_name="test1"
FreeBSD在启动过程的早期重命名接口,然后设置IP地址或其他值。这意味着任何进一步的接口配置都必须引用新的接口名称,而不是旧的接口名称。带有IP地址和别名的重命名接口的完整配置如下:
xxxxxxxxxx
ifconfig_em1_name="dmz2"
ifconfig_dmz2="inet 203.0.113.2 netmask 255.255.255.0"
ifconfig_dmz2_alias0="inet 203.0.113.3"
很少有网络对所有事情都使用DHCP,包括服务器。DHCP服务器将为您设置服务器的IP地址、网络掩码、名称服务器和默认网关。如果您的网络管理员通过DHCP配置服务器,您可以通过以下方式告诉网卡通过DHCP进行配置:
xxxxxxxxxx
ifconfig_em0="DHCP"
现在您已经完全配置了网络接口,请务必重新启动以测试您对/etc/rc.conf所做的任何更改。如果FreeBSD在/etc/rc.conf中发现错误,特别是在网络配置中,您将无法远程访问系统。最好知道你是在受控条件下打错的,而不是在睡眠时间的中间。
若你们觉得生活很危险,你们可以使用接口名称重新启动服务网络,只重新配置一个接口。
xxxxxxxxxx
# service netif restart em0
跳过接口名称,这将重新启动所有接口。这不是一个完美的测试,但它会抓住一堆愚蠢。重启总是最好的测试。
域名服务——Domain Name Service——DNS,是一种安静的幕后服务,没有得到应得的关注。
DNS提供主机名和IP地址之间的映射。它还提供IP地址到主机名的反向映射。
对大多数终端用户来说,DNS故障就是互联网故障。
名称服务器有两种类型:权威(authoritative)和递归(recursive)。
权威(Authoritative)名称服务器为公众提供DNS映射,以查找组织的名称服务器。权威名称服务器只回答有关其管理的域的查询。
递归(Recursive)名称服务器为客户端请求提供服务。当客户端需要解析一个域名时,本地递归名称服务器在互联网上搜索该域名的权威名称服务器。一旦递归名称服务器检索到主机名到IP的映射,它就会将该响应反馈给客户端。
本书不讨论权威名称服务器,仅介绍如何使用递归名称服务器以及如何启用自己的递归名称服务器。
系统的解析器(resolver)负责配置主机如何执行DNS查询,并将响应中继(replaying)到程序。配置解析器是系统管理的重要组成部分。即使是DNS服务器也需要一个配置好的解析器,因为除非你告诉它,否则主机不会知道它是一个名称服务器。
配置解析器需要回答几个问题:
这些问题的答案在/etc/nsswitch.conf和/etc/resolv.conf中配置。
FreeBSD和所有类Unix操作系统一样,可以从DNS和明文主机文件/etc/hosts中获取主机名/IP信息。
当FreeBSD需要知道某个主机的地址(或地址的主机名)时,默认情况下,查询首先会转到hosts文件,然后是配置的名称服务器。这意味着你可以在本地覆盖名称服务器结果,这对于NAT后面的主机或具有奇怪要求的大型企业网络非常有用。
可以在/etc/nsswitch.conf中设置名称查询的顺序,比如先查询DNS,然后查询hosts文件。
/etc/nsswitch.conf文件不仅供解析器(resolver)使用,也供所有其他名称服务器使用。网络操作系统包括许多不同的名称服务器。/etc/services中的TCP/IP端口是名称服务以及网络协议名称和编号。确定用户的UID和GID需要不同类型的名称查找(见第九章)。 /etc/nsswitch.conf决定所有这些查询的顺序等等。本章只讨论主机名查找(hostname lookups),第二十章将介绍更多关于名称服务切换的内容。
/etc/nsswitch.conf中的每个条目一行,其中包含名称服务的名称、冒号、信息源列表。例如:
xxxxxxxxxx
hosts: files dns
解析器按所列顺序查询信息源。如果有其他信息源,如nscd(8),请在此处列出。这些附加组件的文档来源应包括服务的名称。
/etc/hosts文件将互联网地址与主机名相匹配。
石器时代,互联网上只有一个hosts文件,提供互联网上每个节点的主机名和IP地址。系统管理员将他们的主机更改提交给中央维护人员,后者每个几个月发布一个修订后的主机文件。然后,系统管理员将下载hosts文件并将其安装在所有计算机上。随着互联网上的终端以指数级增长,这中方式变得完全无法维护。
虽然hosts文件很有效,但它仅在安装它的计算机上工作,并且必须由系统管理员维护。公共DNS在很大程度上取代了/etc/hosts,但在你不想运行本地权威(local authoritative)DNS或位于IPv4 NAT设备后面的环境中,它仍然很有用。当你的网络长到足够大,就该学习构建一个权威的名称服务器了。
/etc/hosts中的每一行代表一个主机。每行的第一个条目是IP地址,第二个是主机的完全限定域名(fully qualified domain name——FQDN),在这两条后面,你可以列出该主机的任意数量的别名。
例如,一家小公司可能只有一台服务器来处理电子邮件、提供FTP、网页和DNS服务,以及执行各种其他功能。该网络上的桌面可能有这一的hosts文件条目:
xxxxxxxxxx
203.0.113.3 mail.mycompany.com mail ftp www dns
使用此/etc/hosts条目,桌面可以找到具有完整域名或列出的任何简短别名服务器。
告诉你的主机如何使用/etc/resolve.conf文件查询名称服务器。你可能希望提供一个本地域或域搜索列表,然后列出名称服务器。
如果你的组织有很多机器,键入完整的主机名可能很快就会过时。如果你正在进行维护并需要登录每个web服务器,你可能需要一个更简短的主机名。在/etc/resolv.conf的第一行提供本地搜索或要搜索的域列表。
domain关键字告诉解析程序默认情况下要检查哪个本地域以查找所有主机名。我的所有测试主机都在域名michaelwlucas.com中,因此我可以将其设置为默认域名:
xxxxxxxxxx
domain michaelwlucas.com
指定本地域后,解析器将自动将该域附加到任何短主机名。比如,键入ping www,解析器将附加本地域并向www.michaelwlucas.com发送ping(8)。但是,如果我给出完整的主机名,比如www.bertjwregeer.com ,解析器不会添加默认域。
也许我有多个域名想搜索。使用search关键字按顺序给出要尝试的域名列表。与domain一样,search必须是resolve.conf的第一行。
xxxxxxxxxx
search michaelwlucas.com bertjwregeer.com mwl.io
当你使用简短的主机名,例如www,解析器会在search列表中附加第一个域名,如果没有答案,它将使用第二个域名重复查询,然后第三个域名。如果这些域中都不存在这样的主机,则搜索失败。
如果你在/etc/resolve.conf中既没有domain,也没有search条目,但计算机的主机名包含域名,则解析器将使用本地计算机的域名。
现在你的解析器知道要尝试哪些域,告诉它要查询哪些名称服务器。在/etc/resolv.conf中按优先顺序列出每个条目。每个条目包括nameserver关键字和DNS服务器的IP地址。解析器按顺序查询列出的名称服务器。一个完整的resolv.conf可能看起来像这样:
xxxxxxxxxx
domain mwl.io
nameserver 127.0.0.1
nameserver 203.0.113.8
nameserver 192.0.2.8
这个解析器可以工作了。
不过,请注意第一个nameserver条目,地址127.0.0.1始终附加到本地主机。此计算机正在运行本地递归名称服务器(local recursive nameserver)。
解析器本身不会缓存任何DNS数据。配置本地递归服务器只需要在/etc/rc.conf中加入一行,这可以让FreeBSD主机缓存其DNS响应,同时减少网络拥塞并提高性能。
使用rc.conf变量local_unbound_enable启用本地域名服务器:
xxxxxxxxxx
# sysrc local_unbound_enable=YES
local_unbound_enable: NO -> YES
# service local_unbound start
第一次启动此服务时,unbound会自动配置。它从/etc/resolv.conf中提取系统的名称服务器,并配置自己将所有查询转发到这些服务器。然后设置过程编辑/etc/resolv.conf,将所有查询指向IP地址127.0.0.1上运行的本地名称服务器。
当你的主机进行DNS查询时,解析器查询将请求unbound。本地名称服务器检查其缓存,以查看是否有有效且未过期的查询答案。如果它没有缓存的响应,则unbound查询你首选的名称服务器。
我建议在每台不是DNS服务器的服务器上启用local_unbound。
有几种方法可以查看网络活动。FreeBSD命令netstat(8)和sockstat(1)提供了比正常情况更多的网络信息。
通过网络管理程序netstat(8)根据给定的标志显示不同的信息。netstat -w选项显示了系统正在处理多少数据包和字节。-w(wait)标志接受一个参数,即更新之间的秒数。-d(drop)标志告诉netstat包含从未进入系统的数据包的信息。以下示例netstat每5秒更新一次显示:
xxxxxxxxxx
# netstat -w 5 -d
input (Total) output
packets errs idrops bytes packets errs bytes colls drops
➊34 ➋0 ➌0 ➍44068 ➎23 ➏0 ➐1518 ➑0 ➒0
33 0 0 42610 23 0 1518 0 0
--snip--
当您输入此命令时,似乎没有任何事情发生,但几秒钟后,显示器会打印出一行信息。前三列描述入站流量,后三列描述出站流量。我们可以看到自上次更新以来接收到的数据包数量➊、自上次更新后入站流量的接口错误数量➌以及入站丢弃的数据包的数量➋。输入信息以自上次更新之后接收到的字节数➍结尾。接下来的三列显示了自上次更新之前计算机传输的数据包数➎、自从上次更新之后传输的错误数➏以及我们发送了多少字节➐。然后我们可以看到自从上次更新以来发生的网络冲突数➑和丢弃的数据包数➒。例如,在这个显示中,自netstat -w 5 -d开始运行以来,系统收到了34个数据包。
五秒钟后,netstat打印第二行,描述自打印第一行以来的活动。
你可以使输出尽可能详细,并根据需要运行它。五秒钟的间隔比较合适。
按CTRL-C可以停止报告。
另一个经典问题是“哪些端口是开放的,哪些程序在监听它们?”
FreeBSD的sockstat(1)是一个友好的工具,它显示了可供客户端使用的活动连接和端口。
sockstat(1)程序不仅列出了监听网络的端口,还列出了系统上的任何其他端口(或套接字——sockets)。使用-4标志查看IPv4套接字,使用-6查看IPv6。
【示例略】
虽然sockstat(1)提供了一个很好的网络服务可用性高级视图,但你可以通过netstat(8)获得有关单个连接的更详细信息。要查看打开的网络连接,可使用netstat -a,-n标志会告诉netstat(8)不要麻烦将IP地址转化成主机名;这种翻译不仅会减慢输出速度,还会导致输出不明确。最后,-f inet选项告诉netstat(8)只担心IPv4网络连接,而-f inet6处理IPv6。以下是一个示例:
xxxxxxxxxx
# netstat -na -f inet
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 48 203.0.113.43.22 24.192.127.92.62937 ESTABLISHED
tcp4 0 0 *.25 *.* LISTEN
tcp4 0 0 *.23 *.* LISTEN
tcp4 0 0 *.80 *.* LISTEN
tcp4 0 0 *.22 *.* LISTEN
tcp4 0 0 203.0.113.8.53 *.* LISTEN
udp4 0 0 203.0.113.8.53 *.*
在这里,我们不知道连接到任何端口的程序是什么。每列中的第一个条目是套接字使用的传输协议——主要是TCP,但最后一行显示了一个UDP。
Recv-Q和Send-Q列显示了等待此连接处理的字节数。如果您在大多数情况下看到某个连接的非零Recv-Q数,那么您就知道在该端口上侦听的程序无法足够快地处理传入数据以跟上网络堆栈。同样,如果Send-Q列一直有非零条目,那么您就知道网络或远程系统无法像您发送数据那样快速地接受数据。偶尔排队的数据包是正常的,但如果它们没有消失,您可能需要调查为什么速度很慢。你必须观察自己的系统,了解什么是正常的。
Local Address是网络连接正在侦听的本地系统上的IP地址和网络端口号。网络端口出现在条目末尾,域IP地址用句点隔开。例如203.0.113.43.22是IP地址203.0.113.43的22号端口。如果条目是星号,后跟句点和端口号,则意味着系统正在侦听所有可用IP地址上的该端口。系统已经准备好接受该端口上的连接。
Foreign Address列显示任何连接的远程地址和端口号。
最后,(stat)列显示TCP握手的状态。无需知道所有可能的TCP连接状态,只要知道什么是正常的。
上面例子中,一个TCP连接正在运行,四个已准备好接受客户端。由于UDP是无状态的,因此这些连接不列车状态信息。
通过阅读此输出并将其与sockstat(1)提供的信息相结合,你可以准确了解哪些程序表现良好,哪些程序遇到了瓶颈。
如果你对监听套接字不感兴趣,而只对那些有活动连接的套接字感兴趣,可以使用netstat -b选项。运行 netstat -nb -f inet仅显示与外部系统的连接。
还可以使用netstat -T在单个连接上显示TCP重传(retransmits)和乱序数据包(out-of-order packets)。重传和数据包排序错误是数据包丢失的症状。
FreeBSD的内核通过使用mbufs来处理网络内存。mbuf是用于网络的内核内存块。在FreeBSD网络堆栈文档中,你会不断地遇到对mbufs的提及,所以至少对它们有一个模糊的概念是很重要的。
FreeBSD在启动时根据系统中的物理RAM量自动分配网络容量。假设你有一个64GB RAM的系统,你想在网络上使用比1GBRAM的小盒子更多的内存。通过netstat -s和netstat -m查看FreeBSD如何使用其资源。让我们先看看最短的一个。
要获取用于网络的内核内存的通用视图,请运行netstat -m。输出可分为两大类:使用了多少内存和失败了多少请求。以下输出被修剪为仅包含其中的几个示例,但它们都遵循相同的通用格式:
xxxxxxxxxx
# netstat -m
--snip--
➊32/372/404/➋25600 mbuf clusters in use (current/cache/total/max)
--snip--
0/0/0 requests for mbufs ➌denied (mbufs/clusters/mbuf+clusters)
--snip--
这里我们看到使用了多少个mbuf簇➊,你可能会猜到这些簇与mbuf有关。不必确切知道mbuf集群是什么,重要的是,知道可以分配多少个➋,并且可以看到你在这个限制之下。
同样,我们可以看到内核拒绝了多少不同的mbuf请求➌。该系统没有拒绝任何mbufs请求,这意味着我们没有因为内存不足而出现性能问题。如果你的系统因为内存不足而开始拒绝mbuf请求,那么就需要参考下面的“优化网络性能”。
虽然netstat -m会生成十几行输出,但netstat -s会分类输出。它提供每协议的性能统计数据。就像netstat -m一样,你可以将这些统计数据分为完成了多少工作和遇到了多少问题的类别。偶尔在你的系统上运行这两个命令,并查看结果,以使你知道服务器上的正常情况,并在出现问题时识别异常数字。
既然能看到发生了什么,该如何提高FreeBSD的网络性能呢?
在考虑优化时,有一个简单的经验法则:don't。
网络性能通常仅受硬件的限制。许多应用程序无法像网络提供的那样快速处理数据。如果你认为你需要优化你的表现,你可能找错了方向。查看第二十一章,了解有关调查性能瓶颈的提示。
一般来说,只有当你遇到网络问题时,才应该调整网络性能。这意味着你该从netstat -m 或netstat -s获得输出,指示内存存在资源问题。如果内核开始拒绝资源请求或丢弃连接请求,请查看本书中的提示。如果你有问题,或者你认为你应该获得更好的性能,请先看看硬件。
并非所有网络硬件都是平等的。虽然IT界的任何人都经常听到这一点,但FreeBSD的开放性使这一点显而易见。例如,这是rl(4)网卡驱动源代码的注释:
xxxxxxxxxx
The RealTek 8139 PCI NIC redefines the meaning of 'low end.' This is
probably the worst PCI ethernet controller ever made, with the possible
exception of the FEAST chip made by SMC. The 8139 supports bus-master
DMA, but it has a terrible interface that nullifies any performance
gains that bus-master DMA usually offers.
(RealTek 8139 PCI NIC重新定义了“低端”的含义这可能是有史以来最糟糕的PCI以太网控制器,SMC制造的FEAST芯片可能是个例外。8139支持总线主DMA,但它有一个糟糕的接口,抵消了总线主DMA通常提供的任何性能提升。)
这可以概括为:“这张卡既糟糕又糟糕。再买一张卡。”虽然这是我在FreeBSD源代码中看到的最尖刻的评论,而且这种特殊的硬件今天很难找到,但某些其他卡的驱动程序以更礼貌的方式说了同样的话。更换廉价的网卡可能会解决您的问题。一般来说,英特尔生产的网卡不错;他们为有线网卡维护FreeBSD驱动程序,并提供支持,以便FreeBSD社区可以帮助维护驱动程序。(无线网卡是另一回事。)同样,许多制造服务器级机器的公司都强调使用服务器级网卡。一些公司提供FreeBSD驱动程序,但不提供其硬件的文档。这意味着驱动程序可能可以工作,但你完全取决于供应商未来对FreeBSD的喜爱程度。专门从事廉价消费网络设备的公司并不是您选择高性能卡的最佳选择——毕竟,普通家庭用户不知道如何选择网卡,所以他们只考虑价格。如有疑问,请查看FreeBSD问题邮件列表档案,了解最新的网卡建议。
同样,交换机质量差异很大。声称千兆的交换机,并以不意味着你实际上可以通过每个端口实现千兆速度。在生产环境中,不要使用为家庭设计的交换机。
FreeBSD使用系统中安装的内存量来决定为mbufs保留多少内存空间。除非netstat -m告诉你缺少mbuf空间,否则不要调整你创建mbuf的数量。如果你有一个mbuf问题,真正的解决方法是给你的机器添加内存。这将使FreeBSD重新计算启动时创建的mbuf数量,并解决你的问题。否则,你只会将问题转移到系统的不同部分或不同的应用程序。你可能会为网络连接配置了大量内存,并现象你已经扼杀了数据库服务。如果你确定要继续,可以按照以下方法操作。
两个sysctl值控制mbuf分配,即kern.maxusers和kern.ipc.nmbclusters。
kern.maxusers是一个启动时可调的程序。你的系统在启动时会自动从系统硬件中确定适当的kern.maxusers值。调整此值可能是扩展整个系统的最佳方法。在FreeBSD的旧版本中,kern.maxusers为网络预先分配了内存,并拒绝将其释放用于其他任务,因此增加kern.maxusers可能会严重影响系统的其他部分。然而,现代FreeBSD并不预先分配网络内存,所以这只是对网络内存呢的上限。如果kern.maxusers太小,你将在/var/log/messages中受到警告(参阅第二十一章)。
kern.ipc.nmbclusters专门控制系统为套接字缓冲区中等待发送到应用程序或由应用程序读取的数据分配的mbuf数量。虽然这是运行时可调的,但最好在启动时尽早设置,在/etc/sysctl.conf中定义它。然而,如果你把这个值设置得太高,你实际上可能会耗尽内存内核以执行其他任务,并使机器死机。
xxxxxxxxxx
# sysctl kern.ipc.nmbclusters
kern.ipc.nmbclusters: 25600
mbufs以称为nmbclusters(有时称为mbuf clusters)的单位分配。虽然mbuf的大小各不相同,但一个集群的大小约为2KB。你可以使用简单的数学计算出当前nmbcluster设置需要多少RAM,然后为你的系统和应用程序计算合理的值。此示例机器具有25600 nmbcluster,这意味着内核最多可以使用约50MB RAM用于网络目的。这并不大,但在嵌入式系统上明显不合适。
要计算适当数量的mbuf集群,请在服务器非常繁忙时运行netstat -m。输出的第二行将为你提供正在使用的mbuf数量和可用的总数。如果你最繁忙的服务器使用的nmbcluster没有达到可用的数量,那么你找错了方向——停止使用mbufs,更换硬件。例如:
xxxxxxxxxx
➊32/372/➌404/➍25600 mbuf clusters in use (current/cache/total/max)
此系统当前在此计算机上使用32个nmbcluster➊,并缓存了372个以前使用的nmbclusters➋。此时内存中总共有404个集群➌,因此我们25600个集群➍的容量利用率为1.5%。如果这是您的真实系统负载,那么实际上减少nmbcluster的数量可能是有意义的。
我的个人经验法则是,服务器应该有足够的mbuf来处理其标准高负载的两倍。如果你的服务器在高峰时段使用25000 nmbcluster,那么它应该至少有50000个可用资源来处理这些短暂的不规则峰值。
始终将一生一次的事件规划与正常负载规划区分开来。
FreeBSD内核提供了处理一定数量的新TCP连接的能力。这不是指服务器之前接收到并正在处理的连接,而是指试图同时启动连接的客户端。例如,当前交付给客户端的网页不计算在内,但已达到内核并未到达web服务器进程的传入请求计算在内。这是一个非常窄的窗口,但一些网站确实会溢出(overflow)它。
kern.ipc.somaxconn规定了系统将尝试处理的同时连接尝试次数。默认值为128,对于高负载的web服务器来说可能不够。如果你运行的是高容量服务器,预计会同时收到128个以上的新请求,则可能需要增加此sysctl。如果用户开始抱怨他们无法连接,这可能是你的锅。当然,很少有应用程序会同时接受这么多新连接。在达到这一点之前,你可能需要更好地调整你的应用程序。
一些千兆网卡可以通过轮询(polling)来提高性能。轮询采用了历史悠久的中断和IRQ概念,并将其推出窗口,代之以定期检查网络活动。在经典的中断驱动模型中,每当数据包到达网卡时,网卡都会通过产生中断来引起CPU的注意。CPU停止它正在做的任何事并处理这些数据。当网卡不处理大量流量时,这是伟大的,甚至是可取的。然而,一旦系统开始处理大量数据,该卡就会持续产生中断。如果内核定期从卡中获取网络数据,系统将更高效,而不是不断中断。这种定期检查称为轮询。一般来说,只有当你推送大量流量时,轮询才有用。
在撰写此文时,轮询还不能作为内核模块使用,因为它需要修改设备驱动程序。这也意味着并非所有网卡都支持轮询,因此务必检查polling(4)以获取完整列表。通过在内核配置中添加DEVICE_POLLING来启用轮询。重启后,使用ifconfig(8)在每个接口的基础上启用轮询。
xxxxxxxxxx
# ifconfig em0 polling
同样,使用参数-polling禁用轮询。如果接口上启用了轮询,ifconfig(8)命令也会显示。由于您可以动态启用和禁用轮询,因此请在系统负载较重时启用轮询,并查看性能是否有所提高。 轮询仅用于旧卡。10GB卡和更快的卡无法轮询。
FreeBSD大约有200个与网络相关的系统。你拥有所需的所有工具,可以极大地优化你的系统,使其不再通过任何流量。使用网络优化时要非常小心。许多看似解决问题的设置实际上只解决了一组问题,但同时可能引入一系列全新的问题。
一些软件供应商(即Samba)建议对特定的网络sysctl进行更改。谨慎食用。在接受它们作为新的默认值之前,注意对其他程序的意外副作用。TCP/IP是一个极其复杂的协议,FreeBSD的默认设置和自动调整反映了多年的经验、测试和系统管理员的痛苦。
请记住,FreeBSD已经有二十多年的历史了。几年前的邮件列表和论坛帖子可能对网络调优没有帮助。
随着网络服务器对业务越来越重要,冗余变得越来越重要。服务器中有冗余硬盘,数据中心有冗余带宽,但服务器中的冗余带宽呢?在较小的范围内,当你在办公室走动时,你可能会在无线和有限连接之间移动你的笔记本电脑。最好不要因为拔下电缆而失去现有的SSH会话。
FreeBSD可以将两个网卡视为一个实体,允许你使用单个交换机进行多个连接。这通常被称为网络适配器组队(network adapter teaming)、绑定(bonding)或链路聚合(link aggregation)。FreeBSD通过链路聚合接口lagg(4)实现适配器组。
一些供应商使用trunk这个词来描述链路聚合。其他供应商使用“trunk”一词来描述一条具有多个网络(VLAN)的电缆。FreeBSD通过不使用trunk这个词来避免这种争论。如果有人当着你的面开始讨论行trunks,问问他们在说什么。
内核模块lagg(4)提供了一个lagg0虚拟接口。你将物理接口分配给lagg0接口,使其成为聚合链接的一部分。虽然你可以将lagg(4)仅用于一个物理接口,但聚合链接只有在你有两个或多个物理接口要分配给聚合链接时才有意义。lagg(4)模块允许你在有线和无线网络之间实现无缝漫游、故障转移和几种不同的聚合协议。
并非所有网络交换机都支持所有链路聚合协议。FreeBSD有一些复杂的高端协议的基本实现,还包括非常基本的故障转移设置。我推荐的三个是Fast EtherChannel(快速以太网通道)、LACP(链路聚合控制协议)、failover(故障转移)。
lagg接口是虚拟的,这意味着任何物理接口都不会被命名为lagg0。
在配置接口之前,你必须先创建它。FreeBSD允许使用ifconfig interfacename create创建接口,也可以在/etc/rc.conf中使用cloned_interfaces语句来创建接口。
在rc.conf中配置lagg(4)接口有三个步骤:创建接口、启动物理接口和聚合它们。
以下示例中,我们用两个Intel千兆以太网卡em0和em1创建了一个单一的lagg0接口:
xxxxxxxxxx
cloned_interfaces="lagg0"
ifconfig_em0="up"
ifconfig_em1="up"
ifconfig_lagg0="laggproto lacp laggport em0 laggport em1 inet 203.0.113.1/24"
首先,将lagg0列为克隆接口,因此FreeBSD将在启动时创建此接口。然后打开接口em0和em1,但不对其进行配置。最后,告诉lagg0接口要使用什么聚合协议(此例中为lacp),哪些物理接口属于它,以及它的网络信息。这几行配置为你提供了高可用性的以太网连接。
VLAN——virtual LAN,虚拟局域网,允许你在一根网线上获得多个以太网段。你有时会看到称为802.1q、tagging或这些术语的组合的VLAN。
你可以通过配置连接到物理接口的其他逻辑接口来使用这些多个网络。然而,物理线路仍然只能承载一定数量的数据,因此共享线路的所有VLAN和常规网络都使用公共带宽池。如果你需要同时在多个以太网段上使用FreeBSD,这是一种不需要铺设更多电缆的方法。
到达网卡的VLAN帧类似于常规以太网帧,标记有一个额外的标头,注明这是VLAN编号的一部分。每个VLAN都由1到4096的标签标识。本机VLAN到达时没有任何标记。网络经常在内部调用此VLAN 1。
在FreeBSD主机上配置VLAN并不能将主机连接到VLAN。网络配置为将这些VLAN发送到你的主机,你必须与网络团队合作才能访问VLAN。
使用ifconfig(8)可以创建VLAN接口。你必须知道物理接口和VLAN标签(tag):
xxxxxxxxxx
# ifconfig interface.tag create vlan tag vlandev interface
下面我创建为VLAN 2创建一个接口,然后将em0接口附加上去:
xxxxxxxxxx
# ifconfig em0.2 create vlan 2 vlandev em0
现在我可以用物理接口的方式配置接口em0.2:
xxxxxxxxxx
# ifconfig em0.2 inet 192.0.2.236/28
实际上,我可以在一个命令中完成以上两步操作:
xxxxxxxxxx
# ifconfig em0.2 create vlan 2 vlandev em0 inet 192.0.2.236/28
完成了,现在使用ifconfig(8)显示你的新接口:
xxxxxxxxxx
# ifconfig em0.2
em0.2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=503<RXCSUM,TXCSUM,TSO4,LRO>
ether 00:25:90:db:d5:94
inet 198.22.65.236 netmask 0xffffff00 broadcast 255.255.255.240
inet6 fe80::225:90ff:fedb:d594%em0.2 prefixlen 64 scopeid 0x6
nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
➊ media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
➋ vlan: 2 vlanpcp: 0 parent interface: em0
➌ groups: vlan
这看起来几乎与任何其他物理接口完全相同。媒体信息➊直接来自底层接口。您将看到一个带有VLAN信息➋的标签,并注意到它与其他VLAN接口➌分组。
使用rc.conf变量配置在启动时启用VLAN。首先,使用标记有接口名称的vlan_变量列出连接到该接口的VLAN。此处,我告诉FreeBSD在接口em0上启用VLAN 2和3,并为每个VLAN分配一个IP配置:
xxxxxxxxxx
vlans_em0="2 3"
ifconfig_em0_2="inet 192.0.2.236/28"
ifconfig_em0_3="inet 198.51.100.50/24"
如果底层接口没有配置,你至少要将其打开。除非物理接口打开,否则VLAN接口将无法工作:
xxxxxxxxxx
ifconfig_em0="up"
现在,您在启动时有了虚拟局域网。祝贺 你!
现在您已经有了一个可用的网络,让我们在本地多看一点,看看基本的系统安全。