X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=30cd0f6390695d9a98e9a05fed3f05ef83754827;hb=4b60911067a82fbdfa87b7c2824412da20287ed8;hp=433d1687a3015eff9c55930559d622e3d72eed23;hpb=cb22974d773942d66da42b700b8bca0db27a0920;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 433d1687a..30cd0f639 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -55,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); @@ -138,6 +139,8 @@ struct tc { * Written only by TC implementation. */ }; +#define TC_INITIALIZER(TC, OPS) { OPS, HMAP_INITIALIZER(&(TC)->queues) } + /* One traffic control queue. * * Each TC implementation subclasses this with whatever additional data it @@ -310,7 +313,7 @@ static const struct tc_ops tc_ops_hfsc; static const struct tc_ops tc_ops_default; static const struct tc_ops tc_ops_other; -static const struct tc_ops *tcs[] = { +static const struct tc_ops *const tcs[] = { &tc_ops_htb, /* Hierarchy token bucket (see tc-htb(8)). */ &tc_ops_hfsc, /* Hierarchical fair service curve. */ &tc_ops_default, /* Default qdisc (see tc-pfifo_fast(8)). */ @@ -419,7 +422,7 @@ static int netdev_linux_do_ioctl(const char *name, struct ifreq *, int cmd, 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_dev *, unsigned int *flags); -static int set_flags(struct netdev *, unsigned int flags); +static int set_flags(const char *, unsigned int flags); static int do_get_ifindex(const char *netdev_name); static int get_ifindex(const struct netdev *, int *ifindexp); static int do_set_addr(struct netdev *netdev, @@ -915,7 +918,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); @@ -1001,8 +1004,8 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); + struct netdev_saved_flags *sf = NULL; int error; - bool up_again = false; if (netdev_dev->cache_valid & VALID_ETHERADDR) { if (netdev_dev->ether_addr_error) { @@ -1019,8 +1022,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, enum netdev_flags flags; if (!netdev_get_flags(netdev_, &flags) && (flags & NETDEV_UP)) { - netdev_turn_flags_off(netdev_, NETDEV_UP, false); - up_again = true; + netdev_turn_flags_off(netdev_, NETDEV_UP, &sf); } } error = set_etheraddr(netdev_get_name(netdev_), mac); @@ -1032,9 +1034,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, } } - if (up_again) { - netdev_turn_flags_on(netdev_, NETDEV_UP, false); - } + netdev_restore_flags(sf); return error; } @@ -1309,6 +1309,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) @@ -1320,7 +1372,7 @@ 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); + 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)); @@ -1798,7 +1850,7 @@ static int netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED, struct sset *types) { - const struct tc_ops **opsp; + const struct tc_ops *const *opsp; for (opsp = tcs; *opsp != NULL; opsp++) { const struct tc_ops *ops = *opsp; @@ -1812,7 +1864,7 @@ netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED, static const struct tc_ops * tc_lookup_ovs_name(const char *name) { - const struct tc_ops **opsp; + const struct tc_ops *const *opsp; for (opsp = tcs; *opsp != NULL; opsp++) { const struct tc_ops *ops = *opsp; @@ -1826,7 +1878,7 @@ tc_lookup_ovs_name(const char *name) static const struct tc_ops * tc_lookup_linux_name(const char *name) { - const struct tc_ops **opsp; + const struct tc_ops *const *opsp; for (opsp = tcs; *opsp != NULL; opsp++) { const struct tc_ops *ops = *opsp; @@ -2395,19 +2447,19 @@ iff_to_nd_flags(int iff) } static int -netdev_linux_update_flags(struct netdev *netdev, enum netdev_flags off, +netdev_linux_update_flags(struct netdev_dev *dev_, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp) { struct netdev_dev_linux *netdev_dev; int old_flags, new_flags; int error = 0; - netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); + netdev_dev = netdev_dev_linux_cast(dev_); old_flags = netdev_dev->ifi_flags; *old_flagsp = iff_to_nd_flags(old_flags); new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); if (new_flags != old_flags) { - error = set_flags(netdev, new_flags); + error = set_flags(netdev_dev_get_name(dev_), new_flags); get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); } return error; @@ -3506,13 +3558,11 @@ default_install__(struct netdev *netdev) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); - static struct tc *tc; + static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_default); - if (!tc) { - tc = xmalloc(sizeof *tc); - tc_init(tc, &tc_ops_default); - } - netdev_dev->tc = tc; + /* Nothing but a tc class implementation is allowed to write to a tc. This + * class never does that, so we can legitimately use a const tc object. */ + netdev_dev->tc = CONST_CAST(struct tc *, &tc); } static int @@ -3555,13 +3605,11 @@ other_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); - static struct tc *tc; + static const struct tc tc = TC_INITIALIZER(&tc, &tc_ops_other); - if (!tc) { - tc = xmalloc(sizeof *tc); - tc_init(tc, &tc_ops_other); - } - netdev_dev->tc = tc; + /* Nothing but a tc class implementation is allowed to write to a tc. This + * class never does that, so we can legitimately use a const tc object. */ + netdev_dev->tc = CONST_CAST(struct tc *, &tc); return 0; } @@ -3730,7 +3778,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); @@ -4430,13 +4478,12 @@ get_flags(const struct netdev_dev *dev, unsigned int *flags) } static int -set_flags(struct netdev *netdev, unsigned int flags) +set_flags(const char *name, unsigned int flags) { struct ifreq ifr; ifr.ifr_flags = flags; - return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, SIOCSIFFLAGS, - "SIOCSIFFLAGS"); + return netdev_linux_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); } static int @@ -4586,7 +4633,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));