X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=c0e0c40c5d2df63ef950da1b27192c150c9d43fc;hb=d978fa4832bbc5176e05edd05bcdf2452a8dded2;hp=b81396824a94cedd1c174383431afa4f1fa56374;hpb=7eb1bd81120806b4189e860b2a6468925d8e7bba;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index b81396824..c0e0c40c5 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ #include "netdev-linux.h" -#include #include #include #include @@ -56,18 +55,19 @@ #include "hmap.h" #include "netdev-provider.h" #include "netdev-vport.h" -#include "netlink.h" #include "netlink-notifier.h" #include "netlink-socket.h" +#include "netlink.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" #include "rtnetlink-link.h" -#include "socket-util.h" #include "shash.h" +#include "socket-util.h" #include "sset.h" #include "timer.h" +#include "unaligned.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_linux); @@ -444,7 +444,7 @@ static struct netdev_dev_linux * netdev_dev_linux_cast(const struct netdev_dev *netdev_dev) { const struct netdev_class *netdev_class = netdev_dev_get_class(netdev_dev); - assert(is_netdev_linux_class(netdev_class)); + ovs_assert(is_netdev_linux_class(netdev_class)); return CONTAINER_OF(netdev_dev, struct netdev_dev_linux, netdev_dev); } @@ -454,7 +454,7 @@ netdev_linux_cast(const struct netdev *netdev) { struct netdev_dev *netdev_dev = netdev_get_dev(netdev); const struct netdev_class *netdev_class = netdev_dev_get_class(netdev_dev); - assert(is_netdev_linux_class(netdev_class)); + ovs_assert(is_netdev_linux_class(netdev_class)); return CONTAINER_OF(netdev, struct netdev_linux, netdev); } @@ -497,28 +497,6 @@ netdev_linux_wait(void) netdev_linux_miimon_wait(); } -static int -netdev_linux_get_drvinfo(struct netdev_dev_linux *netdev_dev) -{ - - int error; - - if (netdev_dev->cache_valid & VALID_DRVINFO) { - return 0; - } - - COVERAGE_INC(netdev_get_ethtool); - memset(&netdev_dev->drvinfo, 0, sizeof netdev_dev->drvinfo); - error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, - (struct ethtool_cmd *)&netdev_dev->drvinfo, - ETHTOOL_GDRVINFO, - "ETHTOOL_GDRVINFO"); - if (!error) { - netdev_dev->cache_valid |= VALID_DRVINFO; - } - return error; -} - static void netdev_dev_linux_changed(struct netdev_dev_linux *dev, unsigned int ifi_flags, @@ -605,7 +583,7 @@ static int cache_notifier_ref(void) { if (!cache_notifier_refcount) { - assert(!netdev_linux_cache_notifier); + ovs_assert(!netdev_linux_cache_notifier); netdev_linux_cache_notifier = rtnetlink_link_notifier_create(netdev_linux_cache_cb, NULL); @@ -622,9 +600,9 @@ cache_notifier_ref(void) static void cache_notifier_unref(void) { - assert(cache_notifier_refcount > 0); + ovs_assert(cache_notifier_refcount > 0); if (!--cache_notifier_refcount) { - assert(netdev_linux_cache_notifier); + ovs_assert(netdev_linux_cache_notifier); rtnetlink_link_notifier_destroy(netdev_linux_cache_notifier); netdev_linux_cache_notifier = NULL; } @@ -743,7 +721,6 @@ netdev_linux_destroy(struct netdev_dev *netdev_dev_) static int netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp) { - struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_); struct netdev_linux *netdev; enum netdev_flags flags; int error; @@ -768,17 +745,6 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp) } } - if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") && - !netdev_dev->state.tap.opened) { - - /* We assume that the first user of the tap device is the primary user - * and give them the tap FD. Subsequent users probably just expect - * this to be a system device so open it normally to avoid send/receive - * directions appearing to be reversed. */ - netdev->fd = netdev_dev->state.tap.fd; - netdev_dev->state.tap.opened = true; - } - *netdevp = &netdev->netdev; return 0; @@ -803,6 +769,8 @@ static int netdev_linux_listen(struct netdev *netdev_) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct netdev_dev_linux *netdev_dev = + netdev_dev_linux_cast(netdev_get_dev(netdev_)); struct sockaddr_ll sll; int ifindex; int error; @@ -812,6 +780,13 @@ netdev_linux_listen(struct netdev *netdev_) return 0; } + if (!strcmp(netdev_get_type(netdev_), "tap") + && !netdev_dev->state.tap.opened) { + netdev->fd = netdev_dev->state.tap.fd; + netdev_dev->state.tap.opened = true; + return 0; + } + /* Create file descriptor. */ fd = socket(PF_PACKET, SOCK_RAW, 0); if (fd < 0) { @@ -941,7 +916,7 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) sock = af_packet_sock(); if (sock < 0) { - return sock; + return -sock; } error = get_ifindex(netdev_, &ifindex); @@ -1335,6 +1310,58 @@ swap_uint64(uint64_t *a, uint64_t *b) *b = tmp; } +/* Copies 'src' into 'dst', performing format conversion in the process. + * + * 'src' is allowed to be misaligned. */ +static void +netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst, + const struct ovs_vport_stats *src) +{ + dst->rx_packets = get_unaligned_u64(&src->rx_packets); + dst->tx_packets = get_unaligned_u64(&src->tx_packets); + dst->rx_bytes = get_unaligned_u64(&src->rx_bytes); + dst->tx_bytes = get_unaligned_u64(&src->tx_bytes); + dst->rx_errors = get_unaligned_u64(&src->rx_errors); + dst->tx_errors = get_unaligned_u64(&src->tx_errors); + dst->rx_dropped = get_unaligned_u64(&src->rx_dropped); + dst->tx_dropped = get_unaligned_u64(&src->tx_dropped); + dst->multicast = 0; + dst->collisions = 0; + dst->rx_length_errors = 0; + dst->rx_over_errors = 0; + dst->rx_crc_errors = 0; + dst->rx_frame_errors = 0; + dst->rx_fifo_errors = 0; + dst->rx_missed_errors = 0; + dst->tx_aborted_errors = 0; + dst->tx_carrier_errors = 0; + dst->tx_fifo_errors = 0; + dst->tx_heartbeat_errors = 0; + dst->tx_window_errors = 0; +} + +static int +get_stats_via_vport__(const struct netdev *netdev, struct netdev_stats *stats) +{ + struct dpif_linux_vport reply; + struct ofpbuf *buf; + int error; + + error = dpif_linux_vport_get(netdev_get_name(netdev), &reply, &buf); + if (error) { + return error; + } else if (!reply.stats) { + ofpbuf_delete(buf); + return EOPNOTSUPP; + } + + netdev_stats_from_ovs_vport_stats(stats, reply.stats); + + ofpbuf_delete(buf); + + return 0; +} + static void get_stats_via_vport(const struct netdev *netdev_, struct netdev_stats *stats) @@ -1346,8 +1373,8 @@ get_stats_via_vport(const struct netdev *netdev_, !(netdev_dev->cache_valid & VALID_VPORT_STAT_ERROR)) { int error; - error = netdev_vport_get_stats(netdev_, stats); - if (error) { + error = get_stats_via_vport__(netdev_, stats); + if (error && error != ENOENT) { VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed " "(%s)", netdev_get_name(netdev_), strerror(error)); } @@ -1502,6 +1529,41 @@ netdev_internal_get_stats(const struct netdev *netdev_, return netdev_dev->vport_stats_error; } +static int +netdev_internal_set_stats(struct netdev *netdev, + const struct netdev_stats *stats) +{ + struct ovs_vport_stats vport_stats; + struct dpif_linux_vport vport; + int err; + + vport_stats.rx_packets = stats->rx_packets; + vport_stats.tx_packets = stats->tx_packets; + vport_stats.rx_bytes = stats->rx_bytes; + vport_stats.tx_bytes = stats->tx_bytes; + vport_stats.rx_errors = stats->rx_errors; + vport_stats.tx_errors = stats->tx_errors; + vport_stats.rx_dropped = stats->rx_dropped; + vport_stats.tx_dropped = stats->tx_dropped; + + dpif_linux_vport_init(&vport); + vport.cmd = OVS_VPORT_CMD_SET; + vport.name = netdev_get_name(netdev); + vport.stats = &vport_stats; + + err = dpif_linux_vport_transact(&vport, NULL, NULL); + + /* If the vport layer doesn't know about the device, that doesn't mean it + * doesn't exist (after all were able to open it when netdev_open() was + * called), it just means that it isn't attached and we'll be getting + * stats a different way. */ + if (err == ENODEV) { + err = EOPNOTSUPP; + } + + return err; +} + static void netdev_linux_read_features(struct netdev_dev_linux *netdev_dev) { @@ -1909,11 +1971,11 @@ netdev_linux_set_qos(struct netdev *netdev, if (error) { return error; } - assert(netdev_dev->tc == NULL); + ovs_assert(netdev_dev->tc == NULL); /* Install new qdisc. */ error = new_ops->tc_install(netdev, details); - assert((error == 0) == (netdev_dev->tc != NULL)); + ovs_assert((error == 0) == (netdev_dev->tc != NULL)); return error; } @@ -2291,13 +2353,26 @@ netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop, } static int -netdev_linux_get_drv_info(const struct netdev *netdev, struct smap *smap) +netdev_linux_get_status(const struct netdev *netdev, struct smap *smap) { - int error; - struct netdev_dev_linux *netdev_dev = - netdev_dev_linux_cast(netdev_get_dev(netdev)); + struct netdev_dev_linux *netdev_dev; + int error = 0; + + netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); + if (!(netdev_dev->cache_valid & VALID_DRVINFO)) { + struct ethtool_cmd *cmd = (struct ethtool_cmd *) &netdev_dev->drvinfo; + + COVERAGE_INC(netdev_get_ethtool); + memset(&netdev_dev->drvinfo, 0, sizeof netdev_dev->drvinfo); + error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, + cmd, + ETHTOOL_GDRVINFO, + "ETHTOOL_GDRVINFO"); + if (!error) { + netdev_dev->cache_valid |= VALID_DRVINFO; + } + } - error = netdev_linux_get_drvinfo(netdev_dev); if (!error) { smap_add(smap, "driver_name", netdev_dev->drvinfo.driver); smap_add(smap, "driver_version", netdev_dev->drvinfo.version); @@ -2307,8 +2382,8 @@ netdev_linux_get_drv_info(const struct netdev *netdev, struct smap *smap) } static int -netdev_internal_get_drv_info(const struct netdev *netdev OVS_UNUSED, - struct smap *smap) +netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED, + struct smap *smap) { smap_add(smap, "driver_name", "openvswitch"); return 0; @@ -2341,7 +2416,7 @@ netdev_linux_arp_lookup(const struct netdev *netdev, memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN); } else if (retval != ENXIO) { VLOG_WARN_RL(&rl, "%s: could not look up ARP entry for "IP_FMT": %s", - netdev_get_name(netdev), IP_ARGS(&ip), strerror(retval)); + netdev_get_name(netdev), IP_ARGS(ip), strerror(retval)); } return retval; } @@ -2410,6 +2485,7 @@ netdev_linux_change_seq(const struct netdev *netdev) netdev_linux_destroy, \ NULL, /* get_config */ \ NULL, /* set_config */ \ + NULL, /* get_tunnel_config */ \ \ netdev_linux_open, \ netdev_linux_close, \ @@ -2468,7 +2544,7 @@ const struct netdev_class netdev_linux_class = netdev_linux_get_stats, NULL, /* set_stats */ netdev_linux_get_features, - netdev_linux_get_drv_info); + netdev_linux_get_status); const struct netdev_class netdev_tap_class = NETDEV_LINUX_CLASS( @@ -2477,16 +2553,16 @@ const struct netdev_class netdev_tap_class = netdev_tap_get_stats, NULL, /* set_stats */ netdev_linux_get_features, - netdev_linux_get_drv_info); + netdev_linux_get_status); const struct netdev_class netdev_internal_class = NETDEV_LINUX_CLASS( "internal", netdev_linux_create, netdev_internal_get_stats, - netdev_vport_set_stats, + netdev_internal_set_stats, NULL, /* get_features */ - netdev_internal_get_drv_info); + netdev_internal_get_status); /* HTB traffic control class. */ @@ -3707,7 +3783,7 @@ tc_add_policer(struct netdev *netdev, int kbits_rate, int kbits_burst) memset(&tc_police, 0, sizeof tc_police); tc_police.action = TC_POLICE_SHOT; tc_police.mtu = mtu; - tc_fill_rate(&tc_police.rate, kbits_rate/8 * 1000, mtu); + tc_fill_rate(&tc_police.rate, (kbits_rate * 1000)/8, mtu); tc_police.burst = tc_bytes_to_ticks(tc_police.rate.rate, kbits_burst * 1024); @@ -4121,7 +4197,7 @@ tc_query_qdisc(const struct netdev *netdev) /* Instantiate it. */ load_error = ops->tc_load(CONST_CAST(struct netdev *, netdev), qdisc); - assert((load_error == 0) == (netdev_dev->tc != NULL)); + ovs_assert((load_error == 0) == (netdev_dev->tc != NULL)); ofpbuf_delete(qdisc); return error ? error : load_error; @@ -4563,7 +4639,11 @@ af_packet_sock(void) if (sock == INT_MIN) { sock = socket(AF_PACKET, SOCK_RAW, 0); if (sock >= 0) { - set_nonblocking(sock); + int error = set_nonblocking(sock); + if (error) { + close(sock); + sock = -error; + } } else { sock = -errno; VLOG_ERR("failed to create packet socket: %s", strerror(errno));