-
ipvsadmin配置命令,开启persistent选项之后,ipvs将来自同一个客户端的请求全部调度到一个固定的RS服务器上。对于SSL和FTP这类,其多个报文之间是相互关联的协议,需要开启此类功能。但是对于NAT转发模式,由于NAT将对端口号进行修改,FTP服务需要使用ip_vs_ftp模块才能正常工作
-
命令行选项netmask默认为255.255.255.255,仅对同一个客户端进行持续调度。如下指定掩码255.255.255.0,可对同一个网段内的所有客户端,调度到同一个目的服务器进行处理
./ipvsadm -A -t 207.175.44.110:80 -s rr --persistent 500 --netmask 255.255.255.0
-
dp_vs_schedule
struct dp_vs_conn *dp_vs_schedule(struct dp_vs_service *svc, const struct dp_vs_iphdr *iph, struct rte_mbuf *mbuf, bool is_synproxy_on, bool outwall) { .... if (svc->flags & DP_VS_SVC_F_PERSISTENT) { return(dp_vs_sched_persist(svc, iph, mbuf, is_synproxy_on)); } .... }
-
dp_vs_sched_persist
- 首先根据客户端地址&掩码与操作,可实现将一个网段内的所有客户端调度到同一个目的服务器
- 查找模板连接,查找到则将dest设置为模板连接的dest,保证同一客户端调度到同一目的服务器,如果未查找到新建模板连接
- 根据模板连接信息,新建该tcp的连接
- 设置新conn关联的control实例,并添加control的引用计数,在连接清理处可以看到
/* * IPVS persistent scheduling funciton. * It create a connection entry according to its template if exists, * or selects a server and creates a connection entry plus a template. */ static struct dp_vs_conn *dp_vs_sched_persist(struct dp_vs_service *svc, const struct dp_vs_iphdr *iph, struct rte_mbuf *mbuf, bool is_synproxy_on) { uint32_t conn_flags; uint16_t _ports[2], *ports; uint16_t dport; struct dp_vs_dest * dest; struct dp_vs_conn * conn, *ct; struct dp_vs_conn_param param; union inet_addr snet; /* source network of eth client after masking */ #ifdef CONFIG_DPVS_IPVS_DEBUG char sbuf[64], dbuf[64], maskbuf[64]; #endif assert(svc && iph && mbuf); conn_flags = (is_synproxy_on ? DPVS_CONN_F_SYNPROXY : 0); if (svc->af == AF_INET6) { /* FIXME: Is OK to use svc->netmask as IPv6 prefix length ? */ ipv6_addr_prefix_copy(&snet.in6, &iph->saddr.in6, svc->netmask); } else { //ipvsadm设置的时候,可以通过netmask对一个网段的客户端进行调度,首先获取数据包中ip源地址与设置网段掩码的与操作, //用于网段进行匹配。客户端地址和掩码的与操作,可实现将一个网段内的所有客户端调度到同一个目的服务器上 snet.in.s_addr = iph->saddr.in.s_addr & svc->netmask; } //获取端口的偏移 ports = mbuf_header_pointer(mbuf, iph->len, sizeof(_ports), _ports); if (!ports) { return(NULL); } #ifdef CONFIG_DPVS_IPVS_DEBUG RTE_LOG(DEBUG, IPVS, "%s: persist-schedule: src %s/%u dest %s/%u snet %s\\n", __func__, inet_ntop(svc->af, &iph->saddr, sbuf, sizeof(sbuf)), ntohs(ports[0]), inet_ntop(svc->af, &iph->daddr, dbuf, sizeof(dbuf)), ntohs(ports[1]), inet_ntop(svc->af, &snet, maskbuf, sizeof(maskbuf))); #endif //如果配置了DPVS虚拟服务的指定服务端口号,则根据端口号是否为服务端口,创建的连接模板有所不同。 if (ports[1] == svc->port) { /* regular persistent service: <proto, caddr, 0, vaddr, vport, daddr, dport> */ //找到已经创建的模板,主要用于将同一客户端重定向至同一rs ct = dp_vs_ct_in_get(svc->af, iph->proto, &snet, &iph->daddr, 0, ports[1]); if (!ct || !dp_vs_check_template(ct)) { /* no template found, or the dest of the conn template is not available */ //如果没有指定当前报文的连接模板,首先创建连接模板,再创建相应的连接结构。后续的报文,如果匹配此模板,将据此 //模板生成连接结构,而不再执行调度,这样确保了根据模板生成的连接,具有相同的目的服务器,以实现持续调度的功能 dest = svc->scheduler->schedule(svc, mbuf); if (unlikely(NULL == dest)) { RTE_LOG(WARNING, IPVS, "%s: persist-schedule: no dest found.\\n", __func__); return(NULL); } /* create a conn template */ dp_vs_conn_fill_param(iph->af, iph->proto, &snet, &iph->daddr, 0, ports[1], 0, ¶m); //创建新的模板连接,设置DPVS_CONN_F_TEMPLATE标识是一个模板 ct = dp_vs_conn_new(mbuf, iph, ¶m, dest, conn_flags | DPVS_CONN_F_TEMPLATE); if (unlikely(NULL == ct)) { return(NULL); } ct->timeout.tv_sec = svc->timeout; } else { /* set destination with the found template */ //如果找到,则该客户端之前有过连接,选取与之前的连接相同的rs,设置dest dest = ct->dest; } dport = dest->port; } else { /* port zero service: <proto, caddr, 0, vaddr, 0, daddr, 0> * fw-mark based service: not support */ //如果未指定服务端口,此处查找时忽略目的端口 ct = dp_vs_ct_in_get(svc->af, iph->proto, &snet, &iph->daddr, 0, 0); if (!ct || !dp_vs_check_template(ct)) { dest = svc->scheduler->schedule(svc, mbuf); if (unlikely(NULL == dest)) { RTE_LOG(WARNING, IPVS, "%s: persist-schedule: no dest found.\\n", __func__); return(NULL); } /* create a conn template */ dp_vs_conn_fill_param(iph->af, iph->proto, &snet, &iph->daddr, 0, 0, 0, ¶m); ct = dp_vs_conn_new(mbuf, iph, ¶m, dest, conn_flags | DPVS_CONN_F_TEMPLATE); if (unlikely(NULL == ct)) { return(NULL); } ct->timeout.tv_sec = svc->timeout; } else { /* set destination with the found template */ dest = ct->dest; } dport = ports[1]; } /* create a new connection according to the template */ //根据上面找的连接模板,选择了dest后,创建连接 dp_vs_conn_fill_param(iph->af, iph->proto, &iph->saddr, &iph->daddr, ports[0], ports[1], dport, ¶m); conn = dp_vs_conn_new(mbuf, iph, ¶m, dest, conn_flags); if (unlikely(NULL == conn)) { dp_vs_conn_put(ct); return(NULL); } /* add control for the new connection */ //设置新建conn的control为模板连接,并添加模板连接的引用计数 dp_vs_control_add(conn, ct); dp_vs_conn_put(ct); dp_vs_stats_conn(conn); return(conn); }
dpvs persistent调度
最新推荐文章于 2022-12-28 19:57:59 发布