From 5f374fc6244281e310e4b4ce17d56bf926484504 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:06:16 +0100 Subject: [PATCH 01/24] ipvs: Add snmp_vs_stats_update_interval for updating SNMP stats The timer for updating VS and RS stats for SNMP was hard coded to 5 seconds. This commit still deffaults to 5 seconds but allows the timer to be configured. Signed-off-by: Quentin Armitage --- doc/man/man5/keepalived.conf.5.in | 7 +++++++ keepalived/check/check_data.c | 15 --------------- keepalived/check/ipvswrapper.c | 6 ++++-- keepalived/core/global_data.c | 4 ++++ keepalived/core/global_parser.c | 12 ++++++++++++ keepalived/include/check_data.h | 4 ++-- keepalived/include/global_data.h | 1 + keepalived/include/ipvswrapper.h | 3 +-- lib/utils.c | 15 +++++++++++++++ lib/utils.h | 1 + 10 files changed, 47 insertions(+), 21 deletions(-) diff --git a/doc/man/man5/keepalived.conf.5.in b/doc/man/man5/keepalived.conf.5.in index 37dcc74618..b90150de81 100644 --- a/doc/man/man5/keepalived.conf.5.in +++ b/doc/man/man5/keepalived.conf.5.in @@ -678,6 +678,13 @@ possibly following any cleanup actions needed. # enable SNMP traps \fBenable_traps\fR + # When SNMP requests are made, the checker process only updates the + # virtual and real server stats from the kernel if the last time the + # stats for that virtual server were read was more than this configured + # interval. The default interval is 5 seconds, and the valid range is + # 1 milli-second to 30 seconds. + \fBsnmp_vs_stats_update_interval\fR + # If Keepalived has been build with DBus support, the following # keywords are available. # -- diff --git a/keepalived/check/check_data.c b/keepalived/check/check_data.c index 74b45aaba7..cfb0e6dabd 100644 --- a/keepalived/check/check_data.c +++ b/keepalived/check/check_data.c @@ -469,21 +469,6 @@ dump_tracking_rs(FILE *fp, const void *data) conf_write(fp, " %s -> %s, weight %d%s", FMT_VS(checker->vs), FMT_RS(checker->rs, checker->vs), top->weight, top->weight_multiplier == -1 ? " reverse" : ""); } -static const char * -format_decimal(unsigned long val, int dp) -{ - static char buf[22]; /* Sufficient for 2^64 as decimal plus decimal point */ - unsigned dp_factor = 1; - int i; - - for (i = 0; i < dp; i++) - dp_factor *= 10; - - snprintf(buf, sizeof(buf), "%lu.%*.*lu", val / dp_factor, dp, dp, val % dp_factor); - - return buf; -} - static void dump_notify_vs_rs_script(FILE *fp, const notify_script_t *script, const char *type, const char *state) { diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index 17611abd05..c31508bdd0 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -911,10 +911,12 @@ ipvs_update_stats(virtual_server_t *vs) uint16_t port; union nf_inet_addr nfaddr; real_server_t *rs; - time_t cur_time = time(NULL); + struct timespec cur_time; uint16_t af; - if (cur_time - vs->lastupdated < STATS_REFRESH) + clock_gettime(CLOCK_MONOTONIC, &cur_time); + if ((unsigned long)((cur_time.tv_sec - vs->lastupdated.tv_sec) * TIMER_HZ + + cur_time.tv_nsec / (NSEC_PER_SEC / TIMER_HZ) - vs->lastupdated.tv_nsec / (NSEC_PER_SEC / TIMER_HZ)) < global_data->snmp_vs_stats_update_interval) return; vs->lastupdated = cur_time; diff --git a/keepalived/core/global_data.c b/keepalived/core/global_data.c index 6e26a76596..dcd16351fb 100644 --- a/keepalived/core/global_data.c +++ b/keepalived/core/global_data.c @@ -281,6 +281,9 @@ alloc_global_data(void) if (snmp_socket) new->snmp_socket = STRDUP(snmp_socket); +#ifdef _WITH_SNMP_CHECKER_ + new->snmp_vs_stats_update_interval = 5 * TIMER_HZ; /* 5 seconds */ +#endif #endif #ifdef _WITH_LVS_ @@ -851,6 +854,7 @@ dump_global_data(FILE *fp, data_t * data) #ifdef _WITH_SNMP_ conf_write(fp, " SNMP traps %s", data->enable_traps ? "enabled" : "disabled"); conf_write(fp, " SNMP socket = %s", data->snmp_socket ? data->snmp_socket : "default (unix:/var/agentx/master)"); + conf_write(fp, " SNMP VS stats update interval = %s", format_decimal(data->snmp_vs_stats_update_interval, TIMER_HZ_DIGITS)); #endif #ifdef _WITH_DBUS_ conf_write(fp, " DBus %s", data->enable_dbus ? "enabled" : "disabled"); diff --git a/keepalived/core/global_parser.c b/keepalived/core/global_parser.c index 92b20554ab..4d72a1e683 100644 --- a/keepalived/core/global_parser.c +++ b/keepalived/core/global_parser.c @@ -1627,6 +1627,17 @@ snmp_checker_handler(__attribute__((unused)) const vector_t *strvec) { global_data->enable_snmp_checker = true; } +static void +snmp_vs_stats_update_interval_handler(const vector_t *strvec) +{ + unsigned long interval; + + /* Valid range is 1 ms to 30s */ + if (read_timer(strvec, 1, &interval, 1000, 30 * TIMER_HZ, true)) + global_data->snmp_vs_stats_update_interval = interval; + else + report_config_error(CONFIG_GENERAL_ERROR, "snmp stats vs update interval '%s' invalid - ignoring", strvec_slot(strvec, 1)); +} #endif #endif @@ -2515,6 +2526,7 @@ init_global_keywords(bool global_active) #endif #ifdef _WITH_SNMP_CHECKER_ install_keyword("enable_snmp_checker", &snmp_checker_handler); + install_keyword("snmp_vs_stats_update_interval", &snmp_vs_stats_update_interval_handler); #endif #endif #ifdef _WITH_DBUS_ diff --git a/keepalived/include/check_data.h b/keepalived/include/check_data.h index 9b9d828559..c805ad3b32 100644 --- a/keepalived/include/check_data.h +++ b/keepalived/include/check_data.h @@ -223,9 +223,9 @@ typedef struct _virtual_server { int smtp_alert; /* Send email on status change */ bool quorum_state_up; /* Reflects result of the last transition done. */ bool reloaded; /* quorum_state was copied from old config while reloading */ -#if defined(_WITH_SNMP_CHECKER_) +#if defined _WITH_SNMP_CHECKER_ /* Statistics */ - time_t lastupdated; + struct timespec lastupdated; #ifndef _WITH_LVS_64BIT_STATS_ struct ip_vs_stats_user stats; #else diff --git a/keepalived/include/global_data.h b/keepalived/include/global_data.h index 3ec1199251..74c66b5790 100644 --- a/keepalived/include/global_data.h +++ b/keepalived/include/global_data.h @@ -251,6 +251,7 @@ typedef struct _data { #endif #ifdef _WITH_LVS_ bool enable_snmp_checker; + unsigned long snmp_vs_stats_update_interval; #endif #endif #ifdef _WITH_DBUS_ diff --git a/keepalived/include/ipvswrapper.h b/keepalived/include/ipvswrapper.h index 434c49cadc..e93338ed3d 100644 --- a/keepalived/include/ipvswrapper.h +++ b/keepalived/include/ipvswrapper.h @@ -82,8 +82,7 @@ extern void remove_fwmark_vs(virtual_server_t *, int); extern void add_fwmark_vs(virtual_server_t *, int); #endif -/* Refresh statistics at most every 5 seconds */ -#define STATS_REFRESH 5 +/* Refresh statistics at most every global_data->snmp_stats_update_interval */ extern void ipvs_update_stats(virtual_server_t * vs); #endif diff --git a/lib/utils.c b/lib/utils.c index afac2e8f02..73a5c1b6be 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -940,6 +940,21 @@ format_mac_buf(char *op, size_t op_len, const unsigned char *addr, size_t addr_l } } +const char * +format_decimal(unsigned long val, int dp) +{ + static char buf[22]; /* Sufficient for 2^64 as decimal plus decimal point */ + unsigned dp_factor = 1; + int i; + + for (i = 0; i < dp; i++) + dp_factor *= 10; + + snprintf(buf, sizeof(buf), "%lu.%*.*lu", val / dp_factor, dp, dp, val % dp_factor); + + return buf; +} + /* Getting localhost official canonical name */ const char * __attribute__((malloc)) get_local_name(void) diff --git a/lib/utils.h b/lib/utils.h index 01748a2a82..34794ab610 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -279,6 +279,7 @@ extern int inet_sockaddrip6(const sockaddr_t *, struct in6_addr *); extern int inet_inaddrcmp(int, const void *, const void *); __attribute__ ((pure)) extern int inet_sockaddrcmp(const sockaddr_t *, const sockaddr_t *) __attribute__ ((pure)); extern void format_mac_buf(char *, size_t, const unsigned char *, size_t); +extern const char *format_decimal(unsigned long, int); extern const char *get_local_name(void) __attribute__((malloc)); extern bool string_equal(const char *, const char *) __attribute__ ((pure)); extern int integer_to_string(const int, char *, size_t); From 7361417a82a01d78e7e0e178f754a5f6746cfe3d Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:07:48 +0100 Subject: [PATCH 02/24] ipvs: Don't call calloc() in ipvs_get_service() We need to use our wrappers around malloc/free calls, so it now just calls MALLOC(). Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 36b9ef374c..9008a7d151 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -1274,7 +1274,7 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add #endif len = sizeof(*svc); - svc = calloc(1, len); + svc = MALLOC(len); if (!svc) return NULL; From f94ddac3b13d0304ca10d0f35f0275f954d8e341 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:09:04 +0100 Subject: [PATCH 03/24] ipvs: Make ipvs_get_dests() use individual parameters Signed-off-by: Quentin Armitage --- keepalived/check/ipvswrapper.c | 2 +- keepalived/check/libipvs.c | 52 ++++++++++++++++------------------ keepalived/include/libipvs.h | 3 +- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index c31508bdd0..7c778edbea 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -857,7 +857,7 @@ ipvs_update_vs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n vs->stats.outbps += serv->stats.outbps; /* Get real servers */ - dests = ipvs_get_dests(serv); + dests = ipvs_get_dests(fwmark, af, vs->service_type, nfaddr, port, serv->user.num_dests); FREE(serv); if (!dests) return; diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 9008a7d151..31821805f5 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -1124,14 +1124,14 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) } #endif /* LIBIPVS_USE_NL */ -struct ip_vs_get_dests_app *ipvs_get_dests(ipvs_service_entry_t *svc) +struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *addr, __u16 port, unsigned num_dests) { struct ip_vs_get_dests_app *d; struct ip_vs_get_dests *dk; socklen_t len; unsigned i; - len = (socklen_t)(sizeof(*d) + sizeof(ipvs_dest_entry_t) * svc->user.num_dests); + len = (socklen_t)(sizeof(*d) + sizeof(ipvs_dest_entry_t) * (num_dests ? num_dests : 1)); if (!(d = MALLOC(len))) return NULL; @@ -1141,14 +1141,12 @@ struct ip_vs_get_dests_app *ipvs_get_dests(ipvs_service_entry_t *svc) if (try_nl) { struct nl_msg *msg; struct nlattr *nl_service; - if (svc->user.num_dests == 0) - d = REALLOC(d,sizeof(*d) + sizeof(ipvs_dest_entry_t)); - d->user.fwmark = svc->user.fwmark; - d->user.protocol = svc->user.protocol; - d->nf_addr = svc->nf_addr; - d->user.port = svc->user.port; - d->user.num_dests = svc->user.num_dests; - d->af = svc->af; + d->user.fwmark = fwmark; + d->user.protocol = protocol; + d->nf_addr = *addr; + d->user.port = port; + d->user.num_dests = num_dests; + d->af = af; msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); if (!msg) @@ -1158,15 +1156,14 @@ struct ip_vs_get_dests_app *ipvs_get_dests(ipvs_service_entry_t *svc) if (!nl_service) goto nla_put_failure; - NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, af); - if (svc->user.fwmark) { - NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->user.fwmark); + if (fwmark) { + NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, fwmark); } else { - NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->user.protocol); - NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->nf_addr), - &svc->nf_addr); - NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->user.port); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, protocol); + NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(*addr), addr); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, port); } nla_nest_end(msg, nl_service); @@ -1183,33 +1180,32 @@ struct ip_vs_get_dests_app *ipvs_get_dests(ipvs_service_entry_t *svc) } #endif /* LIBIPVS_USE_NL */ - if (svc->af != AF_INET) { + if (af != AF_INET) { errno = EAFNOSUPPORT; FREE(d); return NULL; } - len = (socklen_t)(sizeof(*dk) + sizeof(struct ip_vs_dest_entry) * svc->user.num_dests); + len = (socklen_t)(sizeof(*dk) + sizeof(struct ip_vs_dest_entry) * num_dests); if (!(dk = MALLOC(len))) { FREE(d); return NULL; } - dk->fwmark = svc->user.fwmark; - dk->protocol = svc->user.protocol; - dk->addr = svc->nf_addr.ip; - dk->port = svc->user.port; - dk->num_dests = svc->user.num_dests; + dk->fwmark = fwmark; + dk->protocol = protocol; + dk->addr = addr->ip; + dk->port = port; + dk->num_dests = num_dests; - if (getsockopt(sockfd, IPPROTO_IP, - IP_VS_SO_GET_DESTS, dk, &len) < 0) { + 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)); + memcpy(&d->user, dk, sizeof(struct ip_vs_get_dests)); d->af = AF_INET; - d->nf_addr.ip = d->user.addr; + d->nf_addr.ip = dk->addr; for (i = 0; i < dk->num_dests; i++) { memcpy(&d->user.entrytable[i], &dk->entrytable[i], sizeof(struct ip_vs_dest_entry)); diff --git a/keepalived/include/libipvs.h b/keepalived/include/libipvs.h index 245c2fcfbe..b0264b3b17 100644 --- a/keepalived/include/libipvs.h +++ b/keepalived/include/libipvs.h @@ -71,7 +71,8 @@ extern int ipvs_stop_daemon(ipvs_daemon_t *dm); #ifdef _WITH_SNMP_CHECKER_ /* get the destination array of the specified service */ -extern struct ip_vs_get_dests_app *ipvs_get_dests(ipvs_service_entry_t *svc); +extern struct ip_vs_get_dests_app *ipvs_get_dests(__u32, __u16, __u16, union nf_inet_addr *, __u16, unsigned); + /* get an ipvs service entry */ extern ipvs_service_entry_t * From cd8a13ee56987af1f50d8a9b569e58a8e24c0cb3 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:09:47 +0100 Subject: [PATCH 04/24] ipvs: rs_cnt is only used when using SNMP Signed-off-by: Quentin Armitage --- keepalived/check/check_data.c | 2 ++ keepalived/check/check_parser.c | 2 ++ keepalived/include/check_data.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/keepalived/check/check_data.c b/keepalived/check/check_data.c index cfb0e6dabd..913f633642 100644 --- a/keepalived/check/check_data.c +++ b/keepalived/check/check_data.c @@ -1161,7 +1161,9 @@ validate_check_config(void) if (rs_iseq(rs, rs1)) { report_config_error(CONFIG_GENERAL_ERROR, "VS %s: real server %s is duplicated - removing second rs", FMT_VS(vs), FMT_RS(rs, vs)); free_rs(rs); +#ifdef _WITH_SNMP_CHECKER_ vs->rs_cnt--; +#endif rs_removed = true; break; } diff --git a/keepalived/check/check_parser.c b/keepalived/check/check_parser.c index a555511380..dd67a42fd6 100644 --- a/keepalived/check/check_parser.c +++ b/keepalived/check/check_parser.c @@ -670,7 +670,9 @@ rs_end_handler(void) } list_add_tail(¤t_rs->e_list, ¤t_vs->rs); +#ifdef _WITH_SNMP_CHECKER_ current_vs->rs_cnt++; +#endif } static void diff --git a/keepalived/include/check_data.h b/keepalived/include/check_data.h index c805ad3b32..f8290716c2 100644 --- a/keepalived/include/check_data.h +++ b/keepalived/include/check_data.h @@ -205,7 +205,6 @@ typedef struct _virtual_server { if not set on real servers */ int weight; list_head_t rs; /* real_server_t */ - unsigned rs_cnt; /* Number of real_server in list */ int alive; bool alpha; /* Set if alpha mode is default. */ bool omega; /* Omega mode enabled. */ @@ -226,6 +225,7 @@ typedef struct _virtual_server { #if defined _WITH_SNMP_CHECKER_ /* Statistics */ struct timespec lastupdated; + unsigned rs_cnt; /* Number of real_server in list */ #ifndef _WITH_LVS_64BIT_STATS_ struct ip_vs_stats_user stats; #else From 91496f8a2e9e8fe58dfebdde6019aa3a3a266e0d Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:10:51 +0100 Subject: [PATCH 05/24] ipvs: optimise setting tsvc in ipvs_get_service() Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 31821805f5..46ba55ba24 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -1229,19 +1229,12 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add if (try_nl) { struct ip_vs_get_services *get; struct nl_msg *msg; - ipvs_service_t tsvc; + ipvs_service_t tsvc = { .user.fwmark = fwmark, .af = af, .user.protocol = protocol, .nf_addr = *addr, .user.port = port }; svc = MALLOC(sizeof(*svc)); if (!svc) return NULL; - memset(&tsvc, 0, sizeof(tsvc)); - tsvc.user.fwmark = fwmark; - tsvc.af = af; - tsvc.user.protocol= protocol; - tsvc.nf_addr = *addr; - tsvc.user.port = port; - if (!(get = MALLOC(sizeof(*get) + sizeof(ipvs_service_entry_t)))) goto ipvs_get_service_err2; From 97d0ac443e6df158e47f2dca6aab2415534b3f15 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:11:38 +0100 Subject: [PATCH 06/24] configure: add comment re when IPVS netlink support started Signed-off-by: Quentin Armitage --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 46feca7219..0bab7e7d9e 100644 --- a/configure.ac +++ b/configure.ac @@ -1507,6 +1507,7 @@ dnl ----[ Checks for libraries ]---- NETLINK_VER=0 IPVS_USE_NL=No if test .$enable_lvs != .no -a .${enable_libnl} != .no; then + dnl -- IPVS netlink support since linux 2.6.28 - 24/12/08 $PKG_CONFIG --exists libnl-3.0 if test $? -eq 0; then add_pkg_config([libnl-3.0], [NL3], [remove-requires]) From 3a8ea5f55f890ba0a384fc664b13f5e42384b27e Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:12:38 +0100 Subject: [PATCH 07/24] ipvs: Add snmp_rs_stats_update_interval This compliments snmp_vs_stats_update_interval, and also real server stats are now only fetched from the kernel when there is an SNMP request for them; i.e. VS stats and RS stats are updated separately. Signed-off-by: Quentin Armitage --- doc/man/man5/keepalived.conf.5.in | 5 ++ keepalived/check/check_snmp.c | 98 ++++++++++---------- keepalived/check/ipvswrapper.c | 144 ++++++++++++++++++++++-------- keepalived/check/libipvs.c | 105 +++++++++++++++------- keepalived/core/global_data.c | 8 ++ keepalived/core/global_parser.c | 12 +++ keepalived/include/check_data.h | 4 +- keepalived/include/global_data.h | 3 +- keepalived/include/ip_vs.h | 4 +- keepalived/include/ipvswrapper.h | 7 +- 10 files changed, 267 insertions(+), 123 deletions(-) diff --git a/doc/man/man5/keepalived.conf.5.in b/doc/man/man5/keepalived.conf.5.in index b90150de81..56077f0099 100644 --- a/doc/man/man5/keepalived.conf.5.in +++ b/doc/man/man5/keepalived.conf.5.in @@ -685,6 +685,11 @@ possibly following any cleanup actions needed. # 1 milli-second to 30 seconds. \fBsnmp_vs_stats_update_interval\fR + # Like snmp_vs_stats_update_interval but for real servers. Stats for + # real servers are only read if there is an SNMP request for real server + # stats. + \fBsnmp_rs_stats_update_interval\fR + # If Keepalived has been build with DBus support, the following # keywords are available. # -- diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index 2a4042658f..fe02b38d3e 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -569,106 +569,106 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, long_ret.u++; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSCONNS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.conns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSINPKTS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSOUTPKTS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSINBYTES: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); counter64_ret.low = v->stats.inbytes & 0xffffffff; counter64_ret.high = v->stats.inbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSOUTBYTES: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); counter64_ret.low = v->stats.outbytes & 0xffffffff; counter64_ret.high = v->stats.outbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATECPS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.cps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inbps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPS: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outbps; return PTR_CAST(u_char, &long_ret); #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_VSSTATSCONNS64: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); counter64_ret.low = v->stats.conns & 0xffffffff; counter64_ret.high = v->stats.conns >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSINPKTS64: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); counter64_ret.low = v->stats.inpkts & 0xffffffff; counter64_ret.high = v->stats.inpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSOUTPKTS64: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); counter64_ret.low = v->stats.outpkts & 0xffffffff; counter64_ret.high = v->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATECPSLOW: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.cps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATECPSHIGH: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.cps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPSLOW: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inpps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEINPPSHIGH: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPSLOW: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outpps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEOUTPPSHIGH: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPSLOW: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inbps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEINBPSHIGH: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.inbps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPSLOW: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outbps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEOUTBPSHIGH: - ipvs_update_stats(v); + ipvs_vs_update_stats(v); long_ret.u = v->stats.outbps >> 32; return PTR_CAST(u_char, &long_ret); #endif @@ -1009,118 +1009,118 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, long_ret.u = be->num_failed_checkers; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSCONNS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.conns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSACTIVECONNS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->activeconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINACTIVECONNS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->inactconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSPERSISTENTCONNS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->persistconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINPKTS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSOUTPKTS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINBYTES: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); counter64_ret.low = be->stats.inbytes & 0xffffffff; counter64_ret.high = be->stats.inbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSOUTBYTES: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); counter64_ret.low = be->stats.outbytes & 0xffffffff; counter64_ret.high = be->stats.outbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATECPS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inbps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPS: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outbps; return PTR_CAST(u_char, &long_ret); #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_RSSTATSCONNS64: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); counter64_ret.low = be->stats.conns & 0xffffffff; counter64_ret.high = be->stats.conns >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSINPKTS64: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); counter64_ret.low = be->stats.inpkts & 0xffffffff; counter64_ret.high = be->stats.inpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSOUTPKTS64: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); counter64_ret.low = be->stats.outpkts & 0xffffffff; counter64_ret.high = be->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATECPSLOW: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATECPSHIGH: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPSLOW: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEINPPSHIGH: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPSLOW: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEOUTPPSHIGH: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPSLOW: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inbps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEINBPSHIGH: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inbps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPSLOW: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outbps & 0xffffffff; return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEOUTBPSHIGH: - ipvs_update_stats(bvs); + ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outbps >> 32; return PTR_CAST(u_char, &long_ret); #endif diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index 7c778edbea..28fdca98d3 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -836,9 +836,6 @@ vsd_equal(real_server_t *rs, struct ip_vs_dest_entry_app *entry) static void ipvs_update_vs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union nf_inet_addr *nfaddr, uint16_t port) { - struct ip_vs_get_dests_app *dests = NULL; - real_server_t *rs, *rs_match; - unsigned int i; ipvs_service_entry_t *serv; if (!(serv = ipvs_get_service(fwmark, af, vs->service_type, nfaddr, port))) @@ -856,21 +853,32 @@ ipvs_update_vs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n vs->stats.inbps += serv->stats.inbps; vs->stats.outbps += serv->stats.outbps; - /* Get real servers */ - dests = ipvs_get_dests(fwmark, af, vs->service_type, nfaddr, port, serv->user.num_dests); + vs->num_dests = serv->user.num_dests; // Only needed if using old socket interface + FREE(serv); +} + +static void +ipvs_update_rs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union nf_inet_addr *nfaddr, uint16_t port) +{ + struct ip_vs_get_dests_app *dests; + real_server_t *rs, *rs_match; + unsigned int i; + + /* Get real servers */ + dests = ipvs_get_dests(fwmark, af, vs->service_type, nfaddr, port, vs->num_dests ? vs->num_dests : vs->rs_cnt + !!vs->s_svr); if (!dests) return; for (i = 0; i < dests->user.num_dests; i++) { rs = NULL; - rs_match = NULL; /* Is it the sorry server? */ if (vs->s_svr && vsd_equal(vs->s_svr, &dests->user.entrytable[i])) rs = vs->s_svr; else { /* Search for a match in the list of real servers */ + rs_match = NULL; list_for_each_entry(rs, &vs->rs, e_list) { if (vsd_equal(rs, &dests->user.entrytable[i])) { rs_match = rs; @@ -881,47 +889,114 @@ ipvs_update_vs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n rs = NULL; } - if (rs) { - rs->activeconns += dests->user.entrytable[i].user.activeconns; - rs->inactconns += dests->user.entrytable[i].user.inactconns; - rs->persistconns += dests->user.entrytable[i].user.persistconns; - rs->stats.conns += dests->user.entrytable[i].stats.conns; - rs->stats.inpkts += dests->user.entrytable[i].stats.inpkts; - rs->stats.outpkts += dests->user.entrytable[i].stats.outpkts; - rs->stats.inbytes += dests->user.entrytable[i].stats.inbytes; - rs->stats.outbytes += dests->user.entrytable[i].stats.outbytes; - rs->stats.cps += dests->user.entrytable[i].stats.cps; - rs->stats.inpps += dests->user.entrytable[i].stats.inpps; - rs->stats.outpps += dests->user.entrytable[i].stats.outpps; - rs->stats.inbps += dests->user.entrytable[i].stats.inbps; - rs->stats.outbps += dests->user.entrytable[i].stats.outbps; - } + if (!rs) + continue; + + rs->activeconns += dests->user.entrytable[i].user.activeconns; + rs->inactconns += dests->user.entrytable[i].user.inactconns; + rs->persistconns += dests->user.entrytable[i].user.persistconns; + rs->stats.conns += dests->user.entrytable[i].stats.conns; + rs->stats.inpkts += dests->user.entrytable[i].stats.inpkts; + rs->stats.outpkts += dests->user.entrytable[i].stats.outpkts; + rs->stats.inbytes += dests->user.entrytable[i].stats.inbytes; + rs->stats.outbytes += dests->user.entrytable[i].stats.outbytes; + rs->stats.cps += dests->user.entrytable[i].stats.cps; + rs->stats.inpps += dests->user.entrytable[i].stats.inpps; + rs->stats.outpps += dests->user.entrytable[i].stats.outpps; + rs->stats.inbps += dests->user.entrytable[i].stats.inbps; + rs->stats.outbps += dests->user.entrytable[i].stats.outbps; } + FREE(dests); } -/* Update statistics for a given virtual server. This includes - statistics of real servers. The update is only done if we need - refreshing. */ +/* Update statistics for a given virtual server. The update is only + done if we need refreshing. */ void -ipvs_update_stats(virtual_server_t *vs) +ipvs_vs_update_stats(virtual_server_t *vs) { virtual_server_group_entry_t *vsg_entry; uint32_t addr_ip, addr_end; uint16_t port; union nf_inet_addr nfaddr; - real_server_t *rs; struct timespec cur_time; uint16_t af; clock_gettime(CLOCK_MONOTONIC, &cur_time); - if ((unsigned long)((cur_time.tv_sec - vs->lastupdated.tv_sec) * TIMER_HZ + - cur_time.tv_nsec / (NSEC_PER_SEC / TIMER_HZ) - vs->lastupdated.tv_nsec / (NSEC_PER_SEC / TIMER_HZ)) < global_data->snmp_vs_stats_update_interval) + if ((unsigned long)((cur_time.tv_sec - vs->vs_stats_last_updated.tv_sec) * TIMER_HZ + + cur_time.tv_nsec / (NSEC_PER_SEC / TIMER_HZ) - vs->vs_stats_last_updated.tv_nsec / (NSEC_PER_SEC / TIMER_HZ)) < global_data->snmp_vs_stats_update_interval) return; - vs->lastupdated = cur_time; + vs->vs_stats_last_updated = cur_time; /* Reset stats */ memset(&vs->stats, 0, sizeof(vs->stats)); + + /* Update the stats */ + if (vs->vsg) { + for (af = (vs->vsg->have_ipv4) ? AF_INET : AF_INET6; af != AF_UNSPEC; af = af == AF_INET && vs->vsg->have_ipv6 ? AF_INET6 : AF_UNSPEC) { +#ifdef _WITH_NFTABLES_ + if (VS_USES_VSG_AUTO_FWMARK(vs)) + ipvs_update_vs_stats(vs, af, vs->vsg->auto_fwmark[protocol_to_index(vs->service_type)], NULL, 0); + else +#endif + { + list_for_each_entry(vsg_entry, &vs->vsg->vfwmark, e_list) + ipvs_update_vs_stats(vs, af, vsg_entry->vfwmark, NULL, 0); + + list_for_each_entry(vsg_entry, &vs->vsg->addr_range, e_list) { + addr_ip = (vsg_entry->addr.ss_family == AF_INET6) ? + ntohs(PTR_CAST(struct sockaddr_in6, &vsg_entry->addr)->sin6_addr.s6_addr16[7]) : + ntohl(PTR_CAST(struct sockaddr_in, &vsg_entry->addr)->sin_addr.s_addr); + addr_end = (vsg_entry->addr.ss_family == AF_INET6) ? + ntohs(PTR_CAST(struct sockaddr_in6, &vsg_entry->addr_end)->sin6_addr.s6_addr16[7]) : + ntohl(PTR_CAST(struct sockaddr_in, &vsg_entry->addr_end)->sin_addr.s_addr); + if (vsg_entry->addr.ss_family == AF_INET6) + inet_sockaddrip6(&vsg_entry->addr, &nfaddr.in6); + + port = inet_sockaddrport(&vsg_entry->addr); + do { + if (vsg_entry->addr.ss_family == AF_INET6) + nfaddr.in6.s6_addr16[7] = htons(addr_ip); + else + nfaddr.ip = htonl(addr_ip); + + ipvs_update_vs_stats(vs, af, 0, &nfaddr, port); +// This doesn't work for /111 say + } while (addr_ip++ != addr_end); + } + } + } + } else if (vs->vfwmark) { + ipvs_update_vs_stats(vs, vs->af, vs->vfwmark, NULL, 0); + } else { + memcpy(&nfaddr, (vs->addr.ss_family == AF_INET6) ? + (void*)(&PTR_CAST(struct sockaddr_in6, &vs->addr)->sin6_addr) : + (void*)(&PTR_CAST(struct sockaddr_in, &vs->addr)->sin_addr), + sizeof(nfaddr)); + ipvs_update_vs_stats(vs, vs->af, 0, &nfaddr, inet_sockaddrport(&vs->addr)); + } +} + +/* Update statistics for a given real server. The update is only + done if we need refreshing. */ +void +ipvs_rs_update_stats(virtual_server_t *vs) +{ + virtual_server_group_entry_t *vsg_entry; + uint32_t addr_ip, addr_end; + uint16_t port; + union nf_inet_addr nfaddr; + real_server_t *rs; + struct timespec cur_time; + uint16_t af; + + clock_gettime(CLOCK_MONOTONIC, &cur_time); + if ((unsigned long)((cur_time.tv_sec - vs->rs_stats_last_updated.tv_sec) * TIMER_HZ + + cur_time.tv_nsec / (NSEC_PER_SEC / TIMER_HZ) - vs->rs_stats_last_updated.tv_nsec / (NSEC_PER_SEC / TIMER_HZ)) < global_data->snmp_rs_stats_update_interval) + return; + vs->rs_stats_last_updated = cur_time; + + /* Reset stats */ if (vs->s_svr) { memset(&vs->s_svr->stats, 0, sizeof(vs->s_svr->stats)); vs->s_svr->activeconns = @@ -937,12 +1012,12 @@ ipvs_update_stats(virtual_server_t *vs) for (af = (vs->vsg->have_ipv4) ? AF_INET : AF_INET6; af != AF_UNSPEC; af = af == AF_INET && vs->vsg->have_ipv6 ? AF_INET6 : AF_UNSPEC) { #ifdef _WITH_NFTABLES_ if (VS_USES_VSG_AUTO_FWMARK(vs)) - ipvs_update_vs_stats(vs, af, vs->vsg->auto_fwmark[protocol_to_index(vs->service_type)], &nfaddr, 0); + ipvs_update_rs_stats(vs, af, vs->vsg->auto_fwmark[protocol_to_index(vs->service_type)], NULL, 0); else #endif { list_for_each_entry(vsg_entry, &vs->vsg->vfwmark, e_list) - ipvs_update_vs_stats(vs, af, vsg_entry->vfwmark, &nfaddr, 0); + ipvs_update_rs_stats(vs, af, vsg_entry->vfwmark, NULL, 0); list_for_each_entry(vsg_entry, &vs->vsg->addr_range, e_list) { addr_ip = (vsg_entry->addr.ss_family == AF_INET6) ? @@ -961,21 +1036,20 @@ ipvs_update_stats(virtual_server_t *vs) else nfaddr.ip = htonl(addr_ip); - ipvs_update_vs_stats(vs, af, 0, &nfaddr, port); + ipvs_update_rs_stats(vs, af, 0, &nfaddr, port); // This doesn't work for /111 say } while (addr_ip++ != addr_end); } } } } else if (vs->vfwmark) { - memset(&nfaddr, 0, sizeof(nfaddr)); - ipvs_update_vs_stats(vs, vs->af, vs->vfwmark, &nfaddr, 0); + ipvs_update_rs_stats(vs, vs->af, vs->vfwmark, NULL, 0); } else { memcpy(&nfaddr, (vs->addr.ss_family == AF_INET6) ? (void*)(&PTR_CAST(struct sockaddr_in6, &vs->addr)->sin6_addr) : (void*)(&PTR_CAST(struct sockaddr_in, &vs->addr)->sin_addr), sizeof(nfaddr)); - ipvs_update_vs_stats(vs, vs->af, 0, &nfaddr, inet_sockaddrport(&vs->addr)); + ipvs_update_rs_stats(vs, vs->af, 0, &nfaddr, inet_sockaddrport(&vs->addr)); } } #endif /* _WITH_SNMP_CHECKER_ */ diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 46ba55ba24..7959eb2ba9 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -977,7 +977,11 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) struct ip_vs_get_services_app **getp = PTR_CAST(struct ip_vs_get_services_app *, arg); struct ip_vs_get_services_app *get = *getp; struct ip_vs_flags flags; - unsigned i = get->user.num_services; + + if (get->user.num_services) { + log_message(LOG_INFO, "ipvs_services_parse_cb get->user.num_services = %u != 0", get->user.num_services); + return -1; + } if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; @@ -988,7 +992,7 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) if (nla_parse_nested(svc_attrs, IPVS_SVC_ATTR_MAX, attrs[IPVS_CMD_ATTR_SERVICE], ipvs_service_policy)) return -1; - memset(&(get->user.entrytable[i]), 0, sizeof(get->user.entrytable[i])); + memset(&(get->user.entrytable[0]), 0, sizeof(get->user.entrytable[0])); if (!(svc_attrs[IPVS_SVC_ATTR_AF] && (svc_attrs[IPVS_SVC_ATTR_FWMARK] || @@ -1001,50 +1005,52 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) svc_attrs[IPVS_SVC_ATTR_FLAGS])) return -1; - get->user.entrytable[i].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]); + get->user.entrytable[0].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]); if (svc_attrs[IPVS_SVC_ATTR_FWMARK]) - get->user.entrytable[i].user.fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]); + get->user.entrytable[0].user.fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]); else { - get->user.entrytable[i].user.protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]); - memcpy(&(get->user.entrytable[i].nf_addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]), - sizeof(get->user.entrytable[i].nf_addr)); - get->user.entrytable[i].user.port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]); + get->user.entrytable[0].user.protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]); + memcpy(&(get->user.entrytable[0].nf_addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]), + sizeof(get->user.entrytable[0].nf_addr)); + get->user.entrytable[0].user.port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]); } - strcpy_safe(get->user.entrytable[i].user.sched_name, + strcpy_safe(get->user.entrytable[0].user.sched_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME])); if (svc_attrs[IPVS_SVC_ATTR_PE_NAME]) - strcpy_safe(get->user.entrytable[i].pe_name, + strcpy_safe(get->user.entrytable[0].pe_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_PE_NAME])); - get->user.entrytable[i].user.netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]); - get->user.entrytable[i].user.timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]); + get->user.entrytable[0].user.netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]); + get->user.entrytable[0].user.timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]); nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags)); - get->user.entrytable[i].user.flags = flags.flags & flags.mask; + get->user.entrytable[0].user.flags = flags.flags & flags.mask; #ifdef _WITH_LVS_64BIT_STATS_ if (svc_attrs[IPVS_SVC_ATTR_STATS64]) { - if (ipvs_parse_stats64(&(get->user.entrytable[i].stats), + if (ipvs_parse_stats64(&(get->user.entrytable[0].stats), svc_attrs[IPVS_SVC_ATTR_STATS64]) != 0) return -1; } else if (svc_attrs[IPVS_SVC_ATTR_STATS]) #endif { - if (ipvs_parse_stats(&(get->user.entrytable[i].stats), + if (ipvs_parse_stats(&(get->user.entrytable[0].stats), svc_attrs[IPVS_SVC_ATTR_STATS]) != 0) return -1; } - get->user.entrytable[i].user.num_dests = 0; + get->user.entrytable[0].user.num_dests = 0; - i++; + get->user.num_services++; - get->user.num_services = i; +#if 0 get = REALLOC(get, sizeof(*get) + sizeof(ipvs_service_entry_t) * (get->user.num_services + 1)); *getp = get; +#endif + return 0; } @@ -1070,8 +1076,6 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) if (nla_parse_nested(dest_attrs, IPVS_DEST_ATTR_MAX, attrs[IPVS_CMD_ATTR_DEST], ipvs_dest_policy)) return -1; - memset(&(d->user.entrytable[i]), 0, sizeof(d->user.entrytable[i])); - if (!(dest_attrs[IPVS_DEST_ATTR_ADDR] && dest_attrs[IPVS_DEST_ATTR_PORT] && dest_attrs[IPVS_DEST_ATTR_FWD_METHOD] && @@ -1083,6 +1087,13 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS])) return -1; + if (d->user.num_dests == d->num_entries) { + /* There are more RS than we expected. Allow space for another 10. */ + d = REALLOC(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->num_entries += 10)); + } + + memset(&(d->user.entrytable[i]), 0, sizeof(d->user.entrytable[i])); + memcpy(&(d->user.entrytable[i].nf_addr), nla_data(dest_attrs[IPVS_DEST_ATTR_ADDR]), sizeof(d->user.entrytable[i].nf_addr)); @@ -1115,11 +1126,9 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) return -1; } - i++; - - d->user.num_dests = i; - d = REALLOC(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->user.num_dests + 1)); + d->user.num_dests++; *dp = d; + return 0; } #endif /* LIBIPVS_USE_NL */ @@ -1131,10 +1140,13 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco socklen_t len; unsigned i; - len = (socklen_t)(sizeof(*d) + sizeof(ipvs_dest_entry_t) * (num_dests ? num_dests : 1)); + len = (socklen_t)(sizeof(*d) + sizeof(ipvs_dest_entry_t) * num_dests); + if (!(d = MALLOC(len))) return NULL; + d->num_entries = num_dests; + ipvs_func = ipvs_get_dests; #ifdef LIBIPVS_USE_NL @@ -1143,7 +1155,8 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco struct nlattr *nl_service; d->user.fwmark = fwmark; d->user.protocol = protocol; - d->nf_addr = *addr; + if (addr) + d->nf_addr = *addr; d->user.port = port; d->user.num_dests = num_dests; d->af = af; @@ -1165,8 +1178,9 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(*addr), addr); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, port); } - nla_nest_end(msg, nl_service); + +// Does ipvs_nl_send_message() free msg? if (ipvs_nl_send_message(msg, ipvs_dests_parse_cb, &d)) goto ipvs_nl_dest_failure; @@ -1194,7 +1208,8 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco dk->fwmark = fwmark; dk->protocol = protocol; - dk->addr = addr->ip; + if (addr) + dk->addr = addr->ip; dk->port = port; dk->num_dests = num_dests; @@ -1205,7 +1220,8 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco } memcpy(&d->user, dk, sizeof(struct ip_vs_get_dests)); d->af = AF_INET; - d->nf_addr.ip = dk->addr; + if (addr) + d->nf_addr.ip = dk->addr; for (i = 0; i < dk->num_dests; i++) { memcpy(&d->user.entrytable[i], &dk->entrytable[i], sizeof(struct ip_vs_dest_entry)); @@ -1227,9 +1243,13 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add #ifdef LIBIPVS_USE_NL if (try_nl) { - struct ip_vs_get_services *get; +// get should be a ip_vs_get_services_app??? + struct ip_vs_get_services_app *get; + struct nlattr *nl_service; struct nl_msg *msg; - ipvs_service_t tsvc = { .user.fwmark = fwmark, .af = af, .user.protocol = protocol, .nf_addr = *addr, .user.port = port }; +// ipvs_service_t tsvc = { .user.fwmark = fwmark, .af = af, .user.protocol = protocol, .user.port = port }; +// if (addr) +// tsvc.nf_addr = *addr; svc = MALLOC(sizeof(*svc)); if (!svc) @@ -1238,18 +1258,35 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add if (!(get = MALLOC(sizeof(*get) + sizeof(ipvs_service_entry_t)))) goto ipvs_get_service_err2; - get->num_services = 0; + get->user.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)) +// if (ipvs_nl_fill_service_attr(msg, &tsvc)) +// goto nla_put_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, af); + + if (fwmark) { + NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, fwmark); + } else { + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, protocol); + NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(*addr), addr); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, port); + } + nla_nest_end(msg, nl_service); + +// Does ipvs_nl_send_message free msg? if (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get)) goto ipvs_get_service_err; - memcpy(svc, &(get->entrytable[0]), sizeof(*svc)); + *svc = get->user.entrytable[0]; FREE(get); + return svc; nla_put_failure: diff --git a/keepalived/core/global_data.c b/keepalived/core/global_data.c index dcd16351fb..b082ffc080 100644 --- a/keepalived/core/global_data.c +++ b/keepalived/core/global_data.c @@ -283,6 +283,7 @@ alloc_global_data(void) new->snmp_socket = STRDUP(snmp_socket); #ifdef _WITH_SNMP_CHECKER_ new->snmp_vs_stats_update_interval = 5 * TIMER_HZ; /* 5 seconds */ + new->snmp_rs_stats_update_interval = 0; #endif #endif @@ -415,6 +416,10 @@ init_global_data(data_t * data, data_t *prev_global_data, bool copy_unchangeable } #endif } +#ifdef _WITH_SNMP_CHECKER_ + if (!data->snmp_rs_stats_update_interval) + data->snmp_rs_stats_update_interval = data->snmp_vs_stats_update_interval; +#endif #endif } @@ -854,7 +859,10 @@ dump_global_data(FILE *fp, data_t * data) #ifdef _WITH_SNMP_ conf_write(fp, " SNMP traps %s", data->enable_traps ? "enabled" : "disabled"); conf_write(fp, " SNMP socket = %s", data->snmp_socket ? data->snmp_socket : "default (unix:/var/agentx/master)"); +#endif +#ifdef _WITH_SNMP_CHECKER_ conf_write(fp, " SNMP VS stats update interval = %s", format_decimal(data->snmp_vs_stats_update_interval, TIMER_HZ_DIGITS)); + conf_write(fp, " SNMP RS stats update interval = %s", format_decimal(data->snmp_rs_stats_update_interval, TIMER_HZ_DIGITS)); #endif #ifdef _WITH_DBUS_ conf_write(fp, " DBus %s", data->enable_dbus ? "enabled" : "disabled"); diff --git a/keepalived/core/global_parser.c b/keepalived/core/global_parser.c index 4d72a1e683..ed76b5cb08 100644 --- a/keepalived/core/global_parser.c +++ b/keepalived/core/global_parser.c @@ -1638,6 +1638,17 @@ snmp_vs_stats_update_interval_handler(const vector_t *strvec) else report_config_error(CONFIG_GENERAL_ERROR, "snmp stats vs update interval '%s' invalid - ignoring", strvec_slot(strvec, 1)); } +static void +snmp_rs_stats_update_interval_handler(const vector_t *strvec) +{ + unsigned long interval; + + /* Valid range is 1 ms to 30s */ + if (read_timer(strvec, 1, &interval, 1000, 30 * TIMER_HZ, true)) + global_data->snmp_rs_stats_update_interval = interval; + else + report_config_error(CONFIG_GENERAL_ERROR, "snmp stats vs update interval '%s' invalid - ignoring", strvec_slot(strvec, 1)); +} #endif #endif @@ -2527,6 +2538,7 @@ init_global_keywords(bool global_active) #ifdef _WITH_SNMP_CHECKER_ install_keyword("enable_snmp_checker", &snmp_checker_handler); install_keyword("snmp_vs_stats_update_interval", &snmp_vs_stats_update_interval_handler); + install_keyword("snmp_rs_stats_update_interval", &snmp_rs_stats_update_interval_handler); #endif #endif #ifdef _WITH_DBUS_ diff --git a/keepalived/include/check_data.h b/keepalived/include/check_data.h index f8290716c2..1beed31dbc 100644 --- a/keepalived/include/check_data.h +++ b/keepalived/include/check_data.h @@ -224,8 +224,10 @@ typedef struct _virtual_server { bool reloaded; /* quorum_state was copied from old config while reloading */ #if defined _WITH_SNMP_CHECKER_ /* Statistics */ - struct timespec lastupdated; + struct timespec vs_stats_last_updated; + struct timespec rs_stats_last_updated; unsigned rs_cnt; /* Number of real_server in list */ + unsigned num_dests; /* Only needed if using old socket interface */ #ifndef _WITH_LVS_64BIT_STATS_ struct ip_vs_stats_user stats; #else diff --git a/keepalived/include/global_data.h b/keepalived/include/global_data.h index 74c66b5790..f4533389f6 100644 --- a/keepalived/include/global_data.h +++ b/keepalived/include/global_data.h @@ -249,9 +249,10 @@ typedef struct _data { bool enable_snmp_rfcv3; #endif #endif -#ifdef _WITH_LVS_ +#ifdef _WITH_SNMP_CHECKER_ bool enable_snmp_checker; unsigned long snmp_vs_stats_update_interval; + unsigned long snmp_rs_stats_update_interval; #endif #endif #ifdef _WITH_DBUS_ diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index ffdcde3ba3..c81d397774 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -99,6 +99,8 @@ struct ip_vs_get_dests_app { /* the real servers */ struct ip_vs_dest_entry_app entrytable[]; } user; + + unsigned num_entries; /* Number of entries space allocated for */ }; /* The argument to IP_VS_SO_GET_SERVICES */ @@ -108,7 +110,7 @@ struct ip_vs_get_services_app { unsigned int num_services; /* service table */ - struct ip_vs_service_entry_app entrytable[0]; + struct ip_vs_service_entry_app entrytable[]; } user; }; diff --git a/keepalived/include/ipvswrapper.h b/keepalived/include/ipvswrapper.h index e93338ed3d..7b2fa972e6 100644 --- a/keepalived/include/ipvswrapper.h +++ b/keepalived/include/ipvswrapper.h @@ -82,7 +82,10 @@ extern void remove_fwmark_vs(virtual_server_t *, int); extern void add_fwmark_vs(virtual_server_t *, int); #endif -/* Refresh statistics at most every global_data->snmp_stats_update_interval */ -extern void ipvs_update_stats(virtual_server_t * vs); +/* Refresh VS statistics at most every global_data->snmp_vs_stats_update_interval */ +extern void ipvs_vs_update_stats(virtual_server_t * vs); + +/* Refresh RS statistics at most every global_data->snmp_rs_stats_update_interval */ +extern void ipvs_rs_update_stats(virtual_server_t * vs); #endif From c7bade7d03e4777150335098c582d4313161dfd1 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:14:36 +0100 Subject: [PATCH 08/24] ipvs: Use assignment of structures rather than memcpy() This allows proper type checking by the compiler. Signed-off-by: Quentin Armitage --- keepalived/check/ipvswrapper.c | 2 ++ keepalived/check/libipvs.c | 24 ++++++++---------------- keepalived/include/ip_vs.h | 32 ++++++++++++++++---------------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index 28fdca98d3..ccf6a3da46 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -879,7 +879,9 @@ ipvs_update_rs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n else { /* Search for a match in the list of real servers */ rs_match = NULL; + int no = 0; list_for_each_entry(rs, &vs->rs, e_list) { + no++; if (vsd_equal(rs, &dests->user.entrytable[i])) { rs_match = rs; break; diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 7959eb2ba9..ed8e510d6d 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -342,14 +342,14 @@ static int ipvs_nl_send_message(struct nl_msg *msg, nl_recvmsg_msg_cb_t func, vo int err = EINVAL; int ret = 0; + if (!msg) + return 0; + if (!sock && open_nl_sock()) { nlmsg_free(msg); return -1; } - if (!msg) - return 0; - if (func != cur_nl_sock_cb_func) { if (!nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg)) cur_nl_sock_cb_func = func; @@ -1090,6 +1090,7 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) if (d->user.num_dests == d->num_entries) { /* There are more RS than we expected. Allow space for another 10. */ d = REALLOC(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->num_entries += 10)); + *dp = d; } memset(&(d->user.entrytable[i]), 0, sizeof(d->user.entrytable[i])); @@ -1127,7 +1128,6 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) } d->user.num_dests++; - *dp = d; return 0; } @@ -1158,7 +1158,7 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco if (addr) d->nf_addr = *addr; d->user.port = port; - d->user.num_dests = num_dests; + d->user.num_dests = 0; d->af = af; msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); @@ -1180,7 +1180,6 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco } nla_nest_end(msg, nl_service); -// Does ipvs_nl_send_message() free msg? if (ipvs_nl_send_message(msg, ipvs_dests_parse_cb, &d)) goto ipvs_nl_dest_failure; @@ -1218,13 +1217,13 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco FREE(dk); return NULL; } - memcpy(&d->user, dk, sizeof(struct ip_vs_get_dests)); + + d->user = *(struct ip_vs_get_dests_entries_app *)dk; d->af = AF_INET; if (addr) d->nf_addr.ip = dk->addr; for (i = 0; i < dk->num_dests; i++) { - memcpy(&d->user.entrytable[i], &dk->entrytable[i], - sizeof(struct ip_vs_dest_entry)); + d->user.entrytable[i].user = dk->entrytable[i]; d->user.entrytable[i].af = AF_INET; d->user.entrytable[i].nf_addr.ip = d->user.entrytable[i].user.addr; } @@ -1243,13 +1242,9 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add #ifdef LIBIPVS_USE_NL if (try_nl) { -// get should be a ip_vs_get_services_app??? struct ip_vs_get_services_app *get; struct nlattr *nl_service; struct nl_msg *msg; -// ipvs_service_t tsvc = { .user.fwmark = fwmark, .af = af, .user.protocol = protocol, .user.port = port }; -// if (addr) -// tsvc.nf_addr = *addr; svc = MALLOC(sizeof(*svc)); if (!svc) @@ -1263,8 +1258,6 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add 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; nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); if (!nl_service) goto nla_put_failure; @@ -1280,7 +1273,6 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add } nla_nest_end(msg, nl_service); -// Does ipvs_nl_send_message free msg? if (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get)) goto ipvs_get_service_err; diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index c81d397774..c032df9814 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -86,31 +86,31 @@ struct ip_vs_get_dests_app { uint16_t af; union nf_inet_addr nf_addr; - struct { - /* which service: user fills in these */ - __u16 protocol; - __be32 addr; /* virtual address */ - __be16 port; - __u32 fwmark; /* firwall mark of service */ + unsigned num_entries; /* Number of entries space allocated for */ - /* number of real servers */ - unsigned int num_dests; + struct ip_vs_get_dests_entries_app { + /* which service: user fills in these */ + __u16 protocol; + __be32 addr; /* virtual address */ + __be16 port; + __u32 fwmark; /* firwall mark of service */ - /* the real servers */ - struct ip_vs_dest_entry_app entrytable[]; - } user; + /* number of real servers */ + unsigned int num_dests; - unsigned num_entries; /* Number of entries space allocated for */ + /* the real servers */ + struct ip_vs_dest_entry_app entrytable[]; + } user; }; /* The argument to IP_VS_SO_GET_SERVICES */ struct ip_vs_get_services_app { struct { - /* number of virtual services */ - unsigned int num_services; + /* number of virtual services */ + unsigned int num_services; - /* service table */ - struct ip_vs_service_entry_app entrytable[]; + /* service table */ + struct ip_vs_service_entry_app entrytable[]; } user; }; From 7752c337c27dcbbebe6c5f002b1b57900bad25ab Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:15:44 +0100 Subject: [PATCH 09/24] ipvs: fix updating stats for SNMP when fetched via socket interface This code is probably never used, since netlink is now used in preference to the old socket interface, and the socket interface is only used if netlink fails, which should neveer be the case. Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index ed8e510d6d..e09814f218 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -435,8 +435,6 @@ int ipvs_init(void) try_nl = libnl_init(); if (!try_nl) log_message(LOG_INFO, "Note: IPVS with IPv6 will not be supported"); -#else - try_nl = true; #endif if (try_nl && ipvs_nl_send_message(NULL, NULL, NULL) == 0) @@ -966,7 +964,6 @@ static int ipvs_parse_stats(ip_vs_stats_t *stats, struct nlattr *nla) stats->outbps = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTBPS]); return 0; - } static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) @@ -1133,6 +1130,29 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) } #endif /* LIBIPVS_USE_NL */ +#ifdef _WITH_LVS_64BIT_STATS_ +static void +ipvs_copy_stats(ip_vs_stats_t *stats_out, const struct ip_vs_stats_user *stats_in) +{ + stats_out->conns = stats_in->conns; + stats_out->inpkts = stats_in->inpkts; + stats_out->outpkts = stats_in->outpkts; + stats_out->inbytes = stats_in->inbytes; + stats_out->outbytes = stats_in->outbytes; + stats_out->cps = stats_in->cps; + stats_out->inpps = stats_in->inpps; + stats_out->outpps = stats_in->outpps; + stats_out->inbps = stats_in->inbps; + stats_out->outbps = stats_in->outbps; +} +#else +static void +ipvs_copy_stats(ip_vs_stats_t *stats_out, const ip_vs_stats_user *stats_in) +{ + *stats_out = *stats_in; +} +#endif + struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *addr, __u16 port, unsigned num_dests) { struct ip_vs_get_dests_app *d; @@ -1226,6 +1246,7 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco d->user.entrytable[i].user = dk->entrytable[i]; d->user.entrytable[i].af = AF_INET; d->user.entrytable[i].nf_addr.ip = d->user.entrytable[i].user.addr; + ipvs_copy_stats(&d->user.entrytable[i].stats, &dk->entrytable[i].stats); } FREE(dk); return d; @@ -1311,6 +1332,7 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add svc->af = AF_INET; svc->nf_addr.ip = svc->user.addr; svc->pe_name[0] = '\0'; + ipvs_copy_stats(&svc->stats, &svc->user.stats); return svc; out_err: From 930f3b726102eda82e945004e9f9038f3f3d3aa6 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:17:23 +0100 Subject: [PATCH 10/24] ipvs: Don't duplicate storage of 32 bit SNMP stats Signed-off-by: Quentin Armitage --- keepalived/check/ipvswrapper.c | 40 +++++++++++++------------- keepalived/check/libipvs.c | 52 ++++++++++++++++------------------ keepalived/include/ip_vs.h | 6 ++++ 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index ccf6a3da46..93205a267f 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -842,16 +842,16 @@ ipvs_update_vs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n return; /* Update virtual server stats */ - vs->stats.conns += serv->stats.conns; - vs->stats.inpkts += serv->stats.inpkts; - vs->stats.outpkts += serv->stats.outpkts; - vs->stats.inbytes += serv->stats.inbytes; - vs->stats.outbytes += serv->stats.outbytes; - vs->stats.cps += serv->stats.cps; - vs->stats.inpps += serv->stats.inpps; - vs->stats.outpps += serv->stats.outpps; - vs->stats.inbps += serv->stats.inbps; - vs->stats.outbps += serv->stats.outbps; + vs->stats.conns += serv->ip_vs_stats.conns; + vs->stats.inpkts += serv->ip_vs_stats.inpkts; + vs->stats.outpkts += serv->ip_vs_stats.outpkts; + vs->stats.inbytes += serv->ip_vs_stats.inbytes; + vs->stats.outbytes += serv->ip_vs_stats.outbytes; + vs->stats.cps += serv->ip_vs_stats.cps; + vs->stats.inpps += serv->ip_vs_stats.inpps; + vs->stats.outpps += serv->ip_vs_stats.outpps; + vs->stats.inbps += serv->ip_vs_stats.inbps; + vs->stats.outbps += serv->ip_vs_stats.outbps; vs->num_dests = serv->user.num_dests; // Only needed if using old socket interface @@ -897,16 +897,16 @@ ipvs_update_rs_stats(virtual_server_t *vs, uint16_t af, uint32_t fwmark, union n rs->activeconns += dests->user.entrytable[i].user.activeconns; rs->inactconns += dests->user.entrytable[i].user.inactconns; rs->persistconns += dests->user.entrytable[i].user.persistconns; - rs->stats.conns += dests->user.entrytable[i].stats.conns; - rs->stats.inpkts += dests->user.entrytable[i].stats.inpkts; - rs->stats.outpkts += dests->user.entrytable[i].stats.outpkts; - rs->stats.inbytes += dests->user.entrytable[i].stats.inbytes; - rs->stats.outbytes += dests->user.entrytable[i].stats.outbytes; - rs->stats.cps += dests->user.entrytable[i].stats.cps; - rs->stats.inpps += dests->user.entrytable[i].stats.inpps; - rs->stats.outpps += dests->user.entrytable[i].stats.outpps; - rs->stats.inbps += dests->user.entrytable[i].stats.inbps; - rs->stats.outbps += dests->user.entrytable[i].stats.outbps; + rs->stats.conns += dests->user.entrytable[i].ip_vs_stats.conns; + rs->stats.inpkts += dests->user.entrytable[i].ip_vs_stats.inpkts; + rs->stats.outpkts += dests->user.entrytable[i].ip_vs_stats.outpkts; + rs->stats.inbytes += dests->user.entrytable[i].ip_vs_stats.inbytes; + rs->stats.outbytes += dests->user.entrytable[i].ip_vs_stats.outbytes; + rs->stats.cps += dests->user.entrytable[i].ip_vs_stats.cps; + rs->stats.inpps += dests->user.entrytable[i].ip_vs_stats.inpps; + rs->stats.outpps += dests->user.entrytable[i].ip_vs_stats.outpps; + rs->stats.inbps += dests->user.entrytable[i].ip_vs_stats.inbps; + rs->stats.outbps += dests->user.entrytable[i].ip_vs_stats.outbps; } FREE(dests); diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index e09814f218..99d59726df 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -897,6 +897,23 @@ int ipvs_stop_daemon(ipvs_daemon_t *dm) } #ifdef _WITH_SNMP_CHECKER_ +#ifdef _WITH_LVS_64BIT_STATS_ +static void +ipvs_copy_stats(ip_vs_stats_t *stats_out, const struct ip_vs_stats_user *stats_in) +{ + stats_out->conns = stats_in->conns; + stats_out->inpkts = stats_in->inpkts; + stats_out->outpkts = stats_in->outpkts; + stats_out->inbytes = stats_in->inbytes; + stats_out->outbytes = stats_in->outbytes; + stats_out->cps = stats_in->cps; + stats_out->inpps = stats_in->inpps; + stats_out->outpps = stats_in->outpps; + stats_out->inbps = stats_in->inbps; + stats_out->outbps = stats_in->outbps; +} +#endif + #ifdef LIBIPVS_USE_NL #ifdef _WITH_LVS_64BIT_STATS_ static int ipvs_parse_stats64(ip_vs_stats_t *stats, struct nlattr *nla) @@ -1033,7 +1050,7 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) } else if (svc_attrs[IPVS_SVC_ATTR_STATS]) #endif { - if (ipvs_parse_stats(&(get->user.entrytable[0].stats), + if (ipvs_parse_stats64(&(get->user.entrytable[0].ip_vs_stats), svc_attrs[IPVS_SVC_ATTR_STATS]) != 0) return -1; } @@ -1113,13 +1130,13 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) #ifdef _WITH_LVS_64BIT_STATS_ if (dest_attrs[IPVS_DEST_ATTR_STATS64]) { - if (ipvs_parse_stats64(&(d->user.entrytable[i].stats), + if (ipvs_parse_stats64(&(d->user.entrytable[i].ip_vs_stats), dest_attrs[IPVS_DEST_ATTR_STATS64]) != 0) return -1; } else if (dest_attrs[IPVS_DEST_ATTR_STATS]) #endif { - if (ipvs_parse_stats(&(d->user.entrytable[i].stats), + if (ipvs_parse_stats(&(d->user.entrytable[i].ip_vs_stats), dest_attrs[IPVS_DEST_ATTR_STATS]) != 0) return -1; } @@ -1130,29 +1147,6 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) } #endif /* LIBIPVS_USE_NL */ -#ifdef _WITH_LVS_64BIT_STATS_ -static void -ipvs_copy_stats(ip_vs_stats_t *stats_out, const struct ip_vs_stats_user *stats_in) -{ - stats_out->conns = stats_in->conns; - stats_out->inpkts = stats_in->inpkts; - stats_out->outpkts = stats_in->outpkts; - stats_out->inbytes = stats_in->inbytes; - stats_out->outbytes = stats_in->outbytes; - stats_out->cps = stats_in->cps; - stats_out->inpps = stats_in->inpps; - stats_out->outpps = stats_in->outpps; - stats_out->inbps = stats_in->inbps; - stats_out->outbps = stats_in->outbps; -} -#else -static void -ipvs_copy_stats(ip_vs_stats_t *stats_out, const ip_vs_stats_user *stats_in) -{ - *stats_out = *stats_in; -} -#endif - struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *addr, __u16 port, unsigned num_dests) { struct ip_vs_get_dests_app *d; @@ -1246,7 +1240,9 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco d->user.entrytable[i].user = dk->entrytable[i]; d->user.entrytable[i].af = AF_INET; d->user.entrytable[i].nf_addr.ip = d->user.entrytable[i].user.addr; - ipvs_copy_stats(&d->user.entrytable[i].stats, &dk->entrytable[i].stats); +#ifdef _WITH_LVS_64BIT_STATS_ + ipvs_copy_stats(&d->user.entrytable[i].ip_vs_stats, &dk->entrytable[i].stats); +#endif } FREE(dk); return d; @@ -1332,7 +1328,9 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add svc->af = AF_INET; svc->nf_addr.ip = svc->user.addr; svc->pe_name[0] = '\0'; +#ifdef _WITH_LVS_64BIT_STATS_ ipvs_copy_stats(&svc->stats, &svc->user.stats); +#endif return svc; out_err: diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index c032df9814..de593fd91a 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -41,8 +41,10 @@ struct ip_vs_stats64 { __u64 outbps; /* current out byte rate */ }; typedef struct ip_vs_stats64 ip_vs_stats_t; +#define ip_vs_stats stats #else typedef struct ip_vs_stats_user ip_vs_stats_t; +#define ip_vs_stats user.stats #endif struct ip_vs_service_app { @@ -68,7 +70,9 @@ struct ip_vs_dest_app { struct ip_vs_service_entry_app { struct ip_vs_service_entry user; +#ifdef _WITH_LVS_64BIT_STATS_ ip_vs_stats_t stats; +#endif uint16_t af; union nf_inet_addr nf_addr; char pe_name[IP_VS_PENAME_MAXLEN + 1]; @@ -76,7 +80,9 @@ struct ip_vs_service_entry_app { struct ip_vs_dest_entry_app { struct ip_vs_dest_entry user; +#ifdef _WITH_LVS_64BIT_STATS_ ip_vs_stats_t stats; +#endif uint16_t af; union nf_inet_addr nf_addr; From aa83c572f5244ffe0f59ff5f31da274d063de6d8 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:18:32 +0100 Subject: [PATCH 11/24] ipvs: Use correct variable for returning 64 bit stats for SNMP The long_ret variable was being set but the address of the counter64_ret variable was being return for the low 32 bits of the stats counters. Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index fe02b38d3e..71542cca0e 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -634,7 +634,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_VSRATECPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.cps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATECPSHIGH: ipvs_vs_update_stats(v); long_ret.u = v->stats.cps >> 32; @@ -642,7 +642,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_VSRATEINPPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.inpps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPSHIGH: ipvs_vs_update_stats(v); long_ret.u = v->stats.inpps >> 32; @@ -650,7 +650,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_VSRATEOUTPPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.outpps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPSHIGH: ipvs_vs_update_stats(v); long_ret.u = v->stats.outpps >> 32; @@ -658,7 +658,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_VSRATEINBPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.inbps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPSHIGH: ipvs_vs_update_stats(v); long_ret.u = v->stats.inbps >> 32; @@ -666,7 +666,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_VSRATEOUTBPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.outbps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPSHIGH: ipvs_vs_update_stats(v); long_ret.u = v->stats.outbps >> 32; @@ -1086,7 +1086,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_RSRATECPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATECPSHIGH: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps >> 32; @@ -1094,7 +1094,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_RSRATEINPPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPSHIGH: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inpps >> 32; @@ -1102,7 +1102,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_RSRATEOUTPPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPSHIGH: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outpps >> 32; @@ -1110,7 +1110,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_RSRATEINBPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inbps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPSHIGH: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.inbps >> 32; @@ -1118,7 +1118,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case CHECK_SNMP_RSRATEOUTBPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outbps & 0xffffffff; - return PTR_CAST(u_char, &counter64_ret); + return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPSHIGH: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.outbps >> 32; From 7f3f2ba6e1121fa184ec345801ac89ed7ecd458c Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:21:23 +0100 Subject: [PATCH 12/24] ipvs: Add counter64 options for 64 bit SNMP stats For most 64 bit counter stats, the only way of reading them was to read the high and low 32 bits seperately. This commit adds 64 bit counters for this stats, so they can be read with only one snmp get. Signed-off-by: Quentin Armitage --- doc/KEEPALIVED-MIB.txt | 122 ++++++++++++++++++++++++++++++++-- keepalived/check/check_snmp.c | 108 ++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 5 deletions(-) diff --git a/doc/KEEPALIVED-MIB.txt b/doc/KEEPALIVED-MIB.txt index 234bcadd4e..3e138fee55 100644 --- a/doc/KEEPALIVED-MIB.txt +++ b/doc/KEEPALIVED-MIB.txt @@ -22,12 +22,14 @@ IMPORTS FROM SNMPv2-TC; keepalived MODULE-IDENTITY - LAST-UPDATED "202403180001Z" + LAST-UPDATED "202404050001Z" ORGANIZATION "Keepalived" CONTACT-INFO "http://www.keepalived.org" DESCRIPTION "This MIB describes objects used by keepalived, both for VRRP and health checker." + REVISION "202404050001Z" + DESCRIPTION "add missing 64 bit counters for 64 bit stats" REVISION "202403180001Z" DESCRIPTION "add separate path and argv[0] for scripts" REVISION "202212090001Z" @@ -3426,7 +3428,12 @@ VirtualServerEntry ::= SEQUENCE { virtualServerTunnelCsum INTEGER, virtualServerName DisplayString, virtualServerQuorumUpPath DisplayString, - virtualServerQuorumDownPath DisplayString + virtualServerQuorumDownPath DisplayString, + virtualServerRateCps64 Counter64, + virtualServerRateInPPS64 Counter64, + virtualServerRateOutPPS64 Counter64, + virtualServerRateInBPS64 Counter64, + virtualServerRateOutBPS64 Counter64 } virtualServerIndex OBJECT-TYPE @@ -4084,6 +4091,51 @@ virtualServerQuorumDownPath OBJECT-TYPE "Path to command to execute when the quorum is not met." ::= { virtualServerEntry 73 } +virtualServerRateCps64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "connections/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current connection rate for this virtual server." + ::= { virtualServerEntry 74 } + +virtualServerRateInPPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "packets/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current in packet rate for this virtual server." + ::= { virtualServerEntry 75 } + +virtualServerRateOutPPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "packets/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current out packet rate for this virtual server." + ::= { virtualServerEntry 76 } + +virtualServerRateInBPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "bytes/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current incoming rate for this virtual server." + ::= { virtualServerEntry 77 } + +virtualServerRateOutBPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "bytes/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current outgoing rate for this virtual server." + ::= { virtualServerEntry 78 } + -- real servers @@ -4161,7 +4213,12 @@ RealServerEntry ::= SEQUENCE { realServerTunnelCsum INTEGER, realServerName DisplayString, realServerNotifyUpPath DisplayString, - realServerNotifyDownPath DisplayString + realServerNotifyDownPath DisplayString, + realServerRateCps64 Counter64, + realServerRateInPPS64 Counter64, + realServerRateOutPPS64 Counter64, + realServerRateInBPS64 Counter64, + realServerRateOutBPS64 Counter64 } realServerIndex OBJECT-TYPE @@ -4666,6 +4723,51 @@ realServerNotifyDownPath OBJECT-TYPE "Path to command to execute when this server becomes dead." ::= { realServerEntry 57 } +realServerRateCps64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "connections/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current connection rate for this real server." + ::= { realServerEntry 58 } + +realServerRateInPPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "packets/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current in packet rate for this real server." + ::= { realServerEntry 59 } + +realServerRateOutPPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "packets/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current out packet rate for this real server." + ::= { realServerEntry 60 } + +realServerRateInBPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "bytes/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current incoming rate for this real server." + ::= { realServerEntry 61 } + +realServerRateOutBPS64 OBJECT-TYPE + SYNTAX Counter64 + UNITS "bytes/s" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current outgoing rate for this real server." + ::= { realServerEntry 62 } + lvsSyncDaemon OBJECT IDENTIFIER ::= { check 6 } lvsSyncDaemonEnabled OBJECT-TYPE @@ -5299,7 +5401,12 @@ virtualServerGroup OBJECT-GROUP virtualServerTunnelCsum, virtualServerName, virtualServerQuorumUpPath, - virtualServerQuorumDownPath + virtualServerQuorumDownPath, + virtualServerRateCps64, + virtualServerRateInPPS64, + virtualServerRateOutPPS64, + virtualServerRateInBPS64, + virtualServerRateOutBPS64 } STATUS current DESCRIPTION @@ -5363,7 +5470,12 @@ realServerGroup OBJECT-GROUP realServerTunnelCsum, realServerName, realServerNotifyUpPath, - realServerNotifyDownPath + realServerNotifyDownPath, + realServerRateCps64, + realServerRateInPPS64, + realServerRateOutPPS64, + realServerRateInBPS64, + realServerRateOutBPS64 } STATUS current DESCRIPTION diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index 71542cca0e..46e67086d9 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -90,6 +90,7 @@ enum check_snmp_virtualserver_magic { CHECK_SNMP_VSSTATSCONNS64, CHECK_SNMP_VSSTATSINPKTS64, CHECK_SNMP_VSSTATSOUTPKTS64, + /* See below for VSRATECPS64 64 bit counters for rates */ CHECK_SNMP_VSRATECPSLOW, CHECK_SNMP_VSRATECPSHIGH, CHECK_SNMP_VSRATEINPPSLOW, @@ -127,6 +128,13 @@ enum check_snmp_virtualserver_magic { CHECK_SNMP_VSNAME, CHECK_SNMP_VSQUORUMUPPATH, CHECK_SNMP_VSQUORUMDOWNPATH, +#ifdef _WITH_LVS_64BIT_STATS_ + CHECK_SNMP_VSRATECPS64, + CHECK_SNMP_VSRATEINPPS64, + CHECK_SNMP_VSRATEOUTPPS64, + CHECK_SNMP_VSRATEINBPS64, + CHECK_SNMP_VSRATEOUTBPS64, +#endif }; enum check_snmp_realserver_magic { @@ -159,6 +167,7 @@ enum check_snmp_realserver_magic { CHECK_SNMP_RSSTATSCONNS64, CHECK_SNMP_RSSTATSINPKTS64, CHECK_SNMP_RSSTATSOUTPKTS64, + /* See below for RSRATECPS64 etc 64 bit counters for rates */ CHECK_SNMP_RSRATECPSLOW, CHECK_SNMP_RSRATECPSHIGH, CHECK_SNMP_RSRATEINPPSLOW, @@ -192,6 +201,13 @@ enum check_snmp_realserver_magic { CHECK_SNMP_RSNAME, CHECK_SNMP_RSNOTIFYUPPATH, CHECK_SNMP_RSNOTIFYDOWNPATH, +#ifdef _WITH_LVS_64BIT_STATS_ + CHECK_SNMP_RSRATECPS64, + CHECK_SNMP_RSRATEINPPS64, + CHECK_SNMP_RSRATEOUTPPS64, + CHECK_SNMP_RSRATEINBPS64, + CHECK_SNMP_RSRATEOUTBPS64, +#endif }; #define STATE_VSGM_FWMARK 1 @@ -631,6 +647,7 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, counter64_ret.high = v->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); + /* See below for VSRATECPS64 etc 64 bit counters for rates */ case CHECK_SNMP_VSRATECPSLOW: ipvs_vs_update_stats(v); long_ret.u = v->stats.cps & 0xffffffff; @@ -770,6 +787,38 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, ret.cp = v->notify_quorum_down->path ? v->notify_quorum_down->path : v->notify_quorum_down->args[0]; *var_len = strlen(ret.cp); return ret.p; +#ifdef _WITH_LVS_64BIT_STATS_ + case CHECK_SNMP_VSRATECPS64: + ipvs_vs_update_stats(v); + counter64_ret.low = v->stats.cps & 0xffffffff; + counter64_ret.high = v->stats.cps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_VSRATEINPPS64: + ipvs_vs_update_stats(v); + counter64_ret.low = v->stats.inpps & 0xffffffff; + counter64_ret.high = v->stats.inpps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_VSRATEOUTPPS64: + ipvs_vs_update_stats(v); + counter64_ret.low = v->stats.outpps & 0xffffffff; + counter64_ret.high = v->stats.outpps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_VSRATEINBPS64: + ipvs_vs_update_stats(v); + counter64_ret.low = v->stats.inbps & 0xffffffff; + counter64_ret.high = v->stats.inbps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_VSRATEOUTBPS64: + ipvs_vs_update_stats(v); + counter64_ret.low = v->stats.outbps & 0xffffffff; + counter64_ret.high = v->stats.outbps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); +#endif default: return NULL; } @@ -1083,6 +1132,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, counter64_ret.high = be->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); + /* See below for RSRATECPS64 etc 64 bit counters for rates */ case CHECK_SNMP_RSRATECPSLOW: ipvs_rs_update_stats(bvs); long_ret.u = be->stats.cps & 0xffffffff; @@ -1204,6 +1254,38 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, ret.cp = be->notify_down->path ? be->notify_down->path : be->notify_down->args[0]; *var_len = strlen(ret.cp); return ret.p; +#ifdef _WITH_LVS_64BIT_STATS_ + case CHECK_SNMP_RSRATECPS64: + ipvs_rs_update_stats(bvs); + counter64_ret.low = be->stats.cps & 0xffffffff; + counter64_ret.high = be->stats.cps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_RSRATEINPPS64: + ipvs_rs_update_stats(bvs); + counter64_ret.low = be->stats.inpps & 0xffffffff; + counter64_ret.high = be->stats.inpps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_RSRATEOUTPPS64: + ipvs_rs_update_stats(bvs); + counter64_ret.low = be->stats.outpps & 0xffffffff; + counter64_ret.high = be->stats.outpps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_RSRATEINBPS64: + ipvs_rs_update_stats(bvs); + counter64_ret.low = be->stats.inbps & 0xffffffff; + counter64_ret.high = be->stats.inbps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); + case CHECK_SNMP_RSRATEOUTBPS64: + ipvs_rs_update_stats(bvs); + counter64_ret.low = be->stats.outbps & 0xffffffff; + counter64_ret.high = be->stats.outbps >> 32; + *var_len = sizeof(struct counter64); + return PTR_CAST(u_char, &counter64_ret); +#endif default: return NULL; } @@ -1415,6 +1497,7 @@ static struct variable8 check_vars[] = { check_snmp_virtualserver, 3, {3, 1, 39}}, {CHECK_SNMP_VSSTATSOUTPKTS64, ASN_COUNTER64, RONLY, check_snmp_virtualserver, 3, {3, 1, 40}}, + /* See below for VSRATECPS64 etc 64 bit counters for rates */ {CHECK_SNMP_VSRATECPSLOW, ASN_UNSIGNED, RONLY, check_snmp_virtualserver, 3, {3, 1, 41}}, {CHECK_SNMP_VSRATECPSHIGH, ASN_UNSIGNED, RONLY, @@ -1486,6 +1569,18 @@ static struct variable8 check_vars[] = { check_snmp_virtualserver, 3, {3, 1, 72}}, {CHECK_SNMP_VSQUORUMDOWNPATH, ASN_OCTET_STR, RONLY, check_snmp_virtualserver, 3, {3, 1, 73}}, +#ifdef _WITH_LVS_64BIT_STATS_ + {CHECK_SNMP_VSRATECPS64, ASN_COUNTER64, RONLY, + check_snmp_virtualserver, 3, {3, 1, 74}}, + {CHECK_SNMP_VSRATEINPPS64, ASN_COUNTER64, RONLY, + check_snmp_virtualserver, 3, {3, 1, 75}}, + {CHECK_SNMP_VSRATEOUTPPS64, ASN_COUNTER64, RONLY, + check_snmp_virtualserver, 3, {3, 1, 76}}, + {CHECK_SNMP_VSRATEINBPS64, ASN_COUNTER64, RONLY, + check_snmp_virtualserver, 3, {3, 1, 77}}, + {CHECK_SNMP_VSRATEOUTBPS64, ASN_COUNTER64, RONLY, + check_snmp_virtualserver, 3, {3, 1, 78}}, +#endif /* realServerTable */ {CHECK_SNMP_RSTYPE, ASN_INTEGER, RONLY, @@ -1545,6 +1640,7 @@ static struct variable8 check_vars[] = { check_snmp_realserver, 3, {4, 1, 28}}, {CHECK_SNMP_RSSTATSOUTPKTS64, ASN_COUNTER64, RONLY, check_snmp_realserver, 3, {4, 1, 29}}, + /* See below for RSRATECPS64 64 bit counters for rates */ {CHECK_SNMP_RSRATECPSLOW, ASN_UNSIGNED, RONLY, check_snmp_realserver, 3, {4, 1, 30}}, {CHECK_SNMP_RSRATECPSHIGH, ASN_UNSIGNED, RONLY, @@ -1606,6 +1702,18 @@ static struct variable8 check_vars[] = { check_snmp_realserver, 3, {4, 1, 56}}, {CHECK_SNMP_RSNOTIFYDOWNPATH, ASN_OCTET_STR, RONLY, check_snmp_realserver, 3, {4, 1, 57}}, +#ifdef _WITH_LVS_64BIT_STATS_ + {CHECK_SNMP_RSRATECPS64, ASN_COUNTER64, RONLY, + check_snmp_realserver, 3, {4, 1, 58}}, + {CHECK_SNMP_RSRATEINPPS64, ASN_COUNTER64, RONLY, + check_snmp_realserver, 3, {4, 1, 59}}, + {CHECK_SNMP_RSRATEOUTPPS64, ASN_COUNTER64, RONLY, + check_snmp_realserver, 3, {4, 1, 60}}, + {CHECK_SNMP_RSRATEINBPS64, ASN_COUNTER64, RONLY, + check_snmp_realserver, 3, {4, 1, 61}}, + {CHECK_SNMP_RSRATEOUTBPS64, ASN_COUNTER64, RONLY, + check_snmp_realserver, 3, {4, 1, 62}}, +#endif #ifdef _WITH_VRRP_ /* LVS sync daemon configuration */ From e13b3b8cb9758fb977147965f939282f8943dbf8 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:24:02 +0100 Subject: [PATCH 13/24] ipvs: Use structure sizes for lengths of IPv4/6 addresses Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index 46e67086d9..c3c5e7d460 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -246,18 +246,19 @@ enum check_snmp_lvs_timeouts { do { \ if (entity->addr.ss_family == AF_INET6) { \ struct sockaddr_in6 *addr6 = PTR_CAST(struct sockaddr_in6, &entity->addr); \ - *var_len = 16; \ + *var_len = sizeof(struct in6_addr); \ return PTR_CAST(u_char, &addr6->sin6_addr); \ } else { \ struct sockaddr_in *addr4 = PTR_CAST(struct sockaddr_in, &entity->addr); \ - *var_len = 4; \ + *var_len = sizeof(struct in_addr); \ return PTR_CAST(u_char, &addr4->sin_addr); \ } \ } while(0) -/* Static return value */ +/* Static return values */ static longret_t long_ret; static char buf[MAXBUF]; +static struct counter64 counter64_ret; static u_char* check_snmp_vsgroup(struct variable *vp, oid *name, size_t *length, @@ -423,7 +424,6 @@ 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; real_server_t *rs; snmp_ret_t ret; @@ -886,7 +886,6 @@ static u_char * check_snmp_realserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - static struct counter64 counter64_ret; oid *target, current[2]; int result; size_t target_len; From 63591bc4be8206eb0593213b7f712601014e1669 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:24:44 +0100 Subject: [PATCH 14/24] ipvs: Use SNMP variable3/4/7 instead of variable8 where appropriate This reduces the memory usage of keepalived Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 6 +++--- keepalived/core/snmp.c | 6 +++--- keepalived/vrrp/vrrp_snmp.c | 18 +++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index c3c5e7d460..dd59273c32 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -1397,7 +1397,7 @@ check_snmp_lvs_timeouts(struct variable *vp, oid *name, size_t *length, } static oid check_oid[] = {CHECK_OID}; -static struct variable8 check_vars[] = { +static struct variable3 check_vars[] = { /* virtualServerGroupTable */ {CHECK_SNMP_VSGROUPNAME, ASN_OCTET_STR, RONLY, check_snmp_vsgroup, 3, {1, 1, 2}}, @@ -1756,8 +1756,8 @@ check_snmp_agent_init(const char *snmp_socket) snmp_agent_init(snmp_socket, true); snmp_register_mib(check_oid, OID_LENGTH(check_oid), "Healthchecker", PTR_CAST(struct variable, check_vars), - sizeof(struct variable8), - sizeof(check_vars)/sizeof(struct variable8)); + sizeof(check_vars[0]), + sizeof(check_vars)/sizeof(check_vars[0])); } void diff --git a/keepalived/core/snmp.c b/keepalived/core/snmp.c index 0a44b449eb..b750e1e26e 100644 --- a/keepalived/core/snmp.c +++ b/keepalived/core/snmp.c @@ -353,7 +353,7 @@ snmp_mail(struct variable *vp, oid *name, size_t *length, static const char global_name[] = "Keepalived"; static oid global_oid[] = GLOBAL_OID; -static struct variable8 global_vars[] = { +static struct variable4 global_vars[] = { /* version */ {SNMP_KEEPALIVEDVERSION, ASN_OCTET_STR, RONLY, snmp_scalar, 1, {1}}, /* routerId */ @@ -487,8 +487,8 @@ snmp_agent_init(const char *snmp_socket_name, bool base_mib) if (base_mib) snmp_register_mib(global_oid, OID_LENGTH(global_oid), global_name, PTR_CAST(struct variable, global_vars), - sizeof(struct variable8), - sizeof(global_vars)/sizeof(struct variable8)); + sizeof(global_vars[0]), + sizeof(global_vars)/sizeof(global_vars[0])); init_snmp(global_name); master->snmp_timer_thread = thread_add_timer(master, snmp_timeout_thread, 0, TIMER_NEVER); diff --git a/keepalived/vrrp/vrrp_snmp.c b/keepalived/vrrp/vrrp_snmp.c index 5e1038af5b..e18272ae70 100644 --- a/keepalived/vrrp/vrrp_snmp.c +++ b/keepalived/vrrp/vrrp_snmp.c @@ -2574,7 +2574,7 @@ vrrp_snmp_group_trackedprocess(struct variable *vp, oid *name, size_t *length, #endif static oid vrrp_oid[] = {VRRP_OID}; -static struct variable8 vrrp_vars[] = { +static struct variable3 vrrp_vars[] = { /* vrrpSyncGroupTable */ {VRRP_SNMP_SYNCGROUP_NAME, ASN_OCTET_STR, RONLY, vrrp_snmp_syncgroup, 3, {1, 1, 2}}, @@ -3667,7 +3667,7 @@ vrrp_rfcv2_snmp_statstable(struct variable *vp, oid *name, size_t *length, } static oid vrrp_rfcv2_oid[] = {VRRP_RFC_OID}; -static struct variable8 vrrp_rfcv2_vars[] = { +static struct variable4 vrrp_rfcv2_vars[] = { { VRRP_RFC_SNMP_NODE_VER, ASN_INTEGER, RONLY, vrrp_rfcv2_snmp_node_info, 2, {1, 1}}, { VRRP_RFC_SNMP_NOTIF_CNTL, ASN_INTEGER, RONLY, @@ -4341,7 +4341,7 @@ vrrp_rfcv3_snmp_statstable(struct variable *vp, oid *name, size_t *length, } static oid vrrp_rfcv3_oid[] = {VRRP_RFCv3_OID}; -static struct variable8 vrrp_rfcv3_vars[] = { +static struct variable7 vrrp_rfcv3_vars[] = { /* vrrpOperTable */ { VRRP_RFCv3_SNMP_OPER_MIP, ASN_OCTET_STR, RONLY, vrrp_rfcv3_snmp_opertable, 5, {1, 1, 1, 1, 3}}, @@ -4539,22 +4539,22 @@ vrrp_snmp_agent_init(const char *snmp_socket_name) if (global_data->enable_snmp_vrrp) snmp_register_mib(vrrp_oid, OID_LENGTH(vrrp_oid), "KEEPALIVED-VRRP", PTR_CAST(struct variable, vrrp_vars), - sizeof(struct variable8), - sizeof(vrrp_vars)/sizeof(struct variable8)); + sizeof(vrrp_vars[0]), + sizeof(vrrp_vars)/sizeof(vrrp_vars[0])); #endif #ifdef _WITH_SNMP_RFCV2_ if (global_data->enable_snmp_rfcv2) snmp_register_mib(vrrp_rfcv2_oid, OID_LENGTH(vrrp_rfcv2_oid), "VRRP", PTR_CAST(struct variable, vrrp_rfcv2_vars), - sizeof(struct variable8), - sizeof(vrrp_rfcv2_vars)/sizeof(struct variable8)); + sizeof(vrrp_rfcv2_vars[0]), + sizeof(vrrp_rfcv2_vars)/sizeof(vrrp_rfcv2_vars[0])); #endif #ifdef _WITH_SNMP_RFCV3_ if (global_data->enable_snmp_rfcv3) snmp_register_mib(vrrp_rfcv3_oid, OID_LENGTH(vrrp_rfcv3_oid), "VRRPV3", PTR_CAST(struct variable, vrrp_rfcv3_vars), - sizeof(struct variable8), - sizeof(vrrp_rfcv3_vars)/sizeof(struct variable8)); + sizeof(vrrp_rfcv3_vars[0]), + sizeof(vrrp_rfcv3_vars)/sizeof(vrrp_rfcv3_vars[0])); #endif } From b37052a42a230ebd57abb1714966999fe2738816 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:25:55 +0100 Subject: [PATCH 15/24] ipvs: streamline SNMP real server code when no sorry server Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index dd59273c32..1e714b575a 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -919,7 +919,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, curreal = 0; if (target_len && (curvirtual < target[0])) continue; /* Optimization: cannot be part of our set */ - state = STATE_RS_SORRY; + state = vs->s_svr ? STATE_RS_SORRY : STATE_RS_REGULAR_FIRST; while (state != STATE_RS_END) { switch (state) { case STATE_RS_SORRY: From 062f1df4304ab665e4f7a0badcabf2ad778baa2f Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:27:11 +0100 Subject: [PATCH 16/24] ipvs: Merge several SNMP functions that were doing nearly the same thing Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 295 ++++++++++++++----------------------- keepalived/include/ip_vs.h | 1 - 2 files changed, 108 insertions(+), 188 deletions(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 99d59726df..806bdf1906 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -53,11 +53,6 @@ #include "namespaces.h" #include "global_data.h" -typedef struct ipvs_servicedest_s { - struct ip_vs_service_user svc; - struct ip_vs_dest_user dest; -} ipvs_servicedest_t; - static int sockfd = -1; static void* ipvs_func = NULL; static ipvs_timeout_t orig_ipvs_timeouts; @@ -164,19 +159,6 @@ static struct nla_policy ipvs_info_policy[IPVS_INFO_ATTR_MAX + 1] = { }; #endif -#define CHECK_IPV4(s, ret) if (s->af && s->af != AF_INET) \ - { errno = EAFNOSUPPORT; goto out_err; } \ - s->user.addr = s->nf_addr.ip; \ - -#define CHECK_PE(s, ret) if (s->pe_name[0]) \ - { errno = EAFNOSUPPORT; goto out_err; } - -#define CHECK_COMPAT_DEST(s, ret) CHECK_IPV4(s, ret) - -#define CHECK_COMPAT_SVC(s, ret) \ - CHECK_IPV4(s, ret); \ - CHECK_PE(s, ret); - #ifdef LIBIPVS_USE_NL #ifndef NLA_PUT_S32 #define NLA_PUT_S32(msg, attrtype, value) \ @@ -418,8 +400,7 @@ static int ipvs_getinfo(void) } len = sizeof(ipvs_info); - return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, - (char *)&ipvs_info, &len); + return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len); } #endif @@ -450,7 +431,7 @@ int ipvs_init(void) return -1; len = sizeof(ipvs_info); - if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, (char *)&ipvs_info, &len)) { + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len)) { close(sockfd); sockfd = -1; return -1; @@ -509,12 +490,12 @@ static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc) } #endif -int ipvs_add_service(ipvs_service_t *svc) +static int +ipvs_do_service(ipvs_service_t *svc, uint8_t cmd) { - ipvs_func = ipvs_add_service; #ifdef LIBIPVS_USE_NL if (try_nl) { - struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_SERVICE, 0); + struct nl_msg *msg = ipvs_nl_message(cmd, 0); if (!msg) return -1; if (ipvs_nl_fill_service_attr(msg, svc)) { nlmsg_free(msg); @@ -524,82 +505,52 @@ int ipvs_add_service(ipvs_service_t *svc) } #endif - CHECK_COMPAT_SVC(svc, -1); - return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc, - sizeof(struct ip_vs_service_user)); -out_err: - return -1; + if (svc->af != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } + + svc->user.addr = svc->nf_addr.ip; + + return setsockopt(sockfd, IPPROTO_IP, + cmd == IPVS_CMD_NEW_SERVICE ? IP_VS_SO_SET_ADD : +#ifdef _INCLUDE_UNUSED_CODE_ + cmd == IPVS_CMD_ZERO ? IP_VS_SO_SET_ZERO : +#endif + cmd == IPVS_CMD_DEL_SERVICE ? IP_VS_SO_SET_DEL : IP_VS_SO_SET_EDIT, + &svc->user, sizeof(svc->user)); } +int +ipvs_add_service(ipvs_service_t *svc) +{ + ipvs_func = ipvs_add_service; -int ipvs_update_service(ipvs_service_t *svc) + return ipvs_do_service(svc, IPVS_CMD_NEW_SERVICE); +} + +int +ipvs_update_service(ipvs_service_t *svc) { ipvs_func = ipvs_update_service; -#ifdef LIBIPVS_USE_NL - if (try_nl) { - struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_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_EDIT, (char *)svc, - sizeof(struct ip_vs_service_user)); -out_err: - return -1; -} + return ipvs_do_service(svc, IPVS_CMD_SET_SERVICE); +} -int ipvs_del_service(ipvs_service_t *svc) +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_COMPAT_SVC(svc, -1); - return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc, - sizeof(struct ip_vs_service_user)); -out_err: - return -1; + + return ipvs_do_service(svc, IPVS_CMD_DEL_SERVICE); } #ifdef _INCLUDE_UNUSED_CODE_ 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->user.fwmark - || memcmp(&in6addr_any, &svc->nf_addr.in6, sizeof(struct in6_addr)) - || svc->user.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_user)); -out_err: - return -1; + return ipvs_do_service(svc, IPVS_CMD_ZERO); } #endif @@ -641,16 +592,19 @@ static int ipvs_nl_fill_dest_attr(struct nl_msg *msg, ipvs_dest_t *dst) } #endif -int ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +static int +ipvs_do_dest(ipvs_service_t *svc, ipvs_dest_t *dest, uint8_t cmd) { - ipvs_servicedest_t svcdest; - - ipvs_func = ipvs_add_dest; + struct { + struct ip_vs_service_user svc; + struct ip_vs_dest_user dest; + } svcdest; #ifdef LIBIPVS_USE_NL if (try_nl) { - struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DEST, 0); - if (!msg) return -1; + struct nl_msg *msg = ipvs_nl_message(cmd, 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)) @@ -663,77 +617,45 @@ int ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest) } #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_ADDDEST, - (char *)&svcdest, sizeof(svcdest)); -out_err: - return -1; -} + if (svc->af != AF_INET || dest->af != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } + svcdest.svc = svc->user; + svcdest.dest = dest->user; -int ipvs_update_dest(ipvs_service_t *svc, ipvs_dest_t *dest) + svcdest.svc.addr = svc->nf_addr.ip; + svcdest.dest.addr = dest->nf_addr.ip; + + return setsockopt(sockfd, IPPROTO_IP, + cmd == IPVS_CMD_NEW_DEST ? IP_VS_SO_SET_ADDDEST : + cmd == IPVS_CMD_SET_DEST ? IP_VS_SO_SET_EDITDEST : IP_VS_SO_SET_DELDEST, + &svcdest, sizeof(svcdest)); +} + +int +ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest) { - ipvs_servicedest_t svcdest; + ipvs_func = ipvs_add_dest; + + return ipvs_do_dest(svc, dest, IPVS_CMD_NEW_DEST); +} +int +ipvs_update_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +{ ipvs_func = ipvs_update_dest; -#ifdef LIBIPVS_USE_NL - if (try_nl) { - struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_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_EDITDEST, - (char *)&svcdest, sizeof(svcdest)); -out_err: - return -1; + return ipvs_do_dest(svc, dest, IPVS_CMD_SET_DEST); } - -int ipvs_del_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +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; + return ipvs_do_dest(svc, dest, IPVS_CMD_DEL_DEST); } #ifdef LIBIPVS_USE_NL @@ -775,8 +697,7 @@ ipvs_get_timeout(void) #endif len = sizeof(orig_ipvs_timeouts); - if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUT, - (char *)&orig_ipvs_timeouts, &len)) { + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUT, &orig_ipvs_timeouts, &len)) { log_message(LOG_INFO, "Failed to get IPVS timeouts"); return; } @@ -858,8 +779,7 @@ int ipvs_start_daemon(ipvs_daemon_t *dm) 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)); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STARTDAEMON, &dmk, sizeof(dmk)); } @@ -892,8 +812,7 @@ int ipvs_stop_daemon(ipvs_daemon_t *dm) #endif memset(&dmk, 0, sizeof(dmk)); dmk.state = dm->state; - return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, - (char *)&dmk, sizeof(dmk)); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, &dmk, sizeof(dmk)); } #ifdef _WITH_SNMP_CHECKER_ @@ -1308,20 +1227,23 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add } #endif + if (af != AF_INET) { + errno = EAFNOSUPPORT; + return NULL; + } + len = sizeof(*svc); svc = MALLOC(len); if (!svc) return NULL; svc->user.fwmark = fwmark; - svc->af = af; + svc->af = AF_INET; svc->user.protocol = protocol; - svc->nf_addr = *addr; + svc->user.addr = addr->ip; svc->user.port = port; - CHECK_COMPAT_SVC(svc, NULL); - if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, - (char *)svc, &len)) { + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, svc, &len)) { FREE(svc); return NULL; } @@ -1333,9 +1255,6 @@ ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr *add #endif return svc; -out_err: - FREE(svc); - return NULL; } #endif /* _WITH_SNMP_CHECKER_ */ @@ -1356,31 +1275,33 @@ void ipvs_close(void) } } -const char *ipvs_strerror(int err) +static struct table_struct { + void *func; + int err; + const char *message; +} table [] = { + { ipvs_add_service, EEXIST, "Service already exists" }, + { ipvs_add_service, ENOENT, "Scheduler or persistence engine not found" }, + { ipvs_update_service, ENOENT, "Scheduler or persistence engine not found" }, + { ipvs_add_dest, EEXIST, "Destination already exists" }, + { ipvs_update_dest, ENOENT, "No such destination" }, + { ipvs_del_dest, ENOENT, "No such destination" }, + { ipvs_start_daemon, EEXIST, "Daemon has already run" }, + { ipvs_stop_daemon, ESRCH, "No daemon is running" }, + { NULL, ESRCH, "No such service" }, + { NULL, EPERM, "Permission denied (you must be root)" }, + { NULL, EINVAL, "Invalid operation. Possibly wrong module version, address not unicast, ..." }, + { NULL, ENOPROTOOPT, "Protocol not available" }, + { NULL, ENOMEM, "Memory allocation problem" }, + { NULL, EOPNOTSUPP, "Operation not supported with IPv6" }, + { NULL, EAFNOSUPPORT, "Operation not supported with specified address family" }, + { NULL, EMSGSIZE, "Module is wrong version" }, +}; + +const char * +ipvs_strerror(int err) { unsigned int i; - struct table_struct { - void *func; - int err; - const char *message; - } table [] = { - { ipvs_add_service, EEXIST, "Service already exists" }, - { ipvs_add_service, ENOENT, "Scheduler or persistence engine not found" }, - { ipvs_update_service, ENOENT, "Scheduler or persistence engine not found" }, - { ipvs_add_dest, EEXIST, "Destination already exists" }, - { ipvs_update_dest, ENOENT, "No such destination" }, - { ipvs_del_dest, ENOENT, "No such destination" }, - { ipvs_start_daemon, EEXIST, "Daemon has already run" }, - { ipvs_stop_daemon, ESRCH, "No daemon is running" }, - { NULL, ESRCH, "No such service" }, - { NULL, EPERM, "Permission denied (you must be root)" }, - { NULL, EINVAL, "Invalid operation. Possibly wrong module version, address not unicast, ..." }, - { NULL, ENOPROTOOPT, "Protocol not available" }, - { NULL, ENOMEM, "Memory allocation problem" }, - { NULL, EOPNOTSUPP, "Operation not supported with IPv6" }, - { NULL, EAFNOSUPPORT, "Operation not supported with specified address family" }, - { NULL, EMSGSIZE, "Module is wrong version" }, - }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { if ((!table[i].func || table[i].func == ipvs_func) diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index de593fd91a..382fa7fd47 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -85,7 +85,6 @@ struct ip_vs_dest_entry_app { #endif uint16_t af; union nf_inet_addr nf_addr; - }; struct ip_vs_get_dests_app { From 18f3835e8dff1c9868c56ededb211622bf324aac Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:29:17 +0100 Subject: [PATCH 17/24] ipvs: Use kernel structures for ipvs daemon parameters Signed-off-by: Quentin Armitage --- keepalived/check/ipvswrapper.c | 8 ++++---- keepalived/check/libipvs.c | 28 +++++++++++----------------- keepalived/include/ip_vs.h | 21 +-------------------- 3 files changed, 16 insertions(+), 41 deletions(-) diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c index 93205a267f..2cfbd8c08a 100644 --- a/keepalived/check/ipvswrapper.c +++ b/keepalived/check/ipvswrapper.c @@ -252,9 +252,9 @@ ipvs_syncd_cmd(int cmd, const struct lvs_syncd_config *config, int state, bool i /* prepare user rule */ if (config) { - daemonrule.syncid = (int)config->syncid; + daemonrule.user.syncid = (int)config->syncid; if (cmd == IPVS_STARTDAEMON) { - strcpy_safe(daemonrule.mcast_ifn, config->ifname); + strcpy_safe(daemonrule.user.mcast_ifn, config->ifname); #ifdef _HAVE_IPVS_SYNCD_ATTRIBUTES_ if (config->sync_maxlen) @@ -276,14 +276,14 @@ ipvs_syncd_cmd(int cmd, const struct lvs_syncd_config *config, int state, bool i } if (state & IPVS_MASTER) { - daemonrule.state = IP_VS_STATE_MASTER; + daemonrule.user.state = IP_VS_STATE_MASTER; /* Talk to the IPVS channel */ ipvs_talk(cmd, NULL, NULL, &daemonrule, ignore_error); } if (state & IPVS_BACKUP) { - daemonrule.state = IP_VS_STATE_BACKUP; + daemonrule.user.state = IP_VS_STATE_BACKUP; /* Talk to the IPVS channel */ ipvs_talk(cmd, NULL, NULL, &daemonrule, ignore_error); diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 806bdf1906..932949ad6d 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -737,9 +737,8 @@ int ipvs_set_timeout(const ipvs_timeout_t *to) 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; @@ -750,9 +749,9 @@ int ipvs_start_daemon(ipvs_daemon_t *dm) if (!nl_daemon) goto nla_put_failure; - NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); - NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); - NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); + NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_STATE, dm->user.state); + NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->user.mcast_ifn); + NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->user.syncid); #ifdef _HAVE_IPVS_SYNCD_ATTRIBUTES_ if (dm->sync_maxlen) NLA_PUT_U16(msg, IPVS_DAEMON_ATTR_SYNC_MAXLEN, dm->sync_maxlen); @@ -775,19 +774,15 @@ int ipvs_start_daemon(ipvs_daemon_t *dm) 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, &dmk, sizeof(dmk)); + + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STARTDAEMON, &dm->user, sizeof(dm->user)); } int ipvs_stop_daemon(ipvs_daemon_t *dm) { - struct ip_vs_daemon_kern dmk; - ipvs_func = ipvs_stop_daemon; + #ifdef LIBIPVS_USE_NL if (try_nl) { struct nlattr *nl_daemon; @@ -798,8 +793,8 @@ int ipvs_stop_daemon(ipvs_daemon_t *dm) if (!nl_daemon) goto nla_put_failure; - NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); - NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); + NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_STATE, dm->user.state); + NLA_PUT_S32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->user.syncid); nla_nest_end(msg, nl_daemon); @@ -810,9 +805,8 @@ int ipvs_stop_daemon(ipvs_daemon_t *dm) return -1; } #endif - memset(&dmk, 0, sizeof(dmk)); - dmk.state = dm->state; - return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, &dmk, sizeof(dmk)); + + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, &dm->user, sizeof(dm->user)); } #ifdef _WITH_SNMP_CHECKER_ diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index 382fa7fd47..75a632b79b 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -124,27 +124,8 @@ struct ip_vs_get_services_app { #error The code assumes that IP_VS_IFNAME_MAXLEN <= IFNAMSIZ #endif -/* The argument to IP_VS_SO_GET_DAEMON */ -struct ip_vs_daemon_kern { - /* sync daemon state (master/backup) */ - int state; - - /* multicast interface name */ - char mcast_ifn[IP_VS_IFNAME_MAXLEN]; - - /* SyncID we belong to */ - int syncid; -}; - struct ip_vs_daemon_app { - /* sync daemon state (master/backup) */ - int state; - - /* multicast interface name */ - char mcast_ifn[IP_VS_IFNAME_MAXLEN]; - - /* SyncID we belong to */ - int syncid; + struct ip_vs_daemon_user user; #ifdef _HAVE_IPVS_SYNCD_ATTRIBUTES_ /* UDP Payload Size */ From 247fd14e3667e7c6c50009cbfa4303a792d446b3 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:30:04 +0100 Subject: [PATCH 18/24] ipvs: Remove unused fields from ip_vs_get_dest_entries_app structure Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 55 +++++++++++++++----------------------- keepalived/include/ip_vs.h | 9 +------ 2 files changed, 22 insertions(+), 42 deletions(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 932949ad6d..a2a51c41c7 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -987,12 +987,10 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *dest_attrs[IPVS_DEST_ATTR_MAX + 1]; -#if HAVE_DECL_IPVS_DEST_ATTR_ADDR_FAMILY - struct nlattr *attr_addr_family = NULL; -#endif struct ip_vs_get_dests_app **dp = PTR_CAST(struct ip_vs_get_dests_app *, arg); struct ip_vs_get_dests_app *d = PTR_CAST(struct ip_vs_get_dests_app, *dp); unsigned i = d->user.num_dests; + struct ip_vs_dest_entry_app *ent; if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) return -1; @@ -1020,37 +1018,35 @@ static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) *dp = d; } - memset(&(d->user.entrytable[i]), 0, sizeof(d->user.entrytable[i])); + ent = &d->user.entrytable[i]; + memset(ent, 0, sizeof(*ent)); - memcpy(&(d->user.entrytable[i].nf_addr), + memcpy(&ent->nf_addr, nla_data(dest_attrs[IPVS_DEST_ATTR_ADDR]), - sizeof(d->user.entrytable[i].nf_addr)); - d->user.entrytable[i].user.port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]); - d->user.entrytable[i].user.conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]); - d->user.entrytable[i].user.weight = nla_get_s32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]); - d->user.entrytable[i].user.u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]); - d->user.entrytable[i].user.l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]); - d->user.entrytable[i].user.activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]); - d->user.entrytable[i].user.inactconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_INACT_CONNS]); - d->user.entrytable[i].user.persistconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]); + nla_len(dest_attrs[IPVS_DEST_ATTR_ADDR])); + ent->user.port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]); + ent->user.conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]); + ent->user.weight = nla_get_s32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]); + ent->user.u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]); + ent->user.l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]); + ent->user.activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]); + ent->user.inactconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_INACT_CONNS]); + ent->user.persistconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]); #if HAVE_DECL_IPVS_DEST_ATTR_ADDR_FAMILY - attr_addr_family = dest_attrs[IPVS_DEST_ATTR_ADDR_FAMILY]; - if (attr_addr_family) - d->user.entrytable[i].af = nla_get_u16(attr_addr_family); + if (dest_attrs[IPVS_DEST_ATTR_ADDR_FAMILY]) + ent->af = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_ADDR_FAMILY]); else #endif - d->user.entrytable[i].af = d->af; + ent->af = d->af; #ifdef _WITH_LVS_64BIT_STATS_ if (dest_attrs[IPVS_DEST_ATTR_STATS64]) { - if (ipvs_parse_stats64(&(d->user.entrytable[i].ip_vs_stats), - dest_attrs[IPVS_DEST_ATTR_STATS64]) != 0) + if (ipvs_parse_stats64(&ent->ip_vs_stats, dest_attrs[IPVS_DEST_ATTR_STATS64]) != 0) return -1; } else if (dest_attrs[IPVS_DEST_ATTR_STATS]) #endif { - if (ipvs_parse_stats(&(d->user.entrytable[i].ip_vs_stats), - dest_attrs[IPVS_DEST_ATTR_STATS]) != 0) + if (ipvs_parse_stats(&ent->ip_vs_stats, dest_attrs[IPVS_DEST_ATTR_STATS]) != 0) return -1; } @@ -1080,13 +1076,8 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco if (try_nl) { struct nl_msg *msg; struct nlattr *nl_service; - d->user.fwmark = fwmark; - d->user.protocol = protocol; - if (addr) - d->nf_addr = *addr; - d->user.port = port; - d->user.num_dests = 0; d->af = af; + d->user.num_dests = 0; msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); if (!msg) @@ -1102,7 +1093,7 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, fwmark); } else { NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, protocol); - NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(*addr), addr); + NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr), addr); NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, port); } nla_nest_end(msg, nl_service); @@ -1137,7 +1128,6 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco if (addr) dk->addr = addr->ip; dk->port = port; - dk->num_dests = num_dests; if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DESTS, dk, &len) < 0) { FREE(d); @@ -1145,10 +1135,7 @@ struct ip_vs_get_dests_app *ipvs_get_dests(__u32 fwmark, __u16 af, __u16 protoco return NULL; } - d->user = *(struct ip_vs_get_dests_entries_app *)dk; - d->af = AF_INET; - if (addr) - d->nf_addr.ip = dk->addr; + d->user.num_dests = dk->num_dests; for (i = 0; i < dk->num_dests; i++) { d->user.entrytable[i].user = dk->entrytable[i]; d->user.entrytable[i].af = AF_INET; diff --git a/keepalived/include/ip_vs.h b/keepalived/include/ip_vs.h index 75a632b79b..e1ee563a0c 100644 --- a/keepalived/include/ip_vs.h +++ b/keepalived/include/ip_vs.h @@ -88,18 +88,11 @@ struct ip_vs_dest_entry_app { }; struct ip_vs_get_dests_app { - uint16_t af; - union nf_inet_addr nf_addr; + uint16_t af; /* Needed if don't get IPVS_DEST_ATTR_ADDR_FAMILY */ unsigned num_entries; /* Number of entries space allocated for */ struct ip_vs_get_dests_entries_app { - /* which service: user fills in these */ - __u16 protocol; - __be32 addr; /* virtual address */ - __be16 port; - __u32 fwmark; /* firwall mark of service */ - /* number of real servers */ unsigned int num_dests; From c3133e9fc0cc1fa099d1cf744c11595033428662 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:31:00 +0100 Subject: [PATCH 19/24] ipvs: Streamline finding VS group entry for SNMP Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 81 ++++++++++++++++------------------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index 1e714b575a..190ffa4be0 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -288,12 +288,12 @@ static u_char* check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - oid *target, current[2], best[2]; + oid *target; + oid current[2] = { 0 }; int result; size_t target_len; - unsigned curgroup = 0, curentry; virtual_server_group_t *group; - virtual_server_group_entry_t *vsge, *be = NULL; + virtual_server_group_entry_t *vsge; int state; list_head_t *l; @@ -312,15 +312,14 @@ check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, /* 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; list_for_each_entry(group, &check_data->vs_group, e_list) { - curgroup++; - curentry = 0; - if (target_len && (curgroup < target[0])) + current[0]++; + current[1] = 0; + if (target_len && (current[0] < target[0])) continue; /* Optimization: cannot be part of our set */ - state = STATE_VSGM_FWMARK; + state = list_empty(&group->vfwmark) ? STATE_VSGM_ADDRESS_RANGE : STATE_VSGM_FWMARK; while (state < STATE_VSGM_END) { switch (state) { case STATE_VSGM_FWMARK: @@ -335,27 +334,23 @@ check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, } state++; list_for_each_entry(vsge, l, e_list) { - curentry++; - /* We build our current match */ - current[0] = curgroup; - current[1] = curentry; + current[1]++; /* 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) { + if (!exact) + continue; + /* Got an exact match and asked for it */ - be = vsge; - goto vsgmember_found; - } - if (snmp_oid_compare(current, 2, best, 2) < 0) { + } else { /* This is our best match */ - memcpy(best, current, sizeof(oid) * 2); - be = vsge; - goto vsgmember_be_found; + target[0] = current[0]; + target[1] = current[1]; + *length = (unsigned)vp->namelen + 2; } + goto vsgmember_found; } } } @@ -363,51 +358,47 @@ check_snmp_vsgroupmember(struct variable *vp, oid *name, size_t *length, /* Nothing found */ 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->is_fwmark) + if (vsge->is_fwmark) long_ret.u = 1; - else if (inet_sockaddrcmp(&be->addr, &be->addr_end)) + else if (inet_sockaddrcmp(&vsge->addr, &vsge->addr_end)) long_ret.u = 3; else long_ret.u = 2; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSGROUPMEMBERFWMARK: - if (!be->is_fwmark) break; - long_ret.u = be->vfwmark; + if (!vsge->is_fwmark) break; + long_ret.u = vsge->vfwmark; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSGROUPMEMBERADDRTYPE: - if (be->is_fwmark) break; - long_ret.u = SNMP_InetAddressType(be->addr.ss_family); + if (vsge->is_fwmark) break; + long_ret.u = SNMP_InetAddressType(vsge->addr.ss_family); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSGROUPMEMBERADDRESS: - if (be->is_fwmark || inet_sockaddrcmp(&be->addr, &be->addr_end)) break; - RETURN_IP46ADDRESS(be); + if (vsge->is_fwmark || inet_sockaddrcmp(&vsge->addr, &vsge->addr_end)) break; + RETURN_IP46ADDRESS(vsge); break; case CHECK_SNMP_VSGROUPMEMBERADDR1: - if (be->is_fwmark || !inet_sockaddrcmp(&be->addr, &be->addr_end)) break; - RETURN_IP46ADDRESS(be); + if (vsge->is_fwmark || !inet_sockaddrcmp(&vsge->addr, &vsge->addr_end)) break; + RETURN_IP46ADDRESS(vsge); break; case CHECK_SNMP_VSGROUPMEMBERADDR2: - if (!inet_sockaddrcmp(&be->addr, &be->addr_end) || be->is_fwmark) break; - if (be->addr.ss_family == AF_INET6) { - struct sockaddr_in6 *addr6 = PTR_CAST(struct sockaddr_in6, &be->addr_end); - *var_len = 16; + if (!inet_sockaddrcmp(&vsge->addr, &vsge->addr_end) || vsge->is_fwmark) break; + if (vsge->addr.ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = PTR_CAST(struct sockaddr_in6, &vsge->addr_end); + *var_len = sizeof(addr6->sin6_addr); return PTR_CAST(u_char, &addr6->sin6_addr); } else { - struct sockaddr_in *addr4 = PTR_CAST(struct sockaddr_in, &be->addr_end); - *var_len = 4; + struct sockaddr_in *addr4 = PTR_CAST(struct sockaddr_in, &vsge->addr_end); + *var_len = sizeof(addr4->sin_addr); return PTR_CAST(u_char, &addr4->sin_addr); } break; case CHECK_SNMP_VSGROUPMEMBERPORT: - if (be->is_fwmark) break; - long_ret.u = htons(inet_sockaddrport(&be->addr)); + if (vsge->is_fwmark) break; + long_ret.u = htons(inet_sockaddrport(&vsge->addr)); return PTR_CAST(u_char, &long_ret); default: return NULL; @@ -1356,11 +1347,11 @@ check_snmp_lvs_sync_daemon(struct variable *vp, oid *name, size_t *length, return NULL; if (global_data->lvs_syncd.mcast_group.ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = PTR_CAST(struct sockaddr_in6, &global_data->lvs_syncd.mcast_group); - *var_len = 16; + *var_len = sizeof(addr6->sin6_addr); return PTR_CAST(u_char, &addr6->sin6_addr); } else { struct sockaddr_in *addr4 = PTR_CAST(struct sockaddr_in, &global_data->lvs_syncd.mcast_group); - *var_len = 4; + *var_len = sizeof(addr4->sin_addr); return PTR_CAST(u_char, &addr4->sin_addr); } #endif From 280e16b335a3d9fee0da102d0a599eef79d8d3ec Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:31:33 +0100 Subject: [PATCH 20/24] ipvs: Streamline finding RS for SNMP Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 285 +++++++++++++++++----------------- 1 file changed, 141 insertions(+), 144 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index 190ffa4be0..dff5d98ec8 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -877,12 +877,12 @@ static u_char * check_snmp_realserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - oid *target, current[2]; + oid *target; + oid current[2] = { 0 };; int result; size_t target_len; - unsigned curvirtual = 0, curreal; - real_server_t *e = NULL, *be = NULL; - virtual_server_t *vs, *bvs = NULL; + real_server_t *rs; + virtual_server_t *vs; int state; int type; snmp_ret_t ret; @@ -905,48 +905,44 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, target_len = *length - vp->namelen; list_for_each_entry(vs, &check_data->vs, e_list) { - curvirtual++; - current[0] = curvirtual; - curreal = 0; - if (target_len && (curvirtual < target[0])) + current[0]++; + if (target_len && (current[0] < target[0])) continue; /* Optimization: cannot be part of our set */ state = vs->s_svr ? STATE_RS_SORRY : STATE_RS_REGULAR_FIRST; while (state != STATE_RS_END) { switch (state) { case STATE_RS_SORRY: - e = vs->s_svr; + rs = vs->s_svr; type = STATE_RS_SORRY; state = STATE_RS_REGULAR_FIRST; break; case STATE_RS_REGULAR_FIRST: if (list_empty(&vs->rs)) { - e = NULL; + rs = NULL; state = STATE_RS_END; break; } - e = list_first_entry(&vs->rs, real_server_t, e_list); + rs = list_first_entry(&vs->rs, real_server_t, e_list); type = STATE_RS_REGULAR_FIRST; state = STATE_RS_REGULAR_NEXT; break; case STATE_RS_REGULAR_NEXT: type = STATE_RS_REGULAR_NEXT; - if (list_is_last(&e->e_list, &vs->rs)) { - e = NULL; + if (list_is_last(&rs->e_list, &vs->rs)) { + rs = NULL; state = STATE_RS_END; break; } - e = list_entry(e->e_list.next, real_server_t, e_list); + rs = list_entry(rs->e_list.next, real_server_t, e_list); break; default: /* Dunno? */ return NULL; } - if (!e) + if (!rs) continue; - curreal++; - /* We build our current match */ - current[1] = curreal; + current[1]++; /* And compare it to our target match */ if ((result = snmp_oid_compare(current, 2, target, @@ -957,20 +953,19 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, if (!exact) continue; } else { - memcpy(target, current, sizeof(oid) * 2); + target[0] = current[0]; + target[1] = current[1]; *length = (unsigned)vp->namelen + 2; } - bvs = vs; - be = e; break; } - if (be) + if (rs) break; } - if (be == NULL) { + if (rs == NULL) { /* No match */ return NULL; } @@ -980,17 +975,16 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, long_ret.u = SNMP_TruthValue(type != STATE_RS_SORRY); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSADDRTYPE: - long_ret.u = SNMP_InetAddressType(be->addr.ss_family); + long_ret.u = SNMP_InetAddressType(rs->addr.ss_family); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSADDRESS: - RETURN_IP46ADDRESS(be); + RETURN_IP46ADDRESS(rs); break; case CHECK_SNMP_RSPORT: - long_ret.u = htons(inet_sockaddrport(&be->addr)); + long_ret.u = htons(inet_sockaddrport(&rs->addr)); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSLOADBALANCINGKIND: - long_ret.u = 0; - switch (be->forwarding_method) { + switch (rs->forwarding_method) { case IP_VS_CONN_F_MASQ: long_ret.u = 1; break; @@ -1000,279 +994,282 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, case IP_VS_CONN_F_TUNNEL: long_ret.u = 3; break; + default: + long_ret.u = 0; + break; } if (!long_ret.u) break; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATUS: if (type == STATE_RS_SORRY) break; - long_ret.u = SNMP_TruthValue(be->alive); + long_ret.u = SNMP_TruthValue(rs->alive); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSWEIGHT: if (type == STATE_RS_SORRY) break; - long_ret.s = real_weight(be->effective_weight); + long_ret.s = real_weight(rs->effective_weight); *write_method = check_snmp_realserver_weight; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSUPPERCONNECTIONLIMIT: if (type == STATE_RS_SORRY) break; - if (!be->u_threshold) break; - long_ret.u = be->u_threshold; + if (!rs->u_threshold) break; + long_ret.u = rs->u_threshold; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSLOWERCONNECTIONLIMIT: if (type == STATE_RS_SORRY) break; - if (!be->l_threshold) break; - long_ret.u = be->l_threshold; + if (!rs->l_threshold) break; + long_ret.u = rs->l_threshold; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSACTIONWHENDOWN: if (type == STATE_RS_SORRY) break; - long_ret.u = SNMP_TruthValue(!be->inhibit); + long_ret.u = SNMP_TruthValue(!rs->inhibit); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSNOTIFYUP: if (type == STATE_RS_SORRY) break; - if (!be->notify_up) break; - cmd_str_r(be->notify_up, buf, sizeof(buf)); + if (!rs->notify_up) break; + cmd_str_r(rs->notify_up, buf, sizeof(buf)); *var_len = strlen(buf); return PTR_CAST(u_char, buf); case CHECK_SNMP_RSNOTIFYDOWN: if (type == STATE_RS_SORRY) break; - if (!be->notify_down) break; - cmd_str_r(be->notify_down, buf, sizeof(buf)); + if (!rs->notify_down) break; + cmd_str_r(rs->notify_down, buf, sizeof(buf)); *var_len = strlen(buf); return PTR_CAST(u_char, buf); case CHECK_SNMP_RSVIRTUALHOST: - if (!be->virtualhost) break; - *var_len = strlen(be->virtualhost); - ret.cp = be->virtualhost; + if (!rs->virtualhost) break; + *var_len = strlen(rs->virtualhost); + ret.cp = rs->virtualhost; return ret.p; case CHECK_SNMP_RSFAILEDCHECKS: if (type == STATE_RS_SORRY) break; - long_ret.u = be->num_failed_checkers; + long_ret.u = rs->num_failed_checkers; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSCONNS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.conns; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.conns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSACTIVECONNS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->activeconns; + ipvs_rs_update_stats(vs); + long_ret.u = rs->activeconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINACTIVECONNS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->inactconns; + ipvs_rs_update_stats(vs); + long_ret.u = rs->inactconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSPERSISTENTCONNS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->persistconns; + ipvs_rs_update_stats(vs); + long_ret.u = rs->persistconns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINPKTS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inpkts; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSOUTPKTS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outpkts; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSTATSINBYTES: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.inbytes & 0xffffffff; - counter64_ret.high = be->stats.inbytes >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.inbytes & 0xffffffff; + counter64_ret.high = rs->stats.inbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSOUTBYTES: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.outbytes & 0xffffffff; - counter64_ret.high = be->stats.outbytes >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.outbytes & 0xffffffff; + counter64_ret.high = rs->stats.outbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATECPS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.cps; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.cps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inpps; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outpps; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inbps; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inbps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPS: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outbps; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outbps; return PTR_CAST(u_char, &long_ret); #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_RSSTATSCONNS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.conns & 0xffffffff; - counter64_ret.high = be->stats.conns >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.conns & 0xffffffff; + counter64_ret.high = rs->stats.conns >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSINPKTS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.inpkts & 0xffffffff; - counter64_ret.high = be->stats.inpkts >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.inpkts & 0xffffffff; + counter64_ret.high = rs->stats.inpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSSTATSOUTPKTS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.outpkts & 0xffffffff; - counter64_ret.high = be->stats.outpkts >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.outpkts & 0xffffffff; + counter64_ret.high = rs->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); /* See below for RSRATECPS64 etc 64 bit counters for rates */ case CHECK_SNMP_RSRATECPSLOW: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.cps & 0xffffffff; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.cps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATECPSHIGH: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.cps >> 32; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.cps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPSLOW: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inpps & 0xffffffff; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inpps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINPPSHIGH: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inpps >> 32; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPSLOW: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outpps & 0xffffffff; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outpps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTPPSHIGH: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outpps >> 32; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPSLOW: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inbps & 0xffffffff; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inbps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEINBPSHIGH: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.inbps >> 32; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.inbps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPSLOW: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outbps & 0xffffffff; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outbps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRATEOUTBPSHIGH: - ipvs_rs_update_stats(bvs); - long_ret.u = be->stats.outbps >> 32; + ipvs_rs_update_stats(vs); + long_ret.u = rs->stats.outbps >> 32; return PTR_CAST(u_char, &long_ret); #endif case CHECK_SNMP_RSALPHA: - long_ret.u = SNMP_TruthValue(be->alpha); + long_ret.u = SNMP_TruthValue(rs->alpha); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSRETRY: - long_ret.u = be->retry == UINT_MAX ? 0 : be->retry; + long_ret.u = rs->retry == UINT_MAX ? 0 : rs->retry; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSDELAYBEFORERETRY: - long_ret.u = be->delay_before_retry == ULONG_MAX ? 0 : be->delay_before_retry / TIMER_HZ; + long_ret.u = rs->delay_before_retry == ULONG_MAX ? 0 : rs->delay_before_retry / TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSWARMUP: - long_ret.u = be->warmup == ULONG_MAX ? 0 : be->warmup / TIMER_HZ; + long_ret.u = rs->warmup == ULONG_MAX ? 0 : rs->warmup / TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSDELAYLOOP: - long_ret.u = be->delay_loop == ULONG_MAX ? 0 : be->delay_loop / TIMER_HZ; + long_ret.u = rs->delay_loop == ULONG_MAX ? 0 : rs->delay_loop / TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSSMTPALERT: - long_ret.u = SNMP_TruthValue(be->smtp_alert); + long_ret.u = SNMP_TruthValue(rs->smtp_alert); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSDELAYBEFORERETRYUSEC: - long_ret.u = be->delay_before_retry == ULONG_MAX ? 0 : be->delay_before_retry; + long_ret.u = rs->delay_before_retry == ULONG_MAX ? 0 : rs->delay_before_retry; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSWARMUPUSEC: - long_ret.u = be->warmup == ULONG_MAX ? 0 : be->warmup; + long_ret.u = rs->warmup == ULONG_MAX ? 0 : rs->warmup; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSDELAYLOOPUSEC: - long_ret.u = be->delay_loop == ULONG_MAX ? 0 : be->delay_loop; + long_ret.u = rs->delay_loop == ULONG_MAX ? 0 : rs->delay_loop; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSCONNTIMEOUTUSEC: - long_ret.u = be->connection_to; + long_ret.u = rs->connection_to; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_RSTUNNELTYPE: - if (be->forwarding_method != IP_VS_CONN_F_TUNNEL) + if (rs->forwarding_method != IP_VS_CONN_F_TUNNEL) break; #ifndef _HAVE_IPVS_TUN_TYPE_ long_ret.u = 1; /* IPIP */ #else - long_ret.u = be->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP ? 1 - : be->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE ? 2 + long_ret.u = rs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP ? 1 + : rs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE ? 2 #ifdef _HAVE_IPVS_TUN_GRE_ - : be->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE ? 3 + : rs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE ? 3 #endif : 0; #endif return PTR_CAST(u_char, &long_ret); #ifdef _HAVE_IPVS_TUN_TYPE_ case CHECK_SNMP_RSTUNNELPORT: - if (be->forwarding_method != IP_VS_CONN_F_TUNNEL || - be->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_GUE) + if (rs->forwarding_method != IP_VS_CONN_F_TUNNEL || + rs->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_GUE) break; - long_ret.u = ntohs(be->tun_port); + long_ret.u = ntohs(rs->tun_port); return PTR_CAST(u_char, &long_ret); #ifdef _HAVE_IPVS_TUN_CSUM_ case CHECK_SNMP_RSTUNNELCSUM: - if (be->forwarding_method != IP_VS_CONN_F_TUNNEL || - be->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP) + if (rs->forwarding_method != IP_VS_CONN_F_TUNNEL || + rs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP) break; - long_ret.u = be->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM ? 1 - : be->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_CSUM ? 2 - : be->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM ? 3 + long_ret.u = rs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM ? 1 + : rs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_CSUM ? 2 + : rs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM ? 3 : 0; return PTR_CAST(u_char, &long_ret); #endif #endif case CHECK_SNMP_RSNAME: - if (!be->snmp_name) break; - *var_len = strlen(be->snmp_name); - ret.cp = be->snmp_name; + if (!rs->snmp_name) break; + *var_len = strlen(rs->snmp_name); + ret.cp = rs->snmp_name; return ret.p; case CHECK_SNMP_RSNOTIFYUPPATH: if (type == STATE_RS_SORRY) break; - if (!be->notify_up) break; - ret.cp = be->notify_up->path ? be->notify_up->path : be->notify_up->args[0]; + if (!rs->notify_up) break; + ret.cp = rs->notify_up->path ? rs->notify_up->path : rs->notify_up->args[0]; *var_len = strlen(ret.cp); return ret.p; case CHECK_SNMP_RSNOTIFYDOWNPATH: if (type == STATE_RS_SORRY) break; - if (!be->notify_down) break; - ret.cp = be->notify_down->path ? be->notify_down->path : be->notify_down->args[0]; + if (!rs->notify_down) break; + ret.cp = rs->notify_down->path ? rs->notify_down->path : rs->notify_down->args[0]; *var_len = strlen(ret.cp); return ret.p; #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_RSRATECPS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.cps & 0xffffffff; - counter64_ret.high = be->stats.cps >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.cps & 0xffffffff; + counter64_ret.high = rs->stats.cps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEINPPS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.inpps & 0xffffffff; - counter64_ret.high = be->stats.inpps >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.inpps & 0xffffffff; + counter64_ret.high = rs->stats.inpps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEOUTPPS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.outpps & 0xffffffff; - counter64_ret.high = be->stats.outpps >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.outpps & 0xffffffff; + counter64_ret.high = rs->stats.outpps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEINBPS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.inbps & 0xffffffff; - counter64_ret.high = be->stats.inbps >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.inbps & 0xffffffff; + counter64_ret.high = rs->stats.inbps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_RSRATEOUTBPS64: - ipvs_rs_update_stats(bvs); - counter64_ret.low = be->stats.outbps & 0xffffffff; - counter64_ret.high = be->stats.outbps >> 32; + ipvs_rs_update_stats(vs); + counter64_ret.low = rs->stats.outbps & 0xffffffff; + counter64_ret.high = rs->stats.outbps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); #endif From 254513a1da5dd8927591baeba63fa14dbdd0f611 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:32:00 +0100 Subject: [PATCH 21/24] ipvs: Streamline finding VS for SNMP Signed-off-by: Quentin Armitage --- keepalived/check/check_snmp.c | 323 +++++++++++++++++----------------- 1 file changed, 162 insertions(+), 161 deletions(-) diff --git a/keepalived/check/check_snmp.c b/keepalived/check/check_snmp.c index dff5d98ec8..90a87f8fc4 100644 --- a/keepalived/check/check_snmp.c +++ b/keepalived/check/check_snmp.c @@ -415,7 +415,7 @@ static u_char * check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { - virtual_server_t *v; + virtual_server_t *vs; real_server_t *rs; snmp_ret_t ret; list_head_t *e; @@ -425,78 +425,78 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, &check_data->vs)) == NULL) return NULL; - v = list_entry(e, virtual_server_t, e_list); + vs = list_entry(e, virtual_server_t, e_list); switch (vp->magic) { case CHECK_SNMP_VSTYPE: - if (v->vsg) + if (vs->vsg) long_ret.u = 3; - else if (v->vfwmark) + else if (vs->vfwmark) long_ret.u = 1; else long_ret.u = 2; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSNAMEGROUP: - if (!v->vsg) break; - ret.cp = v->vsgname; + if (!vs->vsg) break; + ret.cp = vs->vsgname; *var_len = strlen(ret.cp); return ret.p; case CHECK_SNMP_VSFWMARK: - if (!v->vfwmark) break; - long_ret.u = v->vfwmark; + if (!vs->vfwmark) break; + long_ret.u = vs->vfwmark; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSADDRTYPE: - long_ret.u = SNMP_InetAddressType(v->af); + long_ret.u = SNMP_InetAddressType(vs->af); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSADDRESS: - if (v->vfwmark || v->vsg) break; - RETURN_IP46ADDRESS(v); + if (vs->vfwmark || vs->vsg) break; + RETURN_IP46ADDRESS(vs); break; case CHECK_SNMP_VSPORT: - if (v->vfwmark || v->vsg) break; - long_ret.u = htons(inet_sockaddrport(&v->addr)); + if (vs->vfwmark || vs->vsg) break; + long_ret.u = htons(inet_sockaddrport(&vs->addr)); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSPROTOCOL: - if (v->vfwmark) break; - long_ret.u = (v->service_type == IPPROTO_TCP) ? 1 : - (v->service_type == IPPROTO_UDP) ? 2 : - (v->service_type == IPPROTO_SCTP) ? 3 : 4; + if (vs->vfwmark) break; + long_ret.u = (vs->service_type == IPPROTO_TCP) ? 1 : + (vs->service_type == IPPROTO_UDP) ? 2 : + (vs->service_type == IPPROTO_SCTP) ? 3 : 4; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSLOADBALANCINGALGO: - if (!strcmp(v->sched, "rr")) + if (!strcmp(vs->sched, "rr")) long_ret.u = 1; - else if (!strcmp(v->sched, "wrr")) + else if (!strcmp(vs->sched, "wrr")) long_ret.u = 2; - else if (!strcmp(v->sched, "lc")) + else if (!strcmp(vs->sched, "lc")) long_ret.u = 3; - else if (!strcmp(v->sched, "wlc")) + else if (!strcmp(vs->sched, "wlc")) long_ret.u = 4; - else if (!strcmp(v->sched, "lblc")) + else if (!strcmp(vs->sched, "lblc")) long_ret.u = 5; - else if (!strcmp(v->sched, "lblcr")) + else if (!strcmp(vs->sched, "lblcr")) long_ret.u = 6; - else if (!strcmp(v->sched, "dh")) + else if (!strcmp(vs->sched, "dh")) long_ret.u = 7; - else if (!strcmp(v->sched, "sh")) + else if (!strcmp(vs->sched, "sh")) long_ret.u = 8; - else if (!strcmp(v->sched, "sed")) + else if (!strcmp(vs->sched, "sed")) long_ret.u = 9; - else if (!strcmp(v->sched, "nq")) + else if (!strcmp(vs->sched, "nq")) long_ret.u = 10; - else if (!strcmp(v->sched, "fo")) + else if (!strcmp(vs->sched, "fo")) long_ret.u = 11; - else if (!strcmp(v->sched, "ovf")) + else if (!strcmp(vs->sched, "ovf")) long_ret.u = 12; - else if (!strcmp(v->sched, "mh")) + else if (!strcmp(vs->sched, "mh")) long_ret.u = 13; - else if (!strcmp(v->sched, "twos")) + else if (!strcmp(vs->sched, "twos")) long_ret.u = 14; else long_ret.u = 99; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSLOADBALANCINGKIND: long_ret.u = 0; - switch (v->forwarding_method) { + switch (vs->forwarding_method) { case IP_VS_CONN_F_MASQ: long_ret.u = 1; break; @@ -510,303 +510,303 @@ check_snmp_virtualserver(struct variable *vp, oid *name, size_t *length, if (!long_ret.u) break; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATUS: - long_ret.u = SNMP_TruthValue(v->alive); + long_ret.u = SNMP_TruthValue(vs->alive); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSVIRTUALHOST: - if (!v->virtualhost) break; - *var_len = strlen(v->virtualhost); - ret.cp = v->virtualhost; + if (!vs->virtualhost) break; + *var_len = strlen(vs->virtualhost); + ret.cp = vs->virtualhost; return ret.p; case CHECK_SNMP_VSPERSIST: - long_ret.u = SNMP_TruthValue(v->persistence_timeout); + long_ret.u = SNMP_TruthValue(vs->persistence_timeout); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSPERSISTTIMEOUT: - if (!v->persistence_timeout) break; - long_ret.u = v->persistence_timeout; + if (!vs->persistence_timeout) break; + long_ret.u = vs->persistence_timeout; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSPERSISTGRANULARITY: - if (v->addr.ss_family == AF_INET6) break; - *var_len = sizeof(v->persistence_granularity); - return PTR_CAST(u_char, &v->persistence_granularity); + if (vs->addr.ss_family == AF_INET6) break; + *var_len = sizeof(vs->persistence_granularity); + return PTR_CAST(u_char, &vs->persistence_granularity); case CHECK_SNMP_VSPERSISTGRANULARITY6: - if (v->addr.ss_family == AF_INET) break; - *var_len = sizeof(v->persistence_granularity); - return PTR_CAST(u_char, &v->persistence_granularity); + if (vs->addr.ss_family == AF_INET) break; + *var_len = sizeof(vs->persistence_granularity); + return PTR_CAST(u_char, &vs->persistence_granularity); case CHECK_SNMP_VSDELAYLOOP: - long_ret.u = v->delay_loop/TIMER_HZ; + long_ret.u = vs->delay_loop/TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSHASUSPEND: - long_ret.u = SNMP_TruthValue(v->ha_suspend); + long_ret.u = SNMP_TruthValue(vs->ha_suspend); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSOPS: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_ONEPACKET); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_ONEPACKET); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSALPHA: - long_ret.u = SNMP_TruthValue(v->alpha); + long_ret.u = SNMP_TruthValue(vs->alpha); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSOMEGA: - long_ret.u = SNMP_TruthValue(v->omega); + long_ret.u = SNMP_TruthValue(vs->omega); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSQUORUM: - long_ret.u = v->quorum; + long_ret.u = vs->quorum; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSQUORUMSTATUS: - long_ret.u = SNMP_TruthValue(v->quorum_state_up); + long_ret.u = SNMP_TruthValue(vs->quorum_state_up); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSQUORUMUP: - if (!v->notify_quorum_up) break; - cmd_str_r(v->notify_quorum_up, buf, sizeof(buf)); + if (!vs->notify_quorum_up) break; + cmd_str_r(vs->notify_quorum_up, buf, sizeof(buf)); *var_len = strlen(buf); return PTR_CAST(u_char, buf); case CHECK_SNMP_VSQUORUMDOWN: - if (!v->notify_quorum_down) break; - cmd_str_r(v->notify_quorum_down, buf, sizeof(buf)); + if (!vs->notify_quorum_down) break; + cmd_str_r(vs->notify_quorum_down, buf, sizeof(buf)); *var_len = strlen(buf); return PTR_CAST(u_char, buf); case CHECK_SNMP_VSHYSTERESIS: - long_ret.u = v->hysteresis; + long_ret.u = vs->hysteresis; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSREALTOTAL: - long_ret.u = v->rs_cnt; + long_ret.u = vs->rs_cnt; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSREALUP: long_ret.u = 0; - list_for_each_entry(rs, &v->rs, e_list) + list_for_each_entry(rs, &vs->rs, e_list) if (rs->alive) long_ret.u++; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSCONNS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.conns; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.conns; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSINPKTS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inpkts; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSOUTPKTS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outpkts; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outpkts; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSTATSINBYTES: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.inbytes & 0xffffffff; - counter64_ret.high = v->stats.inbytes >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.inbytes & 0xffffffff; + counter64_ret.high = vs->stats.inbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSOUTBYTES: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.outbytes & 0xffffffff; - counter64_ret.high = v->stats.outbytes >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.outbytes & 0xffffffff; + counter64_ret.high = vs->stats.outbytes >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATECPS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.cps; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.cps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inpps; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outpps; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outpps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inbps; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inbps; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPS: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outbps; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outbps; return PTR_CAST(u_char, &long_ret); #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_VSSTATSCONNS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.conns & 0xffffffff; - counter64_ret.high = v->stats.conns >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.conns & 0xffffffff; + counter64_ret.high = vs->stats.conns >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSINPKTS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.inpkts & 0xffffffff; - counter64_ret.high = v->stats.inpkts >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.inpkts & 0xffffffff; + counter64_ret.high = vs->stats.inpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSSTATSOUTPKTS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.outpkts & 0xffffffff; - counter64_ret.high = v->stats.outpkts >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.outpkts & 0xffffffff; + counter64_ret.high = vs->stats.outpkts >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); /* See below for VSRATECPS64 etc 64 bit counters for rates */ case CHECK_SNMP_VSRATECPSLOW: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.cps & 0xffffffff; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.cps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATECPSHIGH: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.cps >> 32; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.cps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPSLOW: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inpps & 0xffffffff; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inpps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINPPSHIGH: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inpps >> 32; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPSLOW: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outpps & 0xffffffff; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outpps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTPPSHIGH: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outpps >> 32; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outpps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPSLOW: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inbps & 0xffffffff; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inbps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEINBPSHIGH: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.inbps >> 32; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.inbps >> 32; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPSLOW: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outbps & 0xffffffff; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outbps & 0xffffffff; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRATEOUTBPSHIGH: - ipvs_vs_update_stats(v); - long_ret.u = v->stats.outbps >> 32; + ipvs_vs_update_stats(vs); + long_ret.u = vs->stats.outbps >> 32; return PTR_CAST(u_char, &long_ret); #endif #ifdef IP_VS_SVC_F_SCHED1 case CHECK_SNMP_VSHASHED: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_HASHED); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_HASHED); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSHFALLBACK: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_SCHED_SH_FALLBACK); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_SCHED_SH_FALLBACK); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSHPORT: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_SCHED_SH_PORT); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_SCHED_SH_PORT); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSMHFALLBACK: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_SCHED_MH_FALLBACK); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_SCHED_MH_FALLBACK); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSMHPORT: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_SCHED_MH_PORT); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_SCHED_MH_PORT); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSCHED3: - long_ret.u = SNMP_TruthValue(v->flags & IP_VS_SVC_F_SCHED3); + long_ret.u = SNMP_TruthValue(vs->flags & IP_VS_SVC_F_SCHED3); return PTR_CAST(u_char, &long_ret); #endif case CHECK_SNMP_VSACTIONWHENDOWN: - long_ret.u = SNMP_TruthValue(!v->inhibit); + long_ret.u = SNMP_TruthValue(!vs->inhibit); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSRETRY: - long_ret.u = v->retry == UINT_MAX ? 0 : v->retry; + long_ret.u = vs->retry == UINT_MAX ? 0 : vs->retry; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSDELAYBEFORERETRY: - long_ret.u = v->delay_before_retry == ULONG_MAX ? 0 : v->delay_before_retry / TIMER_HZ; + long_ret.u = vs->delay_before_retry == ULONG_MAX ? 0 : vs->delay_before_retry / TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSWARMUP: - long_ret.u = v->warmup == ULONG_MAX ? 0 : v->warmup / TIMER_HZ; + long_ret.u = vs->warmup == ULONG_MAX ? 0 : vs->warmup / TIMER_HZ; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSWEIGHT: - long_ret.s = v->weight; + long_ret.s = vs->weight; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSSMTPALERT: - long_ret.u = SNMP_TruthValue(v->smtp_alert); + long_ret.u = SNMP_TruthValue(vs->smtp_alert); return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSDELAYLOOPUSEC: - long_ret.u = v->delay_loop; + long_ret.u = vs->delay_loop; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSDELAYBEFORERETRYUSEC: - long_ret.u = v->delay_before_retry == ULONG_MAX ? 0 : v->delay_before_retry; + long_ret.u = vs->delay_before_retry == ULONG_MAX ? 0 : vs->delay_before_retry; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSWARMUPUSEC: - long_ret.u = v->warmup == ULONG_MAX ? 0 : v->warmup; + long_ret.u = vs->warmup == ULONG_MAX ? 0 : vs->warmup; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSCONNTIMEOUTUSEC: - long_ret.u = v->connection_to; + long_ret.u = vs->connection_to; return PTR_CAST(u_char, &long_ret); case CHECK_SNMP_VSTUNNELTYPE: - if (v->forwarding_method != IP_VS_CONN_F_TUNNEL) + if (vs->forwarding_method != IP_VS_CONN_F_TUNNEL) break; #ifndef _HAVE_IPVS_TUN_TYPE_ long_ret.u = 1; /* IPIP */ #else - long_ret.u = v->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP ? 1 - : v->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE ? 2 + long_ret.u = vs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP ? 1 + : vs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE ? 2 #ifdef _HAVE_IPVS_TUN_GRE_ - : v->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE ? 3 + : vs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GRE ? 3 #endif : 0; #endif return PTR_CAST(u_char, &long_ret); #ifdef _HAVE_IPVS_TUN_TYPE_ case CHECK_SNMP_VSTUNNELPORT: - if (v->forwarding_method != IP_VS_CONN_F_TUNNEL || - v->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_GUE) + if (vs->forwarding_method != IP_VS_CONN_F_TUNNEL || + vs->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_GUE) break; - long_ret.u = ntohs(v->tun_port); + long_ret.u = ntohs(vs->tun_port); return PTR_CAST(u_char, &long_ret); #ifdef _HAVE_IPVS_TUN_CSUM_ case CHECK_SNMP_VSTUNNELCSUM: - if (v->forwarding_method != IP_VS_CONN_F_TUNNEL || - v->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP) + if (vs->forwarding_method != IP_VS_CONN_F_TUNNEL || + vs->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_IPIP) break; - long_ret.u = v->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM ? 1 - : v->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_CSUM ? 2 - : v->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM ? 3 + long_ret.u = vs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM ? 1 + : vs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_CSUM ? 2 + : vs->tun_flags == IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM ? 3 : 0; return PTR_CAST(u_char, &long_ret); #endif #endif case CHECK_SNMP_VSNAME: - if (!v->snmp_name) break; - *var_len = strlen(v->snmp_name); - ret.cp = v->snmp_name; + if (!vs->snmp_name) break; + *var_len = strlen(vs->snmp_name); + ret.cp = vs->snmp_name; return ret.p; case CHECK_SNMP_VSQUORUMUPPATH: - if (!v->notify_quorum_up) break; - ret.cp = v->notify_quorum_up->path ? v->notify_quorum_up->path : v->notify_quorum_up->args[0] ; + if (!vs->notify_quorum_up) break; + ret.cp = vs->notify_quorum_up->path ? vs->notify_quorum_up->path : vs->notify_quorum_up->args[0] ; *var_len = strlen(ret.cp); return ret.p; case CHECK_SNMP_VSQUORUMDOWNPATH: - if (!v->notify_quorum_down) break; - ret.cp = v->notify_quorum_down->path ? v->notify_quorum_down->path : v->notify_quorum_down->args[0]; + if (!vs->notify_quorum_down) break; + ret.cp = vs->notify_quorum_down->path ? vs->notify_quorum_down->path : vs->notify_quorum_down->args[0]; *var_len = strlen(ret.cp); return ret.p; #ifdef _WITH_LVS_64BIT_STATS_ case CHECK_SNMP_VSRATECPS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.cps & 0xffffffff; - counter64_ret.high = v->stats.cps >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.cps & 0xffffffff; + counter64_ret.high = vs->stats.cps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEINPPS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.inpps & 0xffffffff; - counter64_ret.high = v->stats.inpps >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.inpps & 0xffffffff; + counter64_ret.high = vs->stats.inpps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEOUTPPS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.outpps & 0xffffffff; - counter64_ret.high = v->stats.outpps >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.outpps & 0xffffffff; + counter64_ret.high = vs->stats.outpps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEINBPS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.inbps & 0xffffffff; - counter64_ret.high = v->stats.inbps >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.inbps & 0xffffffff; + counter64_ret.high = vs->stats.inbps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); case CHECK_SNMP_VSRATEOUTBPS64: - ipvs_vs_update_stats(v); - counter64_ret.low = v->stats.outbps & 0xffffffff; - counter64_ret.high = v->stats.outbps >> 32; + ipvs_vs_update_stats(vs); + counter64_ret.low = vs->stats.outbps & 0xffffffff; + counter64_ret.high = vs->stats.outbps >> 32; *var_len = sizeof(struct counter64); return PTR_CAST(u_char, &counter64_ret); #endif @@ -878,7 +878,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { oid *target; - oid current[2] = { 0 };; + oid current[2] = { 0 }; int result; size_t target_len; real_server_t *rs; @@ -906,6 +906,7 @@ check_snmp_realserver(struct variable *vp, oid *name, size_t *length, list_for_each_entry(vs, &check_data->vs, e_list) { current[0]++; + current[1] = 0; if (target_len && (current[0] < target[0])) continue; /* Optimization: cannot be part of our set */ state = vs->s_svr ? STATE_RS_SORRY : STATE_RS_REGULAR_FIRST; From 35195dcf860400067cbb761b344eb934b8c37870 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:32:28 +0100 Subject: [PATCH 22/24] ipvs: don't duplicate ipvs_getinfo() functionality Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index a2a51c41c7..7dfa2419d2 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -406,9 +406,6 @@ static int ipvs_getinfo(void) int ipvs_init(void) { - socklen_t len; - struct ip_vs_getinfo ipvs_info; - ipvs_func = ipvs_init; #ifdef LIBIPVS_USE_NL @@ -430,8 +427,7 @@ int ipvs_init(void) if (sockfd == -1) return -1; - len = sizeof(ipvs_info); - if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len)) { + if (ipvs_getinfo()) { close(sockfd); sockfd = -1; return -1; From 2e165dfc17a776610b1c1c82454a7bbdb9f823ae Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:33:12 +0100 Subject: [PATCH 23/24] ipvs: set var_len = 0 when returning an error to SNMP The net-snmp code does this in header_simple_table(), so we should do so when using a non-simple table. Signed-off-by: Quentin Armitage --- keepalived/core/snmp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/keepalived/core/snmp.c b/keepalived/core/snmp.c index b750e1e26e..86572c43d2 100644 --- a/keepalived/core/snmp.c +++ b/keepalived/core/snmp.c @@ -73,8 +73,15 @@ snmp_header_list_head_table(struct variable *vp, oid *name, size_t *length, if (header_simple_table(vp, name, length, exact, var_len, write_method, -1) != MATCH_SUCCEEDED) return NULL; - if (list_empty(l)) + /* header_simple_table sets *var_len = 0 on error. On success it sets + *var_len = sizeof(long), and *write_method = NULL. + If we reach here, the success values will have been written. */ + + if (list_empty(l)) { + if (var_len) + *var_len = 0; return NULL; + } target = name[*length - 1]; @@ -85,9 +92,12 @@ snmp_header_list_head_table(struct variable *vp, oid *name, size_t *length, if (current == target) /* Exact match */ return e; - if (exact) + if (exact) { /* No exact match found */ + if (var_len) + *var_len = 0; return NULL; + } /* current is the best match */ name[*length - 1] = current; return e; @@ -95,6 +105,9 @@ snmp_header_list_head_table(struct variable *vp, oid *name, size_t *length, /* There are insufficent entries in the list or no match * at the end then just return no match */ + if (var_len) + *var_len = 0; + return NULL; } From 5a85decc82fe4f0baab1c867fefd40c55dce5e27 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 28 Apr 2024 23:43:54 +0100 Subject: [PATCH 24/24] ipvs: fix building with SNMP support without using netlink interface Signed-off-by: Quentin Armitage --- keepalived/check/libipvs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c index 7dfa2419d2..f3ae74e8c0 100644 --- a/keepalived/check/libipvs.c +++ b/keepalived/check/libipvs.c @@ -383,6 +383,7 @@ static int ipvs_getinfo_parse_cb(struct nl_msg *msg, __attribute__((unused)) voi return NL_OK; } +#endif static int ipvs_getinfo(void) { @@ -391,6 +392,7 @@ static int ipvs_getinfo(void) ipvs_func = ipvs_getinfo; +#ifdef LIBIPVS_USE_NL if (try_nl) { struct nl_msg *msg; if (!(msg = ipvs_nl_message(IPVS_CMD_GET_INFO, 0))) @@ -398,11 +400,11 @@ static int ipvs_getinfo(void) return ipvs_nl_send_message(msg, ipvs_getinfo_parse_cb, NULL); } +#endif len = sizeof(ipvs_info); return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len); } -#endif int ipvs_init(void) {