For SNAT, don't store the pre-fragment L2 header before actions are applied.
[sliver-openvswitch.git] / lib / netdev.c
index 92c1a34..9a91e2f 100644 (file)
 #include "fatal-signal.h"
 #include "list.h"
 #include "ofpbuf.h"
-#include "openflow.h"
+#include "openflow/openflow.h"
 #include "packets.h"
 #include "poll-loop.h"
 #include "socket-util.h"
+#include "svec.h"
 
 #define THIS_MODULE VLM_netdev
 #include "vlog.h"
@@ -86,6 +87,7 @@ struct netdev {
     int speed;
     int mtu;
     int txqlen;
+    int hwaddr_family;
 
     /* Bitmaps of OFPPF_* that describe features.  All bits disabled if
      * unsupported or unavailable. */
@@ -144,6 +146,7 @@ get_ipv6_address(const char *name, struct in6_addr *in6)
                    ifname) == 17
             && !strcmp(name, ifname))
         {
+            fclose(file);
             return;
         }
     }
@@ -354,6 +357,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd,
     struct in6_addr in6;
     int mtu;
     int txqlen;
+    int hwaddr_family;
     int error;
     struct netdev *netdev;
 
@@ -411,10 +415,10 @@ do_open_netdev(const char *name, int ethertype, int tap_fd,
                  name, strerror(errno));
         goto error;
     }
-    if (ifr.ifr_hwaddr.sa_family != AF_UNSPEC
-        && ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+    hwaddr_family = ifr.ifr_hwaddr.sa_family;
+    if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
         VLOG_WARN("%s device has unknown hardware address family %d",
-                  name, (int) ifr.ifr_hwaddr.sa_family);
+                  name, hwaddr_family);
     }
     memcpy(etheraddr, ifr.ifr_hwaddr.sa_data, sizeof etheraddr);
 
@@ -441,6 +445,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd,
     netdev->name = xstrdup(name);
     netdev->ifindex = ifindex;
     netdev->txqlen = txqlen;
+    netdev->hwaddr_family = hwaddr_family;
     netdev->netdev_fd = netdev_fd;
     netdev->tap_fd = tap_fd < 0 ? netdev_fd : tap_fd;
     memcpy(netdev->etheraddr, etheraddr, sizeof etheraddr);
@@ -507,8 +512,7 @@ static void
 pad_to_minimum_length(struct ofpbuf *buffer)
 {
     if (buffer->size < ETH_TOTAL_MIN) {
-        size_t shortage = ETH_TOTAL_MIN - buffer->size;
-        memset(ofpbuf_put_uninit(buffer, shortage), 0, shortage);
+        ofpbuf_put_zeros(buffer, ETH_TOTAL_MIN - buffer->size);
     }
 }
 
@@ -631,6 +635,26 @@ netdev_send_wait(struct netdev *netdev)
     }
 }
 
+/* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
+ * otherwise a positive errno value. */
+int
+netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
+{
+    struct ifreq ifr;
+
+    memset(&ifr, 0, sizeof ifr);
+    strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
+    ifr.ifr_hwaddr.sa_family = netdev->hwaddr_family;
+    memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN);
+    if (ioctl(netdev->netdev_fd, SIOCSIFHWADDR, &ifr) < 0) {
+        VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s",
+                 netdev->name, strerror(errno));
+        return errno;
+    }
+    memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
+    return 0;
+}
+
 /* Returns a pointer to 'netdev''s MAC address.  The caller must not modify or
  * free the returned buffer. */
 const uint8_t *
@@ -925,6 +949,27 @@ netdev_arp_lookup(const struct netdev *netdev,
     }
     return retval;
 }
+
+/* Initializes 'svec' with a list of the names of all known network devices. */
+void
+netdev_enumerate(struct svec *svec)
+{
+    struct if_nameindex *names;
+
+    svec_init(svec);
+    names = if_nameindex();
+    if (names) {
+        size_t i;
+
+        for (i = 0; names[i].if_name != NULL; i++) {
+            svec_add(svec, names[i].if_name);
+        }
+        if_freenameindex(names);
+    } else {
+        VLOG_WARN("could not obtain list of network device names: %s",
+                  strerror(errno));
+    }
+}
 \f
 static void restore_all_flags(void *aux);