diff --git a/bsp/buildroot_external/package/netifd/netifd.mk b/bsp/buildroot_external/package/netifd/netifd.mk index 32410739..0e25a1de 100644 --- a/bsp/buildroot_external/package/netifd/netifd.mk +++ b/bsp/buildroot_external/package/netifd/netifd.mk @@ -4,7 +4,7 @@ # ################################################################################ -NETIFD_VERSION:= 2016.06.06 +NETIFD_VERSION:= 2017.01.25 NETIFD_SITE = $(TOPDIR)/../../src/3P/netifd/builders/cmake NETIFD_SITE_METHOD = local diff --git a/src/3P/netifd/CMakeLists.txt b/src/3P/netifd/CMakeLists.txt index 85527bec..1f35d260 100644 --- a/src/3P/netifd/CMakeLists.txt +++ b/src/3P/netifd/CMakeLists.txt @@ -5,11 +5,6 @@ ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -Wmissing-declarations) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -IF(APPLE) - INCLUDE_DIRECTORIES(/opt/local/include) - LINK_DIRECTORIES(/opt/local/lib) -ENDIF() - SET(SOURCES main.c utils.c system.c tunnel.c handler.c interface.c interface-ip.c interface-event.c diff --git a/src/3P/netifd/alias.c b/src/3P/netifd/alias.c index 6b938ca0..649f2d13 100644 --- a/src/3P/netifd/alias.c +++ b/src/3P/netifd/alias.c @@ -30,8 +30,6 @@ struct alias_device { char name[]; }; -static const struct device_type alias_device_type; - static void alias_set_device(struct alias_device *alias, struct device *dev) { if (dev == alias->dep.dev) { @@ -61,8 +59,10 @@ static void alias_set_device(struct alias_device *alias, struct device *dev) device_set_ifindex(&alias->dev, dev->ifindex); device_set_ifname(&alias->dev, dev->ifname); device_add_user(&alias->dep, dev); - } else + } else { device_set_ifname(&alias->dev, ""); + device_set_link(&alias->dev, false); + } } static int @@ -111,7 +111,8 @@ static void alias_device_cb(struct device_user *dep, enum device_event ev) } static struct device * -alias_device_create(const char *name, struct blob_attr *attr) +alias_device_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct alias_device *alias; @@ -122,7 +123,7 @@ alias_device_create(const char *name, struct blob_attr *attr) strcpy(alias->name, name); alias->dev.set_state = alias_device_set_state; alias->dev.hidden = true; - device_init_virtual(&alias->dev, &alias_device_type, NULL); + device_init_virtual(&alias->dev, devtype, NULL); alias->avl.key = alias->name; avl_insert(&aliases, &alias->avl); alias->dep.alias = true; @@ -160,7 +161,7 @@ static int alias_check_state(struct device *dev) return 0; } -static const struct device_type alias_device_type = { +static struct device_type alias_device_type = { .name = "Network alias", .create = alias_device_create, .free = alias_device_free, @@ -190,7 +191,7 @@ device_alias_get(const char *name) if (alias) return &alias->dev; - return alias_device_create(name, NULL); + return alias_device_create(name, &alias_device_type, NULL); } static void __init alias_init(void) diff --git a/src/3P/netifd/bridge.c b/src/3P/netifd/bridge.c index 1c163cd9..c46d44e2 100644 --- a/src/3P/netifd/bridge.c +++ b/src/3P/netifd/bridge.c @@ -72,17 +72,21 @@ static const struct uci_blob_param_list bridge_attr_list = { .next = { &device_attr_list }, }; -static struct device *bridge_create(const char *name, struct blob_attr *attr); +static struct device *bridge_create(const char *name, struct device_type *devtype, + struct blob_attr *attr); static void bridge_config_init(struct device *dev); static void bridge_free(struct device *dev); static void bridge_dump_info(struct device *dev, struct blob_buf *b); enum dev_change_type bridge_reload(struct device *dev, struct blob_attr *attr); -const struct device_type bridge_device_type = { - .name = "Bridge", +static struct device_type bridge_device_type = { + .name = "bridge", .config_params = &bridge_attr_list, + .bridge_capability = true, + .name_prefix = "br", + .create = bridge_create, .config_init = bridge_config_init, .reload = bridge_reload, @@ -390,24 +394,25 @@ bridge_set_state(struct device *dev, bool up) } static struct bridge_member * -bridge_create_member(struct bridge_state *bst, struct device *dev, bool hotplug) +bridge_create_member(struct bridge_state *bst, const char *name, + struct device *dev, bool hotplug) { struct bridge_member *bm; - bm = calloc(1, sizeof(*bm) + strlen(dev->ifname) + 1); + bm = calloc(1, sizeof(*bm) + strlen(name) + 1); if (!bm) return NULL; bm->bst = bst; bm->dev.cb = bridge_member_cb; bm->dev.hotplug = hotplug; - strcpy(bm->name, dev->ifname); + strcpy(bm->name, name); bm->dev.dev = dev; vlist_add(&bst->members, &bm->node, bm->name); // Need to look up the bridge member again as the above // created pointer will be freed in case the bridge member // already existed - bm = vlist_find(&bst->members, dev->ifname, bm, node); + bm = vlist_find(&bst->members, name, bm, node); if (hotplug && bm) bm->node.version = -1; @@ -451,7 +456,7 @@ bridge_add_member(struct bridge_state *bst, const char *name) if (!dev) return; - bridge_create_member(bst, dev, false); + bridge_create_member(bst, name, dev, false); } static int @@ -459,7 +464,7 @@ bridge_hotplug_add(struct device *dev, struct device *member) { struct bridge_state *bst = container_of(dev, struct bridge_state, dev); - bridge_create_member(bst, member, true); + bridge_create_member(bst, member->ifname, member, true); return 0; } @@ -519,8 +524,12 @@ bridge_dump_info(struct device *dev, struct blob_buf *b) system_if_dump_info(dev, b); list = blobmsg_open_array(b, "bridge-members"); - vlist_for_each_element(&bst->members, bm, node) + vlist_for_each_element(&bst->members, bm, node) { + if (bm->dev.dev->hidden) + continue; + blobmsg_add_string(b, NULL, bm->dev.dev->ifname); + } blobmsg_close_array(b, list); } @@ -559,8 +568,6 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) /* defaults */ cfg->stp = false; cfg->forward_delay = 2; - cfg->igmp_snoop = true; - cfg->multicast_querier = true; cfg->robustness = 2; cfg->query_interval = 12500; cfg->query_response_interval = 1000; @@ -646,6 +653,9 @@ bridge_reload(struct device *dev, struct blob_attr *attr) blobmsg_parse(bridge_attrs, __BRIDGE_ATTR_MAX, tb_br, blob_data(attr), blob_len(attr)); + if (tb_dev[DEV_ATTR_MACADDR]) + bst->primary_port = NULL; + bst->ifnames = tb_br[BRIDGE_ATTR_IFNAME]; device_init_settings(dev, tb_dev); bridge_apply_settings(bst, tb_br); @@ -699,7 +709,8 @@ bridge_retry_members(struct uloop_timeout *timeout) } static struct device * -bridge_create(const char *name, struct blob_attr *attr) +bridge_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct bridge_state *bst; struct device *dev = NULL; @@ -709,7 +720,7 @@ bridge_create(const char *name, struct blob_attr *attr) return NULL; dev = &bst->dev; - device_init(dev, &bridge_device_type, name); + device_init(dev, devtype, name); dev->config_pending = true; bst->retry.cb = bridge_retry_members; @@ -724,3 +735,8 @@ bridge_create(const char *name, struct blob_attr *attr) return dev; } + +static void __init bridge_device_type_init(void) +{ + device_type_add(&bridge_device_type); +} diff --git a/src/3P/netifd/config.c b/src/3P/netifd/config.c index be2fa150..0d965d33 100644 --- a/src/3P/netifd/config.c +++ b/src/3P/netifd/config.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include "netifd.h" #include "interface.h" @@ -53,18 +53,18 @@ config_section_idx(struct uci_section *s) } static int -config_parse_bridge_interface(struct uci_section *s) +config_parse_bridge_interface(struct uci_section *s, struct device_type *devtype) { char *name; - name = alloca(strlen(s->e.name) + 4); - sprintf(name, "br-%s", s->e.name); + name = alloca(strlen(s->e.name) + strlen(devtype->name_prefix) + 2); + sprintf(name, "%s-%s", devtype->name_prefix, s->e.name); blobmsg_add_string(&b, "name", name); - uci_to_blob(&b, s, bridge_device_type.config_params); - if (!device_create(name, &bridge_device_type, b.head)) { - D(INTERFACE, "Failed to create bridge for interface '%s'\n", s->e.name); - return -EINVAL; + uci_to_blob(&b, s, devtype->config_params); + if (!device_create(name, devtype, b.head)) { + D(INTERFACE, "Failed to create '%s' device for interface '%s'\n", + devtype->name, s->e.name); } blob_buf_init(&b, 0); @@ -79,6 +79,7 @@ config_parse_interface(struct uci_section *s, bool alias) const char *type = NULL, *disabled; struct blob_attr *config; bool bridge = false; + struct device_type *devtype = NULL; disabled = uci_lookup_option_string(uci_ctx, s, "disabled"); if (disabled && !strcmp(disabled, "1")) @@ -88,8 +89,12 @@ config_parse_interface(struct uci_section *s, bool alias) if (!alias) type = uci_lookup_option_string(uci_ctx, s, "type"); - if (type && !strcmp(type, "bridge")) { - if (config_parse_bridge_interface(s)) + + if (type) + devtype = device_type_get(type); + + if (devtype && devtype->bridge_capability) { + if (config_parse_bridge_interface(s, devtype)) return; bridge = true; @@ -157,7 +162,7 @@ config_init_devices(void) uci_foreach_element(&uci_network->sections, e) { const struct uci_blob_param_list *params = NULL; struct uci_section *s = uci_to_section(e); - const struct device_type *devtype = NULL; + struct device_type *devtype = NULL; struct device *dev; const char *type, *name; @@ -169,18 +174,8 @@ config_init_devices(void) continue; type = uci_lookup_option_string(uci_ctx, s, "type"); - if (type) { - if (!strcmp(type, "8021ad")) - devtype = &vlandev_device_type; - else if (!strcmp(type, "8021q")) - devtype = &vlandev_device_type; - else if (!strcmp(type, "bridge")) - devtype = &bridge_device_type; - else if (!strcmp(type, "macvlan")) - devtype = &macvlan_device_type; - else if (!strcmp(type, "tunnel")) - devtype = &tunnel_device_type; - } + if (type) + devtype = device_type_get(type); if (devtype) params = devtype->config_params; diff --git a/src/3P/netifd/config.h b/src/3P/netifd/config.h index b29e94a5..5adaca6d 100644 --- a/src/3P/netifd/config.h +++ b/src/3P/netifd/config.h @@ -15,7 +15,7 @@ #define __NETIFD_CONFIG_H #include -#include +#include extern bool config_init; diff --git a/src/3P/netifd/device.c b/src/3P/netifd/device.c index fa3d00fe..43881e5f 100644 --- a/src/3P/netifd/device.c +++ b/src/3P/netifd/device.c @@ -24,10 +24,13 @@ #include #endif +#include + #include "netifd.h" #include "system.h" #include "config.h" +static struct list_head devtypes = LIST_HEAD_INIT(devtypes); static struct avl_tree devices; static bool default_ps = true; @@ -51,9 +54,11 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = { [DEV_ATTR_DADTRANSMITS] = { .name = "dadtransmits", .type = BLOBMSG_TYPE_INT32 }, [DEV_ATTR_MULTICAST_TO_UNICAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL }, [DEV_ATTR_MULTICAST_ROUTER] = { .name = "multicast_router", .type = BLOBMSG_TYPE_INT32 }, + [DEV_ATTR_MULTICAST_FAST_LEAVE] = { .name = "multicast_fast_leave", . type = BLOBMSG_TYPE_BOOL }, [DEV_ATTR_MULTICAST] = { .name ="multicast", .type = BLOBMSG_TYPE_BOOL }, [DEV_ATTR_LEARNING] = { .name ="learning", .type = BLOBMSG_TYPE_BOOL }, [DEV_ATTR_UNICAST_FLOOD] = { .name ="unicast_flood", .type = BLOBMSG_TYPE_BOOL }, + [DEV_ATTR_SENDREDIRECTS] = { .name = "sendredirects", .type = BLOBMSG_TYPE_BOOL }, }; const struct uci_blob_param_list device_attr_list = { @@ -63,6 +68,36 @@ const struct uci_blob_param_list device_attr_list = { static int __devlock = 0; +int device_type_add(struct device_type *devtype) +{ + if (device_type_get(devtype->name)) { + netifd_log_message(L_WARNING, "Device handler '%s' already exists\n", + devtype->name); + return 1; + } + + netifd_log_message(L_NOTICE, "Added device handler type: %s\n", + devtype->name); + + list_add(&devtype->list, &devtypes); + return 0; +} + +/* Retrieve the device type for the given name. If 'bridge' is true, the type + * must have bridge capabilities + */ +struct device_type * +device_type_get(const char *tname) +{ + struct device_type *cur; + + list_for_each_entry(cur, &devtypes, list) + if (!strcmp(cur->name, tname)) + return cur; + + return NULL; +} + void device_lock(void) { __devlock++; @@ -118,11 +153,15 @@ simple_device_set_state(struct device *dev, bool state) } static struct device * -simple_device_create(const char *name, struct blob_attr *attr) +simple_device_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct blob_attr *tb[__DEV_ATTR_MAX]; struct device *dev = NULL; + /* device type is unused for simple devices */ + devtype = NULL; + blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, blob_data(attr), blob_len(attr)); dev = device_get(name, true); if (!dev) @@ -141,7 +180,7 @@ static void simple_device_free(struct device *dev) free(dev); } -const struct device_type simple_device_type = { +struct device_type simple_device_type = { .name = "Network device", .config_params = &device_attr_list, @@ -184,8 +223,11 @@ device_merge_settings(struct device *dev, struct device_settings *n) s->multicast : os->multicast; n->multicast_to_unicast = s->multicast_to_unicast; n->multicast_router = s->multicast_router; + n->multicast_fast_leave = s->multicast_fast_leave; n->learning = s->learning; n->unicast_flood = s->unicast_flood; + n->sendredirects = s->flags & DEV_OPT_SENDREDIRECTS ? + s->sendredirects : os->sendredirects; n->flags = s->flags | os->flags | os->valid_flags; } @@ -201,12 +243,12 @@ device_init_settings(struct device *dev, struct blob_attr **tb) if ((cur = tb[DEV_ATTR_ENABLED])) disabled = !blobmsg_get_bool(cur); - if ((cur = tb[DEV_ATTR_MTU])) { + if ((cur = tb[DEV_ATTR_MTU]) && blobmsg_get_u32(cur) >= 68) { s->mtu = blobmsg_get_u32(cur); s->flags |= DEV_OPT_MTU; } - if ((cur = tb[DEV_ATTR_MTU6])) { + if ((cur = tb[DEV_ATTR_MTU6]) && blobmsg_get_u32(cur) >= 1280) { s->mtu6 = blobmsg_get_u32(cur); s->flags |= DEV_OPT_MTU6; } @@ -304,6 +346,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb) DPRINTF("Invalid value: %d - (Use 0: never, 1: learn, 2: always)\n", blobmsg_get_u32(cur)); } + if ((cur = tb[DEV_ATTR_MULTICAST_FAST_LEAVE])) { + s->multicast_fast_leave = blobmsg_get_bool(cur); + s->flags |= DEV_OPT_MULTICAST_FAST_LEAVE; + } + if ((cur = tb[DEV_ATTR_MULTICAST])) { s->multicast = blobmsg_get_bool(cur); s->flags |= DEV_OPT_MULTICAST; @@ -319,6 +366,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb) s->flags |= DEV_OPT_UNICAST_FLOOD; } + if ((cur = tb[DEV_ATTR_SENDREDIRECTS])) { + s->sendredirects = blobmsg_get_bool(cur); + s->flags |= DEV_OPT_SENDREDIRECTS; + } + device_set_disabled(dev, disabled); } @@ -406,6 +458,10 @@ void device_release(struct device_user *dep) device_broadcast_event(dev, DEV_EVENT_TEARDOWN); if (!dev->external) dev->set_state(dev, false); + + if (dev->active) + return; + device_broadcast_event(dev, DEV_EVENT_DOWN); } @@ -417,7 +473,7 @@ int device_check_state(struct device *dev) return dev->type->check_state(dev); } -void device_init_virtual(struct device *dev, const struct device_type *type, const char *name) +void device_init_virtual(struct device *dev, struct device_type *type, const char *name) { assert(dev); assert(type); @@ -434,7 +490,7 @@ void device_init_virtual(struct device *dev, const struct device_type *type, con dev->set_state = set_device_state; } -int device_init(struct device *dev, const struct device_type *type, const char *ifname) +int device_init(struct device *dev, struct device_type *type, const char *ifname) { int ret; @@ -729,7 +785,7 @@ device_init_pending(void) } static enum dev_change_type -device_set_config(struct device *dev, const struct device_type *type, +device_set_config(struct device *dev, struct device_type *type, struct blob_attr *attr) { struct blob_attr *tb[__DEV_ATTR_MAX]; @@ -758,7 +814,7 @@ device_set_config(struct device *dev, const struct device_type *type, } enum dev_change_type -device_apply_config(struct device *dev, const struct device_type *type, +device_apply_config(struct device *dev, struct device_type *type, struct blob_attr *config) { enum dev_change_type change; @@ -883,13 +939,13 @@ device_set_default_ps(bool state) } struct device * -device_create(const char *name, const struct device_type *type, +device_create(const char *name, struct device_type *type, struct blob_attr *config) { struct device *odev = NULL, *dev; enum dev_change_type change; - odev = device_get(name, false); + odev = device_find(name); if (odev) { odev->current_config = true; change = device_apply_config(odev, type, config); @@ -908,7 +964,7 @@ device_create(const char *name, const struct device_type *type, if (!config) return NULL; - dev = type->create(name, config); + dev = type->create(name, type, config); if (!dev) return NULL; @@ -994,12 +1050,16 @@ device_dump_status(struct blob_buf *b, struct device *dev) blobmsg_add_u8(b, "multicast_to_unicast", st.multicast_to_unicast); if (st.flags & DEV_OPT_MULTICAST_ROUTER) blobmsg_add_u32(b, "multicast_router", st.multicast_router); + if (st.flags & DEV_OPT_MULTICAST_FAST_LEAVE) + blobmsg_add_u8(b, "multicast_fast_leave", st.multicast_fast_leave); if (st.flags & DEV_OPT_MULTICAST) blobmsg_add_u8(b, "multicast", st.multicast); if (st.flags & DEV_OPT_LEARNING) blobmsg_add_u8(b, "learning", st.learning); if (st.flags & DEV_OPT_UNICAST_FLOOD) blobmsg_add_u8(b, "unicast_flood", st.unicast_flood); + if (st.flags & DEV_OPT_SENDREDIRECTS) + blobmsg_add_u8(b, "sendredirects", st.sendredirects); } s = blobmsg_open_table(b, "statistics"); @@ -1009,3 +1069,8 @@ device_dump_status(struct blob_buf *b, struct device *dev) system_if_dump_stats(dev, b); blobmsg_close_table(b, s); } + +static void __init simple_device_type_init(void) +{ + device_type_add(&simple_device_type); +} diff --git a/src/3P/netifd/device.h b/src/3P/netifd/device.h index e13e4350..87236d42 100644 --- a/src/3P/netifd/device.h +++ b/src/3P/netifd/device.h @@ -19,6 +19,7 @@ #include struct device; +struct device_type; struct device_user; struct device_hotplug_ops; struct interface; @@ -44,10 +45,12 @@ enum { DEV_ATTR_DADTRANSMITS, DEV_ATTR_MULTICAST_TO_UNICAST, DEV_ATTR_MULTICAST_ROUTER, + DEV_ATTR_MULTICAST_FAST_LEAVE, DEV_ATTR_MULTICAST, DEV_ATTR_LEARNING, DEV_ATTR_UNICAST_FLOOD, DEV_ATTR_NEIGHGCSTALETIME, + DEV_ATTR_SENDREDIRECTS, __DEV_ATTR_MAX, }; @@ -62,9 +65,13 @@ struct device_type { struct list_head list; const char *name; + bool bridge_capability; + const char *name_prefix; + const struct uci_blob_param_list *config_params; - struct device *(*create)(const char *name, struct blob_attr *attr); + struct device *(*create)(const char *name, struct device_type *devtype, + struct blob_attr *attr); void (*config_init)(struct device *); enum dev_change_type (*reload)(struct device *, struct blob_attr *); void (*dump_info)(struct device *, struct blob_buf *buf); @@ -94,6 +101,8 @@ enum { DEV_OPT_LEARNING = (1 << 17), DEV_OPT_UNICAST_FLOOD = (1 << 18), DEV_OPT_NEIGHGCSTALETIME = (1 << 19), + DEV_OPT_MULTICAST_FAST_LEAVE = (1 << 20), + DEV_OPT_SENDREDIRECTS = (1 << 21), }; /* events broadcasted to all users of a device */ @@ -156,9 +165,11 @@ struct device_settings { unsigned int dadtransmits; bool multicast_to_unicast; unsigned int multicast_router; + bool multicast_fast_leave; bool multicast; bool learning; bool unicast_flood; + bool sendredirects; }; /* @@ -166,7 +177,7 @@ struct device_settings { * can be used to support VLANs as well */ struct device { - const struct device_type *type; + struct device_type *type; struct avl_node avl; struct safe_list users; @@ -217,30 +228,29 @@ struct device_hotplug_ops { }; extern const struct uci_blob_param_list device_attr_list; -extern const struct device_type simple_device_type; -extern const struct device_type bridge_device_type; -extern const struct device_type tunnel_device_type; -extern const struct device_type macvlan_device_type; -extern const struct device_type vlandev_device_type; +extern struct device_type simple_device_type; +extern struct device_type tunnel_device_type; void device_lock(void); void device_unlock(void); -struct device *device_create(const char *name, const struct device_type *type, +int device_type_add(struct device_type *devtype); +struct device_type *device_type_get(const char *tname); +struct device *device_create(const char *name, struct device_type *type, struct blob_attr *config); void device_init_settings(struct device *dev, struct blob_attr **tb); void device_init_pending(void); enum dev_change_type -device_apply_config(struct device *dev, const struct device_type *type, +device_apply_config(struct device *dev, struct device_type *type, struct blob_attr *config); void device_reset_config(void); void device_reset_old(void); void device_set_default_ps(bool state); -void device_init_virtual(struct device *dev, const struct device_type *type, const char *name); -int device_init(struct device *iface, const struct device_type *type, const char *ifname); +void device_init_virtual(struct device *dev, struct device_type *type, const char *name); +int device_init(struct device *iface, struct device_type *type, const char *ifname); void device_cleanup(struct device *dev); struct device *device_find(const char *name); struct device *device_get(const char *name, int create); diff --git a/src/3P/netifd/interface-event.c b/src/3P/netifd/interface-event.c index 3cdfbdbd..4976c2cf 100644 --- a/src/3P/netifd/interface-event.c +++ b/src/3P/netifd/interface-event.c @@ -30,7 +30,14 @@ static void task_complete(struct uloop_process *proc, int ret); static struct uloop_process task = { .cb = task_complete, }; -static const char * const eventnames[] = {"ifdown", "ifup", "ifupdate", "free", "reload"}; +static const char * const eventnames[] = { + [IFEV_DOWN] = "ifdown", + [IFEV_UP] = "ifup", + [IFEV_UPDATE] = "ifupdate", + [IFEV_FREE] = "free", + [IFEV_RELOAD] = "reload", + [IFEV_LINK_UP] = "iflink", +}; static void run_cmd(const char *ifname, const char *device, enum interface_event event, @@ -117,6 +124,10 @@ interface_queue_event(struct interface *iface, enum interface_event ev) netifd_ubus_interface_notify(iface, ev != IFEV_DOWN); + /* no hotplug.d calls for link up */ + if (ev == IFEV_LINK_UP) + return; + if (current == iface) { /* an event for iface is being processed */ if (!list_empty(&iface->hotplug_list)) { @@ -178,15 +189,17 @@ static void interface_event_cb(struct interface_user *dep, struct interface *ifa enum interface_event ev) { switch (ev) { + case IFEV_LINK_UP: case IFEV_UP: case IFEV_UPDATE: case IFEV_DOWN: interface_queue_event(iface, ev); break; case IFEV_FREE: - case IFEV_RELOAD: interface_dequeue_event(iface); break; + default: + break; } } diff --git a/src/3P/netifd/interface-ip.c b/src/3P/netifd/interface-ip.c index 26a28654..f8dab840 100644 --- a/src/3P/netifd/interface-ip.c +++ b/src/3P/netifd/interface-ip.c @@ -40,6 +40,7 @@ enum { ROUTE_SOURCE, ROUTE_ONLINK, ROUTE_TYPE, + ROUTE_PROTO, __ROUTE_MAX }; @@ -54,7 +55,8 @@ static const struct blobmsg_policy route_attr[__ROUTE_MAX] = { [ROUTE_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_INT32 }, [ROUTE_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING }, [ROUTE_ONLINK] = { .name = "onlink", .type = BLOBMSG_TYPE_BOOL }, - [ROUTE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING } + [ROUTE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, + [ROUTE_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }, }; const struct uci_blob_param_list route_attr_list = { @@ -405,6 +407,14 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) route->flags |= DEVROUTE_TYPE; } + if ((cur = tb[ROUTE_PROTO]) != NULL) { + if (!system_resolve_rt_proto(blobmsg_data(cur), &route->proto)) { + DPRINTF("Failed to resolve proto type: %s\n", (char *) blobmsg_data(cur)); + goto error; + } + route->flags |= DEVROUTE_PROTO; + } + interface_set_route_info(iface, route); vlist_add(&ip->route, &route->node, route); return; @@ -478,10 +488,13 @@ interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, memcpy(&r->addr, &addr->addr, sizeof(r->addr)); clear_if_addr(&r->addr, r->mask); - r->flags |= DEVADDR_KERNEL; + if (!system_resolve_rt_proto("kernel", &r->proto)) + return; + + r->flags |= DEVROUTE_PROTO; system_del_route(dev, r); - r->flags &= ~DEVADDR_KERNEL; + r->flags &= ~DEVROUTE_PROTO; interface_set_route_info(iface, r); system_add_route(dev, r); @@ -634,7 +647,7 @@ interface_update_proto_route(struct vlist_tree *tree, if (node_old && node_new) keep = !memcmp(&route_old->nexthop, &route_new->nexthop, sizeof(route_old->nexthop)) && (route_old->mtu == route_new->mtu) && (route_old->type == route_new->type) && - !route_old->failed; + (route_old->proto == route_new->proto) && !route_old->failed; if (node_old) { if (!(route_old->flags & DEVADDR_EXTERNAL) && route_old->enabled && !keep) @@ -1197,10 +1210,70 @@ write_resolv_conf_entries(FILE *f, struct interface_ip_settings *ip, const char } } +/* Sorting of interface resolver entries : */ +/* Primary on interface dns_metric : lowest metric first */ +/* Secondary on interface metric : lowest metric first */ +/* Finally alphabetical order of interface names */ +static int resolv_conf_iface_cmp(const void *k1, const void *k2, void *ptr) +{ + const struct interface *iface1 = k1, *iface2 = k2; + + if (iface1->dns_metric != iface2->dns_metric) + return iface1->dns_metric - iface2->dns_metric; + + if (iface1->metric != iface2->metric) + return iface1->metric - iface2->metric; + + return strcmp(iface1->name, iface2->name); +} + +static void +__interface_write_dns_entries(FILE *f) +{ + struct interface *iface; + struct { + struct avl_node node; + } *entry, *n_entry; + struct avl_tree resolv_conf_iface_entries; + + avl_init(&resolv_conf_iface_entries, resolv_conf_iface_cmp, false, NULL); + + vlist_for_each_element(&interfaces, iface, node) { + if (iface->state != IFS_UP) + continue; + + if (vlist_simple_empty(&iface->proto_ip.dns_search) && + vlist_simple_empty(&iface->proto_ip.dns_servers) && + vlist_simple_empty(&iface->config_ip.dns_search) && + vlist_simple_empty(&iface->config_ip.dns_servers)) + continue; + + entry = calloc(1, sizeof(*entry)); + if (!entry) + continue; + + entry->node.key = iface; + avl_insert(&resolv_conf_iface_entries, &entry->node); + } + + avl_for_each_element(&resolv_conf_iface_entries, entry, node) { + iface = (struct interface *)entry->node.key; + + fprintf(f, "# Interface %s\n", iface->name); + + write_resolv_conf_entries(f, &iface->config_ip, iface->ifname); + + if (!iface->proto_ip.no_dns) + write_resolv_conf_entries(f, &iface->proto_ip, iface->ifname); + } + + avl_remove_all_elements(&resolv_conf_iface_entries, entry, node, n_entry) + free(entry); +} + void interface_write_resolv_conf(void) { - struct interface *iface; char *path = alloca(strlen(resolv_conf) + 5); FILE *f; uint32_t crcold, crcnew; @@ -1213,21 +1286,8 @@ interface_write_resolv_conf(void) return; } - vlist_for_each_element(&interfaces, iface, node) { - if (iface->state != IFS_UP) - continue; + __interface_write_dns_entries(f); - if (vlist_simple_empty(&iface->proto_ip.dns_search) && - vlist_simple_empty(&iface->proto_ip.dns_servers) && - vlist_simple_empty(&iface->config_ip.dns_search) && - vlist_simple_empty(&iface->config_ip.dns_servers)) - continue; - - fprintf(f, "# Interface %s\n", iface->name); - write_resolv_conf_entries(f, &iface->config_ip, iface->ifname); - if (!iface->proto_ip.no_dns) - write_resolv_conf_entries(f, &iface->proto_ip, iface->ifname); - } fflush(f); rewind(f); crcnew = crc32_file(f); diff --git a/src/3P/netifd/interface-ip.h b/src/3P/netifd/interface-ip.h index bbef62ce..01727c9b 100644 --- a/src/3P/netifd/interface-ip.h +++ b/src/3P/netifd/interface-ip.h @@ -31,8 +31,8 @@ enum device_addr_flags { /* route overrides the default interface mtu */ DEVROUTE_MTU = (1 << 4), - /* route automatically added by kernel */ - DEVADDR_KERNEL = (1 << 5), + /* route overrides the default proto type */ + DEVROUTE_PROTO = (1 << 5), /* address is off-link (no subnet-route) */ DEVADDR_OFFLINK = (1 << 6), @@ -92,6 +92,7 @@ struct device_route { union if_addr nexthop; int mtu; unsigned int type; + unsigned int proto; time_t valid_until; /* must be last */ diff --git a/src/3P/netifd/interface.c b/src/3P/netifd/interface.c index 7b18cef5..a014111a 100644 --- a/src/3P/netifd/interface.c +++ b/src/3P/netifd/interface.c @@ -35,6 +35,7 @@ enum { IFACE_ATTR_PEERDNS, IFACE_ATTR_DNS, IFACE_ATTR_DNS_SEARCH, + IFACE_ATTR_DNS_METRIC, IFACE_ATTR_METRIC, IFACE_ATTR_INTERFACE, IFACE_ATTR_IP6ASSIGN, @@ -57,6 +58,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_METRIC] = { .name = "metric", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY }, + [IFACE_ATTR_DNS_METRIC] = { .name = "dns_metric", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_IP6ASSIGN] = { .name = "ip6assign", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_IP6HINT] = { .name = "ip6hint", .type = BLOBMSG_TYPE_STRING }, @@ -260,6 +262,7 @@ mark_interface_down(struct interface *iface) if (state == IFS_DOWN) return; + iface->link_up_event = false; iface->state = IFS_DOWN; if (state == IFS_UP) interface_event(iface, IFEV_DOWN); @@ -355,6 +358,11 @@ interface_set_link_state(struct interface *iface, bool new_state) netifd_log_message(L_NOTICE, "Interface '%s' has link connectivity %s\n", iface->name, new_state ? "" : "loss"); iface->link_state = new_state; interface_check_state(iface); + + if (new_state && iface->force_link && iface->state == IFS_UP && !iface->link_up_event) { + interface_event(iface, IFEV_LINK_UP); + iface->link_up_event = true; + } } static void @@ -408,7 +416,8 @@ interface_l3_dev_cb(struct device_user *dep, enum device_event ev) switch (ev) { case DEV_EVENT_LINK_DOWN: - interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false); + if (iface->proto_handler->flags & PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN) + interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false); break; default: break; @@ -550,8 +559,7 @@ interface_alias_cb(struct interface_user *dep, struct interface *iface, enum int case IFEV_FREE: interface_remove_user(dep); break; - case IFEV_RELOAD: - case IFEV_UPDATE: + default: break; } } @@ -580,6 +588,8 @@ interface_claim_device(struct interface *iface) if (iface->parent_iface.iface) interface_remove_user(&iface->parent_iface); + device_lock(); + if (iface->parent_ifname) { parent = vlist_find(&interfaces, iface->parent_ifname, parent, node); iface->parent_iface.cb = interface_alias_cb; @@ -595,6 +605,8 @@ interface_claim_device(struct interface *iface) if (dev) interface_set_main_dev(iface, dev); + device_unlock(); + if (iface->proto_handler->flags & PROTO_FLAG_INIT_AVAILABLE) interface_set_available(iface, true); } @@ -681,7 +693,8 @@ interface_proto_event_cb(struct interface_proto_state *state, enum interface_pro switch (ev) { case IFPEV_UP: if (iface->state != IFS_SETUP) { - interface_event(iface, IFEV_UPDATE); + if (iface->state == IFS_UP && iface->updated) + interface_event(iface, IFEV_UPDATE); return; } @@ -785,6 +798,9 @@ interface_alloc(const char *name, struct blob_attr *config) if ((cur = tb[IFACE_ATTR_DNS_SEARCH])) interface_add_dns_search_list(&iface->config_ip, cur); + if ((cur = tb[IFACE_ATTR_DNS_METRIC])) + iface->dns_metric = blobmsg_get_u32(cur); + if ((cur = tb[IFACE_ATTR_METRIC])) iface->metric = blobmsg_get_u32(cur); @@ -1076,10 +1092,12 @@ set_config_state(struct interface *iface, enum interface_config_state s) } void -interface_update_start(struct interface *iface) +interface_update_start(struct interface *iface, const bool keep_old) { iface->updated = 0; - interface_ip_update_start(&iface->proto_ip); + + if (!keep_old) + interface_ip_update_start(&iface->proto_ip); } void @@ -1175,6 +1193,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new) if_old->parent_ifname = if_new->parent_ifname; if_old->proto_handler = if_new->proto_handler; if_old->force_link = if_new->force_link; + if_old->dns_metric = if_new->dns_metric; if_old->proto_ip.no_dns = if_new->proto_ip.no_dns; interface_replace_dns(&if_old->config_ip, &if_new->config_ip); diff --git a/src/3P/netifd/interface.h b/src/3P/netifd/interface.h index 73a3b556..7d5b3094 100644 --- a/src/3P/netifd/interface.h +++ b/src/3P/netifd/interface.h @@ -26,6 +26,7 @@ enum interface_event { IFEV_UPDATE, IFEV_FREE, IFEV_RELOAD, + IFEV_LINK_UP, }; enum interface_state { @@ -113,6 +114,7 @@ struct interface { bool force_link; bool dynamic; bool policy_rules_set; + bool link_up_event; time_t start_time; enum interface_state state; @@ -143,6 +145,7 @@ struct interface { struct vlist_tree host_routes; int metric; + int dns_metric; unsigned int ip4table; unsigned int ip6table; @@ -196,7 +199,7 @@ void interface_add_error(struct interface *iface, const char *subsystem, int interface_add_data(struct interface *iface, const struct blob_attr *data); int interface_parse_data(struct interface *iface, const struct blob_attr *attr); -void interface_update_start(struct interface *iface); +void interface_update_start(struct interface *iface, const bool keep_old); void interface_update_complete(struct interface *iface); void interface_start_pending(void); diff --git a/src/3P/netifd/macvlan.c b/src/3P/netifd/macvlan.c index a0f11ae1..021d3944 100644 --- a/src/3P/netifd/macvlan.c +++ b/src/3P/netifd/macvlan.c @@ -228,7 +228,8 @@ macvlan_reload(struct device *dev, struct blob_attr *attr) } static struct device * -macvlan_create(const char *name, struct blob_attr *attr) +macvlan_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct macvlan_device *mvdev; struct device *dev = NULL; @@ -238,7 +239,7 @@ macvlan_create(const char *name, struct blob_attr *attr) return NULL; dev = &mvdev->dev; - device_init(dev, &macvlan_device_type, name); + device_init(dev, devtype, name); dev->config_pending = true; mvdev->set_state = dev->set_state; @@ -252,8 +253,8 @@ macvlan_create(const char *name, struct blob_attr *attr) return dev; } -const struct device_type macvlan_device_type = { - .name = "MAC VLAN", +static struct device_type macvlan_device_type = { + .name = "macvlan", .config_params = &macvlan_attr_list, .create = macvlan_create, .config_init = macvlan_config_init, @@ -261,3 +262,8 @@ const struct device_type macvlan_device_type = { .free = macvlan_free, .dump_info = macvlan_dump_info, }; + +static void __init macvlan_device_type_init(void) +{ + device_type_add(&macvlan_device_type); +} diff --git a/src/3P/netifd/netifd.h b/src/3P/netifd/netifd.h index d4e3fc8f..5a908587 100644 --- a/src/3P/netifd/netifd.h +++ b/src/3P/netifd/netifd.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include "utils.h" diff --git a/src/3P/netifd/proto-shell.c b/src/3P/netifd/proto-shell.c index 25dec009..ef56aa80 100644 --- a/src/3P/netifd/proto-shell.c +++ b/src/3P/netifd/proto-shell.c @@ -44,7 +44,6 @@ struct proto_shell_handler { char *config_buf; char *script_name; bool init_available; - bool no_proto_task; struct uci_blob_param_list config; }; @@ -306,7 +305,7 @@ proto_shell_task_finish(struct proto_shell_state *state, if (state->renew_pending) proto_shell_handler(&state->proto, PROTO_CMD_RENEW, false); - else if (!state->handler->no_proto_task && + else if (!(state->handler->proto.flags & PROTO_FLAG_NO_TASK) && !state->proto_task.uloop.pending && state->sm == S_SETUP) proto_shell_handler(&state->proto, @@ -539,10 +538,10 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, return UBUS_STATUS_UNKNOWN_ERROR; device_set_present(dev, true); - - interface_update_start(iface); } + interface_update_start(iface, keep); + proto_apply_ip_settings(iface, data, addr_ext); if ((cur = tb[NOTIFY_ROUTES]) != NULL) @@ -563,8 +562,7 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, interface_update_complete(state->proto.iface); if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) { - if (!keep) - state->proto.proto_event(&state->proto, IFPEV_UP); + state->proto.proto_event(&state->proto, IFPEV_UP); state->sm = S_IDLE; } @@ -892,7 +890,8 @@ proto_shell_add_handler(const char *script, const char *name, json_object *obj) handler->proto.flags |= PROTO_FLAG_NODEV; tmp = json_get_field(obj, "no-proto-task", json_type_boolean); - handler->no_proto_task = tmp && json_object_get_boolean(tmp); + if (tmp && json_object_get_boolean(tmp)) + handler->proto.flags |= PROTO_FLAG_NO_TASK; tmp = json_get_field(obj, "available", json_type_boolean); if (tmp && json_object_get_boolean(tmp)) @@ -906,6 +905,10 @@ proto_shell_add_handler(const char *script, const char *name, json_object *obj) if (tmp && json_object_get_boolean(tmp)) handler->proto.flags |= PROTO_FLAG_LASTERROR; + tmp = json_get_field(obj, "teardown-on-l3-link-down", json_type_boolean); + if (tmp && json_object_get_boolean(tmp)) + handler->proto.flags |= PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN; + config = json_get_field(obj, "config", json_type_array); if (config) handler->config_buf = netifd_handler_parse_config(&handler->config, config); diff --git a/src/3P/netifd/proto.c b/src/3P/netifd/proto.c index 45eeb4b9..fd48354d 100644 --- a/src/3P/netifd/proto.c +++ b/src/3P/netifd/proto.c @@ -36,6 +36,7 @@ enum { OPT_GATEWAY, OPT_IP6GW, OPT_IP6PREFIX, + OPT_IP6DEPRECATED, __OPT_MAX, }; @@ -47,6 +48,7 @@ static const struct blobmsg_policy proto_ip_attributes[__OPT_MAX] = { [OPT_GATEWAY] = { .name = "gateway", .type = BLOBMSG_TYPE_STRING }, [OPT_IP6GW] = { .name = "ip6gw", .type = BLOBMSG_TYPE_STRING }, [OPT_IP6PREFIX] = { .name = "ip6prefix", .type = BLOBMSG_TYPE_ARRAY }, + [OPT_IP6DEPRECATED] = { .name = "ip6deprecated", .type = BLOBMSG_TYPE_BOOL }, }; static const struct uci_blob_param_info proto_ip_attr_info[__OPT_MAX] = { @@ -113,7 +115,7 @@ alloc_device_addr(bool v6, bool ext) static bool parse_addr(struct interface *iface, const char *str, bool v6, int mask, - bool ext, uint32_t broadcast) + bool ext, uint32_t broadcast, bool deprecated) { struct device_addr *addr; int af = v6 ? AF_INET6 : AF_INET; @@ -123,22 +125,36 @@ parse_addr(struct interface *iface, const char *str, bool v6, int mask, return false; addr->mask = mask; - if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) { - interface_add_error(iface, "proto", "INVALID_ADDRESS", &str, 1); - free(addr); - return false; - } + if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) + goto error; + + if (!v6) { + if (IN_EXPERIMENTAL(ntohl(addr->addr.in.s_addr))) + goto error; + + } else if (IN6_IS_ADDR_MULTICAST(&addr->addr.in6)) + goto error; if (broadcast) addr->broadcast = broadcast; + if (deprecated) + addr->preferred_until = system_get_rtime(); + vlist_add(&iface->proto_ip.addr, &addr->node, &addr->flags); return true; + +error: + interface_add_error(iface, "proto", "INVALID_ADDRESS", &str, 1); + free(addr); + + return false; } static int parse_static_address_option(struct interface *iface, struct blob_attr *attr, - bool v6, int netmask, bool ext, uint32_t broadcast) + bool v6, int netmask, bool ext, uint32_t broadcast, + bool deprecated) { struct blob_attr *cur; int n_addr = 0; @@ -150,7 +166,7 @@ parse_static_address_option(struct interface *iface, struct blob_attr *attr, n_addr++; if (!parse_addr(iface, blobmsg_data(cur), v6, netmask, ext, - broadcast)) + broadcast, deprecated)) return -1; } @@ -390,6 +406,7 @@ proto_apply_static_ip_settings(struct interface *iface, struct blob_attr *attr) struct blob_attr *cur; const char *error; unsigned int netmask = 32; + bool ip6deprecated; int n_v4 = 0, n_v6 = 0; struct in_addr bcast = {}; @@ -410,13 +427,15 @@ proto_apply_static_ip_settings(struct interface *iface, struct blob_attr *attr) } } + ip6deprecated = blobmsg_get_bool_default(tb[OPT_IP6DEPRECATED], false); + if ((cur = tb[OPT_IPADDR])) n_v4 = parse_static_address_option(iface, cur, false, - netmask, false, bcast.s_addr); + netmask, false, bcast.s_addr, false); if ((cur = tb[OPT_IP6ADDR])) n_v6 = parse_static_address_option(iface, cur, true, - 128, false, 0); + 128, false, 0, ip6deprecated); if ((cur = tb[OPT_IP6PREFIX])) if (parse_prefix_list(iface, cur) < 0) @@ -567,7 +586,14 @@ proto_dump_handlers(struct blob_buf *b) blobmsg_add_string(b, p->config_params->params[i].name, uci_get_validate_string(p->config_params, i)); blobmsg_close_table(b, v); } + blobmsg_add_u8(b, "immediate", !!(p->flags & PROTO_FLAG_IMMEDIATE)); blobmsg_add_u8(b, "no_device", !!(p->flags & PROTO_FLAG_NODEV)); + blobmsg_add_u8(b, "init_available", !!(p->flags & PROTO_FLAG_INIT_AVAILABLE)); + blobmsg_add_u8(b, "renew_available", !!(p->flags & PROTO_FLAG_RENEW_AVAILABLE)); + blobmsg_add_u8(b, "force_link_default", !!(p->flags & PROTO_FLAG_FORCE_LINK_DEFAULT)); + blobmsg_add_u8(b, "last_error", !!(p->flags & PROTO_FLAG_LASTERROR)); + blobmsg_add_u8(b, "teardown_on_l3_link_down", !!(p->flags & PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN)); + blobmsg_add_u8(b, "no_task", !!(p->flags & PROTO_FLAG_NO_TASK)); blobmsg_close_table(b, c); } } diff --git a/src/3P/netifd/proto.h b/src/3P/netifd/proto.h index 87dec4e9..26a54bd1 100644 --- a/src/3P/netifd/proto.h +++ b/src/3P/netifd/proto.h @@ -38,6 +38,8 @@ enum { PROTO_FLAG_RENEW_AVAILABLE = (1 << 3), PROTO_FLAG_FORCE_LINK_DEFAULT = (1 << 4), PROTO_FLAG_LASTERROR = (1 << 5), + PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN = (1 << 6), + PROTO_FLAG_NO_TASK = (1 << 7), }; struct interface_proto_state { diff --git a/src/3P/netifd/scripts/netifd-proto.sh b/src/3P/netifd/scripts/netifd-proto.sh index 447f0f66..cc7031a3 100644 --- a/src/3P/netifd/scripts/netifd-proto.sh +++ b/src/3P/netifd/scripts/netifd-proto.sh @@ -1,4 +1,5 @@ NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}" +PROTO_DEFAULT_OPTIONS="defaultroute peerdns metric" . /usr/share/libubox/jshn.sh . $NETIFD_MAIN_DIR/utils.sh @@ -15,6 +16,18 @@ proto_config_add_boolean() { config_add_boolean "$@" } +proto_config_add_defaults() { + proto_config_add_boolean "defaultroute" + proto_config_add_boolean "peerdns" + proto_config_add_int "metric" +} + +proto_add_dynamic_defaults() { + [ -n "$defaultroute" ] && json_add_boolean defaultroute "$defaultroute" + [ -n "$peerdns" ] && json_add_boolean peerdns "$peerdns" + [ -n "$metric" ] && json_add_int metric "$metric" +} + _proto_do_teardown() { json_load "$data" eval "proto_$1_teardown \"$interface\" \"$ifname\"" @@ -365,6 +378,7 @@ init_proto() { no_proto_task=0 available=0 renew_handler=0 + teardown_on_l3_link_down=0 add_default_handler "proto_$1_init_config" @@ -378,6 +392,7 @@ init_proto() { json_add_boolean available "$available" json_add_boolean renew-handler "$renew_handler" json_add_boolean lasterror "$lasterror" + json_add_boolean teardown-on-l3-link-down "$teardown_on_l3_link_down" json_dump } ;; diff --git a/src/3P/netifd/system-dummy.c b/src/3P/netifd/system-dummy.c index 9c734ea5..2ea25ac5 100644 --- a/src/3P/netifd/system-dummy.c +++ b/src/3P/netifd/system-dummy.c @@ -202,6 +202,12 @@ bool system_resolve_rt_type(const char *type, unsigned int *id) return true; } +bool system_resolve_rt_proto(const char *type, unsigned int *id) +{ + *id = 0; + return true; +} + bool system_resolve_rt_table(const char *name, unsigned int *id) { *id = 0; diff --git a/src/3P/netifd/system-linux.c b/src/3P/netifd/system-linux.c index d868c15d..fcd1b2e5 100644 --- a/src/3P/netifd/system-linux.c +++ b/src/3P/netifd/system-linux.c @@ -52,7 +52,6 @@ #define IFA_FLAGS (IFA_MULTICAST + 1) #endif - #include #include #include @@ -326,6 +325,11 @@ static void system_bridge_set_multicast_to_unicast(struct device *dev, const cha system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val); } +static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_fast_leave", dev->ifname, val); +} + static void system_bridge_set_hairpin_mode(struct device *dev, const char *val) { system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, val); @@ -392,6 +396,11 @@ static void system_bridge_set_unicast_flood(struct device *dev, const char *val) system_set_dev_sysctl("/sys/class/net/%s/brport/unicast_flood", dev->ifname, val); } +static void system_set_sendredirects(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val); +} + static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz) { int fd = -1, ret = -1; @@ -480,6 +489,12 @@ static int system_get_dadtransmits(struct device *dev, char *buf, const size_t b dev->ifname, buf, buf_sz); } +static int system_get_sendredirects(struct device *dev, char *buf, const size_t buf_sz) +{ + return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", + dev->ifname, buf, buf_sz); +} + // Evaluate netlink messages static int cb_rtnl_event(struct nl_msg *msg, void *arg) { @@ -680,6 +695,10 @@ int system_bridge_addif(struct device *bridge, struct device *dev) system_bridge_set_multicast_router(dev, buf, false); } + if (dev->settings.flags & DEV_OPT_MULTICAST_FAST_LEAVE && + dev->settings.multicast_fast_leave) + system_bridge_set_multicast_fast_leave(dev, "1"); + if (dev->settings.flags & DEV_OPT_LEARNING && !dev->settings.learning) system_bridge_set_learning(dev, "0"); @@ -1279,6 +1298,11 @@ system_if_get_settings(struct device *dev, struct device_settings *s) s->dadtransmits = strtoul(buf, NULL, 0); s->flags |= DEV_OPT_DADTRANSMITS; } + + if (!system_get_sendredirects(dev, buf, sizeof(buf))) { + s->sendredirects = strtoul(buf, NULL, 0); + s->flags |= DEV_OPT_SENDREDIRECTS; + } } static void @@ -1384,6 +1408,8 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned !s->multicast ? IFF_MULTICAST : 0) < 0) s->flags &= ~DEV_OPT_MULTICAST; } + if (s->flags & DEV_OPT_SENDREDIRECTS & apply_mask) + system_set_sendredirects(dev, s->sendredirects ? "1" : "0"); system_if_apply_rps_xps(dev, s); } @@ -1755,7 +1781,7 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) .rtm_dst_len = route->mask, .rtm_src_len = route->sourcemask, .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC, - .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC, + .rtm_protocol = (route->flags & DEVROUTE_PROTO) ? route->proto : RTPROT_STATIC, .rtm_scope = RT_SCOPE_NOWHERE, .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST, .rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0, @@ -1873,6 +1899,45 @@ bool system_resolve_rt_type(const char *type, unsigned int *id) return system_rtn_aton(type, id); } +bool system_resolve_rt_proto(const char *type, unsigned int *id) +{ + FILE *f; + char *e, buf[128]; + unsigned int n, proto = 256; + + if ((n = strtoul(type, &e, 0)) >= 0 && !*e && e != type) + proto = n; + else if (!strcmp(type, "unspec")) + proto = RTPROT_UNSPEC; + else if (!strcmp(type, "kernel")) + proto = RTPROT_KERNEL; + else if (!strcmp(type, "boot")) + proto = RTPROT_BOOT; + else if (!strcmp(type, "static")) + proto = RTPROT_STATIC; + else if ((f = fopen("/etc/iproute2/rt_protos", "r")) != NULL) { + while (fgets(buf, sizeof(buf) - 1, f) != NULL) { + if ((e = strtok(buf, " \t\n")) == NULL || *e == '#') + continue; + + n = strtoul(e, NULL, 10); + e = strtok(NULL, " \t\n"); + + if (e && !strcmp(e, type)) { + proto = n; + break; + } + } + fclose(f); + } + + if (proto > 255) + return false; + + *id = proto; + return true; +} + bool system_resolve_rt_table(const char *name, unsigned int *id) { FILE *f; @@ -2118,7 +2183,7 @@ static int system_add_gre_tunnel(const char *name, const char *kind, uint32_t ikey = 0, okey = 0, flags = 0, flowinfo = 0; uint16_t iflags = 0, oflags = 0; uint8_t tos = 0; - int ret = 0, ttl = 64; + int ret = 0, ttl = 0; nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); if (!nlm) @@ -2146,8 +2211,6 @@ static int system_add_gre_tunnel(const char *name, const char *kind, if ((cur = tb[TUNNEL_ATTR_TTL])) ttl = blobmsg_get_u32(cur); - nla_put_u8(nlm, IFLA_GRE_TTL, ttl); - if ((cur = tb[TUNNEL_ATTR_TOS])) { char *str = blobmsg_get_string(cur); if (strcmp(str, "inherit")) { @@ -2221,6 +2284,9 @@ static int system_add_gre_tunnel(const char *name, const char *kind, if (flags) nla_put_u32(nlm, IFLA_GRE_FLAGS, flags); + + if (!ttl) + ttl = 64; } else { struct in_addr inbuf; bool set_df = true; @@ -2256,17 +2322,23 @@ static int system_add_gre_tunnel(const char *name, const char *kind, if ((cur = tb[TUNNEL_ATTR_DF])) set_df = blobmsg_get_bool(cur); - /* ttl !=0 and nopmtudisc are incompatible */ - if (ttl && !set_df) { - ret = -EINVAL; - goto failure; - } + if (!set_df) { + /* ttl != 0 and nopmtudisc are incompatible */ + if (ttl) { + ret = -EINVAL; + goto failure; + } + } else if (!ttl) + ttl = 64; nla_put_u8(nlm, IFLA_GRE_PMTUDISC, set_df ? 1 : 0); nla_put_u8(nlm, IFLA_GRE_TOS, tos); } + if (ttl) + nla_put_u8(nlm, IFLA_GRE_TTL, ttl); + if (oflags) nla_put_u16(nlm, IFLA_GRE_OFLAGS, oflags); @@ -2476,10 +2548,14 @@ int system_update_ipv6_mtu(struct device *dev, int mtu) { int ret = -1; char buf[64]; + int fd; + snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu", dev->ifname); - int fd = open(buf, O_RDWR); + fd = open(buf, O_RDWR); + if (fd < 0) + return ret; if (!mtu) { ssize_t len = read(fd, buf, sizeof(buf) - 1); diff --git a/src/3P/netifd/system.h b/src/3P/netifd/system.h index d5cb4e37..e810ed9e 100644 --- a/src/3P/netifd/system.h +++ b/src/3P/netifd/system.h @@ -146,6 +146,7 @@ int system_del_route(struct device *dev, struct device_route *route); int system_flush_routes(void); bool system_resolve_rt_type(const char *type, unsigned int *id); +bool system_resolve_rt_proto(const char *type, unsigned int *id); bool system_resolve_rt_table(const char *name, unsigned int *id); bool system_is_default_rt_table(unsigned int id); bool system_resolve_rpfilter(const char *filter, unsigned int *id); diff --git a/src/3P/netifd/tunnel.c b/src/3P/netifd/tunnel.c index 4a6c4093..3fa3e215 100644 --- a/src/3P/netifd/tunnel.c +++ b/src/3P/netifd/tunnel.c @@ -61,7 +61,8 @@ tunnel_reload(struct device *dev, struct blob_attr *attr) } static struct device * -tunnel_create(const char *name, struct blob_attr *attr) +tunnel_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct tunnel *tun; struct device *dev; @@ -71,10 +72,10 @@ tunnel_create(const char *name, struct blob_attr *attr) return NULL; dev = &tun->dev; - device_init(dev, &tunnel_device_type, name); + device_init(dev, devtype, name); tun->set_state = dev->set_state; dev->set_state = tunnel_set_state; - device_apply_config(dev, &tunnel_device_type, attr); + device_apply_config(dev, devtype, attr); device_set_present(dev, true); return dev; @@ -88,12 +89,15 @@ tunnel_free(struct device *dev) free(tun); } -const struct device_type tunnel_device_type = { - .name = "IP tunnel", +struct device_type tunnel_device_type = { + .name = "tunnel", .config_params = &tunnel_attr_list, .reload = tunnel_reload, .create = tunnel_create, .free = tunnel_free, }; - +static void __init tunnel_device_type_init(void) +{ + device_type_add(&tunnel_device_type); +} diff --git a/src/3P/netifd/ubus.c b/src/3P/netifd/ubus.c index 74cdf28d..0123b17e 100644 --- a/src/3P/netifd/ubus.c +++ b/src/3P/netifd/ubus.c @@ -204,7 +204,7 @@ netifd_dev_status(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg)); if (tb[DEV_NAME]) { - dev = device_get(blobmsg_data(tb[DEV_NAME]), false); + dev = device_find(blobmsg_data(tb[DEV_NAME])); if (!dev) return UBUS_STATUS_INVALID_ARGUMENT; } @@ -486,6 +486,9 @@ interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled) if (route->flags & DEVROUTE_TYPE) blobmsg_add_u32(&b, "type", route->type); + if (route->flags & DEVROUTE_PROTO) + blobmsg_add_u32(&b, "proto", route->proto); + if (route->flags & DEVROUTE_MTU) blobmsg_add_u32(&b, "mtu", route->mtu); @@ -600,12 +603,21 @@ interface_ip_dump_prefix_assignment_list(struct interface *iface) if (prefix->valid_until) blobmsg_add_u32(&b, "valid", prefix->valid_until - now); + void *c = blobmsg_open_table(&b, "local-address"); + if (assign->enabled) { + buf = blobmsg_alloc_string_buffer(&b, "address", buflen); + inet_ntop(AF_INET6, &assign->addr, buf, buflen); + blobmsg_add_string_buffer(&b); + + blobmsg_add_u32(&b, "mask", assign->length < 64 ? 64 : assign->length); + } + blobmsg_close_table(&b, c); + blobmsg_close_table(&b, a); } } } - static void interface_ip_dump_dns_server_list(struct interface_ip_settings *ip, bool enabled) @@ -685,8 +697,9 @@ netifd_dump_status(struct interface *iface) if (iface->ip4table) blobmsg_add_u32(&b, "ip4table", iface->ip4table); if (iface->ip6table) - blobmsg_add_u32(&b, "ip6table", iface->ip6table); + blobmsg_add_u32(&b, "ip6table", iface->ip6table); blobmsg_add_u32(&b, "metric", iface->metric); + blobmsg_add_u32(&b, "dns_metric", iface->dns_metric); blobmsg_add_u8(&b, "delegation", !iface->proto_ip.no_delegation); a = blobmsg_open_array(&b, "ipv4-address"); interface_ip_dump_address_list(&iface->config_ip, false, true); diff --git a/src/3P/netifd/utils.c b/src/3P/netifd/utils.c index e01b633c..ba269527 100644 --- a/src/3P/netifd/utils.c +++ b/src/3P/netifd/utils.c @@ -119,7 +119,6 @@ int parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask) { char *astr = alloca(strlen(str) + 1); - int ret = 0; strcpy(astr, str); if (!split_netmask(astr, netmask, af == AF_INET6)) @@ -133,23 +132,7 @@ parse_ip_and_netmask(int af, const char *str, void *addr, unsigned int *netmask) return 0; } - ret = inet_pton(af, astr, addr); - if (ret > 0) { - if (af == AF_INET) { - struct in_addr *ip4_addr = (struct in_addr *)addr; - uint32_t host_addr = ntohl(ip4_addr->s_addr); - - if (IN_EXPERIMENTAL(host_addr)) { - return 0; - } - } - else if (af == AF_INET6) { - if (IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) { - return 0; - } - } - } - return ret; + return inet_pton(af, astr, addr); } char * diff --git a/src/3P/netifd/utils.h b/src/3P/netifd/utils.h index 12cfda1f..4e14bcf5 100644 --- a/src/3P/netifd/utils.h +++ b/src/3P/netifd/utils.h @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/3P/netifd/vlan.c b/src/3P/netifd/vlan.c index 7f8697b6..067f6245 100644 --- a/src/3P/netifd/vlan.c +++ b/src/3P/netifd/vlan.c @@ -96,7 +96,7 @@ static void vlan_dev_cb(struct device_user *dep, enum device_event ev) static struct device *get_vlan_device(struct device *dev, int id, bool create) { - static const struct device_type vlan_type = { + static struct device_type vlan_type = { .name = "VLAN", .config_params = &device_attr_list, .free = free_vlan_if, diff --git a/src/3P/netifd/vlandev.c b/src/3P/netifd/vlandev.c index b93527c5..7e462512 100644 --- a/src/3P/netifd/vlandev.c +++ b/src/3P/netifd/vlandev.c @@ -20,14 +20,12 @@ #include "system.h" enum { - VLANDEV_ATTR_TYPE, VLANDEV_ATTR_IFNAME, VLANDEV_ATTR_VID, __VLANDEV_ATTR_MAX }; static const struct blobmsg_policy vlandev_attrs[__VLANDEV_ATTR_MAX] = { - [VLANDEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING }, [VLANDEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_STRING }, [VLANDEV_ATTR_VID] = { "vid", BLOBMSG_TYPE_INT32 }, }; @@ -40,6 +38,8 @@ static const struct uci_blob_param_list vlandev_attr_list = { .next = { &device_attr_list }, }; +static struct device_type vlan8021q_device_type; + struct vlandev_device { struct device dev; struct device_user parent; @@ -158,15 +158,10 @@ vlandev_apply_settings(struct vlandev_device *mvdev, struct blob_attr **tb) struct vlandev_config *cfg = &mvdev->config; struct blob_attr *cur; - cfg->proto = VLAN_PROTO_8021Q; + cfg->proto = (mvdev->dev.type == &vlan8021q_device_type) ? + VLAN_PROTO_8021Q : VLAN_PROTO_8021AD; cfg->vid = 1; - if ((cur = tb[VLANDEV_ATTR_TYPE])) - { - if(!strcmp(blobmsg_data(cur), "8021ad")) - cfg->proto = VLAN_PROTO_8021AD; - } - if ((cur = tb[VLANDEV_ATTR_VID])) cfg->vid = (uint16_t) blobmsg_get_u32(cur); } @@ -216,7 +211,8 @@ vlandev_reload(struct device *dev, struct blob_attr *attr) } static struct device * -vlandev_create(const char *name, struct blob_attr *attr) +vlandev_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) { struct vlandev_device *mvdev; struct device *dev = NULL; @@ -226,7 +222,7 @@ vlandev_create(const char *name, struct blob_attr *attr) return NULL; dev = &mvdev->dev; - device_init(dev, &vlandev_device_type, name); + device_init(dev, devtype, name); dev->config_pending = true; mvdev->set_state = dev->set_state; @@ -240,8 +236,8 @@ vlandev_create(const char *name, struct blob_attr *attr) return dev; } -const struct device_type vlandev_device_type = { - .name = "VLANDEV", +static struct device_type vlan8021ad_device_type = { + .name = "8021ad", .config_params = &vlandev_attr_list, .create = vlandev_create, .config_init = vlandev_config_init, @@ -249,3 +245,19 @@ const struct device_type vlandev_device_type = { .free = vlandev_free, .dump_info = vlandev_dump_info, }; + +static struct device_type vlan8021q_device_type = { + .name = "8021q", + .config_params = &vlandev_attr_list, + .create = vlandev_create, + .config_init = vlandev_config_init, + .reload = vlandev_reload, + .free = vlandev_free, + .dump_info = vlandev_dump_info, +}; + +static void __init vlandev_device_type_init(void) +{ + device_type_add(&vlan8021ad_device_type); + device_type_add(&vlan8021q_device_type); +} diff --git a/src/3P/netifd/wireless.c b/src/3P/netifd/wireless.c index 34dd328e..387f4baf 100644 --- a/src/3P/netifd/wireless.c +++ b/src/3P/netifd/wireless.c @@ -83,7 +83,7 @@ vif_config_add_bridge(struct blob_buf *buf, struct blob_attr *networks, bool pre if (!dev) return; - if (dev->type != &bridge_device_type) + if (!dev->type->bridge_capability) return; } @@ -287,6 +287,12 @@ __wireless_device_set_up(struct wireless_device *wdev) if (wdev->disabled) return; + if (wdev->retry_setup_failed) + return; + + if (!wdev->autostart) + return; + if (wdev->state != IFS_DOWN || config_init) return; @@ -314,9 +320,9 @@ wdev_handle_config_change(struct wireless_device *wdev) switch(state) { case IFC_NORMAL: case IFC_RELOAD: + __wireless_device_set_up(wdev); + wdev->config_state = IFC_NORMAL; - if (wdev->autostart) - __wireless_device_set_up(wdev); break; case IFC_REMOVE: wireless_device_free(wdev); @@ -399,7 +405,7 @@ wireless_device_retry_setup(struct wireless_device *wdev) return; if (--wdev->retry < 0) - wdev->autostart = false; + wdev->retry_setup_failed = true; __wireless_device_set_down(wdev); } @@ -424,6 +430,7 @@ wireless_device_script_task_cb(struct netifd_process *proc, int ret) void wireless_device_set_down(struct wireless_device *wdev) { + wdev->retry_setup_failed = false; wdev->autostart = false; __wireless_device_set_down(wdev); } @@ -467,6 +474,7 @@ wdev_change_config(struct wireless_device *wdev, struct wireless_device *wd_new) free(wdev->config); wdev->config = blob_memdup(new_config); wdev->disabled = disabled; + wdev->retry_setup_failed = false; wdev_set_config_state(wdev, IFC_RELOAD); } @@ -605,6 +613,7 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new, wireless_interface_init_config(vif_new); } else if (vif_old) { D(WIRELESS, "Delete wireless interface %s on device %s\n", vif_old->name, wdev->name); + wireless_interface_handle_link(vif_old, false); free((void *) vif_old->section); free(vif_old->config); free(vif_old); @@ -681,8 +690,8 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo wdev->config_state = IFC_NORMAL; wdev->name = strcpy(name_buf, name); wdev->config = data; - wdev->config_autostart = true; - wdev->autostart = wdev->config_autostart; + wdev->retry_setup_failed = false; + wdev->autostart = true; INIT_LIST_HEAD(&wdev->script_proc); vlist_init(&wdev->interfaces, avl_strcmp, vif_update); wdev->interfaces.keep_old = true; @@ -752,6 +761,7 @@ wireless_device_status(struct wireless_device *wdev, struct blob_buf *b) blobmsg_add_u8(b, "pending", wdev->state == IFS_SETUP || wdev->state == IFS_TEARDOWN); blobmsg_add_u8(b, "autostart", wdev->autostart); blobmsg_add_u8(b, "disabled", wdev->disabled); + blobmsg_add_u8(b, "retry_setup_failed", wdev->retry_setup_failed); put_container(b, wdev->config, "config"); i = blobmsg_open_array(b, "interfaces"); @@ -991,6 +1001,5 @@ wireless_start_pending(void) struct wireless_device *wdev; vlist_for_each_element(&wireless_devices, wdev, node) - if (wdev->autostart) - __wireless_device_set_up(wdev); + __wireless_device_set_up(wdev); } diff --git a/src/3P/netifd/wireless.h b/src/3P/netifd/wireless.h index 665cdb7c..3498bd83 100644 --- a/src/3P/netifd/wireless.h +++ b/src/3P/netifd/wireless.h @@ -53,9 +53,9 @@ struct wireless_device { struct blob_attr *config; struct blob_attr *data; - bool config_autostart; bool autostart; bool disabled; + bool retry_setup_failed; enum interface_state state; enum interface_config_state config_state;