Commit d42c1dbd authored by Killian Lufau's avatar Killian Lufau Committed by Juliusz Chroboczek

Add install filter parameter pref_src.

The purpose is to override *locally* RTA_PREFSRC ('src' in ip-route).
parent 90fc2cbf
......@@ -562,6 +562,12 @@ filter, specify the kernel routing table to use. For source-specific
routes, this only works reliably for IPv6, and only when
.B ipv6-subtrees
is true.
.TP
.BI pref-src " ip"
Specify the preferred source address to use with this route. Only useful
in an
.B install
filter.
.PP
If
.I action
......
......@@ -471,6 +471,15 @@ parse_filter(int c, gnc_t gnc, void *closure, struct filter **filter_return)
if(table <= 0 || table > INFINITY)
goto error;
filter->action.table = table;
} 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 {
goto error;
}
......@@ -1337,11 +1346,12 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen,
int
install_filter(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,
src_prefix, src_plen, NULL, 0, 0, result);
src_prefix, src_plen, NULL, ifindex, 0, result);
if(res < 0)
res = INFINITY;
return res;
......
......@@ -34,6 +34,7 @@ struct filter_result {
unsigned char *src_prefix;
unsigned char src_plen;
unsigned int table;
unsigned char *pref_src;
};
struct filter {
......@@ -75,5 +76,5 @@ int redistribute_filter(const unsigned char *prefix, unsigned short plen,
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);
unsigned int ifindex, struct filter_result *result);
int finalise_config(void);
......@@ -221,17 +221,21 @@ change_route(int operation, const struct zone *zone,
int new_ifindex, int new_metric)
{
struct filter_result filter_result;
unsigned char *pref_src = NULL;
unsigned int ifindex = route->neigh->ifp->ifindex;
install_filter(zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen, &filter_result);
int m = install_filter(zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen,
ifindex, &filter_result);
if (m < INFINITY)
pref_src = filter_result.pref_src;
int table = filter_result.table ? filter_result.table :
find_table(zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen);
return kernel_route(operation, table, zone->dst_prefix, zone->dst_plen,
zone->src_prefix, zone->src_plen,
zone->src_prefix, zone->src_plen, pref_src,
route->nexthop, ifindex,
metric, new_next_hop, new_ifindex, new_metric,
operation == ROUTE_MODIFY ? table : 0);
......
......@@ -94,6 +94,7 @@ int kernel_disambiguate(int v4);
int kernel_route(int operation, int table,
const unsigned char *dest, unsigned short 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 *newgate, int newifindex,
unsigned int newmetric, int newtable);
......
......@@ -944,6 +944,7 @@ int
kernel_route(int operation, int table,
const unsigned char *dest, unsigned short 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 *newgate, int newifindex,
unsigned int newmetric, int newtable)
......@@ -997,11 +998,11 @@ kernel_route(int operation, int table,
stick with the naive approach, and hope that the window is
small enough to be negligible. */
kernel_route(ROUTE_FLUSH, table, dest, plen,
src, src_plen,
src, src_plen, pref_src,
gate, ifindex, metric,
NULL, 0, 0, 0);
rc = kernel_route(ROUTE_ADD, newtable, dest, plen,
src, src_plen,
src, src_plen, pref_src,
newgate, newifindex, newmetric,
NULL, 0, 0, 0);
if(rc < 0) {
......@@ -1084,17 +1085,24 @@ kernel_route(int operation, int table,
rta->rta_type = RTA_OIF;
*(int*)RTA_DATA(rta) = ifindex;
if(ipv4) {
rta = RTA_NEXT(rta, len);
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
rta->rta_type = RTA_GATEWAY;
memcpy(RTA_DATA(rta), gate + 12, sizeof(struct in_addr));
} else {
rta = RTA_NEXT(rta, len);
rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
rta->rta_type = RTA_GATEWAY;
memcpy(RTA_DATA(rta), gate, sizeof(struct in6_addr));
}
#define ADD_IPARG(type, addr) \
do if(ipv4) { \
rta = RTA_NEXT(rta, len); \
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); \
rta->rta_type = type; \
memcpy(RTA_DATA(rta), addr + 12, sizeof(struct in_addr)); \
} else { \
rta = RTA_NEXT(rta, len); \
rta->rta_len = RTA_LENGTH(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 {
*(int*)RTA_DATA(rta) = -1;
}
......
......@@ -408,6 +408,7 @@ int
kernel_route(int operation, int table,
const unsigned char *dest, unsigned short 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 *newgate, int newifindex,
unsigned int newmetric, int newtable)
......@@ -424,8 +425,9 @@ kernel_route(int operation, int table,
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}};
/* Source-specific routes are not implemented yet for BSD. */
if(!is_default(src, src_plen)) {
/* Source-specific routes & preferred source IPs
* are not implemented yet for BSD. */
if((!is_default(src, src_plen)) || pref_src) {
errno = ENOSYS;
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