2 * Copyright (c) 2014, 2016 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"
27 #include "openvswitch/ofpbuf.h"
29 #include "poll-loop.h"
30 #include "openvswitch/shash.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 netdev_windows_info_init(info
);
229 struct ofpbuf b
= ofpbuf_const_initializer(buf
->data
, buf
->size
);
230 struct nlmsghdr
*nlmsg
= ofpbuf_try_pull(&b
, sizeof *nlmsg
);
231 struct genlmsghdr
*genl
= ofpbuf_try_pull(&b
, sizeof *genl
);
232 struct ovs_header
*ovs_header
= ofpbuf_try_pull(&b
, sizeof *ovs_header
);
234 struct nlattr
*a
[ARRAY_SIZE(ovs_netdev_policy
)];
235 if (!nlmsg
|| !genl
|| !ovs_header
236 || nlmsg
->nlmsg_type
!= ovs_win_netdev_family
237 || !nl_policy_parse(&b
, 0, ovs_netdev_policy
, a
,
238 ARRAY_SIZE(ovs_netdev_policy
))) {
242 info
->cmd
= genl
->cmd
;
243 info
->dp_ifindex
= ovs_header
->dp_ifindex
;
244 info
->port_no
= nl_attr_get_odp_port(a
[OVS_WIN_NETDEV_ATTR_PORT_NO
]);
245 info
->ovs_type
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_TYPE
]);
246 info
->name
= nl_attr_get_string(a
[OVS_WIN_NETDEV_ATTR_NAME
]);
247 memcpy(&info
->mac_address
, nl_attr_get_unspec(a
[OVS_WIN_NETDEV_ATTR_MAC_ADDR
],
248 sizeof(info
->mac_address
)), sizeof(info
->mac_address
));
249 info
->mtu
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_MTU
]);
250 info
->ifi_flags
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_IF_FLAGS
]);
256 query_netdev(const char *devname
,
257 struct netdev_windows_netdev_info
*info
,
258 struct ofpbuf
**bufp
)
261 struct ofpbuf
*request_buf
;
263 ovs_assert(info
!= NULL
);
264 netdev_windows_info_init(info
);
266 error
= netdev_windows_init_();
270 netdev_windows_info_init(info
);
275 request_buf
= ofpbuf_new(1024);
276 info
->cmd
= OVS_WIN_NETDEV_CMD_GET
;
277 info
->name
= devname
;
278 error
= netdev_windows_netdev_to_ofpbuf(info
, request_buf
);
280 ofpbuf_delete(request_buf
);
284 error
= nl_transact(NETLINK_GENERIC
, request_buf
, bufp
);
285 ofpbuf_delete(request_buf
);
289 error
= netdev_windows_netdev_from_ofpbuf(info
, *bufp
);
292 netdev_windows_info_init(info
);
293 ofpbuf_delete(*bufp
);
302 netdev_windows_destruct(struct netdev
*netdev_
)
308 netdev_windows_dealloc(struct netdev
*netdev_
)
310 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
315 netdev_windows_get_etheraddr(const struct netdev
*netdev_
,
316 struct eth_addr
*mac
)
318 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
320 ovs_assert((netdev
->cache_valid
& VALID_ETHERADDR
) != 0);
321 if (netdev
->cache_valid
& VALID_ETHERADDR
) {
330 netdev_windows_get_mtu(const struct netdev
*netdev_
, int *mtup
)
332 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
334 ovs_assert((netdev
->cache_valid
& VALID_MTU
) != 0);
335 if (netdev
->cache_valid
& VALID_MTU
) {
343 /* This functionality is not really required by the datapath.
344 * But vswitchd bringup expects this to be implemented. */
346 netdev_windows_set_etheraddr(const struct netdev
*netdev_
,
347 const struct eth_addr mac
)
352 /* This functionality is not really required by the datapath.
353 * But vswitchd bringup expects this to be implemented. */
355 netdev_windows_update_flags(struct netdev
*netdev_
,
356 enum netdev_flags off
,
357 enum netdev_flags on
,
358 enum netdev_flags
*old_flagsp
)
360 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
362 ovs_assert((netdev
->cache_valid
& VALID_IFFLAG
) != 0);
363 if (netdev
->cache_valid
& VALID_IFFLAG
) {
364 *old_flagsp
= netdev
->ifi_flags
;
365 /* Setting the interface flags is not supported. */
372 /* Looks up in the ARP table entry for a given 'ip'. If it is found, the
373 * corresponding MAC address will be copied in 'mac' and return 0. If no
374 * matching entry is found or an error occurs it will log it and return ENXIO.
377 netdev_windows_arp_lookup(const struct netdev
*netdev
,
378 ovs_be32 ip
, struct eth_addr
*mac
)
380 PMIB_IPNETTABLE arp_table
= NULL
;
381 /* The buffer length of all ARP entries */
382 uint32_t buffer_length
= 0;
383 uint32_t ret_val
= 0;
384 uint32_t counter
= 0;
386 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
388 if (ret_val
!= ERROR_INSUFFICIENT_BUFFER
) {
389 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
390 ovs_format_message(ret_val
));
394 arp_table
= (MIB_IPNETTABLE
*) malloc(buffer_length
);
396 if (arp_table
== NULL
) {
397 VLOG_ERR("Could not allocate memory for all the interfaces");
401 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
403 if (ret_val
== NO_ERROR
) {
404 for (counter
= 0; counter
< arp_table
->dwNumEntries
; counter
++) {
405 if (arp_table
->table
[counter
].dwAddr
== ip
) {
406 memcpy(mac
, arp_table
->table
[counter
].bPhysAddr
, ETH_ADDR_LEN
);
413 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
414 ovs_format_message(ret_val
));
422 netdev_windows_get_next_hop(const struct in_addr
*host
,
423 struct in_addr
*next_hop
,
426 uint32_t ret_val
= 0;
427 /* The buffer length of all addresses */
428 uint32_t buffer_length
= 0;
429 PIP_ADAPTER_ADDRESSES all_addr
= NULL
;
430 PIP_ADAPTER_ADDRESSES cur_addr
= NULL
;
432 ret_val
= GetAdaptersAddresses(AF_INET
,
433 GAA_FLAG_INCLUDE_PREFIX
|
434 GAA_FLAG_INCLUDE_GATEWAYS
,
435 NULL
, NULL
, &buffer_length
);
437 if (ret_val
!= ERROR_BUFFER_OVERFLOW
) {
438 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
439 ovs_format_message(ret_val
));
443 all_addr
= (IP_ADAPTER_ADDRESSES
*) malloc(buffer_length
);
445 if (all_addr
== NULL
) {
446 VLOG_ERR("Could not allocate memory for all the interfaces");
450 ret_val
= GetAdaptersAddresses(AF_INET
,
451 GAA_FLAG_INCLUDE_PREFIX
|
452 GAA_FLAG_INCLUDE_GATEWAYS
,
453 NULL
, all_addr
, &buffer_length
);
455 if (ret_val
== NO_ERROR
) {
458 if(cur_addr
->FirstGatewayAddress
&&
459 cur_addr
->FirstGatewayAddress
->Address
.lpSockaddr
) {
460 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)
461 cur_addr
->FirstGatewayAddress
->Address
.lpSockaddr
;
462 next_hop
->s_addr
= ipv4
->sin_addr
.S_un
.S_addr
;
463 *netdev_name
= xstrdup((char *)cur_addr
->FriendlyName
);
470 cur_addr
= cur_addr
->Next
;
473 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
474 ovs_format_message(ret_val
));
484 netdev_windows_internal_construct(struct netdev
*netdev_
)
486 return netdev_windows_system_construct(netdev_
);
490 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
494 .alloc = netdev_windows_alloc, \
495 .construct = CONSTRUCT, \
496 .destruct = netdev_windows_destruct, \
497 .dealloc = netdev_windows_dealloc, \
498 .get_etheraddr = netdev_windows_get_etheraddr, \
499 .set_etheraddr = netdev_windows_set_etheraddr, \
500 .update_flags = netdev_windows_update_flags, \
501 .get_next_hop = netdev_windows_get_next_hop, \
502 .arp_lookup = netdev_windows_arp_lookup, \
505 const struct netdev_class netdev_windows_class
=
506 NETDEV_WINDOWS_CLASS(
508 netdev_windows_system_construct
);
510 const struct netdev_class netdev_internal_class
=
511 NETDEV_WINDOWS_CLASS(
513 netdev_windows_internal_construct
);