X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=system-linux.c;h=dae98b0aa8cc324d44e03086ed8300dc9f1cacd0;hp=604c206c4526df9c4235d9b574b994475b466252;hb=134775b1f41fa19a816768268b9d0f8dad86bd90;hpb=2008ae9a80fb82b0018fd510043c291b58e7cc46 diff --git a/system-linux.c b/system-linux.c index 604c206..dae98b0 100644 --- a/system-linux.c +++ b/system-linux.c @@ -29,13 +29,18 @@ #include #include #include +#include #include #include #include +#include #include #include -#include +#ifndef RTN_FAILED_POLICY +#define RTN_FAILED_POLICY 12 +#endif + #include #include #include @@ -581,11 +586,9 @@ int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg) system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping", bridge->ifname, cfg->igmp_snoop ? "1" : "0"); - if (cfg->flags & BRIDGE_OPT_PRIORITY) { - args[0] = BRCTL_SET_BRIDGE_PRIORITY; - args[1] = cfg->priority; - system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args); - } + args[0] = BRCTL_SET_BRIDGE_PRIORITY; + args[1] = cfg->priority; + system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args); if (cfg->flags & BRIDGE_OPT_AGEING_TIME) { args[0] = BRCTL_SET_AGEING_TIME; @@ -608,6 +611,93 @@ int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg) return 0; } +int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg) +{ + struct nl_msg *msg; + struct nlattr *linkinfo, *data; + struct ifinfomsg iim = { .ifi_family = AF_INET }; + int ifindex = system_if_resolve(dev); + int i, rv; + static const struct { + const char *name; + enum macvlan_mode val; + } modes[] = { + { "private", MACVLAN_MODE_PRIVATE }, + { "vepa", MACVLAN_MODE_VEPA }, + { "bridge", MACVLAN_MODE_BRIDGE }, + { "passthru", MACVLAN_MODE_PASSTHRU }, + }; + + 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); + + 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_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"); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (cfg->mode) { + for (i = 0; i < ARRAY_SIZE(modes); i++) { + if (strcmp(cfg->mode, modes[i].name) != 0) + continue; + + nla_put_u32(msg, IFLA_MACVLAN_MODE, modes[i].val); + break; + } + } + + nla_nest_end(msg, data); + nla_nest_end(msg, linkinfo); + + rv = system_rtnl_call(msg); + if (rv) + D(SYSTEM, "Error adding macvlan '%s' over '%s': %d\n", macvlan->ifname, dev->ifname, rv); + + return rv; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + +int system_macvlan_del(struct device *macvlan) +{ + struct nl_msg *msg; + struct ifinfomsg iim; + + iim.ifi_family = AF_INET; + iim.ifi_index = 0; + + msg = nlmsg_alloc_simple(RTM_DELLINK, 0); + + if (!msg) + return -1; + + nlmsg_append(msg, &iim, sizeof(iim), 0); + + 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; +} + static int system_vlan(struct device *dev, int id) { struct vlan_ioctl_args ifr = { @@ -919,17 +1009,21 @@ static int system_addr(struct device *dev, struct device_addr *addr, int cmd) struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0}; if (addr->preferred_until) { - int preferred = addr->preferred_until - now; + int64_t preferred = addr->preferred_until - now; if (preferred < 0) preferred = 0; + else if (preferred > UINT32_MAX) + preferred = UINT32_MAX; cinfo.ifa_prefered = preferred; } if (addr->valid_until) { - int valid = addr->valid_until - now; + int64_t valid = addr->valid_until - now; if (valid <= 0) return -1; + else if (valid > UINT32_MAX) + valid = UINT32_MAX; cinfo.ifa_valid = valid; } @@ -967,7 +1061,8 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd) unsigned char scope = (cmd == RTM_DELROUTE) ? RT_SCOPE_NOWHERE : (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; - unsigned int table = (route->flags & DEVROUTE_TABLE) ? route->table : RT_TABLE_MAIN; + unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE)) + ? route->table : RT_TABLE_MAIN; struct rtmsg rtm = { .rtm_family = (alen == 4) ? AF_INET : AF_INET6, @@ -1251,6 +1346,8 @@ bool system_resolve_iprule_action(const char *action, unsigned int *id) 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) @@ -1279,14 +1376,6 @@ time_t system_get_rtime(void) #define IP_DF 0x4000 #endif -static void tunnel_parm_init(struct ip_tunnel_parm *p) -{ - memset(p, 0, sizeof(*p)); - p->iph.version = 4; - p->iph.ihl = 5; - p->iph.frag_off = htons(IP_DF); -} - static int tunnel_ioctl(const char *name, int cmd, void *p) { struct ifreq ifr; @@ -1299,10 +1388,7 @@ static int tunnel_ioctl(const char *name, int cmd, void *p) int system_del_ip_tunnel(const char *name) { - struct ip_tunnel_parm p; - - tunnel_parm_init(&p); - return tunnel_ioctl(name, SIOCDELTUNNEL, &p); + return tunnel_ioctl(name, SIOCDELTUNNEL, NULL); } int system_update_ipv6_mtu(struct device *dev, int mtu) @@ -1332,86 +1418,112 @@ out: return ret; } -static int parse_ipaddr(struct blob_attr *attr, __be32 *addr) -{ - if (!attr) - return 1; - - return inet_pton(AF_INET, blobmsg_data(attr), (void *) addr); -} - - int system_add_ip_tunnel(const char *name, struct blob_attr *attr) { struct blob_attr *tb[__TUNNEL_ATTR_MAX]; struct blob_attr *cur; - struct ip_tunnel_parm p; - const char *base, *str; - bool is_sit; + bool set_df = true; + const char *str; system_del_ip_tunnel(name); - tunnel_parm_init(&p); - blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb, blob_data(attr), blob_len(attr)); if (!(cur = tb[TUNNEL_ATTR_TYPE])) return -EINVAL; str = blobmsg_data(cur); - is_sit = !strcmp(str, "sit"); - if (is_sit) { - p.iph.protocol = IPPROTO_IPV6; - base = "sit0"; - } else - return -EINVAL; - - if (!parse_ipaddr(tb[TUNNEL_ATTR_LOCAL], &p.iph.saddr)) - return -EINVAL; - - if (!parse_ipaddr(tb[TUNNEL_ATTR_REMOTE], &p.iph.daddr)) - return -EINVAL; + if ((cur = tb[TUNNEL_ATTR_DF])) + set_df = blobmsg_get_bool(cur); + unsigned int ttl = 0; if ((cur = tb[TUNNEL_ATTR_TTL])) { - unsigned int val = blobmsg_get_u32(cur); + ttl = blobmsg_get_u32(cur); + if (ttl > 255 || (!set_df && ttl)) + return -EINVAL; + } - if (val > 255) + unsigned int link = 0; + if ((cur = tb[TUNNEL_ATTR_LINK])) { + struct interface *iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node); + if (!iface) return -EINVAL; - p.iph.ttl = val; + if (iface->l3_dev.dev) + link = iface->l3_dev.dev->ifindex; } - strncpy(p.name, name, sizeof(p.name)); - if (tunnel_ioctl(base, SIOCADDTUNNEL, &p) < 0) - return -1; - -#ifdef SIOCADD6RD - cur = tb[TUNNEL_ATTR_6RD_PREFIX]; - if (cur && is_sit) { - unsigned int mask; - struct ip_tunnel_6rd p6; + if (!strcmp(str, "sit")) { + struct ip_tunnel_parm p = { + .link = link, + .iph = { + .version = 4, + .ihl = 5, + .frag_off = set_df ? htons(IP_DF) : 0, + .protocol = IPPROTO_IPV6, + .ttl = ttl + } + }; - memset(&p6, 0, sizeof(p6)); + if ((cur = tb[TUNNEL_ATTR_LOCAL]) && + inet_pton(AF_INET, blobmsg_data(cur), &p.iph.saddr) < 1) + return -EINVAL; - if (!parse_ip_and_netmask(AF_INET6, blobmsg_data(cur), - &p6.prefix, &mask) || mask > 128) + if ((cur = tb[TUNNEL_ATTR_REMOTE]) && + inet_pton(AF_INET, blobmsg_data(cur), &p.iph.daddr) < 1) return -EINVAL; - p6.prefixlen = mask; - if ((cur = tb[TUNNEL_ATTR_6RD_RELAY_PREFIX])) { - if (!parse_ip_and_netmask(AF_INET, blobmsg_data(cur), - &p6.relay_prefix, &mask) || mask > 32) + strncpy(p.name, name, sizeof(p.name)); + if (tunnel_ioctl("sit0", SIOCADDTUNNEL, &p) < 0) + return -1; + +#ifdef SIOCADD6RD + if ((cur = tb[TUNNEL_ATTR_6RD_PREFIX])) { + unsigned int mask; + struct ip_tunnel_6rd p6; + + memset(&p6, 0, sizeof(p6)); + + if (!parse_ip_and_netmask(AF_INET6, blobmsg_data(cur), + &p6.prefix, &mask) || mask > 128) return -EINVAL; - p6.relay_prefixlen = mask; - } + p6.prefixlen = mask; - if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) { - system_del_ip_tunnel(name); - return -1; + if ((cur = tb[TUNNEL_ATTR_6RD_RELAY_PREFIX])) { + if (!parse_ip_and_netmask(AF_INET, blobmsg_data(cur), + &p6.relay_prefix, &mask) || mask > 32) + return -EINVAL; + p6.relay_prefixlen = mask; + } + + if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) { + system_del_ip_tunnel(name); + return -1; + } } - } #endif + } else if (!strcmp(str, "ipip6")) { + struct ip6_tnl_parm p = { + .link = link, + .proto = IPPROTO_IPIP, + .hop_limit = (ttl) ? ttl : 64, + .encap_limit = 4, + }; + + if ((cur = tb[TUNNEL_ATTR_LOCAL]) && + inet_pton(AF_INET6, blobmsg_data(cur), &p.laddr) < 1) + return -EINVAL; + + if ((cur = tb[TUNNEL_ATTR_REMOTE]) && + inet_pton(AF_INET6, blobmsg_data(cur), &p.raddr) < 1) + return -EINVAL; + + strncpy(p.name, name, sizeof(p.name)); + if (tunnel_ioctl("ip6tnl0", SIOCADDTUNNEL, &p) < 0) + return -1; + } else + return -EINVAL; return 0; }