datapath-windows: Avoid BSOD when no event queue found.
[cascardo/ovs.git] / lib / netdev-windows.c
1 /*
2  * Copyright (c) 2014 VMware, Inc.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <stdlib.h>
18 #include <config.h>
19 #include <errno.h>
20
21 #include <net/if.h>
22
23 #include "coverage.h"
24 #include "fatal-signal.h"
25 #include "netdev-provider.h"
26 #include "ofpbuf.h"
27 #include "packets.h"
28 #include "poll-loop.h"
29 #include "shash.h"
30 #include "svec.h"
31 #include "vlog.h"
32 #include "odp-netlink.h"
33 #include "netlink-socket.h"
34 #include "netlink.h"
35
36 VLOG_DEFINE_THIS_MODULE(netdev_windows);
37 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
38
39 enum {
40     VALID_ETHERADDR         = 1 << 0,
41     VALID_MTU               = 1 << 1,
42     VALID_IFFLAG            = 1 << 5,
43 };
44
45 /* Caches the information of a netdev. */
46 struct netdev_windows {
47     struct netdev up;
48     int32_t dev_type;
49     uint32_t port_no;
50
51     unsigned int change_seq;
52
53     unsigned int cache_valid;
54     int ifindex;
55     uint8_t mac[ETH_ADDR_LEN];
56     uint32_t mtu;
57     unsigned int ifi_flags;
58 };
59
60 /* Utility structure for netdev commands. */
61 struct netdev_windows_netdev_info {
62     /* Generic Netlink header. */
63     uint8_t cmd;
64
65     /* Information that is relevant to ovs. */
66     uint32_t dp_ifindex;
67     uint32_t port_no;
68     uint32_t ovs_type;
69
70     /* General information of a network device. */
71     const char *name;
72     uint8_t mac_address[ETH_ADDR_LEN];
73     uint32_t mtu;
74     uint32_t ifi_flags;
75 };
76
77 static int refresh_port_status(struct netdev_windows *netdev);
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);
83
84 /* Generic Netlink family numbers for OVS.
85  *
86  * Initialized by netdev_windows_init_(). */
87 static int ovs_win_netdev_family;
88 struct nl_sock *ovs_win_netdev_sock;
89
90
91 static bool
92 is_netdev_windows_class(const struct netdev_class *netdev_class)
93 {
94     return netdev_class->alloc == netdev_windows_alloc;
95 }
96
97 static struct netdev_windows *
98 netdev_windows_cast(const struct netdev *netdev_)
99 {
100     ovs_assert(is_netdev_windows_class(netdev_get_class(netdev_)));
101     return CONTAINER_OF(netdev_, struct netdev_windows, up);
102 }
103
104 static int
105 netdev_windows_init_(void)
106 {
107     int error = 0;
108     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
109
110     if (ovsthread_once_start(&once)) {
111         error = nl_lookup_genl_family(OVS_WIN_NETDEV_FAMILY,
112                                       &ovs_win_netdev_family);
113         if (error) {
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);
117         }
118         if (!error) {
119             /* XXX: Where to close this socket? */
120             error = nl_sock_create(NETLINK_GENERIC, &ovs_win_netdev_sock);
121         }
122
123         ovsthread_once_done(&once);
124     }
125
126     return error;
127 }
128
129 static struct netdev *
130 netdev_windows_alloc(void)
131 {
132     struct netdev_windows *netdev = xzalloc(sizeof *netdev);
133     return netdev ? &netdev->up : NULL;
134 }
135
136 static int
137 netdev_windows_system_construct(struct netdev *netdev_)
138 {
139     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
140     uint8_t mac[ETH_ADDR_LEN];
141     struct netdev_windows_netdev_info info;
142     struct ofpbuf *buf;
143     int ret;
144
145     /* Query the attributes and runtime status of the netdev. */
146     ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
147     if (ret) {
148         return ret;
149     }
150     ofpbuf_delete(buf);
151
152     netdev->change_seq = 1;
153     netdev->dev_type = info.ovs_type;
154     netdev->port_no = info.port_no;
155
156     memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
157     netdev->cache_valid = VALID_ETHERADDR;
158     netdev->ifindex = -EOPNOTSUPP;
159
160     netdev->mtu = info.mtu;
161     netdev->cache_valid |= VALID_MTU;
162
163     netdev->ifi_flags = info.ifi_flags;
164     netdev->cache_valid |= VALID_IFFLAG;
165
166     VLOG_DBG("construct device %s, ovs_type: %u.",
167              netdev_get_name(&netdev->up), info.ovs_type);
168     return 0;
169 }
170
171 static int
172 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
173                                 struct ofpbuf *buf)
174 {
175     struct ovs_header *ovs_header;
176     int error = EINVAL;
177
178     nl_msg_put_genlmsghdr(buf, 0, ovs_win_netdev_family,
179                           NLM_F_REQUEST | NLM_F_ECHO,
180                           info->cmd, OVS_WIN_NETDEV_VERSION);
181
182     ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
183     ovs_header->dp_ifindex = info->dp_ifindex;
184
185     if (info->name) {
186         nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
187         error = 0;
188     }
189
190     return error;
191 }
192
193 static void
194 netdev_windows_info_init(struct netdev_windows_netdev_info *info)
195 {
196     memset(info, 0, sizeof *info);
197 }
198
199 static int
200 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
201                                   struct ofpbuf *buf)
202 {
203     static const struct nl_policy ovs_netdev_policy[] = {
204         [OVS_WIN_NETDEV_ATTR_PORT_NO] = { .type = NL_A_U32 },
205         [OVS_WIN_NETDEV_ATTR_TYPE] = { .type = NL_A_U32 },
206         [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
207         [OVS_WIN_NETDEV_ATTR_MAC_ADDR] = { NL_POLICY_FOR(info->mac_address) },
208         [OVS_WIN_NETDEV_ATTR_MTU] = { .type = NL_A_U32 },
209         [OVS_WIN_NETDEV_ATTR_IF_FLAGS] = { .type = NL_A_U32 },
210     };
211
212     struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
213     struct ovs_header *ovs_header;
214     struct nlmsghdr *nlmsg;
215     struct genlmsghdr *genl;
216     struct ofpbuf b;
217
218     netdev_windows_info_init(info);
219
220     ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
221     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
222     genl = ofpbuf_try_pull(&b, sizeof *genl);
223     ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
224     if (!nlmsg || !genl || !ovs_header
225         || nlmsg->nlmsg_type != ovs_win_netdev_family
226         || !nl_policy_parse(&b, 0, ovs_netdev_policy, a,
227                             ARRAY_SIZE(ovs_netdev_policy))) {
228         return EINVAL;
229     }
230
231     info->cmd = genl->cmd;
232     info->dp_ifindex = ovs_header->dp_ifindex;
233     info->port_no = nl_attr_get_odp_port(a[OVS_WIN_NETDEV_ATTR_PORT_NO]);
234     info->ovs_type = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_TYPE]);
235     info->name = nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]);
236     memcpy(info->mac_address, nl_attr_get_string(a[OVS_WIN_NETDEV_ATTR_NAME]),
237            sizeof(info->mac_address));
238     info->mtu = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_MTU]);
239     info->ifi_flags = nl_attr_get_u32(a[OVS_WIN_NETDEV_ATTR_IF_FLAGS]);
240
241     return 0;
242 }
243
244 static int
245 query_netdev(const char *devname,
246              struct netdev_windows_netdev_info *info,
247              struct ofpbuf **bufp)
248 {
249     int error = 0;
250     struct ofpbuf *request_buf;
251
252     ovs_assert(info != NULL);
253     netdev_windows_info_init(info);
254
255     error = netdev_windows_init_();
256     if (error) {
257         if (info) {
258             *bufp = NULL;
259             netdev_windows_info_init(info);
260         }
261         return error;
262     }
263
264     request_buf = ofpbuf_new(1024);
265     info->cmd = OVS_WIN_NETDEV_CMD_GET;
266     info->name = devname;
267     error = netdev_windows_netdev_to_ofpbuf(info, request_buf);
268     if (error) {
269         ofpbuf_delete(request_buf);
270         return error;
271     }
272
273     error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
274     ofpbuf_delete(request_buf);
275
276     if (info) {
277         if (!error) {
278             error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
279         }
280         if (error) {
281             netdev_windows_info_init(info);
282             ofpbuf_delete(*bufp);
283             *bufp = NULL;
284         }
285     }
286
287     return 0;
288 }
289
290 static void
291 netdev_windows_destruct(struct netdev *netdev_)
292 {
293
294 }
295
296 static void
297 netdev_windows_dealloc(struct netdev *netdev_)
298 {
299     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
300     free(netdev);
301 }
302
303 static int
304 netdev_windows_get_etheraddr(const struct netdev *netdev_,
305                              uint8_t mac[ETH_ADDR_LEN])
306 {
307     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
308
309     ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
310     if (netdev->cache_valid & VALID_ETHERADDR) {
311         memcpy(mac, netdev->mac, ETH_ADDR_LEN);
312     } else {
313         return EINVAL;
314     }
315     return 0;
316 }
317
318 static int
319 netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
320 {
321     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
322
323     ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
324     if (netdev->cache_valid & VALID_MTU) {
325         *mtup = netdev->mtu;
326     } else {
327         return EINVAL;
328     }
329     return 0;
330 }
331
332 /* This functionality is not really required by the datapath.
333  * But vswitchd bringup expects this to be implemented. */
334 static int
335 netdev_windows_set_etheraddr(const struct netdev *netdev_,
336                              uint8_t mac[ETH_ADDR_LEN])
337 {
338     return 0;
339 }
340
341 /* We do not really have to update anything in kernel. */
342 static int
343 netdev_win_set_flag(const char *name, uint32_t flags)
344 {
345     return 0;
346 }
347
348 /* This functionality is not really required by the datapath.
349  * But vswitchd bringup expects this to be implemented. */
350 static int
351 netdev_win_update_flags_system(struct netdev *netdev_,
352                                enum netdev_flags off,
353                                enum netdev_flags on,
354                                enum netdev_flags *old_flagsp)
355 {
356     return 0;
357 }
358
359
360 static int
361 netdev_windows_internal_construct(struct netdev *netdev_)
362 {
363     return netdev_windows_system_construct(netdev_);
364 }
365
366
367 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT)                           \
368 {                                                                       \
369     .type               = NAME,                                         \
370     .alloc              = netdev_windows_alloc,                         \
371     .construct          = CONSTRUCT,                                    \
372     .destruct           = netdev_windows_destruct,                      \
373     .dealloc            = netdev_windows_dealloc,                       \
374     .get_etheraddr      = netdev_windows_get_etheraddr,                 \
375     .set_etheraddr      = netdev_windows_set_etheraddr,                 \
376     .update_flags       = netdev_win_update_flags_system,               \
377 }
378
379 const struct netdev_class netdev_windows_class =
380     NETDEV_WINDOWS_CLASS(
381         "system",
382         netdev_windows_system_construct);
383
384 const struct netdev_class netdev_internal_class =
385     NETDEV_WINDOWS_CLASS(
386         "internal",
387         netdev_windows_internal_construct);