]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-windows.c
Revert "dpif-netdev: includes microsecond delta in meter bucket calculation".
[mirror_ovs.git] / lib / netdev-windows.c
CommitLineData
078eedf4 1/*
0a2869d5 2 * Copyright (c) 2014, 2016 VMware, Inc.
078eedf4
NR
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>
694ebbc8 20#include <iphlpapi.h>
078eedf4
NR
21
22#include <net/if.h>
23
24#include "coverage.h"
25#include "fatal-signal.h"
26#include "netdev-provider.h"
64c96779 27#include "openvswitch/ofpbuf.h"
3bd0fd39 28#include "packets.h"
fd016ae3 29#include "openvswitch/poll-loop.h"
ee89ea7b 30#include "openvswitch/shash.h"
078eedf4 31#include "svec.h"
e6211adc 32#include "openvswitch/vlog.h"
078eedf4
NR
33#include "odp-netlink.h"
34#include "netlink-socket.h"
35#include "netlink.h"
36
37VLOG_DEFINE_THIS_MODULE(netdev_windows);
38static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
39
40enum {
41 VALID_ETHERADDR = 1 << 0,
42 VALID_MTU = 1 << 1,
43 VALID_IFFLAG = 1 << 5,
44};
45
46/* Caches the information of a netdev. */
47struct 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;
74ff3298 56 struct eth_addr mac;
078eedf4
NR
57 uint32_t mtu;
58 unsigned int ifi_flags;
59};
60
61/* Utility structure for netdev commands. */
62struct 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;
74ff3298 73 struct eth_addr mac_address;
078eedf4
NR
74 uint32_t mtu;
75 uint32_t ifi_flags;
76};
77
3e648bc5
NR
78static int query_netdev(const char *devname,
79 struct netdev_windows_netdev_info *reply,
80 struct ofpbuf **bufp);
0bfecde1
NR
81static struct netdev *netdev_windows_alloc(void);
82static int netdev_windows_init_(void);
3e648bc5
NR
83
84/* Generic Netlink family numbers for OVS.
85 *
0bfecde1 86 * Initialized by netdev_windows_init_(). */
3e648bc5
NR
87static int ovs_win_netdev_family;
88struct nl_sock *ovs_win_netdev_sock;
89
90
91static bool
92is_netdev_windows_class(const struct netdev_class *netdev_class)
93{
0bfecde1 94 return netdev_class->alloc == netdev_windows_alloc;
3e648bc5
NR
95}
96
97static struct netdev_windows *
98netdev_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
078eedf4 104static int
0bfecde1 105netdev_windows_init_(void)
078eedf4 106{
3e648bc5
NR
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;
078eedf4
NR
127}
128
129static struct netdev *
130netdev_windows_alloc(void)
131{
3e648bc5
NR
132 struct netdev_windows *netdev = xzalloc(sizeof *netdev);
133 return netdev ? &netdev->up : NULL;
078eedf4
NR
134}
135
ee4dac3b
NR
136static uint32_t
137dp_to_netdev_ifi_flags(uint32_t dp_flags)
138{
139 uint32_t nd_flags = 0;
140
fa41c89c 141 if (dp_flags & OVS_WIN_NETDEV_IFF_UP) {
ee4dac3b
NR
142 nd_flags |= NETDEV_UP;
143 }
144
fa41c89c 145 if (dp_flags & OVS_WIN_NETDEV_IFF_PROMISC) {
ee4dac3b
NR
146 nd_flags |= NETDEV_PROMISC;
147 }
148
149 return nd_flags;
150}
151
078eedf4
NR
152static int
153netdev_windows_system_construct(struct netdev *netdev_)
154{
3e648bc5 155 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
3e648bc5
NR
156 struct netdev_windows_netdev_info info;
157 struct ofpbuf *buf;
158 int ret;
159
160 /* Query the attributes and runtime status of the netdev. */
161 ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
fb55a74c
AS
162 /* "Internal" netdevs do not exist in the kernel yet. They need to be
163 * transformed into a netdev object and passed to dpif_port_add(), which
164 * will add them to the kernel. */
165 if (strcmp(netdev_get_type(&netdev->up), "internal") && ret) {
3e648bc5
NR
166 return ret;
167 }
168 ofpbuf_delete(buf);
169
170 netdev->change_seq = 1;
171 netdev->dev_type = info.ovs_type;
172 netdev->port_no = info.port_no;
173
74ff3298 174 netdev->mac = info.mac_address;
3e648bc5
NR
175 netdev->cache_valid = VALID_ETHERADDR;
176 netdev->ifindex = -EOPNOTSUPP;
177
178 netdev->mtu = info.mtu;
179 netdev->cache_valid |= VALID_MTU;
180
ee4dac3b 181 netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags);
3e648bc5
NR
182 netdev->cache_valid |= VALID_IFFLAG;
183
184 VLOG_DBG("construct device %s, ovs_type: %u.",
185 netdev_get_name(&netdev->up), info.ovs_type);
186 return 0;
187}
188
189static int
190netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
191 struct ofpbuf *buf)
192{
193 struct ovs_header *ovs_header;
194 int error = EINVAL;
195
196 nl_msg_put_genlmsghdr(buf, 0, ovs_win_netdev_family,
197 NLM_F_REQUEST | NLM_F_ECHO,
198 info->cmd, OVS_WIN_NETDEV_VERSION);
199
200 ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
201 ovs_header->dp_ifindex = info->dp_ifindex;
202
203 if (info->name) {
204 nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
205 error = 0;
206 }
207
208 return error;
209}
210
211static void
212netdev_windows_info_init(struct netdev_windows_netdev_info *info)
213{
214 memset(info, 0, sizeof *info);
215}
216
217static int
218netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
219 struct ofpbuf *buf)
220{
221 static const struct nl_policy ovs_netdev_policy[] = {
222 [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 },
223 [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 },
224 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
225 [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) },
226 [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 },
227 [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
228 };
229
3e648bc5
NR
230 netdev_windows_info_init(info);
231
583d3467 232 struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
0a2869d5
BP
233 struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
234 struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
235 struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
236
237 struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
3e648bc5
NR
238 if (!nlmsg || !genl || !ovs_header
239 || nlmsg->nlmsg_type != ovs_win_netdev_family
240 || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
241 ARRAY_SIZE(ovs_netdev_policy))) {
242 return EINVAL;
243 }
244
245 info->cmd = genl->cmd;
246 info->dp_ifindex = ovs_header->dp_ifindex;
247 info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);
248 info->ovs_type = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_TYPE]);
249 info->name = nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]);
ef901b35 250 memcpy(&info->mac_address, nl_attr_get_unspec(a[OVS_WIN_NETDEV_ATTR_MAC_ADDR],
ee4dac3b 251 sizeof(info->mac_address)), sizeof(info->mac_address));
3e648bc5
NR
252 info->mtu = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_MTU]);
253 info->ifi_flags = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_IF_FLAGS]);
254
255 return 0;
256}
257
258static int
259query_netdev(const char *devname,
260 struct netdev_windows_netdev_info *info,
261 struct ofpbuf **bufp)
262{
263 int error = 0;
264 struct ofpbuf *request_buf;
265
266 ovs_assert(info != NULL);
267 netdev_windows_info_init(info);
268
0bfecde1 269 error = netdev_windows_init_();
3e648bc5
NR
270 if (error) {
271 if (info) {
272 *bufp = NULL;
273 netdev_windows_info_init(info);
274 }
275 return error;
276 }
277
278 request_buf = ofpbuf_new(1024);
279 info->cmd = OVS_WIN_NETDEV_CMD_GET;
280 info->name = devname;
281 error = netdev_windows_netdev_to_ofpbuf(info, request_buf);
282 if (error) {
283 ofpbuf_delete(request_buf);
284 return error;
285 }
286
287 error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
288 ofpbuf_delete(request_buf);
289
290 if (info) {
291 if (!error) {
292 error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
293 }
294 if (error) {
295 netdev_windows_info_init(info);
296 ofpbuf_delete(*bufp);
297 *bufp = NULL;
298 }
299 }
300
fa07525f 301 return error;
3e648bc5
NR
302}
303
304static void
305netdev_windows_destruct(struct netdev *netdev_)
306{
307
078eedf4
NR
308}
309
310static void
311netdev_windows_dealloc(struct netdev *netdev_)
312{
3e648bc5
NR
313 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
314 free(netdev);
078eedf4
NR
315}
316
317static int
3bd0fd39 318netdev_windows_get_etheraddr(const struct netdev *netdev_,
74ff3298 319 struct eth_addr *mac)
078eedf4 320{
3e648bc5
NR
321 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
322
323 ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
324 if (netdev->cache_valid & VALID_ETHERADDR) {
74ff3298 325 *mac = netdev->mac;
3e648bc5
NR
326 } else {
327 return EINVAL;
328 }
329 return 0;
078eedf4
NR
330}
331
332static int
333netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
334{
3e648bc5
NR
335 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
336
337 ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
338 if (netdev->cache_valid & VALID_MTU) {
339 *mtup = netdev->mtu;
340 } else {
341 return EINVAL;
342 }
343 return 0;
078eedf4 344}
6cac056e
AS
345
346/* This functionality is not really required by the datapath.
347 * But vswitchd bringup expects this to be implemented. */
348static int
3bd0fd39 349netdev_windows_set_etheraddr(const struct netdev *netdev_,
74ff3298 350 const struct eth_addr mac)
6cac056e
AS
351{
352 return 0;
353}
354
6cac056e
AS
355/* This functionality is not really required by the datapath.
356 * But vswitchd bringup expects this to be implemented. */
357static int
ee4dac3b
NR
358netdev_windows_update_flags(struct netdev *netdev_,
359 enum netdev_flags off,
360 enum netdev_flags on,
361 enum netdev_flags *old_flagsp)
6cac056e 362{
ee4dac3b
NR
363 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
364
365 ovs_assert((netdev->cache_valid & VALID_IFFLAG) != 0);
366 if (netdev->cache_valid & VALID_IFFLAG) {
367 *old_flagsp = netdev->ifi_flags;
368 /* Setting the interface flags is not supported. */
369 } else {
370 return EINVAL;
371 }
6cac056e
AS
372 return 0;
373}
374
694ebbc8
AS
375/* Looks up in the ARP table entry for a given 'ip'. If it is found, the
376 * corresponding MAC address will be copied in 'mac' and return 0. If no
377 * matching entry is found or an error occurs it will log it and return ENXIO.
378 */
379static int
380netdev_windows_arp_lookup(const struct netdev *netdev,
74ff3298 381 ovs_be32 ip, struct eth_addr *mac)
694ebbc8
AS
382{
383 PMIB_IPNETTABLE arp_table = NULL;
384 /* The buffer length of all ARP entries */
385 uint32_t buffer_length = 0;
386 uint32_t ret_val = 0;
387 uint32_t counter = 0;
388
389 ret_val = GetIpNetTable(arp_table, &buffer_length, false);
390
391 if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
392 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
393 ovs_format_message(ret_val));
394 return ENXIO;
395 }
396
95c36eb7 397 arp_table = (MIB_IPNETTABLE *) xmalloc(buffer_length);
694ebbc8
AS
398
399 ret_val = GetIpNetTable(arp_table, &buffer_length, false);
400
401 if (ret_val == NO_ERROR) {
402 for (counter = 0; counter < arp_table->dwNumEntries; counter++) {
403 if (arp_table->table[counter].dwAddr == ip) {
404 memcpy(mac, arp_table->table[counter].bPhysAddr, ETH_ADDR_LEN);
405
406 free(arp_table);
407 return 0;
408 }
409 }
410 } else {
411 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
412 ovs_format_message(ret_val));
413 }
414
415 free(arp_table);
416 return ENXIO;
417}
418
419static int
420netdev_windows_get_next_hop(const struct in_addr *host,
421 struct in_addr *next_hop,
422 char **netdev_name)
423{
424 uint32_t ret_val = 0;
425 /* The buffer length of all addresses */
e83cb658 426 uint32_t buffer_length = 0;
694ebbc8
AS
427 PIP_ADAPTER_ADDRESSES all_addr = NULL;
428 PIP_ADAPTER_ADDRESSES cur_addr = NULL;
429
430 ret_val = GetAdaptersAddresses(AF_INET,
431 GAA_FLAG_INCLUDE_PREFIX |
432 GAA_FLAG_INCLUDE_GATEWAYS,
e83cb658 433 NULL, NULL, &buffer_length);
694ebbc8 434
e83cb658 435 if (ret_val != ERROR_BUFFER_OVERFLOW ) {
694ebbc8
AS
436 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
437 ovs_format_message(ret_val));
438 return ENXIO;
439 }
440
95c36eb7 441 all_addr = (IP_ADAPTER_ADDRESSES *) xmalloc(buffer_length);
694ebbc8
AS
442
443 ret_val = GetAdaptersAddresses(AF_INET,
444 GAA_FLAG_INCLUDE_PREFIX |
445 GAA_FLAG_INCLUDE_GATEWAYS,
446 NULL, all_addr, &buffer_length);
447
448 if (ret_val == NO_ERROR) {
449 cur_addr = all_addr;
450 while (cur_addr) {
451 if(cur_addr->FirstGatewayAddress &&
452 cur_addr->FirstGatewayAddress->Address.lpSockaddr) {
453 struct sockaddr_in *ipv4 = (struct sockaddr_in *)
454 cur_addr->FirstGatewayAddress->Address.lpSockaddr;
455 next_hop->s_addr = ipv4->sin_addr.S_un.S_addr;
456 *netdev_name = xstrdup((char *)cur_addr->FriendlyName);
457
458 free(all_addr);
459
460 return 0;
461 }
462
463 cur_addr = cur_addr->Next;
464 }
465 } else {
466 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
467 ovs_format_message(ret_val));
468 }
469
470 if (all_addr) {
471 free(all_addr);
472 }
473 return ENXIO;
474}
475
078eedf4
NR
476static int
477netdev_windows_internal_construct(struct netdev *netdev_)
478{
479 return netdev_windows_system_construct(netdev_);
480}
481
482
483#define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
484{ \
485 .type = NAME, \
118c77b1 486 .is_pmd = false, \
078eedf4
NR
487 .alloc = netdev_windows_alloc, \
488 .construct = CONSTRUCT, \
3e648bc5 489 .destruct = netdev_windows_destruct, \
078eedf4
NR
490 .dealloc = netdev_windows_dealloc, \
491 .get_etheraddr = netdev_windows_get_etheraddr, \
6cac056e 492 .set_etheraddr = netdev_windows_set_etheraddr, \
ee4dac3b 493 .update_flags = netdev_windows_update_flags, \
694ebbc8
AS
494 .get_next_hop = netdev_windows_get_next_hop, \
495 .arp_lookup = netdev_windows_arp_lookup, \
078eedf4
NR
496}
497
498const struct netdev_class netdev_windows_class =
499 NETDEV_WINDOWS_CLASS(
500 "system",
501 netdev_windows_system_construct);
502
503const struct netdev_class netdev_internal_class =
504 NETDEV_WINDOWS_CLASS(
505 "internal",
506 netdev_windows_internal_construct);