From patchwork Tue Jan 12 03:36:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pavel_=C5=A0imerda?= X-Patchwork-Id: 1424964 X-Patchwork-Delegate: ynezz@true.cz Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.openwrt.org (client-ip=2001:8b0:10b:1231::1; helo=merlin.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=simerda.eu Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=merlin.20170209 header.b=E92aW6Wu; dkim-atps=neutral Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:8b0:10b:1231::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DFGXk3hr5z9sXH for ; Tue, 12 Jan 2021 14:39:30 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject: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=xzQVBdp1KsfQYAnv3uiIwppq+VomNyydPLuztTyeoew=; b=E92aW6Wul8iUCHX31zhZJ5EqZs tJtECKwkYkEVsi9+TccMP3B2zfiWYJ6oom9yGihEdLUcGrjinGC688WiPLS4fNxZTzWA61wjp7Cp2 amlOk7cbOVwyXtGsEtAVIh6/Tger4CSIjetJw+3bR3of/TklV85ms/GSne1gBBxFMSMzO5M3j5UCQ mAWPm2csA+9ryBc3qF0tTZmjPG9vhi45G/qf0GLvyjl0DPrQPd9y39XMw1UYuu7pNdDPwqhnrN+hD OwHrCbvNC3EsHZ3DIcHAK3zR8ls1ioFqJEps4TIGbGL6fBvbTZ5m+w7ITPTyrdJyyHIIuTELURolG M5NHXKNA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kzAUH-0005l3-3j; Tue, 12 Jan 2021 03:36:53 +0000 Received: from fox.pavlix.cz ([2a01:430:17:1::ffff:1417]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kzAUD-0005iX-7P for openwrt-devel@lists.openwrt.org; Tue, 12 Jan 2021 03:36:50 +0000 Received: from zorg.lan (unknown [217.30.64.218]) by fox.pavlix.cz (Postfix) with ESMTPSA id 99681E25C4; Tue, 12 Jan 2021 04:36:41 +0100 (CET) From: =?utf-8?q?Pavel_=C5=A0imerda?= To: openwrt-devel@lists.openwrt.org Subject: [PATCH netifd] team: add simple bonding/teaming module Date: Tue, 12 Jan 2021 04:36:36 +0100 Message-Id: <20210112033636.31687-1-code@simerda.eu> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210111_223649_409750_38857775 X-CRM114-Status: GOOD ( 20.38 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Pavel_=C5=A0imerda?= Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org An initial version of a bonding/teaming module based on libteam and the kernel team driver. It is capable of creating a team device and add member ports. The ultimate goal is to support LAG offloaded to DSA switch hardware with teamd handling the LACP management. config interface teamdev option ifname "lan1 lan2" option type team The module requires libteam's teamd and teamdctl commands. Signed-off-by: Pavel Šimerda --- CMakeLists.txt | 2 +- team.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 team.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d19817..351e303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ SET(SOURCES main.c utils.c system.c tunnel.c handler.c 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 + config.c device.c bridge.c team.c veth.c vlan.c alias.c macvlan.c ubus.c vlandev.c wireless.c) diff --git a/team.c b/team.c new file mode 100644 index 0000000..9b67566 --- /dev/null +++ b/team.c @@ -0,0 +1,178 @@ +/* + * netifd - network interface daemon + * Copyright (C) 2021 Pavel Šimerda + * + * 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 +#include +#include + +#include "netifd.h" +#include "device.h" +#include "interface.h" +#include "system.h" + +enum { + TEAM_ATTR_IFNAME, + __TEAM_ATTR_MAX +}; + +static const struct blobmsg_policy team_attrs[__TEAM_ATTR_MAX] = { + [TEAM_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY }, +}; + +static const struct uci_blob_param_info team_attr_info[__TEAM_ATTR_MAX] = { + [TEAM_ATTR_IFNAME] = { .type = BLOBMSG_TYPE_STRING }, +}; + +static const struct uci_blob_param_list team_attr_list = { + .n_params = __TEAM_ATTR_MAX, + .params = team_attrs, + .info = team_attr_info, + + .n_next = 1, + .next = { &device_attr_list }, +}; + +struct team_device { + struct device dev; + device_state_cb set_state; + + struct blob_attr *config_data; + struct blob_attr *ifnames; + + int pid; +}; + +static int +team_set_state(struct device *dev, bool up) +{ + struct team_device *teamdev = container_of(dev, struct team_device, dev); + + if (up) { + int pid; + struct blob_attr *cur; + int rem; + char buffer[64]; + + printf("TEAM start teamd\n"); + + pid = fork(); + if (pid == -1) + return -errno; + if (pid == 0) + execlp("teamd", "teamd", "-t", dev->ifname, NULL); + teamdev->pid = pid; + // TODO: Better handling of newly created devices. + sleep(1); + if (teamdev->ifnames) { + printf("TEAM port init\n"); + blobmsg_for_each_attr(cur, teamdev->ifnames, rem) { + printf("TEAM one port init\n"); + snprintf(buffer, sizeof buffer, + "teamdctl %s port add %s", + dev->ifname, + blobmsg_get_string(cur)); + system(buffer); + } + } + teamdev->set_state(dev, up); + return 0; + } else { + printf("TEAM: killing %d\n", teamdev->pid); + if (teamdev->pid) { + kill(teamdev->pid, SIGTERM); + waitpid(teamdev->pid, NULL, 0); + teamdev->pid = 0; + } + return 0; + } +} + +static enum dev_change_type +team_reload(struct device *dev, struct blob_attr *attr) +{ + struct team_device *teamdev = container_of(dev, struct team_device, dev); + struct blob_attr *tb_tm[__TEAM_ATTR_MAX]; + + attr = blob_memdup(attr); + + blobmsg_parse(team_attrs, __TEAM_ATTR_MAX, tb_tm, blob_data(attr), blob_len(attr)); + teamdev->ifnames = tb_tm[TEAM_ATTR_IFNAME]; + + if (teamdev->pid) { + // TODO: More fine-grained reconfiguration + team_set_state(dev, false); + team_set_state(dev, true); + } + + free(teamdev->config_data); + teamdev->config_data = attr; + return DEV_CONFIG_APPLIED; +} + +static struct device * +team_create(const char *name, struct device_type *devtype, + struct blob_attr *attr) +{ + struct team_device *teamdev; + struct device *dev = NULL; + + teamdev = calloc(1, sizeof(*teamdev)); + if (!teamdev) + return NULL; + dev = &teamdev->dev; + + if (device_init(dev, devtype, name) < 0) { + device_cleanup(dev); + free(teamdev); + return NULL; + } + + teamdev->set_state = dev->set_state; + dev->set_state = team_set_state; + + device_set_present(dev, true); + team_reload(dev, attr); + + return dev; +} + +static void +team_free(struct device *dev) +{ + struct team_device *teamdev = container_of(dev, struct team_device, dev); + + free(teamdev->config_data); + free(teamdev); +} + +static struct device_type team_device_type = { + .name = "team", + .config_params = &team_attr_list, + + .bridge_capability = true, + .name_prefix = "tm", + + .create = team_create, + .reload = team_reload, + .free = team_free, +}; + +static void __init team_device_type_init(void) +{ + device_type_add(&team_device_type); +}