summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--interface-ip.c48
-rw-r--r--interface-ip.h2
2 files changed, 29 insertions, 21 deletions
diff --git a/interface-ip.c b/interface-ip.c
index 220f4a0..5533615 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -440,32 +440,37 @@ static void
interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, bool add)
{
struct device *dev = iface->l3_dev.dev;
- struct device_route route;
bool v6 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET6);
+ struct device_route *r = &addr->subnet;
if (addr->flags & DEVADDR_OFFLINK)
return;
- memset(&route, 0, sizeof(route));
- route.iface = iface;
- route.flags = addr->flags;
- route.mask = addr->mask;
- memcpy(&route.addr, &addr->addr, sizeof(route.addr));
- clear_if_addr(&route.addr, route.mask);
-
- if (add) {
- route.flags |= DEVADDR_KERNEL;
- system_del_route(dev, &route);
+ if (!add) {
+ if (!addr->subnet.iface)
+ return;
- route.flags &= ~DEVADDR_KERNEL;
- route.metric = iface->metric;
- route.table = (v6) ? iface->ip6table : iface->ip4table;
- if (route.table)
- route.flags |= DEVROUTE_SRCTABLE;
- system_add_route(dev, &route);
- } else {
- system_del_route(dev, &route);
+ system_del_route(dev, r);
+ memset(r, 0, sizeof(*r));
+ return;
}
+
+ r->iface = iface;
+ r->flags = addr->flags;
+ r->mask = addr->mask;
+ memcpy(&r->addr, &addr->addr, sizeof(r->addr));
+ clear_if_addr(&r->addr, r->mask);
+
+ r->flags |= DEVADDR_KERNEL;
+ system_del_route(dev, r);
+
+ r->flags &= ~DEVADDR_KERNEL;
+ r->metric = iface->metric;
+ r->table = (v6) ? iface->ip6table : iface->ip4table;
+ if (r->table)
+ r->flags |= DEVROUTE_SRCTABLE;
+
+ system_add_route(dev, r);
}
static void
@@ -1230,10 +1235,11 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
if (enabled) {
system_add_address(dev, addr);
- if (iface->metric)
- interface_handle_subnet_route(iface, addr, true);
addr->policy_table = (v6) ? iface->ip6table : iface->ip4table;
+ if (iface->metric || addr->policy_table)
+ interface_handle_subnet_route(iface, addr, true);
+
if (addr->policy_table)
set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &addr->addr,
(v6) ? 128 : 32, addr->policy_table, NULL, NULL);
diff --git a/interface-ip.h b/interface-ip.h
index f24b0ec..bbef62c 100644
--- a/interface-ip.h
+++ b/interface-ip.h
@@ -110,6 +110,8 @@ struct device_addr {
bool failed;
unsigned int policy_table;
+ struct device_route subnet;
+
/* ipv4 only */
uint32_t broadcast;
uint32_t point_to_point;