summaryrefslogtreecommitdiff
path: root/interface-ip.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2015-12-15 11:57:48 +0100
committerFelix Fietkau <nbd@openwrt.org>2015-12-15 11:57:52 +0100
commitd5f53f4d79231f59494da852b73d2d9d2b9c43cc (patch)
treee6faf6554096249b7658634259ce971c82a67be2 /interface-ip.c
parente911dd3a798a543d40b93fe8dcb0824bd011c621 (diff)
downloadnetifd-d5f53f4d79231f59494da852b73d2d9d2b9c43cc.tar.gz
interface-ip: fix subnet route handling
When the kernel subnet route has to be replaced, the cleanup call needs to match the properties of the replacement route exactly, mainly the metric and the routing table. Fix handling this by embedding the device_route for the subnet in the device_addr struct and using it in the cleanup path. This fixes issues on config reload with changes to the routing table Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Diffstat (limited to 'interface-ip.c')
-rw-r--r--interface-ip.c48
1 files changed, 27 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);