#include "rtnetlink-link.h"
#include "socket-util.h"
#include "shash.h"
-#include "svec.h"
+#include "sset.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(netdev_linux);
int fd;
};
-/* An AF_INET socket (used for ioctl operations). */
-static int af_inet_sock = -1;
+/* Sockets used for ioctl operations. */
+static int af_inet_sock = -1; /* AF_INET, SOCK_DGRAM. */
+static int af_packet_sock = -1; /* AF_PACKET, SOCK_RAW. */
/* A Netlink routing socket that is not subscribed to any multicast groups. */
static struct nl_sock *rtnl_sock;
status = af_inet_sock >= 0 ? 0 : errno;
if (status) {
VLOG_ERR("failed to create inet socket: %s", strerror(status));
+ } else {
+ /* Create AF_PACKET socket. */
+ af_packet_sock = socket(AF_PACKET, SOCK_RAW, 0);
+ status = af_packet_sock >= 0 ? 0 : errno;
+ if (status) {
+ VLOG_ERR("failed to create packet socket: %s",
+ strerror(status));
+ }
}
/* Create rtnetlink socket. */
free(netdev);
}
-/* Initializes 'svec' with a list of the names of all known network devices. */
+/* Initializes 'sset' with a list of the names of all known network devices. */
static int
-netdev_linux_enumerate(struct svec *svec)
+netdev_linux_enumerate(struct sset *sset)
{
struct if_nameindex *names;
size_t i;
for (i = 0; names[i].if_name != NULL; i++) {
- svec_add(svec, names[i].if_name);
+ sset_add(sset, names[i].if_name);
}
if_freenameindex(names);
return 0;
static int
netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
{
- struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ struct sockaddr_ll sll;
+ struct msghdr msg;
+ struct iovec iov;
+ int ifindex;
+ int error;
- /* XXX should support sending even if 'ethertype' was NETDEV_ETH_TYPE_NONE.
- */
- if (netdev->fd < 0) {
- return EPIPE;
+ error = get_ifindex(netdev_, &ifindex);
+ if (error) {
+ return error;
}
+ /* We don't bother setting most fields in sockaddr_ll because the kernel
+ * ignores them for SOCK_RAW. */
+ memset(&sll, 0, sizeof sll);
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = ifindex;
+
+ iov.iov_base = (void *) data;
+ iov.iov_len = size;
+
+ msg.msg_name = &sll;
+ msg.msg_namelen = sizeof sll;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
for (;;) {
- ssize_t retval = write(netdev->fd, data, size);
+ ssize_t retval = sendmsg(af_packet_sock, &msg, 0);
if (retval < 0) {
/* The Linux AF_PACKET implementation never blocks waiting for room
* for packets, instead returning ENOBUFS. Translate this into
static int
netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED,
- struct svec *types)
+ struct sset *types)
{
const struct tc_ops **opsp;
for (opsp = tcs; *opsp != NULL; opsp++) {
const struct tc_ops *ops = *opsp;
if (ops->tc_install && ops->ovs_name[0] != '\0') {
- svec_add(types, ops->ovs_name);
+ sset_add(types, ops->ovs_name);
}
}
return 0;
int retval;
memset(&r, 0, sizeof r);
+ memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = 0;
return CONTAINER_OF(netdev_dev->tc, struct htb, tc);
}
-static struct htb *
+static void
htb_install__(struct netdev *netdev, uint64_t max_rate)
{
struct netdev_dev_linux *netdev_dev =
htb->max_rate = max_rate;
netdev_dev->tc = &htb->tc;
-
- return htb;
}
/* Create an HTB qdisc.
return EINVAL;
}
- /* min-rate. Don't allow a min-rate below 1500 bytes/s. */
- if (!min_rate_s) {
- /* min-rate is required. */
- return EINVAL;
- }
- hc->min_rate = strtoull(min_rate_s, NULL, 10) / 8;
- hc->min_rate = MAX(hc->min_rate, 1500);
+ /* HTB requires at least an mtu sized min-rate to send any traffic even
+ * on uncongested links. */
+ hc->min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0;
+ hc->min_rate = MAX(hc->min_rate, mtu);
hc->min_rate = MIN(hc->min_rate, htb->max_rate);
/* max-rate */
struct ofpbuf msg;
struct nl_dump dump;
struct htb_class hc;
- struct htb *htb;
/* Get qdisc options. */
hc.max_rate = 0;
htb_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL);
- htb = htb_install__(netdev, hc.max_rate);
+ htb_install__(netdev, hc.max_rate);
/* Get queues. */
if (!start_queue_dump(netdev, &dump)) {
return CONTAINER_OF(queue, struct hfsc_class, tc_queue);
}
-static struct hfsc *
+static void
hfsc_install__(struct netdev *netdev, uint32_t max_rate)
{
struct netdev_dev_linux * netdev_dev;
tc_init(&hfsc->tc, &tc_ops_hfsc);
hfsc->max_rate = max_rate;
netdev_dev->tc = &hfsc->tc;
-
- return hfsc;
}
static void
min_rate_s = shash_find_data(details, "min-rate");
max_rate_s = shash_find_data(details, "max-rate");
- if (!min_rate_s) {
- return EINVAL;
- }
-
- min_rate = strtoull(min_rate_s, NULL, 10) / 8;
- min_rate = MAX(min_rate, 1500);
+ min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0;
+ min_rate = MAX(min_rate, 1);
min_rate = MIN(min_rate, hfsc->max_rate);
max_rate = (max_rate_s
hfsc_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED)
{
struct ofpbuf msg;
- struct hfsc *hfsc;
struct nl_dump dump;
struct hfsc_class hc;
hc.max_rate = 0;
hfsc_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL);
- hfsc = hfsc_install__(netdev, hc.max_rate);
+ hfsc_install__(netdev, hc.max_rate);
if (!start_queue_dump(netdev, &dump)) {
return ENODEV;