Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions device.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
[DEV_ATTR_MASTER] = { .name = "conduit", .type = BLOBMSG_TYPE_STRING },
[DEV_ATTR_EEE] = { .name = "eee", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_TAGS] = { .name = "tags", .type = BLOBMSG_TYPE_ARRAY },
[DEV_ATTR_RXHASH] = { .name = "rxhash", .type = BLOBMSG_TYPE_BOOL },
};

const struct uci_blob_param_list device_attr_list = {
Expand Down Expand Up @@ -310,6 +311,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
n->gro = s->flags & DEV_OPT_GRO ? s->gro : os->gro;
n->eee = s->flags & DEV_OPT_EEE ? s->eee : os->eee;
n->master_ifindex = s->flags & DEV_OPT_MASTER ? s->master_ifindex : os->master_ifindex;
n->rxhash = s->flags & DEV_OPT_RXHASH ? s->rxhash : os->rxhash;
n->flags = s->flags | os->flags | os->valid_flags;
}

Expand Down Expand Up @@ -579,6 +581,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
s->flags |= DEV_OPT_EEE;
}

if ((cur = tb[DEV_ATTR_RXHASH])) {
s->rxhash = blobmsg_get_bool(cur);
s->flags |= DEV_OPT_RXHASH;
}

/* Remember the settings present in UCI */
s->valid_flags = s->flags;

Expand Down Expand Up @@ -1437,6 +1444,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
blobmsg_add_u8(b, "gro", st.gro);
if (st.flags & DEV_OPT_EEE)
blobmsg_add_u8(b, "eee", st.eee);
if (st.flags & DEV_OPT_RXHASH)
blobmsg_add_u8(b, "rxhash", st.rxhash);
}

s = blobmsg_open_table(b, "statistics");
Expand Down
3 changes: 3 additions & 0 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum {
DEV_ATTR_MASTER,
DEV_ATTR_EEE,
DEV_ATTR_TAGS,
DEV_ATTR_RXHASH,
__DEV_ATTR_MAX,
};

Expand Down Expand Up @@ -145,6 +146,7 @@ enum {
DEV_OPT_GRO = (1ULL << 37),
DEV_OPT_MASTER = (1ULL << 38),
DEV_OPT_EEE = (1ULL << 39),
DEV_OPT_RXHASH = (1ULL << 40),
};

/* events broadcasted to all users of a device */
Expand Down Expand Up @@ -230,6 +232,7 @@ struct device_settings {
bool gro;
int master_ifindex;
bool eee;
bool rxhash;
};

struct device_vlan_range {
Expand Down
74 changes: 68 additions & 6 deletions system-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ static int cb_rtnl_event(struct nl_msg *msg, void *arg);
static void handle_hotplug_event(struct uloop_fd *u, unsigned int events);
static int system_add_proto_tunnel(const char *name, const uint8_t proto,
const unsigned int link, struct blob_attr **tb);
static int ethtool_get_feature_value(const char *ifname, const char *keyname);
static int ethtool_set_feature_value(const char *ifname, const char *keyname,
bool activate);

static char dev_buf[256];
static const char *proc_path = "/proc";
Expand Down Expand Up @@ -2128,6 +2131,18 @@ system_set_ethtool_eee_settings(struct device *dev, struct device_settings *s)
netifd_log_message(L_WARNING, "cannot set eee %d for device %s", s->eee, dev->ifname);
}

static int
system_get_ethtool_rxhash(struct device *dev)
{
return ethtool_get_feature_value(dev->ifname, "rx-hashing");
}

static void
system_set_ethtool_rxhash(struct device *dev, struct device_settings *s)
{
ethtool_set_feature_value(dev->ifname, "rx-hashing", s->rxhash);
}

static void
system_set_ethtool_settings(struct device *dev, struct device_settings *s)
{
Expand All @@ -2146,6 +2161,8 @@ system_set_ethtool_settings(struct device *dev, struct device_settings *s)

if (s->flags & DEV_OPT_EEE)
system_set_ethtool_eee_settings(dev, s);
if (s->flags & DEV_OPT_RXHASH)
system_set_ethtool_rxhash(dev, s);

memset(&ecmd, 0, sizeof(ecmd));
ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
Expand Down Expand Up @@ -2346,6 +2363,12 @@ system_if_get_settings(struct device *dev, struct device_settings *s)
s->flags |= DEV_OPT_GRO;
}

ret = system_get_ethtool_rxhash(dev);
if (ret >= 0) {
s->rxhash = ret;
s->flags |= DEV_OPT_RXHASH;
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
ret = system_if_get_master_ifindex(dev);
if (ret >= 0) {
Expand Down Expand Up @@ -2948,8 +2971,8 @@ ethtool_feature_index(const char *ifname, const char *keyname)
return i;
}

static bool
ethtool_feature_value(const char *ifname, const char *keyname)
static int
ethtool_get_feature_value(const char *ifname, const char *keyname)
{
struct ethtool_get_features_block *feature_block;
struct ethtool_gfeatures *feature_values;
Expand All @@ -2960,14 +2983,14 @@ ethtool_feature_value(const char *ifname, const char *keyname)
feature_idx = ethtool_feature_index(ifname, keyname);

if (feature_idx < 0)
return false;
return -1;

feature_values = calloc(1,
sizeof(*feature_values) +
sizeof(feature_values->features[0]) * DIV_ROUND_UP(feature_idx, 32));

if (!feature_values)
return false;
return -1;

feature_values->cmd = ETHTOOL_GFEATURES;
feature_values->size = DIV_ROUND_UP(feature_idx, 32);
Expand All @@ -2978,7 +3001,7 @@ ethtool_feature_value(const char *ifname, const char *keyname)
if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0) {
free(feature_values);

return false;
return -1;
}

feature_block = &feature_values->features[feature_idx / 32];
Expand All @@ -2989,6 +3012,45 @@ ethtool_feature_value(const char *ifname, const char *keyname)
return active;
}

static int
ethtool_set_feature_value(const char *ifname, const char *keyname, bool activate)
{
struct ethtool_set_features_block *feature_block;
struct ethtool_sfeatures *feature_values;
struct ifreq ifr = { 0 };
int32_t feature_idx;
int ret;

feature_idx = ethtool_feature_index(ifname, keyname);

if (feature_idx < 0)
return -1;

feature_values = calloc(1,
sizeof(*feature_values) +
sizeof(feature_values->features[0]) * DIV_ROUND_UP(feature_idx, 32));

if (!feature_values)
return -1;

feature_values->cmd = ETHTOOL_SFEATURES;
feature_values->size = DIV_ROUND_UP(feature_idx, 32);

strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
ifr.ifr_data = (void *)feature_values;

feature_block = &feature_values->features[feature_idx / 32];
feature_block->valid |= (1U << feature_idx % 32);

if (activate)
feature_block->requested |= (1U << feature_idx % 32);

ret = ioctl(sock_ioctl, SIOCETHTOOL, &ifr);
free(feature_values);

return ret;
}

static void
system_add_link_mode_name(struct blob_buf *b, int i, bool half)
{
Expand Down Expand Up @@ -3197,7 +3259,7 @@ system_if_dump_info(struct device *dev, struct blob_buf *b)
blobmsg_close_table(b, c);

blobmsg_add_u8(b, "hw-tc-offload",
ethtool_feature_value(dev->ifname, "hw-tc-offload"));
ethtool_get_feature_value(dev->ifname, "hw-tc-offload") == 1);

system_add_devtype(b, dev->ifname);

Expand Down