From: Ben Pfaff Date: Wed, 21 May 2008 21:11:59 +0000 (-0700) Subject: New functions for getting and setting network device flags. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=23e054dcb699c58cc142cee1920972da02211341;p=openvswitch New functions for getting and setting network device flags. This allows us to open network devices without bringing them up and setting them for promiscuous mode, which will be useful in the secchan for in-band communication. --- diff --git a/include/netdev.h b/include/netdev.h index 990d499d..3dfd5dba 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -47,6 +47,11 @@ struct buffer; struct in_addr; struct in6_addr; +enum netdev_flags { + NETDEV_UP = 0x0001, /* Device enabled? */ + NETDEV_PROMISC = 0x0002 /* Promiscuous mode? */ +}; + struct netdev; int netdev_open(const char *name, struct netdev **); void netdev_close(struct netdev *); @@ -60,5 +65,7 @@ int netdev_get_speed(const struct netdev *); uint32_t netdev_get_features(const struct netdev *); bool netdev_get_in4(const struct netdev *, struct in_addr *); bool netdev_get_in6(const struct netdev *, struct in6_addr *); +int netdev_get_flags(const struct netdev *, enum netdev_flags *); +int netdev_set_flags(struct netdev *, enum netdev_flags); #endif /* netdev.h */ diff --git a/lib/netdev.c b/lib/netdev.c index df967925..d29848d7 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -80,6 +80,8 @@ static struct list netdev_list = LIST_INITIALIZER(&netdev_list); static void init_netdev(void); static int restore_flags(struct netdev *netdev); +static int get_flags(const struct netdev *, int *flagsp); +static int set_flags(struct netdev *, int flags); /* Obtains the IPv4 address for 'name' into 'in4'. Returns true if * successful. */ @@ -321,32 +323,21 @@ netdev_open(const char *name, struct netdev **netdev_) do_ethtool(netdev); /* Save flags to restore at close or exit. */ - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { - VLOG_ERR("ioctl(SIOCGIFFLAGS) on %s device failed: %s", - name, strerror(errno)); - goto error; + error = get_flags(netdev, &netdev->save_flags); + if (error) { + goto preset_error; } - netdev->save_flags = ifr.ifr_flags; fatal_signal_block(); list_push_back(&netdev_list, &netdev->node); fatal_signal_unblock(); - /* Bring up interface and set promiscuous mode. */ - ifr.ifr_flags |= IFF_PROMISC | IFF_UP; - if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { - error = errno; - VLOG_ERR("failed to set promiscuous mode on %s device: %s", - name, strerror(errno)); - netdev_close(netdev); - return error; - } - /* Success! */ *netdev_ = netdev; return 0; error: error = errno; +preset_error: close(fd); return error; } @@ -561,6 +552,54 @@ netdev_get_in6(const struct netdev *netdev, struct in6_addr *in6) *in6 = netdev->in6; return memcmp(in6, &in6addr_any, sizeof *in6) != 0; } + +/* Obtains the current flags for 'netdev' and stores them into '*flagsp'. + * Returns 0 if successful, otherwise a positive errno value. */ +int +netdev_get_flags(const struct netdev *netdev, enum netdev_flags *flagsp) +{ + int error, flags; + + error = get_flags(netdev, &flags); + if (error) { + return error; + } + + *flagsp = 0; + if (flags & IFF_UP) { + *flagsp |= NETDEV_UP; + } + if (flags & IFF_PROMISC) { + *flagsp |= NETDEV_PROMISC; + } + return 0; +} + +/* Sets the flags for 'netdev' to 'nd_flags'. + * Returns 0 if successful, otherwise a positive errno value. */ +int +netdev_set_flags(struct netdev *netdev, enum netdev_flags nd_flags) +{ + int old_flags, new_flags; + int error; + + error = get_flags(netdev, &old_flags); + if (error) { + return error; + } + + new_flags = old_flags & ~(IFF_UP | IFF_PROMISC); + if (nd_flags & NETDEV_UP) { + new_flags |= IFF_UP; + } + if (nd_flags & NETDEV_PROMISC) { + new_flags |= IFF_PROMISC; + } + if (new_flags != old_flags) { + error = set_flags(netdev, new_flags); + } + return error; +} static void restore_all_flags(void *aux); @@ -614,3 +653,31 @@ restore_all_flags(void *aux UNUSED) restore_flags(netdev); } } + +static int +get_flags(const struct netdev *netdev, int *flags) +{ + struct ifreq ifr; + strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name); + if (ioctl(netdev->fd, SIOCGIFFLAGS, &ifr) < 0) { + VLOG_ERR("ioctl(SIOCGIFFLAGS) on %s device failed: %s", + netdev->name, strerror(errno)); + return errno; + } + *flags = ifr.ifr_flags; + return 0; +} + +static int +set_flags(struct netdev *netdev, int flags) +{ + struct ifreq ifr; + strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name); + ifr.ifr_flags = flags; + if (ioctl(netdev->fd, SIOCSIFFLAGS, &ifr) < 0) { + VLOG_ERR("ioctl(SIOCSIFFLAGS) on %s device failed: %s", + netdev->name, strerror(errno)); + return errno; + } + return 0; +} diff --git a/switch/datapath.c b/switch/datapath.c index b83ac483..5a0e14c4 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -226,6 +226,12 @@ dp_add_port(struct datapath *dp, const char *name) if (error) { return error; } + error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC); + if (error) { + VLOG_ERR("Couldn't set promiscuous mode on %s device", name); + netdev_close(netdev); + return error; + } if (netdev_get_in4(netdev, &in4)) { VLOG_ERR("%s device has assigned IP address %s", name, inet_ntoa(in4)); }