X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=6ad08520050307f64aabf784e2dbaf86e862091d;hb=dd1ba5b3f4425c8eba008d1a93b044da63466812;hp=9ff286ee4fe75b0031c2f24dae02a66622dbb0f9;hpb=a57a8488da2e6e02f515230d42a958126971ba8e;p=openvswitch diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 9ff286ee..6ad08520 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011 Nicira Networks. + * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -368,7 +368,7 @@ struct netdev_dev_linux { struct in_addr address, netmask; struct in6_addr in6; int mtu; - bool carrier; + unsigned int ifi_flags; long long int carrier_resets; uint32_t kbits_rate; /* Policing data. */ uint32_t kbits_burst; @@ -403,8 +403,8 @@ static int netdev_linux_do_ioctl(const char *name, struct ifreq *, 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 *, int *flagsp); -static int set_flags(struct netdev *, int flags); +static int get_flags(const struct netdev_dev *, unsigned int *flags); +static int set_flags(struct netdev *, 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, @@ -415,7 +415,6 @@ static int set_etheraddr(const char *netdev_name, int hwaddr_family, const uint8_t[ETH_ADDR_LEN]); static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats); static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats); -static int get_carrier_via_sysfs(const char *name, bool *carrier); static int af_packet_sock(void); static void netdev_linux_miimon_run(void); static void netdev_linux_miimon_wait(void); @@ -484,12 +483,18 @@ netdev_linux_wait(void) } static void -netdev_dev_linux_changed(struct netdev_dev_linux *dev) +netdev_dev_linux_changed(struct netdev_dev_linux *dev, unsigned int ifi_flags) { dev->change_seq++; if (!dev->change_seq) { dev->change_seq++; } + + if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) { + dev->carrier_resets++; + } + dev->ifi_flags = ifi_flags; + dev->cache_valid = 0; } @@ -506,13 +511,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, if (is_netdev_linux_class(netdev_class)) { dev = netdev_dev_linux_cast(base_dev); - - if (dev->carrier != change->running) { - dev->carrier = change->running; - dev->carrier_resets++; - } - - netdev_dev_linux_changed(dev); + netdev_dev_linux_changed(dev, change->ifi_flags); } } } else { @@ -522,17 +521,12 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, shash_init(&device_shash); netdev_dev_get_devices(&netdev_linux_class, &device_shash); SHASH_FOR_EACH (node, &device_shash) { - bool carrier; + unsigned int flags; dev = node->data; - get_carrier_via_sysfs(node->name, &carrier); - if (dev->carrier != carrier) { - dev->carrier = carrier; - dev->carrier_resets++; - } - - netdev_dev_linux_changed(dev); + get_flags(&dev->netdev_dev, &flags); + netdev_dev_linux_changed(dev, flags); } shash_destroy(&device_shash); } @@ -583,7 +577,7 @@ netdev_linux_create(const struct netdev_class *class, const char *name, netdev_dev = xzalloc(sizeof *netdev_dev); netdev_dev->change_seq = 1; netdev_dev_init(&netdev_dev->netdev_dev, name, class); - get_carrier_via_sysfs(name, &netdev_dev->carrier); + get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); *netdev_devp = &netdev_dev->netdev_dev; return 0; @@ -802,9 +796,9 @@ netdev_linux_recv(struct netdev *netdev_, void *data, size_t size) } for (;;) { - ssize_t retval = read(netdev->fd, data, size); + ssize_t retval = recv(netdev->fd, data, size, MSG_TRUNC); if (retval >= 0) { - return retval; + return retval <= size ? retval : -EMSGSIZE; } else if (errno != EINTR) { if (errno != EAGAIN) { VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", @@ -1030,6 +1024,10 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu) struct ifreq ifr; int error; + if (netdev_dev->cache_valid & VALID_MTU && + netdev_dev->mtu == mtu) { + return 0; + } ifr.ifr_mtu = mtu; error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, SIOCSIFMTU, "SIOCSIFMTU"); @@ -1062,7 +1060,7 @@ netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier) if (netdev_dev->miimon_interval > 0) { *carrier = netdev_dev->miimon; } else { - *carrier = netdev_dev->carrier; + *carrier = (netdev_dev->ifi_flags & IFF_RUNNING) != 0; } return 0; @@ -1168,7 +1166,7 @@ netdev_linux_miimon_run(void) netdev_linux_get_miimon(dev->netdev_dev.name, &miimon); if (miimon != dev->miimon) { dev->miimon = miimon; - netdev_dev_linux_changed(dev); + netdev_dev_linux_changed(dev, dev->ifi_flags); } timer_set_duration(&dev->miimon_timer, dev->miimon_interval); @@ -2209,16 +2207,17 @@ static int netdev_linux_update_flags(struct netdev *netdev, 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; + int error = 0; - error = get_flags(netdev, &old_flags); - if (!error) { - *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); - } + netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); + 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); + get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); } return error; } @@ -4214,71 +4213,22 @@ get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats) } static int -get_carrier_via_sysfs(const char *name, bool *carrier) -{ - char line[8]; - int retval; - - int error = 0; - char *fn = NULL; - int fd = -1; - - *carrier = false; - - fn = xasprintf("/sys/class/net/%s/carrier", name); - fd = open(fn, O_RDONLY); - if (fd < 0) { - error = errno; - VLOG_WARN_RL(&rl, "%s: open failed: %s", fn, strerror(error)); - goto exit; - } - - retval = read(fd, line, sizeof line); - if (retval < 0) { - error = errno; - if (error == EINVAL) { - /* This is the normal return value when we try to check carrier if - * the network device is not up. */ - } else { - VLOG_WARN_RL(&rl, "%s: read failed: %s", fn, strerror(error)); - } - goto exit; - } else if (retval == 0) { - error = EPROTO; - VLOG_WARN_RL(&rl, "%s: unexpected end of file", fn); - goto exit; - } - - if (line[0] != '0' && line[0] != '1') { - error = EPROTO; - VLOG_WARN_RL(&rl, "%s: value is %c (expected 0 or 1)", fn, line[0]); - goto exit; - } - *carrier = line[0] != '0'; - error = 0; - -exit: - if (fd >= 0) { - close(fd); - } - free(fn); - return error; -} - -static int -get_flags(const struct netdev *netdev, int *flags) +get_flags(const struct netdev_dev *dev, unsigned int *flags) { struct ifreq ifr; int error; - error = netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, SIOCGIFFLAGS, + *flags = 0; + error = netdev_linux_do_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); - *flags = ifr.ifr_flags; + if (!error) { + *flags = ifr.ifr_flags; + } return error; } static int -set_flags(struct netdev *netdev, int flags) +set_flags(struct netdev *netdev, unsigned int flags) { struct ifreq ifr;