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
;
56 uint8_t mac
[ETH_ADDR_LEN
];
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 uint8_t mac_address
[ETH_ADDR_LEN
];
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 uint8_t mac
[ETH_ADDR_LEN
];
157 struct netdev_windows_netdev_info info
;
161 /* Query the attributes and runtime status of the netdev. */
162 ret
= query_netdev(netdev_get_name(&netdev
->up
), &info
, &buf
);
168 netdev
->change_seq
= 1;
169 netdev
->dev_type
= info
.ovs_type
;
170 netdev
->port_no
= info
.port_no
;
172 memcpy(netdev
->mac
, info
.mac_address
, ETH_ADDR_LEN
);
173 netdev
->cache_valid
= VALID_ETHERADDR
;
174 netdev
->ifindex
= -EOPNOTSUPP
;
176 netdev
->mtu
= info
.mtu
;
177 netdev
->cache_valid
|= VALID_MTU
;
179 netdev
->ifi_flags
= dp_to_netdev_ifi_flags(info
.ifi_flags
);
180 netdev
->cache_valid
|= VALID_IFFLAG
;
182 VLOG_DBG("construct device %s, ovs_type: %u.",
183 netdev_get_name(&netdev
->up
), info
.ovs_type
);
188 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info
*info
,
191 struct ovs_header
*ovs_header
;
194 nl_msg_put_genlmsghdr(buf
, 0, ovs_win_netdev_family
,
195 NLM_F_REQUEST
| NLM_F_ECHO
,
196 info
->cmd
, OVS_WIN_NETDEV_VERSION
);
198 ovs_header
= ofpbuf_put_uninit(buf
, sizeof *ovs_header
);
199 ovs_header
->dp_ifindex
= info
->dp_ifindex
;
202 nl_msg_put_string(buf
, OVS_WIN_NETDEV_ATTR_NAME
, info
->name
);
210 netdev_windows_info_init(struct netdev_windows_netdev_info
*info
)
212 memset(info
, 0, sizeof *info
);
216 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info
*info
,
219 static const struct nl_policy ovs_netdev_policy
[] = {
220 [OVS_WIN_NETDEV_ATTR_PORT_NO
] = { .type
= NL_A_U32
},
221 [OVS_WIN_NETDEV_ATTR_TYPE
] = { .type
= NL_A_U32
},
222 [OVS_WIN_NETDEV_ATTR_NAME
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
},
223 [OVS_WIN_NETDEV_ATTR_MAC_ADDR
] = { NL_POLICY_FOR(info
->mac_address
) },
224 [OVS_WIN_NETDEV_ATTR_MTU
] = { .type
= NL_A_U32
},
225 [OVS_WIN_NETDEV_ATTR_IF_FLAGS
] = { .type
= NL_A_U32
},
228 struct nlattr
*a
[ARRAY_SIZE(ovs_netdev_policy
)];
229 struct ovs_header
*ovs_header
;
230 struct nlmsghdr
*nlmsg
;
231 struct genlmsghdr
*genl
;
234 netdev_windows_info_init(info
);
236 ofpbuf_use_const(&b
, buf
->data
, buf
->size
);
237 nlmsg
= ofpbuf_try_pull(&b
, sizeof *nlmsg
);
238 genl
= ofpbuf_try_pull(&b
, sizeof *genl
);
239 ovs_header
= ofpbuf_try_pull(&b
, sizeof *ovs_header
);
240 if (!nlmsg
|| !genl
|| !ovs_header
241 || nlmsg
->nlmsg_type
!= ovs_win_netdev_family
242 || !nl_policy_parse(&b
, 0, ovs_netdev_policy
, a
,
243 ARRAY_SIZE(ovs_netdev_policy
))) {
247 info
->cmd
= genl
->cmd
;
248 info
->dp_ifindex
= ovs_header
->dp_ifindex
;
249 info
->port_no
= nl_attr_get_odp_port(a
[OVS_WIN_NETDEV_ATTR_PORT_NO
]);
250 info
->ovs_type
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_TYPE
]);
251 info
->name
= nl_attr_get_string(a
[OVS_WIN_NETDEV_ATTR_NAME
]);
252 memcpy(info
->mac_address
, nl_attr_get_unspec(a
[OVS_WIN_NETDEV_ATTR_MAC_ADDR
],
253 sizeof(info
->mac_address
)), sizeof(info
->mac_address
));
254 info
->mtu
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_MTU
]);
255 info
->ifi_flags
= nl_attr_get_u32(a
[OVS_WIN_NETDEV_ATTR_IF_FLAGS
]);
261 query_netdev(const char *devname
,
262 struct netdev_windows_netdev_info
*info
,
263 struct ofpbuf
**bufp
)
266 struct ofpbuf
*request_buf
;
268 ovs_assert(info
!= NULL
);
269 netdev_windows_info_init(info
);
271 error
= netdev_windows_init_();
275 netdev_windows_info_init(info
);
280 request_buf
= ofpbuf_new(1024);
281 info
->cmd
= OVS_WIN_NETDEV_CMD_GET
;
282 info
->name
= devname
;
283 error
= netdev_windows_netdev_to_ofpbuf(info
, request_buf
);
285 ofpbuf_delete(request_buf
);
289 error
= nl_transact(NETLINK_GENERIC
, request_buf
, bufp
);
290 ofpbuf_delete(request_buf
);
294 error
= netdev_windows_netdev_from_ofpbuf(info
, *bufp
);
297 netdev_windows_info_init(info
);
298 ofpbuf_delete(*bufp
);
307 netdev_windows_destruct(struct netdev
*netdev_
)
313 netdev_windows_dealloc(struct netdev
*netdev_
)
315 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
320 netdev_windows_get_etheraddr(const struct netdev
*netdev_
,
321 uint8_t mac
[ETH_ADDR_LEN
])
323 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
325 ovs_assert((netdev
->cache_valid
& VALID_ETHERADDR
) != 0);
326 if (netdev
->cache_valid
& VALID_ETHERADDR
) {
327 memcpy(mac
, netdev
->mac
, ETH_ADDR_LEN
);
335 netdev_windows_get_mtu(const struct netdev
*netdev_
, int *mtup
)
337 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
339 ovs_assert((netdev
->cache_valid
& VALID_MTU
) != 0);
340 if (netdev
->cache_valid
& VALID_MTU
) {
348 /* This functionality is not really required by the datapath.
349 * But vswitchd bringup expects this to be implemented. */
351 netdev_windows_set_etheraddr(const struct netdev
*netdev_
,
352 uint8_t mac
[ETH_ADDR_LEN
])
357 /* This functionality is not really required by the datapath.
358 * But vswitchd bringup expects this to be implemented. */
360 netdev_windows_update_flags(struct netdev
*netdev_
,
361 enum netdev_flags off
,
362 enum netdev_flags on
,
363 enum netdev_flags
*old_flagsp
)
365 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
367 ovs_assert((netdev
->cache_valid
& VALID_IFFLAG
) != 0);
368 if (netdev
->cache_valid
& VALID_IFFLAG
) {
369 *old_flagsp
= netdev
->ifi_flags
;
370 /* Setting the interface flags is not supported. */
377 /* Looks up in the ARP table entry for a given 'ip'. If it is found, the
378 * corresponding MAC address will be copied in 'mac' and return 0. If no
379 * matching entry is found or an error occurs it will log it and return ENXIO.
382 netdev_windows_arp_lookup(const struct netdev
*netdev
,
383 ovs_be32 ip
, uint8_t mac
[ETH_ADDR_LEN
])
385 PMIB_IPNETTABLE arp_table
= NULL
;
386 /* The buffer length of all ARP entries */
387 uint32_t buffer_length
= 0;
388 uint32_t ret_val
= 0;
389 uint32_t counter
= 0;
391 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
393 if (ret_val
!= ERROR_INSUFFICIENT_BUFFER
) {
394 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
395 ovs_format_message(ret_val
));
399 arp_table
= (MIB_IPNETTABLE
*) malloc(buffer_length
);
401 if (arp_table
== NULL
) {
402 VLOG_ERR("Could not allocate memory for all the interfaces");
406 ret_val
= GetIpNetTable(arp_table
, &buffer_length
, false);
408 if (ret_val
== NO_ERROR
) {
409 for (counter
= 0; counter
< arp_table
->dwNumEntries
; counter
++) {
410 if (arp_table
->table
[counter
].dwAddr
== ip
) {
411 memcpy(mac
, arp_table
->table
[counter
].bPhysAddr
, ETH_ADDR_LEN
);
418 VLOG_ERR("Call to GetIpNetTable failed with error: %s",
419 ovs_format_message(ret_val
));
427 netdev_windows_get_next_hop(const struct in_addr
*host
,
428 struct in_addr
*next_hop
,
431 uint32_t ret_val
= 0;
432 /* The buffer length of all addresses */
433 uint32_t buffer_length
= 1000;
434 PIP_ADAPTER_ADDRESSES all_addr
= NULL
;
435 PIP_ADAPTER_ADDRESSES cur_addr
= NULL
;
437 ret_val
= GetAdaptersAddresses(AF_INET
,
438 GAA_FLAG_INCLUDE_PREFIX
|
439 GAA_FLAG_INCLUDE_GATEWAYS
,
440 NULL
, all_addr
, &buffer_length
);
442 if (ret_val
!= ERROR_INSUFFICIENT_BUFFER
) {
443 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
444 ovs_format_message(ret_val
));
448 all_addr
= (IP_ADAPTER_ADDRESSES
*) malloc(buffer_length
);
450 if (all_addr
== NULL
) {
451 VLOG_ERR("Could not allocate memory for all the interfaces");
455 ret_val
= GetAdaptersAddresses(AF_INET
,
456 GAA_FLAG_INCLUDE_PREFIX
|
457 GAA_FLAG_INCLUDE_GATEWAYS
,
458 NULL
, all_addr
, &buffer_length
);
460 if (ret_val
== NO_ERROR
) {
463 if(cur_addr
->FirstGatewayAddress
&&
464 cur_addr
->FirstGatewayAddress
->Address
.lpSockaddr
) {
465 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)
466 cur_addr
->FirstGatewayAddress
->Address
.lpSockaddr
;
467 next_hop
->s_addr
= ipv4
->sin_addr
.S_un
.S_addr
;
468 *netdev_name
= xstrdup((char *)cur_addr
->FriendlyName
);
475 cur_addr
= cur_addr
->Next
;
478 VLOG_ERR("Call to GetAdaptersAddresses failed with error: %s",
479 ovs_format_message(ret_val
));
489 netdev_windows_internal_construct(struct netdev
*netdev_
)
491 return netdev_windows_system_construct(netdev_
);
495 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
498 .alloc = netdev_windows_alloc, \
499 .construct = CONSTRUCT, \
500 .destruct = netdev_windows_destruct, \
501 .dealloc = netdev_windows_dealloc, \
502 .get_etheraddr = netdev_windows_get_etheraddr, \
503 .set_etheraddr = netdev_windows_set_etheraddr, \
504 .update_flags = netdev_windows_update_flags, \
505 .get_next_hop = netdev_windows_get_next_hop, \
506 .arp_lookup = netdev_windows_arp_lookup, \
509 const struct netdev_class netdev_windows_class
=
510 NETDEV_WINDOWS_CLASS(
512 netdev_windows_system_construct
);
514 const struct netdev_class netdev_internal_class
=
515 NETDEV_WINDOWS_CLASS(
517 netdev_windows_internal_construct
);