From 570302d28d18d47f095f864be161045e169b5941 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 13 May 2013 10:55:01 +0200 Subject: [PATCH] Add support for IPv6 and interface target-routes & dependencies Signed-off-by: Steven Barth --- dummy/netifd-proto.sh | 2 ++ interface-ip.c | 15 ++++++++++++--- interface-ip.h | 2 +- proto-shell.c | 28 ++++++++++++++++++++++------ ubus.c | 9 +++++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/dummy/netifd-proto.sh b/dummy/netifd-proto.sh index ae5a346..d8b540d 100755 --- a/dummy/netifd-proto.sh +++ b/dummy/netifd-proto.sh @@ -334,6 +334,7 @@ proto_set_available() { proto_add_host_dependency() { local interface="$1" local host="$2" + local ifname="$3" # execute in subshell to not taint callers env # see tickets #11046, #11545, #11570 @@ -341,6 +342,7 @@ proto_add_host_dependency() { json_init json_add_int action 6 json_add_string host "$host" + [ -n "$ifname" ] && json_add_string ifname "$ifname" _proto_notify "$interface" -S ) } diff --git a/interface-ip.c b/interface-ip.c index e0bcdc0..31842c4 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -170,9 +170,8 @@ interface_ip_find_route_target(struct interface *iface, union if_addr *a, } struct interface * -interface_ip_add_target_route(union if_addr *addr, bool v6) +interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface) { - struct interface *iface; struct device_route *route, *r_next = NULL; bool defaultroute_target = false; int addrsize = v6 ? sizeof(addr->in6) : sizeof(addr->in); @@ -188,7 +187,7 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) else memcpy(&route->addr, addr, addrsize); - vlist_for_each_element(&interfaces, iface, node) { + if (iface) { /* look for locally addressable target first */ if (interface_ip_find_addr_target(iface, addr, v6)) goto done; @@ -196,6 +195,16 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) /* do not stop at the first route, let the lookup compare * masks to find the best match */ interface_ip_find_route_target(iface, addr, v6, &r_next); + } else { + vlist_for_each_element(&interfaces, iface, node) { + /* look for locally addressable target first */ + if (interface_ip_find_addr_target(iface, addr, v6)) + goto done; + + /* do not stop at the first route, let the lookup compare + * masks to find the best match */ + interface_ip_find_route_target(iface, addr, v6, &r_next); + } } if (!r_next) { diff --git a/interface-ip.h b/interface-ip.h index cd6ec84..c2213fd 100644 --- a/interface-ip.h +++ b/interface-ip.h @@ -137,7 +137,7 @@ void interface_ip_flush(struct interface_ip_settings *ip); void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled); void interface_ip_update_metric(struct interface_ip_settings *ip, int metric); -struct interface *interface_ip_add_target_route(union if_addr *addr, bool v6); +struct interface *interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface); struct device_prefix* interface_ip_add_device_prefix(struct interface *iface, struct in6_addr *addr, uint8_t length, time_t valid_until, time_t preferred_until, diff --git a/proto-shell.c b/proto-shell.c index 02f1836..8bbc36e 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -58,6 +58,8 @@ struct proto_shell_dependency { union if_addr host; bool v6; + + char interface[]; }; struct proto_shell_state { @@ -105,12 +107,15 @@ proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface, static void proto_shell_update_host_dep(struct proto_shell_dependency *dep) { - struct interface *iface; + struct interface *iface = NULL; if (dep->dep.iface) goto out; - iface = interface_ip_add_target_route(&dep->host, dep->v6); + if (dep->interface[0]) + iface = vlist_find(&interfaces, dep->interface, iface, node); + + iface = interface_ip_add_target_route(&dep->host, dep->v6, iface); if (!iface) goto out; @@ -616,17 +621,28 @@ proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_att { struct proto_shell_dependency *dep; struct blob_attr *host = tb[NOTIFY_HOST]; + struct blob_attr *ifname = tb[NOTIFY_IFNAME]; + size_t ifnamelen = (ifname) ? blobmsg_data_len(ifname) : 1; if (!host) return UBUS_STATUS_INVALID_ARGUMENT; - dep = calloc(1, sizeof(*dep)); - if (!inet_pton(AF_INET, blobmsg_data(host), &dep->host)) { - free(dep); - return UBUS_STATUS_INVALID_ARGUMENT; + dep = calloc(1, sizeof(*dep) + ifnamelen); + if (inet_pton(AF_INET, blobmsg_data(host), &dep->host) < 1) { + if (inet_pton(AF_INET6, blobmsg_data(host), &dep->host) < 1) { + free(dep); + return UBUS_STATUS_INVALID_ARGUMENT; + } else { + dep->v6 = true; + } } dep->proto = state; + if (ifname) + memcpy(dep->interface, blobmsg_data(ifname), ifnamelen); + else + dep->interface[0] = 0; + dep->dep.cb = proto_shell_if_up_cb; interface_add_user(&dep->dep, NULL); list_add(&dep->list, &state->deps); diff --git a/ubus.c b/ubus.c index 0592399..774f9d1 100644 --- a/ubus.c +++ b/ubus.c @@ -50,12 +50,14 @@ netifd_handle_reload(struct ubus_context *ctx, struct ubus_object *obj, enum { HR_TARGET, HR_V6, + HR_INTERFACE, __HR_MAX }; static const struct blobmsg_policy route_policy[__HR_MAX] = { [HR_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, [HR_V6] = { .name = "v6", .type = BLOBMSG_TYPE_BOOL }, + [HR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, }; static int @@ -64,7 +66,7 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { struct blob_attr *tb[__HR_MAX]; - struct interface *iface; + struct interface *iface = NULL; union if_addr a; bool v6 = false; @@ -75,12 +77,15 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj, if (tb[HR_V6]) v6 = blobmsg_get_bool(tb[HR_V6]); + if (tb[HR_INTERFACE]) + iface = vlist_find(&interfaces, blobmsg_data(tb[HR_INTERFACE]), iface, node); + memset(&a, 0, sizeof(a)); if (!inet_pton(v6 ? AF_INET6 : AF_INET, blobmsg_data(tb[HR_TARGET]), &a)) return UBUS_STATUS_INVALID_ARGUMENT; - iface = interface_ip_add_target_route(&a, v6); + iface = interface_ip_add_target_route(&a, v6, iface); if (!iface) return UBUS_STATUS_NOT_FOUND; -- 2.11.0