#include "dp-packet.h"
#include "dpif-netlink.h"
#include "dpif-netdev.h"
-#include "dynamic-string.h"
+#include "openvswitch/dynamic-string.h"
#include "fatal-signal.h"
#include "hash.h"
#include "hmap.h"
#include "netlink-notifier.h"
#include "netlink-socket.h"
#include "netlink.h"
-#include "ofpbuf.h"
+#include "openvswitch/ofpbuf.h"
#include "openflow/openflow.h"
#include "ovs-atomic.h"
#include "packets.h"
uint16_t tp_vlan_tpid;
};
+/* Linux 2.6.27 introduced ethtool_cmd_speed
+ *
+ * To avoid revisiting problems reported with using configure to detect
+ * compatibility (see report at
+ * http://openvswitch.org/pipermail/dev/2014-October/047978.html)
+ * unconditionally replace ethtool_cmd_speed. */
+#define ethtool_cmd_speed rpl_ethtool_cmd_speed
+static inline uint32_t rpl_ethtool_cmd_speed(const struct ethtool_cmd *ep)
+{
+ return ep->speed | (ep->speed_hi << 16);
+}
+
+/* Linux 2.6.30 introduced supported and advertised flags for
+ * 1G base KX, and 10G base KX4, KR and R. */
+#ifndef SUPPORTED_1000baseKX_Full
+#define SUPPORTED_1000baseKX_Full (1 << 17)
+#define SUPPORTED_10000baseKX4_Full (1 << 18)
+#define SUPPORTED_10000baseKR_Full (1 << 19)
+#define SUPPORTED_10000baseR_FEC (1 << 20)
+#define ADVERTISED_1000baseKX_Full (1 << 17)
+#define ADVERTISED_10000baseKX4_Full (1 << 18)
+#define ADVERTISED_10000baseKR_Full (1 << 19)
+#define ADVERTISED_10000baseR_FEC (1 << 20)
+#endif
+
+/* Linux 3.5 introduced supported and advertised flags for
+ * 40G base KR4, CR4, SR4 and LR4. */
+#ifndef SUPPORTED_40000baseKR4_Full
+#define SUPPORTED_40000baseKR4_Full (1 << 23)
+#define SUPPORTED_40000baseCR4_Full (1 << 24)
+#define SUPPORTED_40000baseSR4_Full (1 << 25)
+#define SUPPORTED_40000baseLR4_Full (1 << 26)
+#define ADVERTISED_40000baseKR4_Full (1 << 23)
+#define ADVERTISED_40000baseCR4_Full (1 << 24)
+#define ADVERTISED_40000baseSR4_Full (1 << 25)
+#define ADVERTISED_40000baseLR4_Full (1 << 26)
+#endif
+
/* Linux 2.6.35 introduced IFLA_STATS64 and rtnl_link_stats64.
*
* Tests for rtnl_link_stats64 don't seem to consistently work, e.g. on
enum {
VALID_IFINDEX = 1 << 0,
VALID_ETHERADDR = 1 << 1,
- VALID_IN4 = 1 << 2,
- VALID_IN6 = 1 << 3,
- VALID_MTU = 1 << 4,
- VALID_POLICING = 1 << 5,
- VALID_VPORT_STAT_ERROR = 1 << 6,
- VALID_DRVINFO = 1 << 7,
- VALID_FEATURES = 1 << 8,
+ VALID_IN = 1 << 2,
+ VALID_MTU = 1 << 3,
+ VALID_POLICING = 1 << 4,
+ VALID_VPORT_STAT_ERROR = 1 << 5,
+ VALID_DRVINFO = 1 << 6,
+ VALID_FEATURES = 1 << 7,
};
\f
/* Traffic control. */
static const struct tc_ops tc_ops_fqcodel;
static const struct tc_ops tc_ops_sfq;
static const struct tc_ops tc_ops_default;
+static const struct tc_ops tc_ops_noop;
static const struct tc_ops tc_ops_other;
static const struct tc_ops *const tcs[] = {
&tc_ops_codel, /* Controlled delay */
&tc_ops_fqcodel, /* Fair queue controlled delay */
&tc_ops_sfq, /* Stochastic fair queueing */
+ &tc_ops_noop, /* Non operating qos type. */
&tc_ops_default, /* Default qdisc (see tc-pfifo_fast(8)). */
&tc_ops_other, /* Some other qdisc. */
NULL
/* The following are figured out "on demand" only. They are only valid
* when the corresponding VALID_* bit in 'cache_valid' is set. */
int ifindex;
- uint8_t etheraddr[ETH_ADDR_LEN];
- struct in_addr address, netmask;
- struct in6_addr in6;
+ struct eth_addr etheraddr;
int mtu;
unsigned int ifi_flags;
long long int carrier_resets;
static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
int cmd, const char *cmd_name);
-static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *,
- int cmd, const char *cmd_name);
static int get_flags(const struct netdev *, unsigned int *flags);
static int set_flags(const char *, unsigned int flags);
static int update_flags(struct netdev_linux *netdev, enum netdev_flags off,
static int do_set_addr(struct netdev *netdev,
int ioctl_nr, const char *ioctl_name,
struct in_addr addr);
-static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]);
-static int set_etheraddr(const char *netdev_name, const uint8_t[ETH_ADDR_LEN]);
+static int get_etheraddr(const char *netdev_name, struct eth_addr *ea);
+static int set_etheraddr(const char *netdev_name, const struct eth_addr);
static int get_stats_via_netlink(const struct netdev *, struct netdev_stats *);
static int af_packet_sock(void);
static bool netdev_linux_miimon_enabled(void);
unsigned int ifi_flags, unsigned int mask)
OVS_REQUIRES(netdev->mutex);
-/* Returns a NETLINK_ROUTE socket listening for RTNLGRP_LINK changes, or NULL
+/* Returns a NETLINK_ROUTE socket listening for RTNLGRP_LINK,
+ * RTNLGRP_IPV4_IFADDR and RTNLGRP_IPV6_IFADDR changes, or NULL
* if no such socket could be created. */
static struct nl_sock *
netdev_linux_notify_sock(void)
{
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
static struct nl_sock *sock;
+ unsigned int mcgroups[] = {RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR,
+ RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_IFINFO};
if (ovsthread_once_start(&once)) {
int error;
error = nl_sock_create(NETLINK_ROUTE, &sock);
if (!error) {
- error = nl_sock_join_mcgroup(sock, RTNLGRP_LINK);
- if (error) {
- nl_sock_destroy(sock);
- sock = NULL;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(mcgroups); i++) {
+ error = nl_sock_join_mcgroup(sock, mcgroups[i]);
+ if (error) {
+ nl_sock_destroy(sock);
+ sock = NULL;
+ break;
+ }
}
}
ovsthread_once_done(&once);
struct rtnetlink_change change;
if (rtnetlink_parse(&buf, &change)) {
- struct netdev *netdev_ = netdev_from_name(change.ifname);
+ struct netdev *netdev_ = NULL;
+ char dev_name[IFNAMSIZ];
+
+ if (!change.ifname) {
+ change.ifname = if_indextoname(change.if_index, dev_name);
+ }
+
+ if (change.ifname) {
+ netdev_ = netdev_from_name(change.ifname);
+ }
if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
dev->ifi_flags = ifi_flags;
dev->cache_valid &= mask;
+ if (!(mask & VALID_IN)) {
+ netdev_get_addrs_list_flush();
+ }
}
static void
const struct rtnetlink_change *change)
OVS_REQUIRES(dev->mutex)
{
- if (change->nlmsg_type == RTM_NEWLINK) {
- /* Keep drv-info */
- netdev_linux_changed(dev, change->ifi_flags, VALID_DRVINFO);
+ if (rtnetlink_type_is_rtnlgrp_link(change->nlmsg_type)){
+ if (change->nlmsg_type == RTM_NEWLINK) {
+ /* Keep drv-info, and ip addresses. */
+ netdev_linux_changed(dev, change->ifi_flags,
+ VALID_DRVINFO | VALID_IN);
+
+ /* Update netdev from rtnl-change msg. */
+ if (change->mtu) {
+ dev->mtu = change->mtu;
+ dev->cache_valid |= VALID_MTU;
+ dev->netdev_mtu_error = 0;
+ }
- /* Update netdev from rtnl-change msg. */
- if (change->mtu) {
- dev->mtu = change->mtu;
- dev->cache_valid |= VALID_MTU;
- dev->netdev_mtu_error = 0;
- }
+ if (!eth_addr_is_zero(change->mac)) {
+ dev->etheraddr = change->mac;
+ dev->cache_valid |= VALID_ETHERADDR;
+ dev->ether_addr_error = 0;
+ }
- if (!eth_addr_is_zero(change->addr)) {
- memcpy(dev->etheraddr, change->addr, ETH_ADDR_LEN);
- dev->cache_valid |= VALID_ETHERADDR;
- dev->ether_addr_error = 0;
+ dev->ifindex = change->if_index;
+ dev->cache_valid |= VALID_IFINDEX;
+ dev->get_ifindex_error = 0;
+ } else {
+ netdev_linux_changed(dev, change->ifi_flags, 0);
}
-
- dev->ifindex = change->if_index;
- dev->cache_valid |= VALID_IFINDEX;
- dev->get_ifindex_error = 0;
+ } else if (rtnetlink_type_is_rtnlgrp_addr(change->nlmsg_type)) {
+ /* Invalidates in4, in6. */
+ netdev_linux_changed(dev, dev->ifi_flags, ~VALID_IN);
} else {
- netdev_linux_changed(dev, change->ifi_flags, 0);
+ OVS_NOT_REACHED();
}
}
if (retval < 0) {
return errno;
- } else if (retval > size) {
- return EMSGSIZE;
}
dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
}
static int
-netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **packets,
- int *c)
+netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
{
struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
struct netdev *netdev = rx->up.netdev;
if (retval) {
if (retval != EAGAIN && retval != EMSGSIZE) {
VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
- ovs_strerror(errno), netdev_rxq_get_name(rxq_));
+ netdev_rxq_get_name(rxq_), ovs_strerror(errno));
}
dp_packet_delete(buffer);
} else {
dp_packet_pad(buffer);
- dp_packet_set_rss_hash(buffer, 0);
- packets[0] = buffer;
- *c = 1;
+ batch->packets[0] = buffer;
+ batch->count = 1;
}
return retval;
* expected to do additional queuing of packets. */
static int
netdev_linux_send(struct netdev *netdev_, int qid OVS_UNUSED,
- struct dp_packet **pkts, int cnt, bool may_steal)
+ struct dp_packet_batch *batch, bool may_steal)
{
int i;
int error = 0;
/* 'i' is incremented only if there's no error */
- for (i = 0; i < cnt;) {
- const void *data = dp_packet_data(pkts[i]);
- size_t size = dp_packet_size(pkts[i]);
+ for (i = 0; i < batch->count;) {
+ const void *data = dp_packet_data(batch->packets[i]);
+ size_t size = dp_packet_size(batch->packets[i]);
ssize_t retval;
+ /* Truncate the packet if it is configured. */
+ size -= dp_packet_get_cutlen(batch->packets[i]);
+
if (!is_tap_netdev(netdev_)) {
/* Use our AF_PACKET socket to send to this device. */
struct sockaddr_ll sll;
}
if (retval < 0) {
- /* The Linux AF_PACKET implementation never blocks waiting for room
- * for packets, instead returning ENOBUFS. Translate this into
- * EAGAIN for the caller. */
- error = errno == ENOBUFS ? EAGAIN : errno;
- if (error == EINTR) {
- /* continue without incrementing 'i', i.e. retry this packet */
+ if (errno == EINTR) {
+ /* The send was interrupted by a signal. Retry the packet by
+ * continuing without incrementing 'i'.*/
continue;
+ } else if (errno == EIO && is_tap_netdev(netdev_)) {
+ /* The Linux tap driver returns EIO if the device is not up.
+ * From the OVS side this is not an error, so ignore it. */
+ } else {
+ /* The Linux AF_PACKET implementation never blocks waiting for
+ * room for packets, instead returning ENOBUFS. Translate this
+ * into EAGAIN for the caller. */
+ error = errno == ENOBUFS ? EAGAIN : errno;
+ break;
}
- break;
} else if (retval != size) {
VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRIuSIZE" bytes"
" of %"PRIuSIZE") on %s", retval, size,
i++;
}
- if (may_steal) {
- for (i = 0; i < cnt; i++) {
- dp_packet_delete(pkts[i]);
- }
- }
+ dp_packet_delete_batch(batch, may_steal);
if (error && error != EAGAIN) {
VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
/* Attempts to set 'netdev''s MAC address to 'mac'. Returns 0 if successful,
* otherwise a positive errno value. */
static int
-netdev_linux_set_etheraddr(struct netdev *netdev_,
- const uint8_t mac[ETH_ADDR_LEN])
+netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
enum netdev_flags old_flags = 0;
netdev->ether_addr_error = error;
netdev->cache_valid |= VALID_ETHERADDR;
if (!error) {
- memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
+ netdev->etheraddr = mac;
}
}
/* Copies 'netdev''s MAC address to 'mac' which is passed as param. */
static int
-netdev_linux_get_etheraddr(const struct netdev *netdev_,
- uint8_t mac[ETH_ADDR_LEN])
+netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
int error;
ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_ETHERADDR)) {
netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_),
- netdev->etheraddr);
+ &netdev->etheraddr);
netdev->cache_valid |= VALID_ETHERADDR;
}
error = netdev->ether_addr_error;
if (!error) {
- memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+ *mac = netdev->etheraddr;
}
ovs_mutex_unlock(&netdev->mutex);
if (ecmd.supported & SUPPORTED_1000baseT_Half) {
netdev->supported |= NETDEV_F_1GB_HD;
}
- if (ecmd.supported & SUPPORTED_1000baseT_Full) {
+ if ((ecmd.supported & SUPPORTED_1000baseT_Full) ||
+ (ecmd.supported & SUPPORTED_1000baseKX_Full)) {
netdev->supported |= NETDEV_F_1GB_FD;
}
- if (ecmd.supported & SUPPORTED_10000baseT_Full) {
+ if ((ecmd.supported & SUPPORTED_10000baseT_Full) ||
+ (ecmd.supported & SUPPORTED_10000baseKX4_Full) ||
+ (ecmd.supported & SUPPORTED_10000baseKR_Full) ||
+ (ecmd.supported & SUPPORTED_10000baseR_FEC)) {
netdev->supported |= NETDEV_F_10GB_FD;
}
+ if ((ecmd.supported & SUPPORTED_40000baseKR4_Full) ||
+ (ecmd.supported & SUPPORTED_40000baseCR4_Full) ||
+ (ecmd.supported & SUPPORTED_40000baseSR4_Full) ||
+ (ecmd.supported & SUPPORTED_40000baseLR4_Full)) {
+ netdev->supported |= NETDEV_F_40GB_FD;
+ }
if (ecmd.supported & SUPPORTED_TP) {
netdev->supported |= NETDEV_F_COPPER;
}
if (ecmd.advertising & ADVERTISED_1000baseT_Half) {
netdev->advertised |= NETDEV_F_1GB_HD;
}
- if (ecmd.advertising & ADVERTISED_1000baseT_Full) {
+ if ((ecmd.advertising & ADVERTISED_1000baseT_Full) ||
+ (ecmd.advertising & ADVERTISED_1000baseKX_Full)) {
netdev->advertised |= NETDEV_F_1GB_FD;
}
- if (ecmd.advertising & ADVERTISED_10000baseT_Full) {
+ if ((ecmd.advertising & ADVERTISED_10000baseT_Full) ||
+ (ecmd.advertising & ADVERTISED_10000baseKX4_Full) ||
+ (ecmd.advertising & ADVERTISED_10000baseKR_Full) ||
+ (ecmd.advertising & ADVERTISED_10000baseR_FEC)) {
netdev->advertised |= NETDEV_F_10GB_FD;
}
+ if ((ecmd.advertising & ADVERTISED_40000baseKR4_Full) ||
+ (ecmd.advertising & ADVERTISED_40000baseCR4_Full) ||
+ (ecmd.advertising & ADVERTISED_40000baseSR4_Full) ||
+ (ecmd.advertising & ADVERTISED_40000baseLR4_Full)) {
+ netdev->advertised |= NETDEV_F_40GB_FD;
+ }
if (ecmd.advertising & ADVERTISED_TP) {
netdev->advertised |= NETDEV_F_COPPER;
}
}
/* Current settings. */
- speed = ecmd.speed;
+ speed = ethtool_cmd_speed(&ecmd);
if (speed == SPEED_10) {
netdev->current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD;
} else if (speed == SPEED_100) {
int error;
kbits_burst = (!kbits_rate ? 0 /* Force to 0 if no rate specified. */
- : !kbits_burst ? 1000 /* Default to 1000 kbits if 0. */
+ : !kbits_burst ? 8000 /* Default to 8000 kbits if 0. */
: kbits_burst); /* Stick with user-specified value. */
ovs_mutex_lock(&netdev->mutex);
struct sset *types)
{
const struct tc_ops *const *opsp;
-
for (opsp = tcs; *opsp != NULL; opsp++) {
const struct tc_ops *ops = *opsp;
if (ops->tc_install && ops->ovs_name[0] != '\0') {
return EOPNOTSUPP;
}
+ if (new_ops == &tc_ops_noop) {
+ return new_ops->tc_install(netdev_, details);
+ }
+
ovs_mutex_lock(&netdev->mutex);
error = tc_query_qdisc(netdev_);
if (error) {
return error;
}
-static int
-netdev_linux_get_in4(const struct netdev *netdev_,
- struct in_addr *address, struct in_addr *netmask)
-{
- struct netdev_linux *netdev = netdev_linux_cast(netdev_);
- int error;
-
- ovs_mutex_lock(&netdev->mutex);
- if (!(netdev->cache_valid & VALID_IN4)) {
- error = netdev_linux_get_ipv4(netdev_, &netdev->address,
- SIOCGIFADDR, "SIOCGIFADDR");
- if (!error) {
- error = netdev_linux_get_ipv4(netdev_, &netdev->netmask,
- SIOCGIFNETMASK, "SIOCGIFNETMASK");
- if (!error) {
- netdev->cache_valid |= VALID_IN4;
- }
- }
- } else {
- error = 0;
- }
-
- if (!error) {
- if (netdev->address.s_addr != INADDR_ANY) {
- *address = netdev->address;
- *netmask = netdev->netmask;
- } else {
- error = EADDRNOTAVAIL;
- }
- }
- ovs_mutex_unlock(&netdev->mutex);
-
- return error;
-}
-
static int
netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
struct in_addr netmask)
ovs_mutex_lock(&netdev->mutex);
error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address);
if (!error) {
- netdev->cache_valid |= VALID_IN4;
- netdev->address = address;
- netdev->netmask = netmask;
if (address.s_addr != INADDR_ANY) {
error = do_set_addr(netdev_, SIOCSIFNETMASK,
"SIOCSIFNETMASK", netmask);
}
}
+
ovs_mutex_unlock(&netdev->mutex);
return error;
}
-static bool
-parse_if_inet6_line(const char *line,
- struct in6_addr *in6, char ifname[16 + 1])
-{
- uint8_t *s6 = in6->s6_addr;
-#define X8 "%2"SCNx8
- return ovs_scan(line,
- " "X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8
- "%*x %*x %*x %*x %16s\n",
- &s6[0], &s6[1], &s6[2], &s6[3],
- &s6[4], &s6[5], &s6[6], &s6[7],
- &s6[8], &s6[9], &s6[10], &s6[11],
- &s6[12], &s6[13], &s6[14], &s6[15],
- ifname);
-}
-
-/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address (if
- * 'in6' is non-null) and returns true. Otherwise, returns false. */
+/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
+ * Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
+ * error. */
static int
-netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
+netdev_linux_get_addr_list(const struct netdev *netdev_,
+ struct in6_addr **addr, struct in6_addr **mask, int *n_cnt)
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ int error;
ovs_mutex_lock(&netdev->mutex);
- if (!(netdev->cache_valid & VALID_IN6)) {
- FILE *file;
- char line[128];
-
- netdev->in6 = in6addr_any;
-
- file = fopen("/proc/net/if_inet6", "r");
- if (file != NULL) {
- const char *name = netdev_get_name(netdev_);
- while (fgets(line, sizeof line, file)) {
- struct in6_addr in6_tmp;
- char ifname[16 + 1];
- if (parse_if_inet6_line(line, &in6_tmp, ifname)
- && !strcmp(name, ifname))
- {
- netdev->in6 = in6_tmp;
- break;
- }
- }
- fclose(file);
- }
- netdev->cache_valid |= VALID_IN6;
- }
- *in6 = netdev->in6;
+ error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
ovs_mutex_unlock(&netdev->mutex);
- return 0;
+ return error;
}
static void
* ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
static int
netdev_linux_arp_lookup(const struct netdev *netdev,
- ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
+ ovs_be32 ip, struct eth_addr *mac)
{
struct arpreq r;
struct sockaddr_in sin;
GET_FEATURES, GET_STATUS) \
{ \
NAME, \
+ false, /* is_pmd */ \
\
NULL, \
netdev_linux_run, \
NULL, /* push header */ \
NULL, /* pop header */ \
NULL, /* get_numa_id */ \
- NULL, /* set_multiq */ \
+ NULL, /* set_tx_multiq */ \
\
netdev_linux_send, \
netdev_linux_send_wait, \
netdev_linux_queue_dump_done, \
netdev_linux_dump_queue_stats, \
\
- netdev_linux_get_in4, \
netdev_linux_set_in4, \
- netdev_linux_get_in6, \
+ netdev_linux_get_addr_list, \
netdev_linux_add_router, \
netdev_linux_get_next_hop, \
GET_STATUS, \
netdev_linux_arp_lookup, \
\
netdev_linux_update_flags, \
+ NULL, /* reconfigure */ \
\
netdev_linux_rxq_alloc, \
netdev_linux_rxq_construct, \
htb_tc_destroy(struct tc *tc)
{
struct htb *htb = CONTAINER_OF(tc, struct htb, tc);
- struct htb_class *hc, *next;
+ struct htb_class *hc;
- HMAP_FOR_EACH_SAFE (hc, next, tc_queue.hmap_node, &htb->tc.queues) {
- hmap_remove(&htb->tc.queues, &hc->tc_queue.hmap_node);
+ HMAP_FOR_EACH_POP (hc, tc_queue.hmap_node, &htb->tc.queues) {
free(hc);
}
tc_destroy(tc);
hfsc_class_dump_stats /* class_dump_stats */
};
\f
+/* "linux-noop" traffic control class. */
+
+static void
+noop_install__(struct netdev *netdev_)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_default);
+
+ netdev->tc = CONST_CAST(struct tc *, &tc);
+}
+
+static int
+noop_tc_install(struct netdev *netdev,
+ const struct smap *details OVS_UNUSED)
+{
+ noop_install__(netdev);
+ return 0;
+}
+
+static int
+noop_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
+{
+ noop_install__(netdev);
+ return 0;
+}
+
+static const struct tc_ops tc_ops_noop = {
+ NULL, /* linux_name */
+ "linux-noop", /* ovs_name */
+ 0, /* n_queues */
+ noop_tc_install,
+ noop_tc_load,
+ NULL, /* tc_destroy */
+ NULL, /* qdisc_get */
+ NULL, /* qdisc_set */
+ NULL, /* class_get */
+ NULL, /* class_set */
+ NULL, /* class_delete */
+ NULL, /* class_get_stats */
+ NULL /* class_dump_stats */
+};
+\f
/* "linux-default" traffic control class.
*
* This class represents the default, unnamed Linux qdisc. It corresponds to
tc_police.mtu = mtu;
tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu);
- /* The following appears wrong in two ways:
- *
- * - tc_bytes_to_ticks() should take "bytes" as quantity for both of its
- * arguments (or at least consistently "bytes" as both or "bits" as
- * both), but this supplies bytes for the first argument and bits for the
- * second.
- *
- * - In networking a kilobit is usually 1000 bits but this uses 1024 bits.
+ /* The following appears wrong in one way: In networking a kilobit is
+ * usually 1000 bits but this uses 1024 bits.
*
* However if you "fix" those problems then "tc filter show ..." shows
* "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit ==
* 1,000,000 bits, whereas this actually ends up doing the right thing from
* tc's point of view. Whatever. */
tc_police.burst = tc_bytes_to_ticks(
- tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024);
+ tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024 / 8);
tcmsg = tc_make_request(netdev, RTM_NEWTFILTER,
NLM_F_EXCL | NLM_F_CREATE, &request);
}
COVERAGE_INC(netdev_set_ethtool);
- evalue.data = new_flags = (evalue.data & ~flag) | (enable ? flag : 0);
+ new_flags = (evalue.data & ~flag) | (enable ? flag : 0);
+ if (new_flags == evalue.data) {
+ return 0;
+ }
+ evalue.data = new_flags;
error = netdev_linux_do_ethtool(netdev_name,
(struct ethtool_cmd *)&evalue,
ETHTOOL_SFLAGS, "ETHTOOL_SFLAGS");
struct ofpbuf *reply;
int error;
+ /* Filtering all counters by default */
+ memset(stats, 0xFF, sizeof(struct netdev_stats));
+
ofpbuf_init(&request, 0);
nl_msg_put_nlmsghdr(&request,
sizeof(struct ifinfomsg) + NL_ATTR_SIZE(IFNAMSIZ),
}
static int
-get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
+get_etheraddr(const char *netdev_name, struct eth_addr *ea)
{
struct ifreq ifr;
int hwaddr_family;
}
hwaddr_family = ifr.ifr_hwaddr.sa_family;
if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
- VLOG_WARN("%s device has unknown hardware address family %d",
+ VLOG_INFO("%s device has unknown hardware address family %d",
netdev_name, hwaddr_family);
+ return EINVAL;
}
memcpy(ea, ifr.ifr_hwaddr.sa_data, ETH_ADDR_LEN);
return 0;
}
static int
-set_etheraddr(const char *netdev_name,
- const uint8_t mac[ETH_ADDR_LEN])
+set_etheraddr(const char *netdev_name, const struct eth_addr mac)
{
struct ifreq ifr;
int error;
memset(&ifr, 0, sizeof ifr);
ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
- memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN);
+ memcpy(ifr.ifr_hwaddr.sa_data, &mac, ETH_ADDR_LEN);
COVERAGE_INC(netdev_set_hwaddr);
error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
if (error) {
return error;
}
-static int
-netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip,
- int cmd, const char *cmd_name)
-{
- struct ifreq ifr;
- int error;
-
- ifr.ifr_addr.sa_family = AF_INET;
- error = af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, cmd, cmd_name);
- if (!error) {
- const struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *,
- &ifr.ifr_addr);
- *ip = sin->sin_addr;
- }
- return error;
-}
-
/* Returns an AF_PACKET raw socket or a negative errno value. */
static int
af_packet_sock(void)