(8)__ip_masq_put
格式:static __inline __void __ip_masq_put(struct ip_masq *ms)
返回值:无
处理流程:
1. 将ms的访问计数减一。
(9)get_next_mport
格式:static __u16 get_next_mport(void)
返回值:返回一个16位的端口号。
处理流程:
1. 为masq_mport_lock加旋转锁。
2. Mport = htons(masq_port ++)。
3. 如果masq_port是最后一个锁,则masq_port = 开始锁。
4. 解旋转锁masq_port_lock。
5. 返回mport。
(10)ip_masq_new
格式:struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
返回值:成功:返回ms;失败:返回null。
处理流程:
1. 如果没有可用端口,返回NULL。
2. 若mflags 设IP_MASQ_F_USER位,则 prio = GFP_KERNEL;不然, prio=GFP_ATOMIC。
3. 为ms分配空间,若失败,返回NULL。
4. MOD_INC_USE_CONUNT。
5. 清空ms。
6. 初始化ms->timer。
7. ms->timer.data = (unsigned long)ms;
ms->timer.function = masq_expire;
ms->protocol = proto;
ms->saddr = saddr;
ms->sport = sport;
ms->daddr = daddr;
ms->dport = dport;
ms->flags = NULL;
ms->app_data = NULL;
ms->control = NULL;
设ms->n_control 为0;
设ms->refcnt 为0;
ms->maddr = maddr;
ms->flags设IP_MASQ_F_NO_REPLY位。
8. 如果((协议不是TCP 和UDP)|| mport),ms的伪装端口设为mport。调用__ip_masq_in_get取得ms。
9. 如果没有匹配的ms,则ms->flags设 IP_MASQ_F_MPORT位;增加伪装端口计数;将ms加入HASH队列;调用ip_masq_bind_app(ms);ms的访问计数加一;为ms的IP_MASQ_S_NONE状态设置超时;返回ms。
10. 如果有匹配项,则调用__ip_masq_put(mst)使访问计数减一;释放ms; MOD_DEC_USE_COUNT;返回NULL。
11. 调用mport = get_next_mport()来找一个可用的端口。
12. 赋值 ms->mport = mport。
13. 调用ip_masq_bind_app(ms)。
14. 设n_fails为0。
15.ms的访问计数增一。
16.为ms的IP_MASQ_S_NONE设置超时。
17.返回ms。
(11)ip_fw_masquerade
格式:int ip_masquerade(struct sk_buff **skb_p, __u32 maddr)
返回值:成功:返回大于0的数;失败:返回-1。
处理流程:
1. 先做一些有关校验和的检查。
2. 调用ip_masq_out_get_iph看入口是否已经存在。
3. 如果入口存在的话,将老的ms从HASH表中删除,将ms->maddr替换为maddr,并将新的ms结构加入HASH队列。
4. 如果没有定义源端口,做以下几步:将老的ms从HASH表中删除,设置ms->sport =h.portp[0],即设置ms的源端口为TCP头中的源端口,将新的ms加入HASH表。
5. 如果定义了IP_MASQ_F_DLOOSE,ms->dport = h .port[1]; ms->daddr = iph->daddr。
6. 如果入口不存在则创建一个新的ms。
7. 将IP头的源地址替换为平衡器的ip地址。
8. 将TCP头的源端口替换为ms的伪装端口。
9. 做一些有关校验和的操作。
10. ms的访问计数减一。
11. 返回0。
(12)ip_fw_demasquerade
格式: int ip_fw_demasquerade(struct sk_buff **skb_p)
返回值:成功:返回1;失败:返回-1。
处理流程:
1. 取得sk_buff中的数据取的起始地址。
2. 取得数据区的大小。
3. 取得针对协议的偏移量。
4. Maddr = iph->daddr。
5.察看协议类型,如果是ICMP,则调用ip_fw_demasq_icmp;如果是TCP,什么也不做;如果是UDP协议,则首先确认端口号在BEGIN 和END之间,然后对校验和进行一定的操作。
6. 看现有表中是否有匹配项,返回ms。
7.如果有匹配项,设置标识位~IP_MASQ_F_NO_REPLY;如果定义了非严格路由,则ms->dport = h.portp[0], ms->daddr = iph_saddr。
8. 如果定义了IP_MASQ_F_NO_DPORT,则标识位设~IP_MASQ_F_DPORT, ms的目的端口设为TCP头中的源端口。
9.如果定义了IP_MASQ_F_NO_DADDR,ms的标识位设~IP_MASQ_F_NO_DADDR,ms的目标地址设为IP头的源地址。
10. 调用masq_skb_cow复制一个skb。
11. 将IP头的目标地址设为ms的源地址。
12. 将TCP头中的目标端口设为ms的源端口。
13. 调用ip_masq_app_pkt_in。
14. 对校验和进行操作。
15. 调用ip_send_check(iph)。
16. 调用masq_set_state(ms, 0 , iph, h.portp )。
17. ms的访问计数减一。
18. 返回1。
7. ip 端口转发模块的分析
7.1 设计思想
ip端口转发模块的主要工作:
1. 接受外部网的连接请求。
2. 对外只呈现平衡器,使所有请求看起来都是由平衡器处理的。
3. 建立一个端口转发链表。
4. 接收外部网发向内部网的请求。根据连接请求的源地址、源端口、目标地址和目标端口的信息察看链表中是否有对应表项,如果有,则调用ip伪装模块将请求转发到实际服务器上;如果没有对应表项,则创建一个新的端口转发表项,并且在ip伪装HASH表中增加相应的表项。将实际服务器的处理结果回传给平衡器,再由平衡器发给外部网中的客户。
5. 在ip端口转发模块中通过系统调用的实现函数对用户的系统调用进行处理,首先清空ip端口转发链表,然后建立对应于最轻负载机器ip地址的ip端口转发表项。
7.2 模块流程

7.3 结构设计
程序名 | 标识符 | 功能 | 源程序 |
删除表项 | ip_portfw_del | 在双向链表中删除一个ip_portfw结构的表项 | ip_masq_portfw.c |
清空双向链表 | ip_portfw_flush | 清空双向链表,释放空间 | ip_masq_portfw.c |
寻找匹配表项 | ip_portfw_lookup | 寻找符合要求的表项 | ip_masq_portfw.c |
设置权重 | ip_portfw_edit | 为匹配的表项设置权重 | ip_masq_portfw.c |
添加表项 | ip_portfw_add | 添加一个表项 | ip_masq_portfw.c |
控制双向链表 | ip_portfw_ctl | 对双向链表进行控制,进行添加、删除和清空操作 | ip_masq_portfw.c |
匹配表项 | portfw_in_rule | 判断是否存在匹配表项 | ip_masq_portfw.c |
创建新入口 | portfw_in_creat | 如果没有匹配表项,则创建一个新的ip_masq结构的表项。 | ip_masq_portfw.c |
系统调用处理函数 | getip | 接受来自用户层的系统调用,根据负载最轻的机器的IP值建立新的端口转发链表 | ip_masq_portfw.c |
7.4 主要数据结构
struct ip_portfw{ struct list_head list; __u32 laddr, raddr; __u16 lport, rport; atomic_t pref_cnt; int pref; } struct list_head{ struct list_head *next, *prev; } . TAG: Linux 集群 理论 |