diff --git a/src/config.c b/src/config.c index 2b02467..f5b94d6 100644 --- a/src/config.c +++ b/src/config.c @@ -10,6 +10,7 @@ #include #include "defs.h" +static TAILQ_HEAD(, uvif) cvifs = TAILQ_HEAD_INITIALIZER(cvifs); static TAILQ_HEAD(, uvif) vifs = TAILQ_HEAD_INITIALIZER(vifs); void config_set_ifflag(uint32_t flag) @@ -127,6 +128,22 @@ struct uvif *config_init_tunnel(in_addr_t lcl_addr, in_addr_t rmt_addr, uint32_t return uv; } +/* + * Find index of an already installed vif. + */ +static vifi_t find_vifi(struct uvif *v) +{ + struct uvif *uv; + vifi_t vifi; + + UVIF_FOREACH(vifi, uv) { + if (strcmp(v->uv_name, uv->uv_name) == 0) { + return vifi; + } + } + return NO_VIF; +} + /* * Ignore any kernel interface that is disabled, or connected to the * same subnet as one already installed in the uvifs[] array. @@ -183,6 +200,61 @@ static vifi_t check_vif(struct uvif *v) return vifi; } +static void reload_gone_vifs(void) +{ + struct uvif *uv; + struct uvif *nuv; + + int found; + TAILQ_FOREACH(uv, &cvifs, uv_link) { + found = 0; + TAILQ_FOREACH(nuv, &vifs, uv_link) { + if (uv->uv_ifindex == nuv->uv_ifindex) { + found = 1; + break; + } + } + if (!found) { + vifi_t vifi = find_vifi(uv); + if (vifi == NO_VIF) { + TAILQ_REMOVE(&vifs, uv, uv_link); + free(uv); + continue; + } + stop_vif(vifi); + uninstall_uvif(uv); + } + } +} + +static void reload_new_vifs(void) +{ + struct uvif *uv; + struct uvif *nuv; + + int found; + TAILQ_FOREACH(nuv, &vifs, uv_link) { + found = 0; + TAILQ_FOREACH(uv, &cvifs, uv_link) { + if (uv->uv_ifindex == nuv->uv_ifindex) { + found = 1; + break; + } + } + if (!found) { + vifi_t vifi = check_vif(nuv); + if (vifi == NO_VIF || install_uvif(nuv)) { + TAILQ_REMOVE(&vifs, nuv, uv_link); + free(nuv); + continue; + } + init_installvif(nuv, vifi); + start_vif2(vifi); + } + } +} + + void config_vifs_correlate(void) { struct listaddr *al, *al_tmp; @@ -209,11 +281,19 @@ void config_vifs_correlate(void) vifi, v->uv_rate_limit); } - /* - * XXX: one future extension may be to keep this for adding/removing - * dynamic interfaces at runtime. Now we re-init and let SIGHUP - * rebuild it to recheck since we tear down all vifs anyway. - */ + TAILQ_FIRST(&cvifs) = TAILQ_FIRST(&vifs); + TAILQ_INIT(&vifs); +} + + +void config_vifs_from_reload() +{ + config_vifs_from_kernel(); + reload_gone_vifs(); + reload_new_vifs(); + + TAILQ_INIT(&cvifs); + TAILQ_FIRST(&cvifs) = TAILQ_FIRST(&vifs); TAILQ_INIT(&vifs); } diff --git a/src/defs.h b/src/defs.h index 6b7b6ac..85eb573 100644 --- a/src/defs.h +++ b/src/defs.h @@ -256,6 +256,8 @@ extern int mrt_table_id; extern int debug_list(int, char *, size_t); extern int debug_parse(char *); extern void restart(void); +extern void reload_iface(void); +extern void reload_vifs(void); extern char * scaletime(time_t); extern int register_input_handler(int, ihfunc_t); extern void deregister_input_handler(int); @@ -311,17 +313,21 @@ extern void report_to_all_neighbors(int); extern int report_next_chunk(void); extern void add_vif_to_routes(vifi_t); extern void delete_vif_from_routes(vifi_t); +extern void discard_vif_from_routes(vifi_t); extern void add_neighbor_to_routes(vifi_t, uint32_t); extern void delete_neighbor_from_routes(uint32_t, vifi_t, uint32_t); extern void dump_routes(FILE *, int); /* vif.c */ extern void init_vifs(void); +extern void start_vif2(vifi_t); +extern void stop_vif(vifi_t); extern void blaster_alloc(struct uvif *); extern void blaster_free(struct uvif *); extern void zero_vif(struct uvif *, int); extern void init_installvifs(void); extern int install_uvif(struct uvif *); +extern int uninstall_uvif(struct uvif *); extern void check_vif_state(void); extern void send_on_vif(struct uvif *, uint32_t, int, size_t); extern struct uvif *find_uvif(vifi_t); @@ -357,6 +363,7 @@ extern struct uvif *config_find_ifaddr(in_addr_t addr); extern struct uvif *config_init_tunnel(in_addr_t lcl_addr, in_addr_t rmt_addr, uint32_t flags); extern void config_vifs_correlate(void); extern void config_vifs_from_kernel(void); +extern void config_vifs_from_reload(void); /* cfparse.y */ extern void config_vifs_from_file(void); @@ -452,6 +459,7 @@ extern int pidfile(const char *basename); #define IPC_SHOW_MFC_CMD 21 #define IPC_SHOW_NEIGH_CMD 22 #define IPC_SHOW_ROUTES_CMD 23 +#define IPC_RELOAD_IFACE_CMD 30 #define IPC_SHOW_COMPAT_CMD 250 #define IPC_EOF_CMD 254 #define IPC_ERR_CMD 255 diff --git a/src/ipc.c b/src/ipc.c index a3db797..e51dce2 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -618,6 +618,10 @@ static void ipc_handle(int sd) restart(); break; + case IPC_RELOAD_IFACE_CMD: + reload_iface(); + break; + case IPC_DEBUG_CMD: ipc_generic(client, &msg, do_debug, &msg); break; diff --git a/src/main.c b/src/main.c index 6a6ffae..4ede8bb 100644 --- a/src/main.c +++ b/src/main.c @@ -504,7 +504,7 @@ int main(int argc, char *argv[]) } logit(LOG_NOTICE, 0, "%s exiting", versionstring); - free(pfd); + free(pfd); cleanup(); return 0; @@ -803,6 +803,22 @@ void restart(void) timer_set(TIMER_INTERVAL, timer, NULL); } +/* + * Reload ifaces + */ +void reload_iface(void) +{ + FILE *fp = NULL; + char *s = NULL; + + s = strdup (" reload ifaces"); + if (s == NULL) + logit(LOG_ERR, 0, "out of memory"); + + reload_vifs(); +} + + #define SCALETIMEBUFLEN 27 char *scaletime(time_t t) { diff --git a/src/mroutectl.c b/src/mroutectl.c index 9567b45..39ba311 100644 --- a/src/mroutectl.c +++ b/src/mroutectl.c @@ -320,6 +320,7 @@ static int usage(int rc) " kill Kill running mrouted, like SIGTERM\n" " log [? | none | LEVEL] Set log level: none, err, notice*, info, debug\n" " restart Restart mrouted and reload .conf file, like SIGHUP\n" + " reload ifaces Reload listening interfaces\n" " show version Show version, and uptime (-d), of running mrouted\n" " show status Show status summary, default\n" " show compat Show status, compat mode, previously `mrouted -r`\n" @@ -416,13 +417,18 @@ int main(int argc, char *argv[]) { "version", NULL, NULL, IPC_VERSION_CMD }, { NULL, NULL, NULL, 0 } }; + struct cmd reload[] = { + { "ifaces", NULL, NULL, IPC_RELOAD_IFACE_CMD }, + { NULL, NULL, NULL, 0 } + }; struct cmd command[] = { - { "debug", NULL, set_debug, 0 }, - { "help", NULL, help, 0 }, - { "kill", NULL, NULL, IPC_KILL_CMD }, - { "log", NULL, set_loglevel, 0 }, - { "restart", NULL, NULL, IPC_RESTART_CMD }, - { "show", show, show_status, 0 }, + { "debug", NULL, set_debug, 0 }, + { "help", NULL, help, 0 }, + { "kill", NULL, NULL, IPC_KILL_CMD }, + { "log", NULL, set_loglevel, 0 }, + { "restart", NULL, NULL, IPC_RESTART_CMD }, + { "show", show, show_status, 0 }, + { "reload", reload, NULL, 0 }, { NULL, NULL, NULL, 0 } }; int c; diff --git a/src/route.c b/src/route.c index 6696ade..d34f33e 100644 --- a/src/route.c +++ b/src/route.c @@ -163,6 +163,17 @@ void delete_vif_from_routes(vifi_t vifi) } +void discard_vif_from_routes(vifi_t vifi) +{ + struct rtentry *r, *tmp; + + TAILQ_FOREACH_SAFE(r, &rtable, rt_link, tmp) { + if (r->rt_parent == vifi || VIFM_ISSET(vifi, r->rt_children)) + discard_route(r); + } +} + + /* * A new neighbor has come up. If we're flooding on the neighbor's * vif, mark that neighbor as subordinate for all routes whose parent @@ -325,7 +336,6 @@ static void create_route(uint32_t origin, uint32_t mask) ++nroutes; } - /* * Discard the routing table entry following the one to which 'rt' points. * [.|prev|.]--->[.|rt|.]<---[.|next|.] diff --git a/src/vif.c b/src/vif.c index 09ed00e..64b034b 100644 --- a/src/vif.c +++ b/src/vif.c @@ -38,9 +38,9 @@ static int dvmrp_timerid = -1; /* * Forward declarations. */ -static void start_vif (vifi_t vifi); -static void start_vif2 (vifi_t vifi); -static void stop_vif (vifi_t vifi); +static void start_vif (vifi_t vifi); +void start_vif2 (vifi_t vifi); +void stop_vif (vifi_t vifi); static void send_probe_on_vif (struct uvif *v); @@ -161,6 +161,14 @@ void init_vifs(void) dvmrp_timerid = timer_set(NEIGHBOR_PROBE_INTERVAL, query_dvmrp, NULL); } +/* + * Reload the virtual interfaces, removing gone vifs and add new vifs. + */ +void reload_vifs(void) +{ + config_vifs_from_reload(); +} + /* * Initialize the passed vif with all appropriate default values. * "t" is true if a tunnel, or false if a phyint. @@ -230,27 +238,20 @@ void blaster_free(struct uvif *uv) uv->uv_blastertimer = timer_clear(uv->uv_blastertimer); } -/* - * Start routing on all virtual interfaces that are not down or - * administratively disabled. - */ -void init_installvifs(void) + +void init_installvif(struct uvif *uv, vifi_t vifi) { - struct listaddr *al, *tmp; - struct uvif *uv; - vifi_t vifi; + struct listaddr *al, *tmp; - logit(LOG_INFO, 0, "Installing vifs in kernel ..."); - UVIF_FOREACH(vifi, uv) { if (uv->uv_flags & VIFF_DISABLED) { logit(LOG_DEBUG, 0, "%s is disabled", uv->uv_name); - continue; + return; } if (uv->uv_flags & VIFF_DOWN) { logit(LOG_INFO, 0, "%s is not yet up; vif #%u not in service", uv->uv_name, vifi); - continue; + return; } if (uv->uv_flags & VIFF_TUNNEL) { @@ -277,6 +278,20 @@ void init_installvifs(void) update_lclgrp(vifi, group); chkgrp_graft(vifi, group); } +} + +/* + * Start routing on all virtual interfaces that are not down or + * administratively disabled. + */ +void init_installvifs(void) +{ + struct uvif *uv; + vifi_t vifi; + + logit(LOG_INFO, 0, "Installing vifs in kernel ..."); + UVIF_FOREACH(vifi, uv) { + init_installvif(uv, vifi); } } @@ -292,6 +307,31 @@ int install_uvif(struct uvif *uv) return 0; } +int uninstall_uvif(struct uvif *uv) +{ + if (numvifs == 0) { + logit(LOG_WARNING, 0, "No vifs, ignoring %s", uv->uv_name); + return 1; + } + + int i; + for (i = 0; i < numvifs; i++) { + if (uv->uv_ifindex == uvifs[i]->uv_ifindex) { + break; + } + } + + if (i == numvifs) + return 1; + + for (; i < numvifs - 1; i++) { + uvifs[i] = uvifs[i + 1]; + } + numvifs--; + + return 0; +} + /* * See if any interfaces have changed from up state to down, or vice versa, * including any non-multicast-capable interfaces that are in use as local @@ -456,7 +496,7 @@ static void start_vif(vifi_t vifi) * Add a vifi to all the user-level data structures but don't add * it to the kernel yet. */ -static void start_vif2(vifi_t vifi) +void start_vif2(vifi_t vifi) { struct listaddr *a; struct phaddr *p; @@ -540,7 +580,7 @@ static void start_vif2(vifi_t vifi) /* * Stop routing on the specified virtual interface. */ -static void stop_vif(vifi_t vifi) +void stop_vif(vifi_t vifi) { struct listaddr *a, *tmp; struct phaddr *p; @@ -597,6 +637,7 @@ static void stop_vif(vifi_t vifi) * Update the existing route entries to take into account the vif failure. */ delete_vif_from_routes(vifi); + discard_vif_from_routes(vifi); /* * Delete the interface from the kernel's vif structure.