From d5f53f4d79231f59494da852b73d2d9d2b9c43cc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 Dec 2015 11:57:48 +0100 Subject: 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 --- interface-ip.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'interface-ip.c') 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); -- cgit v1.2.1