int
netdev_open(const char *name, int ethertype, struct netdev **netdevp)
{
- if (!strncmp(name, "tap:", 4)) {
- return netdev_open_tap(name + 4, netdevp);
- } else {
+ if (strncmp(name, "tap:", 4)) {
return do_open_netdev(name, ethertype, -1, netdevp);
- }
-}
+ } else {
+ static const char tap_dev[] = "/dev/net/tun";
+ struct ifreq ifr;
+ int error;
+ int tap_fd;
-/* Opens a TAP virtual network device. If 'name' is a nonnull, non-empty
- * string, attempts to assign that name to the TAP device (failing if the name
- * is already in use); otherwise, a name is automatically assigned. Returns
- * zero if successful, otherwise a positive errno value. On success, sets
- * '*netdevp' to the new network device, otherwise to null. */
-int
-netdev_open_tap(const char *name, struct netdev **netdevp)
-{
- static const char tap_dev[] = "/dev/net/tun";
- struct ifreq ifr;
- int error;
- int tap_fd;
+ tap_fd = open(tap_dev, O_RDWR);
+ if (tap_fd < 0) {
+ ovs_error(errno, "opening \"%s\" failed", tap_dev);
+ return errno;
+ }
- tap_fd = open(tap_dev, O_RDWR);
- if (tap_fd < 0) {
- ovs_error(errno, "opening \"%s\" failed", tap_dev);
- return errno;
- }
+ memset(&ifr, 0, sizeof ifr);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (name) {
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ }
+ if (ioctl(tap_fd, TUNSETIFF, &ifr) < 0) {
+ int error = errno;
+ ovs_error(error, "ioctl(TUNSETIFF) on \"%s\" failed", tap_dev);
+ close(tap_fd);
+ return error;
+ }
- memset(&ifr, 0, sizeof ifr);
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- if (name) {
- strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
- }
- if (ioctl(tap_fd, TUNSETIFF, &ifr) < 0) {
- int error = errno;
- ovs_error(error, "ioctl(TUNSETIFF) on \"%s\" failed", tap_dev);
- close(tap_fd);
- return error;
- }
+ error = set_nonblocking(tap_fd);
+ if (error) {
+ ovs_error(error, "set_nonblocking on \"%s\" failed", tap_dev);
+ close(tap_fd);
+ return error;
+ }
- error = set_nonblocking(tap_fd);
- if (error) {
- ovs_error(error, "set_nonblocking on \"%s\" failed", tap_dev);
- close(tap_fd);
+ error = do_open_netdev(ifr.ifr_name, NETDEV_ETH_TYPE_NONE, tap_fd,
+ netdevp);
+ if (error) {
+ close(tap_fd);
+ }
return error;
}
-
- error = do_open_netdev(ifr.ifr_name, NETDEV_ETH_TYPE_NONE, tap_fd,
- netdevp);
- if (error) {
- close(tap_fd);
- }
- return error;
}
+
static int
do_open_netdev(const char *name, int ethertype, int tap_fd,
struct netdev **netdev_)
}
}
+/* Checks whether a network device named 'name' exists and returns true if so,
+ * false otherwise. */
+bool
+netdev_exists(const char *name)
+{
+ struct stat s;
+ char *filename;
+ int error;
+
+ filename = xasprintf("/sys/class/net/%s", name);
+ error = stat(filename, &s);
+ free(filename);
+ return !error;
+}
+
/* Pads 'buffer' out with zero-bytes to the minimum valid length of an
* Ethernet packet, if necessary. */
static void
return set_etheraddr(name, ARPHRD_ETHER, mac);
}
-/* Returns a pointer to 'netdev''s MAC address. The caller must not modify or
- * free the returned buffer. */
-const uint8_t *
-netdev_get_etheraddr(const struct netdev *netdev)
+/* Retrieves 'netdev''s MAC address. If successful, returns 0 and copies the
+ * the MAC address into 'mac'. On failure, returns a positive errno value and
+ * clears 'mac' to all-zeros. */
+int
+netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN])
{
- return netdev->etheraddr;
+ memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+ return 0;
}
/* Returns the name of the network device that 'netdev' represents,
return netdev->name;
}
-/* Returns the maximum size of transmitted (and received) packets on 'netdev',
- * in bytes, not including the hardware header; thus, this is typically 1500
- * bytes for Ethernet devices. */
+/* Retrieves the MTU of 'netdev'. The MTU is the maximum size of transmitted
+ * (and received) packets, in bytes, not including the hardware header; thus,
+ * this is typically 1500 bytes for Ethernet devices.
+ *
+ * If successful, returns 0 and stores the MTU size in '*mtup'. On failure,
+ * returns a positive errno value and stores ETH_PAYLOAD_MAX (1500) in
+ * '*mtup'. */
int
-netdev_get_mtu(const struct netdev *netdev)
+netdev_get_mtu(const struct netdev *netdev, int *mtup)
{
- return netdev->mtu;
+ *mtup = netdev->mtu;
+ return 0;
}
/* Stores the features supported by 'netdev' into each of '*current',
}
/* If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if
- * 'in4' is non-null) and returns true. Otherwise, returns false. */
-bool
+ * 'in4' is non-null) and returns 0. Otherwise, returns a positive errno value
+ * and sets '*in4' to INADDR_ANY (0). */
+int
netdev_nodev_get_in4(const char *netdev_name, struct in_addr *in4)
{
struct ifreq ifr;
struct in_addr ip = { INADDR_ANY };
+ int error;
init_netdev();
if (ioctl(af_inet_sock, SIOCGIFADDR, &ifr) == 0) {
struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
ip = sin->sin_addr;
+ error = ip.s_addr != INADDR_ANY ? 0 : EADDRNOTAVAIL;
} else {
VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFADDR) failed: %s",
netdev_name, strerror(errno));
+ error = errno;
}
if (in4) {
*in4 = ip;
}
- return ip.s_addr != INADDR_ANY;
+ return error;
}
-bool
+int
netdev_get_in4(const struct netdev *netdev, struct in_addr *in4)
{
return netdev_nodev_get_in4(netdev->name, in4);
return error;
}
-/* Adds 'router' as a default IP gateway. */
+/* Adds 'router' as a default IP gateway for the TCP/IP stack that corresponds
+ * to 'netdev'. */
int
-netdev_add_router(struct in_addr router)
+netdev_add_router(struct netdev *netdev UNUSED, struct in_addr router)
{
struct in_addr any = { INADDR_ANY };
struct rtentry rt;
struct svec dev_list;
/* Check the hint first. */
- if (*netdev_name && (netdev_nodev_get_in4(*netdev_name, &dev_in4))
+ if (*netdev_name && !netdev_nodev_get_in4(*netdev_name, &dev_in4)
&& (dev_in4.s_addr == in4->s_addr)) {
return true;
}
netdev_enumerate(&dev_list);
for (i=0; i<dev_list.n; i++) {
- if ((netdev_nodev_get_in4(dev_list.names[i], &dev_in4))
+ if (!netdev_nodev_get_in4(dev_list.names[i], &dev_in4)
&& (dev_in4.s_addr == in4->s_addr)) {
*netdev_name = xstrdup(dev_list.names[i]);
svec_destroy(&dev_list);