diff --git a/.gitignore b/.gitignore index 4e888447..afcd3145 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ tags *.orig *~ \#*# +.vscode/ diff --git a/babeld.c b/babeld.c index b0b7f55d..46b5a6b4 100644 --- a/babeld.c +++ b/babeld.c @@ -514,7 +514,7 @@ main(int argc, char **argv) check_interfaces(); - rc = check_xroutes(0, 0); + rc = check_xroutes(0, 0, 0); if(rc < 0) fprintf(stderr, "Warning: couldn't check exported routes.\n"); @@ -684,7 +684,7 @@ main(int argc, char **argv) if(kernel_addr_changed || (kernel_check_interval > 0 && now.tv_sec >= kernel_dump_time)) { - rc = check_xroutes(1, !kernel_addr_changed); + rc = check_xroutes(1, !kernel_addr_changed, 0); if(rc < 0) fprintf(stderr, "Warning: couldn't check exported routes.\n"); kernel_addr_changed = 0; diff --git a/configuration.c b/configuration.c index 045d3043..2033a408 100644 --- a/configuration.c +++ b/configuration.c @@ -64,6 +64,8 @@ static int config_finalised = 0; /* get_next_char callback */ typedef int (*gnc_t)(void*); +static int update_filter(struct filter *f, struct filter *newf); + static int skip_whitespace(int c, gnc_t gnc, void *closure) { @@ -1177,12 +1179,26 @@ parse_config_line(int c, gnc_t gnc, void *closure, add_filter(filter, FILTER_TYPE_OUTPUT); } else if(strcmp(token, "redistribute") == 0) { struct filter *filter; - if(config_finalised) - goto fail; c = parse_filter(c, gnc, closure, &filter); if(c < -1) goto fail; - add_filter(filter, FILTER_TYPE_REDISTRIBUTE); + if(config_finalised) { + if(!action_return) + goto fail; + c = update_filter(redistribute_filters, filter); + free_filter(filter); + if (c == 0) { + if(action_return) + *action_return = CONFIG_ACTION_NO; + if(message_return) { + *message_return = "Couldn't find the redistribute filter to update"; + } + } + if(c < -1) + goto fail; + } else { + add_filter(filter, FILTER_TYPE_REDISTRIBUTE); + } } else if(strcmp(token, "install") == 0) { struct filter *filter; if(config_finalised) @@ -1256,6 +1272,11 @@ parse_config_line(int c, gnc_t gnc, void *closure, goto fail; add_key(key->id, key->type, key->len, key->value); free(key); + } else if(strcmp(token, "check_xroutes") == 0) { + c = skip_eol(c, gnc, closure); + if(c < -1 || !action_return) + goto fail; + *action_return = CONFIG_ACTION_CHECK_XROUTES; } else { c = parse_option(c, gnc, closure, token); if(c < -1) @@ -1460,6 +1481,23 @@ do_filter(struct filter *f, const unsigned char *id, return -1; } +static int +update_filter(struct filter *f, struct filter *newf) +{ + while(f) { + if(filter_match(f, newf->id, newf->prefix, newf->plen, newf->src_prefix, newf->src_plen, + newf->neigh, newf->ifindex, newf->proto)) { + f->action.add_metric = newf->action.add_metric; + // f->action.table = newf->action.table; + // memcpy(f->action.pref_src, newf->action.pref_src, 16); + return -1; + } + f = f->next; + } + + return 0; +} + int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, @@ -1503,13 +1541,14 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen, } int -install_filter(const unsigned char *prefix, unsigned short plen, +install_filter(const unsigned char *id, + const unsigned char *prefix, unsigned short plen, const unsigned char *src_prefix, unsigned short src_plen, unsigned int ifindex, struct filter_result *result) { int res; - res = do_filter(install_filters, NULL, prefix, plen, + res = do_filter(install_filters, id, prefix, plen, src_prefix, src_plen, NULL, ifindex, 0, result); if(res < 0) res = INFINITY; diff --git a/configuration.h b/configuration.h index 95ce16cc..f99a2e63 100644 --- a/configuration.h +++ b/configuration.h @@ -28,6 +28,7 @@ THE SOFTWARE. #define CONFIG_ACTION_MONITOR 3 #define CONFIG_ACTION_UNMONITOR 4 #define CONFIG_ACTION_NO 5 +#define CONFIG_ACTION_CHECK_XROUTES 6 #define AUTH_TYPE_NONE 0 #define AUTH_TYPE_SHA256 1 @@ -84,7 +85,8 @@ int redistribute_filter(const unsigned char *prefix, unsigned short plen, const unsigned char *src_prefix, unsigned short src_plen, unsigned int ifindex, int proto, struct filter_result *result); -int install_filter(const unsigned char *prefix, unsigned short plen, +int install_filter(const unsigned char *id, + const unsigned char *prefix, unsigned short plen, const unsigned char *src_prefix, unsigned short src_plen, unsigned int ifindex, struct filter_result *result); int finalise_config(void); diff --git a/kernel.h b/kernel.h index 94bcb4fb..56060d1a 100644 --- a/kernel.h +++ b/kernel.h @@ -85,7 +85,8 @@ int kernel_route(int operation, int table, const unsigned char *pref_src, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, - unsigned int newmetric, int newtable); + unsigned int newmetric, int newtable, + const unsigned char *newpref_src); int kernel_dump(int operation, struct kernel_filter *filter); int kernel_callback(struct kernel_filter *filter); int if_eui64(char *ifname, int ifindex, unsigned char *eui); diff --git a/kernel_netlink.c b/kernel_netlink.c index 6ee991d8..5de9cc04 100644 --- a/kernel_netlink.c +++ b/kernel_netlink.c @@ -959,7 +959,8 @@ kernel_route(int operation, int table, const unsigned char *pref_src, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, - unsigned int newmetric, int newtable) + unsigned int newmetric, int newtable, + const unsigned char *newpref_src) { union { char raw[1024]; struct nlmsghdr nh; } buf; struct rtmsg *rtm; @@ -1011,11 +1012,11 @@ kernel_route(int operation, int table, kernel_route(ROUTE_FLUSH, table, dest, plen, src, src_plen, pref_src, gate, ifindex, metric, - NULL, 0, 0, 0); + NULL, 0, 0, 0, NULL); rc = kernel_route(ROUTE_ADD, newtable, dest, plen, - src, src_plen, pref_src, + src, src_plen, newpref_src, newgate, newifindex, newmetric, - NULL, 0, 0, 0); + NULL, 0, 0, 0, NULL); if(rc < 0) { if(errno == EEXIST) rc = 1; diff --git a/kernel_socket.c b/kernel_socket.c index 9ffa2f53..f96e6b5c 100644 --- a/kernel_socket.c +++ b/kernel_socket.c @@ -407,7 +407,8 @@ kernel_route(int operation, int table, const unsigned char *pref_src, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, - unsigned int newmetric, int newtable) + unsigned int newmetric, int newtable, + const unsigned char *newpref_src) { struct { struct rt_msghdr m_rtm; @@ -423,7 +424,7 @@ kernel_route(int operation, int table, /* Source-specific routes & preferred source IPs * are not implemented yet for BSD. */ - if((!is_default(src, src_plen)) || pref_src) { + if((!is_default(src, src_plen)) || pref_src || newpref_src) { errno = ENOSYS; return -1; } @@ -454,11 +455,11 @@ kernel_route(int operation, int table, kernel_route(ROUTE_FLUSH, table, dest, plen, src, src_plen, NULL, gate, ifindex, metric, - NULL, 0, 0, 0); + NULL, 0, 0, 0, NULL); return kernel_route(ROUTE_ADD, table, dest, plen, src, src_plen, NULL, newgate, newifindex, newmetric, - NULL, 0, 0, 0); + NULL, 0, 0, 0, NULL); } diff --git a/local.c b/local.c index d4103c44..facdc143 100644 --- a/local.c +++ b/local.c @@ -366,6 +366,12 @@ local_read(struct local_socket *s) snprintf(reply, sizeof(reply), "no%s%s\n", message ? " " : "", message ? message : ""); break; + case CONFIG_ACTION_CHECK_XROUTES: + rc = check_xroutes(1, 0, 1); + if(rc < 0) { + snprintf(reply, sizeof(reply), "Warning: couldn't check exported routes.\n"); + } + break; default: snprintf(reply, sizeof(reply), "bad\n"); } diff --git a/route.c b/route.c index fa5bf30a..b316ef7a 100644 --- a/route.c +++ b/route.c @@ -439,14 +439,17 @@ move_installed_route(struct babel_route *route, int i) static int change_route(int operation, const struct babel_route *route, int metric, const unsigned char *new_next_hop, - int new_ifindex, int new_metric) + int new_ifindex, int new_metric, + const struct source *newsrc) { struct filter_result filter_result; unsigned char *pref_src = NULL; + unsigned char *newpref_src = NULL; unsigned int ifindex = route->neigh->ifp->ifindex; int m, table; - m = install_filter(route->src->prefix, route->src->plen, + m = install_filter(route->src->id, + route->src->prefix, route->src->plen, route->src->src_prefix, route->src->src_plen, ifindex, &filter_result); if(m >= INFINITY && operation == ROUTE_ADD) { @@ -455,13 +458,24 @@ change_route(int operation, const struct babel_route *route, int metric, } pref_src = filter_result.pref_src; + newpref_src = pref_src; table = filter_result.table ? filter_result.table : export_table; + if(newsrc) { + m = install_filter(newsrc->id, + newsrc->prefix, newsrc->plen, + newsrc->src_prefix, newsrc->src_plen, + new_ifindex, &filter_result); + if(m < INFINITY && filter_result.pref_src) + newpref_src = filter_result.pref_src; + } + return kernel_route(operation, table, route->src->prefix, route->src->plen, route->src->src_prefix, route->src->src_plen, pref_src, route->nexthop, ifindex, metric, new_next_hop, new_ifindex, new_metric, - operation == ROUTE_MODIFY ? table : 0); + operation == ROUTE_MODIFY ? table : 0, + newpref_src); } void @@ -490,7 +504,7 @@ install_route(struct babel_route *route) format_prefix(route->src->prefix, route->src->plen), format_prefix(route->src->src_prefix, route->src->src_plen)); rc = change_route(ROUTE_ADD, route, metric_to_kernel(route_metric(route)), - NULL, 0, 0); + NULL, 0, 0, NULL); if(rc < 0 && errno != EEXIST) { perror("kernel_route(ADD)"); return; @@ -516,7 +530,7 @@ uninstall_route(struct babel_route *route) format_prefix(route->src->prefix, route->src->plen), format_prefix(route->src->src_prefix, route->src->src_plen)); rc = change_route(ROUTE_FLUSH, route, metric_to_kernel(route_metric(route)), - NULL, 0, 0); + NULL, 0, 0, NULL); if(rc < 0) { perror("kernel_route(FLUSH)"); return; @@ -550,7 +564,8 @@ switch_routes(struct babel_route *old, struct babel_route *new) format_prefix(old->src->src_prefix, old->src->src_plen)); rc = change_route(ROUTE_MODIFY, old, metric_to_kernel(route_metric(old)), new->nexthop, new->neigh->ifp->ifindex, - metric_to_kernel(route_metric(new))); + metric_to_kernel(route_metric(new)), + new->src); if(rc < 0) { perror("kernel_route(MODIFY)"); return; @@ -580,7 +595,7 @@ change_route_metric(struct babel_route *route, format_prefix(route->src->src_prefix, route->src->src_plen), old_metric, new_metric); rc = change_route(ROUTE_MODIFY, route, old_metric, route->nexthop, - route->neigh->ifp->ifindex, new_metric); + route->neigh->ifp->ifindex, new_metric, NULL); if(rc < 0) { perror("kernel_route(MODIFY metric)"); return; diff --git a/xroute.c b/xroute.c index fb881ea3..03cbe582 100644 --- a/xroute.c +++ b/xroute.c @@ -434,7 +434,7 @@ kernel_route_notify(int add, struct kernel_route *kroute, void *closure) int -check_xroutes(int send_updates, int warn) +check_xroutes(int send_updates, int warn, int check_infinity) { int i, j, change = 0, rc; struct kernel_route *routes; @@ -481,6 +481,8 @@ check_xroutes(int send_updates, int warn) memcpy(routes[i].src_prefix, filter_result.src_prefix, 16); routes[i].src_plen = filter_result.src_plen; } + debugf("Route %s metric %d\n", + format_prefix(routes[i].prefix, routes[i].plen), routes[i].metric); } qsort(routes, numroutes, sizeof(struct kernel_route), kernel_route_compare); @@ -488,7 +490,7 @@ check_xroutes(int send_updates, int warn) j = 0; while(i < numroutes || j < numxroutes) { /* Ignore routes filtered out. */ - if(i < numroutes && routes[i].metric >= INFINITY) { + if(!check_infinity && i < numroutes && routes[i].metric >= INFINITY) { i++; continue; } diff --git a/xroute.h b/xroute.h index 812da58e..95dab6c4 100644 --- a/xroute.h +++ b/xroute.h @@ -45,4 +45,4 @@ void xroute_stream_done(struct xroute_stream *stream); int kernel_addresses(int ifindex, int ll, struct kernel_route *routes, int maxroutes); void kernel_route_notify(int add, struct kernel_route *route, void *closure); -int check_xroutes(int send_updates, int warn); +int check_xroutes(int send_updates, int warn, int check_infinity);