2 * Copyright (c) 2014 VMware, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "fatal-signal.h"
26 #include "netdev-provider.h"
29 #include "poll-loop.h"
32 #include "openvswitch/vlog.h"
33 #include "odp-netlink.h"
34 #include "netlink-socket.h"
37 VLOG_DEFINE_THIS_MODULE(netdev_windows);
38 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
41 VALID_ETHERADDR = 1 << 0,
43 VALID_IFFLAG = 1 << 5,
46 /* Caches the information of a netdev. */
47 struct netdev_windows {
52 unsigned int change_seq;
54 unsigned int cache_valid;
58 unsigned int ifi_flags;
61 /* Utility structure for netdev commands. */
62 struct netdev_windows_netdev_info {
63 /* Generic Netlink header. */
66 /* Information that is relevant to ovs. */
71 /* General information of a network device. */
73 struct eth_addr mac_address;
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);
84 /* Generic Netlink family numbers for OVS.
86 * Initialized by netdev_windows_init_(). */
87 static int ovs_win_netdev_family;
88 struct nl_sock *ovs_win_netdev_sock;
92 is_netdev_windows_class(const struct netdev_class *netdev_class)
94 return netdev_class->alloc == netdev_windows_alloc;
97 static struct netdev_windows *
98 netdev_windows_cast(const struct netdev *netdev_)
100 ovs_assert(is_netdev_windows_class(netdev_get_class(netdev_)));
101 return CONTAINER_OF(netdev_, struct netdev_windows, up);
105 netdev_windows_init_(void)
108 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
110 if (ovsthread_once_start(&once)) {
111 error = nl_lookup_genl_family(OVS_WIN_NETDEV_FAMILY,
112 &ovs_win_netdev_family);
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);
119 /* XXX: Where to close this socket? */
120 error = nl_sock_create(NETLINK_GENERIC, &ovs_win_netdev_sock);
123 ovsthread_once_done(&once);
129 static struct netdev *
130 netdev_windows_alloc(void)
132 struct netdev_windows *netdev = xzalloc(sizeof *netdev);
133 return netdev ? &netdev->up : NULL;
137 dp_to_netdev_ifi_flags(uint32_t dp_flags)
139 uint32_t nd_flags = 0;
141 if (dp_flags && OVS_WIN_NETDEV_IFF_UP) {
142 nd_flags |= NETDEV_UP;
145 if (dp_flags && OVS_WIN_NETDEV_IFF_PROMISC) {
146 nd_flags |= NETDEV_PROMISC;
153 netdev_windows_system_construct(struct netdev *netdev_)
155 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
156 struct netdev_windows_netdev_info info;
160 /* Query the attributes and runtime status of the netdev. */
161 ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
167 netdev->change_seq = 1;
168 netdev->dev_type = info.ovs_type;
169 netdev->port_no = info.port_no;
171 netdev->mac = info.mac_address;
172 netdev->cache_valid = VALID_ETHERADDR;
173 netdev->ifindex = -EOPNOTSUPP;
175 netdev->mtu = info.mtu;
176 netdev->cache_valid |= VALID_MTU;
178 netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags);
179 netdev->cache_valid |= VALID_IFFLAG;
181 VLOG_DBG("construct device %s, ovs_type: %u.",
182 netdev_get_name(&netdev->up), info.ovs_type);
187 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
190 struct ovs_header *ovs_header;
193 nl_msg_put_genlmsghdr(buf, 0, ovs_win_netdev_family,
194 NLM_F_REQUEST | NLM_F_ECHO,
195 info->cmd, OVS_WIN_NETDEV_VERSION);
197 ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
198 ovs_header->dp_ifindex = info->dp_ifindex;
201 nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
209 netdev_windows_info_init(struct netdev_windows_netdev_info *info)
211 memset(info, 0, sizeof *info);
215 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
218 static const struct nl_policy ovs_netdev_policy[] = {
219 [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 },
220 [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 },
221 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
222 [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) },
223 [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 },
224 [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
227 struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
228 struct ovs_header *ovs_header;
229 struct nlmsghdr *nlmsg;
230 struct genlmsghdr *genl;
233 netdev_windows_info_init(info);
235 ofpbuf_use_const(&b, buf->data, buf->size);
236 nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
237 genl = ofpbuf_try_pull(&b, sizeof *genl);
238 ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
239 if (!nlmsg || !genl || !ovs_header
240 || nlmsg->nlmsg_type != ovs_win_netdev_family
241 || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
242 ARRAY_SIZE(ovs_netdev_policy))) {
246 info->cmd = genl->cmd;
247 info->dp_ifindex = ovs_header->dp_ifindex;
248 info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);
249 info->ovs_type = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_TYPE]);
250 info->name = nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]);
251 memcpy(&info->mac_address, nl_attr_get_unspec(a[OVS_WIN_NETDEV_ATTR_MAC_ADDR],
252 sizeof(info->mac_address)), sizeof(info->mac_address));
253 info->mtu = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_MTU]);
254 info->ifi_flags = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_IF_FLAGS]);
260 query_netdev(const char *devname,
261 struct netdev_windows_netdev_info *info,
262 struct ofpbuf **bufp)
265 struct ofpbuf *request_buf;
267 ovs_assert(info != NULL);
268 netdev_windows_info_init(info);
270 error = netdev_windows_init_();
274 netdev_windows_info_init(info);
279 request_buf = ofpbuf_new(1024);
280 info->cmd = OVS_WIN_NETDEV_CMD_GET;
281 info->name = devname;
282 error = netdev_windows_netdev_to_ofpbuf(info, request_buf);
284 ofpbuf_delete(request_buf);
288 error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
289 ofpbuf_delete(request_buf);
293 error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
296 netdev_windows_info_init(info);
297 ofpbuf_delete(*bufp);
306 netdev_windows_destruct(struct netdev *netdev_)
312 netdev_windows_dealloc(struct netdev *netdev_)
314 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
319 netdev_windows_get_etheraddr(const struct netdev *netdev_,
320 struct eth_addr *mac)
322 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
324 ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
325 if (netdev->cache_valid & VALID_ETHERADDR) {
334 netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
336 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
338 ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
339 if (netdev->cache_valid & VALID_MTU) {
347 /* This functionality is not really required by the datapath.
348 * But vswitchd bringup expects this to be implemented. */
350 netdev_windows_set_etheraddr(const struct netdev *netdev_,
351 const struct eth_addr mac)
356 /* This functionality is not really required by the datapath.
357 * But vswitchd bringup expects this to be implemented. */
359 netdev_windows_update_flags(struct netdev *netdev_,
360 enum netdev_flags off,
361 enum netdev_flags on,
362 enum netdev_flags *old_flagsp)
364 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
366 ovs_assert((netdev->cache_valid & VALID_IFFLAG) != 0);
367 if (netdev->cache_valid & VALID_IFFLAG) {
368 *old_flagsp = netdev->ifi_flags;
369 /* Setting the interface flags is not supported. */
376 /* Looks up in the ARP table entry for a given 'ip'. If it is found, the
377 * corresponding MAC address will be copied in 'mac' and return 0. If no
378 * matching entry is found or an error occurs it will log it and return ENXIO.
381 netdev_windows_arp_lookup(const struct netdev *netdev,
382 ovs_be32 ip, struct eth_addr *mac)
384 PMIB_IPNETTABLE arp_table = NULL;
385 /* The buffer length of all ARP entries */
386 uint32_t buffer_length = 0;
387 uint32_t ret_val = 0;
388 uint32_t counter = 0;
390 ret_val = GetIpNetTable(arp_table, &buffer_length, false);
392 if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
393 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
394 ovs_format_message(ret_val));
398 arp_table = (MIB_IPNETTABLE *) malloc(buffer_length);
400 if (arp_table == NULL) {
401 VLOG_ERR("Could not allocate memory for all the interfaces");
405 ret_val = GetIpNetTable(arp_table, &buffer_length, false);
407 if (ret_val == NO_ERROR) {
408 for (counter = 0; counter < arp_table->dwNumEntries; counter++) {
409 if (arp_table->table[counter].dwAddr == ip) {
410 memcpy(mac, arp_table->table[counter].bPhysAddr, ETH_ADDR_LEN);
417 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
418 ovs_format_message(ret_val));
426 netdev_windows_get_next_hop(const struct in_addr *host,
427 struct in_addr *next_hop,
430 uint32_t ret_val = 0;
431 /* The buffer length of all addresses */
432 uint32_t buffer_length = 1000;
433 PIP_ADAPTER_ADDRESSES all_addr = NULL;
434 PIP_ADAPTER_ADDRESSES cur_addr = NULL;
436 ret_val = GetAdaptersAddresses(AF_INET,
437 GAA_FLAG_INCLUDE_PREFIX |
438 GAA_FLAG_INCLUDE_GATEWAYS,
439 NULL, all_addr, &buffer_length);
441 if (ret_val != ERROR_INSUFFICIENT_BUFFER ) {
442 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
443 ovs_format_message(ret_val));
447 all_addr = (IP_ADAPTER_ADDRESSES *) malloc(buffer_length);
449 if (all_addr == NULL) {
450 VLOG_ERR("Could not allocate memory for all the interfaces");
454 ret_val = GetAdaptersAddresses(AF_INET,
455 GAA_FLAG_INCLUDE_PREFIX |
456 GAA_FLAG_INCLUDE_GATEWAYS,
457 NULL, all_addr, &buffer_length);
459 if (ret_val == NO_ERROR) {
462 if(cur_addr->FirstGatewayAddress &&
463 cur_addr->FirstGatewayAddress->Address.lpSockaddr) {
464 struct sockaddr_in *ipv4 = (struct sockaddr_in *)
465 cur_addr->FirstGatewayAddress->Address.lpSockaddr;
466 next_hop->s_addr = ipv4->sin_addr.S_un.S_addr;
467 *netdev_name = xstrdup((char *)cur_addr->FriendlyName);
474 cur_addr = cur_addr->Next;
477 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
478 ovs_format_message(ret_val));
488 netdev_windows_internal_construct(struct netdev *netdev_)
490 return netdev_windows_system_construct(netdev_);
494 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
497 .alloc = netdev_windows_alloc, \
498 .construct = CONSTRUCT, \
499 .destruct = netdev_windows_destruct, \
500 .dealloc = netdev_windows_dealloc, \
501 .get_etheraddr = netdev_windows_get_etheraddr, \
502 .set_etheraddr = netdev_windows_set_etheraddr, \
503 .update_flags = netdev_windows_update_flags, \
504 .get_next_hop = netdev_windows_get_next_hop, \
505 .arp_lookup = netdev_windows_arp_lookup, \
508 const struct netdev_class netdev_windows_class =
509 NETDEV_WINDOWS_CLASS(
511 netdev_windows_system_construct);
513 const struct netdev_class netdev_internal_class =
514 NETDEV_WINDOWS_CLASS(
516 netdev_windows_internal_construct);