Blame cgdcbxd.c

Packit 84c3e8
/*
Packit 84c3e8
 * Copyright Intel Corporation. 2012
Packit 84c3e8
 *
Packit 84c3e8
 * Authors:	John Fastabend <john.r.fastabend@lintel.com>
Packit 84c3e8
 *
Packit 84c3e8
 * This program is free software; you can redistribute it and/or modify it
Packit 84c3e8
 * under the terms and conditions of the GNU General Public License,
Packit 84c3e8
 * version 2, as published by the Free Software Foundation.
Packit 84c3e8
 *
Packit 84c3e8
 * This program is distributed in the hope it will be useful, but WITHOUT
Packit 84c3e8
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 84c3e8
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit 84c3e8
 * more details.
Packit 84c3e8
 *
Packit 84c3e8
 * You should have received a copy of the GNU General Public License along with
Packit 84c3e8
 * this program; if not, write to the Free Software Foundation, Inc.,
Packit 84c3e8
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit 84c3e8
 * This program is free software; you can redistribute it and/or modify it
Packit 84c3e8
 * under the terms and conditions of the GNU General Public License,
Packit 84c3e8
 * version 2, as published by the Free Software Foundation.
Packit 84c3e8
 *
Packit 84c3e8
 * The full GNU General Public License is included in this distribution in
Packit 84c3e8
 * the file called "COPYING".
Packit 84c3e8
 */
Packit 84c3e8
Packit 84c3e8
#include <libcgroup.h>
Packit 84c3e8
#include <stdio.h>
Packit 84c3e8
#include <stdlib.h>
Packit 84c3e8
#include <string.h>
Packit 84c3e8
#include <errno.h>
Packit 84c3e8
#include <getopt.h>
Packit 84c3e8
#include <libmnl/libmnl.h>
Packit 84c3e8
#include <linux/if_link.h>
Packit 84c3e8
#include <linux/rtnetlink.h>
Packit 84c3e8
#include <net/if.h>
Packit 84c3e8
#include <linux/dcbnl.h>
Packit 84c3e8
#include <sys/queue.h>
Packit 84c3e8
#include <signal.h>
Packit 84c3e8
#include <sys/select.h>
Packit 84c3e8
#include <syslog.h>
Packit 84c3e8
#include <sys/file.h>
Packit 84c3e8
#include <unistd.h>
Packit 84c3e8
#include <time.h>
Packit 84c3e8
Packit 84c3e8
#define UNUSED __attribute__((__unused__))
Packit 84c3e8
Packit 84c3e8
#define PID_FILE "/var/run/cgdcbxd.pid"
Packit 84c3e8
#define NET_PRIO "net_prio"
Packit 84c3e8
#define IFPRIOMAP "net_prio.ifpriomap"
Packit 84c3e8
Packit 84c3e8
struct cgdcbx_virt {
Packit 84c3e8
	char *ifname;
Packit 84c3e8
	int ifindex;
Packit 84c3e8
	__u32 iflink;
Packit 84c3e8
	LIST_ENTRY(cgdcbx_virt) entry;
Packit 84c3e8
};
Packit 84c3e8
Packit 84c3e8
struct cgdcbx_entry {
Packit 84c3e8
	struct dcb_app app;
Packit 84c3e8
	bool active;
Packit 84c3e8
	LIST_ENTRY(cgdcbx_entry) entry;
Packit 84c3e8
};
Packit 84c3e8
Packit 84c3e8
struct cgdcbx_iface {
Packit 84c3e8
	char *ifname;
Packit 84c3e8
	int mode;
Packit 84c3e8
	int ifindex;
Packit 84c3e8
	int dflt_priority;
Packit 84c3e8
	LIST_HEAD(cgdcbx_apps, cgdcbx_entry) apps;
Packit 84c3e8
	LIST_HEAD(cgdcbx_slaves, cgdcbx_virt) virt;
Packit 84c3e8
	LIST_ENTRY(cgdcbx_iface) entry;
Packit 84c3e8
};
Packit 84c3e8
Packit 84c3e8
LIST_HEAD(cgdcbx_iface_head, cgdcbx_iface) iface_list;
Packit 84c3e8
Packit 84c3e8
static void usage(const char *program_name)
Packit 84c3e8
{
Packit 84c3e8
	fprintf(stderr,
Packit 84c3e8
		"\n"
Packit 84c3e8
		"Usage: %s [-hn]"
Packit 84c3e8
		"\n"
Packit 84c3e8
		"options:\n"
Packit 84c3e8
		"   -h  show this usage\n"
Packit 84c3e8
		"   -n  don't fork daemon\n",
Packit 84c3e8
		program_name);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int dcb_attr_cb(const struct nlattr *attr, void *data)
Packit 84c3e8
{
Packit 84c3e8
	const struct nlattr **tb = (const struct nlattr **)data;
Packit 84c3e8
	int type = mnl_attr_get_type(attr);
Packit 84c3e8
	int ret = 0;
Packit 84c3e8
Packit 84c3e8
	/* skip unsupported attribute in user-space */
Packit 84c3e8
	if (mnl_attr_type_valid(attr, DCB_CMD_MAX) < 0)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	switch (type) {
Packit 84c3e8
	case DCB_ATTR_IFNAME:
Packit 84c3e8
		ret = mnl_attr_validate(attr, MNL_TYPE_STRING);
Packit 84c3e8
		break;
Packit 84c3e8
	case DCB_ATTR_APP:
Packit 84c3e8
		ret = mnl_attr_validate(attr, MNL_TYPE_NESTED);
Packit 84c3e8
		break;
Packit 84c3e8
	case DCB_CMD_GDCBX:
Packit 84c3e8
		ret = mnl_attr_validate(attr, MNL_TYPE_U8);
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (ret < 0) {
Packit 84c3e8
		perror("mnl_attr_validate");
Packit 84c3e8
		return MNL_CB_ERROR;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	tb[type] = attr;
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int parse_attr_ieee(const struct nlattr *attr, void *data)
Packit 84c3e8
{
Packit 84c3e8
	const struct nlattr **tb = data;
Packit 84c3e8
	int type = mnl_attr_get_type(attr);
Packit 84c3e8
Packit 84c3e8
	if (mnl_attr_type_valid(attr, DCB_ATTR_IEEE_MAX) < 0)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	switch (type) {
Packit 84c3e8
	case DCB_ATTR_IEEE_APP_TABLE:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate: DCB_ATTR_IEEE_APP_TABLE");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	tb[type] = attr;
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int parse_attr_cee(const struct nlattr *attr, void *data)
Packit 84c3e8
{
Packit 84c3e8
	const struct nlattr **tb = data;
Packit 84c3e8
	int type = mnl_attr_get_type(attr);
Packit 84c3e8
Packit 84c3e8
	if (mnl_attr_type_valid(attr, DCB_ATTR_CEE_MAX) < 0)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	switch (type) {
Packit 84c3e8
	case DCB_ATTR_CEE_APP_TABLE:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate: DCB_ATTR_CEE_TABLE");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	tb[type] = attr;
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static struct cgdcbx_entry *__cgdcbx_lookup_app(struct cgdcbx_iface *iface,
Packit 84c3e8
						struct dcb_app *app)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_entry *np;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(np, &iface->apps, entry) {
Packit 84c3e8
		if (np->app.selector == app->selector &&
Packit 84c3e8
		    np->app.protocol == app->protocol)
Packit 84c3e8
			return np;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return NULL;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static struct cgdcbx_entry *cgdcbx_lookup_app(struct cgdcbx_iface *iface,
Packit 84c3e8
					      struct dcb_app *app)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_entry *entry = __cgdcbx_lookup_app(iface, app);
Packit 84c3e8
Packit 84c3e8
	if (entry) {
Packit 84c3e8
		entry->app.priority = app->priority;
Packit 84c3e8
		entry->active = true;
Packit 84c3e8
	} else {
Packit 84c3e8
		entry = malloc(sizeof(*entry));
Packit 84c3e8
		if (!entry)
Packit 84c3e8
			return NULL;
Packit 84c3e8
Packit 84c3e8
		memcpy(&entry->app, app, sizeof(entry->app));
Packit 84c3e8
		entry->active = true;
Packit 84c3e8
		LIST_INSERT_HEAD(&iface->apps, entry, entry);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return entry;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int cgdcbx_del_cgroup(struct cgroup *cg)
Packit 84c3e8
{
Packit 84c3e8
	int err = cgroup_delete_cgroup(cg, 1);
Packit 84c3e8
Packit 84c3e8
	if (err)
Packit 84c3e8
		fprintf(stderr, "cgdcbx: libcgroup delete cgroup failed: %s\n",
Packit 84c3e8
			cgroup_strerror(err));
Packit 84c3e8
	return err;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int link_attr_cb(const struct nlattr *attr, void *data)
Packit 84c3e8
{
Packit 84c3e8
	const struct nlattr **tb = (const struct nlattr **)data;
Packit 84c3e8
	int type = mnl_attr_get_type(attr);
Packit 84c3e8
Packit 84c3e8
	/* skip unsupported attribute in user-space */
Packit 84c3e8
	if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	switch (type) {
Packit 84c3e8
	case IFLA_IFNAME:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate IFLA_IFNAME");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	case IFLA_LINK:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate IFLA_LINK");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	tb[type] = attr;
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
struct cgdcbx_link_data {
Packit 84c3e8
	struct cgdcbx_iface *iface;
Packit 84c3e8
	struct cgdcbx_virt *virt;
Packit 84c3e8
	int nlmsg_type;
Packit 84c3e8
	unsigned ifi_flags;
Packit 84c3e8
};
Packit 84c3e8
Packit 84c3e8
static int cgdcbx_link_cb(const struct nlmsghdr *nlh, void *data)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *iface = NULL;
Packit 84c3e8
	struct cgdcbx_virt *virt = NULL;
Packit 84c3e8
	struct cgdcbx_link_data *cgdcbx_data = data;
Packit 84c3e8
	const struct nlattr *tb[IFLA_MAX+1] = {};
Packit 84c3e8
	struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
Packit 84c3e8
Packit 84c3e8
	mnl_attr_parse(nlh, sizeof(*ifm), link_attr_cb, tb);
Packit 84c3e8
Packit 84c3e8
	/* Require IFLA_IFNAME attribute to build priomap string */
Packit 84c3e8
	if (!tb[IFLA_IFNAME])
Packit 84c3e8
		goto out;
Packit 84c3e8
Packit 84c3e8
	/* Add priomap string to cgroup */
Packit 84c3e8
	if (tb[IFLA_LINK]) {
Packit 84c3e8
		struct cgdcbx_virt *v;
Packit 84c3e8
		__u32 iflink = mnl_attr_get_u32(tb[IFLA_LINK]);
Packit 84c3e8
Packit 84c3e8
		/* Check that device does not already exist */
Packit 84c3e8
		LIST_FOREACH(iface, &iface_list, entry) {
Packit 84c3e8
			LIST_FOREACH(virt, &iface->virt, entry) {
Packit 84c3e8
				if (virt->ifindex == ifm->ifi_index)
Packit 84c3e8
					goto out;
Packit 84c3e8
			}
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		virt = malloc(sizeof(struct cgdcbx_virt));
Packit 84c3e8
		if (!virt)
Packit 84c3e8
			goto out;
Packit 84c3e8
Packit 84c3e8
		virt->ifname = strdup(mnl_attr_get_str(tb[IFLA_IFNAME]));
Packit 84c3e8
		virt->ifindex = ifm->ifi_index;
Packit 84c3e8
		virt->iflink = iflink;
Packit 84c3e8
Packit 84c3e8
		/* Devices can be stacked on other virtual devices so we
Packit 84c3e8
		 * must search list of virtual devices for a map and add
Packit 84c3e8
		 * to virtual device list to propagate priority.
Packit 84c3e8
		 */
Packit 84c3e8
		LIST_FOREACH(iface, &iface_list, entry) {
Packit 84c3e8
			if (iflink == if_nametoindex(iface->ifname)) {
Packit 84c3e8
				LIST_INSERT_HEAD(&iface->virt, virt, entry);
Packit 84c3e8
				goto out;
Packit 84c3e8
			}
Packit 84c3e8
			LIST_FOREACH(v, &iface->virt, entry) {
Packit 84c3e8
				if (iflink == if_nametoindex(v->ifname)) {
Packit 84c3e8
					LIST_INSERT_HEAD(&iface->virt,
Packit 84c3e8
							 virt,
Packit 84c3e8
							 entry);
Packit 84c3e8
					goto out;
Packit 84c3e8
				}
Packit 84c3e8
			}
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		free(virt->ifname);
Packit 84c3e8
		free(virt);
Packit 84c3e8
	} else {
Packit 84c3e8
		/* Check that device does not already exist */
Packit 84c3e8
		LIST_FOREACH(iface, &iface_list, entry) {
Packit 84c3e8
			if (iface->ifindex == ifm->ifi_index)
Packit 84c3e8
				goto out;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		/* If device is not being tracked wait for DCB event */
Packit 84c3e8
	}
Packit 84c3e8
	iface = NULL;
Packit 84c3e8
	virt = NULL;
Packit 84c3e8
out:
Packit 84c3e8
	if (cgdcbx_data) {
Packit 84c3e8
		cgdcbx_data->nlmsg_type = nlh->nlmsg_type;
Packit 84c3e8
		cgdcbx_data->iface = iface;
Packit 84c3e8
		cgdcbx_data->virt = virt;
Packit 84c3e8
		cgdcbx_data->ifi_flags = ifm->ifi_flags;
Packit 84c3e8
	}
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_write_virtmap(struct cgdcbx_virt *virt,
Packit 84c3e8
				 char *file, struct cgdcbx_entry *np)
Packit 84c3e8
{
Packit 84c3e8
	struct cgroup *vcg_app;
Packit 84c3e8
	struct cgroup_controller *vcg_ctrl;
Packit 84c3e8
	char value[IFNAMSIZ + 3];
Packit 84c3e8
	int err;
Packit 84c3e8
Packit 84c3e8
	vcg_app = cgroup_new_cgroup(file);
Packit 84c3e8
	if (!vcg_app) {
Packit 84c3e8
		fprintf(stderr,
Packit 84c3e8
			"cgdcbx: libcgroup %s cgroup_new_cgroup failed\n",
Packit 84c3e8
			file);
Packit 84c3e8
		return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	vcg_ctrl = cgroup_get_controller(vcg_app, NET_PRIO);
Packit 84c3e8
	if (!vcg_ctrl) {
Packit 84c3e8
		vcg_ctrl = cgroup_add_controller(vcg_app, NET_PRIO);
Packit 84c3e8
		if (!vcg_ctrl)
Packit 84c3e8
			return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	err = cgroup_create_cgroup(vcg_app, 1);
Packit 84c3e8
	if (err) {
Packit 84c3e8
		fprintf(stderr,
Packit 84c3e8
			"cgdcbx: libcgroup %s create failed: %s\n",
Packit 84c3e8
			file,
Packit 84c3e8
			cgroup_strerror(err));
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	snprintf(value, sizeof(value), "%s %i", virt->ifname, np->app.priority);
Packit 84c3e8
Packit 84c3e8
	err = cgroup_add_value_string(vcg_ctrl, IFPRIOMAP, value);
Packit 84c3e8
	if (err) {
Packit 84c3e8
		fprintf(stderr,
Packit 84c3e8
			"cgdcbx: %s: libcgroup %s add value failed: %s\n",
Packit 84c3e8
			virt->ifname, file, cgroup_strerror(err));
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	err = cgroup_modify_cgroup(vcg_app);
Packit 84c3e8
	cgroup_free(&vcg_app);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_write_ifpriomap(struct cgdcbx_iface *iface, char *file,
Packit 84c3e8
				   struct cgdcbx_entry *np)
Packit 84c3e8
{
Packit 84c3e8
	struct cgroup *cg_app;
Packit 84c3e8
	struct cgroup_controller *cg_ctrl;
Packit 84c3e8
	int err;
Packit 84c3e8
Packit 84c3e8
	cg_app = cgroup_new_cgroup(file);
Packit 84c3e8
	if (!cg_app) {
Packit 84c3e8
		fprintf(stderr,
Packit 84c3e8
			"cgdcbx: libcgroup %s cgroup_new_cgroup failed\n",
Packit 84c3e8
			file);
Packit 84c3e8
		return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	cg_ctrl = cgroup_get_controller(cg_app, NET_PRIO);
Packit 84c3e8
	if (!cg_ctrl) {
Packit 84c3e8
		cg_ctrl = cgroup_add_controller(cg_app, NET_PRIO);
Packit 84c3e8
		if (!cg_ctrl) {
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"cgdcbx: libcgroup %s get & add failed\n",
Packit 84c3e8
				file);
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (!np->active) {
Packit 84c3e8
		struct cgdcbx_iface *itr;
Packit 84c3e8
		struct cgdcbx_entry *entry = NULL;
Packit 84c3e8
		struct dcb_app app = np->app;
Packit 84c3e8
Packit 84c3e8
		entry = __cgdcbx_lookup_app(iface, &np->app);
Packit 84c3e8
		if (entry) {
Packit 84c3e8
			LIST_REMOVE(entry, entry);
Packit 84c3e8
			free(entry);
Packit 84c3e8
		} else {
Packit 84c3e8
			fprintf(stderr, "cgdcbx: request delete entry that does not exist\n");
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		LIST_FOREACH(itr, &iface_list, entry) {
Packit 84c3e8
			entry = __cgdcbx_lookup_app(itr, &app);
Packit 84c3e8
Packit 84c3e8
			if (entry)
Packit 84c3e8
				break;
Packit 84c3e8
		}
Packit 84c3e8
		/* Only remove cgroup if its not in use */
Packit 84c3e8
		if (!entry)
Packit 84c3e8
			err = cgdcbx_del_cgroup(cg_app);
Packit 84c3e8
	} else {
Packit 84c3e8
		char value[IFNAMSIZ + 3];
Packit 84c3e8
		struct cgdcbx_virt *virt;
Packit 84c3e8
Packit 84c3e8
		err = cgroup_create_cgroup(cg_app, 1);
Packit 84c3e8
		if (err) {
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"cgdcbx: libcgroup %s create failed: %s\n",
Packit 84c3e8
				file,
Packit 84c3e8
				cgroup_strerror(err));
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		snprintf(value, sizeof(value), "%s %i",
Packit 84c3e8
			 iface->ifname, np->app.priority);
Packit 84c3e8
		err = cgroup_add_value_string(cg_ctrl, IFPRIOMAP, value);
Packit 84c3e8
		if (err) {
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"cgdcbx: %s: libcgroup %s add value failed: %s\n",
Packit 84c3e8
				iface->ifname,
Packit 84c3e8
				file,
Packit 84c3e8
				cgroup_strerror(err));
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		/* Update any stacked devices as well */
Packit 84c3e8
		virt = LIST_FIRST(&iface->virt);
Packit 84c3e8
		while (virt) {
Packit 84c3e8
			cgdcbx_write_virtmap(virt, file, np);
Packit 84c3e8
			virt = LIST_NEXT(virt, entry);
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		err = cgroup_modify_cgroup(cg_app);
Packit 84c3e8
		if (err) {
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"cgdcbx: libcgroup modify \"%s %s\" cgroup failed(%i): %s\n",
Packit 84c3e8
				value,
Packit 84c3e8
				file,
Packit 84c3e8
				err,
Packit 84c3e8
				cgroup_strerror(err));
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
	}
Packit 84c3e8
err:
Packit 84c3e8
	cgroup_free(&cg_app);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbxd_update_default_iface_prio(struct cgdcbx_iface *iface)
Packit 84c3e8
{
Packit 84c3e8
	char child_name[FILENAME_MAX] = "";
Packit 84c3e8
	void *handle;
Packit 84c3e8
	struct cgroup_file_info info;
Packit 84c3e8
	int ret, level, group_len;
Packit 84c3e8
	struct cgdcbx_entry entry;
Packit 84c3e8
Packit 84c3e8
	/* Initialize dummy default priority entry */
Packit 84c3e8
	entry.app.selector = 1;
Packit 84c3e8
	entry.app.protocol = 0;
Packit 84c3e8
	entry.app.priority = iface->dflt_priority;
Packit 84c3e8
	entry.active = 1;
Packit 84c3e8
Packit 84c3e8
	ret = cgroup_walk_tree_begin(NET_PRIO, "/", 0, &handle, &info, &level);
Packit 84c3e8
	if (ret)
Packit 84c3e8
		return;
Packit 84c3e8
Packit 84c3e8
	ret = cgroup_walk_tree_set_flags(&handle, CGROUP_WALK_TYPE_POST_DIR);
Packit 84c3e8
	if (ret) {
Packit 84c3e8
		cgroup_walk_tree_end(&handle);
Packit 84c3e8
		return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	cgdcbx_write_ifpriomap(iface, "/", &entry);
Packit 84c3e8
Packit 84c3e8
	group_len = strlen(info.full_path);
Packit 84c3e8
Packit 84c3e8
	/*
Packit 84c3e8
	 * Skip the root group, it will be handled explicitly at the end.
Packit 84c3e8
	 */
Packit 84c3e8
	ret = cgroup_walk_tree_next(0, &handle, &info, level);
Packit 84c3e8
Packit 84c3e8
	while (ret == 0) {
Packit 84c3e8
		if (info.type == CGROUP_FILE_TYPE_DIR && info.depth > 0) {
Packit 84c3e8
			struct cgdcbx_entry *np;
Packit 84c3e8
			int selector = 0, protocol = 0;
Packit 84c3e8
Packit 84c3e8
			snprintf(child_name, sizeof(child_name), "%s",
Packit 84c3e8
				 info.full_path + group_len);
Packit 84c3e8
			sscanf(info.full_path + group_len,
Packit 84c3e8
			      "cgdcb-%i", &selector);
Packit 84c3e8
Packit 84c3e8
			if (selector == 1)
Packit 84c3e8
				sscanf(info.full_path + group_len,
Packit 84c3e8
				      "cgdcb-%i-%4x", &selector, &protocol);
Packit 84c3e8
			else
Packit 84c3e8
				sscanf(info.full_path + group_len,
Packit 84c3e8
				       "cgdcb-%i-%i", &selector, &protocol);
Packit 84c3e8
Packit 84c3e8
Packit 84c3e8
			LIST_FOREACH(np, &iface->apps, entry) {
Packit 84c3e8
				if (np->app.selector == selector &&
Packit 84c3e8
				    np->app.protocol == protocol)
Packit 84c3e8
					break;
Packit 84c3e8
			}
Packit 84c3e8
Packit 84c3e8
			if (!np)
Packit 84c3e8
				cgdcbx_write_ifpriomap(iface,
Packit 84c3e8
						       child_name, &entry);
Packit 84c3e8
		}
Packit 84c3e8
		ret = cgroup_walk_tree_next(0, &handle, &info, level);
Packit 84c3e8
	}
Packit 84c3e8
	cgroup_walk_tree_end(&handle);
Packit 84c3e8
	return;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_modify_cgroup(struct cgdcbx_iface *iface,
Packit 84c3e8
				 struct cgdcbx_entry *np)
Packit 84c3e8
{
Packit 84c3e8
	char file[19];
Packit 84c3e8
Packit 84c3e8
	/* selector == 1 and protocol == 0 is a special case which
Packit 84c3e8
	 * indicates the default priority should be set. All other
Packit 84c3e8
	 * cases use the selector-protocol control group syntax.
Packit 84c3e8
	 */
Packit 84c3e8
	if ((iface->mode == DCB_CAP_DCBX_VER_IEEE) &&
Packit 84c3e8
	    np->app.selector == 1 &&
Packit 84c3e8
	    np->app.protocol == 0) {
Packit 84c3e8
		snprintf(file, sizeof(file), "/");
Packit 84c3e8
		iface->dflt_priority = np->app.priority;
Packit 84c3e8
	} else if (np->app.selector == 1) {
Packit 84c3e8
		snprintf(file, sizeof(file), "cgdcb-%i-%04x",
Packit 84c3e8
			 np->app.selector,
Packit 84c3e8
			 np->app.protocol);
Packit 84c3e8
	} else {
Packit 84c3e8
		snprintf(file, sizeof(file), "cgdcb-%i-%i",
Packit 84c3e8
			 np->app.selector,
Packit 84c3e8
			 np->app.protocol);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	cgdcbx_write_ifpriomap(iface, file, np);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_update_iface_cg(struct cgdcbx_iface *iface)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_entry *entry;
Packit 84c3e8
Packit 84c3e8
	entry = LIST_FIRST(&iface->apps);
Packit 84c3e8
	while (entry) {
Packit 84c3e8
		struct cgdcbx_entry *np = entry;
Packit 84c3e8
Packit 84c3e8
		entry = LIST_NEXT(entry, entry);
Packit 84c3e8
		cgdcbx_modify_cgroup(iface, np);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_update_iface_cg_all(void)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *iface;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(iface, &iface_list, entry) {
Packit 84c3e8
		cgdcbx_update_iface_cg(iface);
Packit 84c3e8
	}
Packit 84c3e8
#ifdef HAVE_CGROUP_CHANGE_ALL_CGROUPS
Packit 84c3e8
	cgroup_change_all_cgroups();
Packit 84c3e8
#endif
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_populate_virtual_devs(void)
Packit 84c3e8
{
Packit 84c3e8
	static struct mnl_socket *nl;
Packit 84c3e8
	struct nlmsghdr *nlh;
Packit 84c3e8
	struct rtgenmsg *rt;
Packit 84c3e8
	char buf[MNL_SOCKET_BUFFER_SIZE];
Packit 84c3e8
	unsigned int portid;
Packit 84c3e8
	int ret, groups = 0;
Packit 84c3e8
Packit 84c3e8
	nl = mnl_socket_open(NETLINK_ROUTE);
Packit 84c3e8
	if (!nl) {
Packit 84c3e8
		perror("mnl_socket_open");
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (mnl_socket_bind(nl, groups, MNL_SOCKET_AUTOPID) < 0) {
Packit 84c3e8
		perror("mnl_socket_bind");
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
	portid = mnl_socket_get_portid(nl);
Packit 84c3e8
Packit 84c3e8
	memset(buf, 0, sizeof(buf));
Packit 84c3e8
	nlh = mnl_nlmsg_put_header(buf);
Packit 84c3e8
	nlh->nlmsg_type = RTM_GETLINK;
Packit 84c3e8
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
Packit 84c3e8
	nlh->nlmsg_seq = time(NULL);
Packit 84c3e8
Packit 84c3e8
	rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
Packit 84c3e8
	rt->rtgen_family = AF_PACKET;
Packit 84c3e8
Packit 84c3e8
	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
Packit 84c3e8
		perror("cgdcbx: init_tables, mnl_socket_send");
Packit 84c3e8
		return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit 84c3e8
	while (ret > 0) {
Packit 84c3e8
		ret = mnl_cb_run(buf, ret, 0, portid,
Packit 84c3e8
				 cgdcbx_link_cb, NULL);
Packit 84c3e8
		if (ret <= MNL_CB_STOP)
Packit 84c3e8
			break;
Packit 84c3e8
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	mnl_socket_close(nl);
Packit 84c3e8
	return;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_free_apps(struct cgdcbx_iface *iface)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_entry *app;
Packit 84c3e8
Packit 84c3e8
	app = LIST_FIRST(&iface->apps);
Packit 84c3e8
	while (app) {
Packit 84c3e8
		struct cgdcbx_entry *a = app;
Packit 84c3e8
Packit 84c3e8
		app = LIST_NEXT(app, entry);
Packit 84c3e8
		LIST_REMOVE(a, entry);
Packit 84c3e8
		free(a);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_free_virt(struct cgdcbx_iface *iface)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_virt *virt;
Packit 84c3e8
Packit 84c3e8
	virt = LIST_FIRST(&iface->virt);
Packit 84c3e8
	while (virt) {
Packit 84c3e8
		struct cgdcbx_virt *v = virt;
Packit 84c3e8
Packit 84c3e8
		virt = LIST_NEXT(virt, entry);
Packit 84c3e8
		LIST_REMOVE(v, entry);
Packit 84c3e8
		free(v->ifname);
Packit 84c3e8
		free(v);
Packit 84c3e8
	}
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_free_iface(struct cgdcbx_iface *iface,
Packit 84c3e8
			      struct cgdcbx_virt *virt)
Packit 84c3e8
{
Packit 84c3e8
	if (!virt) {
Packit 84c3e8
		LIST_REMOVE(iface, entry);
Packit 84c3e8
		cgdcbx_free_apps(iface);
Packit 84c3e8
		cgdcbx_free_virt(iface);
Packit 84c3e8
		free(iface->ifname);
Packit 84c3e8
		free(iface);
Packit 84c3e8
	} else {
Packit 84c3e8
		LIST_REMOVE(virt, entry);
Packit 84c3e8
		free(virt->ifname);
Packit 84c3e8
		free(virt);
Packit 84c3e8
	}
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_int_signal()
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *entry;
Packit 84c3e8
Packit 84c3e8
	entry = LIST_FIRST(&iface_list);
Packit 84c3e8
	while (entry) {
Packit 84c3e8
		struct cgdcbx_iface *np = entry;
Packit 84c3e8
		struct cgdcbx_entry *app;
Packit 84c3e8
Packit 84c3e8
		entry = LIST_NEXT(entry, entry);
Packit 84c3e8
Packit 84c3e8
		LIST_FOREACH(app, &np->apps, entry) {
Packit 84c3e8
			app->active = false;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		cgdcbx_update_iface_cg(np);
Packit 84c3e8
		cgdcbx_free_iface(np, NULL);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	exit(EXIT_SUCCESS);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_purge_apps(struct cgdcbx_iface *iface)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_entry *app;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(app, &iface->apps, entry)
Packit 84c3e8
		app->active = false;
Packit 84c3e8
Packit 84c3e8
	iface->dflt_priority = 0;
Packit 84c3e8
	cgdcbx_update_iface_cg(iface);
Packit 84c3e8
	cgdcbxd_update_default_iface_prio(iface);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_parse_app_table(struct cgdcbx_iface *iface,
Packit 84c3e8
				   struct nlattr *nested)
Packit 84c3e8
{
Packit 84c3e8
	struct nlattr *pos;
Packit 84c3e8
	struct cgdcbx_entry *np;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(np, &iface->apps, entry) {
Packit 84c3e8
		np->active = false;
Packit 84c3e8
		np->app.priority = 0;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	iface->dflt_priority = 0;
Packit 84c3e8
Packit 84c3e8
	mnl_attr_for_each_nested(pos, nested) {
Packit 84c3e8
		struct dcb_app *app;
Packit 84c3e8
		struct cgdcbx_entry *entry;
Packit 84c3e8
		int type = mnl_attr_get_type(pos);
Packit 84c3e8
Packit 84c3e8
		if (type != DCB_ATTR_IEEE_APP)
Packit 84c3e8
			continue;
Packit 84c3e8
Packit 84c3e8
		app = mnl_attr_get_payload(pos);
Packit 84c3e8
		entry = cgdcbx_lookup_app(iface, app);
Packit 84c3e8
		if (!entry)
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"cgdcbxd %s IEEE entry lookup failed\n",
Packit 84c3e8
				iface->ifname);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	cgdcbx_update_iface_cg(iface);
Packit 84c3e8
	cgdcbxd_update_default_iface_prio(iface);
Packit 84c3e8
#ifdef HAVE_CGROUP_CHANGE_ALL_CGROUPS
Packit 84c3e8
	cgroup_change_all_cgroups();
Packit 84c3e8
#endif
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int parse_attr_cee_nested_app(const struct nlattr *attr, void *data)
Packit 84c3e8
{
Packit 84c3e8
	const struct nlattr **tb = data;
Packit 84c3e8
	int type = mnl_attr_get_type(attr);
Packit 84c3e8
Packit 84c3e8
	if (mnl_attr_type_valid(attr, DCB_APP_ATTR_MAX) < 0)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	switch (type) {
Packit 84c3e8
	case DCB_APP_ATTR_IDTYPE:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate: DCB_APP_ATTR_IDTYPE");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	case DCB_APP_ATTR_ID:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate: DCB_APP_ATTR_ID");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	case DCB_APP_ATTR_PRIORITY:
Packit 84c3e8
		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
Packit 84c3e8
			perror("mnl_attr_validate: DCB_APP_ATTR_PRIORITY");
Packit 84c3e8
			return MNL_CB_ERROR;
Packit 84c3e8
		}
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	tb[type] = attr;
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
#define CGDCBX_CEE_APPSEL_ERROR	0xff
Packit 84c3e8
Packit 84c3e8
static __u8 cee2app_selector(__u8 selector)
Packit 84c3e8
{
Packit 84c3e8
	__u8 s = CGDCBX_CEE_APPSEL_ERROR;
Packit 84c3e8
Packit 84c3e8
	/* CEE Application TLV defines two selector types,
Packit 84c3e8
	 *   0: Application Protocol ID is L2 Ethertype
Packit 84c3e8
	 *   1: Application Protocol ID is Socket Number (TCP/UDP)
Packit 84c3e8
	 *
Packit 84c3e8
	 * When mapping this back to cgdcbx APP structure which
Packit 84c3e8
	 * is using the IEEE definitions, map 0 to the IEEE L2
Packit 84c3e8
	 * type (1) and TCP/UDP socket to TCP, UDP, SCTP, or DCCP
Packit 84c3e8
	 * socket type (4). Not a perfect match but good enough.
Packit 84c3e8
	 */
Packit 84c3e8
	switch (selector) {
Packit 84c3e8
	case 0:
Packit 84c3e8
		s = 1;
Packit 84c3e8
		break;
Packit 84c3e8
	case 1:
Packit 84c3e8
		s = 4;
Packit 84c3e8
		break;
Packit 84c3e8
	default:
Packit 84c3e8
		break;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return s;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static __u16 cee2app_protocol(UNUSED __u8 selector, __u16 protocol)
Packit 84c3e8
{
Packit 84c3e8
	return protocol;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static __u8 cee2app_priority(__u8 priority)
Packit 84c3e8
{
Packit 84c3e8
	return ffs(priority) - 1;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_parse_cee_app_table(struct cgdcbx_iface *iface,
Packit 84c3e8
				       struct nlattr *nested)
Packit 84c3e8
{
Packit 84c3e8
	struct nlattr *pos;
Packit 84c3e8
	struct cgdcbx_entry *np;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(np, &iface->apps, entry) {
Packit 84c3e8
		np->active = false;
Packit 84c3e8
		np->app.priority = 0;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	iface->dflt_priority = 0;
Packit 84c3e8
Packit 84c3e8
	mnl_attr_for_each_nested(pos, nested) {
Packit 84c3e8
		struct dcb_app app;
Packit 84c3e8
		struct cgdcbx_entry *entry;
Packit 84c3e8
		struct nlattr *tbx[DCB_APP_ATTR_MAX + 1] = {};
Packit 84c3e8
		int type = mnl_attr_get_type(pos);
Packit 84c3e8
		__u8 selector, priority;
Packit 84c3e8
		__u16 protocol;
Packit 84c3e8
Packit 84c3e8
		if (type != DCB_ATTR_APP)
Packit 84c3e8
			continue;
Packit 84c3e8
Packit 84c3e8
		mnl_attr_parse_nested(pos, parse_attr_cee_nested_app, tbx);
Packit 84c3e8
		if (tbx[DCB_APP_ATTR_IDTYPE])
Packit 84c3e8
			selector = mnl_attr_get_u8(tbx[DCB_APP_ATTR_IDTYPE]);
Packit 84c3e8
		else
Packit 84c3e8
			continue;
Packit 84c3e8
Packit 84c3e8
		if (tbx[DCB_APP_ATTR_ID])
Packit 84c3e8
			protocol = mnl_attr_get_u16(tbx[DCB_APP_ATTR_ID]);
Packit 84c3e8
		else
Packit 84c3e8
			continue;
Packit 84c3e8
Packit 84c3e8
		if (tbx[DCB_APP_ATTR_PRIORITY])
Packit 84c3e8
			priority = mnl_attr_get_u8(tbx[DCB_APP_ATTR_PRIORITY]);
Packit 84c3e8
		else
Packit 84c3e8
			continue;
Packit 84c3e8
Packit 84c3e8
		app.selector = cee2app_selector(selector);
Packit 84c3e8
		app.protocol = cee2app_protocol(selector, protocol);
Packit 84c3e8
		app.priority = cee2app_priority(priority);
Packit 84c3e8
Packit 84c3e8
		if (app.selector != CGDCBX_CEE_APPSEL_ERROR) {
Packit 84c3e8
			entry = cgdcbx_lookup_app(iface, &app);
Packit 84c3e8
			if (!entry)
Packit 84c3e8
				fprintf(stderr,
Packit 84c3e8
					"cgdcbxd %s CEE entry lookup failed\n",
Packit 84c3e8
					iface->ifname);
Packit 84c3e8
		}
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	cgdcbx_update_iface_cg(iface);
Packit 84c3e8
	cgdcbxd_update_default_iface_prio(iface);
Packit 84c3e8
#ifdef HAVE_CGROUP_CHANGE_ALL_CGROUPS
Packit 84c3e8
	cgroup_change_all_cgroups();
Packit 84c3e8
#endif
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static struct cgdcbx_iface *cgdcbx_add_iface(const char *ifname)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *entry = calloc(1, sizeof(*entry));
Packit 84c3e8
Packit 84c3e8
	if (!entry)
Packit 84c3e8
		return NULL;
Packit 84c3e8
Packit 84c3e8
	entry->ifname = strdup(ifname);
Packit 84c3e8
	entry->ifindex = if_nametoindex(ifname);
Packit 84c3e8
	entry->dflt_priority = 0;
Packit 84c3e8
Packit 84c3e8
	if (!entry->ifname)
Packit 84c3e8
		return NULL;
Packit 84c3e8
Packit 84c3e8
	LIST_INIT(&entry->apps);
Packit 84c3e8
	LIST_INIT(&entry->virt);
Packit 84c3e8
	LIST_INSERT_HEAD(&iface_list, entry, entry);
Packit 84c3e8
Packit 84c3e8
	return entry;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static struct cgdcbx_iface *cgdcbx_lookup_iface(const char *ifname)
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *np;
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(np, &iface_list, entry) {
Packit 84c3e8
		if (!strncmp(np->ifname, ifname, IFNAMSIZ))
Packit 84c3e8
			return np;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return cgdcbx_add_iface(ifname);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int cgdcbx_getdcbx_reply(const struct nlmsghdr *nlh, void *data)
Packit 84c3e8
{
Packit 84c3e8
	struct nlattr *tb[IFLA_MAX + 1] = {};
Packit 84c3e8
	struct dcbmsg *dcb;
Packit 84c3e8
	__u8 bitmask = 0;
Packit 84c3e8
	__u8 *mode = data;
Packit 84c3e8
Packit 84c3e8
	if (nlh->nlmsg_type != RTM_GETDCB)
Packit 84c3e8
		return MNL_CB_OK;
Packit 84c3e8
Packit 84c3e8
	dcb = mnl_nlmsg_get_payload(nlh);
Packit 84c3e8
Packit 84c3e8
	mnl_attr_parse(nlh, sizeof(*dcb), dcb_attr_cb, tb);
Packit 84c3e8
	if (tb[DCB_ATTR_DCBX]) {
Packit 84c3e8
		bitmask = mnl_attr_get_u8(tb[DCB_ATTR_DCBX]);
Packit 84c3e8
		*mode = bitmask &
Packit 84c3e8
			(DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_VER_IEEE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static int cgdcbx_dcb_cb(const struct nlmsghdr *nlh, UNUSED void *data)
Packit 84c3e8
{
Packit 84c3e8
	struct nlattr *tb[IFLA_MAX + 1] = {};
Packit 84c3e8
	struct dcbmsg *dcb;
Packit 84c3e8
	struct cgdcbx_iface *iface;
Packit 84c3e8
Packit 84c3e8
	dcb = mnl_nlmsg_get_payload(nlh);
Packit 84c3e8
Packit 84c3e8
	mnl_attr_parse(nlh, sizeof(*dcb), dcb_attr_cb, tb);
Packit 84c3e8
	if (tb[DCB_ATTR_IFNAME]) {
Packit 84c3e8
		const char *ifname = mnl_attr_get_str(tb[DCB_ATTR_IFNAME]);
Packit 84c3e8
Packit 84c3e8
		iface = cgdcbx_lookup_iface(ifname);
Packit 84c3e8
		if (!iface)
Packit 84c3e8
			return MNL_CB_OK;
Packit 84c3e8
	} else {
Packit 84c3e8
		return MNL_CB_STOP;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (tb[DCB_ATTR_IEEE]) {
Packit 84c3e8
		struct nlattr *tbx[DCB_ATTR_IEEE_MAX + 1] = {};
Packit 84c3e8
		struct nlattr *app_nest;
Packit 84c3e8
Packit 84c3e8
		if (iface->mode != DCB_CAP_DCBX_VER_IEEE) {
Packit 84c3e8
			cgdcbx_purge_apps(iface);
Packit 84c3e8
			iface->mode = DCB_CAP_DCBX_VER_IEEE;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		mnl_attr_parse_nested(tb[DCB_ATTR_IEEE], parse_attr_ieee, tbx);
Packit 84c3e8
		app_nest = tbx[DCB_ATTR_IEEE_APP_TABLE];
Packit 84c3e8
		if (app_nest)
Packit 84c3e8
			cgdcbx_parse_app_table(iface, app_nest);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (tb[DCB_ATTR_CEE]) {
Packit 84c3e8
		struct nlattr *tbx[DCB_ATTR_CEE_MAX + 1] = {};
Packit 84c3e8
		struct nlattr *app_nest;
Packit 84c3e8
Packit 84c3e8
		if (iface->mode != DCB_CAP_DCBX_VER_CEE) {
Packit 84c3e8
			cgdcbx_purge_apps(iface);
Packit 84c3e8
			iface->mode = DCB_CAP_DCBX_VER_CEE;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		mnl_attr_parse_nested(tb[DCB_ATTR_CEE], parse_attr_cee, tbx);
Packit 84c3e8
		app_nest = tbx[DCB_ATTR_CEE_APP_TABLE];
Packit 84c3e8
		if (app_nest)
Packit 84c3e8
			cgdcbx_parse_cee_app_table(iface, app_nest);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	return MNL_CB_OK;
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_app_print(struct cgdcbx_entry *entry)
Packit 84c3e8
{
Packit 84c3e8
	if (entry->app.selector == 1)
Packit 84c3e8
		fprintf(stdout, " (%i, %i, 0x%04x)",
Packit 84c3e8
			entry->app.priority,
Packit 84c3e8
			entry->app.selector,
Packit 84c3e8
			entry->app.protocol);
Packit 84c3e8
	else
Packit 84c3e8
		fprintf(stdout, " (%i, %i, %i)",
Packit 84c3e8
			entry->app.priority,
Packit 84c3e8
			entry->app.selector,
Packit 84c3e8
			entry->app.protocol);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_usr1_signal()
Packit 84c3e8
{
Packit 84c3e8
	struct cgdcbx_iface *np;
Packit 84c3e8
	struct cgdcbx_entry *entry;
Packit 84c3e8
	struct cgdcbx_virt *virt;
Packit 84c3e8
Packit 84c3e8
	fprintf(stdout, "cgdcbx --- ifname: (priority, selector, protocol)\n");
Packit 84c3e8
Packit 84c3e8
	LIST_FOREACH(np, &iface_list, entry) {
Packit 84c3e8
		fprintf(stdout, "%s:", np->ifname);
Packit 84c3e8
		LIST_FOREACH(entry, &np->apps, entry) {
Packit 84c3e8
			cgdcbx_app_print(entry);
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		if (!LIST_EMPTY(&np->virt)) {
Packit 84c3e8
			fprintf(stdout, "\n  virt: ");
Packit 84c3e8
			LIST_FOREACH(virt, &np->virt, entry) {
Packit 84c3e8
				fprintf(stdout, " %s", virt->ifname);
Packit 84c3e8
			}
Packit 84c3e8
		}
Packit 84c3e8
		fprintf(stdout, "\n");
Packit 84c3e8
	}
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbx_init_tables(struct mnl_socket *nl)
Packit 84c3e8
{
Packit 84c3e8
	struct if_nameindex *nameidx, *p;
Packit 84c3e8
	struct nlmsghdr *nlh;
Packit 84c3e8
	struct dcbmsg *dcb;
Packit 84c3e8
	char buf[MNL_SOCKET_BUFFER_SIZE];
Packit 84c3e8
	unsigned int seq, portid;
Packit 84c3e8
	int ret;
Packit 84c3e8
	__u8 mode = 0;
Packit 84c3e8
Packit 84c3e8
	nameidx = if_nameindex();
Packit 84c3e8
	if (nameidx == NULL) {
Packit 84c3e8
		fprintf(stderr, "cgdcbx: if_nameindex() error\n");
Packit 84c3e8
		return;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	portid = mnl_socket_get_portid(nl);
Packit 84c3e8
	p = nameidx;
Packit 84c3e8
Packit 84c3e8
	while (p->if_index != 0) {
Packit 84c3e8
		memset(buf, 0, sizeof(buf));
Packit 84c3e8
		nlh = mnl_nlmsg_put_header(buf);
Packit 84c3e8
		nlh->nlmsg_type = RTM_GETDCB;
Packit 84c3e8
		nlh->nlmsg_flags = NLM_F_REQUEST;
Packit 84c3e8
		nlh->nlmsg_seq = seq = time(NULL);
Packit 84c3e8
Packit 84c3e8
		dcb = mnl_nlmsg_put_extra_header(nlh, sizeof(struct dcbmsg));
Packit 84c3e8
		dcb->dcb_family = AF_UNSPEC;
Packit 84c3e8
		dcb->cmd = DCB_CMD_GDCBX;
Packit 84c3e8
		dcb->dcb_pad = 0;
Packit 84c3e8
Packit 84c3e8
		mnl_attr_put(nlh,
Packit 84c3e8
			     DCB_ATTR_IFNAME,
Packit 84c3e8
			     strlen(p->if_name) + 1,
Packit 84c3e8
			     p->if_name);
Packit 84c3e8
Packit 84c3e8
		if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
Packit 84c3e8
			perror("cgdcbx: init_tables, mnl_socket_send");
Packit 84c3e8
			goto index_failure;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit 84c3e8
		if (ret > 0)
Packit 84c3e8
			mnl_cb_run(buf, ret, 0, portid,
Packit 84c3e8
				   cgdcbx_getdcbx_reply, &mode);
Packit 84c3e8
Packit 84c3e8
		memset(buf, 0, sizeof(buf));
Packit 84c3e8
		nlh = mnl_nlmsg_put_header(buf);
Packit 84c3e8
		nlh->nlmsg_type = RTM_GETDCB;
Packit 84c3e8
		nlh->nlmsg_flags = NLM_F_REQUEST;
Packit 84c3e8
		nlh->nlmsg_seq = seq = time(NULL);
Packit 84c3e8
Packit 84c3e8
		dcb = mnl_nlmsg_put_extra_header(nlh, sizeof(struct dcbmsg));
Packit 84c3e8
		dcb->dcb_family = AF_UNSPEC;
Packit 84c3e8
		dcb->dcb_pad = 0;
Packit 84c3e8
		if (mode == DCB_CAP_DCBX_VER_CEE)
Packit 84c3e8
			dcb->cmd = DCB_CMD_CEE_GET;
Packit 84c3e8
		else
Packit 84c3e8
			dcb->cmd = DCB_CMD_IEEE_GET;
Packit 84c3e8
Packit 84c3e8
		mnl_attr_put(nlh,
Packit 84c3e8
			     DCB_ATTR_IFNAME,
Packit 84c3e8
			     strlen(p->if_name) + 1,
Packit 84c3e8
			     p->if_name);
Packit 84c3e8
Packit 84c3e8
		if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
Packit 84c3e8
			perror("cgdcbx: init_tables, mnl_socket_send");
Packit 84c3e8
			goto index_failure;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit 84c3e8
		if (ret > 0)
Packit 84c3e8
			mnl_cb_run(buf, ret, 0, portid, cgdcbx_dcb_cb, NULL);
Packit 84c3e8
index_failure:
Packit 84c3e8
		p++;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if_freenameindex(nameidx);
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
static void cgdcbxd_sock_init(struct mnl_socket **nl, int groups)
Packit 84c3e8
{
Packit 84c3e8
	*nl = mnl_socket_open(NETLINK_ROUTE);
Packit 84c3e8
	if (*nl == NULL) {
Packit 84c3e8
		perror("mnl_socket_open");
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (mnl_socket_bind(*nl, groups, MNL_SOCKET_AUTOPID) < 0) {
Packit 84c3e8
		perror("mnl_socket_bind");
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
}
Packit 84c3e8
Packit 84c3e8
int main(int argc, char *argv[])
Packit 84c3e8
{
Packit 84c3e8
	int ret, err;
Packit 84c3e8
	int c;
Packit 84c3e8
	char buf[MNL_SOCKET_BUFFER_SIZE];
Packit 84c3e8
	unsigned int groups;
Packit 84c3e8
	unsigned char daemonize = 1;
Packit 84c3e8
	int nlfd_dcb, nlfd_rt, max_fd, pidfd;
Packit 84c3e8
	int rcv_size = 8192;
Packit 84c3e8
	fd_set fds, readfds;
Packit 84c3e8
	sigset_t sigset;
Packit 84c3e8
	struct cgroup_mount_point info;
Packit 84c3e8
	void *handle;
Packit 84c3e8
	static struct mnl_socket *nl_dcb, *nl_rt;
Packit 84c3e8
	struct sigaction sa_usr1, sa_int;
Packit 84c3e8
	struct option longopts[] = {
Packit 84c3e8
			{ 0, 0, 0, 0}
Packit 84c3e8
	};
Packit 84c3e8
Packit 84c3e8
	while ((c = getopt_long(argc, argv, "vhns", longopts, NULL)) > 0) {
Packit 84c3e8
		switch (c) {
Packit 84c3e8
		case 'h':
Packit 84c3e8
			usage(argv[0]);
Packit 84c3e8
			exit(0);
Packit 84c3e8
		case 'n':
Packit 84c3e8
			daemonize = 0;
Packit 84c3e8
			break;
Packit 84c3e8
		case 'v':
Packit 84c3e8
			printf("%s\n", PACKAGE_STRING);
Packit 84c3e8
			exit(0);
Packit 84c3e8
		default:
Packit 84c3e8
			exit(1);
Packit 84c3e8
		}
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	groups = 1 << (RTNLGRP_DCB - 1);
Packit 84c3e8
	cgdcbxd_sock_init(&nl_dcb, groups);
Packit 84c3e8
Packit 84c3e8
	groups = 1 << (RTNLGRP_LINK - 1);
Packit 84c3e8
	cgdcbxd_sock_init(&nl_rt, groups);
Packit 84c3e8
Packit 84c3e8
	ret = cgroup_init();
Packit 84c3e8
	if (ret) {
Packit 84c3e8
		fprintf(stderr, "%s: libcgroup initialization failed: %s\n",
Packit 84c3e8
			argv[0], cgroup_strerror(ret));
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	err = cgroup_get_controller_begin(&handle, &info;;
Packit 84c3e8
	while (!err) {
Packit 84c3e8
		if (strcmp(NET_PRIO, info.name) == 0)
Packit 84c3e8
			break;
Packit 84c3e8
		err = cgroup_get_controller_next(&handle, &info;;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (err == ECGEOF) {
Packit 84c3e8
		fprintf(stderr, "%s: net_prio cgroup not mounted: %s\n",
Packit 84c3e8
			argv[0], cgroup_strerror(err));
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	nlfd_dcb = mnl_socket_get_fd(nl_dcb);
Packit 84c3e8
	nlfd_rt = mnl_socket_get_fd(nl_rt);
Packit 84c3e8
	FD_ZERO(&readfds);
Packit 84c3e8
	FD_SET(nlfd_dcb, &readfds);
Packit 84c3e8
	FD_SET(nlfd_rt, &readfds);
Packit 84c3e8
Packit 84c3e8
	setsockopt(nlfd_dcb, SOL_SOCKET, SO_RCVBUF, &rcv_size, sizeof(int));
Packit 84c3e8
	setsockopt(nlfd_rt, SOL_SOCKET, SO_RCVBUF, &rcv_size, sizeof(int));
Packit 84c3e8
Packit 84c3e8
	memset(&sa_usr1, 0, sizeof(sa_usr1));
Packit 84c3e8
	sa_usr1.sa_handler = &cgdcbx_usr1_signal;
Packit 84c3e8
	sigemptyset(&sa_usr1.sa_mask);
Packit 84c3e8
	err = sigaction(SIGUSR1, &sa_usr1, NULL);
Packit 84c3e8
	if (err) {
Packit 84c3e8
		fprintf(stderr, "Failed to set up signal hander for SIGUSR1."
Packit 84c3e8
				" Error: %s:",
Packit 84c3e8
			strerror(errno));
Packit 84c3e8
		goto err;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	memset(&sa_int, 0, sizeof(sa_int));
Packit 84c3e8
	sa_int.sa_handler = &cgdcbx_int_signal;
Packit 84c3e8
	sigemptyset(&sa_int.sa_mask);
Packit 84c3e8
	err = sigaction(SIGINT, &sa_int, NULL);
Packit 84c3e8
	err |= sigaction(SIGTERM, &sa_int, NULL);
Packit 84c3e8
	if (err) {
Packit 84c3e8
		fprintf(stderr, "Failed to set up signal hander for SIGINT."
Packit 84c3e8
				" Error: %s:",
Packit 84c3e8
			strerror(errno));
Packit 84c3e8
		goto err;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	pidfd = open(PID_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
Packit 84c3e8
	if (pidfd < 0) {
Packit 84c3e8
		fprintf(stderr, "cgdcbx: Error opening lock file");
Packit 84c3e8
		goto err;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	errno = 0;
Packit 84c3e8
	if (flock(pidfd, LOCK_EX | LOCK_NB) < 0) {
Packit 84c3e8
		if (errno == EWOULDBLOCK) {
Packit 84c3e8
			char buf[256] = { 0 };
Packit 84c3e8
Packit 84c3e8
			ret = read(pidfd, buf, sizeof(buf));
Packit 84c3e8
			fprintf(stderr, "cgdcbx: already running pid = %s\n",
Packit 84c3e8
				ret > 0 ? buf : "<unknown>");
Packit 84c3e8
		} else {
Packit 84c3e8
			perror("cgdcbx: flock error:");
Packit 84c3e8
		}
Packit 84c3e8
		goto pidfd_err;
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	if (daemonize) {
Packit 84c3e8
		char buf[256] = { 0 };
Packit 84c3e8
Packit 84c3e8
		errno = 0;
Packit 84c3e8
		err = daemon(1, 0);
Packit 84c3e8
		if (err) {
Packit 84c3e8
			fprintf(stderr, "Failed to daemonize, Error: %s",
Packit 84c3e8
				strerror(errno));
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		snprintf(buf, sizeof(buf), "%u\n", getpid());
Packit 84c3e8
		errno = 0;
Packit 84c3e8
		err = write(pidfd, buf, sizeof(buf));
Packit 84c3e8
		if (err < 0) {
Packit 84c3e8
			fprintf(stderr, "Failed to write pid, Error: %s",
Packit 84c3e8
				strerror(errno));
Packit 84c3e8
			goto err;
Packit 84c3e8
		}
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	/* SIGUSR1 can not be handled while manipulating data structures
Packit 84c3e8
	 * while processing netlink messages
Packit 84c3e8
	 */
Packit 84c3e8
	sigemptyset(&sigset);
Packit 84c3e8
	sigaddset(&sigset, SIGUSR1);
Packit 84c3e8
Packit 84c3e8
	sigprocmask(SIG_BLOCK, &sigset, NULL);
Packit 84c3e8
	/* Find DCB enabled interfaces */
Packit 84c3e8
	cgdcbx_init_tables(nl_dcb);
Packit 84c3e8
	/* Find any stacked interfaces */
Packit 84c3e8
	cgdcbx_populate_virtual_devs();
Packit 84c3e8
	/* Set priority on stacked devices */
Packit 84c3e8
	cgdcbx_update_iface_cg_all();
Packit 84c3e8
	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
Packit 84c3e8
Packit 84c3e8
	max_fd = (nlfd_rt > nlfd_dcb) ? nlfd_rt : nlfd_dcb;
Packit 84c3e8
Packit 84c3e8
	for (;;) {
Packit 84c3e8
		memcpy(&fds, &readfds, sizeof(fd_set));
Packit 84c3e8
		errno = 0;
Packit 84c3e8
		err = select(max_fd + 1, &fds, NULL, NULL, NULL);
Packit 84c3e8
		if (err < 0 && errno != EINTR) {
Packit 84c3e8
			fprintf(stderr,
Packit 84c3e8
				"selecting error: %s\n",
Packit 84c3e8
				strerror(errno));
Packit 84c3e8
			goto err;
Packit 84c3e8
		} else if (errno != EINTR && FD_ISSET(nlfd_dcb, &fds)) {
Packit 84c3e8
			sigprocmask(SIG_BLOCK, &sigset, NULL);
Packit 84c3e8
			ret = mnl_socket_recvfrom(nl_dcb, buf, sizeof(buf));
Packit 84c3e8
			ret = mnl_cb_run(buf, ret, 0, 0, cgdcbx_dcb_cb, NULL);
Packit 84c3e8
			sigprocmask(SIG_UNBLOCK, &sigset, NULL);
Packit 84c3e8
		} else if (errno != EINTR && FD_ISSET(nlfd_rt, &fds)) {
Packit 84c3e8
			struct cgdcbx_link_data data = {.iface = NULL,
Packit 84c3e8
							.virt = NULL,
Packit 84c3e8
							.nlmsg_type = 0};
Packit 84c3e8
Packit 84c3e8
			ret = mnl_socket_recvfrom(nl_rt, buf, sizeof(buf));
Packit 84c3e8
			ret = mnl_cb_run(buf, ret, 0, 0,
Packit 84c3e8
					 cgdcbx_link_cb, &data);
Packit 84c3e8
Packit 84c3e8
			if ((data.ifi_flags & IFF_RUNNING) &&
Packit 84c3e8
			    (data.nlmsg_type != RTM_DELLINK) &&
Packit 84c3e8
			    data.iface) {
Packit 84c3e8
				cgdcbx_update_iface_cg(data.iface);
Packit 84c3e8
#ifdef HAVE_CGROUP_CHANGE_ALL_CGROUPS
Packit 84c3e8
				cgroup_change_all_cgroups();
Packit 84c3e8
#endif
Packit 84c3e8
			} else if ((data.nlmsg_type == RTM_DELLINK) && data.iface) {
Packit 84c3e8
				cgdcbx_free_iface(data.iface, data.virt);
Packit 84c3e8
			}
Packit 84c3e8
		}
Packit 84c3e8
Packit 84c3e8
		if (ret < MNL_CB_STOP)
Packit 84c3e8
			fprintf(stderr, "mnl_cb_run error: %s\n",
Packit 84c3e8
				strerror(errno));
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
pidfd_err:
Packit 84c3e8
	close(pidfd);
Packit 84c3e8
err:
Packit 84c3e8
	if (ret == -1) {
Packit 84c3e8
		perror("error");
Packit 84c3e8
		exit(EXIT_FAILURE);
Packit 84c3e8
	}
Packit 84c3e8
Packit 84c3e8
	mnl_socket_close(nl_dcb);
Packit 84c3e8
	mnl_socket_close(nl_rt);
Packit 84c3e8
	return 0;
Packit 84c3e8
}