static int smtp_send_thread(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); if (thread->type == THREAD_WRITE_TIMEOUT) { log_message(LOG_INFO, "Timeout sending data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } SMTP_FSM_SEND(smtp->stage, thread); /* Handle END command */ if (smtp->stage == END) { SMTP_FSM_READ(QUIT, thread, 0); return 0; } /* Registering next smtp command processing thread */ if (smtp->stage != ERROR) { thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); } else { log_message(LOG_INFO, "Can not send data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); } return 0; }
/* * 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)); }
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; }
/* 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); } }
/* 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; } } } }
/* 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); }
static int connection_timeout(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "Timeout connecting SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); free_smtp_all(smtp); return 0; }
/* layer4 connection handlers */ static int connection_error(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "SMTP connection ERROR to [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); free_smtp_all(smtp); return 0; }
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); }
static int connection_success(thread_t * thread) { smtp_t *smtp = THREAD_ARG(thread); log_message(LOG_INFO, "Remote SMTP server [%s]:%d connected." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); smtp->stage = connect_success; thread_add_read(thread->master, smtp_read_thread, smtp, smtp->fd, global_data->smtp_connection_to); return 0; }
static int connection_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 220) { smtp->stage++; } else { log_message(LOG_INFO, "Error connecting SMTP server[%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; }
static int data_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 354) { smtp->stage++; } else { log_message(LOG_INFO, "Error processing DATA cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; }
/* 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); } }
static int body_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); if (status == 250) { log_message(LOG_INFO, "SMTP alert successfully sent."); smtp->stage++; } else { log_message(LOG_INFO, "Error processing DOT cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; }
static int connection_in_progress(thread_t * thread) { int status; DBG("SMTP connection to [%s]:%d now IN_PROGRESS.", inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); /* * Here we use the propriety of a union structure, * each element of the structure have the same value. */ status = tcp_socket_state(thread->u.fd, thread, connection_in_progress); if (status != connect_in_progress) SMTP_FSM_SEND(status, thread); return 0; }
/* 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; } }
static int rcpt_code(thread_t * thread, int status) { smtp_t *smtp = THREAD_ARG(thread); char *fetched_email; if (status == 250) { smtp->email_it++; fetched_email = fetch_next_email(smtp); if (!fetched_email) smtp->stage++; } else { log_message(LOG_INFO, "Error processing RCPT cmd on SMTP server [%s]:%d." " SMTP status code = %d" , inet_sockaddrtos(&global_data->smtp_server) , SMTP_PORT, status); smtp->stage = ERROR; } return 0; }
void vrrp_print(FILE *file, void *data) { vrrp_t *vrrp = data; char auth_data[sizeof(vrrp->auth_data) + 1]; fprintf(file, " VRRP Instance = %s\n", vrrp->iname); fprintf(file, " VRRP Version = %d\n", vrrp->version); if (vrrp->family == AF_INET6) fprintf(file, " Using Native IPv6\n"); if (vrrp->state == VRRP_STATE_BACK) { fprintf(file, " State = BACKUP\n"); fprintf(file, " Master router = %s\n", inet_sockaddrtos(&vrrp->master_saddr)); fprintf(file, " Master priority = %d\n", vrrp->master_priority); } else if (vrrp->state == VRRP_STATE_FAULT) fprintf(file, " State = FAULT\n"); else if (vrrp->state == VRRP_STATE_MAST) fprintf(file, " State = MASTER\n"); else fprintf(file, " State = %d\n", vrrp->state); fprintf(file, " Last transition = %ld\n", vrrp->last_transition.tv_sec); fprintf(file, " Listening device = %s\n", IF_NAME(vrrp->ifp)); if (vrrp->dont_track_primary) fprintf(file, " VRRP interface tracking disabled\n"); fprintf(file, " Using src_ip = %s\n", inet_sockaddrtos(&vrrp->saddr)); if (vrrp->lvs_syncd_if) fprintf(file, " Runing LVS sync daemon on interface = %s\n", vrrp->lvs_syncd_if); if (vrrp->garp_delay) fprintf(file, " Gratuitous ARP delay = %d\n", vrrp->garp_delay/TIMER_HZ); fprintf(file, " Virtual Router ID = %d\n", vrrp->vrid); fprintf(file, " Priority = %d\n", vrrp->base_priority); fprintf(file, " Advert interval = %d %s\n", (vrrp->version == VRRP_VERSION_2) ? (vrrp->adver_int / TIMER_HZ) : (vrrp->adver_int * 1000 / TIMER_HZ), (vrrp->version == VRRP_VERSION_2) ? "sec" : "milli-sec"); fprintf(file, " Accept = %s\n", ((vrrp->accept) ? "enabled" : "disabled")); if (vrrp->nopreempt) fprintf(file, " Preempt = disabled\n"); else fprintf(file, " Preempt = enabled\n"); if (vrrp->preempt_delay) fprintf(file, " Preempt delay = %ld secs\n", vrrp->preempt_delay / TIMER_HZ); if (vrrp->auth_type) { fprintf(file, " Authentication type = %s\n", (vrrp->auth_type == VRRP_AUTH_AH) ? "IPSEC_AH" : "SIMPLE_PASSWORD"); if (vrrp->auth_type != VRRP_AUTH_AH) { /* vrrp->auth_data is not \0 terminated */ memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data)); auth_data[sizeof(vrrp->auth_data)] = '\0'; fprintf(file, " Password = %s\n", auth_data); } } else fprintf(file, " Authentication type = none\n"); if (!LIST_ISEMPTY(vrrp->track_ifp)) { fprintf(file, " Tracked interfaces = %d\n", LIST_SIZE(vrrp->track_ifp)); vrrp_print_list(file, vrrp->track_ifp, &if_print); } if (!LIST_ISEMPTY(vrrp->track_script)) { fprintf(file, " Tracked scripts = %d\n", LIST_SIZE(vrrp->track_script)); vrrp_print_list(file, vrrp->track_script, &vscript_print); } if (!LIST_ISEMPTY(vrrp->vip)) { fprintf(file, " Virtual IP = %d\n", LIST_SIZE(vrrp->vip)); vrrp_print_list(file, vrrp->vip, &address_print); } if (!LIST_ISEMPTY(vrrp->evip)) { fprintf(file, " Virtual IP Excluded = %d\n", LIST_SIZE(vrrp->evip)); vrrp_print_list(file, vrrp->evip, &address_print); } if (!LIST_ISEMPTY(vrrp->vroutes)) { fprintf(file, " Virtual Routes = %d\n", LIST_SIZE(vrrp->vroutes)); vrrp_print_list(file, vrrp->vroutes, &route_print); } if (!LIST_ISEMPTY(vrrp->vrules)) { fprintf(file, " Virtual Rules = %d\n", LIST_SIZE(vrrp->vrules)); vrrp_print_list(file, vrrp->vrules, &rule_print); } if (vrrp->script_backup) fprintf(file, " Backup state transition script = %s\n", vrrp->script_backup); if (vrrp->script_master) fprintf(file, " Master state transition script = %s\n", vrrp->script_master); if (vrrp->script_fault) fprintf(file, " Fault state transition script = %s\n", vrrp->script_fault); if (vrrp->script_stop) fprintf(file, " Stop state transition script = %s\n", vrrp->script_stop); if (vrrp->script) fprintf(file, " Generic state transition script = '%s'\n", vrrp->script); if (vrrp->smtp_alert) fprintf(file, " Using smtp notification\n"); }
/* SMTP protocol handlers */ static int smtp_read_thread(thread_t * thread) { smtp_t *smtp; char *buffer; char *reply; int rcv_buffer_size = 0; int status = -1; smtp = THREAD_ARG(thread); if (thread->type == THREAD_READ_TIMEOUT) { log_message(LOG_INFO, "Timeout reading data to remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return -1; } buffer = smtp->buffer; rcv_buffer_size = read(thread->u.fd, buffer + smtp->buflen, SMTP_BUFFER_LENGTH - smtp->buflen); if (rcv_buffer_size == -1) { if (errno == EAGAIN) goto end; log_message(LOG_INFO, "Error reading data from remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } /* received data overflow buffer size ? */ if (smtp->buflen >= SMTP_BUFFER_MAX) { log_message(LOG_INFO, "Received buffer from remote SMTP server [%s]:%d" " overflow our get read buffer length." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); return 0; } else { smtp->buflen += rcv_buffer_size; buffer[smtp->buflen] = 0; /* NULL terminate */ } end: /* parse the buffer, finding the last line of the response for the code */ reply = buffer; while (reply < buffer + smtp->buflen) { char *p; p = strstr(reply, "\r\n"); if (!p) { memmove(buffer, reply, smtp->buflen - (reply - buffer)); smtp->buflen -= (reply - buffer); buffer[smtp->buflen] = 0; thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); return 0; } if (reply[3] == '-') { /* Skip over the \r\n */ reply = p + 2; continue; } status = ((reply[0] - '0') * 100) + ((reply[1] - '0') * 10) + (reply[2] - '0'); reply = p + 2; break; } memmove(buffer, reply, smtp->buflen - (reply - buffer)); smtp->buflen -= (reply - buffer); buffer[smtp->buflen] = 0; if (status == -1) { thread_add_read(thread->master, smtp_read_thread, smtp, thread->u.fd, global_data->smtp_connection_to); return 0; } SMTP_FSM_READ(smtp->stage, thread, status); /* Registering next smtp command processing thread */ if (smtp->stage != ERROR) { thread_add_write(thread->master, smtp_send_thread, smtp, smtp->fd, global_data->smtp_connection_to); } else { log_message(LOG_INFO, "Can not read data from remote SMTP server [%s]:%d." , inet_sockaddrtos(&global_data->smtp_server), SMTP_PORT); SMTP_FSM_READ(QUIT, thread, 0); } return 0; }
/* 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); } }
/* 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 vrrp_print(FILE *file, void *data) { vrrp_t *vrrp = data; #ifdef _WITH_VRRP_AUTH_ char auth_data[sizeof(vrrp->auth_data) + 1]; #endif char time_str[26]; fprintf(file, " VRRP Instance = %s\n", vrrp->iname); fprintf(file, " VRRP Version = %d\n", vrrp->version); if (vrrp->family == AF_INET6) fprintf(file, " Using Native IPv6\n"); if (vrrp->state == VRRP_STATE_BACK) { fprintf(file, " State = BACKUP\n"); fprintf(file, " Master router = %s\n", inet_sockaddrtos(&vrrp->master_saddr)); fprintf(file, " Master priority = %d\n", vrrp->master_priority); } else if (vrrp->state == VRRP_STATE_FAULT) fprintf(file, " State = FAULT\n"); else if (vrrp->state == VRRP_STATE_MAST) fprintf(file, " State = MASTER\n"); else fprintf(file, " State = %d\n", vrrp->state); ctime_r(&vrrp->last_transition.tv_sec, time_str); time_str[sizeof(time_str)-2] = '\0'; /* Remove '\n' char */ fprintf(file, " Last transition = %ld (%s)\n", vrrp->last_transition.tv_sec, time_str); fprintf(file, " Listening device = %s\n", IF_NAME(vrrp->ifp)); if (vrrp->dont_track_primary) fprintf(file, " VRRP interface tracking disabled\n"); if (vrrp->skip_check_adv_addr) fprintf(file, " Skip checking advert IP addresses\n"); if (vrrp->strict_mode) fprintf(file, " Enforcing VRRP compliance\n"); fprintf(file, " Using src_ip = %s\n", inet_sockaddrtos(&vrrp->saddr)); fprintf(file, " Gratuitous ARP delay = %d\n", vrrp->garp_delay/TIMER_HZ); fprintf(file, " Gratuitous ARP repeat = %d\n", vrrp->garp_rep); fprintf(file, " Gratuitous ARP refresh = %lu\n", vrrp->garp_refresh.tv_sec/TIMER_HZ); fprintf(file, " Gratuitous ARP refresh repeat = %d\n", vrrp->garp_refresh_rep); fprintf(file, " Gratuitous ARP lower priority delay = %d", vrrp->garp_lower_prio_delay / TIMER_HZ); fprintf(file, " Gratuitous ARP lower priority repeat = %d", vrrp->garp_lower_prio_rep); fprintf(file, " Send advert after receive lower priority advert = %s", vrrp->lower_prio_no_advert ? "false" : "true"); fprintf(file, " Virtual Router ID = %d\n", vrrp->vrid); fprintf(file, " Priority = %d\n", vrrp->base_priority); fprintf(file, " Advert interval = %d %s\n", (vrrp->version == VRRP_VERSION_2) ? (vrrp->adver_int / TIMER_HZ) : (vrrp->adver_int / (TIMER_HZ / 1000)), (vrrp->version == VRRP_VERSION_2) ? "sec" : "milli-sec"); fprintf(file, " Accept = %s\n", ((vrrp->accept) ? "enabled" : "disabled")); if (vrrp->nopreempt) fprintf(file, " Preempt = disabled\n"); else fprintf(file, " Preempt = enabled\n"); if (vrrp->preempt_delay) fprintf(file, " Preempt delay = %ld secs\n", vrrp->preempt_delay / TIMER_HZ); #if defined _WITH_VRRP_AUTH_ if (vrrp->auth_type) { fprintf(file, " Authentication type = %s\n", (vrrp->auth_type == VRRP_AUTH_AH) ? "IPSEC_AH" : "SIMPLE_PASSWORD"); if (vrrp->auth_type != VRRP_AUTH_AH) { /* vrrp->auth_data is not \0 terminated */ memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data)); auth_data[sizeof(vrrp->auth_data)] = '\0'; fprintf(file, " Password = %s\n", auth_data); } } else fprintf(file, " Authentication type = none\n"); #endif if (!LIST_ISEMPTY(vrrp->track_ifp)) { fprintf(file, " Tracked interfaces = %d\n", LIST_SIZE(vrrp->track_ifp)); vrrp_print_list(file, vrrp->track_ifp, &if_print); } if (!LIST_ISEMPTY(vrrp->track_script)) { fprintf(file, " Tracked scripts = %d\n", LIST_SIZE(vrrp->track_script)); vrrp_print_list(file, vrrp->track_script, &vscript_print); } if (!LIST_ISEMPTY(vrrp->vip)) { fprintf(file, " Virtual IP = %d\n", LIST_SIZE(vrrp->vip)); vrrp_print_list(file, vrrp->vip, &address_print); } if (!LIST_ISEMPTY(vrrp->evip)) { fprintf(file, " Virtual IP Excluded = %d\n", LIST_SIZE(vrrp->evip)); vrrp_print_list(file, vrrp->evip, &address_print); } #ifdef _HAVE_FIB_ROUTING_ if (!LIST_ISEMPTY(vrrp->vroutes)) { fprintf(file, " Virtual Routes = %d\n", LIST_SIZE(vrrp->vroutes)); vrrp_print_list(file, vrrp->vroutes, &route_print); } if (!LIST_ISEMPTY(vrrp->vrules)) { fprintf(file, " Virtual Rules = %d\n", LIST_SIZE(vrrp->vrules)); vrrp_print_list(file, vrrp->vrules, &rule_print); } #endif if (vrrp->script_backup) fprintf(file, " Backup state transition script = %s\n", vrrp->script_backup); if (vrrp->script_master) fprintf(file, " Master state transition script = %s\n", vrrp->script_master); if (vrrp->script_fault) fprintf(file, " Fault state transition script = %s\n", vrrp->script_fault); if (vrrp->script_stop) fprintf(file, " Stop state transition script = %s\n", vrrp->script_stop); if (vrrp->script) fprintf(file, " Generic state transition script = '%s'\n", vrrp->script); if (vrrp->smtp_alert) fprintf(file, " Using smtp notification\n"); }