datapath-windows: Update VXLAN header information
[cascardo/ovs.git] / lib / netdev-windows.c
1 /*
2  * Copyright (c) 2014 VMware, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
18 #include <config.h>
19 #include <errno.h>
20 #include <iphlpapi.h>
21
22 #include <net/if.h>
23
24 #include "coverage.h"
25 #include "fatal-signal.h"
26 #include "netdev-provider.h"
27 #include "ofpbuf.h"
28 #include "packets.h"
29 #include "poll-loop.h"
30 #include "shash.h"
31 #include "svec.h"
32 #include "openvswitch/vlog.h"
33 #include "odp-netlink.h"
34 #include "netlink-socket.h"
35 #include "netlink.h"
36
37 VLOG_DEFINE_THIS_MODULE(netdev_windows);
38 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
39
40 enum {
41     VALID_ETHERADDR         = 1 << 0,
42     VALID_MTU               = 1 << 1,
43     VALID_IFFLAG            = 1 << 5,
44 };
45
46 /* Caches the information of a netdev. */
47 struct netdev_windows {
48     struct netdev up;
49     int32_t dev_type;
50     uint32_t port_no;
51
52     unsigned int change_seq;
53
54     unsigned int cache_valid;
55     int ifindex;
56     uint8_t mac[ETH_ADDR_LEN];
57     uint32_t mtu;
58     unsigned int ifi_flags;
59 };
60
61 /* Utility structure for netdev commands. */
62 struct netdev_windows_netdev_info {
63     /* Generic Netlink header. */
64     uint8_t cmd;
65
66     /* Information that is relevant to ovs. */
67     uint32_t dp_ifindex;
68     uint32_t port_no;
69     uint32_t ovs_type;
70
71     /* General information of a network device. */
72     const char *name;
73     uint8_t mac_address[ETH_ADDR_LEN];
74     uint32_t mtu;
75     uint32_t ifi_flags;
76 };
77
78 static int query_netdev(const char *devname,
79                         struct netdev_windows_netdev_info *reply,
80                         struct ofpbuf **bufp);
81 static struct netdev *netdev_windows_alloc(void);
82 static int netdev_windows_init_(void);
83
84 /* Generic Netlink family numbers for OVS.
85  *
86  * Initialized by netdev_windows_init_(). */
87 static int ovs_win_netdev_family;
88 struct nl_sock *ovs_win_netdev_sock;
89
90
91 static bool
92 is_netdev_windows_class(const struct netdev_class *netdev_class)
93 {
94     return netdev_class->alloc == netdev_windows_alloc;
95 }
96
97 static struct netdev_windows *
98 netdev_windows_cast(const struct netdev *netdev_)
99 {
100     ovs_assert(is_netdev_windows_class(netdev_get_class(netdev_)));
101     return CONTAINER_OF(netdev_, struct netdev_windows, up);
102 }
103
104 static int
105 netdev_windows_init_(void)
106 {
107     int error = 0;
108     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
109
110     if (ovsthread_once_start(&once)) {
111         error = nl_lookup_genl_family(OVS_WIN_NETDEV_FAMILY,
112                                       &ovs_win_netdev_family);
113         if (error) {
114             VLOG_ERR("Generic Netlink family '%s' does not exist. "
115                      "The Open vSwitch kernel module is probably not loaded.",
116                      OVS_WIN_NETDEV_FAMILY);
117         }
118         if (!error) {
119             /* XXX: Where to close this socket? */
120             error = nl_sock_create(NETLINK_GENERIC, &ovs_win_netdev_sock);
121         }
122
123         ovsthread_once_done(&once);
124     }
125
126     return error;
127 }
128
129 static struct netdev *
130 netdev_windows_alloc(void)
131 {
132     struct netdev_windows *netdev = xzalloc(sizeof *netdev);
133     return netdev ? &netdev->up : NULL;
134 }
135
136 static uint32_t
137 dp_to_netdev_ifi_flags(uint32_t dp_flags)
138 {
139     uint32_t nd_flags = 0;
140
141     if (dp_flags && OVS_WIN_NETDEV_IFF_UP) {
142         nd_flags |= NETDEV_UP;
143     }
144
145     if (dp_flags && OVS_WIN_NETDEV_IFF_PROMISC) {
146         nd_flags |= NETDEV_PROMISC;
147     }
148
149     return nd_flags;
150 }
151
152 static int
153 netdev_windows_system_construct(struct netdev *netdev_)
154 {
155     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
156     uint8_t mac[ETH_ADDR_LEN];
157     struct netdev_windows_netdev_info info;
158     struct ofpbuf *buf;
159     int ret;
160
161     /* Query the attributes and runtime status of the netdev. */
162     ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
163     if (ret) {
164         return ret;
165     }
166     ofpbuf_delete(buf);
167
168     netdev->change_seq = 1;
169     netdev->dev_type = info.ovs_type;
170     netdev->port_no = info.port_no;
171
172     memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
173     netdev->cache_valid = VALID_ETHERADDR;
174     netdev->ifindex = -EOPNOTSUPP;
175
176     netdev->mtu = info.mtu;
177     netdev->cache_valid |= VALID_MTU;
178
179     netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags);
180     netdev->cache_valid |= VALID_IFFLAG;
181
182     VLOG_DBG("construct device %s, ovs_type: %u.",
183              netdev_get_name(&netdev->up), info.ovs_type);
184     return 0;
185 }
186
187 static int
188 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
189                                 struct ofpbuf *buf)
190 {
191     struct ovs_header *ovs_header;
192     int error = EINVAL;
193
194     nl_msg_put_genlmsghdr(buf, 0, ovs_win_netdev_family,
195                           NLM_F_REQUEST | NLM_F_ECHO,
196                           info->cmd, OVS_WIN_NETDEV_VERSION);
197
198     ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
199     ovs_header->dp_ifindex = info->dp_ifindex;
200
201     if (info->name) {
202         nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
203         error = 0;
204     }
205
206     return error;
207 }
208
209 static void
210 netdev_windows_info_init(struct netdev_windows_netdev_info *info)
211 {
212     memset(info, 0, sizeof *info);
213 }
214
215 static int
216 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
217                                   struct ofpbuf *buf)
218 {
219     static const struct nl_policy ovs_netdev_policy[] = {
220         [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 },
221         [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 },
222         [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
223         [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) },
224         [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 },
225         [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
226     };
227
228     struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
229     struct ovs_header *ovs_header;
230     struct nlmsghdr *nlmsg;
231     struct genlmsghdr *genl;
232     struct ofpbuf b;
233
234     netdev_windows_info_init(info);
235
236     ofpbuf_use_const(&b, buf->data, buf->size);
237     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
238     genl = ofpbuf_try_pull(&b, sizeof *genl);
239     ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
240     if (!nlmsg || !genl || !ovs_header
241         || nlmsg->nlmsg_type != ovs_win_netdev_family
242         || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
243                             ARRAY_SIZE(ovs_netdev_policy))) {
244         return EINVAL;
245     }
246
247     info->cmd = genl->cmd;
248     info->dp_ifindex = ovs_header->dp_ifindex;
249     info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);
250     info->ovs_type = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_TYPE]);
251     info->name = nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]);
252     memcpy(info->mac_address, nl_attr_get_unspec(a[OVS_WIN_NETDEV_ATTR_MAC_ADDR],
253                sizeof(info->mac_address)), sizeof(info->mac_address));
254     info->mtu = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_MTU]);
255     info->ifi_flags = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_IF_FLAGS]);
256
257     return 0;
258 }
259
260 static int
261 query_netdev(const char *devname,
262              struct netdev_windows_netdev_info *info,
263              struct ofpbuf **bufp)
264 {
265     int error = 0;
266     struct ofpbuf *request_buf;
267
268     ovs_assert(info != NULL);
269     netdev_windows_info_init(info);
270
271     error = netdev_windows_init_();
272     if (error) {
273         if (info) {
274             *bufp = NULL;
275             netdev_windows_info_init(info);
276         }
277         return error;
278     }
279
280     request_buf = ofpbuf_new(1024);
281     info->cmd = OVS_WIN_NETDEV_CMD_GET;
282     info->name = devname;
283     error = netdev_windows_netdev_to_ofpbuf(info, request_buf);
284     if (error) {
285         ofpbuf_delete(request_buf);
286         return error;
287     }
288
289     error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
290     ofpbuf_delete(request_buf);
291
292     if (info) {
293         if (!error) {
294             error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
295         }
296         if (error) {
297             netdev_windows_info_init(info);
298             ofpbuf_delete(*bufp);
299             *bufp = NULL;
300         }
301     }
302
303     return 0;
304 }
305
306 static void
307 netdev_windows_destruct(struct netdev *netdev_)
308 {
309
310 }
311
312 static void
313 netdev_windows_dealloc(struct netdev *netdev_)
314 {
315     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
316     free(netdev);
317 }
318
319 static int
320 netdev_windows_get_etheraddr(const struct netdev *netdev_,
321                              uint8_t mac[ETH_ADDR_LEN])
322 {
323     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
324
325     ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
326     if (netdev->cache_valid & VALID_ETHERADDR) {
327         memcpy(mac, netdev->mac, ETH_ADDR_LEN);
328     } else {
329         return EINVAL;
330     }
331     return 0;
332 }
333
334 static int
335 netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
336 {
337     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
338
339     ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
340     if (netdev->cache_valid & VALID_MTU) {
341         *mtup = netdev->mtu;
342     } else {
343         return EINVAL;
344     }
345     return 0;
346 }
347
348 /* This functionality is not really required by the datapath.
349  * But vswitchd bringup expects this to be implemented. */
350 static int
351 netdev_windows_set_etheraddr(const struct netdev *netdev_,
352                              uint8_t mac[ETH_ADDR_LEN])
353 {
354     return 0;
355 }
356
357 /* This functionality is not really required by the datapath.
358  * But vswitchd bringup expects this to be implemented. */
359 static int
360 netdev_windows_update_flags(struct netdev *netdev_,
361                             enum netdev_flags off,
362                             enum netdev_flags on,
363                             enum netdev_flags *old_flagsp)
364 {
365     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
366
367     ovs_assert((netdev->cache_valid & VALID_IFFLAG) != 0);
368     if (netdev->cache_valid & VALID_IFFLAG) {
369         *old_flagsp = netdev->ifi_flags;
370         /* Setting the interface flags is not supported. */
371     } else {
372         return EINVAL;
373     }
374     return 0;
375 }
376
377 /* Looks up in the ARP table entry for a given 'ip'. If it is found, the
378  * corresponding MAC address will be copied in 'mac' and return 0. If no
379  * matching entry is found or an error occurs it will log it and return ENXIO.
380  */
381 static int
382 netdev_windows_arp_lookup(const struct netdev *netdev,
383                           ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
384 {
385     PMIB_IPNETTABLE arp_table = NULL;
386     /* The buffer length of all ARP entries */
387     uint32_t buffer_length = 0;
388     uint32_t ret_val = 0;
389     uint32_t counter = 0;
390
391     ret_val = GetIpNetTable(arp_table, &buffer_length, false);
392
393     if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
394         VLOG_ERR("Call to GetIpNetTable failed with error: %s",
395                  ovs_format_message(ret_val));
396         return ENXIO;
397     }
398
399     arp_table = (MIB_IPNETTABLE *) malloc(buffer_length);
400
401     if (arp_table == NULL) {
402         VLOG_ERR("Could not allocate memory for all the interfaces");
403         return ENXIO;
404     }
405
406     ret_val = GetIpNetTable(arp_table, &buffer_length, false);
407
408     if (ret_val == NO_ERROR) {
409         for (counter = 0; counter < arp_table->dwNumEntries; counter++) {
410             if (arp_table->table[counter].dwAddr == ip) {
411                 memcpy(mac, arp_table->table[counter].bPhysAddr, ETH_ADDR_LEN);
412
413                 free(arp_table);
414                 return 0;
415             }
416         }
417     } else {
418         VLOG_ERR("Call to GetIpNetTable failed with error: %s",
419                  ovs_format_message(ret_val));
420     }
421
422     free(arp_table);
423     return ENXIO;
424 }
425
426 static int
427 netdev_windows_get_next_hop(const struct in_addr *host,
428                             struct in_addr *next_hop,
429                             char **netdev_name)
430 {
431     uint32_t ret_val = 0;
432     /* The buffer length of all addresses */
433     uint32_t buffer_length = 1000;
434     PIP_ADAPTER_ADDRESSES all_addr = NULL;
435     PIP_ADAPTER_ADDRESSES cur_addr = NULL;
436
437     ret_val = GetAdaptersAddresses(AF_INET,
438                                    GAA_FLAG_INCLUDE_PREFIX |
439                                    GAA_FLAG_INCLUDE_GATEWAYS,
440                                    NULL, all_addr, &buffer_length);
441
442     if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
443         VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
444                  ovs_format_message(ret_val));
445         return ENXIO;
446     }
447
448     all_addr = (IP_ADAPTER_ADDRESSES *) malloc(buffer_length);
449
450     if (all_addr == NULL) {
451         VLOG_ERR("Could not allocate memory for all the interfaces");
452         return ENXIO;
453     }
454
455     ret_val = GetAdaptersAddresses(AF_INET,
456                                    GAA_FLAG_INCLUDE_PREFIX |
457                                    GAA_FLAG_INCLUDE_GATEWAYS,
458                                    NULL, all_addr, &buffer_length);
459
460     if (ret_val == NO_ERROR) {
461         cur_addr = all_addr;
462         while (cur_addr) {
463             if(cur_addr->FirstGatewayAddress &&
464                cur_addr->FirstGatewayAddress->Address.lpSockaddr) {
465                 struct sockaddr_in *ipv4 = (struct sockaddr_in *)
466                                            cur_addr->FirstGatewayAddress->Address.lpSockaddr;
467                 next_hop->s_addr = ipv4->sin_addr.S_un.S_addr;
468                 *netdev_name = xstrdup((char *)cur_addr->FriendlyName);
469
470                 free(all_addr);
471
472                 return 0;
473             }
474
475             cur_addr = cur_addr->Next;
476         }
477     } else {
478         VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
479                  ovs_format_message(ret_val));
480     }
481
482     if (all_addr) {
483         free(all_addr);
484     }
485     return ENXIO;
486 }
487
488 static int
489 netdev_windows_internal_construct(struct netdev *netdev_)
490 {
491     return netdev_windows_system_construct(netdev_);
492 }
493
494
495 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT)                           \
496 {                                                                       \
497     .type               = NAME,                                         \
498     .alloc              = netdev_windows_alloc,                         \
499     .construct          = CONSTRUCT,                                    \
500     .destruct           = netdev_windows_destruct,                      \
501     .dealloc            = netdev_windows_dealloc,                       \
502     .get_etheraddr      = netdev_windows_get_etheraddr,                 \
503     .set_etheraddr      = netdev_windows_set_etheraddr,                 \
504     .update_flags       = netdev_windows_update_flags,                  \
505     .get_next_hop       = netdev_windows_get_next_hop,                  \
506     .arp_lookup         = netdev_windows_arp_lookup,                    \
507 }
508
509 const struct netdev_class netdev_windows_class =
510     NETDEV_WINDOWS_CLASS(
511         "system",
512         netdev_windows_system_construct);
513
514 const struct netdev_class netdev_internal_class =
515     NETDEV_WINDOWS_CLASS(
516         "internal",
517         netdev_windows_internal_construct);