Linux下安装编译IPVS内核模块
2017-12-27 14:11:29 阿炯

本文记述了在crux 3.3 x64下安装LVS的内核功能模块(IP virtual server support)的过程。

一般的编译步骤:
1) 在/usr/src/linux/下运行make menuconfig把需要编译成模块的项打上(M),保存并退出。

2) 运行make modules,这一步将在/usr/src/linux/下生成*.o或*.ko文件。

3) 运行make modeules_install来安装,这步会把生成的.o或ko文件拷贝到/lib/modules/`uname -r`/下。

如果你只要编译某一个或几个模块,就可以用下面这个快速的方法:

(1) 找到编译内核所需要的.config文件。
在/usr/src/linux/arch目录下有若干编译内核所用的配置。选择我们想要的配置,将它复制到/usr/src/linux目录下,改名为.config。
cp -fv /usr/src/linux/arch/x86_64/xxconfig /usr/src/linux/.config

(2) 修改.config文件,去掉不用的模块,加上自己想要的模块。
打开.config,有许多XXXX=m的项,这些都是要被编译 为模块的项,因为我们不希望编译这些模块,所以要把XXXX=m的项统统去掉。然后再加上我们想要的模块,例如将# CONFIG_NTFS_FS is not set 改为CONFIG_NTFS_FS=m 当然,可以用你熟悉各种工具来做这件事。再以IP_VS模块为例:
CONFIG_IP_VS=m
CONFIG_IP_VS_DEBUG=y
CONFIG_IP_VS_TAB_BITS=12
# IPVS transport protocol load balancing support
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y

# CONFIG_IP_VS_PROTO_AH is not set
# CONFIG_IP_VS_PROTO_SCTP is not set
# IPVS scheduler
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_FO=m
...

(3) 编译NTFS模块。
在/usr/src/linux目录下运行命令make modules来编译我们想要的模块。

(4) 安装模块。
编译后得到的.o文件在/usr/src/linux/目录下,手动将它复制到正确的目录下。例如:
cp /usr/src/linux/fs/ntfs/ntfs.o /lib/modules/kernel-version/fs/

注意:这里千万不能运行命令make modules_install,否则将带来严重的后果,它会删除你系统中的所有模块,只安装刚刚编译的模块(ntfs.o)。要么就使用下面的指令来安装,经过证明是安全的(v4.9):
cd /usr/src/linux-4.9.x
make menuconfig
make all
make modules_install
cp arch/x86_64/boot/bzImage /boot/vmlinuz
cp System.map /boot

Linux中加载模块有关的几个命令分别如下:
depmod,modprobe,lsmod

depmod:

depmod是一个用来产生modules.dep和map文件的程序。在modules.dep文件中空白行和以'#'开头的行将被忽 略.depmod通过读取/lib /modules/version目录下的每一个模块来创建一个记录模块相依性的列表。这个列表就是/lib/modules/version目录下的 modules.dep。depmod也会在/lib/modules/version目录下创建许多map文件,例如 modules.dep,modules.isapnpmap,modules.pcimap,modules.alias这些文件将会被hotplug用到。

OPTIONS
-a --all Probe all modules. This option is enabled by default if no file names are given in the command-line.
检查所有的模块,这个命令是默认的如果你没有指定模块名字的话。
-A --quick This option scans to see if any modules are newer than the modules.dep file before any work is done.

modprobe:

modprobe 命令是根据depmod -a的输出/lib/modules/version/modules.dep来加载全部的所需要模块,可以通过modprobe -l来显示可以当前可以加载的模块。modprobe 在挂载模块是不用指定模块文件的路径,也不用带文件的后缀.o 或.ko, 而insmod 需要的是模块的所在目录的绝对路径,并且一定要带有模块文件名后缀的(modulefile.o 或modulesfile.ko)。 insmod比较重要的用途是用来测试模块的正确性,加载一般都是依靠modprobe。

用法:modprobe xxx.ko        #加载某个模块
modprobe -r xxx.ko     #卸载某个模块

lsmod:

lsmod 显示当前加载的所有 模块,相当于cat /proc/modules,假设你没有设定开机加载某个模块,比如ntfs,那么开机后执行lsmod,列表里不会有ntfs这个模块的,这时你再执行 mount -t ntfs 后,执行lsmod后列表里就会有ntfs这个模块了。还要注意的是lsmod显示的是模块名,而不是别名(alias)。

在内核中有一个"Automatic kernel module loading"功能被编译到了内核中,当用户尝试打开某类型的文件时,内核会根据需要尝试加载相应的模块。

内核模块加载的配置:

有时候需要一次性加载许多模块,需要在一个地方统一配置modprobe的选项等,有一个比较重要的文件:/etc/modprobe.conf,在openSUSE中, 和它有关的还有modprobe.d/文件夹下的许多文件和modprobe.conf.local文件,在 /etc/modprobe.conf里会include其它所说的文件,一般建议在modprobe.conf.local中修改自己的配置。/etc/modprobe.conf其实就是用于写入模块的加载命令或模块的别名的定义等。man modprobe.conf

alias my-mod really_long_modulename为模块定义一个便于使用的别名

options modulename option...在加载模块时添加选项

install modulename command...使用自己定义的命令去加载指定的模块,如 "install fred /sbin/modprobe barney; /sbin/modprobe --ignore-install fred" 每次加载fred模块的时候用的是 "/sbin/modprobe barney; /sbin/modprobe --ignore-install fred"命令

remove modulename command...用自己定义的命令删除指定的模块

include filename 引入其它文件

blacklist modulename 不再加载某个模块

内核模块开机自动挂载:

对于开机自动挂载模块,在Red Hat系统里,网上说在内核启动的过程中,init执行/etc/rc.d/rc.sysinit后,启动内核外挂模块时会读取/etc/modprobe.conf这个文件。在2.4的内核中, 只要直接修改/etc/modprobe.conf加入install xxx即可。2.6内核则需修改/etc/rc.d/rc.sysinit文件。

Linux如何在系统启动时自动加载模块

为搞清楚如何在系统启动时自动加载模块,搜索了好久,网上有很多人提出这个问题,但都没有正确的答案,无论是中文社区还是英文社区,大家的回答都没 有讲到点子上,无非是围绕 modprobe.conf、modprobe讲来讲去的,要不就是针对特定问题尝试不同的方法。有的还建议把modprobe modulename写入rc.local,却不曾想,rc.local的执行被放在整个启动顺序的很后面,而启动init.d下面定义的服务却在rc.local前面,那么如果某个服务要用这个模块,就不行了。

ip_vs.ko是IPVS的基本模块,不加载IPVS就不能工作(运行ipvsadm会报错的),而其他的都是IPVS的调度算法或特定协议的辅助模块,需要时则须加载。

如果系统运行时手动加载则需:modprobe ip_vs 和modprobe ip_vs_sh等。

要了解如何在系统启动时自动加载模块(Automatically load kernel modules),就得先了解系统是如何启动的,启动的过程中按什么顺序做了什么,怎么做的,这些启动操作都有那些文件和脚本控制。由于Google和 Baidu出来的东西都解决不了问题,而且man modprobe和man modprobe.conf发现并不是需要修改的文件。

于是温习鸟哥的  "开机关机流程与Loader":
1. 整个开机流程是
(1)载入BIOS的硬件信息,并取得第一个开机装置的代号
(2)读取第一个开机装置的MBR的boot Loader (grub)的开机信息
(3)载入OS Kernel信息,解压Kernel,尝试驱动硬件
(4)Kernel执行init程序并获得run-lebel信息(如3或5)
(5)init执行 /etc/rc.d/rc.sysinit
(6)启动内核外挂模块 (/etc/modprobe.conf)
(7)init执行run-level的各种Scripts,启动服务
(8)init执行 /etc/rc.d/rc.local
(9)执行 /bin/login,等待用户Login
(10)Login后进入Shell

看来正确的方式是把需要加载的模块放在(5)或(6),但正如网络上很多人的尝试,修改modprobe.conf都没有成功(例如在 modprobe.conf中增加install ip_vs...)。于是我修改了/etc/rc.d/rc.sysinit就成功加载了。

初步尝试在rc.sysinit最后增加 modprobe.conf ip_vs,重启后lsmod | grep ip_vs,发现成功自动加载了(RedHat Linux)。

于是仿效rc.sysinit中其他模块的加载方法,扩展改脚本文件,在最后增加下来一段:
# load LVS IPVS modules
if [ -d /lib/modules/$unamer/kernel/net/ipv4/ipvs ]; then
for module in /lib/modules/$unamer/kernel/net/ipv4/ipvs/* ; do
module=${module##*/}
module=${module%.ko}
modprobe $module >/dev/null 2>&1
done
fi
就把/lib/modules/kernel-version/kernel/net/ipv4/ipvs/下的所有模块都自动加载了,其中:
if语句检查ipvs模块的目录是否存在
for循环遍历该目录下面的所有文件
module=${module##*/}:其中##表示从前面删除字符,*/表示删除到最后一个/,如果一个#就表示只删除到第一个/。如果变量后面接##,表示在##后面的字符串取最长的(一直到最后面),如果接#,表示取最小的一段。
module=${module%.ko}:表示从后面删除.ko。如果变量后面接%%,表示在%%后面的字符串取最长的(一直到最前面),如果接%,表示取最小的一段。这样多module的两次修改就得到了模块名,就是文件名不带路径和.ko后缀。
modprobe $module >/dev/null 2>&1:加载模块,输出都指向空设备

这样重启后lsmod | grep ip_vs就会得到

IPVS在内核源码中的位置

ipvs模块自2.6后就内置在内核中,那么它位于在哪个编译菜单目录下呢?

Networking support->< >   Virtual (secure) IP: tunneling (NEW) [结果验证为不是]

  x Symbol: NETFILTER_XT_MATCH_IPVS [=n]                                                                                                  x  
  x Type  : tristate                                                                                                                      x  
  x Prompt: "ipvs" match support                                                                                                          x  
  x   Location:                                                                                                                           x  
  x     -> Networking support (NET [=y])                                                                                                  x  
  x       -> Networking options                                                                                                           x  
  x (1)     -> Network packet filtering framework (Netfilter) (NETFILTER [=n])                                                            x  
  x           -> Core Netfilter Configuration                                                                                             x  
  x             -> Netfilter Xtables support (required for ip_tables) (NETFILTER_XTABLES [=n])                                            x  
  x   Defined at net/netfilter/Kconfig:1221                                                                                               x  
  x   Depends on: NET [=y] && INET [=y] && NETFILTER [=n] && NETFILTER_XTABLES [=n] && IP_VS [=n] && NETFILTER_ADVANCED [=n] && NF_CONNTR

具体位置:
Networking support→ Networking options→ Network packet filtering framework (Netfilter→ IP virtual server support

make modules_install

INSTALL net/netfilter/ipvs/ip_vs.ko
INSTALL net/netfilter/ipvs/ip_vs_dh.ko
INSTALL net/netfilter/ipvs/ip_vs_fo.ko
INSTALL net/netfilter/ipvs/ip_vs_lblc.ko
INSTALL net/netfilter/ipvs/ip_vs_lblcr.ko
INSTALL net/netfilter/ipvs/ip_vs_lc.ko
INSTALL net/netfilter/ipvs/ip_vs_nq.ko
INSTALL net/netfilter/ipvs/ip_vs_ovf.ko
INSTALL net/netfilter/ipvs/ip_vs_rr.ko
INSTALL net/netfilter/ipvs/ip_vs_sed.ko
INSTALL net/netfilter/ipvs/ip_vs_sh.ko
INSTALL net/netfilter/ipvs/ip_vs_wlc.ko
INSTALL net/netfilter/ipvs/ip_vs_wrr.ko
 
cp -fv arch/x86_64/boot/bzImage /boot/vmlinuz
cp -fv System.map /boot

在crux下,只要启动keepalived进程,系统就会自动加载ip_vs模块进入内核,否则不会加载该模块,很是智能。估计新版本都是这么智能的,不会再有上述的手动或修改脚本来加载的情况吧。

摘自于金步国主页上的Linux-4.4-x86_64 内核配置选项简介中的片断

IP virtual server support
CONFIG_IP_VS

IPVS(IP Virtual Server)支持.IPVS可以帮助LVS基于多个后端真实服务器创建一个高性能的虚拟服务器.可以使用三种具体的方法实现:NAT,隧道,直接路由(使用较广).

IPv6 support for IPVS
CONFIG_IP_VS_IPV6
为IPVS添加IPv6支持

IP virtual server debugging
CONFIG_IP_VS_DEBUG
为IPVS添加调试支持

IPVS connection table size (the Nth power of 2)
CONFIG_IP_VS_TAB_BITS
设置IPVS连接哈希表的大小(2CONFIG_IP_VS_TAB_BITS),取值范围是[8,20],默认值12的意思是哈希表的大小是212=4096项.IPVS连接哈希表使用链表来处理哈希碰撞.使用大的哈希表能够显著减少碰撞几率,特别是哈希表中有成千上万连接的时候.比较恰当的值差不多等于每秒的新建连接数乘以每个连接的平均持续秒数.太小的值会造成太多碰撞,从而导致性能大幅下降;太大的值又会造成占用太多不必要的内存(每个表项8字节+每个连接128字节).该值也可以通过ip_vs模块的conn_tab_bits参数进行设置

TCP load balancing support
CONFIG_IP_VS_PROTO_TCP
TCP传输协议负载均衡支持

UDP load balancing support
CONFIG_IP_VS_PROTO_UDP
UDP传输协议负载均衡支持

ESP load balancing support
CONFIG_IP_VS_PROTO_ESP
IPSec ESP(Encapsulation Security Payload)传输协议负载均衡支持

AH load balancing support
CONFIG_IP_VS_PROTO_AH
IPSec AH(Authentication Header)传输协议负载均衡支持

SCTP load balancing support
CONFIG_IP_VS_PROTO_SCTP
SCTP传输协议负载均衡支持

round-robin scheduling
CONFIG_IP_VS_RR
循环分散算法:最简单的调度算法,将连接简单的循环分散到后端服务器上

weighted round-robin scheduling
CONFIG_IP_VS_WRR
基于权重的循环分散算法:在循环分散的基础上,权重较高的后端服务器接纳较多的连接

least-connection scheduling
CONFIG_IP_VS_LC
最少连接算法:将连接优先分配到活动连接最少的后端服务器

weighted least-connection scheduling
CONFIG_IP_VS_WLC
基于权重的最少连接算法:结合考虑活动连接数与服务器权重

locality-based least-connection scheduling
CONFIG_IP_VS_LBLC
基于目的IP的最少连接算法(常用于缓存集群):优先根据目的IP地址将连接分配到特定的后端,仅在这些后端过载时(活动连接数大于其权重)才分散到其他后端

locality-based least-connection with replication scheduling
CONFIG_IP_VS_LBLCR
与LBLC类似,不同之处在于:前端负载均衡器会像NAT一样同时记住客户端IP与后端的对应关系,并在新的连接到来的时候,复用这个对应关系

destination hashing scheduling
CONFIG_IP_VS_DH
目标地址哈希表算法:简单的根据静态设定的目标IP地址哈希表将连接分发到后端

source hashing scheduling
CONFIG_IP_VS_SH
源地址哈希表算法:简单的根据静态设定的源IP地址哈希表将连接分发到后端

shortest expected delay scheduling
CONFIG_IP_VS_SED
最小期望延迟算法:将连接分配到根据期望延迟公式((Ci+1)/Ui)算得的延迟最小的后端."i"是后端服务器编号,"Ci"是该服务器当前的连接数,"Ui"是该服务器的权重

never queue scheduling
CONFIG_IP_VS_NQ
无排队算法:这是一个两阶段算法,如果有空闲服务器,就直接分发到空闲服务器(而不是等待速度最快的服务器),如果没有空闲服务器,就分发到期望延迟最小的服务器(SED算法)

IPVS source hashing table size (the Nth power of 2)
CONFIG_IP_VS_SH_TAB_BITS
将源IP地址映射到后端服务器所使用的哈希表的大小(2CONFIG_IP_VS_SH_TAB_BITS),取值范围是[4,20],默认值8的意思是哈希表的大小是28=256项.理想的大小应该是所有后端的权重乘以后端总数?

FTP protocol helper
CONFIG_IP_VS_FTP
FTP协议连接追踪帮助

Netfilter connection tracking
CONFIG_IP_VS_NFCT
Netfilter连接追踪支持

SIP persistence engine
CONFIG_IP_VS_PE_SIP
基于SIP Call-ID提供持久连接支持