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.
24 #include "fatal-signal.h"
25 #include "netdev-provider.h"
28 #include "poll-loop.h"
32 #include "odp-netlink.h"
33 #include "netlink-socket.h"
36 VLOG_DEFINE_THIS_MODULE(netdev_windows);
37 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
40 VALID_ETHERADDR = 1 << 0,
42 VALID_IFFLAG = 1 << 5,
45 /* Caches the information of a netdev. */
46 struct netdev_windows {
51 unsigned int change_seq;
53 unsigned int cache_valid;
55 uint8_t mac[ETH_ADDR_LEN];
57 unsigned int ifi_flags;
60 /* Utility structure for netdev commands. */
61 struct netdev_windows_netdev_info {
62 /* Generic Netlink header. */
65 /* Information that is relevant to ovs. */
70 /* General information of a network device. */
72 uint8_t mac_address[ETH_ADDR_LEN];
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);
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 netdev_windows_system_construct(struct netdev *netdev_)
139 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
140 uint8_t mac[ETH_ADDR_LEN];
141 struct netdev_windows_netdev_info info;
145 /* Query the attributes and runtime status of the netdev. */
146 ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
152 netdev->change_seq = 1;
153 netdev->dev_type = info.ovs_type;
154 netdev->port_no = info.port_no;
156 memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
157 netdev->cache_valid = VALID_ETHERADDR;
158 netdev->ifindex = -EOPNOTSUPP;
160 netdev->mtu = info.mtu;
161 netdev->cache_valid |= VALID_MTU;
163 netdev->ifi_flags = info.ifi_flags;
164 netdev->cache_valid |= VALID_IFFLAG;
166 VLOG_DBG("construct device %s, ovs_type: %u.",
167 netdev_get_name(&netdev->up), info.ovs_type);
172 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info *info,
175 struct ovs_header *ovs_header;
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);
182 ovs_header = ofpbuf_put_uninit(buf, sizeof *ovs_header);
183 ovs_header->dp_ifindex = info->dp_ifindex;
186 nl_msg_put_string(buf, OVS_WIN_NETDEV_ATTR_NAME, info->name);
194 netdev_windows_info_init(struct netdev_windows_netdev_info *info)
196 memset(info, 0, sizeof *info);
200 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info *info,
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 },
212 struct nlattr *a[ARRAY_SIZE(ovs_netdev_policy)];
213 struct ovs_header *ovs_header;
214 struct nlmsghdr *nlmsg;
215 struct genlmsghdr *genl;
218 netdev_windows_info_init(info);
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))) {
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]);
245 query_netdev(const char *devname,
246 struct netdev_windows_netdev_info *info,
247 struct ofpbuf **bufp)
250 struct ofpbuf *request_buf;
252 ovs_assert(info != NULL);
253 netdev_windows_info_init(info);
255 error = netdev_windows_init_();
259 netdev_windows_info_init(info);
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);
269 ofpbuf_delete(request_buf);
273 error = nl_transact(NETLINK_GENERIC, request_buf, bufp);
274 ofpbuf_delete(request_buf);
278 error = netdev_windows_netdev_from_ofpbuf(info, *bufp);
281 netdev_windows_info_init(info);
282 ofpbuf_delete(*bufp);
291 netdev_windows_destruct(struct netdev *netdev_)
297 netdev_windows_dealloc(struct netdev *netdev_)
299 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
304 netdev_windows_get_etheraddr(const struct netdev *netdev_,
305 uint8_t mac[ETH_ADDR_LEN])
307 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
309 ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
310 if (netdev->cache_valid & VALID_ETHERADDR) {
311 memcpy(mac, netdev->mac, ETH_ADDR_LEN);
319 netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
321 struct netdev_windows *netdev = netdev_windows_cast(netdev_);
323 ovs_assert((netdev->cache_valid & VALID_MTU) != 0);
324 if (netdev->cache_valid & VALID_MTU) {
332 /* This functionality is not really required by the datapath.
333 * But vswitchd bringup expects this to be implemented. */
335 netdev_windows_set_etheraddr(const struct netdev *netdev_,
336 uint8_t mac[ETH_ADDR_LEN])
341 /* We do not really have to update anything in kernel. */
343 netdev_win_set_flag(const char *name, uint32_t flags)
348 /* This functionality is not really required by the datapath.
349 * But vswitchd bringup expects this to be implemented. */
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)
361 netdev_windows_internal_construct(struct netdev *netdev_)
363 return netdev_windows_system_construct(netdev_);
367 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
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, \
379 const struct netdev_class netdev_windows_class =
380 NETDEV_WINDOWS_CLASS(
382 netdev_windows_system_construct);
384 const struct netdev_class netdev_internal_class =
385 NETDEV_WINDOWS_CLASS(
387 netdev_windows_internal_construct);