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"
31 #include "openvswitch/vlog.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 query_netdev(const char *devname
,
78 struct netdev_windows_netdev_info
*reply
,
79 struct ofpbuf
**bufp
);
80 static struct netdev
*netdev_windows_alloc(void);
81 static int netdev_windows_init_(void);
83 /* Generic Netlink family numbers for OVS.
85 * Initialized by netdev_windows_init_(). */
86 static int ovs_win_netdev_family
;
87 struct nl_sock
*ovs_win_netdev_sock
;
91 is_netdev_windows_class(const struct netdev_class
*netdev_class
)
93 return netdev_class
->alloc
== netdev_windows_alloc
;
96 static struct netdev_windows
*
97 netdev_windows_cast(const struct netdev
*netdev_
)
99 ovs_assert(is_netdev_windows_class(netdev_get_class(netdev_
)));
100 return CONTAINER_OF(netdev_
, struct netdev_windows
, up
);
104 netdev_windows_init_(void)
107 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
109 if (ovsthread_once_start(&once
)) {
110 error
= nl_lookup_genl_family(OVS_WIN_NETDEV_FAMILY
,
111 &ovs_win_netdev_family
);
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
);
118 /* XXX: Where to close this socket? */
119 error
= nl_sock_create(NETLINK_GENERIC
, &ovs_win_netdev_sock
);
122 ovsthread_once_done(&once
);
128 static struct netdev
*
129 netdev_windows_alloc(void)
131 struct netdev_windows
*netdev
= xzalloc(sizeof *netdev
);
132 return netdev
? &netdev
->up
: NULL
;
136 dp_to_netdev_ifi_flags(uint32_t dp_flags
)
138 uint32_t nd_flags
= 0;
140 if (dp_flags
&& OVS_WIN_NETDEV_IFF_UP
) {
141 nd_flags
|= NETDEV_UP
;
144 if (dp_flags
&& OVS_WIN_NETDEV_IFF_PROMISC
) {
145 nd_flags
|= NETDEV_PROMISC
;
152 netdev_windows_system_construct(struct netdev
*netdev_
)
154 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
155 uint8_t mac
[ETH_ADDR_LEN
];
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
);
167 netdev
->change_seq
= 1;
168 netdev
->dev_type
= info
.ovs_type
;
169 netdev
->port_no
= info
.port_no
;
171 memcpy(netdev
->mac
, info
.mac_address
, ETH_ADDR_LEN
);
172 netdev
->cache_valid
= VALID_ETHERADDR
;
173 netdev
->ifindex
= -EOPNOTSUPP
;
175 netdev
->mtu
= info
.mtu
;
176 netdev
->cache_valid
|= VALID_MTU
;
178 netdev
->ifi_flags
= dp_to_netdev_ifi_flags(info
.ifi_flags
);
179 netdev
->cache_valid
|= VALID_IFFLAG
;
181 VLOG_DBG("construct device %s, ovs_type: %u.",
182 netdev_get_name(&netdev
->up
), info
.ovs_type
);
187 netdev_windows_netdev_to_ofpbuf(struct netdev_windows_netdev_info
*info
,
190 struct ovs_header
*ovs_header
;
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
);
197 ovs_header
= ofpbuf_put_uninit(buf
, sizeof *ovs_header
);
198 ovs_header
->dp_ifindex
= info
->dp_ifindex
;
201 nl_msg_put_string(buf
, OVS_WIN_NETDEV_ATTR_NAME
, info
->name
);
209 netdev_windows_info_init(struct netdev_windows_netdev_info
*info
)
211 memset(info
, 0, sizeof *info
);
215 netdev_windows_netdev_from_ofpbuf(struct netdev_windows_netdev_info
*info
,
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
},
227 struct nlattr
*a
[ARRAY_SIZE(ovs_netdev_policy
)];
228 struct ovs_header
*ovs_header
;
229 struct nlmsghdr
*nlmsg
;
230 struct genlmsghdr
*genl
;
233 netdev_windows_info_init(info
);
235 ofpbuf_use_const(&b
, buf
->data
, buf
->size
);
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
))) {
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
]);
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
));
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
]);
260 query_netdev(const char *devname
,
261 struct netdev_windows_netdev_info
*info
,
262 struct ofpbuf
**bufp
)
265 struct ofpbuf
*request_buf
;
267 ovs_assert(info
!= NULL
);
268 netdev_windows_info_init(info
);
270 error
= netdev_windows_init_();
274 netdev_windows_info_init(info
);
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
);
284 ofpbuf_delete(request_buf
);
288 error
= nl_transact(NETLINK_GENERIC
, request_buf
, bufp
);
289 ofpbuf_delete(request_buf
);
293 error
= netdev_windows_netdev_from_ofpbuf(info
, *bufp
);
296 netdev_windows_info_init(info
);
297 ofpbuf_delete(*bufp
);
306 netdev_windows_destruct(struct netdev
*netdev_
)
312 netdev_windows_dealloc(struct netdev
*netdev_
)
314 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
319 netdev_windows_get_etheraddr(const struct netdev
*netdev_
,
320 uint8_t mac
[ETH_ADDR_LEN
])
322 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
324 ovs_assert((netdev
->cache_valid
& VALID_ETHERADDR
) != 0);
325 if (netdev
->cache_valid
& VALID_ETHERADDR
) {
326 memcpy(mac
, netdev
->mac
, ETH_ADDR_LEN
);
334 netdev_windows_get_mtu(const struct netdev
*netdev_
, int *mtup
)
336 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
338 ovs_assert((netdev
->cache_valid
& VALID_MTU
) != 0);
339 if (netdev
->cache_valid
& VALID_MTU
) {
347 /* This functionality is not really required by the datapath.
348 * But vswitchd bringup expects this to be implemented. */
350 netdev_windows_set_etheraddr(const struct netdev
*netdev_
,
351 uint8_t mac
[ETH_ADDR_LEN
])
356 /* This functionality is not really required by the datapath.
357 * But vswitchd bringup expects this to be implemented. */
359 netdev_windows_update_flags(struct netdev
*netdev_
,
360 enum netdev_flags off
,
361 enum netdev_flags on
,
362 enum netdev_flags
*old_flagsp
)
364 struct netdev_windows
*netdev
= netdev_windows_cast(netdev_
);
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. */
377 netdev_windows_internal_construct(struct netdev
*netdev_
)
379 return netdev_windows_system_construct(netdev_
);
383 #define NETDEV_WINDOWS_CLASS(NAME, CONSTRUCT) \
386 .alloc = netdev_windows_alloc, \
387 .construct = CONSTRUCT, \
388 .destruct = netdev_windows_destruct, \
389 .dealloc = netdev_windows_dealloc, \
390 .get_etheraddr = netdev_windows_get_etheraddr, \
391 .set_etheraddr = netdev_windows_set_etheraddr, \
392 .update_flags = netdev_windows_update_flags, \
395 const struct netdev_class netdev_windows_class
=
396 NETDEV_WINDOWS_CLASS(
398 netdev_windows_system_construct
);
400 const struct netdev_class netdev_internal_class
=
401 NETDEV_WINDOWS_CLASS(
403 netdev_windows_internal_construct
);