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 "openvswitch/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
);
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
) {
170 netdev
->change_seq
= 1;
171 netdev
->dev_type
= info
.ovs_type
;
172 netdev
->port_no
= info
.port_no
;
174 netdev
->mac
= info
.mac_address
;
175 netdev
->cache_valid
= VALID_ETHERADDR
;
176 netdev
->ifindex
= -EOPNOTSUPP
;
178 netdev
->mtu
= info
.mtu
;
179 netdev
->cache_valid
|= VALID_MTU
;
181 netdev
->ifi_flags
= dp_to_netdev_ifi_flags(info
.ifi_flags
);
182 netdev
->cache_valid
|= VALID_IFFLAG
;
184 VLOG_DBG("construct device %s, ovs_type: %u.",
185 netdev_get_name(&netdev
->up
), info
.ovs_type
);
190 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info
*info
,
193 struct ovs_header
*ovs_header
;
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
);
200 ovs_header
= ofpbuf_put_uninit(buf
, sizeof *ovs_header
);
201 ovs_header
->dp_ifindex
= info
->dp_ifindex
;
204 nl_msg_put_string(buf
, OVS_WIN_NETDEV_ATTR_NAME
, info
->name
);
212 netdev_windows_info_init(struct netdev_windows_netdev_info
*info
)
214 memset(info
, 0, sizeof *info
);
218 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info
*info
,
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
},
230 netdev_windows_info_init(info
);
232 struct ofpbuf b
= ofpbuf_const_initializer(buf
->data
, buf
->size
);
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
);
237 struct nlattr
*a
[ARRAY_SIZE(ovs_netdev_policy
)];
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
))) {
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
]);
250 memcpy(&info
->mac_address
, nl_attr_get_unspec(a
[OVS_WIN_NETDEV_ATTR_MAC_ADDR
],
251 sizeof(info
->mac_address
)), sizeof(info
->mac_address
));
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
]);
259 query_netdev(const char *devname
,
260 struct netdev_windows_netdev_info
*info
,
261 struct ofpbuf
**bufp
)
264 struct ofpbuf
*request_buf
;
266 ovs_assert(info
!= NULL
);
267 netdev_windows_info_init(info
);
269 error
= netdev_windows_init_();
273 netdev_windows_info_init(info
);
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
);
283 ofpbuf_delete(request_buf
);
287 error
= nl_transact(NETLINK_GENERIC
, request_buf
, bufp
);
288 ofpbuf_delete(request_buf
);
292 error
= netdev_windows_netdev_from_ofpbuf(info
, *bufp
);
295 netdev_windows_info_init(info
);
296 ofpbuf_delete(*bufp
);
305 netdev_windows_destruct(struct netdev
*netdev_
)
311 netdev_windows_dealloc(struct netdev
*netdev_
)
313 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
318 netdev_windows_get_etheraddr(const struct netdev
*netdev_
,
319 struct eth_addr
*mac
)
321 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
323 ovs_assert((netdev
->cache_valid
& VALID_ETHERADDR
) != 0);
324 if (netdev
->cache_valid
& VALID_ETHERADDR
) {
333 netdev_windows_get_mtu(const struct netdev
*netdev_
, int *mtup
)
335 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
337 ovs_assert((netdev
->cache_valid
& VALID_MTU
) != 0);
338 if (netdev
->cache_valid
& VALID_MTU
) {
346 /* This functionality is not really required by the datapath.
347 * But vswitchd bringup expects this to be implemented. */
349 netdev_windows_set_etheraddr(const struct netdev
*netdev_
,
350 const struct eth_addr mac
)
355 /* This functionality is not really required by the datapath.
356 * But vswitchd bringup expects this to be implemented. */
358 netdev_windows_update_flags(struct netdev
*netdev_
,
359 enum netdev_flags off
,
360 enum netdev_flags on
,
361 enum netdev_flags
*old_flagsp
)
363 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
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. */
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.
380 netdev_windows_arp_lookup(const struct netdev
*netdev
,
381 ovs_be32 ip
, struct eth_addr
*mac
)
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;
389 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
391 if (ret_val
!= ERROR_INSUFFICIENT_BUFFER
) {
392 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
393 ovs_format_message(ret_val
));
397 arp_table
= (MIB_IPNETTABLE
*) xmalloc(buffer_length
);
399 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
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
);
411 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
412 ovs_format_message(ret_val
));
420 netdev_windows_get_next_hop(const struct in_addr
*host
,
421 struct in_addr
*next_hop
,
424 uint32_t ret_val
= 0;
425 /* The buffer length of all addresses */
426 uint32_t buffer_length
= 0;
427 PIP_ADAPTER_ADDRESSES all_addr
= NULL
;
428 PIP_ADAPTER_ADDRESSES cur_addr
= NULL
;
430 ret_val
= GetAdaptersAddresses(AF_INET
,
431 GAA_FLAG_INCLUDE_PREFIX
|
432 GAA_FLAG_INCLUDE_GATEWAYS
,
433 NULL
, NULL
, &buffer_length
);
435 if (ret_val
!= ERROR_BUFFER_OVERFLOW
) {
436 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
437 ovs_format_message(ret_val
));
441 all_addr
= (IP_ADAPTER_ADDRESSES
*) xmalloc(buffer_length
);
443 ret_val
= GetAdaptersAddresses(AF_INET
,
444 GAA_FLAG_INCLUDE_PREFIX
|
445 GAA_FLAG_INCLUDE_GATEWAYS
,
446 NULL
, all_addr
, &buffer_length
);
448 if (ret_val
== NO_ERROR
) {
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
);
463 cur_addr
= cur_addr
->Next
;
466 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
467 ovs_format_message(ret_val
));
477 netdev_windows_internal_construct(struct netdev
*netdev_
)
479 return netdev_windows_system_construct(netdev_
);
483 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
487 .alloc = netdev_windows_alloc, \
488 .construct = CONSTRUCT, \
489 .destruct = netdev_windows_destruct, \
490 .dealloc = netdev_windows_dealloc, \
491 .get_etheraddr = netdev_windows_get_etheraddr, \
492 .set_etheraddr = netdev_windows_set_etheraddr, \
493 .update_flags = netdev_windows_update_flags, \
494 .get_next_hop = netdev_windows_get_next_hop, \
495 .arp_lookup = netdev_windows_arp_lookup, \
498 const struct netdev_class netdev_windows_class
=
499 NETDEV_WINDOWS_CLASS(
501 netdev_windows_system_construct
);
503 const struct netdev_class netdev_internal_class
=
504 NETDEV_WINDOWS_CLASS(
506 netdev_windows_internal_construct
);