[PATCH netifd] team: add simple bonding/teaming module

Pavel Šimerda code at simerda.eu
Sat Jan 16 08:25:10 EST 2021


On 1/16/21 1:55 PM, Petr Štetiar wrote:
> Pavel Šimerda <code at simerda.eu> [2021-01-12 04:36:36]:
> 
> Hi,
> 
>> The module requires libteam's teamd and teamdctl commands.
> 
> This looks like an alien to the OpenWrt ecosystem, basically you're using
> netifd just as a launcher for teamd, teamdctl without any proper error
> handling instead of ubus for configuration etc.

Hey Petr,

this is what I'm using right now to enable the hardware features that were *absent* in OpenWRT. Would you suggest that we keep a local fork for the time being, until someone is willing to invest their time into building a ubus wrapper for libteam?

Cheers,

Pavel Šimerda

> 
>> Signed-off-by: Pavel Šimerda <code at simerda.eu>
>> ---
>>   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 <code at simerda.eu>
>> + *
>> + * 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 <string.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <assert.h>
>> +#include <errno.h>
>> +#include <signal.h>
>> +#include <sys/wait.h>
>> +#include <unistd.h>
>> +
>> +#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");
> 
> if this is needed at all, take a look around and use proper debug logging
> 
>> +		pid = fork();
>> +		if (pid == -1)
>> +			return -errno;
>> +		if (pid == 0)
>> +			execlp("teamd", "teamd", "-t", dev->ifname, NULL);
> 
> this is external dependency and you lack any check for that
> 
>> +		teamdev->pid = pid;
>> +		// TODO: Better handling of newly created devices.
> 
> better? there is no handling of anything
> 
>> +		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);
> 
> puting aside usage of system() for service configuration this smells, you're
> passing possibly malicious input directly to system() in the service running
> as root, what could go wrong?
> 
>> +			}
>> +		}
>> +		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);
>> +}
>> -- 
>> 2.29.2



More information about the openwrt-devel mailing list