Commit a299053a authored by Julien Muchembled's avatar Julien Muchembled

New install filter and pref-src action

The purpose of the this new filter is to override *locally*:
- RTA_SRC ('from' option in ip-route)
- RTA_PREFSRC ('src' in ip-route)

TODO: documentation

To be pushed upstream.
parent b14774d5
Pipeline #296 skipped
...@@ -42,6 +42,7 @@ THE SOFTWARE. ...@@ -42,6 +42,7 @@ THE SOFTWARE.
struct filter *input_filters = NULL; struct filter *input_filters = NULL;
struct filter *output_filters = NULL; struct filter *output_filters = NULL;
struct filter *redistribute_filters = NULL; struct filter *redistribute_filters = NULL;
struct filter *install_filters = NULL;
struct interface_conf *default_interface_conf = NULL; struct interface_conf *default_interface_conf = NULL;
struct interface_conf *interface_confs = NULL; struct interface_conf *interface_confs = NULL;
...@@ -403,6 +404,15 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return) ...@@ -403,6 +404,15 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
goto error; goto error;
if(af == AF_INET && filter->action.src_plen == 96) if(af == AF_INET && filter->action.src_plen == 96)
memset(&filter->action.src_prefix, 0, 16); memset(&filter->action.src_prefix, 0, 16);
} else if(strcmp(token, "pref-src") == 0) {
int af;
c = getip(c, &filter->action.pref_src, &af, gnc, closure);
if(c < -1)
goto error;
if(filter->af == AF_UNSPEC)
filter->af = af;
else if(filter->af != af)
goto error;
} else { } else {
goto error; goto error;
} }
...@@ -835,6 +845,12 @@ parse_config(gnc_t gnc, void *closure) ...@@ -835,6 +845,12 @@ parse_config(gnc_t gnc, void *closure)
if(c < -1) if(c < -1)
return -1; return -1;
add_filter(filter, &redistribute_filters); add_filter(filter, &redistribute_filters);
} else if(strcmp(token, "install") == 0) {
struct filter *filter;
c = parse_filter(c, gnc, closure, &filter);
if(c < -1)
return -1;
add_filter(filter, &install_filters);
} else if(strcmp(token, "interface") == 0) { } else if(strcmp(token, "interface") == 0) {
struct interface_conf *if_conf; struct interface_conf *if_conf;
c = parse_ifconf(c, gnc, closure, &if_conf); c = parse_ifconf(c, gnc, closure, &if_conf);
...@@ -1067,6 +1083,19 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen, ...@@ -1067,6 +1083,19 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen,
return res; return res;
} }
int
install_filter(const unsigned char *prefix, unsigned short plen,
const unsigned char *src_prefix, unsigned short src_plen,
struct filter_result *result)
{
int res;
res = do_filter(install_filters, NULL, prefix, plen,
src_prefix, src_plen, NULL, 0, 0, result);
if(res < 0)
res = INFINITY;
return res;
}
int int
finalise_config() finalise_config()
{ {
......
...@@ -24,6 +24,7 @@ struct filter_result { ...@@ -24,6 +24,7 @@ struct filter_result {
unsigned int add_metric; /* allow = 0, deny = INF, metric = <0..INF> */ unsigned int add_metric; /* allow = 0, deny = INF, metric = <0..INF> */
unsigned char *src_prefix; unsigned char *src_prefix;
unsigned char src_plen; unsigned char src_plen;
unsigned char *pref_src;
}; };
struct filter { struct filter {
...@@ -61,4 +62,7 @@ int redistribute_filter(const unsigned char *prefix, unsigned short plen, ...@@ -61,4 +62,7 @@ int redistribute_filter(const unsigned char *prefix, unsigned short plen,
const unsigned char *src_prefix, unsigned short src_plen, const unsigned char *src_prefix, unsigned short src_plen,
unsigned int ifindex, int proto, unsigned int ifindex, int proto,
struct filter_result *result); struct filter_result *result);
int install_filter(const unsigned char *prefix, unsigned short plen,
const unsigned char *src_prefix, unsigned short src_plen,
struct filter_result *result);
int finalise_config(void); int finalise_config(void);
...@@ -34,6 +34,7 @@ THE SOFTWARE. ...@@ -34,6 +34,7 @@ THE SOFTWARE.
#include "route.h" #include "route.h"
#include "source.h" #include "source.h"
#include "neighbour.h" #include "neighbour.h"
#include "configuration.h"
struct zone { struct zone {
const unsigned char *dst_prefix; const unsigned char *dst_prefix;
...@@ -208,32 +209,51 @@ is_installed(struct zone *zone) ...@@ -208,32 +209,51 @@ is_installed(struct zone *zone)
zone->src_prefix, zone->src_plen) != NULL; zone->src_prefix, zone->src_plen) != NULL;
} }
static const unsigned char *install_zone(struct zone *zone)
{
struct filter_result filter_result;
if(INFINITY == install_filter(zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen,
&filter_result))
return NULL;
if(filter_result.src_prefix) {
zone->src_prefix = filter_result.src_prefix;
zone->src_plen = filter_result.src_plen;
}
return filter_result.pref_src;
}
static int static int
add_route(const struct zone *zone, const struct babel_route *route) add_route(struct zone *zone, const struct babel_route *route)
{ {
const unsigned char *pref_src = install_zone(zone);
return kernel_route(ROUTE_ADD, zone->dst_prefix, zone->dst_plen, return kernel_route(ROUTE_ADD, zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen, zone->src_prefix, zone->src_plen, pref_src,
route->nexthop, route->nexthop,
route->neigh->ifp->ifindex, route->neigh->ifp->ifindex,
metric_to_kernel(route_metric(route)), NULL, 0, 0); metric_to_kernel(route_metric(route)), NULL, 0, 0);
} }
static int static int
del_route(const struct zone *zone, const struct babel_route *route) del_route(struct zone *zone, const struct babel_route *route)
{ {
const unsigned char *pref_src = install_zone(zone);
return kernel_route(ROUTE_FLUSH, zone->dst_prefix, zone->dst_plen, return kernel_route(ROUTE_FLUSH, zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen, zone->src_prefix, zone->src_plen, pref_src,
route->nexthop, route->nexthop,
route->neigh->ifp->ifindex, route->neigh->ifp->ifindex,
metric_to_kernel(route_metric(route)), NULL, 0, 0); metric_to_kernel(route_metric(route)), NULL, 0, 0);
} }
static int static int
chg_route(const struct zone *zone, const struct babel_route *old, chg_route(struct zone *zone, const struct babel_route *old,
const struct babel_route *new) const struct babel_route *new)
{ {
const unsigned char *pref_src = install_zone(zone);
return kernel_route(ROUTE_MODIFY, zone->dst_prefix, zone->dst_plen, return kernel_route(ROUTE_MODIFY, zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen, zone->src_prefix, zone->src_plen, pref_src,
old->nexthop, old->neigh->ifp->ifindex, old->nexthop, old->neigh->ifp->ifindex,
metric_to_kernel(route_metric(old)), metric_to_kernel(route_metric(old)),
new->nexthop, new->neigh->ifp->ifindex, new->nexthop, new->neigh->ifp->ifindex,
...@@ -241,11 +261,12 @@ chg_route(const struct zone *zone, const struct babel_route *old, ...@@ -241,11 +261,12 @@ chg_route(const struct zone *zone, const struct babel_route *old,
} }
static int static int
chg_route_metric(const struct zone *zone, const struct babel_route *route, chg_route_metric(struct zone *zone, const struct babel_route *route,
int old_metric, int new_metric) int old_metric, int new_metric)
{ {
const unsigned char *pref_src = install_zone(zone);
return kernel_route(ROUTE_MODIFY, zone->dst_prefix, zone->dst_plen, return kernel_route(ROUTE_MODIFY, zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen, zone->src_prefix, zone->src_plen, pref_src,
route->nexthop, route->neigh->ifp->ifindex, route->nexthop, route->neigh->ifp->ifindex,
old_metric, old_metric,
route->nexthop, route->neigh->ifp->ifindex, route->nexthop, route->neigh->ifp->ifindex,
......
...@@ -68,6 +68,7 @@ int kernel_interface_channel(const char *ifname, int ifindex); ...@@ -68,6 +68,7 @@ int kernel_interface_channel(const char *ifname, int ifindex);
int kernel_disambiguate(int v4); int kernel_disambiguate(int v4);
int kernel_route(int operation, const unsigned char *dest, unsigned short plen, int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_plen, const unsigned char *src, unsigned short src_plen,
const unsigned char *pref_src,
const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex, const unsigned char *newgate, int newifindex,
unsigned int newmetric); unsigned int newmetric);
......
...@@ -936,6 +936,7 @@ kernel_has_ipv6_subtrees(void) ...@@ -936,6 +936,7 @@ kernel_has_ipv6_subtrees(void)
int int
kernel_route(int operation, const unsigned char *dest, unsigned short plen, kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_plen, const unsigned char *src, unsigned short src_plen,
const unsigned char *pref_src,
const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex, const unsigned char *newgate, int newifindex,
unsigned int newmetric) unsigned int newmetric)
...@@ -989,11 +990,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -989,11 +990,11 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
stick with the naive approach, and hope that the window is stick with the naive approach, and hope that the window is
small enough to be negligible. */ small enough to be negligible. */
kernel_route(ROUTE_FLUSH, dest, plen, kernel_route(ROUTE_FLUSH, dest, plen,
src, src_plen, src, src_plen, pref_src,
gate, ifindex, metric, gate, ifindex, metric,
NULL, 0, 0); NULL, 0, 0);
rc = kernel_route(ROUTE_ADD, dest, plen, rc = kernel_route(ROUTE_ADD, dest, plen,
src, src_plen, src, src_plen, pref_src,
newgate, newifindex, newmetric, newgate, newifindex, newmetric,
NULL, 0, 0); NULL, 0, 0);
if(rc < 0) { if(rc < 0) {
...@@ -1085,17 +1086,24 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -1085,17 +1086,24 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
rta->rta_type = RTA_OIF; rta->rta_type = RTA_OIF;
*(int*)RTA_DATA(rta) = ifindex; *(int*)RTA_DATA(rta) = ifindex;
if(ipv4) { #define ADD_IPARG(type, addr) \
rta = RTA_NEXT(rta, len); do if(ipv4) { \
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rta = RTA_NEXT(rta, len); \
rta->rta_type = RTA_GATEWAY; rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); \
memcpy(RTA_DATA(rta), gate + 12, sizeof(struct in_addr)); rta->rta_type = type; \
} else { memcpy(RTA_DATA(rta), addr + 12, sizeof(struct in_addr)); \
rta = RTA_NEXT(rta, len); } else { \
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rta = RTA_NEXT(rta, len); \
rta->rta_type = RTA_GATEWAY; rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); \
memcpy(RTA_DATA(rta), gate, sizeof(struct in6_addr)); rta->rta_type = type; \
} memcpy(RTA_DATA(rta), addr, sizeof(struct in6_addr)); \
} while (0)
ADD_IPARG(RTA_GATEWAY, gate);
if(pref_src)
ADD_IPARG(RTA_PREFSRC, pref_src);
#undef ADD_IPARG
} else { } else {
*(int*)RTA_DATA(rta) = -1; *(int*)RTA_DATA(rta) = -1;
} }
......
...@@ -397,6 +397,7 @@ kernel_has_ipv6_subtrees(void) ...@@ -397,6 +397,7 @@ kernel_has_ipv6_subtrees(void)
int int
kernel_route(int operation, const unsigned char *dest, unsigned short plen, kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *src, unsigned short src_plen, const unsigned char *src, unsigned short src_plen,
const unsigned char *pref_src,
const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex, const unsigned char *newgate, int newifindex,
unsigned int newmetric) unsigned int newmetric)
...@@ -413,8 +414,9 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -413,8 +414,9 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}}; 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}};
/* Source-specific routes are not implemented yet for BSD. */ /* Source-specific routes & preferred source IPs
if(src_plen > 0) { * are not implemented yet for BSD. */
if(src_plen > 0 || pref_src) {
errno = ENOSYS; errno = ENOSYS;
return -1; return -1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment