|
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 |
}
|