aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-10-07 16:10:10 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2011-10-07 16:10:10 +0200
commit2b4edba3ad8431f8bd8b7218e9f8a5a5e4ee18ac (patch)
tree6561f793b675ae209e6936d8bf9f25f5749df9d1
parentf8b192af8b6611c3832df3024cbabaafffb47591 (diff)
downloadpingu-2b4edba3ad8431f8bd8b7218e9f8a5a5e4ee18ac.tar.bz2
pingu-2b4edba3ad8431f8bd8b7218e9f8a5a5e4ee18ac.tar.xz
pingu_iface: support binding multiple ping hosts to same iface
Add config option for executing actions when interface gateway goes up/down. Add config option for required hosts up per interface (defaults to 1)
-rw-r--r--pingu_conf.c8
-rw-r--r--pingu_host.c46
-rw-r--r--pingu_host.h3
-rw-r--r--pingu_iface.c36
-rw-r--r--pingu_iface.h9
-rw-r--r--pingu_netlink.c4
6 files changed, 78 insertions, 28 deletions
diff --git a/pingu_conf.c b/pingu_conf.c
index 30dec9a..ad433e8 100644
--- a/pingu_conf.c
+++ b/pingu_conf.c
@@ -130,6 +130,14 @@ static int pingu_conf_read_iface(struct pingu_conf *conf, char *ifname)
break;
if (strcmp(key, "route-table") == 0) {
pingu_iface_set_route_table(iface, atoi(value));
+ } else if (strcmp(key, "label") == 0) {
+ iface->label = xstrdup(value);
+ } else if (strcmp(key, "gateway-up-action") == 0) {
+ iface->gw_up_action = xstrdup(value);
+ } else if (strcmp(key, "gateway-down-action") == 0) {
+ iface->gw_down_action = xstrdup(value);
+ } else if (strcmp(key, "required-hosts-online") == 0) {
+ iface->required_hosts_online = atoi(value);
} else if (strcmp(key, "load-balance") == 0) {
int weight = 0;
if (value != NULL) {
diff --git a/pingu_host.c b/pingu_host.c
index a86007f..ca09788 100644
--- a/pingu_host.c
+++ b/pingu_host.c
@@ -18,10 +18,15 @@
static struct list_head host_list = LIST_INITIALIZER(host_list);
-static void execute_action(const char *action)
+void execute_action(const char *action)
{
pid_t pid;
- const char *shell = getenv("SHELL");
+ const char *shell;
+
+ if (action == NULL)
+ return;
+
+ shell = getenv("SHELL");
if (shell == NULL)
shell = "/bin/sh";
@@ -41,7 +46,7 @@ static void execute_action(const char *action)
int pingu_host_set_status(struct pingu_host *host, int status)
{
const char *action;
- int route_action = 0;
+ int adjustment;
host->burst.active = 0;
if (host->status == status) {
log_debug("%s: status is still %i", host->label, status);
@@ -50,18 +55,18 @@ int pingu_host_set_status(struct pingu_host *host, int status)
host->status = status;
log_info("%s: new status: %i", host->label, status);
switch (host->status) {
- case 0:
+ case PINGU_HOST_STATUS_OFFLINE:
action = host->down_action;
- route_action = RTM_DELROUTE;
+ adjustment = -1;
break;
- case 1:
+ case PINGU_HOST_STATUS_ONLINE:
action = host->up_action;
- route_action = RTM_NEWROUTE;
+ adjustment = 1;
break;
}
- if (action != NULL)
- execute_action(action);
- pingu_iface_update_routes(host->iface, route_action);
+
+ execute_action(action);
+ pingu_iface_adjust_hosts_online(host->iface, adjustment);
return status;
}
@@ -78,17 +83,17 @@ int pingu_host_verify_status(struct ev_loop *loop, struct pingu_host *host)
struct pingu_host *pingu_host_new(char *hoststr, float burst_interval,
int max_retries, int required_replies,
- float timeout,
+ float timeout,
const char *up_action,
const char *down_action)
{
struct pingu_host *host = calloc(1, sizeof(struct pingu_host));
-
+
if (host == NULL) {
log_perror(hoststr);
return NULL;
}
-
+
host->host = hoststr;
host->status = PINGU_HOST_DEFAULT_STATUS;
host->burst_interval = burst_interval;
@@ -97,20 +102,11 @@ struct pingu_host *pingu_host_new(char *hoststr, float burst_interval,
host->timeout = timeout;
host->up_action = up_action;
host->down_action = down_action;
-
+
list_add(&host->host_list_entry, &host_list);
return host;
}
-struct pingu_host *pingu_host_find_by_iface(struct pingu_iface *iface)
-{
- struct pingu_host *host;
- list_for_each_entry(host, &host_list, host_list_entry)
- if (host->iface == iface)
- return host;
- return NULL;
-}
-
void pingu_host_dump_status(int fd)
{
struct pingu_host *host;
@@ -131,6 +127,10 @@ int pingu_host_init(struct ev_loop *loop)
ev_timer_init(&host->burst_timeout_watcher,
pingu_burst_timeout_cb, 0, host->burst_interval);
ev_timer_start(loop, &host->burst_timeout_watcher);
+
+ if (host->iface->required_hosts_online == 0)
+ host->iface->required_hosts_online = 1;
+ host->iface->hosts_online += PINGU_HOST_DEFAULT_STATUS;
}
return 0;
}
diff --git a/pingu_host.h b/pingu_host.h
index b5f6e48..a7a879d 100644
--- a/pingu_host.h
+++ b/pingu_host.h
@@ -28,12 +28,13 @@ struct pingu_host {
struct pingu_iface *iface;
};
+void execute_action(const char *action);
+
struct pingu_host *pingu_host_new(char *hoststr, float burst_interval,
int max_retries, int required_replies,
float timeout,
const char *up_action,
const char *down_action);
-struct pingu_host *pingu_host_find_by_iface(struct pingu_iface *iface);
int pingu_host_set_status(struct pingu_host *host, int status);
int pingu_host_init(struct ev_loop *loop);
int pingu_host_verify_status(struct ev_loop *loop, struct pingu_host *host);
diff --git a/pingu_iface.c b/pingu_iface.c
index 5ae0317..820546d 100644
--- a/pingu_iface.c
+++ b/pingu_iface.c
@@ -145,7 +145,7 @@ void pingu_iface_set_balance(struct pingu_iface *iface, int balance_weight)
iface->balance = 1;
iface->balance_weight = balance_weight;
}
-
+
#if 0
void pingu_route_dump(struct pingu_iface *iface)
{
@@ -187,6 +187,40 @@ void pingu_iface_update_routes(struct pingu_iface *iface, int action)
kernel_route_multipath(RTM_NEWROUTE, &iface_list, RT_TABLE_MAIN);
}
+int pingu_iface_gw_is_online(struct pingu_iface *iface)
+{
+ return iface->hosts_online >= iface->required_hosts_online;
+}
+
+/* check if we should bring up/down this ISP */
+void pingu_iface_adjust_hosts_online(struct pingu_iface *iface, int adjustment)
+{
+ int old_status, new_status, route_action;
+ char *action, *statusstr;
+
+ old_status = pingu_iface_gw_is_online(iface);
+ iface->hosts_online += adjustment;
+ new_status = pingu_iface_gw_is_online(iface);
+
+ if (old_status == new_status)
+ return;
+
+ if (new_status) {
+ statusstr = "ONLINE";
+ route_action = RTM_NEWROUTE;
+ action = iface->gw_up_action;
+ } else {
+ statusstr = "OFFLINE";
+ route_action = RTM_DELROUTE;
+ action = iface->gw_down_action;
+ }
+
+ log_info("%s: went %s", iface->label ? iface->label : iface->name,
+ statusstr);
+ pingu_iface_update_routes(iface, route_action);
+ execute_action(action);
+}
+
int pingu_iface_set_route_table(struct pingu_iface *iface, int table)
{
static int initialized = 0;
diff --git a/pingu_iface.h b/pingu_iface.h
index 14f8ba5..e6c8b24 100644
--- a/pingu_iface.h
+++ b/pingu_iface.h
@@ -12,6 +12,12 @@
struct pingu_iface {
char name[32];
+ char *label;
+ char *gw_up_action;
+ char *gw_down_action;
+ int hosts_online;
+ int required_hosts_online;
+
int index;
int has_link;
int has_address;
@@ -39,7 +45,10 @@ int pingu_iface_init(struct ev_loop *loop);
void pingu_iface_set_balance(struct pingu_iface *iface, int balance_weight);
void pingu_iface_set_addr(struct pingu_iface *iface, int family,
void *data, int len);
+void pingu_iface_adjust_hosts_online(struct pingu_iface *iface, int adjustment);
int pingu_iface_set_route_table(struct pingu_iface *iface, int table);
+
+int pingu_iface_gw_is_online(struct pingu_iface *iface);
void pingu_iface_gw_action(struct pingu_iface *iface,
struct pingu_route *gw, int action);
void pingu_iface_update_routes(struct pingu_iface *iface, int action);
diff --git a/pingu_netlink.c b/pingu_netlink.c
index 212e8e9..b5e2dd7 100644
--- a/pingu_netlink.c
+++ b/pingu_netlink.c
@@ -360,7 +360,6 @@ static int add_nexthops(struct nlmsghdr *nlh, size_t nlh_size,
struct rtnexthop *rtnh;
struct pingu_iface *iface;
struct pingu_route *route;
- struct pingu_host *host;
int count = 0;
memset(buf, 0, sizeof(buf));
@@ -372,9 +371,8 @@ static int add_nexthops(struct nlmsghdr *nlh, size_t nlh_size,
route = pingu_route_first_default(&iface->route_list);
switch (action_type) {
case RTM_NEWROUTE:
- host = pingu_host_find_by_iface(iface);
if ((!iface->balance) || iface->index == 0
- || (host != NULL && host->status == PINGU_HOST_STATUS_OFFLINE)
+ || !pingu_iface_gw_is_online(iface)
|| route == NULL) {
iface->has_multipath = 0;
continue;