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
);