int ipvs_stop_daemon(ipvs_daemon_t *dm) { ipvs_func = ipvs_stop_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nlattr *nl_daemon; struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DAEMON, 0); if (!msg) return -1; nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); if (!nl_daemon) goto nla_put_failure; NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); nla_nest_end(msg, nl_daemon); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, (char *)dm, sizeof(*dm)); }
int ipvs_del_dest(ipvs_service_t *svc, ipvs_dest_t *dest) { ipvs_servicedest_t svcdest; ipvs_func = ipvs_del_dest; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DEST, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) goto nla_put_failure; if (ipvs_nl_fill_dest_attr(msg, dest)) goto nla_put_failure; return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif CHECK_COMPAT_SVC(svc, -1); CHECK_COMPAT_DEST(dest, -1); memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DELDEST, (char *)&svcdest, sizeof(svcdest)); out_err: return -1; }
ipvs_daemon_t *ipvs_get_daemon(void) { ipvs_daemon_t *u; socklen_t len; /* note that we need to get the info about two possible daemons, master and backup. */ len = sizeof(*u) * 2; if (!(u = malloc(len))) return NULL; ipvs_func = ipvs_get_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; memset(u, 0, len); msg = ipvs_nl_message(IPVS_CMD_GET_DAEMON, NLM_F_DUMP); if (msg && (ipvs_nl_send_message(msg, ipvs_daemon_parse_cb, u) == 0)) return u; free(u); return NULL; } #endif if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DAEMON, (char *)u, &len)) { free(u); return NULL; } return u; }
int ipvs_zero_service(ipvs_service_t *svc) { ipvs_func = ipvs_zero_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_ZERO, 0); if (!msg) return -1; if (svc->fwmark || memcmp(&in6addr_any, &svc->addr.in6, sizeof(struct in6_addr)) || svc->port) { if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_COMPAT_SVC(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ZERO, (char *)svc, sizeof(struct ip_vs_service_kern)); out_err: return -1; }
int ipvs_init(void) { socklen_t len; ipvs_func = ipvs_init; #ifdef LIBIPVS_USE_NL try_nl = 1; if (ipvs_nl_send_message(NULL, NULL, NULL) == 0) { try_nl = 1; return ipvs_getinfo(); } try_nl = 0; #endif len = sizeof(ipvs_info); if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) return -1; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len)) return -1; return 0; }
ipvs_timeout_t *ipvs_get_timeout(void) { ipvs_timeout_t *u; socklen_t len; len = sizeof(*u); if (!(u = malloc(len))) return NULL; ipvs_func = ipvs_get_timeout; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; memset(u, 0, sizeof(*u)); msg = ipvs_nl_message(IPVS_CMD_GET_TIMEOUT, 0); if (msg && (ipvs_nl_send_message(msg, ipvs_timeout_parse_cb, u) == 0)) return u; free(u); return NULL; } #endif if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUT, (char *)u, &len)) { free(u); return NULL; } return u; }
static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc) { struct nlattr *nl_service; struct ip_vs_flags flags = { .flags = svc->flags, .mask = ~0 }; nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); if (!nl_service) return -1; NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); if (svc->fwmark) { NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); } else { NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &(svc->addr)); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); } NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name); if (svc->pe_name[0]) NLA_PUT_STRING(msg, IPVS_SVC_ATTR_PE_NAME, svc->pe_name); NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout); NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask); nla_nest_end(msg, nl_service); return 0; nla_put_failure: return -1; } #endif int ipvs_add_service(ipvs_service_t *svc) { ipvs_func = ipvs_add_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_SERVICE, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_COMPAT_SVC(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc, sizeof(struct ip_vs_service_kern)); out_err: return -1; }
struct ip_vs_get_services *ipvs_get_services(void) { struct ip_vs_get_services *get; struct ip_vs_get_services_kern *getk; socklen_t len; int i; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; len = sizeof(*get) + sizeof(ipvs_service_entry_t); if (!(get = malloc(len))) return NULL; get->num_services = 0; msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, NLM_F_DUMP); if (msg && (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get) == 0)) return get; free(get); return NULL; } #endif len = sizeof(*get) + sizeof(ipvs_service_entry_t) * ipvs_info.num_services; if (!(get = malloc(len))) return NULL; len = sizeof(*getk) + sizeof(struct ip_vs_service_entry_kern) * ipvs_info.num_services; if (!(getk = malloc(len))) { free(get); return NULL; } ipvs_func = ipvs_get_services; getk->num_services = ipvs_info.num_services; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICES, getk, &len) < 0) { free(get); free(getk); return NULL; } memcpy(get, getk, sizeof(struct ip_vs_get_services)); for (i = 0; i < getk->num_services; i++) { memcpy(&get->entrytable[i], &getk->entrytable[i], sizeof(struct ip_vs_service_entry_kern)); get->entrytable[i].af = AF_INET; get->entrytable[i].addr.ip = get->entrytable[i].__addr_v4; copy_stats_from_kern(&get->entrytable[i].stats64, &get->entrytable[i].stats); } free(getk); return get; }
int ipvs_flush(void) { #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_FLUSH, 0); if (msg && (ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL) == 0)) return 0; return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_FLUSH, NULL, 0); }
int ipvs_start_daemon(ipvs_daemon_t *dm) { struct ip_vs_daemon_kern dmk; ipvs_func = ipvs_start_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nlattr *nl_daemon; struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DAEMON, 0); if (!msg) return -1; nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); if (!nl_daemon) goto nla_put_failure; NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); if (dm->sync_maxlen) NLA_PUT_U16(msg, IPVS_DAEMON_ATTR_SYNC_MAXLEN, dm->sync_maxlen); if (dm->mcast_port) NLA_PUT_U16(msg, IPVS_DAEMON_ATTR_MCAST_PORT, dm->mcast_port); if (dm->mcast_ttl) NLA_PUT_U8(msg, IPVS_DAEMON_ATTR_MCAST_TTL, dm->mcast_ttl); if (AF_INET6 == dm->mcast_af) NLA_PUT(msg, IPVS_DAEMON_ATTR_MCAST_GROUP6, sizeof(dm->mcast_group.in6), &dm->mcast_group.in6); else if (AF_INET == dm->mcast_af) NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_MCAST_GROUP, dm->mcast_group.ip); nla_nest_end(msg, nl_daemon); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif memset(&dmk, 0, sizeof(dmk)); dmk.state = dm->state; strcpy(dmk.mcast_ifn, dm->mcast_ifn); dmk.syncid = dm->syncid; return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STARTDAEMON, (char *)&dmk, sizeof(dmk)); }
int ipvs_del_service(ipvs_service_t *svc) { ipvs_func = ipvs_del_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_SERVICE, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); return -1; } return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); } #endif CHECK_IPV4(svc, -1); return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc, sizeof(struct ip_vs_service_kern)); }
int ipvs_set_timeout(ipvs_timeout_t *to) { ipvs_func = ipvs_set_timeout; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_TIMEOUT, 0); if (!msg) return -1; NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, to->tcp_timeout); NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, to->tcp_fin_timeout); NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, to->udp_timeout); return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); nla_put_failure: nlmsg_free(msg); return -1; } #endif return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_TIMEOUT, (char *)to, sizeof(*to)); }
int ipvs_getinfo(void) { socklen_t len; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; msg = ipvs_nl_message(IPVS_CMD_GET_INFO, 0); if (msg) return ipvs_nl_send_message(msg, ipvs_getinfo_parse_cb, NULL); return -1; } #endif ipvs_func = ipvs_getinfo; len = sizeof(ipvs_info); return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len); }
ipvs_daemon_t *ipvs_get_daemon(void) { struct ip_vs_daemon_kern dmk[2]; ipvs_daemon_t *u; socklen_t len; int i; /* note that we need to get the info about two possible daemons, master and backup. */ len = sizeof(*u) * 2; u = calloc(len, 1); if (!u) return NULL; ipvs_func = ipvs_get_daemon; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; msg = ipvs_nl_message(IPVS_CMD_GET_DAEMON, NLM_F_DUMP); if (msg && (ipvs_nl_send_message(msg, ipvs_daemon_parse_cb, u) == 0)) return u; free(u); return NULL; } #endif if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DAEMON, (char *)dmk, &len)) { free(u); return NULL; } for (i = 0; i < 2; i++) { u[i].state = dmk[i].state; strncpy(u[i].mcast_ifn, dmk[i].mcast_ifn, IP_VS_IFNAME_MAXLEN); u[i].syncid = dmk[i].syncid; } return u; }
ipvs_service_entry_t * ipvs_get_service(u_int32_t fwmark, u_int16_t af, u_int16_t protocol, union nf_inet_addr addr, u_int16_t port) { ipvs_service_entry_t *svc; socklen_t len; ipvs_func = ipvs_get_service; #ifdef LIBIPVS_USE_NL if (try_nl) { struct ip_vs_get_services *get; struct nl_msg *msg; ipvs_service_t tsvc; svc = malloc(sizeof(*svc)); if (!svc) return NULL; tsvc.fwmark = fwmark; tsvc.af = af; tsvc.protocol= protocol; tsvc.addr = addr; tsvc.port = port; if (!(get = malloc(sizeof(*get) + sizeof(ipvs_service_entry_t)))) goto ipvs_get_service_err2; get->num_services = 0; msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, 0); if (!msg) goto ipvs_get_service_err; if (ipvs_nl_fill_service_attr(msg, &tsvc)) goto nla_put_failure; if (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get)) goto ipvs_get_service_err; memcpy(svc, &(get->entrytable[0]), sizeof(*svc)); free(get); return svc; nla_put_failure: nlmsg_free(msg); ipvs_get_service_err: free(get); ipvs_get_service_err2: free(svc); return NULL; } #endif len = sizeof(*svc); svc = calloc(1, len); if (!svc) return NULL; svc->fwmark = fwmark; svc->af = af; svc->protocol = protocol; svc->addr = addr; svc->port = port; CHECK_COMPAT_SVC(svc, NULL); if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, (char *)svc, &len)) { free(svc); return NULL; } svc->af = AF_INET; svc->addr.ip = svc->__addr_v4; svc->pe_name[0] = '\0'; return svc; out_err: free(svc); return NULL; }
struct ip_vs_get_dests *ipvs_get_dests(ipvs_service_entry_t *svc) { struct ip_vs_get_dests *d; struct ip_vs_get_dests_kern *dk; socklen_t len; int i; len = sizeof(*d) + sizeof(ipvs_dest_entry_t) * svc->num_dests; if (!(d = malloc(len))) return NULL; ipvs_func = ipvs_get_dests; #ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; struct nlattr *nl_service; if (svc->num_dests == 0) d = realloc(d,sizeof(*d) + sizeof(ipvs_dest_entry_t)); d->fwmark = svc->fwmark; d->protocol = svc->protocol; d->addr = svc->addr; d->port = svc->port; d->num_dests = svc->num_dests; d->af = svc->af; msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); if (!msg) goto ipvs_nl_dest_failure; nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); if (!nl_service) goto nla_put_failure; NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); if (svc->fwmark) { NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); } else { NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); } nla_nest_end(msg, nl_service); if (ipvs_nl_send_message(msg, ipvs_dests_parse_cb, &d)) goto ipvs_nl_dest_failure; return d; nla_put_failure: nlmsg_free(msg); ipvs_nl_dest_failure: free(d); return NULL; } #endif if (svc->af != AF_INET) { errno = EAFNOSUPPORT; free(d); return NULL; } len = sizeof(*dk) + sizeof(struct ip_vs_dest_entry_kern) * svc->num_dests; if (!(dk = malloc(len))) { free(d); return NULL; } dk->fwmark = svc->fwmark; dk->protocol = svc->protocol; dk->addr = svc->addr.ip; dk->port = svc->port; dk->num_dests = svc->num_dests; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DESTS, dk, &len) < 0) { free(d); free(dk); return NULL; } memcpy(d, dk, sizeof(struct ip_vs_get_dests_kern)); d->af = AF_INET; d->addr.ip = d->__addr_v4; for (i = 0; i < dk->num_dests; i++) { memcpy(&d->entrytable[i], &dk->entrytable[i], sizeof(struct ip_vs_dest_entry_kern)); d->entrytable[i].af = AF_INET; d->entrytable[i].addr.ip = d->entrytable[i].__addr_v4; } free(dk); return d; }