lib/netdev-dpdk: increase ring name length for dpdkr ports
[cascardo/ovs.git] / lib / netdev-windows.c
index 0518156..093175f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 VMware, Inc.
+ * Copyright (c) 2014, 2016 VMware, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <config.h>
 #include <errno.h>
+#include <iphlpapi.h>
 
 #include <net/if.h>
 
 #include "fatal-signal.h"
 #include "netdev-provider.h"
 #include "ofpbuf.h"
+#include "packets.h"
 #include "poll-loop.h"
 #include "shash.h"
 #include "svec.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 #include "odp-netlink.h"
 #include "netlink-socket.h"
 #include "netlink.h"
@@ -51,7 +53,7 @@ struct netdev_windows {
 
     unsigned int cache_valid;
     int ifindex;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     uint32_t mtu;
     unsigned int ifi_flags;
 };
@@ -68,20 +70,20 @@ struct netdev_windows_netdev_info {
 
     /* General information of a network device. */
     const char *name;
-    uint8_t mac_address[ETH_ADDR_LEN];
+    struct eth_addr mac_address;
     uint32_t mtu;
     uint32_t ifi_flags;
 };
 
-static int refresh_port_status(struct netdev_windows *netdev);
 static int query_netdev(const char *devname,
                         struct netdev_windows_netdev_info *reply,
                         struct ofpbuf **bufp);
-static int netdev_windows_init(void);
+static struct netdev *netdev_windows_alloc(void);
+static int netdev_windows_init_(void);
 
 /* Generic Netlink family numbers for OVS.
  *
- * Initialized by netdev_windows_init(). */
+ * Initialized by netdev_windows_init_(). */
 static int ovs_win_netdev_family;
 struct nl_sock *ovs_win_netdev_sock;
 
@@ -89,7 +91,7 @@ struct nl_sock *ovs_win_netdev_sock;
 static bool
 is_netdev_windows_class(const struct netdev_class *netdev_class)
 {
-    return netdev_class->init == netdev_windows_init;
+    return netdev_class->alloc == netdev_windows_alloc;
 }
 
 static struct netdev_windows *
@@ -100,7 +102,7 @@ netdev_windows_cast(const struct netdev *netdev_)
 }
 
 static int
-netdev_windows_init(void)
+netdev_windows_init_(void)
 {
     int error = 0;
     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
@@ -131,11 +133,26 @@ netdev_windows_alloc(void)
     return netdev ? &netdev->up : NULL;
 }
 
+static uint32_t
+dp_to_netdev_ifi_flags(uint32_t dp_flags)
+{
+    uint32_t nd_flags = 0;
+
+    if (dp_flags && OVS_WIN_NETDEV_IFF_UP) {
+        nd_flags |= NETDEV_UP;
+    }
+
+    if (dp_flags && OVS_WIN_NETDEV_IFF_PROMISC) {
+        nd_flags |= NETDEV_PROMISC;
+    }
+
+    return nd_flags;
+}
+
 static int
 netdev_windows_system_construct(struct netdev *netdev_)
 {
     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
-    uint8_t mac[ETH_ADDR_LEN];
     struct netdev_windows_netdev_info info;
     struct ofpbuf *buf;
     int ret;
@@ -151,14 +168,14 @@ netdev_windows_system_construct(struct netdev *netdev_)
     netdev->dev_type = info.ovs_type;
     netdev->port_no = info.port_no;
 
-    memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
+    netdev->mac = info.mac_address;
     netdev->cache_valid = VALID_ETHERADDR;
     netdev->ifindex = -EOPNOTSUPP;
 
     netdev->mtu = info.mtu;
     netdev->cache_valid |= VALID_MTU;
 
-    netdev->ifi_flags = info.ifi_flags;
+    netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags);
     netdev->cache_valid |= VALID_IFFLAG;
 
     VLOG_DBG("construct device %s, ovs_type: %u.",
@@ -207,18 +224,14 @@ netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
         [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
     };
 
-    struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
-    struct ovs_header *ovs_header;
-    struct nlmsghdr *nlmsg;
-    struct genlmsghdr *genl;
-    struct ofpbuf b;
-
     netdev_windows_info_init(info);
 
-    ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
-    nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
-    genl = ofpbuf_try_pull(&b, sizeof *genl);
-    ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
+    struct ofpbuf b = ofpbuf_const_initializer(&b, buf->data, buf->size);
+    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
+    struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
+    struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
+
+    struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
     if (!nlmsg || !genl || !ovs_header
         || nlmsg->nlmsg_type != ovs_win_netdev_family
         || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
@@ -231,8 +244,8 @@ netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
     info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);
     info->ovs_type = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_TYPE]);
     info->name = nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]);
-    memcpy(info->mac_address, nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]),
-           sizeof(info->mac_address));
+    memcpy(&info->mac_address, nl_attr_get_unspec(a[OVS_WIN_NETDEV_ATTR_MAC_ADDR],
+               sizeof(info->mac_address)), sizeof(info->mac_address));
     info->mtu = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_MTU]);
     info->ifi_flags = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_IF_FLAGS]);
 
@@ -250,7 +263,7 @@ query_netdev(const char *devname,
     ovs_assert(info != NULL);
     netdev_windows_info_init(info);
 
-    error = netdev_windows_init();
+    error = netdev_windows_init_();
     if (error) {
         if (info) {
             *bufp = NULL;
@@ -299,13 +312,14 @@ netdev_windows_dealloc(struct netdev *netdev_)
 }
 
 static int
-netdev_windows_get_etheraddr(const struct netdev *netdev_, uint8_t mac[6])
+netdev_windows_get_etheraddr(const struct netdev *netdev_,
+                             struct eth_addr *mac)
 {
     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
 
     ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
     if (netdev->cache_valid & VALID_ETHERADDR) {
-        memcpy(mac, netdev->mac, ETH_ADDR_LEN);
+        *mac = netdev->mac;
     } else {
         return EINVAL;
     }
@@ -325,7 +339,146 @@ netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
     }
     return 0;
 }
-\f
+
+/* This functionality is not really required by the datapath.
+ * But vswitchd bringup expects this to be implemented. */
+static int
+netdev_windows_set_etheraddr(const struct netdev *netdev_,
+                             const struct eth_addr mac)
+{
+    return 0;
+}
+
+/* This functionality is not really required by the datapath.
+ * But vswitchd bringup expects this to be implemented. */
+static int
+netdev_windows_update_flags(struct netdev *netdev_,
+                            enum netdev_flags off,
+                            enum netdev_flags on,
+                            enum netdev_flags *old_flagsp)
+{
+    struct netdev_windows *netdev = netdev_windows_cast(netdev_);
+
+    ovs_assert((netdev->cache_valid & VALID_IFFLAG) != 0);
+    if (netdev->cache_valid & VALID_IFFLAG) {
+        *old_flagsp = netdev->ifi_flags;
+        /* Setting the interface flags is not supported. */
+    } else {
+        return EINVAL;
+    }
+    return 0;
+}
+
+/* Looks up in the ARP table entry for a given 'ip'. If it is found, the
+ * corresponding MAC address will be copied in 'mac' and return 0. If no
+ * matching entry is found or an error occurs it will log it and return ENXIO.
+ */
+static int
+netdev_windows_arp_lookup(const struct netdev *netdev,
+                          ovs_be32 ip, struct eth_addr *mac)
+{
+    PMIB_IPNETTABLE arp_table = NULL;
+    /* The buffer length of all ARP entries */
+    uint32_t buffer_length = 0;
+    uint32_t ret_val = 0;
+    uint32_t counter = 0;
+
+    ret_val = GetIpNetTable(arp_table, &buffer_length, false);
+
+    if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
+        VLOG_ERR("Call to GetIpNetTable failed with error: %s",
+                 ovs_format_message(ret_val));
+        return ENXIO;
+    }
+
+    arp_table = (MIB_IPNETTABLE *) malloc(buffer_length);
+
+    if (arp_table == NULL) {
+        VLOG_ERR("Could not allocate memory for all the interfaces");
+        return ENXIO;
+    }
+
+    ret_val = GetIpNetTable(arp_table, &buffer_length, false);
+
+    if (ret_val == NO_ERROR) {
+        for (counter = 0; counter < arp_table->dwNumEntries; counter++) {
+            if (arp_table->table[counter].dwAddr == ip) {
+                memcpy(mac, arp_table->table[counter].bPhysAddr, ETH_ADDR_LEN);
+
+                free(arp_table);
+                return 0;
+            }
+        }
+    } else {
+        VLOG_ERR("Call to GetIpNetTable failed with error: %s",
+                 ovs_format_message(ret_val));
+    }
+
+    free(arp_table);
+    return ENXIO;
+}
+
+static int
+netdev_windows_get_next_hop(const struct in_addr *host,
+                            struct in_addr *next_hop,
+                            char **netdev_name)
+{
+    uint32_t ret_val = 0;
+    /* The buffer length of all addresses */
+    uint32_t buffer_length = 1000;
+    PIP_ADAPTER_ADDRESSES all_addr = NULL;
+    PIP_ADAPTER_ADDRESSES cur_addr = NULL;
+
+    ret_val = GetAdaptersAddresses(AF_INET,
+                                   GAA_FLAG_INCLUDE_PREFIX |
+                                   GAA_FLAG_INCLUDE_GATEWAYS,
+                                   NULL, all_addr, &buffer_length);
+
+    if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
+        VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
+                 ovs_format_message(ret_val));
+        return ENXIO;
+    }
+
+    all_addr = (IP_ADAPTER_ADDRESSES *) malloc(buffer_length);
+
+    if (all_addr == NULL) {
+        VLOG_ERR("Could not allocate memory for all the interfaces");
+        return ENXIO;
+    }
+
+    ret_val = GetAdaptersAddresses(AF_INET,
+                                   GAA_FLAG_INCLUDE_PREFIX |
+                                   GAA_FLAG_INCLUDE_GATEWAYS,
+                                   NULL, all_addr, &buffer_length);
+
+    if (ret_val == NO_ERROR) {
+        cur_addr = all_addr;
+        while (cur_addr) {
+            if(cur_addr->FirstGatewayAddress &&
+               cur_addr->FirstGatewayAddress->Address.lpSockaddr) {
+                struct sockaddr_in *ipv4 = (struct sockaddr_in *)
+                                           cur_addr->FirstGatewayAddress->Address.lpSockaddr;
+                next_hop->s_addr = ipv4->sin_addr.S_un.S_addr;
+                *netdev_name = xstrdup((char *)cur_addr->FriendlyName);
+
+                free(all_addr);
+
+                return 0;
+            }
+
+            cur_addr = cur_addr->Next;
+        }
+    } else {
+        VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
+                 ovs_format_message(ret_val));
+    }
+
+    if (all_addr) {
+        free(all_addr);
+    }
+    return ENXIO;
+}
 
 static int
 netdev_windows_internal_construct(struct netdev *netdev_)
@@ -337,12 +490,15 @@ netdev_windows_internal_construct(struct netdev *netdev_)
 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT)                           \
 {                                                                       \
     .type               = NAME,                                         \
-    .init               = netdev_windows_init,                          \
     .alloc              = netdev_windows_alloc,                         \
     .construct          = CONSTRUCT,                                    \
     .destruct           = netdev_windows_destruct,                      \
     .dealloc            = netdev_windows_dealloc,                       \
     .get_etheraddr      = netdev_windows_get_etheraddr,                 \
+    .set_etheraddr      = netdev_windows_set_etheraddr,                 \
+    .update_flags       = netdev_windows_update_flags,                  \
+    .get_next_hop       = netdev_windows_get_next_hop,                  \
+    .arp_lookup         = netdev_windows_arp_lookup,                    \
 }
 
 const struct netdev_class netdev_windows_class =