mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-11 05:48:41 +00:00
MINOR: server/event_hdl: add SERVER_INETADDR event
In this patch we add the support for a new SERVER event in the event_hdl API. SERVER_INETADDR is implemented as an advanced server event. It is published each time the server's ip address or port is about to change. (ie: from the cli, dns, lua...) SERVER_INETADDR data is an event_hdl_cb_data_server_inetaddr struct that provides additional info related to the server inet addr change, but can be casted as a regular event_hdl_cb_data_server struct if additional info is not needed.
This commit is contained in:
parent
0e1f389fe9
commit
683b2ae013
@ -274,6 +274,8 @@ struct event_hdl_sub {
|
||||
#define EVENT_HDL_SUB_SERVER_ADMIN EVENT_HDL_SUB_TYPE(1,6)
|
||||
/* server check-related (agent or health) event */
|
||||
#define EVENT_HDL_SUB_SERVER_CHECK EVENT_HDL_SUB_TYPE(1,7)
|
||||
/* server inet addr (addr:svc_port tuple) change event */
|
||||
#define EVENT_HDL_SUB_SERVER_INETADDR EVENT_HDL_SUB_TYPE(1,8)
|
||||
|
||||
/* --------------------------------------- */
|
||||
|
||||
|
@ -477,6 +477,7 @@ struct event_hdl_cb_data_server {
|
||||
* EVENT_HDL_SUB_SERVER_STATE
|
||||
* EVENT_HDL_SUB_SERVER_ADMIN
|
||||
* EVENT_HDL_SUB_SERVER_CHECK
|
||||
* EVENT_HDL_SUB_SERVER_INETADDR
|
||||
*/
|
||||
struct {
|
||||
/* safe data can be safely used from both
|
||||
@ -596,6 +597,39 @@ struct event_hdl_cb_data_server_check {
|
||||
} unsafe;
|
||||
};
|
||||
|
||||
/* data provided to EVENT_HDL_SUB_SERVER_INETADDR handlers through
|
||||
* event_hdl facility
|
||||
*
|
||||
* Note that this may be casted to regular event_hdl_cb_data_server if
|
||||
* you don't care about inetaddr related optional info
|
||||
*/
|
||||
struct event_hdl_cb_data_server_inetaddr {
|
||||
/* provided by:
|
||||
* EVENT_HDL_SUB_SERVER_INETADDR
|
||||
*/
|
||||
struct event_hdl_cb_data_server server; /* must be at the beginning */
|
||||
struct {
|
||||
struct {
|
||||
int family; /* AF_INET or AF_INET6 */
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} addr; /* may hold v4 or v6 addr */
|
||||
unsigned int svc_port;
|
||||
} prev;
|
||||
struct {
|
||||
int family; /* AF_INET or AF_INET6 */
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} addr; /* may hold v4 or v6 addr */
|
||||
unsigned int svc_port;
|
||||
} next;
|
||||
uint8_t purge_conn; /* set to 1 if the network change will force a connection cleanup */
|
||||
} safe;
|
||||
/* no unsafe data */
|
||||
};
|
||||
|
||||
/* Storage structure to load server-state lines from a flat file into
|
||||
* an ebtree, for faster processing
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@ static struct event_hdl_sub_type_map event_hdl_sub_type_map[] = {
|
||||
{"SERVER_STATE", EVENT_HDL_SUB_SERVER_STATE},
|
||||
{"SERVER_ADMIN", EVENT_HDL_SUB_SERVER_ADMIN},
|
||||
{"SERVER_CHECK", EVENT_HDL_SUB_SERVER_CHECK},
|
||||
{"SERVER_INETADDR", EVENT_HDL_SUB_SERVER_INETADDR},
|
||||
};
|
||||
|
||||
/* internal types (only used in this file) */
|
||||
|
125
src/server.c
125
src/server.c
@ -234,6 +234,54 @@ void _srv_event_hdl_prepare_state(struct event_hdl_cb_data_server_state *cb_data
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare SERVER_INETADDR event
|
||||
*
|
||||
* This special event will contain extra hints related to the addr change
|
||||
*
|
||||
*/
|
||||
void _srv_event_hdl_prepare_inetaddr(struct event_hdl_cb_data_server_inetaddr *cb_data,
|
||||
struct sockaddr_storage *prev_addr, unsigned int prev_port,
|
||||
struct sockaddr_storage *next_addr, unsigned int next_port,
|
||||
uint8_t purge_conn)
|
||||
{
|
||||
/* only INET families are supported */
|
||||
BUG_ON((prev_addr->ss_family != AF_UNSPEC &&
|
||||
prev_addr->ss_family != AF_INET && prev_addr->ss_family != AF_INET6) ||
|
||||
(next_addr->ss_family != AF_UNSPEC &&
|
||||
next_addr->ss_family != AF_INET && next_addr->ss_family != AF_INET6));
|
||||
|
||||
/* prev */
|
||||
if (prev_addr->ss_family == AF_INET) {
|
||||
cb_data->safe.prev.family = AF_INET;
|
||||
cb_data->safe.prev.addr.v4.s_addr =
|
||||
((struct sockaddr_in *)prev_addr)->sin_addr.s_addr;
|
||||
}
|
||||
else {
|
||||
cb_data->safe.prev.family = AF_INET6;
|
||||
memcpy(&cb_data->safe.prev.addr.v6.s6_addr,
|
||||
((struct sockaddr_in6 *)prev_addr)->sin6_addr.s6_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
}
|
||||
cb_data->safe.prev.svc_port = prev_port;
|
||||
|
||||
/* next */
|
||||
if (next_addr->ss_family == AF_INET) {
|
||||
cb_data->safe.next.family = AF_INET;
|
||||
cb_data->safe.next.addr.v4.s_addr =
|
||||
((struct sockaddr_in *)next_addr)->sin_addr.s_addr;
|
||||
}
|
||||
else {
|
||||
cb_data->safe.next.family = AF_INET6;
|
||||
memcpy(&cb_data->safe.next.addr.v6.s6_addr,
|
||||
((struct sockaddr_in6 *)next_addr)->sin6_addr.s6_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
}
|
||||
|
||||
cb_data->safe.next.svc_port = next_port;
|
||||
|
||||
cb_data->safe.purge_conn = purge_conn;
|
||||
}
|
||||
|
||||
/* server event publishing helper: publish in both global and
|
||||
* server dedicated subscription list.
|
||||
*/
|
||||
@ -3465,6 +3513,12 @@ struct server *server_find_best_match(struct proxy *bk, char *name, int id, int
|
||||
*/
|
||||
int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
|
||||
{
|
||||
union {
|
||||
struct event_hdl_cb_data_server_inetaddr addr;
|
||||
struct event_hdl_cb_data_server common;
|
||||
} cb_data;
|
||||
struct sockaddr_storage new_addr;
|
||||
|
||||
/* save the new IP family & address if necessary */
|
||||
switch (ip_sin_family) {
|
||||
case AF_INET:
|
||||
@ -3523,16 +3577,25 @@ int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *u
|
||||
}
|
||||
|
||||
/* save the new IP family */
|
||||
s->addr.ss_family = ip_sin_family;
|
||||
new_addr.ss_family = ip_sin_family;
|
||||
/* save the new IP address */
|
||||
switch (ip_sin_family) {
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, ip, 4);
|
||||
memcpy(&((struct sockaddr_in *)&new_addr)->sin_addr.s_addr, ip, 4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, ip, 16);
|
||||
memcpy(((struct sockaddr_in6 *)&new_addr)->sin6_addr.s6_addr, ip, 16);
|
||||
break;
|
||||
};
|
||||
|
||||
_srv_event_hdl_prepare(&cb_data.common, s, 0);
|
||||
_srv_event_hdl_prepare_inetaddr(&cb_data.addr, &s->addr, s->svc_port, &new_addr, s->svc_port, 0);
|
||||
|
||||
/* apply the new IP address */
|
||||
ipcpy(&new_addr, &s->addr);
|
||||
|
||||
_srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_INETADDR, cb_data, s);
|
||||
|
||||
srv_set_dyncookie(s);
|
||||
srv_set_addr_desc(s, 1);
|
||||
|
||||
@ -3659,12 +3722,17 @@ out:
|
||||
*/
|
||||
const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater)
|
||||
{
|
||||
union {
|
||||
struct event_hdl_cb_data_server_inetaddr addr;
|
||||
struct event_hdl_cb_data_server common;
|
||||
} cb_data;
|
||||
struct sockaddr_storage sa;
|
||||
int ret, port_change_required;
|
||||
int ret;
|
||||
char current_addr[INET6_ADDRSTRLEN];
|
||||
uint16_t current_port, new_port;
|
||||
struct buffer *msg;
|
||||
int changed = 0;
|
||||
int ip_change = 0;
|
||||
int port_change = 0;
|
||||
|
||||
msg = get_trash_chunk();
|
||||
chunk_reset(msg);
|
||||
@ -3698,8 +3766,7 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
chunk_appendf(msg, "no need to change the addr");
|
||||
goto port;
|
||||
}
|
||||
ipcpy(&sa, &s->addr);
|
||||
changed = 1;
|
||||
ip_change = 1;
|
||||
|
||||
/* update report for caller */
|
||||
chunk_printf(msg, "IP changed from '%s' to '%s'", current_addr, addr);
|
||||
@ -3716,9 +3783,6 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
/* collecting data currently setup */
|
||||
current_port = s->svc_port;
|
||||
|
||||
/* check if PORT change is required */
|
||||
port_change_required = 0;
|
||||
|
||||
sign = *port;
|
||||
errno = 0;
|
||||
new_port = strtol(port, &endptr, 10);
|
||||
@ -3731,9 +3795,6 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
if (sign == '-' || (sign == '+')) {
|
||||
/* check if server currently uses port map */
|
||||
if (!(s->flags & SRV_F_MAPPORTS)) {
|
||||
/* switch from fixed port to port map mandatorily triggers
|
||||
* a port change */
|
||||
port_change_required = 1;
|
||||
/* check is configured
|
||||
* we're switching from a fixed port to a SRV_F_MAPPORTS (mapped) port
|
||||
* prevent PORT change if check doesn't have it's dedicated port while switching
|
||||
@ -3742,22 +3803,23 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
chunk_appendf(msg, "can't change <port> to port map because it is incompatible with current health check port configuration (use 'port' statement from the 'server' directive.");
|
||||
goto out;
|
||||
}
|
||||
/* switch from fixed port to port map mandatorily triggers
|
||||
* a port change */
|
||||
port_change = 1;
|
||||
}
|
||||
/* we're already using port maps */
|
||||
else {
|
||||
port_change_required = current_port != new_port;
|
||||
port_change = current_port != new_port;
|
||||
}
|
||||
}
|
||||
/* fixed port */
|
||||
else {
|
||||
port_change_required = current_port != new_port;
|
||||
port_change = current_port != new_port;
|
||||
}
|
||||
|
||||
/* applying PORT changes if required and update response message */
|
||||
if (port_change_required) {
|
||||
/* apply new port */
|
||||
s->svc_port = new_port;
|
||||
changed = 1;
|
||||
if (port_change) {
|
||||
uint16_t new_port_print = new_port;
|
||||
|
||||
/* prepare message */
|
||||
chunk_appendf(msg, "port changed from '");
|
||||
@ -3769,7 +3831,7 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
s->flags |= SRV_F_MAPPORTS;
|
||||
chunk_appendf(msg, "%c", sign);
|
||||
/* just use for result output */
|
||||
new_port = -new_port;
|
||||
new_port_print = -new_port_print;
|
||||
}
|
||||
else if (sign == '+') {
|
||||
s->flags |= SRV_F_MAPPORTS;
|
||||
@ -3779,7 +3841,7 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
s->flags &= ~SRV_F_MAPPORTS;
|
||||
}
|
||||
|
||||
chunk_appendf(msg, "%d'", new_port);
|
||||
chunk_appendf(msg, "%d'", new_port_print);
|
||||
}
|
||||
else {
|
||||
chunk_appendf(msg, "no need to change the port");
|
||||
@ -3787,7 +3849,26 @@ const char *srv_update_addr_port(struct server *s, const char *addr, const char
|
||||
}
|
||||
|
||||
out:
|
||||
if (changed) {
|
||||
if (ip_change || port_change) {
|
||||
_srv_event_hdl_prepare(&cb_data.common, s, 0);
|
||||
_srv_event_hdl_prepare_inetaddr(&cb_data.addr, &s->addr, s->svc_port,
|
||||
((ip_change) ? &sa : &s->addr),
|
||||
((port_change) ? new_port : s->svc_port),
|
||||
1);
|
||||
|
||||
if (ip_change) {
|
||||
/* apply new ip */
|
||||
ipcpy(&sa, &s->addr);
|
||||
}
|
||||
|
||||
|
||||
if (port_change) {
|
||||
/* apply new port */
|
||||
s->svc_port = new_port;
|
||||
}
|
||||
|
||||
_srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_INETADDR, cb_data, s);
|
||||
|
||||
/* force connection cleanup on the given server */
|
||||
srv_cleanup_connections(s);
|
||||
srv_set_dyncookie(s);
|
||||
|
Loading…
Reference in New Issue
Block a user