/* Store new weight in real_server struct and then update kernel. */ void update_svr_wgt(int weight, virtual_server * vs, real_server * rs) { char rsip[INET6_ADDRSTRLEN]; if (weight != rs->weight) { log_message(LOG_INFO, "Changing weight from %d to %d for %s service [%s]:%d of VS [%s]:%d" , rs->weight , weight , ISALIVE(rs) ? "active" : "inactive" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); rs->weight = weight; /* * Have weight change take effect now only if rs is in * the pool and alive and the quorum is met (or if * there is no sorry server). If not, it will take * effect later when it becomes alive. */ if (rs->set && ISALIVE(rs) && (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr))) ipvs_cmd(LVS_CMD_EDIT_DEST, check_data->vs_group, vs, rs); update_quorum_state(vs); } }
/* Fill IPVS rule with root vs infos */ void ipvs_set_rule(int cmd, virtual_server * vs, real_server * rs) { /* Clean up target rule */ memset(urule, 0, sizeof (struct ip_vs_rule_user)); strncpy(urule->sched_name, vs->sched, IP_VS_SCHEDNAME_MAXLEN); urule->weight = 1; urule->conn_flags = vs->loadbalancing_kind; urule->netmask = ((u_int32_t) 0xffffffff); urule->protocol = vs->service_type; if (!parse_timeout(vs->timeout_persistence, &urule->timeout)) log_message(LOG_INFO, "IPVS : Virtual service [%s]:%d illegal timeout." , inet_ntop2(inet_sockaddrip4(&vs->addr)) , ntohs(inet_sockaddrport(&vs->addr))); if (urule->timeout != 0 || vs->granularity_persistence) urule->vs_flags = IP_VS_SVC_F_PERSISTENT; if (cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_DEL) if (vs->granularity_persistence) urule->netmask = vs->granularity_persistence; /* SVR specific */ if (rs) { if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST || cmd == IP_VS_SO_SET_EDITDEST) { urule->weight = rs->weight; urule->daddr = inet_sockaddrip4(&rs->addr); urule->dport = inet_sockaddrport(&rs->addr); } } }
int tcp_check_thread(thread_t * thread) { checker_t *checker; tcp_checker_t *tcp_check; int status; checker = THREAD_ARG(thread); tcp_check = CHECKER_ARG(checker); status = tcp_socket_state(thread->u.fd, thread, tcp_check_thread); /* If status = connect_success, TCP connection to remote host is established. * Otherwise we have a real connection error or connection timeout. */ if (status == connect_success) { close(thread->u.fd); if (!svr_checker_up(UP, checker->id, checker->rs)) { log_message(LOG_INFO, "TCP connection to [%s]:%d success." , inet_sockaddrtos(&tcp_check->dst) , ntohs(inet_sockaddrport(&tcp_check->dst))); smtp_alert(checker->rs, NULL, NULL, "UP", "=> TCP CHECK succeed on service <="); update_svr_checker_state(UP, checker->id , checker->vs , checker->rs); } } else { if (svr_checker_up(DOWN, checker->id, checker->rs)) { log_message(LOG_INFO, "TCP connection to [%s]:%d failed !!!" , inet_sockaddrtos(&tcp_check->dst) , ntohs(inet_sockaddrport(&tcp_check->dst))); smtp_alert(checker->rs, NULL, NULL, "DOWN", "=> TCP CHECK failed on service <="); update_svr_checker_state(DOWN, checker->id , checker->vs , checker->rs); } } /* Register next timer checker */ if (status != connect_in_progress) thread_add_timer(thread->master, tcp_connect_thread, checker, checker->vs->delay_loop); return 0; }
static int ipvs_laddr_cmd(int cmd, list vs_group, virtual_server * vs) { local_addr_group *laddr_group = ipvs_get_laddr_group_by_name(vs->local_addr_gname, check_data->laddr_group); if (!laddr_group) { log_message(LOG_ERR, "No address in group %s", vs->local_addr_gname); return IPVS_ERROR; } memset(srule, 0, sizeof(ipvs_service_t)); srule->netmask = (vs->addr.ss_family == AF_INET6) ? 128 : ((u_int32_t) 0xffffffff); srule->protocol = vs->service_type; if(vs->vsgname) { ipvs_laddr_vsg_cmd(cmd, vs_group, vs, laddr_group); } else { if (!vs->vfwmark) { srule->af = vs->addr.ss_family; if (vs->addr.ss_family == AF_INET6) inet_sockaddrip6(&vs->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vs->addr); srule->port = inet_sockaddrport(&vs->addr); ipvs_laddr_group_cmd(cmd, laddr_group); } } return IPVS_SUCCESS; }
/* IPVS group range rule */ static void ipvs_group_range_cmd(int cmd, virtual_server_group_entry *vsg_entry) { uint32_t addr_ip, ip; if (vsg_entry->addr.ss_family == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); ip = srule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&vsg_entry->addr); } /* Set Address Family */ srule->af = vsg_entry->addr.ss_family; /* Parse the whole range */ for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; srule->addr.in6.s6_addr32[3] = addr_ip; } else { srule->addr.ip = addr_ip; } srule->port = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ ipvs_talk(cmd); } }
int ipvs_laddr_remove_entry(virtual_server *vs, local_addr_entry *laddr_entry) { memset(srule, 0, sizeof(ipvs_service_t)); srule->protocol = vs->service_type; if (vs->vsgname) { ipvs_rm_lentry_from_vsg(laddr_entry, vs->vsgname); } else if (!vs->vfwmark) { srule->af = vs->addr.ss_family; if (vs->addr.ss_family == AF_INET6) { srule->netmask = 128; inet_sockaddrip6(&vs->addr, &srule->addr.in6); } else { srule->netmask = 0xffffffff; srule->addr.ip = inet_sockaddrip4(&vs->addr); } srule->port = inet_sockaddrport(&vs->addr); if (laddr_entry->range) { ipvs_laddr_range_cmd(IP_VS_SO_SET_DELLADDR, laddr_entry); } else { memset(laddr_rule, 0, sizeof(ipvs_laddr_t)); laddr_rule->af = laddr_entry->addr.ss_family; if (laddr_entry->addr.ss_family == AF_INET6) inet_sockaddrip6(&laddr_entry->addr, &laddr_rule->addr.in6); else laddr_rule->addr.ip = inet_sockaddrip4(&laddr_entry->addr); ipvs_talk(IP_VS_SO_SET_DELLADDR); } } return IPVS_SUCCESS; }
/* Remove a specific vs group entry */ int ipvs_group_remove_entry(virtual_server *vs, virtual_server_group_entry *vsge) { real_server *rs; int err = 0; element e; list l = vs->rs; /* Clean target rules */ memset(urule, 0, sizeof (struct ip_vs_rule_user)); /* Process realserver queue */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (rs->alive) { /* Prepare the IPVS rule */ if (urule->daddr) { /* Setting IPVS rule with vs root rs */ ipvs_set_rule(IP_VS_SO_SET_DELDEST, vs, rs); } else { urule->weight = rs->weight; urule->daddr = inet_sockaddrip4(&rs->addr); urule->dport = inet_sockaddrport(&rs->addr); } /* Set vs rule */ if (vsge->range) { ipvs_group_range_cmd(IP_VS_SO_SET_DELDEST, vsge); } else { urule->vfwmark = vsge->vfwmark; urule->vaddr = inet_sockaddrip4(&vsge->addr); urule->vport = inet_sockaddrport(&vsge->addr); /* Talk to the IPVS channel */ err = ipvs_talk(IP_VS_SO_SET_DELDEST); } } } /* Remove VS entry */ if (vsge->range) err = ipvs_group_range_cmd(IP_VS_SO_SET_DEL, vsge); else err = ipvs_talk(IP_VS_SO_SET_DEL); return err; }
/* Fill IPVS rule with root vs infos */ void ipvs_set_rule(int cmd, virtual_server * vs, real_server * rs) { /* Clean target rule */ memset(drule, 0, sizeof(ipvs_dest_t)); drule->weight = 1; drule->u_threshold = 0; drule->l_threshold = 0; drule->conn_flags = vs->loadbalancing_kind; strncpy(srule->sched_name, vs->sched, IP_VS_SCHEDNAME_MAXLEN); srule->netmask = (vs->addr.ss_family == AF_INET6) ? 128 : ((u_int32_t) 0xffffffff); srule->protocol = vs->service_type; if (!parse_timeout(vs->timeout_persistence, &srule->timeout)) log_message(LOG_INFO, "IPVS : Virtual service [%s]:%d illegal timeout." , inet_ntop2(inet_sockaddrip4(&vs->addr)) , ntohs(inet_sockaddrport(&vs->addr))); srule->est_timeout = atoi(vs->est_timeout); if (srule->timeout != 0 || vs->granularity_persistence) srule->flags = IP_VS_SVC_F_PERSISTENT; if (cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_DEL) if (vs->granularity_persistence) srule->netmask = vs->granularity_persistence; if(vs->syn_proxy) srule->flags |= IP_VS_SVC_F_SYNPROXY; /* SVR specific */ if (rs) { if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST || cmd == IP_VS_SO_SET_EDITDEST) { drule->af = rs->addr.ss_family; if (rs->addr.ss_family == AF_INET6) inet_sockaddrip6(&rs->addr, &drule->addr.in6); else drule->addr.ip = inet_sockaddrip4(&rs->addr); drule->port = inet_sockaddrport(&rs->addr); drule->weight = rs->weight; drule->u_threshold = rs->u_threshold; drule->l_threshold = rs->l_threshold; } } }
/* Remove a realserver IPVS rule */ static int clear_service_rs(list vs_group, virtual_server * vs, list l) { element e; real_server *rs; char rsip[INET6_ADDRSTRLEN]; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (ISALIVE(rs)) { if (!ipvs_cmd(LVS_CMD_DEL_DEST, vs_group, vs, rs)) return 0; UNSET_ALIVE(rs); if (!vs->omega) continue; /* In Omega mode we call VS and RS down notifiers * all the way down the exit, as necessary. */ if (rs->notify_down) { log_message(LOG_INFO, "Executing [%s] for service [%s]:%d in VS [%s]:%d" , rs->notify_down , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(rs->notify_down); } /* Sooner or later VS will lose the quorum (if any). However, * we don't push in a sorry server then, hence the regression * is intended. */ if (vs->quorum_state == UP && vs->quorum_down && weigh_live_realservers(vs) < vs->quorum - vs->hysteresis) { vs->quorum_state = DOWN; log_message(LOG_INFO, "Executing [%s] for VS [%s]:%d" , vs->quorum_down , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(vs->quorum_down); } } } return 1; }
/* Sync checkers activity with netlink kernel reflection */ void update_checker_activity(sa_family_t family, void *address, int enable) { checker_t *checker; sa_family_t vip_family; element e; char addr_str[INET6_ADDRSTRLEN]; void *addr; /* Display netlink operation */ if (debug & 32) { inet_ntop(family, address, addr_str, sizeof(addr_str)); log_message(LOG_INFO, "Netlink reflector reports IP %s %s" , addr_str, (enable) ? "added" : "removed"); } /* Processing Healthcheckers queue */ if (!LIST_ISEMPTY(checkers_queue)) { for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { checker = ELEMENT_DATA(e); vip_family = checker->vs->addr.ss_family; if (vip_family != family) continue; if (family == AF_INET6) { addr = (void *) &((struct sockaddr_in6 *)&checker->vs->addr)->sin6_addr; } else { addr = (void *) &((struct sockaddr_in *)&checker->vs->addr)->sin_addr; } if (inaddr_equal(family, addr, address) && CHECKER_HA_SUSPEND(checker)) { if (!CHECKER_ENABLED(checker) && enable) log_message(LOG_INFO, "Activating healthchecker for service [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); if (CHECKER_ENABLED(checker) && !enable) log_message(LOG_INFO, "Suspending healthchecker for service [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); checker->enabled = enable; } } } }
/* * Used as a callback from dump_list() to print out all * the list elements in smtp_checker->host. */ void smtp_dump_host(void *data) { smtp_host_t *smtp_host = data; log_message(LOG_INFO, " Checked ip = %s", inet_sockaddrtos(&smtp_host->dst)); log_message(LOG_INFO, " port = %d", ntohs(ntohs(inet_sockaddrport(&smtp_host->dst)))); if (smtp_host->bindto.ss_family) log_message(LOG_INFO, " bindto = %s", inet_sockaddrtos(&smtp_host->bindto)); }
/* dump checker data */ static void dump_checker(void *data) { checker_t *checker = data; log_message(LOG_INFO, " [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); (*checker->dump_func) (checker); }
/* set IPVS group rules */ static int ipvs_group_cmd(int cmd, list vs_group, real_server * rs, char * vsgname) { virtual_server_group *vsg = ipvs_get_group_by_name(vsgname, vs_group); virtual_server_group_entry *vsg_entry; list l; element e; int err = 1; /* return if jointure fails */ if (!vsg) return -1; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); urule->vaddr = inet_sockaddrip4(&vsg_entry->addr); urule->vport = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit vfwmark list */ l = vsg->vfwmark; urule->vaddr = 0; urule->vport = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); urule->vfwmark = vsg_entry->vfwmark; /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit range list */ l = vsg->range; urule->vfwmark = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { err = ipvs_group_range_cmd(cmd, vsg_entry); IPVS_SET_ALIVE(cmd, vsg_entry); } } return err; }
void dump_tcp_check(void *data) { tcp_checker_t *tcp_chk = CHECKER_DATA(data); log_message(LOG_INFO, " Keepalive method = TCP_CHECK"); log_message(LOG_INFO, " Connection port = %d", ntohs(inet_sockaddrport(&tcp_chk->dst))); if (tcp_chk->bindto.ss_family) log_message(LOG_INFO, " Bind to = %s", inet_sockaddrtos(&tcp_chk->bindto)); log_message(LOG_INFO, " Connection timeout = %d", tcp_chk->connection_to/TIMER_HZ); }
/* Set/Remove a RS or a local address group from a VS */ int ipvs_cmd(int cmd, list vs_group, virtual_server * vs, real_server * rs) { /* Set/Remove local address */ if (cmd == IP_VS_SO_SET_ADDLADDR || cmd == IP_VS_SO_SET_DELLADDR) return ipvs_laddr_cmd(cmd, vs_group, vs); /* Allocate the room */ memset(srule, 0, sizeof(ipvs_service_t)); ipvs_set_rule(cmd, vs, rs); /* Does the service use inhibit flag ? */ if (cmd == IP_VS_SO_SET_DELDEST && rs->inhibit) { drule->weight = 0; cmd = IP_VS_SO_SET_EDITDEST; } if (cmd == IP_VS_SO_SET_ADDDEST && rs->inhibit && rs->set) cmd = IP_VS_SO_SET_EDITDEST; /* Set flag */ if (cmd == IP_VS_SO_SET_ADDDEST && !rs->set) rs->set = 1; if (cmd == IP_VS_SO_SET_DELDEST && rs->set) rs->set = 0; /* Set vs rule and send to kernel */ if (vs->vsgname) { ipvs_group_cmd(cmd, vs_group, rs, vs->vsgname); } else { if (vs->vfwmark) { srule->af = AF_INET; srule->fwmark = vs->vfwmark; } else { srule->af = vs->addr.ss_family; if (vs->addr.ss_family == AF_INET6) inet_sockaddrip6(&vs->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vs->addr); srule->port = inet_sockaddrport(&vs->addr); } /* Talk to the IPVS channel */ ipvs_talk(cmd); } return IPVS_SUCCESS; }
/* register checkers to the global I/O scheduler */ void register_checkers_thread(void) { checker_t *checker; element e; for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { checker = ELEMENT_DATA(e); log_message(LOG_INFO, "Activating healthchecker for service [%s]:%d" , inet_sockaddrtos(&checker->rs->addr) , ntohs(inet_sockaddrport(&checker->rs->addr))); CHECKER_ENABLE(checker); if (checker->launch) thread_add_timer(master, checker->launch, checker, BOOTSTRAP_DELAY); } }
/* Main entry point */ void smtp_alert(real_server_t * rs, vrrp_t * vrrp, vrrp_sgroup_t * vgroup, const char *subject, const char *body) { smtp_t *smtp; /* Only send mail if email specified */ if (!LIST_ISEMPTY(global_data->email) && global_data->smtp_server.ss_family != 0) { /* allocate & initialize smtp argument data structure */ smtp = (smtp_t *) MALLOC(sizeof(smtp_t)); smtp->subject = (char *) MALLOC(MAX_HEADERS_LENGTH); smtp->body = (char *) MALLOC(MAX_BODY_LENGTH); smtp->buffer = (char *) MALLOC(SMTP_BUFFER_MAX); smtp->email_to = (char *) MALLOC(SMTP_BUFFER_MAX); /* format subject if rserver is specified */ if (rs) { snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] Realserver [%s]:%d - %s" , global_data->router_id , inet_sockaddrtos(&rs->addr) , ntohs(inet_sockaddrport(&rs->addr)) , subject); } else if (vrrp) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Instance %s - %s" , global_data->router_id , vrrp->iname , subject); else if (vgroup) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] VRRP Group %s - %s" , global_data->router_id , vgroup->gname , subject); else if (global_data->router_id) snprintf(smtp->subject, MAX_HEADERS_LENGTH, "[%s] %s" , global_data->router_id , subject); else snprintf(smtp->subject, MAX_HEADERS_LENGTH, "%s", subject); strncpy(smtp->body, body, MAX_BODY_LENGTH); build_to_header_rcpt_addrs(smtp); smtp_connect(smtp); } }
/* IPVS group range rule */ static int ipvs_group_range_cmd(int cmd, virtual_server_group_entry *vsg_entry) { uint32_t addr_ip; int err = 0; /* Parse the whole range */ for (addr_ip = inet_sockaddrip4(&vsg_entry->addr); ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { urule->vaddr = addr_ip; urule->vport = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ err = ipvs_talk(cmd); } return err; }
/* Set/Remove a RS from a VS */ int ipvs_cmd(int cmd, list vs_group, virtual_server * vs, real_server * rs) { int err = 0; /* Prepare target rule */ ipvs_set_rule(cmd, vs, rs); /* Does the service use inhibit flag ? */ if (cmd == IP_VS_SO_SET_DELDEST && rs->inhibit) { urule->weight = 0; cmd = IP_VS_SO_SET_EDITDEST; } if (cmd == IP_VS_SO_SET_ADDDEST && rs->inhibit && rs->set) cmd = IP_VS_SO_SET_EDITDEST; /* Set flag */ if (cmd == IP_VS_SO_SET_ADDDEST && !rs->set) rs->set = 1; if (cmd == IP_VS_SO_SET_DELDEST && rs->set) rs->set = 0; /* Set vs rule and send to kernel */ if (vs->vsgname) { err = ipvs_group_cmd(cmd, vs_group, rs, vs->vsgname); } else { if (vs->vfwmark) { urule->vfwmark = vs->vfwmark; } else { urule->vaddr = inet_sockaddrip4(&vs->addr); urule->vport = inet_sockaddrport(&vs->addr); } /* Talk to the IPVS channel */ err = ipvs_talk(cmd); } return err; }
/* add or remove _alive_ real servers from a virtual server */ void perform_quorum_state(virtual_server *vs, int add) { element e; real_server *rs; if (LIST_ISEMPTY(vs->rs)) return; log_message(LOG_INFO, "%s the pool for VS [%s]:%d" , add?"Adding alive servers to":"Removing alive servers from" , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); for (e = LIST_HEAD(vs->rs); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (!ISALIVE(rs)) /* We only handle alive servers */ continue; if (add) rs->alive = 0; ipvs_cmd(add?LVS_CMD_ADD_DEST:LVS_CMD_DEL_DEST, check_data->vs_group, vs, rs); rs->alive = 1; } }
/* set quorum state depending on current weight of real servers */ void update_quorum_state(virtual_server * vs) { char rsip[INET6_ADDRSTRLEN]; /* If we have just gained quorum, it's time to consider notify_up. */ if (vs->quorum_state == DOWN && weigh_live_realservers(vs) >= vs->quorum + vs->hysteresis) { vs->quorum_state = UP; log_message(LOG_INFO, "Gained quorum %lu+%lu=%lu <= %u for VS [%s]:%d" , vs->quorum , vs->hysteresis , vs->quorum + vs->hysteresis , weigh_live_realservers(vs) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); if (vs->s_svr && ISALIVE(vs->s_svr)) { log_message(LOG_INFO, "Removing sorry server [%s]:%d from VS [%s]:%d" , inet_sockaddrtos2(&vs->s_svr->addr, rsip) , ntohs(inet_sockaddrport(&vs->s_svr->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); ipvs_cmd(LVS_CMD_DEL_DEST, check_data->vs_group, vs, vs->s_svr); vs->s_svr->alive = 0; /* Adding back alive real servers */ perform_quorum_state(vs, 1); } if (vs->quorum_up) { log_message(LOG_INFO, "Executing [%s] for VS [%s]:%d" , vs->quorum_up , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(vs->quorum_up); } return; } /* If we have just lost quorum for the VS, we need to consider * VS notify_down and sorry_server cases */ if (vs->quorum_state == UP && weigh_live_realservers(vs) < vs->quorum - vs->hysteresis) { vs->quorum_state = DOWN; log_message(LOG_INFO, "Lost quorum %lu-%lu=%lu > %u for VS [%s]:%d" , vs->quorum , vs->hysteresis , vs->quorum - vs->hysteresis , weigh_live_realservers(vs) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); if (vs->quorum_down) { log_message(LOG_INFO, "Executing [%s] for VS [%s]:%d" , vs->quorum_down , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(vs->quorum_down); } if (vs->s_svr) { log_message(LOG_INFO, "Adding sorry server [%s]:%d to VS [%s]:%d" , inet_sockaddrtos2(&vs->s_svr->addr, rsip) , ntohs(inet_sockaddrport(&vs->s_svr->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* the sorry server is now up in the pool, we flag it alive */ ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, vs->s_svr); vs->s_svr->alive = 1; /* Remove remaining alive real servers */ perform_quorum_state(vs, 0); } return; } }
static void ipvs_rm_lentry_from_vsg(local_addr_entry *laddr_entry, char *vsgname) { list l; element e; virtual_server_group *vsg; virtual_server_group_entry *vsg_entry; /* it's not old_check_data. help to ISALIVE check later */ vsg = ipvs_get_group_by_name(vsgname, check_data->vs_group); if (!vsg) return; l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); if (!ISALIVE(vsg_entry)) continue; srule->af = vsg_entry->addr.ss_family; if (vsg_entry->addr.ss_family == AF_INET6) { srule->netmask = 128; inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); } else { srule->netmask = 0xffffffff; srule->addr.ip = inet_sockaddrip4(&vsg_entry->addr); } srule->port = inet_sockaddrport(&vsg_entry->addr); if (laddr_entry->range) ipvs_laddr_range_cmd(IP_VS_SO_SET_DELLADDR, laddr_entry); else { memset(laddr_rule, 0, sizeof(ipvs_laddr_t)); laddr_rule->af = laddr_entry->addr.ss_family; if (laddr_entry->addr.ss_family == AF_INET6) inet_sockaddrip6(&laddr_entry->addr, &laddr_rule->addr.in6); else laddr_rule->addr.ip = inet_sockaddrip4(&laddr_entry->addr); ipvs_talk(IP_VS_SO_SET_DELLADDR); } } l = vsg->range; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); uint32_t addr_ip, ip; if (!ISALIVE(vsg_entry)) continue; srule->af = vsg_entry->addr.ss_family; srule->netmask = (vsg_entry->addr.ss_family == AF_INET6) ? 128 : ((u_int32_t) 0xffffffff); srule->port = inet_sockaddrport(&vsg_entry->addr); if (vsg_entry->addr.ss_family == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); ip = srule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&vsg_entry->addr); } for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { if (srule->af == AF_INET6) srule->addr.in6.s6_addr32[3] = addr_ip; else srule->addr.ip = addr_ip; if (laddr_entry->range) ipvs_laddr_range_cmd(IP_VS_SO_SET_DELLADDR, laddr_entry); else { memset(laddr_rule, 0, sizeof(ipvs_laddr_t)); laddr_rule->af = laddr_entry->addr.ss_family; if (laddr_entry->addr.ss_family == AF_INET6) inet_sockaddrip6(&laddr_entry->addr, &laddr_rule->addr.in6); else laddr_rule->addr.ip = inet_sockaddrip4(&laddr_entry->addr); ipvs_talk(IP_VS_SO_SET_DELLADDR); } } } }
void ipvs_new_laddr_add(virtual_server *vs, local_addr_group *laddr_group) { local_addr_entry *laddr_entry; list l; element e; /* the unalive vs will be set later*/ if (!vs->vsgname && !ISALIVE(vs)) return; memset(srule, 0, sizeof(ipvs_service_t)); srule->netmask = (vs->addr.ss_family == AF_INET6) ? 128 : ((u_int32_t) 0xffffffff); srule->protocol = vs->service_type; l = laddr_group->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { laddr_entry = ELEMENT_DATA(e); if (ISALIVE(laddr_entry)) continue; memset(laddr_rule, 0, sizeof(ipvs_laddr_t)); laddr_rule->af = laddr_entry->addr.ss_family; if (laddr_entry->addr.ss_family == AF_INET6) inet_sockaddrip6(&laddr_entry->addr, &laddr_rule->addr.in6); else laddr_rule->addr.ip = inet_sockaddrip4(&laddr_entry->addr); if (vs->vsgname) { ipvs_new_laddr_vsg(vs); } else { srule->af = vs->addr.ss_family; if (srule->af == AF_INET6) inet_sockaddrip6(&vs->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vs->addr); srule->port = inet_sockaddrport(&vs->addr); /* local address group channel */ ipvs_talk(IP_VS_SO_SET_ADDLADDR); } } l = laddr_group->range; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { laddr_entry = ELEMENT_DATA(e); uint32_t addr_ip, ip; if (ISALIVE(laddr_entry)) continue; memset(laddr_rule, 0, sizeof(ipvs_laddr_t)); laddr_rule->af = laddr_entry->addr.ss_family; if (laddr_entry->addr.ss_family == AF_INET6) { inet_sockaddrip6(&laddr_entry->addr, &laddr_rule->addr.in6); ip = laddr_rule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&laddr_entry->addr); } for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= laddr_entry->range; addr_ip += 0x01000000) { if (laddr_entry->addr.ss_family == AF_INET6) laddr_rule->addr.in6.s6_addr32[3] = addr_ip; else laddr_rule->addr.ip = addr_ip; if (vs->vsgname) { ipvs_new_laddr_vsg(vs); } else { srule->af = vs->addr.ss_family; if (srule->af == AF_INET6) inet_sockaddrip6(&vs->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vs->addr); srule->port = inet_sockaddrport(&vs->addr); /* local address group channel */ ipvs_talk(IP_VS_SO_SET_ADDLADDR); } } } }
static void ipvs_new_laddr_vsg(virtual_server *vs) { list l; element e; virtual_server_group *vsg; virtual_server_group_entry *vsg_entry; vsg = ipvs_get_group_by_name(vs->vsgname, check_data->vs_group); if (!vsg) return; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* will be set later */ if (!ISALIVE(vsg_entry)) continue; srule->af = vsg_entry->addr.ss_family; if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); } else srule->addr.ip = inet_sockaddrip4(&vsg_entry->addr); srule->port = inet_sockaddrport(&vsg_entry->addr); /* local address group channel */ ipvs_talk(IP_VS_SO_SET_ADDLADDR); } /* visit range list */ l = vsg->range; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); uint32_t addr_ip, ip; /* will be set later */ if (!ISALIVE(vsg_entry)) continue; srule->af = vsg_entry->addr.ss_family; if (srule->af == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); ip = srule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&vsg_entry->addr); } /* Parse the whole range */ for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; srule->addr.in6.s6_addr32[3] = addr_ip; } else { srule->addr.ip = addr_ip; } srule->port = inet_sockaddrport(&vsg_entry->addr); ipvs_talk(IP_VS_SO_SET_ADDLADDR); } } }
/* manipulate add/remove rs according to alive state */ void perform_svr_state(int alive, virtual_server * vs, real_server * rs) { char rsip[INET6_ADDRSTRLEN]; /* * | ISALIVE(rs) | alive | context * | 0 | 0 | first check failed under alpha mode, unreachable here * | 0 | 1 | RS went up, add it to the pool * | 1 | 0 | RS went down, remove it from the pool * | 1 | 1 | first check succeeded w/o alpha mode, unreachable here */ if (!ISALIVE(rs) && alive) { log_message(LOG_INFO, "%s service [%s]:%d to VS [%s]:%d" , (rs->inhibit) ? "Enabling" : "Adding" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* Add only if we have quorum or no sorry server */ if (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr)) { ipvs_cmd(LVS_CMD_ADD_DEST, check_data->vs_group, vs, rs); } rs->alive = alive; if (rs->notify_up) { log_message(LOG_INFO, "Executing [%s] for service [%s]:%d in VS [%s]:%d" , rs->notify_up , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(rs->notify_up); } /* We may have gained quorum */ update_quorum_state(vs); } if (ISALIVE(rs) && !alive) { log_message(LOG_INFO, "%s service [%s]:%d from VS [%s]:%d" , (rs->inhibit) ? "Disabling" : "Removing" , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); /* server is down, it is removed from the LVS realserver pool * Remove only if we have quorum or no sorry server */ if (vs->quorum_state == UP || !vs->s_svr || !ISALIVE(vs->s_svr)) { ipvs_cmd(LVS_CMD_DEL_DEST, check_data->vs_group, vs, rs); } rs->alive = alive; if (rs->notify_down) { log_message(LOG_INFO, "Executing [%s] for service [%s]:%d in VS [%s]:%d" , rs->notify_down , inet_sockaddrtos2(&rs->addr, rsip) , ntohs(inet_sockaddrport(&rs->addr)) , (vs->vsgname) ? vs->vsgname : inet_sockaddrtos(&vs->addr) , ntohs(inet_sockaddrport(&vs->addr))); notify_exec(rs->notify_down); } /* We may have lost quorum */ update_quorum_state(vs); } }
static u_char* check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static struct counter64 counter64_ret; virtual_server_t *v; element e; if ((v = (virtual_server_t *) snmp_header_list_table(vp, name, length, exact, var_len, write_method, check_data->vs)) == NULL) return NULL; switch (vp->magic) { case CHECK_SNMP_VSTYPE: if (v->vsgname) long_ret.u = 3; else if (v->vfwmark) long_ret.u = 1; else long_ret.u = 2; return (u_char*)&long_ret; case CHECK_SNMP_VSNAMEGROUP: if (!v->vsgname) break; *var_len = strlen(v->vsgname); return (u_char*)v->vsgname; case CHECK_SNMP_VSFWMARK: if (!v->vfwmark) break; long_ret.u = v->vfwmark; return (u_char*)&long_ret; case CHECK_SNMP_VSADDRTYPE: if (v->vfwmark || v->vsgname) break; long_ret.u = (v->addr.ss_family == AF_INET6) ? 2:1; return (u_char*)&long_ret; case CHECK_SNMP_VSADDRESS: if (v->vfwmark || v->vsgname) break; RETURN_IP46ADDRESS(v); break; case CHECK_SNMP_VSPORT: if (v->vfwmark || v->vsgname) break; long_ret.u = htons(inet_sockaddrport(&v->addr)); return (u_char *)&long_ret; case CHECK_SNMP_VSPROTOCOL: long_ret.u = (v->service_type == IPPROTO_TCP)?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSLOADBALANCINGALGO: if (!strcmp(v->sched, "rr")) long_ret.u = 1; else if (!strcmp(v->sched, "wrr")) long_ret.u = 2; else if (!strcmp(v->sched, "lc")) long_ret.u = 3; else if (!strcmp(v->sched, "wlc")) long_ret.u = 4; else if (!strcmp(v->sched, "lblc")) long_ret.u = 5; else if (!strcmp(v->sched, "lblcr")) long_ret.u = 6; else if (!strcmp(v->sched, "dh")) long_ret.u = 7; else if (!strcmp(v->sched, "sh")) long_ret.u = 8; else if (!strcmp(v->sched, "sed")) long_ret.u = 9; else if (!strcmp(v->sched, "nq")) long_ret.u = 10; else long_ret.u = 99; return (u_char*)&long_ret; case CHECK_SNMP_VSLOADBALANCINGKIND: long_ret.u = 0; switch (v->loadbalancing_kind) { case IP_VS_CONN_F_MASQ: long_ret.u = 1; break; case IP_VS_CONN_F_DROUTE: long_ret.u = 2; break; case IP_VS_CONN_F_TUNNEL: long_ret.u = 3; break; } if (!long_ret.u) break; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATUS: long_ret.u = v->alive?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSVIRTUALHOST: if (!v->virtualhost) break; *var_len = strlen(v->virtualhost); return (u_char*)v->virtualhost; case CHECK_SNMP_VSPERSIST: long_ret.u = (v->persistence_timeout)?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSPERSISTTIMEOUT: if (!v->persistence_timeout) break; long_ret.u = v->persistence_timeout; return (u_char*)&long_ret; case CHECK_SNMP_VSPERSISTGRANULARITY: if (!v->persistence_granularity || v->addr.ss_family == AF_INET6) break; *var_len = sizeof(v->persistence_granularity); return (u_char*)&v->persistence_granularity; case CHECK_SNMP_VSPERSISTGRANULARITY6: if (!v->persistence_granularity || v->addr.ss_family == AF_INET) break; *var_len = sizeof(v->persistence_granularity); return (u_char*)&v->persistence_granularity; case CHECK_SNMP_VSDELAYLOOP: if (v->delay_loop >= TIMER_MAX_SEC) long_ret.u = v->delay_loop/TIMER_HZ; else long_ret.u = v->delay_loop; return (u_char*)&long_ret; case CHECK_SNMP_VSHASUSPEND: long_ret.u = v->ha_suspend?1:2; return (u_char*)&long_ret; #ifdef IP_VS_SVC_F_ONEPACKET case CHECK_SNMP_VSOPS: long_ret.u = v->flags & IP_VS_SVC_F_ONEPACKET?1:2; return (u_char*)&long_ret; #endif case CHECK_SNMP_VSALPHA: long_ret.u = v->alpha?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSOMEGA: long_ret.u = v->omega?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUM: long_ret.u = v->quorum; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUMSTATUS: long_ret.u = v->quorum_state?1:2; return (u_char*)&long_ret; case CHECK_SNMP_VSQUORUMUP: if (!v->quorum_up) break; *var_len = strlen(v->quorum_up->name); return (u_char*)v->quorum_up->name; case CHECK_SNMP_VSQUORUMDOWN: if (!v->quorum_down) break; *var_len = strlen(v->quorum_down->name); return (u_char*)v->quorum_down->name; case CHECK_SNMP_VSHYSTERESIS: long_ret.u = v->hysteresis; return (u_char*)&long_ret; case CHECK_SNMP_VSREALTOTAL: if (LIST_ISEMPTY(v->rs)) long_ret.u = 0; else long_ret.u = LIST_SIZE(v->rs); return (u_char*)&long_ret; case CHECK_SNMP_VSREALUP: long_ret.u = 0; if (!LIST_ISEMPTY(v->rs)) for (e = LIST_HEAD(v->rs); e; ELEMENT_NEXT(e)) if (((real_server_t *)ELEMENT_DATA(e))->alive) long_ret.u++; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSCONNS: ipvs_update_stats(v); long_ret.u = v->stats.conns; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSINPKTS: ipvs_update_stats(v); long_ret.u = v->stats.inpkts; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSOUTPKTS: ipvs_update_stats(v); long_ret.u = v->stats.outpkts; return (u_char*)&long_ret; case CHECK_SNMP_VSSTATSINBYTES: ipvs_update_stats(v); counter64_ret.low = v->stats.inbytes & 0xffffffff; counter64_ret.high = v->stats.inbytes >> 32; *var_len = sizeof(struct counter64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSSTATSOUTBYTES: ipvs_update_stats(v); counter64_ret.low = v->stats.outbytes & 0xffffffff; counter64_ret.high = v->stats.outbytes >> 32; *var_len = sizeof(struct counter64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATECPS: ipvs_update_stats(v); long_ret.u = v->stats.cps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINPPS: ipvs_update_stats(v); long_ret.u = v->stats.inpps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTPPS: ipvs_update_stats(v); long_ret.u = v->stats.outpps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINBPS: ipvs_update_stats(v); long_ret.u = v->stats.inbps; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTBPS: ipvs_update_stats(v); long_ret.u = v->stats.outbps; return (u_char*)&long_ret; #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_VSSTATSCONNS64: ipvs_update_stats(v); counter64_ret.low = v->stats.conns & 0xffffffff; counter64_ret.high = v->stats.conns >> 32; *var_len = sizeof(struct counter64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSSTATSINPKTS64: ipvs_update_stats(v); counter64_ret.low = v->stats.inpkts & 0xffffffff; counter64_ret.high = v->stats.inpkts >> 32; *var_len = sizeof(struct counter64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSSTATSOUTPKTS64: ipvs_update_stats(v); counter64_ret.low = v->stats.outpkts & 0xffffffff; counter64_ret.high = v->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATECPSLOW: ipvs_update_stats(v); long_ret.u = v->stats.cps & 0xffffffff; return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATECPSHIGH: ipvs_update_stats(v); long_ret.u = v->stats.cps >> 32; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINPPSLOW: ipvs_update_stats(v); long_ret.u = v->stats.inpps & 0xffffffff; return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATEINPPSHIGH: ipvs_update_stats(v); long_ret.u = v->stats.inpps >> 32; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTPPSLOW: ipvs_update_stats(v); long_ret.u = v->stats.outpps & 0xffffffff; return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATEOUTPPSHIGH: ipvs_update_stats(v); long_ret.u = v->stats.outpps >> 32; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEINBPSLOW: ipvs_update_stats(v); long_ret.u = v->stats.inbps & 0xffffffff; return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATEINBPSHIGH: ipvs_update_stats(v); long_ret.u = v->stats.inbps >> 32; return (u_char*)&long_ret; case CHECK_SNMP_VSRATEOUTBPSLOW: ipvs_update_stats(v); long_ret.u = v->stats.outbps & 0xffffffff; return (u_char*)&counter64_ret; case CHECK_SNMP_VSRATEOUTBPSHIGH: ipvs_update_stats(v); long_ret.u = v->stats.outbps >> 32; return (u_char*)&long_ret; #endif #ifdef IP_VS_SVC_F_SCHED1 case CHECK_SNMP_VSHASHED: long_ret.u = v->flags & IP_VS_SVC_F_HASHED ? 1 : 2; return (u_char*)&long_ret; case CHECK_SNMP_VSSHFALLBACK: long_ret.u = v->flags & IP_VS_SVC_F_SCHED_SH_FALLBACK ? 1 : 2; return (u_char*)&long_ret; case CHECK_SNMP_VSSHPORT: long_ret.u = v->flags & IP_VS_SVC_F_SCHED_SH_PORT ? 1 : 2; return (u_char*)&long_ret; case CHECK_SNMP_VSSCHED3: long_ret.u = v->flags & IP_VS_SVC_F_SCHED3 ? 1 : 2; return (u_char*)&long_ret; #endif default: return NULL; } if (!exact && (name[*length-1] < MAX_SUBID)) return check_snmp_virtualserver(vp, name, length, exact, var_len, write_method); return NULL; }
static void ipvs_laddr_vsg_cmd(int cmd, list vs_group, virtual_server * vs, local_addr_group *laddr_group) { virtual_server_group *vsg = ipvs_get_group_by_name(vs->vsgname, vs_group); virtual_server_group_entry *vsg_entry; list l; element e; if (!vsg) return; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* reloading may make laddr_set true */ if (vsg_entry->laddr_set && (cmd == IP_VS_SO_SET_ADDLADDR)) continue; vsg_entry->laddr_set = (cmd == IP_VS_SO_SET_ADDLADDR) ? 1:0; srule->af = vsg_entry->addr.ss_family; if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); } else srule->addr.ip = inet_sockaddrip4(&vsg_entry->addr); srule->port = inet_sockaddrport(&vsg_entry->addr); /* local address group channel */ ipvs_laddr_group_cmd(cmd, laddr_group); } /* visit range list */ l = vsg->range; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); uint32_t addr_ip, ip; if (vsg_entry->laddr_set && (cmd == IP_VS_SO_SET_ADDLADDR)) continue; vsg_entry->laddr_set = (cmd == IP_VS_SO_SET_ADDLADDR) ? 1:0; srule->af = vsg_entry->addr.ss_family; if (srule->af == AF_INET6) { inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); ip = srule->addr.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&vsg_entry->addr); } /* Parse the whole range */ for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= vsg_entry->range; addr_ip += 0x01000000) { if (srule->af == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; srule->addr.in6.s6_addr32[3] = addr_ip; } else { srule->addr.ip = addr_ip; } srule->port = inet_sockaddrport(&vsg_entry->addr); ipvs_laddr_group_cmd(cmd, laddr_group); } } }
/* Remove a specific vs group entry */ int ipvs_group_remove_entry(virtual_server *vs, virtual_server_group_entry *vsge) { real_server *rs; element e; list l = vs->rs; /* Clean target rules */ memset(srule, 0, sizeof(ipvs_service_t)); memset(drule, 0, sizeof(ipvs_dest_t)); /* Process realserver queue */ for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { rs = ELEMENT_DATA(e); if (rs->alive) { /* Prepare the IPVS rule */ if (!drule->addr.ip) { /* Setting IPVS rule with vs root rs */ ipvs_set_rule(IP_VS_SO_SET_DELDEST, vs, rs); } else { drule->af = rs->addr.ss_family; if (rs->addr.ss_family == AF_INET6) inet_sockaddrip6(&rs->addr, &drule->addr.in6); else drule->addr.ip = inet_sockaddrip4(&rs->addr); drule->port = inet_sockaddrport(&rs->addr); drule->weight = rs->weight; } /* Set vs rule */ if (vsge->range) { ipvs_group_range_cmd(IP_VS_SO_SET_DELDEST, vsge); } else { srule->af = vsge->addr.ss_family; if (vsge->addr.ss_family == AF_INET6) inet_sockaddrip6(&vsge->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vsge->addr); srule->port = inet_sockaddrport(&vsge->addr); srule->fwmark = vsge->vfwmark; drule->u_threshold = rs->u_threshold; drule->l_threshold = rs->l_threshold; /* Talk to the IPVS channel */ ipvs_talk(IP_VS_SO_SET_DELDEST); } } } /* In case of all rs is unalive */ ipvs_set_rule(IP_VS_SO_SET_DEL, vs, NULL); /* Remove VS entry */ if (vsge->range) ipvs_group_range_cmd(IP_VS_SO_SET_DEL, vsge); else { srule->af = vsge->addr.ss_family; if (vsge->addr.ss_family == AF_INET6) inet_sockaddrip6(&vsge->addr, &srule->addr.in6); else srule->addr.ip = inet_sockaddrip4(&vsge->addr); srule->port = inet_sockaddrport(&vsge->addr); srule->fwmark = vsge->vfwmark; ipvs_talk(IP_VS_SO_SET_DEL); } return IPVS_SUCCESS; }
/* set IPVS group rules */ static void ipvs_group_cmd(int cmd, list vs_group, real_server * rs, char * vsgname) { virtual_server_group *vsg = ipvs_get_group_by_name(vsgname, vs_group); virtual_server_group_entry *vsg_entry; list l; element e; /* return if jointure fails */ if (!vsg) return; /* visit addr_ip list */ l = vsg->addr_ip; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); srule->af = vsg_entry->addr.ss_family; if (vsg_entry->addr.ss_family == AF_INET6) { if (srule->netmask == 0xffffffff) srule->netmask = 128; inet_sockaddrip6(&vsg_entry->addr, &srule->addr.in6); } else srule->addr.ip = inet_sockaddrip4(&vsg_entry->addr); srule->port = inet_sockaddrport(&vsg_entry->addr); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit vfwmark list */ l = vsg->vfwmark; srule->addr.ip = 0; srule->af = 0; srule->port = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); srule->af = AF_INET; srule->fwmark = vsg_entry->vfwmark; /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_talk(cmd); IPVS_SET_ALIVE(cmd, vsg_entry); } } /* visit range list */ l = vsg->range; srule->fwmark = 0; for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { vsg_entry = ELEMENT_DATA(e); /* Talk to the IPVS channel */ if (IPVS_ALIVE(cmd, vsg_entry, rs)) { ipvs_group_range_cmd(cmd, vsg_entry); IPVS_SET_ALIVE(cmd, vsg_entry); } } }
static u_char* check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static uint32_t ip; static struct in6_addr ip6; oid *target, current[2], best[2]; int result; size_t target_len; unsigned curgroup = 0, curentry; element e1, e2; virtual_server_group_t *group; virtual_server_group_entry_t *e, *be = NULL; int state; list l; if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) { memcpy(name, vp->name, sizeof(oid) * vp->namelen); *length = vp->namelen; } *write_method = 0; *var_len = sizeof(long); if (LIST_ISEMPTY(check_data->vs_group)) return NULL; /* We search the best match: equal if exact, the lower OID in the set of the OID strictly superior to the target otherwise. */ best[0] = best[1] = MAX_SUBID; /* Our best match */ target = &name[vp->namelen]; /* Our target match */ target_len = *length - vp->namelen; for (e1 = LIST_HEAD(check_data->vs_group); e1; ELEMENT_NEXT(e1)) { group = ELEMENT_DATA(e1); curgroup++; curentry = 0; if (target_len && (curgroup < target[0])) continue; /* Optimization: cannot be part of our set */ if (be) break; /* Optimization: cannot be the lower anymore */ state = STATE_VSGM_FWMARK; while (state != STATE_VSGM_END) { switch (state) { case STATE_VSGM_FWMARK: l = group->vfwmark; break; case STATE_VSGM_ADDRESS: l = group->addr_ip; break; case STATE_VSGM_RANGE: l = group->range; break; default: /* Dunno? */ return NULL; } state++; if (LIST_ISEMPTY(l)) continue; for (e2 = LIST_HEAD(l); e2; ELEMENT_NEXT(e2)) { e = ELEMENT_DATA(e2); curentry++; /* We build our current match */ current[0] = curgroup; current[1] = curentry; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, target_len)) < 0) continue; if ((result == 0) && !exact) continue; if (result == 0) { /* Got an exact match and asked for it */ be = e; goto vsgmember_found; } if (snmp_oid_compare(current, 2, best, 2) < 0) { /* This is our best match */ memcpy(best, current, sizeof(oid) * 2); be = e; goto vsgmember_be_found; } } } } if (be == NULL) /* No best match */ return NULL; if (exact) /* No exact match */ return NULL; vsgmember_be_found: /* Let's use our best match */ memcpy(target, best, sizeof(oid) * 2); *length = (unsigned)vp->namelen + 2; vsgmember_found: switch (vp->magic) { case CHECK_SNMP_VSGROUPMEMBERTYPE: if (be->vfwmark) long_ret.u = 1; else if (be->range) long_ret.u = 3; else long_ret.u = 2; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERFWMARK: if (!be->vfwmark) break; long_ret.u = be->vfwmark; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERADDRTYPE: if (be->vfwmark) break; long_ret.u = (be->addr.ss_family == AF_INET6) ? 2:1; return (u_char *)&long_ret; case CHECK_SNMP_VSGROUPMEMBERADDRESS: if (be->vfwmark || be->range) break; RETURN_IP46ADDRESS(be); break; case CHECK_SNMP_VSGROUPMEMBERADDR1: if (!be->range) break; RETURN_IP46ADDRESS(be); break; case CHECK_SNMP_VSGROUPMEMBERADDR2: if (!be->range) break; if (be->addr.ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&be->addr; *var_len = 16; memcpy(&ip6, &addr6->sin6_addr, sizeof(ip6)); ip6.s6_addr32[3] &= htonl(0xFFFFFF00); ip6.s6_addr32[3] += htonl(be->range); return (u_char *)&ip6; } else { struct sockaddr_in *addr4 = (struct sockaddr_in *)&be->addr; *var_len = 4; ip = (*(uint32_t *)&addr4->sin_addr) & htonl(0xFFFFFF00); ip += htonl(be->range); return (u_char *)&ip; } break; case CHECK_SNMP_VSGROUPMEMBERPORT: if (be->vfwmark) break; long_ret.u = htons(inet_sockaddrport(&be->addr)); return (u_char *)&long_ret; default: return NULL; } /* If we are here, we asked for a non existent data. Try the next one. */ if (!exact && (name[*length-1] < MAX_SUBID)) return check_snmp_vsgroupmember(vp, name, length, exact, var_len, write_method); return NULL; }