]>
Commit | Line | Data |
---|---|---|
96fba48f | 1 | /* |
856081f6 | 2 | * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. |
96fba48f BP |
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 <config.h> | |
9fe3b9a2 BP |
18 | |
19 | #include "dpif-linux.h" | |
96fba48f BP |
20 | |
21 | #include <assert.h> | |
22 | #include <ctype.h> | |
23 | #include <errno.h> | |
24 | #include <fcntl.h> | |
25 | #include <inttypes.h> | |
26 | #include <net/if.h> | |
b90fa799 | 27 | #include <linux/types.h> |
aae51f53 | 28 | #include <linux/pkt_sched.h> |
e9e28be3 | 29 | #include <linux/rtnetlink.h> |
96fba48f BP |
30 | #include <linux/sockios.h> |
31 | #include <stdlib.h> | |
10dcf8de | 32 | #include <sys/stat.h> |
96fba48f BP |
33 | #include <unistd.h> |
34 | ||
773cd538 | 35 | #include "bitmap.h" |
96fba48f | 36 | #include "dpif-provider.h" |
80e5eed9 | 37 | #include "dynamic-string.h" |
eb8b28e7 | 38 | #include "flow.h" |
3abc4a1a | 39 | #include "netdev.h" |
032aa6a3 | 40 | #include "netdev-linux.h" |
c3827f61 | 41 | #include "netdev-vport.h" |
982b8810 | 42 | #include "netlink-socket.h" |
856081f6 | 43 | #include "netlink.h" |
feebdea2 | 44 | #include "odp-util.h" |
96fba48f | 45 | #include "ofpbuf.h" |
e16a28b5 | 46 | #include "openvswitch/tunnel.h" |
856081f6 | 47 | #include "packets.h" |
96fba48f | 48 | #include "poll-loop.h" |
559843ed | 49 | #include "rtnetlink.h" |
21d6e22e | 50 | #include "rtnetlink-link.h" |
54825e09 | 51 | #include "shash.h" |
b3c01ed3 | 52 | #include "sset.h" |
d6569377 | 53 | #include "unaligned.h" |
96fba48f | 54 | #include "util.h" |
96fba48f | 55 | #include "vlog.h" |
5136ce49 | 56 | |
d98e6007 | 57 | VLOG_DEFINE_THIS_MODULE(dpif_linux); |
96fba48f | 58 | |
773cd538 EJ |
59 | enum { LRU_MAX_PORTS = 1024 }; |
60 | enum { LRU_MASK = LRU_MAX_PORTS - 1}; | |
61 | BUILD_ASSERT_DECL(IS_POW2(LRU_MAX_PORTS)); | |
62 | ||
d6569377 | 63 | struct dpif_linux_dp { |
aaff4b55 BP |
64 | /* Generic Netlink header. */ |
65 | uint8_t cmd; | |
d6569377 | 66 | |
aaff4b55 | 67 | /* struct odp_header. */ |
254f2dc8 | 68 | int dp_ifindex; |
d6569377 BP |
69 | |
70 | /* Attributes. */ | |
71 | const char *name; /* ODP_DP_ATTR_NAME. */ | |
72 | struct odp_stats stats; /* ODP_DP_ATTR_STATS. */ | |
73 | enum odp_frag_handling ipv4_frags; /* ODP_DP_ATTR_IPV4_FRAGS. */ | |
74 | const uint32_t *sampling; /* ODP_DP_ATTR_SAMPLING. */ | |
982b8810 | 75 | uint32_t mcgroups[DPIF_N_UC_TYPES]; /* ODP_DP_ATTR_MCGROUPS. */ |
d6569377 BP |
76 | }; |
77 | ||
78 | static void dpif_linux_dp_init(struct dpif_linux_dp *); | |
aaff4b55 BP |
79 | static int dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *, |
80 | const struct ofpbuf *); | |
81 | static void dpif_linux_dp_dump_start(struct nl_dump *); | |
d6569377 BP |
82 | static int dpif_linux_dp_transact(const struct dpif_linux_dp *request, |
83 | struct dpif_linux_dp *reply, | |
84 | struct ofpbuf **bufp); | |
85 | static int dpif_linux_dp_get(const struct dpif *, struct dpif_linux_dp *reply, | |
86 | struct ofpbuf **bufp); | |
87 | ||
88 | struct dpif_linux_flow { | |
37a1300c BP |
89 | /* Generic Netlink header. */ |
90 | uint8_t cmd; | |
d6569377 | 91 | |
37a1300c | 92 | /* struct odp_header. */ |
d6569377 | 93 | unsigned int nlmsg_flags; |
254f2dc8 | 94 | int dp_ifindex; |
d6569377 BP |
95 | |
96 | /* Attributes. | |
97 | * | |
37a1300c BP |
98 | * The 'stats' and 'used' members point to 64-bit data that might only be |
99 | * aligned on 32-bit boundaries, so get_unaligned_u64() should be used to | |
d2a23af2 BP |
100 | * access their values. |
101 | * | |
102 | * If 'actions' is nonnull then ODP_FLOW_ATTR_ACTIONS will be included in | |
103 | * the Netlink version of the command, even if actions_len is zero. */ | |
d6569377 BP |
104 | const struct nlattr *key; /* ODP_FLOW_ATTR_KEY. */ |
105 | size_t key_len; | |
106 | const struct nlattr *actions; /* ODP_FLOW_ATTR_ACTIONS. */ | |
107 | size_t actions_len; | |
108 | const struct odp_flow_stats *stats; /* ODP_FLOW_ATTR_STATS. */ | |
109 | const uint8_t *tcp_flags; /* ODP_FLOW_ATTR_TCP_FLAGS. */ | |
110 | const uint64_t *used; /* ODP_FLOW_ATTR_USED. */ | |
111 | bool clear; /* ODP_FLOW_ATTR_CLEAR. */ | |
d6569377 BP |
112 | }; |
113 | ||
114 | static void dpif_linux_flow_init(struct dpif_linux_flow *); | |
37a1300c BP |
115 | static int dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *, |
116 | const struct ofpbuf *); | |
117 | static void dpif_linux_flow_to_ofpbuf(const struct dpif_linux_flow *, | |
118 | struct ofpbuf *); | |
d6569377 BP |
119 | static int dpif_linux_flow_transact(const struct dpif_linux_flow *request, |
120 | struct dpif_linux_flow *reply, | |
121 | struct ofpbuf **bufp); | |
122 | static void dpif_linux_flow_get_stats(const struct dpif_linux_flow *, | |
123 | struct dpif_flow_stats *); | |
124 | ||
96fba48f BP |
125 | /* Datapath interface for the openvswitch Linux kernel module. */ |
126 | struct dpif_linux { | |
127 | struct dpif dpif; | |
254f2dc8 | 128 | int dp_ifindex; |
e9e28be3 | 129 | |
982b8810 BP |
130 | /* Multicast group messages. */ |
131 | struct nl_sock *mc_sock; | |
132 | uint32_t mcgroups[DPIF_N_UC_TYPES]; | |
133 | unsigned int listen_mask; | |
134 | ||
e9e28be3 | 135 | /* Change notification. */ |
b3c01ed3 | 136 | struct sset changed_ports; /* Ports that have changed. */ |
46097491 | 137 | struct rtnetlink_notifier port_notifier; |
8b61709d | 138 | bool change_error; |
773cd538 EJ |
139 | |
140 | /* Queue of unused ports. */ | |
141 | unsigned long *lru_bitmap; | |
142 | uint16_t lru_ports[LRU_MAX_PORTS]; | |
143 | size_t lru_head; | |
144 | size_t lru_tail; | |
96fba48f BP |
145 | }; |
146 | ||
147 | static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5); | |
148 | ||
982b8810 | 149 | /* Generic Netlink family numbers for ODP. */ |
aaff4b55 | 150 | static int odp_datapath_family; |
f0fef760 | 151 | static int odp_vport_family; |
37a1300c | 152 | static int odp_flow_family; |
982b8810 BP |
153 | static int odp_packet_family; |
154 | ||
155 | /* Generic Netlink socket. */ | |
156 | static struct nl_sock *genl_sock; | |
157 | ||
158 | static int dpif_linux_init(void); | |
254f2dc8 | 159 | static int open_dpif(const struct dpif_linux_dp *, struct dpif **); |
21d6e22e | 160 | static void dpif_linux_port_changed(const struct rtnetlink_link_change *, |
e9e28be3 | 161 | void *dpif); |
96fba48f | 162 | |
f0fef760 BP |
163 | static void dpif_linux_vport_to_ofpbuf(const struct dpif_linux_vport *, |
164 | struct ofpbuf *); | |
165 | static int dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *, | |
166 | const struct ofpbuf *); | |
167 | ||
96fba48f BP |
168 | static struct dpif_linux * |
169 | dpif_linux_cast(const struct dpif *dpif) | |
170 | { | |
171 | dpif_assert_class(dpif, &dpif_linux_class); | |
172 | return CONTAINER_OF(dpif, struct dpif_linux, dpif); | |
173 | } | |
174 | ||
773cd538 EJ |
175 | static void |
176 | dpif_linux_push_port(struct dpif_linux *dp, uint16_t port) | |
177 | { | |
178 | if (port < LRU_MAX_PORTS && !bitmap_is_set(dp->lru_bitmap, port)) { | |
179 | bitmap_set1(dp->lru_bitmap, port); | |
180 | dp->lru_ports[dp->lru_head++ & LRU_MASK] = port; | |
181 | } | |
182 | } | |
183 | ||
184 | static uint32_t | |
185 | dpif_linux_pop_port(struct dpif_linux *dp) | |
186 | { | |
187 | uint16_t port; | |
188 | ||
189 | if (dp->lru_head == dp->lru_tail) { | |
190 | return UINT32_MAX; | |
191 | } | |
192 | ||
193 | port = dp->lru_ports[dp->lru_tail++ & LRU_MASK]; | |
194 | bitmap_set0(dp->lru_bitmap, port); | |
195 | return port; | |
196 | } | |
197 | ||
d3d22744 | 198 | static int |
d0c23a1a | 199 | dpif_linux_enumerate(struct sset *all_dps) |
d3d22744 | 200 | { |
aaff4b55 BP |
201 | struct nl_dump dump; |
202 | struct ofpbuf msg; | |
aaff4b55 | 203 | int error; |
982b8810 | 204 | |
aaff4b55 BP |
205 | error = dpif_linux_init(); |
206 | if (error) { | |
207 | return error; | |
982b8810 | 208 | } |
d3d22744 | 209 | |
aaff4b55 BP |
210 | dpif_linux_dp_dump_start(&dump); |
211 | while (nl_dump_next(&dump, &msg)) { | |
212 | struct dpif_linux_dp dp; | |
d6569377 | 213 | |
aaff4b55 | 214 | if (!dpif_linux_dp_from_ofpbuf(&dp, &msg)) { |
d0c23a1a | 215 | sset_add(all_dps, dp.name); |
d3d22744 BP |
216 | } |
217 | } | |
aaff4b55 | 218 | return nl_dump_done(&dump); |
d3d22744 BP |
219 | } |
220 | ||
96fba48f | 221 | static int |
4a387741 BP |
222 | dpif_linux_open(const struct dpif_class *class OVS_UNUSED, const char *name, |
223 | bool create, struct dpif **dpifp) | |
96fba48f | 224 | { |
982b8810 | 225 | struct dpif_linux_dp dp_request, dp; |
c19e6535 | 226 | struct ofpbuf *buf; |
c19e6535 | 227 | int error; |
96fba48f | 228 | |
982b8810 BP |
229 | error = dpif_linux_init(); |
230 | if (error) { | |
231 | return error; | |
232 | } | |
233 | ||
982b8810 BP |
234 | /* Create or look up datapath. */ |
235 | dpif_linux_dp_init(&dp_request); | |
aaff4b55 | 236 | dp_request.cmd = create ? ODP_DP_CMD_NEW : ODP_DP_CMD_GET; |
254f2dc8 | 237 | dp_request.name = name; |
982b8810 BP |
238 | error = dpif_linux_dp_transact(&dp_request, &dp, &buf); |
239 | if (error) { | |
240 | return error; | |
c19e6535 | 241 | } |
254f2dc8 | 242 | error = open_dpif(&dp, dpifp); |
c19e6535 | 243 | ofpbuf_delete(buf); |
254f2dc8 | 244 | |
c19e6535 BP |
245 | return error; |
246 | } | |
247 | ||
248 | static int | |
254f2dc8 | 249 | open_dpif(const struct dpif_linux_dp *dp, struct dpif **dpifp) |
c19e6535 | 250 | { |
c19e6535 | 251 | struct dpif_linux *dpif; |
c19e6535 | 252 | int error; |
982b8810 | 253 | int i; |
c19e6535 | 254 | |
c19e6535 BP |
255 | dpif = xmalloc(sizeof *dpif); |
256 | error = rtnetlink_link_notifier_register(&dpif->port_notifier, | |
257 | dpif_linux_port_changed, dpif); | |
258 | if (error) { | |
259 | goto error_free; | |
96fba48f | 260 | } |
c19e6535 | 261 | |
254f2dc8 BP |
262 | dpif_init(&dpif->dpif, &dpif_linux_class, dp->name, |
263 | dp->dp_ifindex, dp->dp_ifindex); | |
c19e6535 | 264 | |
982b8810 BP |
265 | dpif->mc_sock = NULL; |
266 | for (i = 0; i < DPIF_N_UC_TYPES; i++) { | |
267 | dpif->mcgroups[i] = dp->mcgroups[i]; | |
268 | } | |
269 | dpif->listen_mask = 0; | |
254f2dc8 | 270 | dpif->dp_ifindex = dp->dp_ifindex; |
b3c01ed3 | 271 | sset_init(&dpif->changed_ports); |
c19e6535 BP |
272 | dpif->change_error = false; |
273 | *dpifp = &dpif->dpif; | |
274 | ||
773cd538 EJ |
275 | dpif->lru_head = dpif->lru_tail = 0; |
276 | dpif->lru_bitmap = bitmap_allocate(LRU_MAX_PORTS); | |
277 | bitmap_set1(dpif->lru_bitmap, ODPP_LOCAL); | |
278 | for (i = 1; i < LRU_MAX_PORTS; i++) { | |
279 | dpif_linux_push_port(dpif, i); | |
280 | } | |
c19e6535 BP |
281 | return 0; |
282 | ||
283 | error_free: | |
284 | free(dpif); | |
c19e6535 | 285 | return error; |
96fba48f BP |
286 | } |
287 | ||
288 | static void | |
289 | dpif_linux_close(struct dpif *dpif_) | |
290 | { | |
291 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
21d6e22e | 292 | rtnetlink_link_notifier_unregister(&dpif->port_notifier); |
b3c01ed3 | 293 | sset_destroy(&dpif->changed_ports); |
773cd538 | 294 | free(dpif->lru_bitmap); |
96fba48f BP |
295 | free(dpif); |
296 | } | |
297 | ||
298 | static int | |
7dab847a | 299 | dpif_linux_destroy(struct dpif *dpif_) |
96fba48f | 300 | { |
d6569377 BP |
301 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
302 | struct dpif_linux_dp dp; | |
303 | ||
304 | dpif_linux_dp_init(&dp); | |
aaff4b55 | 305 | dp.cmd = ODP_DP_CMD_DEL; |
254f2dc8 | 306 | dp.dp_ifindex = dpif->dp_ifindex; |
d6569377 | 307 | return dpif_linux_dp_transact(&dp, NULL, NULL); |
96fba48f BP |
308 | } |
309 | ||
310 | static int | |
311 | dpif_linux_get_stats(const struct dpif *dpif_, struct odp_stats *stats) | |
312 | { | |
d6569377 BP |
313 | struct dpif_linux_dp dp; |
314 | struct ofpbuf *buf; | |
315 | int error; | |
316 | ||
317 | error = dpif_linux_dp_get(dpif_, &dp, &buf); | |
318 | if (!error) { | |
319 | *stats = dp.stats; | |
320 | ofpbuf_delete(buf); | |
321 | } | |
322 | return error; | |
96fba48f BP |
323 | } |
324 | ||
325 | static int | |
326 | dpif_linux_get_drop_frags(const struct dpif *dpif_, bool *drop_fragsp) | |
327 | { | |
d6569377 BP |
328 | struct dpif_linux_dp dp; |
329 | struct ofpbuf *buf; | |
96fba48f BP |
330 | int error; |
331 | ||
d6569377 | 332 | error = dpif_linux_dp_get(dpif_, &dp, &buf); |
96fba48f | 333 | if (!error) { |
d6569377 BP |
334 | *drop_fragsp = dp.ipv4_frags == ODP_DP_FRAG_DROP; |
335 | ofpbuf_delete(buf); | |
96fba48f BP |
336 | } |
337 | return error; | |
338 | } | |
339 | ||
340 | static int | |
341 | dpif_linux_set_drop_frags(struct dpif *dpif_, bool drop_frags) | |
342 | { | |
d6569377 BP |
343 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
344 | struct dpif_linux_dp dp; | |
345 | ||
346 | dpif_linux_dp_init(&dp); | |
aaff4b55 | 347 | dp.cmd = ODP_DP_CMD_SET; |
254f2dc8 | 348 | dp.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
349 | dp.ipv4_frags = drop_frags ? ODP_DP_FRAG_DROP : ODP_DP_FRAG_ZERO; |
350 | return dpif_linux_dp_transact(&dp, NULL, NULL); | |
96fba48f BP |
351 | } |
352 | ||
353 | static int | |
c19e6535 | 354 | dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev, |
c3827f61 | 355 | uint16_t *port_nop) |
96fba48f | 356 | { |
c19e6535 | 357 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
c3827f61 BP |
358 | const char *name = netdev_get_name(netdev); |
359 | const char *type = netdev_get_type(netdev); | |
c19e6535 BP |
360 | struct dpif_linux_vport request, reply; |
361 | const struct ofpbuf *options; | |
362 | struct ofpbuf *buf; | |
96fba48f BP |
363 | int error; |
364 | ||
c19e6535 | 365 | dpif_linux_vport_init(&request); |
f0fef760 | 366 | request.cmd = ODP_VPORT_CMD_NEW; |
254f2dc8 | 367 | request.dp_ifindex = dpif->dp_ifindex; |
c19e6535 BP |
368 | request.type = netdev_vport_get_vport_type(netdev); |
369 | if (request.type == ODP_VPORT_TYPE_UNSPEC) { | |
c283069c BP |
370 | VLOG_WARN_RL(&error_rl, "%s: cannot create port `%s' because it has " |
371 | "unsupported type `%s'", | |
c19e6535 | 372 | dpif_name(dpif_), name, type); |
c283069c BP |
373 | return EINVAL; |
374 | } | |
c19e6535 | 375 | request.name = name; |
c3827f61 | 376 | |
c19e6535 BP |
377 | options = netdev_vport_get_options(netdev); |
378 | if (options && options->size) { | |
379 | request.options = options->data; | |
380 | request.options_len = options->size; | |
381 | } | |
382 | ||
773cd538 EJ |
383 | /* Loop until we find a port that isn't used. */ |
384 | do { | |
385 | request.port_no = dpif_linux_pop_port(dpif); | |
386 | error = dpif_linux_vport_transact(&request, &reply, &buf); | |
387 | ||
388 | if (!error) { | |
389 | *port_nop = reply.port_no; | |
390 | } | |
c19e6535 | 391 | ofpbuf_delete(buf); |
773cd538 EJ |
392 | } while (request.port_no != UINT32_MAX |
393 | && (error == EBUSY || error == EFBIG)); | |
c3827f61 | 394 | |
96fba48f BP |
395 | return error; |
396 | } | |
397 | ||
398 | static int | |
c19e6535 | 399 | dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no) |
96fba48f | 400 | { |
c19e6535 BP |
401 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
402 | struct dpif_linux_vport vport; | |
773cd538 | 403 | int error; |
c19e6535 BP |
404 | |
405 | dpif_linux_vport_init(&vport); | |
f0fef760 | 406 | vport.cmd = ODP_VPORT_CMD_DEL; |
254f2dc8 | 407 | vport.dp_ifindex = dpif->dp_ifindex; |
c19e6535 | 408 | vport.port_no = port_no; |
773cd538 EJ |
409 | error = dpif_linux_vport_transact(&vport, NULL, NULL); |
410 | ||
411 | if (!error) { | |
412 | dpif_linux_push_port(dpif, port_no); | |
413 | } | |
414 | return error; | |
c3827f61 | 415 | } |
3abc4a1a | 416 | |
c3827f61 | 417 | static int |
4c738a8d BP |
418 | dpif_linux_port_query__(const struct dpif *dpif, uint32_t port_no, |
419 | const char *port_name, struct dpif_port *dpif_port) | |
c3827f61 | 420 | { |
c19e6535 BP |
421 | struct dpif_linux_vport request; |
422 | struct dpif_linux_vport reply; | |
423 | struct ofpbuf *buf; | |
4c738a8d BP |
424 | int error; |
425 | ||
c19e6535 | 426 | dpif_linux_vport_init(&request); |
f0fef760 | 427 | request.cmd = ODP_VPORT_CMD_GET; |
254f2dc8 | 428 | request.dp_ifindex = dpif_linux_cast(dpif)->dp_ifindex; |
c19e6535 BP |
429 | request.port_no = port_no; |
430 | request.name = port_name; | |
4c738a8d | 431 | |
c19e6535 BP |
432 | error = dpif_linux_vport_transact(&request, &reply, &buf); |
433 | if (!error) { | |
434 | dpif_port->name = xstrdup(reply.name); | |
435 | dpif_port->type = xstrdup(netdev_vport_get_netdev_type(&reply)); | |
436 | dpif_port->port_no = reply.port_no; | |
032aa6a3 BP |
437 | if (reply.stats) { |
438 | netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, | |
439 | reply.stats); | |
440 | } else { | |
441 | memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats); | |
442 | } | |
c19e6535 | 443 | ofpbuf_delete(buf); |
3abc4a1a | 444 | } |
c19e6535 | 445 | return error; |
96fba48f BP |
446 | } |
447 | ||
448 | static int | |
c3827f61 | 449 | dpif_linux_port_query_by_number(const struct dpif *dpif, uint16_t port_no, |
4c738a8d | 450 | struct dpif_port *dpif_port) |
96fba48f | 451 | { |
c19e6535 | 452 | return dpif_linux_port_query__(dpif, port_no, NULL, dpif_port); |
96fba48f BP |
453 | } |
454 | ||
455 | static int | |
4c738a8d BP |
456 | dpif_linux_port_query_by_name(const struct dpif *dpif, const char *devname, |
457 | struct dpif_port *dpif_port) | |
96fba48f | 458 | { |
4c738a8d | 459 | return dpif_linux_port_query__(dpif, 0, devname, dpif_port); |
96fba48f BP |
460 | } |
461 | ||
996c1b3d BP |
462 | static int |
463 | dpif_linux_get_max_ports(const struct dpif *dpif OVS_UNUSED) | |
464 | { | |
465 | /* If the datapath increases its range of supported ports, then it should | |
466 | * start reporting that. */ | |
467 | return 1024; | |
468 | } | |
469 | ||
96fba48f BP |
470 | static int |
471 | dpif_linux_flow_flush(struct dpif *dpif_) | |
472 | { | |
9c52546b | 473 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
37a1300c BP |
474 | struct dpif_linux_flow flow; |
475 | ||
476 | dpif_linux_flow_init(&flow); | |
477 | flow.cmd = ODP_FLOW_CMD_DEL; | |
254f2dc8 | 478 | flow.dp_ifindex = dpif->dp_ifindex; |
37a1300c | 479 | return dpif_linux_flow_transact(&flow, NULL, NULL); |
96fba48f BP |
480 | } |
481 | ||
c19e6535 | 482 | struct dpif_linux_port_state { |
f0fef760 | 483 | struct nl_dump dump; |
8522b383 EJ |
484 | unsigned long *port_bitmap; /* Ports in the datapath. */ |
485 | bool complete; /* Dump completed without error. */ | |
c19e6535 BP |
486 | }; |
487 | ||
96fba48f | 488 | static int |
f0fef760 | 489 | dpif_linux_port_dump_start(const struct dpif *dpif_, void **statep) |
96fba48f | 490 | { |
f0fef760 BP |
491 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
492 | struct dpif_linux_port_state *state; | |
493 | struct dpif_linux_vport request; | |
494 | struct ofpbuf *buf; | |
495 | ||
496 | *statep = state = xmalloc(sizeof *state); | |
8522b383 EJ |
497 | state->port_bitmap = bitmap_allocate(LRU_MAX_PORTS); |
498 | state->complete = false; | |
f0fef760 BP |
499 | |
500 | dpif_linux_vport_init(&request); | |
501 | request.cmd = ODP_DP_CMD_GET; | |
254f2dc8 | 502 | request.dp_ifindex = dpif->dp_ifindex; |
f0fef760 BP |
503 | |
504 | buf = ofpbuf_new(1024); | |
505 | dpif_linux_vport_to_ofpbuf(&request, buf); | |
506 | nl_dump_start(&state->dump, genl_sock, buf); | |
507 | ofpbuf_delete(buf); | |
508 | ||
b0ec0f27 BP |
509 | return 0; |
510 | } | |
511 | ||
512 | static int | |
f0fef760 | 513 | dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_, |
4c738a8d | 514 | struct dpif_port *dpif_port) |
b0ec0f27 | 515 | { |
c19e6535 | 516 | struct dpif_linux_port_state *state = state_; |
f0fef760 BP |
517 | struct dpif_linux_vport vport; |
518 | struct ofpbuf buf; | |
96fba48f BP |
519 | int error; |
520 | ||
f0fef760 | 521 | if (!nl_dump_next(&state->dump, &buf)) { |
8522b383 | 522 | state->complete = true; |
f0fef760 BP |
523 | return EOF; |
524 | } | |
c19e6535 | 525 | |
f0fef760 | 526 | error = dpif_linux_vport_from_ofpbuf(&vport, &buf); |
c3827f61 | 527 | if (error) { |
f0fef760 | 528 | return error; |
c3827f61 | 529 | } |
f0fef760 | 530 | |
8522b383 EJ |
531 | if (vport.port_no < LRU_MAX_PORTS) { |
532 | bitmap_set1(state->port_bitmap, vport.port_no); | |
533 | } | |
534 | ||
f0fef760 BP |
535 | dpif_port->name = (char *) vport.name; |
536 | dpif_port->type = (char *) netdev_vport_get_netdev_type(&vport); | |
537 | dpif_port->port_no = vport.port_no; | |
032aa6a3 BP |
538 | if (vport.stats) { |
539 | netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, vport.stats); | |
540 | } else { | |
541 | memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats); | |
542 | } | |
f0fef760 | 543 | return 0; |
b0ec0f27 BP |
544 | } |
545 | ||
546 | static int | |
8522b383 | 547 | dpif_linux_port_dump_done(const struct dpif *dpif_, void *state_) |
b0ec0f27 | 548 | { |
8522b383 | 549 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
c19e6535 | 550 | struct dpif_linux_port_state *state = state_; |
f0fef760 | 551 | int error = nl_dump_done(&state->dump); |
8522b383 EJ |
552 | |
553 | if (state->complete) { | |
554 | uint16_t i; | |
555 | ||
556 | for (i = 0; i < LRU_MAX_PORTS; i++) { | |
557 | if (!bitmap_is_set(state->port_bitmap, i)) { | |
558 | dpif_linux_push_port(dpif, i); | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
563 | free(state->port_bitmap); | |
b0ec0f27 | 564 | free(state); |
f0fef760 | 565 | return error; |
96fba48f BP |
566 | } |
567 | ||
e9e28be3 BP |
568 | static int |
569 | dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep) | |
570 | { | |
571 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
e9e28be3 | 572 | |
8b61709d BP |
573 | if (dpif->change_error) { |
574 | dpif->change_error = false; | |
b3c01ed3 | 575 | sset_clear(&dpif->changed_ports); |
8b61709d | 576 | return ENOBUFS; |
b3c01ed3 BP |
577 | } else if (!sset_is_empty(&dpif->changed_ports)) { |
578 | *devnamep = sset_pop(&dpif->changed_ports); | |
8b61709d | 579 | return 0; |
e9e28be3 | 580 | } else { |
8b61709d | 581 | return EAGAIN; |
e9e28be3 | 582 | } |
e9e28be3 BP |
583 | } |
584 | ||
585 | static void | |
586 | dpif_linux_port_poll_wait(const struct dpif *dpif_) | |
587 | { | |
588 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
b3c01ed3 | 589 | if (!sset_is_empty(&dpif->changed_ports) || dpif->change_error) { |
e9e28be3 BP |
590 | poll_immediate_wake(); |
591 | } else { | |
21d6e22e | 592 | rtnetlink_link_notifier_wait(); |
e9e28be3 BP |
593 | } |
594 | } | |
595 | ||
96fba48f | 596 | static int |
30053024 BP |
597 | dpif_linux_flow_get__(const struct dpif *dpif_, |
598 | const struct nlattr *key, size_t key_len, | |
599 | struct dpif_linux_flow *reply, struct ofpbuf **bufp) | |
96fba48f | 600 | { |
9c52546b | 601 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
30053024 | 602 | struct dpif_linux_flow request; |
feebdea2 | 603 | |
d6569377 | 604 | dpif_linux_flow_init(&request); |
37a1300c | 605 | request.cmd = ODP_FLOW_CMD_GET; |
254f2dc8 | 606 | request.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
607 | request.key = key; |
608 | request.key_len = key_len; | |
30053024 BP |
609 | return dpif_linux_flow_transact(&request, reply, bufp); |
610 | } | |
611 | ||
612 | static int | |
613 | dpif_linux_flow_get(const struct dpif *dpif_, | |
614 | const struct nlattr *key, size_t key_len, | |
615 | struct ofpbuf **actionsp, struct dpif_flow_stats *stats) | |
616 | { | |
617 | struct dpif_linux_flow reply; | |
618 | struct ofpbuf *buf; | |
619 | int error; | |
620 | ||
621 | error = dpif_linux_flow_get__(dpif_, key, key_len, &reply, &buf); | |
feebdea2 BP |
622 | if (!error) { |
623 | if (stats) { | |
d6569377 | 624 | dpif_linux_flow_get_stats(&reply, stats); |
feebdea2 | 625 | } |
d6569377 BP |
626 | if (actionsp) { |
627 | buf->data = (void *) reply.actions; | |
628 | buf->size = reply.actions_len; | |
629 | *actionsp = buf; | |
630 | } else { | |
631 | ofpbuf_delete(buf); | |
feebdea2 BP |
632 | } |
633 | } | |
634 | return error; | |
96fba48f BP |
635 | } |
636 | ||
637 | static int | |
ba25b8f4 | 638 | dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags, |
feebdea2 BP |
639 | const struct nlattr *key, size_t key_len, |
640 | const struct nlattr *actions, size_t actions_len, | |
c97fb132 | 641 | struct dpif_flow_stats *stats) |
96fba48f | 642 | { |
9c52546b | 643 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
d6569377 | 644 | struct dpif_linux_flow request, reply; |
d2a23af2 | 645 | struct nlattr dummy_action; |
d6569377 | 646 | struct ofpbuf *buf; |
feebdea2 BP |
647 | int error; |
648 | ||
d6569377 | 649 | dpif_linux_flow_init(&request); |
37a1300c | 650 | request.cmd = flags & DPIF_FP_CREATE ? ODP_FLOW_CMD_NEW : ODP_FLOW_CMD_SET; |
254f2dc8 | 651 | request.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
652 | request.key = key; |
653 | request.key_len = key_len; | |
d2a23af2 BP |
654 | /* Ensure that ODP_FLOW_ATTR_ACTIONS will always be included. */ |
655 | request.actions = actions ? actions : &dummy_action; | |
d6569377 | 656 | request.actions_len = actions_len; |
ba25b8f4 | 657 | if (flags & DPIF_FP_ZERO_STATS) { |
d6569377 | 658 | request.clear = true; |
ba25b8f4 | 659 | } |
d6569377 BP |
660 | request.nlmsg_flags = flags & DPIF_FP_MODIFY ? 0 : NLM_F_CREATE; |
661 | error = dpif_linux_flow_transact(&request, | |
662 | stats ? &reply : NULL, | |
663 | stats ? &buf : NULL); | |
feebdea2 | 664 | if (!error && stats) { |
d6569377 BP |
665 | dpif_linux_flow_get_stats(&reply, stats); |
666 | ofpbuf_delete(buf); | |
feebdea2 BP |
667 | } |
668 | return error; | |
96fba48f BP |
669 | } |
670 | ||
671 | static int | |
feebdea2 BP |
672 | dpif_linux_flow_del(struct dpif *dpif_, |
673 | const struct nlattr *key, size_t key_len, | |
c97fb132 | 674 | struct dpif_flow_stats *stats) |
96fba48f | 675 | { |
9c52546b | 676 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
d6569377 BP |
677 | struct dpif_linux_flow request, reply; |
678 | struct ofpbuf *buf; | |
feebdea2 BP |
679 | int error; |
680 | ||
d6569377 | 681 | dpif_linux_flow_init(&request); |
37a1300c | 682 | request.cmd = ODP_FLOW_CMD_DEL; |
254f2dc8 | 683 | request.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
684 | request.key = key; |
685 | request.key_len = key_len; | |
686 | error = dpif_linux_flow_transact(&request, | |
687 | stats ? &reply : NULL, | |
688 | stats ? &buf : NULL); | |
feebdea2 | 689 | if (!error && stats) { |
d6569377 BP |
690 | dpif_linux_flow_get_stats(&reply, stats); |
691 | ofpbuf_delete(buf); | |
feebdea2 BP |
692 | } |
693 | return error; | |
96fba48f BP |
694 | } |
695 | ||
feebdea2 | 696 | struct dpif_linux_flow_state { |
37a1300c | 697 | struct nl_dump dump; |
d6569377 | 698 | struct dpif_linux_flow flow; |
c97fb132 | 699 | struct dpif_flow_stats stats; |
30053024 | 700 | struct ofpbuf *buf; |
feebdea2 BP |
701 | }; |
702 | ||
96fba48f | 703 | static int |
37a1300c | 704 | dpif_linux_flow_dump_start(const struct dpif *dpif_, void **statep) |
96fba48f | 705 | { |
37a1300c BP |
706 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
707 | struct dpif_linux_flow_state *state; | |
708 | struct dpif_linux_flow request; | |
709 | struct ofpbuf *buf; | |
710 | ||
711 | *statep = state = xmalloc(sizeof *state); | |
712 | ||
713 | dpif_linux_flow_init(&request); | |
714 | request.cmd = ODP_DP_CMD_GET; | |
254f2dc8 | 715 | request.dp_ifindex = dpif->dp_ifindex; |
37a1300c BP |
716 | |
717 | buf = ofpbuf_new(1024); | |
718 | dpif_linux_flow_to_ofpbuf(&request, buf); | |
719 | nl_dump_start(&state->dump, genl_sock, buf); | |
720 | ofpbuf_delete(buf); | |
721 | ||
30053024 BP |
722 | state->buf = NULL; |
723 | ||
704a1e09 BP |
724 | return 0; |
725 | } | |
726 | ||
727 | static int | |
37a1300c | 728 | dpif_linux_flow_dump_next(const struct dpif *dpif_ OVS_UNUSED, void *state_, |
feebdea2 BP |
729 | const struct nlattr **key, size_t *key_len, |
730 | const struct nlattr **actions, size_t *actions_len, | |
c97fb132 | 731 | const struct dpif_flow_stats **stats) |
704a1e09 | 732 | { |
feebdea2 | 733 | struct dpif_linux_flow_state *state = state_; |
37a1300c | 734 | struct ofpbuf buf; |
96fba48f BP |
735 | int error; |
736 | ||
30053024 BP |
737 | do { |
738 | ofpbuf_delete(state->buf); | |
739 | state->buf = NULL; | |
feebdea2 | 740 | |
30053024 BP |
741 | if (!nl_dump_next(&state->dump, &buf)) { |
742 | return EOF; | |
feebdea2 | 743 | } |
30053024 BP |
744 | |
745 | error = dpif_linux_flow_from_ofpbuf(&state->flow, &buf); | |
746 | if (error) { | |
747 | return error; | |
feebdea2 | 748 | } |
30053024 BP |
749 | |
750 | if (actions && !state->flow.actions) { | |
751 | error = dpif_linux_flow_get__(dpif_, state->flow.key, | |
752 | state->flow.key_len, | |
753 | &state->flow, &state->buf); | |
754 | if (error == ENOENT) { | |
755 | VLOG_DBG("dumped flow disappeared on get"); | |
756 | } else if (error) { | |
757 | VLOG_WARN("error fetching dumped flow: %s", strerror(error)); | |
758 | } | |
feebdea2 | 759 | } |
30053024 BP |
760 | } while (error); |
761 | ||
762 | if (actions) { | |
763 | *actions = state->flow.actions; | |
764 | *actions_len = state->flow.actions_len; | |
765 | } | |
766 | if (key) { | |
767 | *key = state->flow.key; | |
768 | *key_len = state->flow.key_len; | |
769 | } | |
770 | if (stats) { | |
771 | dpif_linux_flow_get_stats(&state->flow, &state->stats); | |
772 | *stats = &state->stats; | |
feebdea2 | 773 | } |
37a1300c | 774 | return error; |
704a1e09 BP |
775 | } |
776 | ||
777 | static int | |
d6569377 | 778 | dpif_linux_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) |
704a1e09 | 779 | { |
d6569377 | 780 | struct dpif_linux_flow_state *state = state_; |
37a1300c | 781 | int error = nl_dump_done(&state->dump); |
30053024 | 782 | ofpbuf_delete(state->buf); |
704a1e09 | 783 | free(state); |
37a1300c | 784 | return error; |
96fba48f BP |
785 | } |
786 | ||
787 | static int | |
eb8b28e7 EJ |
788 | dpif_linux_execute__(int dp_ifindex, |
789 | const struct nlattr *key, size_t key_len, | |
790 | const struct nlattr *actions, size_t actions_len, | |
791 | const struct ofpbuf *packet) | |
96fba48f | 792 | { |
982b8810 | 793 | struct odp_header *execute; |
f7cd0081 BP |
794 | struct ofpbuf *buf; |
795 | int error; | |
796 | ||
797 | buf = ofpbuf_new(128 + actions_len + packet->size); | |
798 | ||
982b8810 BP |
799 | nl_msg_put_genlmsghdr(buf, 0, odp_packet_family, NLM_F_REQUEST, |
800 | ODP_PACKET_CMD_EXECUTE, 1); | |
f7cd0081 | 801 | |
982b8810 | 802 | execute = ofpbuf_put_uninit(buf, sizeof *execute); |
eb8b28e7 | 803 | execute->dp_ifindex = dp_ifindex; |
f7cd0081 | 804 | |
982b8810 | 805 | nl_msg_put_unspec(buf, ODP_PACKET_ATTR_PACKET, packet->data, packet->size); |
80e5eed9 | 806 | nl_msg_put_unspec(buf, ODP_PACKET_ATTR_KEY, key, key_len); |
982b8810 | 807 | nl_msg_put_unspec(buf, ODP_PACKET_ATTR_ACTIONS, actions, actions_len); |
f7cd0081 | 808 | |
982b8810 | 809 | error = nl_sock_transact(genl_sock, buf, NULL); |
f7cd0081 BP |
810 | ofpbuf_delete(buf); |
811 | return error; | |
96fba48f BP |
812 | } |
813 | ||
eb8b28e7 EJ |
814 | static int |
815 | dpif_linux_execute(struct dpif *dpif_, | |
816 | const struct nlattr *key, size_t key_len, | |
817 | const struct nlattr *actions, size_t actions_len, | |
818 | const struct ofpbuf *packet) | |
819 | { | |
820 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
821 | ||
822 | return dpif_linux_execute__(dpif->dp_ifindex, key, key_len, | |
823 | actions, actions_len, packet); | |
824 | } | |
825 | ||
96fba48f BP |
826 | static int |
827 | dpif_linux_recv_get_mask(const struct dpif *dpif_, int *listen_mask) | |
828 | { | |
982b8810 BP |
829 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
830 | *listen_mask = dpif->listen_mask; | |
831 | return 0; | |
96fba48f BP |
832 | } |
833 | ||
834 | static int | |
835 | dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask) | |
836 | { | |
982b8810 BP |
837 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
838 | int error; | |
839 | int i; | |
840 | ||
841 | if (listen_mask == dpif->listen_mask) { | |
842 | return 0; | |
843 | } else if (!listen_mask) { | |
844 | nl_sock_destroy(dpif->mc_sock); | |
845 | dpif->mc_sock = NULL; | |
846 | dpif->listen_mask = 0; | |
847 | return 0; | |
848 | } else if (!dpif->mc_sock) { | |
849 | error = nl_sock_create(NETLINK_GENERIC, &dpif->mc_sock); | |
850 | if (error) { | |
851 | return error; | |
852 | } | |
853 | } | |
854 | ||
855 | /* Unsubscribe from old groups. */ | |
856 | for (i = 0; i < DPIF_N_UC_TYPES; i++) { | |
857 | if (dpif->listen_mask & (1u << i)) { | |
858 | nl_sock_leave_mcgroup(dpif->mc_sock, dpif->mcgroups[i]); | |
859 | } | |
860 | } | |
861 | ||
862 | /* Update listen_mask. */ | |
863 | dpif->listen_mask = listen_mask; | |
864 | ||
865 | /* Subscribe to new groups. */ | |
866 | error = 0; | |
867 | for (i = 0; i < DPIF_N_UC_TYPES; i++) { | |
868 | if (dpif->listen_mask & (1u << i)) { | |
869 | int retval; | |
870 | ||
871 | retval = nl_sock_join_mcgroup(dpif->mc_sock, dpif->mcgroups[i]); | |
872 | if (retval) { | |
873 | error = retval; | |
874 | } | |
875 | } | |
876 | } | |
877 | return error; | |
96fba48f BP |
878 | } |
879 | ||
72b06300 BP |
880 | static int |
881 | dpif_linux_get_sflow_probability(const struct dpif *dpif_, | |
882 | uint32_t *probability) | |
883 | { | |
d6569377 BP |
884 | struct dpif_linux_dp dp; |
885 | struct ofpbuf *buf; | |
886 | int error; | |
887 | ||
888 | error = dpif_linux_dp_get(dpif_, &dp, &buf); | |
889 | if (!error) { | |
890 | *probability = dp.sampling ? *dp.sampling : 0; | |
891 | ofpbuf_delete(buf); | |
892 | } | |
893 | return error; | |
72b06300 BP |
894 | } |
895 | ||
896 | static int | |
897 | dpif_linux_set_sflow_probability(struct dpif *dpif_, uint32_t probability) | |
898 | { | |
d6569377 BP |
899 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); |
900 | struct dpif_linux_dp dp; | |
901 | ||
902 | dpif_linux_dp_init(&dp); | |
aaff4b55 | 903 | dp.cmd = ODP_DP_CMD_SET; |
254f2dc8 | 904 | dp.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
905 | dp.sampling = &probability; |
906 | return dpif_linux_dp_transact(&dp, NULL, NULL); | |
72b06300 BP |
907 | } |
908 | ||
aae51f53 BP |
909 | static int |
910 | dpif_linux_queue_to_priority(const struct dpif *dpif OVS_UNUSED, | |
911 | uint32_t queue_id, uint32_t *priority) | |
912 | { | |
913 | if (queue_id < 0xf000) { | |
17ee3c1f | 914 | *priority = TC_H_MAKE(1 << 16, queue_id + 1); |
aae51f53 BP |
915 | return 0; |
916 | } else { | |
917 | return EINVAL; | |
918 | } | |
919 | } | |
920 | ||
96fba48f | 921 | static int |
982b8810 | 922 | parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall, |
254f2dc8 | 923 | int *dp_ifindex) |
856081f6 BP |
924 | { |
925 | static const struct nl_policy odp_packet_policy[] = { | |
926 | /* Always present. */ | |
856081f6 BP |
927 | [ODP_PACKET_ATTR_PACKET] = { .type = NL_A_UNSPEC, |
928 | .min_len = ETH_HEADER_LEN }, | |
929 | [ODP_PACKET_ATTR_KEY] = { .type = NL_A_NESTED }, | |
930 | ||
982b8810 | 931 | /* ODP_PACKET_CMD_ACTION only. */ |
856081f6 BP |
932 | [ODP_PACKET_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true }, |
933 | ||
982b8810 | 934 | /* ODP_PACKET_CMD_SAMPLE only. */ |
856081f6 BP |
935 | [ODP_PACKET_ATTR_SAMPLE_POOL] = { .type = NL_A_U32, .optional = true }, |
936 | [ODP_PACKET_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true }, | |
937 | }; | |
938 | ||
982b8810 | 939 | struct odp_header *odp_header; |
856081f6 | 940 | struct nlattr *a[ARRAY_SIZE(odp_packet_policy)]; |
982b8810 BP |
941 | struct nlmsghdr *nlmsg; |
942 | struct genlmsghdr *genl; | |
943 | struct ofpbuf b; | |
aaff4b55 | 944 | int type; |
982b8810 BP |
945 | |
946 | ofpbuf_use_const(&b, buf->data, buf->size); | |
947 | ||
948 | nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); | |
949 | genl = ofpbuf_try_pull(&b, sizeof *genl); | |
950 | odp_header = ofpbuf_try_pull(&b, sizeof *odp_header); | |
951 | if (!nlmsg || !genl || !odp_header | |
aaff4b55 | 952 | || nlmsg->nlmsg_type != odp_packet_family |
982b8810 BP |
953 | || !nl_policy_parse(&b, 0, odp_packet_policy, a, |
954 | ARRAY_SIZE(odp_packet_policy))) { | |
856081f6 BP |
955 | return EINVAL; |
956 | } | |
957 | ||
aaff4b55 BP |
958 | type = (genl->cmd == ODP_PACKET_CMD_MISS ? DPIF_UC_MISS |
959 | : genl->cmd == ODP_PACKET_CMD_ACTION ? DPIF_UC_ACTION | |
960 | : genl->cmd == ODP_PACKET_CMD_SAMPLE ? DPIF_UC_SAMPLE | |
961 | : -1); | |
962 | if (type < 0) { | |
963 | return EINVAL; | |
964 | } | |
82272ede | 965 | |
aaff4b55 BP |
966 | memset(upcall, 0, sizeof *upcall); |
967 | upcall->type = type; | |
856081f6 BP |
968 | upcall->packet = buf; |
969 | upcall->packet->data = (void *) nl_attr_get(a[ODP_PACKET_ATTR_PACKET]); | |
970 | upcall->packet->size = nl_attr_get_size(a[ODP_PACKET_ATTR_PACKET]); | |
971 | upcall->key = (void *) nl_attr_get(a[ODP_PACKET_ATTR_KEY]); | |
972 | upcall->key_len = nl_attr_get_size(a[ODP_PACKET_ATTR_KEY]); | |
973 | upcall->userdata = (a[ODP_PACKET_ATTR_USERDATA] | |
974 | ? nl_attr_get_u64(a[ODP_PACKET_ATTR_USERDATA]) | |
975 | : 0); | |
976 | upcall->sample_pool = (a[ODP_PACKET_ATTR_SAMPLE_POOL] | |
977 | ? nl_attr_get_u32(a[ODP_PACKET_ATTR_SAMPLE_POOL]) | |
978 | : 0); | |
979 | if (a[ODP_PACKET_ATTR_ACTIONS]) { | |
980 | upcall->actions = (void *) nl_attr_get(a[ODP_PACKET_ATTR_ACTIONS]); | |
981 | upcall->actions_len = nl_attr_get_size(a[ODP_PACKET_ATTR_ACTIONS]); | |
982 | } | |
983 | ||
254f2dc8 | 984 | *dp_ifindex = odp_header->dp_ifindex; |
982b8810 | 985 | |
856081f6 BP |
986 | return 0; |
987 | } | |
988 | ||
989 | static int | |
990 | dpif_linux_recv(struct dpif *dpif_, struct dpif_upcall *upcall) | |
96fba48f BP |
991 | { |
992 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
993 | struct ofpbuf *buf; | |
96fba48f | 994 | int error; |
982b8810 | 995 | int i; |
96fba48f | 996 | |
982b8810 BP |
997 | if (!dpif->mc_sock) { |
998 | return EAGAIN; | |
999 | } | |
1000 | ||
1001 | for (i = 0; i < 50; i++) { | |
254f2dc8 | 1002 | int dp_ifindex; |
982b8810 BP |
1003 | |
1004 | error = nl_sock_recv(dpif->mc_sock, &buf, false); | |
1005 | if (error) { | |
1006 | return error; | |
96fba48f | 1007 | } |
856081f6 | 1008 | |
254f2dc8 | 1009 | error = parse_odp_packet(buf, upcall, &dp_ifindex); |
982b8810 | 1010 | if (!error |
254f2dc8 | 1011 | && dp_ifindex == dpif->dp_ifindex |
982b8810 BP |
1012 | && dpif->listen_mask & (1u << upcall->type)) { |
1013 | return 0; | |
96fba48f | 1014 | } |
96fba48f | 1015 | |
856081f6 | 1016 | ofpbuf_delete(buf); |
982b8810 BP |
1017 | if (error) { |
1018 | return error; | |
1019 | } | |
856081f6 | 1020 | } |
982b8810 BP |
1021 | |
1022 | return EAGAIN; | |
96fba48f BP |
1023 | } |
1024 | ||
1025 | static void | |
1026 | dpif_linux_recv_wait(struct dpif *dpif_) | |
1027 | { | |
1028 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
982b8810 BP |
1029 | if (dpif->mc_sock) { |
1030 | nl_sock_wait(dpif->mc_sock, POLLIN); | |
1031 | } | |
96fba48f BP |
1032 | } |
1033 | ||
1ba530f4 BP |
1034 | static void |
1035 | dpif_linux_recv_purge(struct dpif *dpif_) | |
1036 | { | |
1037 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
1ba530f4 | 1038 | |
982b8810 BP |
1039 | if (dpif->mc_sock) { |
1040 | nl_sock_drain(dpif->mc_sock); | |
1ba530f4 BP |
1041 | } |
1042 | } | |
1043 | ||
96fba48f | 1044 | const struct dpif_class dpif_linux_class = { |
1a6f1e2a | 1045 | "system", |
d3d22744 | 1046 | dpif_linux_enumerate, |
96fba48f BP |
1047 | dpif_linux_open, |
1048 | dpif_linux_close, | |
7dab847a | 1049 | dpif_linux_destroy, |
640e1b20 BP |
1050 | NULL, /* run */ |
1051 | NULL, /* wait */ | |
96fba48f BP |
1052 | dpif_linux_get_stats, |
1053 | dpif_linux_get_drop_frags, | |
1054 | dpif_linux_set_drop_frags, | |
1055 | dpif_linux_port_add, | |
1056 | dpif_linux_port_del, | |
1057 | dpif_linux_port_query_by_number, | |
1058 | dpif_linux_port_query_by_name, | |
996c1b3d | 1059 | dpif_linux_get_max_ports, |
b0ec0f27 BP |
1060 | dpif_linux_port_dump_start, |
1061 | dpif_linux_port_dump_next, | |
1062 | dpif_linux_port_dump_done, | |
e9e28be3 BP |
1063 | dpif_linux_port_poll, |
1064 | dpif_linux_port_poll_wait, | |
96fba48f BP |
1065 | dpif_linux_flow_get, |
1066 | dpif_linux_flow_put, | |
1067 | dpif_linux_flow_del, | |
1068 | dpif_linux_flow_flush, | |
704a1e09 BP |
1069 | dpif_linux_flow_dump_start, |
1070 | dpif_linux_flow_dump_next, | |
1071 | dpif_linux_flow_dump_done, | |
96fba48f BP |
1072 | dpif_linux_execute, |
1073 | dpif_linux_recv_get_mask, | |
1074 | dpif_linux_recv_set_mask, | |
72b06300 BP |
1075 | dpif_linux_get_sflow_probability, |
1076 | dpif_linux_set_sflow_probability, | |
aae51f53 | 1077 | dpif_linux_queue_to_priority, |
96fba48f BP |
1078 | dpif_linux_recv, |
1079 | dpif_linux_recv_wait, | |
1ba530f4 | 1080 | dpif_linux_recv_purge, |
96fba48f BP |
1081 | }; |
1082 | \f | |
96fba48f | 1083 | static int |
982b8810 | 1084 | dpif_linux_init(void) |
96fba48f | 1085 | { |
982b8810 BP |
1086 | static int error = -1; |
1087 | ||
1088 | if (error < 0) { | |
aaff4b55 BP |
1089 | error = nl_lookup_genl_family(ODP_DATAPATH_FAMILY, |
1090 | &odp_datapath_family); | |
37a1300c BP |
1091 | if (error) { |
1092 | VLOG_ERR("Generic Netlink family '%s' does not exist. " | |
1093 | "The Open vSwitch kernel module is probably not loaded.", | |
1094 | ODP_DATAPATH_FAMILY); | |
1095 | } | |
f0fef760 BP |
1096 | if (!error) { |
1097 | error = nl_lookup_genl_family(ODP_VPORT_FAMILY, &odp_vport_family); | |
1098 | } | |
37a1300c BP |
1099 | if (!error) { |
1100 | error = nl_lookup_genl_family(ODP_FLOW_FAMILY, &odp_flow_family); | |
1101 | } | |
aaff4b55 BP |
1102 | if (!error) { |
1103 | error = nl_lookup_genl_family(ODP_PACKET_FAMILY, | |
1104 | &odp_packet_family); | |
1105 | } | |
982b8810 BP |
1106 | if (!error) { |
1107 | error = nl_sock_create(NETLINK_GENERIC, &genl_sock); | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | return error; | |
96fba48f BP |
1112 | } |
1113 | ||
c19e6535 BP |
1114 | bool |
1115 | dpif_linux_is_internal_device(const char *name) | |
9fe3b9a2 | 1116 | { |
c19e6535 BP |
1117 | struct dpif_linux_vport reply; |
1118 | struct ofpbuf *buf; | |
9fe3b9a2 | 1119 | int error; |
96fba48f | 1120 | |
c19e6535 BP |
1121 | error = dpif_linux_vport_get(name, &reply, &buf); |
1122 | if (!error) { | |
1123 | ofpbuf_delete(buf); | |
141d9ce4 | 1124 | } else if (error != ENODEV && error != ENOENT) { |
c19e6535 BP |
1125 | VLOG_WARN_RL(&error_rl, "%s: vport query failed (%s)", |
1126 | name, strerror(error)); | |
96fba48f BP |
1127 | } |
1128 | ||
c19e6535 | 1129 | return reply.type == ODP_VPORT_TYPE_INTERNAL; |
96fba48f BP |
1130 | } |
1131 | ||
7feba1ac BP |
1132 | int |
1133 | dpif_linux_vport_send(int dp_ifindex, uint32_t port_no, | |
1134 | const void *data, size_t size) | |
1135 | { | |
eb8b28e7 EJ |
1136 | struct ofpbuf actions, key, packet; |
1137 | struct odputil_keybuf keybuf; | |
1138 | struct flow flow; | |
1139 | uint64_t action; | |
7feba1ac | 1140 | |
eb8b28e7 EJ |
1141 | ofpbuf_use_const(&packet, data, size); |
1142 | flow_extract(&packet, htonll(0), 0, &flow); | |
7feba1ac | 1143 | |
eb8b28e7 EJ |
1144 | ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); |
1145 | odp_flow_key_from_flow(&key, &flow); | |
7feba1ac | 1146 | |
eb8b28e7 EJ |
1147 | ofpbuf_use_stack(&actions, &action, sizeof action); |
1148 | nl_msg_put_u32(&actions, ODP_ACTION_ATTR_OUTPUT, port_no); | |
7feba1ac | 1149 | |
eb8b28e7 EJ |
1150 | return dpif_linux_execute__(dp_ifindex, key.data, key.size, |
1151 | actions.data, actions.size, &packet); | |
7feba1ac BP |
1152 | } |
1153 | ||
e9e28be3 | 1154 | static void |
21d6e22e EJ |
1155 | dpif_linux_port_changed(const struct rtnetlink_link_change *change, |
1156 | void *dpif_) | |
e9e28be3 BP |
1157 | { |
1158 | struct dpif_linux *dpif = dpif_; | |
1159 | ||
8b61709d | 1160 | if (change) { |
254f2dc8 | 1161 | if (change->master_ifindex == dpif->dp_ifindex |
8b61709d BP |
1162 | && (change->nlmsg_type == RTM_NEWLINK |
1163 | || change->nlmsg_type == RTM_DELLINK)) | |
1164 | { | |
1165 | /* Our datapath changed, either adding a new port or deleting an | |
1166 | * existing one. */ | |
b3c01ed3 | 1167 | sset_add(&dpif->changed_ports, change->ifname); |
e9e28be3 | 1168 | } |
8b61709d BP |
1169 | } else { |
1170 | dpif->change_error = true; | |
e9e28be3 BP |
1171 | } |
1172 | } | |
c19e6535 | 1173 | \f |
f0fef760 | 1174 | /* Parses the contents of 'buf', which contains a "struct odp_header" followed |
c19e6535 BP |
1175 | * by Netlink attributes, into 'vport'. Returns 0 if successful, otherwise a |
1176 | * positive errno value. | |
1177 | * | |
1178 | * 'vport' will contain pointers into 'buf', so the caller should not free | |
1179 | * 'buf' while 'vport' is still in use. */ | |
1180 | static int | |
1181 | dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *vport, | |
1182 | const struct ofpbuf *buf) | |
1183 | { | |
1184 | static const struct nl_policy odp_vport_policy[] = { | |
1185 | [ODP_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32 }, | |
1186 | [ODP_VPORT_ATTR_TYPE] = { .type = NL_A_U32 }, | |
1187 | [ODP_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ }, | |
1188 | [ODP_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC, | |
1189 | .min_len = sizeof(struct rtnl_link_stats64), | |
1190 | .max_len = sizeof(struct rtnl_link_stats64), | |
1191 | .optional = true }, | |
1192 | [ODP_VPORT_ATTR_ADDRESS] = { .type = NL_A_UNSPEC, | |
1193 | .min_len = ETH_ADDR_LEN, | |
1194 | .max_len = ETH_ADDR_LEN, | |
1195 | .optional = true }, | |
1196 | [ODP_VPORT_ATTR_MTU] = { .type = NL_A_U32, .optional = true }, | |
1197 | [ODP_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = true }, | |
1198 | [ODP_VPORT_ATTR_IFINDEX] = { .type = NL_A_U32, .optional = true }, | |
1199 | [ODP_VPORT_ATTR_IFLINK] = { .type = NL_A_U32, .optional = true }, | |
1200 | }; | |
1201 | ||
c19e6535 | 1202 | struct nlattr *a[ARRAY_SIZE(odp_vport_policy)]; |
f0fef760 BP |
1203 | struct odp_header *odp_header; |
1204 | struct nlmsghdr *nlmsg; | |
1205 | struct genlmsghdr *genl; | |
1206 | struct ofpbuf b; | |
c19e6535 BP |
1207 | |
1208 | dpif_linux_vport_init(vport); | |
1209 | ||
f0fef760 BP |
1210 | ofpbuf_use_const(&b, buf->data, buf->size); |
1211 | nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); | |
1212 | genl = ofpbuf_try_pull(&b, sizeof *genl); | |
1213 | odp_header = ofpbuf_try_pull(&b, sizeof *odp_header); | |
1214 | if (!nlmsg || !genl || !odp_header | |
1215 | || nlmsg->nlmsg_type != odp_vport_family | |
1216 | || !nl_policy_parse(&b, 0, odp_vport_policy, a, | |
1217 | ARRAY_SIZE(odp_vport_policy))) { | |
c19e6535 BP |
1218 | return EINVAL; |
1219 | } | |
c19e6535 | 1220 | |
f0fef760 | 1221 | vport->cmd = genl->cmd; |
254f2dc8 | 1222 | vport->dp_ifindex = odp_header->dp_ifindex; |
c19e6535 BP |
1223 | vport->port_no = nl_attr_get_u32(a[ODP_VPORT_ATTR_PORT_NO]); |
1224 | vport->type = nl_attr_get_u32(a[ODP_VPORT_ATTR_TYPE]); | |
1225 | vport->name = nl_attr_get_string(a[ODP_VPORT_ATTR_NAME]); | |
1226 | if (a[ODP_VPORT_ATTR_STATS]) { | |
1227 | vport->stats = nl_attr_get(a[ODP_VPORT_ATTR_STATS]); | |
1228 | } | |
1229 | if (a[ODP_VPORT_ATTR_ADDRESS]) { | |
1230 | vport->address = nl_attr_get(a[ODP_VPORT_ATTR_ADDRESS]); | |
1231 | } | |
1232 | if (a[ODP_VPORT_ATTR_MTU]) { | |
1233 | vport->mtu = nl_attr_get_u32(a[ODP_VPORT_ATTR_MTU]); | |
f915f1a8 BP |
1234 | } else { |
1235 | vport->mtu = INT_MAX; | |
c19e6535 BP |
1236 | } |
1237 | if (a[ODP_VPORT_ATTR_OPTIONS]) { | |
1238 | vport->options = nl_attr_get(a[ODP_VPORT_ATTR_OPTIONS]); | |
1239 | vport->options_len = nl_attr_get_size(a[ODP_VPORT_ATTR_OPTIONS]); | |
1240 | } | |
1241 | if (a[ODP_VPORT_ATTR_IFINDEX]) { | |
1242 | vport->ifindex = nl_attr_get_u32(a[ODP_VPORT_ATTR_IFINDEX]); | |
1243 | } | |
1244 | if (a[ODP_VPORT_ATTR_IFLINK]) { | |
1245 | vport->iflink = nl_attr_get_u32(a[ODP_VPORT_ATTR_IFLINK]); | |
1246 | } | |
1247 | return 0; | |
1248 | } | |
1249 | ||
f0fef760 | 1250 | /* Appends to 'buf' (which must initially be empty) a "struct odp_header" |
c19e6535 BP |
1251 | * followed by Netlink attributes corresponding to 'vport'. */ |
1252 | static void | |
1253 | dpif_linux_vport_to_ofpbuf(const struct dpif_linux_vport *vport, | |
1254 | struct ofpbuf *buf) | |
1255 | { | |
f0fef760 BP |
1256 | struct odp_header *odp_header; |
1257 | ||
1258 | nl_msg_put_genlmsghdr(buf, 0, odp_vport_family, NLM_F_REQUEST | NLM_F_ECHO, | |
1259 | vport->cmd, 1); | |
c19e6535 | 1260 | |
f0fef760 | 1261 | odp_header = ofpbuf_put_uninit(buf, sizeof *odp_header); |
254f2dc8 | 1262 | odp_header->dp_ifindex = vport->dp_ifindex; |
c19e6535 BP |
1263 | |
1264 | if (vport->port_no != UINT32_MAX) { | |
1265 | nl_msg_put_u32(buf, ODP_VPORT_ATTR_PORT_NO, vport->port_no); | |
1266 | } | |
1267 | ||
1268 | if (vport->type != ODP_VPORT_TYPE_UNSPEC) { | |
1269 | nl_msg_put_u32(buf, ODP_VPORT_ATTR_TYPE, vport->type); | |
1270 | } | |
1271 | ||
1272 | if (vport->name) { | |
1273 | nl_msg_put_string(buf, ODP_VPORT_ATTR_NAME, vport->name); | |
1274 | } | |
1275 | ||
1276 | if (vport->stats) { | |
1277 | nl_msg_put_unspec(buf, ODP_VPORT_ATTR_STATS, | |
1278 | vport->stats, sizeof *vport->stats); | |
1279 | } | |
1280 | ||
1281 | if (vport->address) { | |
1282 | nl_msg_put_unspec(buf, ODP_VPORT_ATTR_ADDRESS, | |
1283 | vport->address, ETH_ADDR_LEN); | |
1284 | } | |
1285 | ||
f915f1a8 | 1286 | if (vport->mtu && vport->mtu != INT_MAX) { |
c19e6535 BP |
1287 | nl_msg_put_u32(buf, ODP_VPORT_ATTR_MTU, vport->mtu); |
1288 | } | |
1289 | ||
1290 | if (vport->options) { | |
1291 | nl_msg_put_nested(buf, ODP_VPORT_ATTR_OPTIONS, | |
1292 | vport->options, vport->options_len); | |
1293 | } | |
1294 | ||
1295 | if (vport->ifindex) { | |
1296 | nl_msg_put_u32(buf, ODP_VPORT_ATTR_IFINDEX, vport->ifindex); | |
1297 | } | |
1298 | ||
1299 | if (vport->iflink) { | |
1300 | nl_msg_put_u32(buf, ODP_VPORT_ATTR_IFLINK, vport->iflink); | |
1301 | } | |
c19e6535 BP |
1302 | } |
1303 | ||
1304 | /* Clears 'vport' to "empty" values. */ | |
1305 | void | |
1306 | dpif_linux_vport_init(struct dpif_linux_vport *vport) | |
1307 | { | |
1308 | memset(vport, 0, sizeof *vport); | |
c19e6535 BP |
1309 | vport->port_no = UINT32_MAX; |
1310 | } | |
1311 | ||
1312 | /* Executes 'request' in the kernel datapath. If the command fails, returns a | |
1313 | * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0 | |
1314 | * without doing anything else. If 'reply' and 'bufp' are nonnull, then the | |
1315 | * result of the command is expected to be an odp_vport also, which is decoded | |
1316 | * and stored in '*reply' and '*bufp'. The caller must free '*bufp' when the | |
1317 | * reply is no longer needed ('reply' will contain pointers into '*bufp'). */ | |
1318 | int | |
1319 | dpif_linux_vport_transact(const struct dpif_linux_vport *request, | |
1320 | struct dpif_linux_vport *reply, | |
1321 | struct ofpbuf **bufp) | |
1322 | { | |
f0fef760 | 1323 | struct ofpbuf *request_buf; |
c19e6535 BP |
1324 | int error; |
1325 | ||
1326 | assert((reply != NULL) == (bufp != NULL)); | |
c19e6535 | 1327 | |
42bb6c72 BP |
1328 | error = dpif_linux_init(); |
1329 | if (error) { | |
1330 | if (reply) { | |
1331 | *bufp = NULL; | |
1332 | dpif_linux_vport_init(reply); | |
1333 | } | |
1334 | return error; | |
1335 | } | |
1336 | ||
f0fef760 BP |
1337 | request_buf = ofpbuf_new(1024); |
1338 | dpif_linux_vport_to_ofpbuf(request, request_buf); | |
1339 | error = nl_sock_transact(genl_sock, request_buf, bufp); | |
1340 | ofpbuf_delete(request_buf); | |
c19e6535 | 1341 | |
f0fef760 BP |
1342 | if (reply) { |
1343 | if (!error) { | |
1344 | error = dpif_linux_vport_from_ofpbuf(reply, *bufp); | |
1345 | } | |
c19e6535 | 1346 | if (error) { |
f0fef760 BP |
1347 | dpif_linux_vport_init(reply); |
1348 | ofpbuf_delete(*bufp); | |
1349 | *bufp = NULL; | |
c19e6535 | 1350 | } |
c19e6535 BP |
1351 | } |
1352 | return error; | |
1353 | } | |
1354 | ||
1355 | /* Obtains information about the kernel vport named 'name' and stores it into | |
1356 | * '*reply' and '*bufp'. The caller must free '*bufp' when the reply is no | |
1357 | * longer needed ('reply' will contain pointers into '*bufp'). */ | |
1358 | int | |
1359 | dpif_linux_vport_get(const char *name, struct dpif_linux_vport *reply, | |
1360 | struct ofpbuf **bufp) | |
1361 | { | |
1362 | struct dpif_linux_vport request; | |
1363 | ||
1364 | dpif_linux_vport_init(&request); | |
f0fef760 | 1365 | request.cmd = ODP_VPORT_CMD_GET; |
c19e6535 BP |
1366 | request.name = name; |
1367 | ||
1368 | return dpif_linux_vport_transact(&request, reply, bufp); | |
1369 | } | |
d6569377 | 1370 | \f |
aaff4b55 BP |
1371 | /* Parses the contents of 'buf', which contains a "struct odp_header" followed |
1372 | * by Netlink attributes, into 'dp'. Returns 0 if successful, otherwise a | |
1373 | * positive errno value. | |
d6569377 BP |
1374 | * |
1375 | * 'dp' will contain pointers into 'buf', so the caller should not free 'buf' | |
1376 | * while 'dp' is still in use. */ | |
1377 | static int | |
1378 | dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const struct ofpbuf *buf) | |
1379 | { | |
1380 | static const struct nl_policy odp_datapath_policy[] = { | |
1381 | [ODP_DP_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ }, | |
1382 | [ODP_DP_ATTR_STATS] = { .type = NL_A_UNSPEC, | |
1383 | .min_len = sizeof(struct odp_stats), | |
1384 | .max_len = sizeof(struct odp_stats), | |
1385 | .optional = true }, | |
1386 | [ODP_DP_ATTR_IPV4_FRAGS] = { .type = NL_A_U32, .optional = true }, | |
1387 | [ODP_DP_ATTR_SAMPLING] = { .type = NL_A_U32, .optional = true }, | |
982b8810 | 1388 | [ODP_DP_ATTR_MCGROUPS] = { .type = NL_A_NESTED, .optional = true }, |
d6569377 BP |
1389 | }; |
1390 | ||
d6569377 | 1391 | struct nlattr *a[ARRAY_SIZE(odp_datapath_policy)]; |
aaff4b55 BP |
1392 | struct odp_header *odp_header; |
1393 | struct nlmsghdr *nlmsg; | |
1394 | struct genlmsghdr *genl; | |
1395 | struct ofpbuf b; | |
d6569377 BP |
1396 | |
1397 | dpif_linux_dp_init(dp); | |
1398 | ||
aaff4b55 BP |
1399 | ofpbuf_use_const(&b, buf->data, buf->size); |
1400 | nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); | |
1401 | genl = ofpbuf_try_pull(&b, sizeof *genl); | |
1402 | odp_header = ofpbuf_try_pull(&b, sizeof *odp_header); | |
1403 | if (!nlmsg || !genl || !odp_header | |
1404 | || nlmsg->nlmsg_type != odp_datapath_family | |
1405 | || !nl_policy_parse(&b, 0, odp_datapath_policy, a, | |
1406 | ARRAY_SIZE(odp_datapath_policy))) { | |
d6569377 BP |
1407 | return EINVAL; |
1408 | } | |
d6569377 | 1409 | |
aaff4b55 | 1410 | dp->cmd = genl->cmd; |
254f2dc8 | 1411 | dp->dp_ifindex = odp_header->dp_ifindex; |
d6569377 BP |
1412 | dp->name = nl_attr_get_string(a[ODP_DP_ATTR_NAME]); |
1413 | if (a[ODP_DP_ATTR_STATS]) { | |
1414 | /* Can't use structure assignment because Netlink doesn't ensure | |
1415 | * sufficient alignment for 64-bit members. */ | |
1416 | memcpy(&dp->stats, nl_attr_get(a[ODP_DP_ATTR_STATS]), | |
1417 | sizeof dp->stats); | |
1418 | } | |
1419 | if (a[ODP_DP_ATTR_IPV4_FRAGS]) { | |
1420 | dp->ipv4_frags = nl_attr_get_u32(a[ODP_DP_ATTR_IPV4_FRAGS]); | |
1421 | } | |
1422 | if (a[ODP_DP_ATTR_SAMPLING]) { | |
1423 | dp->sampling = nl_attr_get(a[ODP_DP_ATTR_SAMPLING]); | |
1424 | } | |
982b8810 BP |
1425 | |
1426 | if (a[ODP_DP_ATTR_MCGROUPS]) { | |
1427 | static const struct nl_policy odp_mcgroup_policy[] = { | |
1428 | [ODP_PACKET_CMD_MISS] = { .type = NL_A_U32, .optional = true }, | |
1429 | [ODP_PACKET_CMD_ACTION] = { .type = NL_A_U32, .optional = true }, | |
1430 | [ODP_PACKET_CMD_SAMPLE] = { .type = NL_A_U32, .optional = true }, | |
1431 | }; | |
1432 | ||
1433 | struct nlattr *mcgroups[ARRAY_SIZE(odp_mcgroup_policy)]; | |
1434 | ||
1435 | if (!nl_parse_nested(a[ODP_DP_ATTR_MCGROUPS], odp_mcgroup_policy, | |
1436 | mcgroups, ARRAY_SIZE(odp_mcgroup_policy))) { | |
1437 | return EINVAL; | |
1438 | } | |
1439 | ||
1440 | if (mcgroups[ODP_PACKET_CMD_MISS]) { | |
1441 | dp->mcgroups[DPIF_UC_MISS] | |
1442 | = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_MISS]); | |
1443 | } | |
1444 | if (mcgroups[ODP_PACKET_CMD_ACTION]) { | |
1445 | dp->mcgroups[DPIF_UC_ACTION] | |
1446 | = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_ACTION]); | |
1447 | } | |
1448 | if (mcgroups[ODP_PACKET_CMD_SAMPLE]) { | |
1449 | dp->mcgroups[DPIF_UC_SAMPLE] | |
1450 | = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_SAMPLE]); | |
1451 | } | |
1452 | } | |
1453 | ||
d6569377 BP |
1454 | return 0; |
1455 | } | |
1456 | ||
aaff4b55 | 1457 | /* Appends to 'buf' the Generic Netlink message described by 'dp'. */ |
d6569377 BP |
1458 | static void |
1459 | dpif_linux_dp_to_ofpbuf(const struct dpif_linux_dp *dp, struct ofpbuf *buf) | |
1460 | { | |
aaff4b55 | 1461 | struct odp_header *odp_header; |
d6569377 | 1462 | |
aaff4b55 BP |
1463 | nl_msg_put_genlmsghdr(buf, 0, odp_datapath_family, |
1464 | NLM_F_REQUEST | NLM_F_ECHO, dp->cmd, 1); | |
1465 | ||
1466 | odp_header = ofpbuf_put_uninit(buf, sizeof *odp_header); | |
254f2dc8 | 1467 | odp_header->dp_ifindex = dp->dp_ifindex; |
d6569377 BP |
1468 | |
1469 | if (dp->name) { | |
1470 | nl_msg_put_string(buf, ODP_DP_ATTR_NAME, dp->name); | |
1471 | } | |
1472 | ||
1473 | /* Skip ODP_DP_ATTR_STATS since we never have a reason to serialize it. */ | |
1474 | ||
1475 | if (dp->ipv4_frags) { | |
1476 | nl_msg_put_u32(buf, ODP_DP_ATTR_IPV4_FRAGS, dp->ipv4_frags); | |
1477 | } | |
1478 | ||
1479 | if (dp->sampling) { | |
1480 | nl_msg_put_u32(buf, ODP_DP_ATTR_SAMPLING, *dp->sampling); | |
1481 | } | |
d6569377 BP |
1482 | } |
1483 | ||
1484 | /* Clears 'dp' to "empty" values. */ | |
d3d8f1f7 | 1485 | static void |
d6569377 BP |
1486 | dpif_linux_dp_init(struct dpif_linux_dp *dp) |
1487 | { | |
1488 | memset(dp, 0, sizeof *dp); | |
d6569377 BP |
1489 | } |
1490 | ||
aaff4b55 BP |
1491 | static void |
1492 | dpif_linux_dp_dump_start(struct nl_dump *dump) | |
1493 | { | |
1494 | struct dpif_linux_dp request; | |
1495 | struct ofpbuf *buf; | |
1496 | ||
1497 | dpif_linux_dp_init(&request); | |
1498 | request.cmd = ODP_DP_CMD_GET; | |
1499 | ||
1500 | buf = ofpbuf_new(1024); | |
1501 | dpif_linux_dp_to_ofpbuf(&request, buf); | |
1502 | nl_dump_start(dump, genl_sock, buf); | |
1503 | ofpbuf_delete(buf); | |
1504 | } | |
1505 | ||
d6569377 BP |
1506 | /* Executes 'request' in the kernel datapath. If the command fails, returns a |
1507 | * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0 | |
1508 | * without doing anything else. If 'reply' and 'bufp' are nonnull, then the | |
aaff4b55 BP |
1509 | * result of the command is expected to be of the same form, which is decoded |
1510 | * and stored in '*reply' and '*bufp'. The caller must free '*bufp' when the | |
1511 | * reply is no longer needed ('reply' will contain pointers into '*bufp'). */ | |
d3d8f1f7 | 1512 | static int |
d6569377 BP |
1513 | dpif_linux_dp_transact(const struct dpif_linux_dp *request, |
1514 | struct dpif_linux_dp *reply, struct ofpbuf **bufp) | |
1515 | { | |
aaff4b55 | 1516 | struct ofpbuf *request_buf; |
d6569377 | 1517 | int error; |
d6569377 BP |
1518 | |
1519 | assert((reply != NULL) == (bufp != NULL)); | |
1520 | ||
aaff4b55 BP |
1521 | request_buf = ofpbuf_new(1024); |
1522 | dpif_linux_dp_to_ofpbuf(request, request_buf); | |
1523 | error = nl_sock_transact(genl_sock, request_buf, bufp); | |
1524 | ofpbuf_delete(request_buf); | |
d6569377 | 1525 | |
aaff4b55 BP |
1526 | if (reply) { |
1527 | if (!error) { | |
1528 | error = dpif_linux_dp_from_ofpbuf(reply, *bufp); | |
1529 | } | |
d6569377 | 1530 | if (error) { |
aaff4b55 BP |
1531 | dpif_linux_dp_init(reply); |
1532 | ofpbuf_delete(*bufp); | |
1533 | *bufp = NULL; | |
d6569377 | 1534 | } |
d6569377 BP |
1535 | } |
1536 | return error; | |
1537 | } | |
1538 | ||
1539 | /* Obtains information about 'dpif_' and stores it into '*reply' and '*bufp'. | |
1540 | * The caller must free '*bufp' when the reply is no longer needed ('reply' | |
1541 | * will contain pointers into '*bufp'). */ | |
d3d8f1f7 | 1542 | static int |
d6569377 BP |
1543 | dpif_linux_dp_get(const struct dpif *dpif_, struct dpif_linux_dp *reply, |
1544 | struct ofpbuf **bufp) | |
1545 | { | |
1546 | struct dpif_linux *dpif = dpif_linux_cast(dpif_); | |
1547 | struct dpif_linux_dp request; | |
1548 | ||
1549 | dpif_linux_dp_init(&request); | |
aaff4b55 | 1550 | request.cmd = ODP_DP_CMD_GET; |
254f2dc8 | 1551 | request.dp_ifindex = dpif->dp_ifindex; |
d6569377 BP |
1552 | |
1553 | return dpif_linux_dp_transact(&request, reply, bufp); | |
1554 | } | |
1555 | \f | |
37a1300c BP |
1556 | /* Parses the contents of 'buf', which contains a "struct odp_header" followed |
1557 | * by Netlink attributes, into 'flow'. Returns 0 if successful, otherwise a | |
d6569377 BP |
1558 | * positive errno value. |
1559 | * | |
1560 | * 'flow' will contain pointers into 'buf', so the caller should not free 'buf' | |
1561 | * while 'flow' is still in use. */ | |
1562 | static int | |
1563 | dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *flow, | |
1564 | const struct ofpbuf *buf) | |
1565 | { | |
1566 | static const struct nl_policy odp_flow_policy[] = { | |
1567 | [ODP_FLOW_ATTR_KEY] = { .type = NL_A_NESTED }, | |
1568 | [ODP_FLOW_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true }, | |
1569 | [ODP_FLOW_ATTR_STATS] = { .type = NL_A_UNSPEC, | |
1570 | .min_len = sizeof(struct odp_flow_stats), | |
1571 | .max_len = sizeof(struct odp_flow_stats), | |
1572 | .optional = true }, | |
1573 | [ODP_FLOW_ATTR_TCP_FLAGS] = { .type = NL_A_U8, .optional = true }, | |
1574 | [ODP_FLOW_ATTR_USED] = { .type = NL_A_U64, .optional = true }, | |
1575 | /* The kernel never uses ODP_FLOW_ATTR_CLEAR. */ | |
d6569377 BP |
1576 | }; |
1577 | ||
d6569377 | 1578 | struct nlattr *a[ARRAY_SIZE(odp_flow_policy)]; |
37a1300c BP |
1579 | struct odp_header *odp_header; |
1580 | struct nlmsghdr *nlmsg; | |
1581 | struct genlmsghdr *genl; | |
1582 | struct ofpbuf b; | |
d6569377 BP |
1583 | |
1584 | dpif_linux_flow_init(flow); | |
1585 | ||
37a1300c BP |
1586 | ofpbuf_use_const(&b, buf->data, buf->size); |
1587 | nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); | |
1588 | genl = ofpbuf_try_pull(&b, sizeof *genl); | |
1589 | odp_header = ofpbuf_try_pull(&b, sizeof *odp_header); | |
1590 | if (!nlmsg || !genl || !odp_header | |
1591 | || nlmsg->nlmsg_type != odp_flow_family | |
1592 | || !nl_policy_parse(&b, 0, odp_flow_policy, a, | |
1593 | ARRAY_SIZE(odp_flow_policy))) { | |
d6569377 BP |
1594 | return EINVAL; |
1595 | } | |
d6569377 | 1596 | |
37a1300c | 1597 | flow->nlmsg_flags = nlmsg->nlmsg_flags; |
254f2dc8 | 1598 | flow->dp_ifindex = odp_header->dp_ifindex; |
d6569377 BP |
1599 | flow->key = nl_attr_get(a[ODP_FLOW_ATTR_KEY]); |
1600 | flow->key_len = nl_attr_get_size(a[ODP_FLOW_ATTR_KEY]); | |
1601 | if (a[ODP_FLOW_ATTR_ACTIONS]) { | |
1602 | flow->actions = nl_attr_get(a[ODP_FLOW_ATTR_ACTIONS]); | |
1603 | flow->actions_len = nl_attr_get_size(a[ODP_FLOW_ATTR_ACTIONS]); | |
1604 | } | |
1605 | if (a[ODP_FLOW_ATTR_STATS]) { | |
1606 | flow->stats = nl_attr_get(a[ODP_FLOW_ATTR_STATS]); | |
1607 | } | |
1608 | if (a[ODP_FLOW_ATTR_TCP_FLAGS]) { | |
1609 | flow->tcp_flags = nl_attr_get(a[ODP_FLOW_ATTR_TCP_FLAGS]); | |
1610 | } | |
9e980142 JG |
1611 | if (a[ODP_FLOW_ATTR_USED]) { |
1612 | flow->used = nl_attr_get(a[ODP_FLOW_ATTR_USED]); | |
1613 | } | |
d6569377 BP |
1614 | return 0; |
1615 | } | |
1616 | ||
37a1300c | 1617 | /* Appends to 'buf' (which must initially be empty) a "struct odp_header" |
d6569377 BP |
1618 | * followed by Netlink attributes corresponding to 'flow'. */ |
1619 | static void | |
1620 | dpif_linux_flow_to_ofpbuf(const struct dpif_linux_flow *flow, | |
1621 | struct ofpbuf *buf) | |
1622 | { | |
37a1300c | 1623 | struct odp_header *odp_header; |
d6569377 | 1624 | |
37a1300c | 1625 | nl_msg_put_genlmsghdr(buf, 0, odp_flow_family, |
f9ef1c31 JG |
1626 | NLM_F_REQUEST | NLM_F_ECHO | flow->nlmsg_flags, |
1627 | flow->cmd, 1); | |
37a1300c BP |
1628 | |
1629 | odp_header = ofpbuf_put_uninit(buf, sizeof *odp_header); | |
254f2dc8 | 1630 | odp_header->dp_ifindex = flow->dp_ifindex; |
d6569377 BP |
1631 | |
1632 | if (flow->key_len) { | |
1633 | nl_msg_put_unspec(buf, ODP_FLOW_ATTR_KEY, flow->key, flow->key_len); | |
1634 | } | |
1635 | ||
d2a23af2 | 1636 | if (flow->actions || flow->actions_len) { |
d6569377 BP |
1637 | nl_msg_put_unspec(buf, ODP_FLOW_ATTR_ACTIONS, |
1638 | flow->actions, flow->actions_len); | |
1639 | } | |
1640 | ||
1641 | /* We never need to send these to the kernel. */ | |
1642 | assert(!flow->stats); | |
1643 | assert(!flow->tcp_flags); | |
1644 | assert(!flow->used); | |
1645 | ||
1646 | if (flow->clear) { | |
1647 | nl_msg_put_flag(buf, ODP_FLOW_ATTR_CLEAR); | |
1648 | } | |
d6569377 BP |
1649 | } |
1650 | ||
1651 | /* Clears 'flow' to "empty" values. */ | |
d3d8f1f7 | 1652 | static void |
d6569377 BP |
1653 | dpif_linux_flow_init(struct dpif_linux_flow *flow) |
1654 | { | |
1655 | memset(flow, 0, sizeof *flow); | |
1656 | } | |
1657 | ||
1658 | /* Executes 'request' in the kernel datapath. If the command fails, returns a | |
1659 | * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0 | |
1660 | * without doing anything else. If 'reply' and 'bufp' are nonnull, then the | |
37a1300c BP |
1661 | * result of the command is expected to be a flow also, which is decoded and |
1662 | * stored in '*reply' and '*bufp'. The caller must free '*bufp' when the reply | |
1663 | * is no longer needed ('reply' will contain pointers into '*bufp'). */ | |
d3d8f1f7 | 1664 | static int |
d6569377 BP |
1665 | dpif_linux_flow_transact(const struct dpif_linux_flow *request, |
1666 | struct dpif_linux_flow *reply, struct ofpbuf **bufp) | |
1667 | { | |
37a1300c | 1668 | struct ofpbuf *request_buf; |
d6569377 | 1669 | int error; |
d6569377 BP |
1670 | |
1671 | assert((reply != NULL) == (bufp != NULL)); | |
1672 | ||
37a1300c BP |
1673 | request_buf = ofpbuf_new(1024); |
1674 | dpif_linux_flow_to_ofpbuf(request, request_buf); | |
1675 | error = nl_sock_transact(genl_sock, request_buf, bufp); | |
1676 | ofpbuf_delete(request_buf); | |
d6569377 | 1677 | |
37a1300c BP |
1678 | if (reply) { |
1679 | if (!error) { | |
1680 | error = dpif_linux_flow_from_ofpbuf(reply, *bufp); | |
1681 | } | |
d6569377 | 1682 | if (error) { |
37a1300c BP |
1683 | dpif_linux_flow_init(reply); |
1684 | ofpbuf_delete(*bufp); | |
1685 | *bufp = NULL; | |
d6569377 | 1686 | } |
d6569377 BP |
1687 | } |
1688 | return error; | |
1689 | } | |
1690 | ||
1691 | static void | |
1692 | dpif_linux_flow_get_stats(const struct dpif_linux_flow *flow, | |
1693 | struct dpif_flow_stats *stats) | |
1694 | { | |
1695 | if (flow->stats) { | |
1696 | stats->n_packets = get_unaligned_u64(&flow->stats->n_packets); | |
1697 | stats->n_bytes = get_unaligned_u64(&flow->stats->n_bytes); | |
1698 | } else { | |
1699 | stats->n_packets = 0; | |
1700 | stats->n_bytes = 0; | |
1701 | } | |
1702 | stats->used = flow->used ? get_unaligned_u64(flow->used) : 0; | |
1703 | stats->tcp_flags = flow->tcp_flags ? *flow->tcp_flags : 0; | |
1704 | } | |
c19e6535 | 1705 |