]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-windows.c
ofp-print: Print bucket ids of OpenFlow 1.5 group messages.
[mirror_ovs.git] / lib / netdev-windows.c
CommitLineData
078eedf4
NR
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"
3bd0fd39 27#include "packets.h"
078eedf4
NR
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
36VLOG_DEFINE_THIS_MODULE(netdev_windows);
37static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
38
39enum {
40 VALID_ETHERADDR = 1 << 0,
41 VALID_MTU = 1 << 1,
42 VALID_IFFLAG = 1 << 5,
43};
44
45/* Caches the information of a netdev. */
46struct 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. */
61struct 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
3e648bc5
NR
77static int query_netdev(const char *devname,
78 struct netdev_windows_netdev_info *reply,
79 struct ofpbuf **bufp);
0bfecde1
NR
80static struct netdev *netdev_windows_alloc(void);
81static int netdev_windows_init_(void);
3e648bc5
NR
82
83/* Generic Netlink family numbers for OVS.
84 *
0bfecde1 85 * Initialized by netdev_windows_init_(). */
3e648bc5
NR
86static int ovs_win_netdev_family;
87struct nl_sock *ovs_win_netdev_sock;
88
89
90static bool
91is_netdev_windows_class(const struct netdev_class *netdev_class)
92{
0bfecde1 93 return netdev_class->alloc == netdev_windows_alloc;
3e648bc5
NR
94}
95
96static struct netdev_windows *
97netdev_windows_cast(const struct netdev *netdev_)
98{
99 ovs_assert(is_netdev_windows_class(netdev_get_class(netdev_)));
100 return CONTAINER_OF(netdev_, struct netdev_windows, up);
101}
102
078eedf4 103static int
0bfecde1 104netdev_windows_init_(void)
078eedf4 105{
3e648bc5
NR
106 int error = 0;
107 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
108
109 if (ovsthread_once_start(&once)) {
110 error = nl_lookup_genl_family(OVS_WIN_NETDEV_FAMILY,
111 &ovs_win_netdev_family);
112 if (error) {
113 VLOG_ERR("Generic Netlink family '%s' does not exist. "
114 "The Open vSwitch kernel module is probably not loaded.",
115 OVS_WIN_NETDEV_FAMILY);
116 }
117 if (!error) {
118 /* XXX: Where to close this socket? */
119 error = nl_sock_create(NETLINK_GENERIC, &ovs_win_netdev_sock);
120 }
121
122 ovsthread_once_done(&once);
123 }
124
125 return error;
078eedf4
NR
126}
127
128static struct netdev *
129netdev_windows_alloc(void)
130{
3e648bc5
NR
131 struct netdev_windows *netdev = xzalloc(sizeof *netdev);
132 return netdev ? &netdev->up : NULL;
078eedf4
NR
133}
134
ee4dac3b
NR
135static uint32_t
136dp_to_netdev_ifi_flags(uint32_t dp_flags)
137{
138 uint32_t nd_flags = 0;
139
140 if (dp_flags && OVS_WIN_NETDEV_IFF_UP) {
141 nd_flags |= NETDEV_UP;
142 }
143
144 if (dp_flags && OVS_WIN_NETDEV_IFF_PROMISC) {
145 nd_flags |= NETDEV_PROMISC;
146 }
147
148 return nd_flags;
149}
150
078eedf4
NR
151static int
152netdev_windows_system_construct(struct netdev *netdev_)
153{
3e648bc5
NR
154 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
155 uint8_t mac[ETH_ADDR_LEN];
156 struct netdev_windows_netdev_info info;
157 struct ofpbuf *buf;
158 int ret;
159
160 /* Query the attributes and runtime status of the netdev. */
161 ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
162 if (ret) {
163 return ret;
164 }
165 ofpbuf_delete(buf);
166
167 netdev->change_seq = 1;
168 netdev->dev_type = info.ovs_type;
169 netdev->port_no = info.port_no;
170
171 memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
172 netdev->cache_valid = VALID_ETHERADDR;
173 netdev->ifindex = -EOPNOTSUPP;
174
175 netdev->mtu = info.mtu;
176 netdev->cache_valid |= VALID_MTU;
177
ee4dac3b 178 netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags);
3e648bc5
NR
179 netdev->cache_valid |= VALID_IFFLAG;
180
181 VLOG_DBG("construct device %s, ovs_type: %u.",
182 netdev_get_name(&netdev->up), info.ovs_type);
183 return 0;
184}
185
186static int
187netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
188 struct ofpbuf *buf)
189{
190 struct ovs_header *ovs_header;
191 int error = EINVAL;
192
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);
196
197 ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
198 ovs_header->dp_ifindex = info->dp_ifindex;
199
200 if (info->name) {
201 nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
202 error = 0;
203 }
204
205 return error;
206}
207
208static void
209netdev_windows_info_init(struct netdev_windows_netdev_info *info)
210{
211 memset(info, 0, sizeof *info);
212}
213
214static int
215netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
216 struct ofpbuf *buf)
217{
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 },
225 };
226
227 struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
228 struct ovs_header *ovs_header;
229 struct nlmsghdr *nlmsg;
230 struct genlmsghdr *genl;
231 struct ofpbuf b;
232
233 netdev_windows_info_init(info);
234
235 ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
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))) {
243 return EINVAL;
244 }
245
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]);
ee4dac3b
NR
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));
3e648bc5
NR
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]);
255
256 return 0;
257}
258
259static int
260query_netdev(const char *devname,
261 struct netdev_windows_netdev_info *info,
262 struct ofpbuf **bufp)
263{
264 int error = 0;
265 struct ofpbuf *request_buf;
266
267 ovs_assert(info != NULL);
268 netdev_windows_info_init(info);
269
0bfecde1 270 error = netdev_windows_init_();
3e648bc5
NR
271 if (error) {
272 if (info) {
273 *bufp = NULL;
274 netdev_windows_info_init(info);
275 }
276 return error;
277 }
278
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);
283 if (error) {
284 ofpbuf_delete(request_buf);
285 return error;
286 }
287
288 error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
289 ofpbuf_delete(request_buf);
290
291 if (info) {
292 if (!error) {
293 error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
294 }
295 if (error) {
296 netdev_windows_info_init(info);
297 ofpbuf_delete(*bufp);
298 *bufp = NULL;
299 }
300 }
301
302 return 0;
303}
304
305static void
306netdev_windows_destruct(struct netdev *netdev_)
307{
308
078eedf4
NR
309}
310
311static void
312netdev_windows_dealloc(struct netdev *netdev_)
313{
3e648bc5
NR
314 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
315 free(netdev);
078eedf4
NR
316}
317
318static int
3bd0fd39
WSH
319netdev_windows_get_etheraddr(const struct netdev *netdev_,
320 uint8_t mac[ETH_ADDR_LEN])
078eedf4 321{
3e648bc5
NR
322 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
323
324 ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
325 if (netdev->cache_valid & VALID_ETHERADDR) {
326 memcpy(mac, netdev->mac, ETH_ADDR_LEN);
327 } else {
328 return EINVAL;
329 }
330 return 0;
078eedf4
NR
331}
332
333static int
334netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
335{
3e648bc5
NR
336 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
337
338 ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
339 if (netdev->cache_valid & VALID_MTU) {
340 *mtup = netdev->mtu;
341 } else {
342 return EINVAL;
343 }
344 return 0;
078eedf4 345}
6cac056e
AS
346
347/* This functionality is not really required by the datapath.
348 * But vswitchd bringup expects this to be implemented. */
349static int
3bd0fd39
WSH
350netdev_windows_set_etheraddr(const struct netdev *netdev_,
351 uint8_t mac[ETH_ADDR_LEN])
6cac056e
AS
352{
353 return 0;
354}
355
6cac056e
AS
356/* This functionality is not really required by the datapath.
357 * But vswitchd bringup expects this to be implemented. */
358static int
ee4dac3b
NR
359netdev_windows_update_flags(struct netdev *netdev_,
360 enum netdev_flags off,
361 enum netdev_flags on,
362 enum netdev_flags *old_flagsp)
6cac056e 363{
ee4dac3b
NR
364 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
365
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. */
370 } else {
371 return EINVAL;
372 }
6cac056e
AS
373 return 0;
374}
375
078eedf4
NR
376static int
377netdev_windows_internal_construct(struct netdev *netdev_)
378{
379 return netdev_windows_system_construct(netdev_);
380}
381
382
383#define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
384{ \
385 .type = NAME, \
078eedf4
NR
386 .alloc = netdev_windows_alloc, \
387 .construct = CONSTRUCT, \
3e648bc5 388 .destruct = netdev_windows_destruct, \
078eedf4
NR
389 .dealloc = netdev_windows_dealloc, \
390 .get_etheraddr = netdev_windows_get_etheraddr, \
6cac056e 391 .set_etheraddr = netdev_windows_set_etheraddr, \
ee4dac3b 392 .update_flags = netdev_windows_update_flags, \
078eedf4
NR
393}
394
395const struct netdev_class netdev_windows_class =
396 NETDEV_WINDOWS_CLASS(
397 "system",
398 netdev_windows_system_construct);
399
400const struct netdev_class netdev_internal_class =
401 NETDEV_WINDOWS_CLASS(
402 "internal",
403 netdev_windows_internal_construct);