X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=system-linux.c;h=c6f17e99c8015ca7f414231c6a77139c7a522e2e;hp=8f46705d5f63670fa9c0eb9de2fa792c141e9dd1;hb=07e9b542017c692ee2abe7a8689517b466150944;hpb=98ca67469da70accd710b14c28e77be2126170a8 diff --git a/system-linux.c b/system-linux.c index 8f46705..c6f17e9 100644 --- a/system-linux.c +++ b/system-linux.c @@ -3,6 +3,7 @@ * Copyright (C) 2012 Felix Fietkau * Copyright (C) 2013 Jo-Philipp Wich * Copyright (C) 2013 Steven Barth + * Copyright (C) 2014 Gioacchino Mazzurco * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -36,6 +37,7 @@ #include #include #include +#include #ifndef RTN_FAILED_POLICY #define RTN_FAILED_POLICY 12 @@ -162,6 +164,46 @@ create_event_socket(struct event_socket *ev, int protocol, return true; } +static bool +system_rtn_aton(const char *src, unsigned int *dst) +{ + char *e; + unsigned int n; + + if (!strcmp(src, "local")) + n = RTN_LOCAL; + else if (!strcmp(src, "nat")) + n = RTN_NAT; + else if (!strcmp(src, "broadcast")) + n = RTN_BROADCAST; + else if (!strcmp(src, "anycast")) + n = RTN_ANYCAST; + else if (!strcmp(src, "multicast")) + n = RTN_MULTICAST; + else if (!strcmp(src, "prohibit")) + n = RTN_PROHIBIT; + else if (!strcmp(src, "unreachable")) + n = RTN_UNREACHABLE; + else if (!strcmp(src, "blackhole")) + n = RTN_BLACKHOLE; + else if (!strcmp(src, "xresolve")) + n = RTN_XRESOLVE; + else if (!strcmp(src, "unicast")) + n = RTN_UNICAST; + else if (!strcmp(src, "throw")) + n = RTN_THROW; + else if (!strcmp(src, "failed_policy")) + n = RTN_FAILED_POLICY; + else { + n = strtoul(src, &e, 0); + if (!e || *e || e == src || n > 255) + return false; + } + + *dst = n; + return true; +} + int system_init(void) { static struct event_socket rtnl_event; @@ -611,11 +653,8 @@ void system_if_clear_state(struct device *dev) static char buf[256]; char *bridge; - if (dev->external) - return; - device_set_ifindex(dev, system_if_resolve(dev)); - if (!dev->ifindex) + if (dev->external || !dev->ifindex) return; system_if_flags(dev->ifname, 0, IFF_UP); @@ -692,7 +731,7 @@ int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvla { struct nl_msg *msg; struct nlattr *linkinfo, *data; - struct ifinfomsg iim = { .ifi_family = AF_INET }; + struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, }; int ifindex = system_if_resolve(dev); int i, rv; static const struct { @@ -717,13 +756,13 @@ int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvla if (cfg->flags & MACVLAN_OPT_MACADDR) nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr); - nla_put(msg, IFLA_IFNAME, IFNAMSIZ, macvlan->ifname); + nla_put_string(msg, IFLA_IFNAME, macvlan->ifname); nla_put_u32(msg, IFLA_LINK, ifindex); if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO))) goto nla_put_failure; - nla_put(msg, IFLA_INFO_KIND, strlen("macvlan"), "macvlan"); + nla_put_string(msg, IFLA_INFO_KIND, "macvlan"); if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) goto nla_put_failure; @@ -752,27 +791,27 @@ nla_put_failure: return -ENOMEM; } -int system_macvlan_del(struct device *macvlan) +static int system_link_del(struct device *dev) { struct nl_msg *msg; - struct ifinfomsg iim; - - iim.ifi_family = AF_INET; - iim.ifi_index = 0; + struct ifinfomsg iim = { + .ifi_family = AF_UNSPEC, + .ifi_index = 0, + }; - msg = nlmsg_alloc_simple(RTM_DELLINK, 0); + msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST); if (!msg) return -1; nlmsg_append(msg, &iim, sizeof(iim), 0); + nla_put_string(msg, IFLA_IFNAME, dev->ifname); + return system_rtnl_call(msg); +} - nla_put(msg, IFLA_INFO_KIND, strlen("macvlan"), "macvlan"); - nla_put(msg, IFLA_IFNAME, sizeof(macvlan->ifname), macvlan->ifname); - - system_rtnl_call(msg); - - return 0; +int system_macvlan_del(struct device *macvlan) +{ + return system_link_del(macvlan); } static int system_vlan(struct device *dev, int id) @@ -805,6 +844,62 @@ int system_vlan_del(struct device *dev) return system_vlan(dev, -1); } +int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg) +{ + struct nl_msg *msg; + struct nlattr *linkinfo, *data; + struct ifinfomsg iim = { .ifi_family = AF_UNSPEC }; + int ifindex = system_if_resolve(dev); + int rv; + + if (ifindex == 0) + return -ENOENT; + + msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + + if (!msg) + return -1; + + nlmsg_append(msg, &iim, sizeof(iim), 0); + nla_put_string(msg, IFLA_IFNAME, vlandev->ifname); + nla_put_u32(msg, IFLA_LINK, ifindex); + + if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO))) + goto nla_put_failure; + + nla_put_string(msg, IFLA_INFO_KIND, "vlan"); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + nla_put_u16(msg, IFLA_VLAN_ID, cfg->vid); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + nla_put_u16(msg, IFLA_VLAN_PROTOCOL, htons(cfg->proto)); +#else + if(cfg->proto == VLAN_PROTO_8021AD) + netifd_log_message(L_WARNING, "%s Your kernel is older than linux 3.10.0, 802.1ad is not supported defaulting to 802.1q", vlandev->type->name); +#endif + + nla_nest_end(msg, data); + nla_nest_end(msg, linkinfo); + + rv = system_rtnl_call(msg); + if (rv) + D(SYSTEM, "Error adding vlandev '%s' over '%s': %d\n", vlandev->ifname, dev->ifname, rv); + + return rv; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + +int system_vlandev_del(struct device *vlandev) +{ + return system_link_del(vlandev); +} + static void system_if_get_settings(struct device *dev, struct device_settings *s) { @@ -1210,9 +1305,6 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) route->nexthop.in6.s6_addr32[2] || route->nexthop.in6.s6_addr32[3]; - unsigned char scope = (cmd == RTM_DELROUTE) ? RT_SCOPE_NOWHERE : - (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; - unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE)) ? route->table : RT_TABLE_MAIN; @@ -1222,8 +1314,9 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) .rtm_src_len = route->sourcemask, .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC, .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC, - .rtm_scope = scope, + .rtm_scope = RT_SCOPE_NOWHERE, .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST, + .rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0, }; struct nl_msg *msg; @@ -1234,6 +1327,23 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) rtm.rtm_scope = RT_SCOPE_UNIVERSE; rtm.rtm_type = RTN_UNREACHABLE; } + else + rtm.rtm_scope = (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; + } + + if (route->flags & DEVROUTE_TYPE) { + rtm.rtm_type = route->type; + if (!(route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))) { + if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_BROADCAST || + rtm.rtm_type == RTN_NAT || rtm.rtm_type == RTN_ANYCAST) + rtm.rtm_table = RT_TABLE_LOCAL; + } + + if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_NAT) + rtm.rtm_scope = RT_SCOPE_HOST; + else if (rtm.rtm_type == RTN_BROADCAST || rtm.rtm_type == RTN_MULTICAST || + rtm.rtm_type == RTN_ANYCAST) + rtm.rtm_scope = RT_SCOPE_LINK; } msg = nlmsg_alloc_simple(cmd, flags); @@ -1260,7 +1370,22 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) if (table >= 256) nla_put_u32(msg, RTA_TABLE, table); + if (route->flags & DEVROUTE_MTU) { + struct nlattr *metrics; + + if (!(metrics = nla_nest_start(msg, RTA_METRICS))) + goto nla_put_failure; + + nla_put_u32(msg, RTAX_MTU, route->mtu); + + nla_nest_end(msg, metrics); + } + return system_rtnl_call(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; } int system_add_route(struct device *dev, struct device_route *route) @@ -1292,6 +1417,11 @@ int system_flush_routes(void) return 0; } +bool system_resolve_rt_type(const char *type, unsigned int *id) +{ + return system_rtn_aton(type, id); +} + bool system_resolve_rt_table(const char *name, unsigned int *id) { FILE *f; @@ -1334,14 +1464,15 @@ bool system_resolve_rt_table(const char *name, unsigned int *id) if (table == RT_TABLE_UNSPEC) return false; - /* do not consider main table special */ - if (table == RT_TABLE_MAIN) - table = RT_TABLE_UNSPEC; - *id = table; return true; } +bool system_is_default_rt_table(unsigned int id) +{ + return (id == RT_TABLE_MAIN); +} + static int system_iprule(struct iprule *rule, int cmd) { int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16; @@ -1477,41 +1608,7 @@ int system_flush_iprules(void) bool system_resolve_iprule_action(const char *action, unsigned int *id) { - char *e; - unsigned int n; - - if (!strcmp(action, "local")) - n = RTN_LOCAL; - else if (!strcmp(action, "nat")) - n = RTN_NAT; - else if (!strcmp(action, "broadcast")) - n = RTN_BROADCAST; - else if (!strcmp(action, "anycast")) - n = RTN_ANYCAST; - else if (!strcmp(action, "multicast")) - n = RTN_MULTICAST; - else if (!strcmp(action, "prohibit")) - n = RTN_PROHIBIT; - else if (!strcmp(action, "unreachable")) - n = RTN_UNREACHABLE; - else if (!strcmp(action, "blackhole")) - n = RTN_BLACKHOLE; - else if (!strcmp(action, "xresolve")) - n = RTN_XRESOLVE; - else if (!strcmp(action, "unicast")) - n = RTN_UNICAST; - else if (!strcmp(action, "throw")) - n = RTN_THROW; - else if (!strcmp(action, "failed_policy")) - n = RTN_FAILED_POLICY; - else { - n = strtoul(action, &e, 0); - if (!e || *e || e == action || n > 255) - return false; - } - - *id = n; - return true; + return system_rtn_aton(action, id); } time_t system_get_rtime(void) @@ -1660,25 +1757,109 @@ int system_add_ip_tunnel(const char *name, struct blob_attr *attr) } #endif } else if (!strcmp(str, "ipip6")) { - struct ip6_tnl_parm p = { - .link = link, - .proto = IPPROTO_IPIP, - .hop_limit = (ttl) ? ttl : 64, - .encap_limit = 4, - }; + struct nl_msg *nlm = nlmsg_alloc_simple(RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); + struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC }; + int ret = 0; - if ((cur = tb[TUNNEL_ATTR_LOCAL]) && - inet_pton(AF_INET6, blobmsg_data(cur), &p.laddr) < 1) - return -EINVAL; + if (!nlm) + return -1; - if ((cur = tb[TUNNEL_ATTR_REMOTE]) && - inet_pton(AF_INET6, blobmsg_data(cur), &p.raddr) < 1) - return -EINVAL; + nlmsg_append(nlm, &ifi, sizeof(ifi), 0); + nla_put_string(nlm, IFLA_IFNAME, name); - strncpy(p.name, name, sizeof(p.name)); - if (tunnel_ioctl("ip6tnl0", SIOCADDTUNNEL, &p) < 0) - return -1; - } else + if (link) + nla_put_u32(nlm, IFLA_LINK, link); + + struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO); + if (!linkinfo) { + ret = -ENOMEM; + goto failure; + } + nla_put_string(nlm, IFLA_INFO_KIND, "ip6tnl"); + struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA); + if (!infodata) { + ret = -ENOMEM; + goto failure; + } + + if (link) + nla_put_u32(nlm, IFLA_IPTUN_LINK, link); + + nla_put_u8(nlm, IFLA_IPTUN_PROTO, IPPROTO_IPIP); + nla_put_u8(nlm, IFLA_IPTUN_TTL, (ttl) ? ttl : 64); + nla_put_u8(nlm, IFLA_IPTUN_ENCAP_LIMIT, 4); + + struct in6_addr in6buf; + if ((cur = tb[TUNNEL_ATTR_LOCAL])) { + if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(nlm, IFLA_IPTUN_LOCAL, sizeof(in6buf), &in6buf); + } + + if ((cur = tb[TUNNEL_ATTR_REMOTE])) { + if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) { + ret = -EINVAL; + goto failure; + } + nla_put(nlm, IFLA_IPTUN_REMOTE, sizeof(in6buf), &in6buf); + } + +#ifdef IFLA_IPTUN_FMR_MAX + if ((cur = tb[TUNNEL_ATTR_FMRS])) { + struct nlattr *fmrs = nla_nest_start(nlm, IFLA_IPTUN_FMRS); + + struct blob_attr *fmr; + unsigned rem, fmrcnt = 0; + blobmsg_for_each_attr(fmr, cur, rem) { + if (blobmsg_type(fmr) != BLOBMSG_TYPE_STRING) + continue; + + unsigned ip4len, ip6len, ealen, offset = 6; + char ip6buf[48]; + char ip4buf[16]; + + if (sscanf(blobmsg_get_string(fmr), "%47[^/]/%u,%15[^/]/%u,%u,%u", + ip6buf, &ip6len, ip4buf, &ip4len, &ealen, &offset) < 5) { + ret = -EINVAL; + goto failure; + } + + struct in6_addr ip6prefix; + struct in_addr ip4prefix; + if (inet_pton(AF_INET6, ip6buf, &ip6prefix) != 1 || + inet_pton(AF_INET, ip4buf, &ip4prefix) != 1) { + ret = -EINVAL; + goto failure; + } + + struct nlattr *rule = nla_nest_start(nlm, ++fmrcnt); + + nla_put(nlm, IFLA_IPTUN_FMR_IP6_PREFIX, sizeof(ip6prefix), &ip6prefix); + nla_put(nlm, IFLA_IPTUN_FMR_IP4_PREFIX, sizeof(ip4prefix), &ip4prefix); + nla_put_u8(nlm, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ip6len); + nla_put_u8(nlm, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ip4len); + nla_put_u8(nlm, IFLA_IPTUN_FMR_EA_LEN, ealen); + nla_put_u8(nlm, IFLA_IPTUN_FMR_OFFSET, offset); + + nla_nest_end(nlm, rule); + } + + nla_nest_end(nlm, fmrs); + } +#endif + + nla_nest_end(nlm, infodata); + nla_nest_end(nlm, linkinfo); + + return system_rtnl_call(nlm); +failure: + nlmsg_free(nlm); + return ret; + } + else return -EINVAL; return 0;