ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol,
const union nf_inet_addr *vaddr, __be16 vport)
{
- struct ip_vs_service *svc;
+ struct ip_vs_service *svc = NULL;
+ int af_id = ip_vs_af_index(af);
/*
* Check the table hashed by fwmark first
*/
- if (fwmark) {
+ if (fwmark && atomic_read(&ipvs->fwm_services[af_id])) {
svc = __ip_vs_svc_fwm_find(ipvs, af, fwmark);
if (svc)
goto out;
}
+ if (!atomic_read(&ipvs->nonfwm_services[af_id]))
+ goto out;
+
/*
* Check the table hashed by <protocol,addr,port>
* for "full" addressed entries
*/
svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, vport);
+ if (svc)
+ goto out;
- if (!svc && protocol == IPPROTO_TCP &&
- atomic_read(&ipvs->ftpsvc_counter) &&
+ if (protocol == IPPROTO_TCP &&
+ atomic_read(&ipvs->ftpsvc_counter[af_id]) &&
(vport == FTPDATA || !inet_port_requires_bind_service(ipvs->net, ntohs(vport)))) {
/*
* Check if ftp service entry exists, the packet
* might belong to FTP data connections.
*/
svc = __ip_vs_service_find(ipvs, af, protocol, vaddr, FTPPORT);
+ if (svc)
+ goto out;
}
- if (svc == NULL
- && atomic_read(&ipvs->nullsvc_counter)) {
+ if (atomic_read(&ipvs->nullsvc_counter[af_id])) {
/*
* Check if the catch-all port (port zero) exists
*/
{
int ret = 0;
struct ip_vs_scheduler *sched = NULL;
+ int af_id = ip_vs_af_index(u->af);
struct ip_vs_pe *pe = NULL;
struct ip_vs_service *svc = NULL;
int ret_hooks = -1;
}
#endif
- if ((u->af == AF_INET && !ipvs->num_services) ||
- (u->af == AF_INET6 && !ipvs->num_services6)) {
+ if (!atomic_read(&ipvs->num_services[af_id])) {
ret = ip_vs_register_hooks(ipvs, u->af);
if (ret < 0)
goto out_err;
/* Update the virtual service counters */
if (svc->port == FTPPORT)
- atomic_inc(&ipvs->ftpsvc_counter);
- else if (svc->port == 0)
- atomic_inc(&ipvs->nullsvc_counter);
+ atomic_inc(&ipvs->ftpsvc_counter[af_id]);
+ else if (!svc->port && !svc->fwmark)
+ atomic_inc(&ipvs->nullsvc_counter[af_id]);
if (pe && pe->conn_out)
- atomic_inc(&ipvs->conn_out_counter);
+ atomic_inc(&ipvs->conn_out_counter[af_id]);
/* Bind the ct retriever */
RCU_INIT_POINTER(svc->pe, pe);
pe = NULL;
- /* Count only IPv4 services for old get/setsockopt interface */
- if (svc->af == AF_INET)
- ipvs->num_services++;
- else if (svc->af == AF_INET6)
- ipvs->num_services6++;
+ if (svc->fwmark)
+ atomic_inc(&ipvs->fwm_services[af_id]);
+ else
+ atomic_inc(&ipvs->nonfwm_services[af_id]);
+ atomic_inc(&ipvs->num_services[af_id]);
/* Hash the service into the service table */
ip_vs_svc_hash(svc);
struct ip_vs_pe *pe = NULL, *old_pe = NULL;
int ret = 0;
bool new_pe_conn_out, old_pe_conn_out;
+ struct netns_ipvs *ipvs = svc->ipvs;
+ int af_id = ip_vs_af_index(svc->af);
/*
* Lookup the scheduler, by 'u->sched_name'
new_pe_conn_out = (pe && pe->conn_out) ? true : false;
old_pe_conn_out = (old_pe && old_pe->conn_out) ? true : false;
if (new_pe_conn_out && !old_pe_conn_out)
- atomic_inc(&svc->ipvs->conn_out_counter);
+ atomic_inc(&ipvs->conn_out_counter[af_id]);
if (old_pe_conn_out && !new_pe_conn_out)
- atomic_dec(&svc->ipvs->conn_out_counter);
+ atomic_dec(&ipvs->conn_out_counter[af_id]);
}
out:
struct ip_vs_scheduler *old_sched;
struct ip_vs_pe *old_pe;
struct netns_ipvs *ipvs = svc->ipvs;
+ int af_id = ip_vs_af_index(svc->af);
- if (svc->af == AF_INET) {
- ipvs->num_services--;
- if (!ipvs->num_services)
- ip_vs_unregister_hooks(ipvs, svc->af);
- } else if (svc->af == AF_INET6) {
- ipvs->num_services6--;
- if (!ipvs->num_services6)
- ip_vs_unregister_hooks(ipvs, svc->af);
- }
+ atomic_dec(&ipvs->num_services[af_id]);
+ if (!atomic_read(&ipvs->num_services[af_id]))
+ ip_vs_unregister_hooks(ipvs, svc->af);
+ if (svc->fwmark)
+ atomic_dec(&ipvs->fwm_services[af_id]);
+ else
+ atomic_dec(&ipvs->nonfwm_services[af_id]);
ip_vs_stop_estimator(svc->ipvs, &svc->stats);
/* Unbind persistence engine, keep svc->pe */
old_pe = rcu_dereference_protected(svc->pe, 1);
if (old_pe && old_pe->conn_out)
- atomic_dec(&ipvs->conn_out_counter);
+ atomic_dec(&ipvs->conn_out_counter[af_id]);
ip_vs_pe_put(old_pe);
/*
* Update the virtual service counters
*/
if (svc->port == FTPPORT)
- atomic_dec(&ipvs->ftpsvc_counter);
- else if (svc->port == 0)
- atomic_dec(&ipvs->nullsvc_counter);
+ atomic_dec(&ipvs->ftpsvc_counter[af_id]);
+ else if (!svc->port && !svc->fwmark)
+ atomic_dec(&ipvs->nullsvc_counter[af_id]);
/*
* Free the service if nobody refers to it
struct ip_vs_getinfo info;
info.version = IP_VS_VERSION_CODE;
info.size = ip_vs_conn_tab_size;
- info.num_services = ipvs->num_services;
+ info.num_services =
+ atomic_read(&ipvs->num_services[IP_VS_AF_INET]);
if (copy_to_user(user, &info, sizeof(info)) != 0)
ret = -EFAULT;
}
INIT_LIST_HEAD(&ipvs->dest_trash);
spin_lock_init(&ipvs->dest_trash_lock);
timer_setup(&ipvs->dest_trash_timer, ip_vs_dest_trash_expire, 0);
- atomic_set(&ipvs->ftpsvc_counter, 0);
- atomic_set(&ipvs->nullsvc_counter, 0);
- atomic_set(&ipvs->conn_out_counter, 0);
+ for (idx = 0; idx < IP_VS_AF_MAX; idx++) {
+ atomic_set(&ipvs->num_services[idx], 0);
+ atomic_set(&ipvs->fwm_services[idx], 0);
+ atomic_set(&ipvs->nonfwm_services[idx], 0);
+ atomic_set(&ipvs->ftpsvc_counter[idx], 0);
+ atomic_set(&ipvs->nullsvc_counter[idx], 0);
+ atomic_set(&ipvs->conn_out_counter[idx], 0);
+ }
INIT_DELAYED_WORK(&ipvs->est_reload_work, est_reload_work_handler);