3.6、ipvs數據包發送
IPVS連接中的數據包的發送方法是由ip_vs_bind_xmit()(net\netfilter\ipvs\ip_vs_conn.c中)函數定義的,具體的發送數據包處理函數定義在net\netfilter\ipvs\Ip_vs_xmit.c文件中
int
ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
NAT發送只發送請求方向的數據,因此是進行目的NAT
int
ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
TUNNEL發送是把原來的IP部分再加在一個IPIP協議(4)頭后發出去,新頭的目的IP是真實目的服務器,源IP是真實客戶端IP,該包是可以路由的,服務器的回應包將直接路由回去而不經過IPVS.
int
ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
DR發送是將原來的skb包中的目的MAC地址修改為目的服務器的MAC地址后直接發出,因此是不能路由的,IPVS均衡設備和目的服務器物理上必須在同一個二層子網。在DR模式下,IPVS和服務器都配置了相同的對外服務的VIP,服務器也配了自己的真實IP,不過服務器上配VIP的網卡屬性中的NOARP信息是打開的,就是在該網卡上不響應ARP信息,但可以接收到達該VIP的數據包,這樣外面請求包先是到IPVS均衡器,因為IPVS的VIP是響應ARP的,然后根據調度找一台服務器,用服務器的真實IP來確定路由,然后直接把包發出來,這時包中所有數據都沒修改,因為目的服務器上VIP地址符合包中的目的地址,因此是可以接收該包的。
int
ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
旁路模式,實際數據包不是給IPVS均衡器自己的,由IPVS進行轉發
int
ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, int offset, unsigned int hooknum)
發送各種ICMP錯誤信息包
3.7、ipvs的應用管理
IPVS的應用是針對象FTP等的多連接協議處理的,由於多連接協議的特殊性,任何以連接為基礎進行處理的模塊如IPVS,netfilter等都必須對這些協議特別處理,不過IPVS相對沒有netfilter那么完善,目前也僅僅支持FTP協議,而netfilter已經可以支持FTP、TFTP、IRC、AMANDA、MMS、SIP、H.323等多種多連接協議。
IPVS應用也是模塊化的,不過其實現有點特別,對於每一個應用協議,會定義一個靜態的struct ip_vs_app結構作為模板,以后登記該協議時,對應的應用指針並不是直接指向這個靜態結構,而是新分配一個struct ip_vs_app結構,結構中的struct ip_vs_app指針指向這個靜態結構,然后把新分配的這個結構分別掛接到靜態struct ip_vs_app結構的具體實現鏈表和IP協議的應用HASH鏈表中進行使用,這種實現方法和netfilter完全不同。
IPVS應用一些共享的處理函數在net\netfilter\ipvs\ip_vs_app.c中定義,其他各協議相關處理分別由各自文件處理,如net\netfilter\ipvs\ip_vs_ftp.c.
3.8、ipvs的主備同步
IPVS支持對連接的同步,兩台IPVS設備可分別以MASTER或BACKUP運行,MASTER進程可將連接信息備份到BACKUP設備上,這樣主設備死機時從設備可以無縫切換。
可以在IPVS設備上同時啟動MASTER和BACKUP進程,使設備之間互為備份,實現IPVS設備的均衡。
IPVS同步實現在net\netfilter\ipvs\ip_vs_sync.c中
3.9、ipvs預估器
IPVS預估器用的估算在一個短暫時間間隔內的連接率,可在用戶空間開一個daemon定時讀取預估器的值以實現較長時間的預估。
預估算法為:
取最后8秒鍾內,每兩秒取一個采樣點進行平滑處理:
avgrate = avgrate*(1-W) + rate*W
其中 W = 2^(-2) = 0.25,速率單位是KBytes/s
預估代碼在net\netfilter\ipvs\ip_vs_est.c中實現。
3.10、ipvs的/proc參數
ipvs在/proc目錄下建立了以下文件:
/proc/net:
/proc/net/ip_vs:IPVS的規則表
/proc/net/ip_vs_app:IPVS應用協議
/proc/net/ip_vs_conn:IPVS當前連接
/proc/net/ip_vs_stats:IPVS狀態統計信息
/proc/sys/net/ipv4/vs:
/proc/sys/net/ipv4/vs/am_droprate:丟包率(缺省10)
/proc/sys/net/ipv4/vs/amemthresh:可用內存閾值(缺省1024)
/proc/sys/net/ipv4/vs/cache_bypass:是否建立旁路cache項
/proc/sys/net/ipv4/vs/debug_level:調試級別
/proc/sys/net/ipv4/vs/drop_entry:確定刪除連接處理級別
/proc/sys/net/ipv4/vs/drop_packet:丟包級別
/proc/sys/net/ipv4/vs/expire_nodest_conn:是否刪除沒有目的服務器的連接
/proc/sys/net/ipv4/vs/lblc_expiration:lblc算法的到期時間(缺省1天)
/proc/sys/net/ipv4/vs/lblcr_expiration:lblcr算法的到期時間(缺省1天)
/proc/sys/net/ipv4/vs/nat_icmp_send:NAT模式下連接異常時發送ICMP包
/proc/sys/net/ipv4/vs/secure_tcp:更安全的TCP狀態轉換
/proc/sys/net/ipv4/vs/sync_threshold:連接同步時的包數閾值數值
/proc/sys/net/ipv4/vs/timeout_close:TCP sCL狀態超時
/proc/sys/net/ipv4/vs/timeout_closewait:TCP sCW狀態超時
/proc/sys/net/ipv4/vs/timeout_established:TCP sES狀態超時
/proc/sys/net/ipv4/vs/timeout_finwait:TCP sFW狀態超時
/proc/sys/net/ipv4/vs/timeout_icmp:ICMP超時
/proc/sys/net/ipv4/vs/timeout_lastack:TCP sLA狀態超時
/proc/sys/net/ipv4/vs/timeout_listen:TCP sLI狀態超時
/proc/sys/net/ipv4/vs/timeout_synack:TCP sSA狀態超時
/proc/sys/net/ipv4/vs/timeout_synrecv:TCP sSR狀態超時
/proc/sys/net/ipv4/vs/timeout_synsent:TCP sSS狀態超時
/proc/sys/net/ipv4/vs/timeout_timewait:TCP sTW狀態超時
/proc/sys/net/ipv4/vs/timeout_udp:UDP超時
3.11、ipvs控制
ipvs控制包括定義IPVS提供的虛擬服務參數和實際的目的服務器等各種參數。
ipvs的控制信息是通過setsockopt系統調用傳遞到內核的,ipvs在用戶層的管理工具是ipvsadm。
關於ipvs控制代碼在net\netfilter\ipvs\ip_vs_ctl.c中。
3.11.1、注冊sockopt
static struct nf_sockopt_ops ip_vs_sockopts = {
.pf = PF_INET,
.set_optmin = IP_VS_BASE_CTL,
.set_optmax = IP_VS_SO_SET_MAX+1,
.set = do_ip_vs_set_ctl,
.get_optmin = IP_VS_BASE_CTL,
.get_optmax = IP_VS_SO_GET_MAX+1,
.get = do_ip_vs_get_ctl,
.owner = THIS_MODULE,
};
借用netfilter的struct nf_sockopt_ops結構來添加
在int __init ip_vs_control_init(void)函數中調用
ret = nf_register_sockopt(&ip_vs_sockopts);來注冊sockopt
static int
do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
寫控制
static int
do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
讀控制
3.11.2、服務控制
static int
ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
struct ip_vs_service **svc_p)
添加服務
static int
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
修改服務和綁定一個新的調度器
static int ip_vs_del_service(struct ip_vs_service *svc)
刪除服務
static int ip_vs_flush(struct net *net)
刪除所有服務
static int ip_vs_zero_service(struct ip_vs_service *svc)
清除服務計數器
3.11.3、真實服務器管理
static int
ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
添加一個真實服務器到一個已存在的虛擬服務
static int
ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
struct ip_vs_dest **dest_p)
在一個虛擬服務中創建一個真實服務器結構
static int
ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
修改真實服務器
static int
ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
在一個虛擬服務中刪除真實服務器
static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest)
刪除一個真實服務器(必須已與虛擬服務解綁)
static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
struct ip_vs_dest *dest,
int svcupd)
在一個虛擬服務中解綁真實服務器
3.11.4、防御級別調整
static void defense_work_handler(struct work_struct *work)
定時處理函數
static void update_defense_level(struct netns_ipvs *ipvs)
更新IPVS的防御級別,需要用到/proc下定義的一些控制參數
4、學習總結
對於對linux內核不了解的人來說,最開始看ipvs和ipvsadm代碼時會一頭霧水,但對內核編程初步了解與看yfydz老大的實現分析系列文章后使我茅塞頓開。ipvs的結構體定義與功能函數實現一目了然,某些關鍵細節還沒有看的很透徹,不過已可以定位關鍵點了。ipvsadm與ipvs之間的控制通信通過setsockopt實現,對照看一些結構體的填充與用戶層和內核之間的數據傳遞,可對控制工作流程有直觀的了解。最后挖掘的地方就是數據包修改功能與調度策略的算法實現,這樣使我對ipvs的代碼實現熟悉起來。希望我整理的函數列表會對大家有幫助,一直看yfydz的大篇注釋有點暈,需要了解的地方再跟進查看吧,感謝ipvs作者與yfydz的技術分享。