return ether_aton(blobmsg_get_string(cur));
}
+int config_get_default_gro(const char *ifname)
+{
+ struct blob_attr *cur;
+
+ if (!board_netdevs)
+ return -1;
+
+ cur = config_find_blobmsg_attr(board_netdevs, ifname, BLOBMSG_TYPE_TABLE);
+ if (!cur)
+ return -1;
+
+ cur = config_find_blobmsg_attr(cur, "gro", BLOBMSG_TYPE_BOOL);
+ if (!cur)
+ return -1;
+
+ return blobmsg_get_bool(cur);
+}
+
static void
config_init_board(void)
{
int config_init_all(void);
struct ether_addr *config_get_default_macaddr(const char *ifname);
+int config_get_default_gro(const char *ifname);
#endif
[DEV_ATTR_RXPAUSE] = { .name = "rxpause", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_TXPAUSE] = { .name = "txpause", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_AUTONEG] = { .name = "autoneg", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_GRO] = { .name = "gro", .type = BLOBMSG_TYPE_BOOL },
};
const struct uci_blob_param_list device_attr_list = {
system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
system_if_up(dev);
+
+ system_if_apply_settings_after_up(dev, &dev->settings);
} else {
system_if_down(dev);
system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
n->rxpause = s->flags & DEV_OPT_RXPAUSE ? s->rxpause : os->rxpause;
n->txpause = s->flags & DEV_OPT_TXPAUSE ? s->txpause : os->txpause;
n->autoneg = s->flags & DEV_OPT_AUTONEG ? s->autoneg : os->autoneg;
+ n->gro = s->flags & DEV_OPT_GRO ? s->gro : os->gro;
n->flags = s->flags | os->flags | os->valid_flags;
}
s->flags |= DEV_OPT_AUTONEG;
}
+ if ((cur = tb[DEV_ATTR_GRO])) {
+ s->gro = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_GRO;
+ }
+
cur = tb[DEV_ATTR_AUTH_VLAN];
free(dev->config_auth_vlans);
dev->config_auth_vlans = cur ? blob_memdup(cur) : NULL;
{
struct device_settings *s = &dev->settings;
struct ether_addr *ea;
+ int ret;
if (!(s->flags & DEV_OPT_MACADDR)) {
ea = config_get_default_macaddr(dev->ifname);
s->flags |= DEV_OPT_DEFAULT_MACADDR;
}
}
+
+ if (!(s->flags & DEV_OPT_GRO)) {
+ ret = config_get_default_gro(dev->ifname);
+ if (ret >= 0) {
+ s->gro = ret;
+ s->flags |= DEV_OPT_GRO;
+ }
+ }
}
int device_claim(struct device_user *dep)
blobmsg_add_u8(b, "arp_accept", st.arp_accept);
if (st.flags & DEV_OPT_AUTH)
blobmsg_add_u8(b, "auth", st.auth);
+ if (st.flags & DEV_OPT_GRO)
+ blobmsg_add_u8(b, "gro", st.gro);
}
s = blobmsg_open_table(b, "statistics");
DEV_ATTR_RXPAUSE,
DEV_ATTR_TXPAUSE,
DEV_ATTR_AUTONEG,
+ DEV_ATTR_GRO,
__DEV_ATTR_MAX,
};
DEV_OPT_RXPAUSE = (1ULL << 34),
DEV_OPT_TXPAUSE = (1ULL << 35),
DEV_OPT_AUTONEG = (1ULL << 36),
+ DEV_OPT_GRO = (1ULL << 37),
};
/* events broadcasted to all users of a device */
bool rxpause;
bool txpause;
bool autoneg;
+ bool gro;
};
struct device_vlan_range {
return !!(mask[nr / 32] & (1U << (nr % 32)));
}
+static int
+system_get_ethtool_gro(struct device *dev)
+{
+ struct ethtool_value ecmd;
+ struct ifreq ifr = {
+ .ifr_data = (caddr_t)&ecmd,
+ };
+
+ memset(&ecmd, 0, sizeof(ecmd));
+ ecmd.cmd = ETHTOOL_GGRO;
+ strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr))
+ return -1;
+
+ return ecmd.data;
+}
+
+static void
+system_set_ethtool_gro(struct device *dev, struct device_settings *s)
+{
+ struct ethtool_value ecmd;
+ struct ifreq ifr = {
+ .ifr_data = (caddr_t)&ecmd,
+ };
+
+ memset(&ecmd, 0, sizeof(ecmd));
+ ecmd.cmd = ETHTOOL_SGRO;
+ ecmd.data = s->gro;
+ strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
+
+ ioctl(sock_ioctl, SIOCETHTOOL, &ifr);
+}
+
static void
system_set_ethtool_pause(struct device *dev, struct device_settings *s)
{
ioctl(sock_ioctl, SIOCETHTOOL, &ifr);
}
+static void
+system_set_ethtool_settings_after_up(struct device *dev, struct device_settings *s)
+{
+ if (s->flags & DEV_OPT_GRO)
+ system_set_ethtool_gro(dev, s);
+}
+
void
system_if_get_settings(struct device *dev, struct device_settings *s)
{
struct ifreq ifr;
char buf[10];
+ int ret;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
s->arp_accept = strtoul(buf, NULL, 0);
s->flags |= DEV_OPT_ARP_ACCEPT;
}
+
+ ret = system_get_ethtool_gro(dev);
+ if (ret >= 0) {
+ s->gro = ret;
+ s->flags |= DEV_OPT_GRO;
+ }
}
void
system_set_ethtool_settings(dev, s);
}
+void system_if_apply_settings_after_up(struct device *dev, struct device_settings *s)
+{
+ system_set_ethtool_settings_after_up(dev, s);
+}
+
int system_if_up(struct device *dev)
{
return system_if_flags(dev->ifname, IFF_UP, 0);
bool system_if_force_external(const char *ifname);
void system_if_apply_settings(struct device *dev, struct device_settings *s,
uint64_t apply_mask);
+void system_if_apply_settings_after_up(struct device *dev, struct device_settings *s);
int system_add_address(struct device *dev, struct device_addr *addr);
int system_del_address(struct device *dev, struct device_addr *addr);