From patchwork Mon Nov 14 13:07:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Smirnov X-Patchwork-Id: 1703594 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=FoBOtyoh; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=cZwcNVJQ; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4N9qy95fqwz1yqS for ; Tue, 15 Nov 2022 00:33:21 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=SlXCZ3MXn0MAH1jYrhiMjLENMy1hGxgRevbvzVsKPRE=; b=FoBOtyohlokZ+1 +wV2HJgQX7Cv/WYAHBhb6Aeqf5LVlfgJbij9fWMFY3BXLkq2cGyRR/1MVk3t7LUKZja/kr3FyDBza tzM5w83VXUPdFuFkXelLbBpyXKLZPL54qXMQtXtoXsf0gaB7ZPwMBER87C4DWon68Ud1bWtM8C9dX +9KcOWGXs7kNaMi8tURgBRQqolIe1d5421LYeFw0FAPIMrqi1Gdb8t5xpvW2smvNBsau6GRhPacC4 HypWv1MJNkY5QXMlsbfYVgjrkd75rhGRWOXhCrQSUGx2a5ytDGHptSkUizLtNnwK2Hl14DPXE7JGy QpSydnVm4a2L+zHdu5SQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1ouZW9-001Dgn-T8; Mon, 14 Nov 2022 13:28:54 +0000 Received: from mail-lf1-x12b.google.com ([2a00:1450:4864:20::12b]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1ouZCg-0015AO-Kh for openwrt-devel@lists.openwrt.org; Mon, 14 Nov 2022 13:08:51 +0000 Received: by mail-lf1-x12b.google.com with SMTP id c1so19171037lfi.7 for ; Mon, 14 Nov 2022 05:08:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=/S8msf2gCblApWE9V0V52oqougW+RlLT5PRFBbIiPag=; b=cZwcNVJQKZT5ZUywBbCiWvJiF8g5vL6J22EobUp3zdRL0N40lXjf9Gs9QjcN+LJKdJ nSEM+pcmBCITOePY8PBFvv5q/HuiDgpzQgJeQ9X7JBHF0SYRrq0aM6HzPNsK/0+kvt1F f55NnhFq1toQRN5+UnlzfsGtJuddPhbmdm4LLCLZJcvH8EJ3Mqkwz37sx0ife+pzRx4U 0iDArvsPYG/vQCJ4VklKvKwrHFAAVIwNF/RTuLYjW02JEjO+/tsRJ3wes06/hpY+3xgh Zxv+osEanpKWV+hKuU5lA2t19oMGi51owT0sbzvtnDftsMa4Te+e64Xb5f5ibCgIg3YK jv5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=/S8msf2gCblApWE9V0V52oqougW+RlLT5PRFBbIiPag=; b=Y4Btnli5d/8RKMnOg/zlJklME7Zje4bq7rMKCE5zZzU0RnwuCsYzD6deWvfVDWK8Wo KQPsYaPCJDuFWNjCe7ToaScaM0Hwj5PK4dJJXheh1349d+Wn8f90eAl+zdaAsEkknOFA KcIu6GfDG99lDykBOaRpgGtDbQiS666p9KzWLOdbfaSRwZkXWZmi+8PLFABXdLGhZBLJ fFm/sbVtLgi7pTjSj9/lzEmYa8dKZOYikUnJ2ilTQVb6ttd0IYh6qyJPkA/M6o3kzIev xvbtUjnJrFpvcoqviwpa4VcUYAF+NeoxQX/ZTvKoaM2gKugaxQlSJ6fzr78dFw6+x6U+ BACQ== X-Gm-Message-State: ANoB5ple49fSJrwo8v/Mrgb/SjdztFioewcT8HrLfQ0Ewv1q1uHFyp5s E7wS1/UddqUxEhQOw1J3VoM56p2Q2Hs= X-Google-Smtp-Source: AA0mqf5yCM4Vvwk7I+u6oMY3To0PWIkK2gpsJMUp+uzmB9vWN293SIJ7PUAmPgRT9MXugy6a3epd1A== X-Received: by 2002:a05:6512:1394:b0:4a2:3a78:106d with SMTP id p20-20020a056512139400b004a23a78106dmr3903532lfa.419.1668431322644; Mon, 14 Nov 2022 05:08:42 -0800 (PST) Received: from scuderia-pc.olvs.miee.ru ([37.204.49.88]) by smtp.gmail.com with ESMTPSA id s11-20020a056512314b00b00494618889c0sm1822710lfi.42.2022.11.14.05.08.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Nov 2022 05:08:41 -0800 (PST) From: Alexey Smirnov To: openwrt-devel@lists.openwrt.org Cc: Alexey Smirnov Subject: [PATCH 1/1] netifd: device: add ipvlan support Date: Mon, 14 Nov 2022 16:07:57 +0300 Message-Id: <20221114130757.24786-1-s.alexey@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20221114_050846_729166_220DD994 X-CRM114-Status: GOOD ( 24.22 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This almost copy-paste from macvlan device with corresponding changes. Signed-off-by: Alexey Smirnov --- CMakeLists.txt | 2 +- ipvlan.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++ system-dummy.c | 10 ++ system-linux.c | 76 ++++++++++++++ system.h | 8 ++ 5 f [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2a00:1450:4864:20:0:0:0:12b listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [s.alexey[at]gmail.com] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org This almost copy-paste from macvlan device with corresponding changes. Signed-off-by: Alexey Smirnov --- CMakeLists.txt | 2 +- ipvlan.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++ system-dummy.c | 10 ++ system-linux.c | 76 ++++++++++++++ system.h | 8 ++ 5 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 ipvlan.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b3bf411..0af7af5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ SET(SOURCES interface.c interface-ip.c interface-event.c iprule.c proto.c proto-static.c proto-shell.c config.c device.c bridge.c veth.c vlan.c alias.c - macvlan.c ubus.c vlandev.c wireless.c + ipvlan.c macvlan.c ubus.c vlandev.c wireless.c extdev.c bonding.c) diff --git a/ipvlan.c b/ipvlan.c new file mode 100644 index 0000000..af597cb --- /dev/null +++ b/ipvlan.c @@ -0,0 +1,263 @@ +/* + * netifd - network interface daemon + * Copyright (C) 2012 Felix Fietkau + * Copyright (C) 2013 Jo-Philipp Wich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + +#include "netifd.h" +#include "device.h" +#include "interface.h" +#include "system.h" + +enum { + IPVLAN_ATTR_IFNAME, + IPVLAN_ATTR_MODE, + IPVLAN_ATTR_FLAG, + __IPVLAN_ATTR_MAX +}; + +static const struct blobmsg_policy ipvlan_attrs[__IPVLAN_ATTR_MAX] = { + [IPVLAN_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_STRING }, + [IPVLAN_ATTR_MODE] = { "mode", BLOBMSG_TYPE_STRING }, + [IPVLAN_ATTR_FLAG] = { "flag", BLOBMSG_TYPE_STRING }, +}; + +static const struct uci_blob_param_list ipvlan_attr_list = { + .n_params = __IPVLAN_ATTR_MAX, + .params = ipvlan_attrs, + + .n_next = 1, + .next = { &device_attr_list }, +}; + +struct ipvlan_device { + struct device dev; + struct device_user parent; + + device_state_cb set_state; + + struct blob_attr *config_data; + struct blob_attr *ifname; + struct ipvlan_config config; +}; + +static void +ipvlan_base_cb(struct device_user *dev, enum device_event ev) +{ + struct ipvlan_device *mvdev = container_of(dev, struct ipvlan_device, parent); + + switch (ev) { + case DEV_EVENT_ADD: + device_set_present(&mvdev->dev, true); + break; + case DEV_EVENT_REMOVE: + device_set_present(&mvdev->dev, false); + break; + default: + return; + } +} + +static int +ipvlan_set_down(struct ipvlan_device *mvdev) +{ + mvdev->set_state(&mvdev->dev, false); + system_ipvlan_del(&mvdev->dev); + device_release(&mvdev->parent); + + return 0; +} + +static int +ipvlan_set_up(struct ipvlan_device *mvdev) +{ + int ret; + + ret = device_claim(&mvdev->parent); + if (ret < 0) + return ret; + + ret = system_ipvlan_add(&mvdev->dev, mvdev->parent.dev, &mvdev->config); + if (ret < 0) + goto release; + + ret = mvdev->set_state(&mvdev->dev, true); + if (ret) + goto delete; + + return 0; + +delete: + system_ipvlan_del(&mvdev->dev); +release: + device_release(&mvdev->parent); + return ret; +} + +static int +ipvlan_set_state(struct device *dev, bool up) +{ + struct ipvlan_device *mvdev; + + D(SYSTEM, "ipvlan_set_state(%s, %u)\n", dev->ifname, up); + + mvdev = container_of(dev, struct ipvlan_device, dev); + if (up) + return ipvlan_set_up(mvdev); + else + return ipvlan_set_down(mvdev); +} + +static void +ipvlan_free(struct device *dev) +{ + struct ipvlan_device *mvdev; + + mvdev = container_of(dev, struct ipvlan_device, dev); + device_remove_user(&mvdev->parent); + free(mvdev->config_data); + free(mvdev); +} + +static void +ipvlan_dump_info(struct device *dev, struct blob_buf *b) +{ + struct ipvlan_device *mvdev; + + mvdev = container_of(dev, struct ipvlan_device, dev); + blobmsg_add_string(b, "parent", mvdev->parent.dev->ifname); + system_if_dump_info(dev, b); +} + +static void +ipvlan_config_init(struct device *dev) +{ + struct ipvlan_device *mvdev; + struct device *basedev = NULL; + + mvdev = container_of(dev, struct ipvlan_device, dev); + if (mvdev->ifname) + basedev = device_get(blobmsg_data(mvdev->ifname), true); + + device_add_user(&mvdev->parent, basedev); +} + +static void +ipvlan_apply_settings(struct ipvlan_device *mvdev, struct blob_attr **tb) +{ + struct ipvlan_config *cfg = &mvdev->config; + struct blob_attr *cur; + + cfg->mode = NULL; + cfg->flag = NULL; + + if ((cur = tb[IPVLAN_ATTR_MODE])) + cfg->mode = blobmsg_data(cur); + + if ((cur = tb[IPVLAN_ATTR_FLAG])) + cfg->flag = blobmsg_data(cur); +} + +static enum dev_change_type +ipvlan_reload(struct device *dev, struct blob_attr *attr) +{ + struct blob_attr *tb_dev[__DEV_ATTR_MAX]; + struct blob_attr *tb_mv[__IPVLAN_ATTR_MAX]; + enum dev_change_type ret = DEV_CONFIG_APPLIED; + struct ipvlan_device *mvdev; + + mvdev = container_of(dev, struct ipvlan_device, dev); + attr = blob_memdup(attr); + + blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev, + blob_data(attr), blob_len(attr)); + blobmsg_parse(ipvlan_attrs, __IPVLAN_ATTR_MAX, tb_mv, + blob_data(attr), blob_len(attr)); + + device_init_settings(dev, tb_dev); + ipvlan_apply_settings(mvdev, tb_mv); + mvdev->ifname = tb_mv[IPVLAN_ATTR_IFNAME]; + + if (mvdev->config_data) { + struct blob_attr *otb_dev[__DEV_ATTR_MAX]; + struct blob_attr *otb_mv[__IPVLAN_ATTR_MAX]; + + blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev, + blob_data(mvdev->config_data), blob_len(mvdev->config_data)); + + if (uci_blob_diff(tb_dev, otb_dev, &device_attr_list, NULL)) + ret = DEV_CONFIG_RESTART; + + blobmsg_parse(ipvlan_attrs, __IPVLAN_ATTR_MAX, otb_mv, + blob_data(mvdev->config_data), blob_len(mvdev->config_data)); + + if (uci_blob_diff(tb_mv, otb_mv, &ipvlan_attr_list, NULL)) + ret = DEV_CONFIG_RESTART; + + ipvlan_config_init(dev); + } + + free(mvdev->config_data); + mvdev->config_data = attr; + return ret; +} + +static struct device * +ipvlan_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) +{ + struct ipvlan_device *mvdev; + struct device *dev = NULL; + + mvdev = calloc(1, sizeof(*mvdev)); + if (!mvdev) + return NULL; + + dev = &mvdev->dev; + if (device_init(dev, devtype, name) < 0) { + device_cleanup(dev); + free(mvdev); + return NULL; + } + + dev->config_pending = true; + + mvdev->set_state = dev->set_state; + dev->set_state = ipvlan_set_state; + + dev->hotplug_ops = NULL; + mvdev->parent.cb = ipvlan_base_cb; + + ipvlan_reload(dev, attr); + + return dev; +} + +static struct device_type ipvlan_device_type = { + .name = "ipvlan", + .config_params = &ipvlan_attr_list, + .create = ipvlan_create, + .config_init = ipvlan_config_init, + .reload = ipvlan_reload, + .free = ipvlan_free, + .dump_info = ipvlan_dump_info, +}; + +static void __init ipvlan_device_type_init(void) +{ + device_type_add(&ipvlan_device_type); +} diff --git a/system-dummy.c b/system-dummy.c index b13bc87..c68fd2b 100644 --- a/system-dummy.c +++ b/system-dummy.c @@ -350,6 +350,16 @@ int system_update_ipv6_mtu(struct device *dev, int mtu) return 0; } +int system_ipvlan_add(struct device *ipvlan, struct device *dev, struct ipvlan_config *cfg) +{ + return 0; +} + +int system_ipvlan_del(struct device *ipvlan) +{ + return 0; +} + int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg) { return 0; diff --git a/system-linux.c b/system-linux.c index 0f13a99..adaeeb2 100644 --- a/system-linux.c +++ b/system-linux.c @@ -1363,6 +1363,82 @@ nla_put_failure: return -ENOMEM; } +int system_ipvlan_add(struct device *ipvlan, struct device *dev, struct ipvlan_config *cfg) +{ + struct nl_msg *msg; + struct nlattr *linkinfo, *data; + int i, rv; + static const struct { + const char *name; + enum ipvlan_mode val; + } modes[] = { + { "l3", IPVLAN_MODE_L3 }, + { "l3s", IPVLAN_MODE_L3S }, + { "l2", IPVLAN_MODE_L2 }, + }; + + static const struct { + const char *name; + unsigned short val; + } flags[] = { + { "bridge", 0 }, + { "private", IPVLAN_F_PRIVATE }, + { "vepa", IPVLAN_F_VEPA }, + }; + + msg = system_ifinfo_msg(ipvlan->ifname, RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL); + if (!msg) + return -1; + + nla_put_u32(msg, IFLA_LINK, dev->ifindex); + + if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO))) + goto nla_put_failure; + + nla_put_string(msg, IFLA_INFO_KIND, "ipvlan"); + + 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_u16(msg, IFLA_IPVLAN_MODE, modes[i].val); + break; + } + } + + if (cfg->flag) { + for (i = 0; i < ARRAY_SIZE(flags); i++) { + if (strcmp(cfg->flag, flags[i].name) != 0) + continue; + + nla_put_u16(msg, IFLA_IPVLAN_FLAGS, flags[i].val); + break; + } + } + + nla_nest_end(msg, data); + nla_nest_end(msg, linkinfo); + + rv = system_rtnl_call(msg); + if (rv) + D(SYSTEM, "Error adding ipvlan '%s' over '%s': %d\n", ipvlan->ifname, dev->ifname, rv); + + return rv; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + +int system_ipvlan_del(struct device *ipvlan) +{ + return system_link_del(ipvlan->ifname); +} + int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg) { struct nl_msg *msg; diff --git a/system.h b/system.h index 0f08c26..b119084 100644 --- a/system.h +++ b/system.h @@ -210,6 +210,11 @@ struct bridge_config { bool vlan_filtering; }; +struct ipvlan_config { + const char *mode; + const char *flag; +}; + enum macvlan_opt { MACVLAN_OPT_MACADDR = (1 << 0), }; @@ -322,6 +327,9 @@ void system_bridge_set_stp_state(struct device *dev, bool val); int system_bonding_set_device(struct device *dev, struct bonding_config *cfg); int system_bonding_set_port(struct device *dev, struct device *port, bool add, bool primary); +int system_ipvlan_add(struct device *ipvlan, struct device *dev, struct ipvlan_config *cfg); +int system_ipvlan_del(struct device *ipvlan); + int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg); int system_macvlan_del(struct device *macvlan);