From: Felix Fietkau Date: Wed, 19 Oct 2011 18:51:57 +0000 (+0200) Subject: rework route handling, move parser code to interface-ip.c, add extra options and... X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=33a44b9c7d5e8c87303b8126fe9e01f8979f48e5;p=oweals%2Fnetifd.git rework route handling, move parser code to interface-ip.c, add extra options and add further support for pulling routes from config --- diff --git a/dummy/netifd-proto.sh b/dummy/netifd-proto.sh index 2a6a393..3ab69d8 100755 --- a/dummy/netifd-proto.sh +++ b/dummy/netifd-proto.sh @@ -110,7 +110,7 @@ _proto_push_route() { json_add_object "" json_add_string target "$target" - json_add_string mask "$mask" + json_add_string netmask "$mask" json_add_string gateway "$gw" json_close_object } diff --git a/interface-ip.c b/interface-ip.c index b875f50..571bb32 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -13,6 +13,96 @@ #include "ubus.h" #include "system.h" +enum { + ROUTE_INTERFACE, + ROUTE_TARGET, + ROUTE_MASK, + ROUTE_GATEWAY, + ROUTE_DEVICE, + ROUTE_METRIC, + ROUTE_MTU, + __ROUTE_LAST +}; + +static const struct blobmsg_policy route_attr[__ROUTE_LAST] = { + [ROUTE_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_MASK] = { .name = "netmask", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_GATEWAY] = { .name = "gateway", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_METRIC] = { .name = "metric", .type = BLOBMSG_TYPE_INT32 }, + [ROUTE_MTU] = { .name = "mtu", .type = BLOBMSG_TYPE_INT32 }, +}; + +void +interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) +{ + struct interface_ip_settings *ip; + struct blob_attr *tb[__ROUTE_LAST], *cur; + struct device_route *route; + int af = v6 ? AF_INET6 : AF_INET; + bool config = false; + + blobmsg_parse(route_attr, __ROUTE_LAST, tb, blobmsg_data(attr), blobmsg_data_len(attr)); + + if (!tb[ROUTE_GATEWAY] && !tb[ROUTE_DEVICE]) + return; + + if (!iface) { + if ((cur = tb[ROUTE_INTERFACE]) == NULL) + return; + + iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node); + if (!iface) + return; + + ip = &iface->config_ip; + config = true; + } else { + ip = &iface->proto_ip; + } + + route = calloc(1, sizeof(*route)); + if (!route) + return; + + route->mask = v6 ? 128 : 32; + if ((cur = tb[ROUTE_MASK]) != NULL) { + route->mask = parse_netmask_string(blobmsg_data(cur), v6); + if (route->mask > (v6 ? 128 : 32)) + goto error; + } + + if ((cur = tb[ROUTE_TARGET]) != NULL) { + if (!inet_pton(af, blobmsg_data(cur), &route->addr)) { + DPRINTF("Failed to parse route target: %s\n", (char *) blobmsg_data(cur)); + goto error; + } + } + + if ((cur = tb[ROUTE_GATEWAY]) != NULL) { + if (!inet_pton(af, blobmsg_data(cur), &route->nexthop)) { + DPRINTF("Failed to parse route gateway: %s\n", (char *) blobmsg_data(cur)); + goto error; + } + } + + if ((cur = tb[ROUTE_METRIC]) != NULL) + route->metric = blobmsg_get_u32(cur); + + if ((cur = tb[ROUTE_MTU]) != NULL) + route->mtu = blobmsg_get_u32(cur); + + if (!config && (cur = tb[ROUTE_DEVICE]) != NULL) + route->device = device_get(blobmsg_data(cur), true); + + vlist_add(&ip->route, &route->node); + return; + +error: + free(route); +} + static int addr_cmp(const void *k1, const void *k2, void *ptr) { @@ -43,7 +133,7 @@ interface_update_proto_addr(struct vlist_tree *tree, if (node_old) { addr = container_of(node_old, struct device_addr, node); - if (!(addr->flags & DEVADDR_EXTERNAL)) + if (!(addr->flags & DEVADDR_EXTERNAL) && addr->enabled) system_del_address(dev, addr); free(addr); } @@ -52,6 +142,7 @@ interface_update_proto_addr(struct vlist_tree *tree, addr = container_of(node_new, struct device_addr, node); if (!(addr->flags & DEVADDR_EXTERNAL)) system_add_address(dev, addr); + addr->enabled = true; } } @@ -71,7 +162,7 @@ interface_update_proto_route(struct vlist_tree *tree, if (node_old) { route = container_of(node_old, struct device_route, node); - if (!(route->flags & DEVADDR_EXTERNAL)) + if (!(route->flags & DEVADDR_EXTERNAL) && route->enabled) system_del_route(dev, route); free(route); } @@ -80,6 +171,7 @@ interface_update_proto_route(struct vlist_tree *tree, route = container_of(node_new, struct device_route, node); if (!(route->flags & DEVADDR_EXTERNAL)) system_add_route(dev, route); + route->enabled = true; } } @@ -224,6 +316,40 @@ interface_write_resolv_conf(void) } } +void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) +{ + struct device_addr *addr; + struct device_route *route; + struct device *dev; + + ip->enabled = enabled; + dev = ip->iface->l3_dev->dev; + if (!dev) + return; + + vlist_for_each_element(&ip->addr, addr, node) { + if (addr->enabled == enabled) + continue; + + if (enabled) + system_add_address(dev, addr); + else + system_del_address(dev, addr); + addr->enabled = enabled; + } + + vlist_for_each_element(&ip->route, route, node) { + if (route->enabled == enabled) + continue; + + if (enabled) + system_add_route(dev, route); + else + system_del_route(dev, route); + route->enabled = enabled; + } +} + void interface_ip_update_start(struct interface_ip_settings *ip) { @@ -253,6 +379,7 @@ void interface_ip_init(struct interface_ip_settings *ip, struct interface *iface) { ip->iface = iface; + ip->enabled = true; INIT_LIST_HEAD(&ip->dns_search); INIT_LIST_HEAD(&ip->dns_servers); vlist_init(&ip->route, route_cmp, interface_update_proto_route, diff --git a/interface-ip.h b/interface-ip.h index 4a1776d..13cd10c 100644 --- a/interface-ip.h +++ b/interface-ip.h @@ -25,6 +25,9 @@ struct device_addr { struct vlist_node node; enum device_addr_flags flags; + bool enabled; + + struct device *device; /* must be last */ unsigned int mask; @@ -35,10 +38,13 @@ struct device_route { struct vlist_node node; enum device_addr_flags flags; + bool enabled; bool keep; union if_addr nexthop; struct device *device; + int metric; + int mtu; /* must be last */ unsigned int mask; @@ -62,9 +68,12 @@ void interface_add_dns_server_list(struct interface_ip_settings *ip, struct blob void interface_add_dns_search_list(struct interface_ip_settings *ip, struct blob_attr *list); void interface_write_resolv_conf(void); +void interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6); + void interface_ip_update_start(struct interface_ip_settings *ip); void interface_ip_update_complete(struct interface_ip_settings *ip); void interface_ip_flush(struct interface_ip_settings *ip); +void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled); #endif diff --git a/interface.c b/interface.c index 11b629a..f5d8821 100644 --- a/interface.c +++ b/interface.c @@ -217,6 +217,7 @@ interface_cleanup(struct interface *iface) list_for_each_entry_safe(dep, tmp, &iface->users, list) interface_remove_user(dep); + interface_ip_flush(&iface->config_ip); interface_flush_state(iface); interface_clear_errors(iface); if (iface->main_dev.dev) @@ -272,6 +273,7 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve if (iface->state != IFS_SETUP) return; + interface_ip_set_enabled(&iface->config_ip, true); system_flush_routes(); iface->state = IFS_UP; iface->start_time = system_get_rtime(); @@ -284,6 +286,7 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve return; netifd_log_message(L_NOTICE, "Interface '%s' is now down\n", iface->name); + interface_ip_set_enabled(&iface->config_ip, false); system_flush_routes(); mark_interface_down(iface); interface_handle_config_change(iface); @@ -331,6 +334,8 @@ interface_init(struct interface *iface, const char *name, INIT_LIST_HEAD(&iface->users); INIT_LIST_HEAD(&iface->hotplug_list); interface_ip_init(&iface->proto_ip, iface); + interface_ip_init(&iface->config_ip, iface); + iface->config_ip.enabled = false; iface->main_dev.cb = interface_cb; iface->l3_dev = &iface->main_dev; @@ -447,6 +452,24 @@ set_config_state(struct interface *iface, enum interface_config_state s) __interface_set_down(iface, false); } +void +interface_update_start(struct interface *iface) +{ + interface_ip_update_start(&iface->proto_ip); +} + +void +interface_update_complete(struct interface *iface) +{ + struct device_route *route; + + interface_ip_update_complete(&iface->proto_ip); + vlist_for_each_element(&iface->config_ip.route, route, node) { + if (iface->l3_dev->dev) + system_add_route(iface->l3_dev->dev, route); + } +} + static void interface_change_config(struct interface *if_old, struct interface *if_new) { diff --git a/interface.h b/interface.h index 598774b..3ce4c99 100644 --- a/interface.h +++ b/interface.h @@ -41,6 +41,7 @@ struct interface_user { struct interface_ip_settings { struct interface *iface; + bool enabled; struct vlist_tree addr; struct vlist_tree route; @@ -83,6 +84,7 @@ struct interface { struct interface_proto_state *proto; struct interface_ip_settings proto_ip; + struct interface_ip_settings config_ip; /* errors/warnings while trying to bring up the interface */ struct list_head errors; @@ -116,6 +118,9 @@ void interface_remove_link(struct interface *iface, struct device *llif); void interface_add_error(struct interface *iface, const char *subsystem, const char *code, const char **data, int n_data); +void interface_update_start(struct interface *iface); +void interface_update_complete(struct interface *iface); + void interface_queue_event(struct interface *iface, enum interface_event ev); void interface_dequeue_event(struct interface *iface); diff --git a/proto-shell.c b/proto-shell.c index ae4ebd3..eb60fc1 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -187,70 +187,8 @@ proto_shell_parse_addr_list(struct interface_ip_settings *ip, struct blob_attr * } } -enum { - ROUTE_TARGET, - ROUTE_MASK, - ROUTE_GATEWAY, - ROUTE_DEVICE, - __ROUTE_LAST -}; - -static const struct blobmsg_policy route_attr[__ROUTE_LAST] = { - [ROUTE_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, - [ROUTE_MASK] = { .name = "mask", .type = BLOBMSG_TYPE_STRING }, - [ROUTE_GATEWAY] = { .name = "gateway", .type = BLOBMSG_TYPE_STRING }, - [ROUTE_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, -}; - -static void -parse_route(struct interface_ip_settings *ip, struct blob_attr *attr, bool v6) -{ - struct blob_attr *tb[__ROUTE_LAST], *cur; - struct device_route *route; - int af = v6 ? AF_INET6 : AF_INET; - - blobmsg_parse(route_attr, __ROUTE_LAST, tb, blobmsg_data(attr), blobmsg_data_len(attr)); - - if (!tb[ROUTE_GATEWAY] && !tb[ROUTE_DEVICE]) - return; - - route = calloc(1, sizeof(*route)); - if (!route) - return; - - route->mask = v6 ? 128 : 32; - if ((cur = tb[ROUTE_MASK]) != NULL) { - route->mask = parse_netmask_string(blobmsg_data(cur), v6); - if (route->mask > (v6 ? 128 : 32)) - goto error; - } - - if ((cur = tb[ROUTE_TARGET]) != NULL) { - if (!inet_pton(af, blobmsg_data(cur), &route->addr)) { - DPRINTF("Failed to parse route target: %s\n", (char *) blobmsg_data(cur)); - goto error; - } - } - - if ((cur = tb[ROUTE_GATEWAY]) != NULL) { - if (!inet_pton(af, blobmsg_data(cur), &route->nexthop)) { - DPRINTF("Failed to parse route gateway: %s\n", (char *) blobmsg_data(cur)); - goto error; - } - } - - if ((cur = tb[ROUTE_DEVICE]) != NULL) - route->device = device_get(blobmsg_data(cur), true); - - vlist_add(&ip->route, &route->node); - return; - -error: - free(route); -} - static void -proto_shell_parse_route_list(struct interface_ip_settings *ip, struct blob_attr *attr, +proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr, bool v6) { struct blob_attr *cur; @@ -262,7 +200,7 @@ proto_shell_parse_route_list(struct interface_ip_settings *ip, struct blob_attr continue; } - parse_route(ip, cur, v6); + interface_ip_add_route(iface, cur, v6); } } @@ -330,7 +268,7 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr **tb) } ip = &state->proto.iface->proto_ip; - interface_ip_update_start(ip); + interface_update_start(state->proto.iface); if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) addr_ext = blobmsg_get_bool(cur); @@ -342,10 +280,10 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr **tb) proto_shell_parse_addr_list(ip, cur, true, addr_ext); if ((cur = tb[NOTIFY_ROUTES]) != NULL) - proto_shell_parse_route_list(ip, cur, false); + proto_shell_parse_route_list(state->proto.iface, cur, false); if ((cur = tb[NOTIFY_ROUTES6]) != NULL) - proto_shell_parse_route_list(ip, cur, true); + proto_shell_parse_route_list(state->proto.iface, cur, true); if ((cur = tb[NOTIFY_DNS]) != NULL) interface_add_dns_server_list(ip, cur); @@ -353,7 +291,7 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr **tb) if ((cur = tb[NOTIFY_DNS_SEARCH]) != NULL) interface_add_dns_search_list(ip, cur); - interface_ip_update_complete(ip); + interface_update_complete(state->proto.iface); state->proto.proto_event(&state->proto, IFPEV_UP); diff --git a/system-linux.c b/system-linux.c index e313cbc..2a85b28 100644 --- a/system-linux.c +++ b/system-linux.c @@ -562,7 +562,17 @@ static int system_addr(struct device *dev, struct device_addr *addr, int cmd) .ifa_index = dev->ifindex, }; - struct nl_msg *msg = nlmsg_alloc_simple(cmd, 0); + struct nl_msg *msg; + + dev = addr->device; + if (dev) { + if (!dev->ifindex) + return -1; + + ifa.ifa_index = dev->ifindex; + } + + msg = nlmsg_alloc_simple(cmd, 0); if (!msg) return -1; @@ -586,6 +596,7 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) int alen = ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16; bool have_gw; unsigned int flags = 0; + int ifindex = dev->ifindex; if (alen == 4) have_gw = !!route->nexthop.in.s_addr; @@ -606,11 +617,20 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) .rtm_scope = scope, .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST, }; + struct nl_msg *msg; if (cmd == RTM_NEWROUTE) flags |= NLM_F_CREATE | NLM_F_REPLACE; - struct nl_msg *msg = nlmsg_alloc_simple(cmd, flags); + dev = route->device; + if (dev) { + if (!dev->ifindex) + return -1; + + ifindex = dev->ifindex; + } + + msg = nlmsg_alloc_simple(cmd, flags); if (!msg) return -1; @@ -623,7 +643,7 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) nla_put(msg, RTA_GATEWAY, alen, &route->nexthop); if (route->flags & DEVADDR_DEVICE) - nla_put_u32(msg, RTA_OIF, dev->ifindex); + nla_put_u32(msg, RTA_OIF, ifindex); return system_rtnl_call(msg); } diff --git a/utils.h b/utils.h index 6500fdf..cbb5775 100644 --- a/utils.h +++ b/utils.h @@ -34,6 +34,9 @@ void __vlist_init(struct vlist_tree *tree, avl_tree_comp cmp, vlist_update_cb up #define vlist_init(tree, cmp, update, type, node, key) \ __vlist_init(tree, cmp, update, offsetof(type, key) - offsetof(type, node)) +#define vlist_find(tree, name, element, node_member) \ + avl_find_element(&(tree)->avl, name, element, node_member.avl) + static inline void vlist_update(struct vlist_tree *tree) { tree->version++;