[OpenWrt-Devel] [PATCH] Netifd: Generic multi-wan support v3
This patch implements the comments received for version 1 (see https://lists.openwrt.org/pipermail/openwrt-devel/2013-May/020119.html), and improves upon version 2 by respecting metrics. * Routes are only added to the specified table. The only exception are the IPv4-routes Linux automatically adds to the default table when an address with a mask less than 32 comes up. In order to respect the metrics, each automatic routes is replaced by one containing the correct metric (if metric is set). Prefsrc is set as the source hint is needed in case of overlapping subnets. The automatic routes, or equivalent, needed to be present (in the default table) for for example adding default routes to interfaces to work. * The rules are divided into three 'parts', in order to support the case where a client is connected to networks with overlapping subnets. The first part consists of the "from IP-address"-rules, so that packets from sockets bound to IPs on the device go through the intended interface. The order here does not matter. Then follows lookups in main and default, before the networks and "from lo"-rules are checked. If metric is set, the priority of this rules is 65535 + metric, otherwise the priority is 65535 + ifindex. The "from lo .." rules are needed so that traffic from sockets not bound to an IP also is routed correctly. * The "from lo"-rules all have different priorities. When there are multiple rules with the same priority and same source, the kernel seems to display undefined behavior. Even though table and priority was specified when netifd sends DELRULE, it seems random which rule is actually deleted. I have been testing this patch on my router for the last two days and it behaves as intended. However, all my WAN-connections are IPv4 and I was only able to test IPv6 in a small, private network. If anyone has time to check the behavior in a full IPv6-network, I would be very grateful. --- interface-ip.c | 108 - interface-ip.h | 3 +- iprule.h | 3 ++ proto.c| 6 ++-- system-linux.c | 3 ++ 5 files changed, 94 insertions(+), 29 deletions(-) diff --git a/interface-ip.c b/interface-ip.c index e265563..05806af 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -90,28 +90,39 @@ match_if_addr(union if_addr *a1, union if_addr *a2, int mask) return !memcmp(p1, p2, sizeof(*p1)); } -static int set_ipv6_source_policy(bool add, const union if_addr *addr, uint8_t mask, int ifindex) +static int set_ip_source_policy(bool add, bool v4, unsigned int priority, + const union if_addr *addr, uint8_t mask, int ifindex) { struct iprule rule = { - .flags = IPRULE_INET6 | IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, - .priority = 65535, - .lookup = interface_ip_resolve_v6_rtable(ifindex), + .flags = IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, + .priority = priority, + .lookup = interface_ip_resolve_rtable(ifindex), .src_addr = *addr, .src_mask = mask, }; + if(v4) + rule.flags |= IPRULE_INET4; + else + rule.flags |= IPRULE_INET6; + return (add) ? system_add_iprule(&rule) : system_del_iprule(&rule); } -static int set_ipv6_lo_policy(bool add, int ifindex) +static int set_ip_lo_policy(bool add, bool v4, int ifindex, unsigned int pri) { struct iprule rule = { - .flags = IPRULE_INET6 | IPRULE_IN | IPRULE_LOOKUP | IPRULE_PRIORITY, - .priority = 65535, - .lookup = interface_ip_resolve_v6_rtable(ifindex), + .flags = IPRULE_IN | IPRULE_LOOKUP | IPRULE_PRIORITY, + .priority = pri, + .lookup = interface_ip_resolve_rtable(ifindex), .in_dev = "lo" }; + if(v4) + rule.flags |= IPRULE_INET4; + else + rule.flags |= IPRULE_INET6; + return (add) ? system_add_iprule(&rule) : system_del_iprule(&rule); } @@ -246,7 +257,6 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) struct blob_attr *tb[__ROUTE_MAX], *cur; struct device_route *route; int af = v6 ? AF_INET6 : AF_INET; - bool is_v6_proto_route = v6 && iface; blobmsg_parse(route_attr, __ROUTE_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr)); @@ -300,10 +310,8 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) } // Use source-based routing - if (is_v6_proto_route) { - route->table = interface_ip_resolve_v6_rtable(iface->l3_dev.dev->ifindex); - route->flags |= DEVROUTE_SRCTABLE; - } + route->table = interface_ip_resolve_rtable(iface->l3_dev.dev->ifindex); + route->flags |= DEVROUTE_
[OpenWrt-Devel] [PATCH] Netifd: Generic multi-wan support v2
From: Kristian Evensen This patch implements the comments received for version 1 (see https://lists.openwrt.org/pipermail/openwrt-devel/2013-May/020119.html). * Routes are only added to the specified table. The only exception are the IPv4-routes Linux generates automatically when an address with a mask less than 32 comes up. These routes are added to the default table and in order to avoid depending on OS-behavior, the routes are not deleted. Also, they are needed (in the default table) to for example be able to add default routes to interfaces. * The rules are divided into three 'parts', in order to support the case where a client is connected to networks with overlapping subnets. The first part consists of the "from IP-address"-rules, so that packets from sockets bound to IPs on the device go through the intended interface. Then follows lookups in main and default, before the networks are checked. Finally, the "from lo"-rules are check so that traffic from sockets not bound to an IP also is routed correctly. * The priority of the "from lo"-rules is set to 65535 + table_id. When there are multiple rules with the same priority and same source, the kernel seems to display undefined behavior. Even though table and priority was specified when netifd sends DELRULE, it seems random which rule is actually deleted. I have been testing this patch on my router the whole day today and it behaves as intended. However, all my WAN-connections are IPv4 and I was only able to test IPv6 in a small, private network. If anyone has time to check the behavior in a full IPv6-network, I would be very grateful. Fixed a whitespace --- interface-ip.c | 75 +++--- interface-ip.h | 2 +- iprule.h | 3 +++ proto.c| 6 ++--- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/interface-ip.c b/interface-ip.c index e265563..7cedf3f 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -90,28 +90,39 @@ match_if_addr(union if_addr *a1, union if_addr *a2, int mask) return !memcmp(p1, p2, sizeof(*p1)); } -static int set_ipv6_source_policy(bool add, const union if_addr *addr, uint8_t mask, int ifindex) +static int set_ip_source_policy(bool add, bool v4, unsigned int priority, + const union if_addr *addr, uint8_t mask, int ifindex) { struct iprule rule = { - .flags = IPRULE_INET6 | IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, - .priority = 65535, - .lookup = interface_ip_resolve_v6_rtable(ifindex), + .flags = IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, + .priority = priority, + .lookup = interface_ip_resolve_rtable(ifindex), .src_addr = *addr, .src_mask = mask, }; + if(v4) + rule.flags |= IPRULE_INET4; + else + rule.flags |= IPRULE_INET6; + return (add) ? system_add_iprule(&rule) : system_del_iprule(&rule); } -static int set_ipv6_lo_policy(bool add, int ifindex) +static int set_ip_lo_policy(bool add, bool v4, int ifindex) { struct iprule rule = { - .flags = IPRULE_INET6 | IPRULE_IN | IPRULE_LOOKUP | IPRULE_PRIORITY, - .priority = 65535, - .lookup = interface_ip_resolve_v6_rtable(ifindex), + .flags = IPRULE_IN | IPRULE_LOOKUP | IPRULE_PRIORITY, + .priority = IPRULE_PRIORITY_NW + interface_ip_resolve_rtable(ifindex), + .lookup = interface_ip_resolve_rtable(ifindex), .in_dev = "lo" }; + if(v4) + rule.flags |= IPRULE_INET4; + else + rule.flags |= IPRULE_INET6; + return (add) ? system_add_iprule(&rule) : system_del_iprule(&rule); } @@ -246,7 +257,6 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) struct blob_attr *tb[__ROUTE_MAX], *cur; struct device_route *route; int af = v6 ? AF_INET6 : AF_INET; - bool is_v6_proto_route = v6 && iface; blobmsg_parse(route_attr, __ROUTE_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr)); @@ -300,10 +310,8 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) } // Use source-based routing - if (is_v6_proto_route) { - route->table = interface_ip_resolve_v6_rtable(iface->l3_dev.dev->ifindex); - route->flags |= DEVROUTE_SRCTABLE; - } + route->table = interface_ip_resolve_rtable(iface->l3_dev.dev->ifindex); + route->flags |= DEVROUTE_SRCTABLE; if ((cur = tb[ROUTE_TABLE]) != NULL) { if (!system_resolve_rt_table(blobmsg_data(cur), &route->table)) { @@ -364,9 +372,11 @@ interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, memset(&route, 0, sizeof(route));
[OpenWrt-Devel] [PATCH] Netifd: Generic multi-wan support
From: Kristian Evensen Multi-wan support was recently added to netifd, but limited to IPv6. This patch enables multi-wan for IPv4 as well. In addition, the patch introduces some changes that make the multi-wan support more robust. 1) Instead of using the interface index to decide on interface metric, a table-option is added to interfaces. This way, users are sure which tables will be used for policy routing and can avoid overlaps. The table-option must be set for an interface to be 'multi-wan', and all routes belonging to the interface will be added to this table. 2) Routes are added both to the original table (for example main) and the interface-specific table. This is done to ensure networked applications running on the node will behave as intended. If routes are only added to the interface-specific tables, traffic from applications not binding to an interface will not be routed correctly. The IPv6 multi-wan support has been converted to use the generic functions. --- interface-ip.c | 35 +++ interface.c| 10 ++ interface.h| 4 proto.c| 1 + system-linux.c | 28 ++-- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/interface-ip.c b/interface-ip.c index e265563..f88162b 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -90,16 +90,19 @@ match_if_addr(union if_addr *a1, union if_addr *a2, int mask) return !memcmp(p1, p2, sizeof(*p1)); } -static int set_ipv6_source_policy(bool add, const union if_addr *addr, uint8_t mask, int ifindex) +static int set_ip_source_policy(bool add, bool v4, const union if_addr *addr, +uint8_t mask, int ifindex, unsigned int table) { struct iprule rule = { - .flags = IPRULE_INET6 | IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, + .flags = IPRULE_SRC | IPRULE_LOOKUP | IPRULE_PRIORITY, .priority = 65535, - .lookup = interface_ip_resolve_v6_rtable(ifindex), + .lookup = table, .src_addr = *addr, .src_mask = mask, }; + rule.flags |= (v4) ? IPRULE_INET4 : IPRULE_INET6; + return (add) ? system_add_iprule(&rule) : system_del_iprule(&rule); } @@ -267,6 +270,7 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) if (!route) return; + route->iface = iface; route->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4; route->mask = v6 ? 128 : 32; if ((cur = tb[ROUTE_MASK]) != NULL) { @@ -433,8 +437,11 @@ interface_update_proto_addr(struct vlist_tree *tree, if (!(a_old->flags & DEVADDR_EXTERNAL) && a_old->enabled && !keep) { interface_handle_subnet_route(iface, a_old, false); - if ((a_old->flags & DEVADDR_FAMILY) == DEVADDR_INET6) - set_ipv6_source_policy(false, &a_old->addr, a_old->mask, dev->ifindex); + if(iface->interface_table > 0){ + bool v4 = (a_old->flags & DEVADDR_FAMILY) == DEVADDR_INET4; + set_ip_source_policy(false, v4, &a_old->addr, a_old->mask, + dev->ifindex, iface->interface_table); + } system_del_address(dev, a_old); } @@ -446,8 +453,11 @@ interface_update_proto_addr(struct vlist_tree *tree, if (!(a_new->flags & DEVADDR_EXTERNAL) && !keep) { system_add_address(dev, a_new); - if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET6) - set_ipv6_source_policy(true, &a_new->addr, a_new->mask, dev->ifindex); + if(iface->interface_table > 0){ + bool v4 = (a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET4; + set_ip_source_policy(true, v4, &a_new->addr, a_new->mask, + dev->ifindex, iface->interface_table); + } if ((a_new->flags & DEVADDR_OFFLINK) || iface->metric) interface_handle_subnet_route(iface, a_new, true); @@ -758,8 +768,9 @@ interface_update_prefix(struct vlist_tree *tree, // Set null-route to avoid routing loops and set routing policy system_add_route(NULL, &route); if (prefix_new->iface) - set_ipv6_source_policy(true, &route.addr, route.mask, - prefix_new->iface->l3_dev.dev->ifindex); + set_ip_source_policy(true, false, &route.addr, route.mask, + prefix_new->iface->l3_dev.dev->ifindex, + prefix_new->iface->interface_table); inter