]>
Commit | Line | Data |
---|---|---|
72865317 | 1 | /* |
e0edde6f | 2 | * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. |
72865317 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> | |
18 | #include "dpif.h" | |
19 | ||
72865317 BP |
20 | #include <ctype.h> |
21 | #include <errno.h> | |
22 | #include <fcntl.h> | |
23 | #include <inttypes.h> | |
72865317 | 24 | #include <netinet/in.h> |
9d82ec47 | 25 | #include <sys/socket.h> |
7f3adc00 | 26 | #include <net/if.h> |
cdee00fd | 27 | #include <stdint.h> |
72865317 BP |
28 | #include <stdlib.h> |
29 | #include <string.h> | |
30 | #include <sys/ioctl.h> | |
31 | #include <sys/stat.h> | |
72865317 BP |
32 | #include <unistd.h> |
33 | ||
34 | #include "csum.h" | |
614c4892 | 35 | #include "dpif.h" |
72865317 | 36 | #include "dpif-provider.h" |
614c4892 | 37 | #include "dummy.h" |
36956a7d | 38 | #include "dynamic-string.h" |
72865317 BP |
39 | #include "flow.h" |
40 | #include "hmap.h" | |
41 | #include "list.h" | |
42 | #include "netdev.h" | |
cdee00fd | 43 | #include "netlink.h" |
72865317 BP |
44 | #include "odp-util.h" |
45 | #include "ofp-print.h" | |
46 | #include "ofpbuf.h" | |
47 | #include "packets.h" | |
48 | #include "poll-loop.h" | |
26c6b6cd | 49 | #include "random.h" |
462278db | 50 | #include "shash.h" |
0cbfe35d | 51 | #include "sset.h" |
72865317 BP |
52 | #include "timeval.h" |
53 | #include "util.h" | |
72865317 | 54 | #include "vlog.h" |
5136ce49 | 55 | |
d98e6007 | 56 | VLOG_DEFINE_THIS_MODULE(dpif_netdev); |
72865317 BP |
57 | |
58 | /* Configuration parameters. */ | |
72865317 BP |
59 | enum { MAX_PORTS = 256 }; /* Maximum number of ports. */ |
60 | enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */ | |
61 | ||
62 | /* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP | |
63 | * headers to be aligned on a 4-byte boundary. */ | |
64 | enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; | |
65 | ||
856081f6 BP |
66 | /* Queues. */ |
67 | enum { N_QUEUES = 2 }; /* Number of queues for dpif_recv(). */ | |
68 | enum { MAX_QUEUE_LEN = 128 }; /* Maximum number of packets per queue. */ | |
69 | enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 }; | |
70 | BUILD_ASSERT_DECL(IS_POW2(MAX_QUEUE_LEN)); | |
71 | ||
d88b629b BP |
72 | struct dp_netdev_upcall { |
73 | struct dpif_upcall upcall; /* Queued upcall information. */ | |
74 | struct ofpbuf buf; /* ofpbuf instance for upcall.packet. */ | |
75 | }; | |
76 | ||
856081f6 | 77 | struct dp_netdev_queue { |
d88b629b | 78 | struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN]; |
856081f6 BP |
79 | unsigned int head, tail; |
80 | }; | |
81 | ||
72865317 BP |
82 | /* Datapath based on the network device interface from netdev.h. */ |
83 | struct dp_netdev { | |
614c4892 | 84 | const struct dpif_class *class; |
462278db | 85 | char *name; |
72865317 | 86 | int open_cnt; |
7dab847a | 87 | bool destroyed; |
72865317 | 88 | |
856081f6 | 89 | struct dp_netdev_queue queues[N_QUEUES]; |
72865317 | 90 | struct hmap flow_table; /* Flow table. */ |
72865317 BP |
91 | |
92 | /* Statistics. */ | |
72865317 BP |
93 | long long int n_hit; /* Number of flow table matches. */ |
94 | long long int n_missed; /* Number of flow table misses. */ | |
95 | long long int n_lost; /* Number of misses not passed to client. */ | |
96 | ||
97 | /* Ports. */ | |
72865317 BP |
98 | struct dp_netdev_port *ports[MAX_PORTS]; |
99 | struct list port_list; | |
100 | unsigned int serial; | |
101 | }; | |
102 | ||
103 | /* A port in a netdev-based datapath. */ | |
104 | struct dp_netdev_port { | |
105 | int port_no; /* Index into dp_netdev's 'ports'. */ | |
106 | struct list node; /* Element in dp_netdev's 'port_list'. */ | |
107 | struct netdev *netdev; | |
0cbfe35d | 108 | char *type; /* Port type as requested by user. */ |
72865317 BP |
109 | }; |
110 | ||
111 | /* A flow in dp_netdev's 'flow_table'. */ | |
112 | struct dp_netdev_flow { | |
113 | struct hmap_node node; /* Element in dp_netdev's 'flow_table'. */ | |
14608a15 | 114 | struct flow key; |
72865317 BP |
115 | |
116 | /* Statistics. */ | |
c97fb132 | 117 | long long int used; /* Last used time, in monotonic msecs. */ |
2105ccc8 BP |
118 | long long int packet_count; /* Number of packets matched. */ |
119 | long long int byte_count; /* Number of bytes matched. */ | |
7c808e39 | 120 | uint8_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */ |
72865317 BP |
121 | |
122 | /* Actions. */ | |
cdee00fd | 123 | struct nlattr *actions; |
cf22f8cb | 124 | size_t actions_len; |
72865317 BP |
125 | }; |
126 | ||
127 | /* Interface to netdev-based datapath. */ | |
128 | struct dpif_netdev { | |
129 | struct dpif dpif; | |
130 | struct dp_netdev *dp; | |
72865317 BP |
131 | unsigned int dp_serial; |
132 | }; | |
133 | ||
134 | /* All netdev-based datapaths. */ | |
462278db | 135 | static struct shash dp_netdevs = SHASH_INITIALIZER(&dp_netdevs); |
72865317 BP |
136 | |
137 | /* Maximum port MTU seen so far. */ | |
138 | static int max_mtu = ETH_PAYLOAD_MAX; | |
139 | ||
9b56fe13 | 140 | static int get_port_by_number(struct dp_netdev *, uint32_t port_no, |
72865317 BP |
141 | struct dp_netdev_port **portp); |
142 | static int get_port_by_name(struct dp_netdev *, const char *devname, | |
143 | struct dp_netdev_port **portp); | |
144 | static void dp_netdev_free(struct dp_netdev *); | |
145 | static void dp_netdev_flow_flush(struct dp_netdev *); | |
c3827f61 | 146 | static int do_add_port(struct dp_netdev *, const char *devname, |
9b56fe13 JP |
147 | const char *type, uint32_t port_no); |
148 | static int do_del_port(struct dp_netdev *, uint32_t port_no); | |
614c4892 BP |
149 | static int dpif_netdev_open(const struct dpif_class *, const char *name, |
150 | bool create, struct dpif **); | |
b85d8d61 | 151 | static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *, |
856081f6 BP |
152 | int queue_no, const struct flow *, |
153 | uint64_t arg); | |
4edb9ae9 PS |
154 | static void dp_netdev_execute_actions(struct dp_netdev *, |
155 | struct ofpbuf *, struct flow *, | |
156 | const struct nlattr *actions, | |
157 | size_t actions_len); | |
72865317 BP |
158 | |
159 | static struct dpif_netdev * | |
160 | dpif_netdev_cast(const struct dpif *dpif) | |
161 | { | |
cb22974d | 162 | ovs_assert(dpif->dpif_class->open == dpif_netdev_open); |
72865317 BP |
163 | return CONTAINER_OF(dpif, struct dpif_netdev, dpif); |
164 | } | |
165 | ||
166 | static struct dp_netdev * | |
167 | get_dp_netdev(const struct dpif *dpif) | |
168 | { | |
169 | return dpif_netdev_cast(dpif)->dp; | |
170 | } | |
171 | ||
2197d7ab GL |
172 | static int |
173 | dpif_netdev_enumerate(struct sset *all_dps) | |
174 | { | |
175 | struct shash_node *node; | |
176 | ||
177 | SHASH_FOR_EACH(node, &dp_netdevs) { | |
178 | sset_add(all_dps, node->name); | |
179 | } | |
180 | return 0; | |
181 | } | |
182 | ||
add90f6f EJ |
183 | static bool |
184 | dpif_netdev_class_is_dummy(const struct dpif_class *class) | |
185 | { | |
186 | return class != &dpif_netdev_class; | |
187 | } | |
188 | ||
0aeaabc8 JP |
189 | static const char * |
190 | dpif_netdev_port_open_type(const struct dpif_class *class, const char *type) | |
191 | { | |
192 | return strcmp(type, "internal") ? type | |
add90f6f | 193 | : dpif_netdev_class_is_dummy(class) ? "dummy" |
0aeaabc8 JP |
194 | : "tap"; |
195 | } | |
196 | ||
72865317 BP |
197 | static struct dpif * |
198 | create_dpif_netdev(struct dp_netdev *dp) | |
199 | { | |
462278db | 200 | uint16_t netflow_id = hash_string(dp->name, 0); |
72865317 | 201 | struct dpif_netdev *dpif; |
72865317 BP |
202 | |
203 | dp->open_cnt++; | |
204 | ||
72865317 | 205 | dpif = xmalloc(sizeof *dpif); |
614c4892 | 206 | dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, netflow_id); |
72865317 | 207 | dpif->dp = dp; |
72865317 | 208 | dpif->dp_serial = dp->serial; |
72865317 BP |
209 | |
210 | return &dpif->dpif; | |
211 | } | |
212 | ||
e44768b7 JP |
213 | static int |
214 | choose_port(struct dp_netdev *dp, const char *name) | |
215 | { | |
216 | int port_no; | |
217 | ||
218 | if (dp->class != &dpif_netdev_class) { | |
219 | const char *p; | |
220 | int start_no = 0; | |
221 | ||
222 | /* If the port name begins with "br", start the number search at | |
223 | * 100 to make writing tests easier. */ | |
224 | if (!strncmp(name, "br", 2)) { | |
225 | start_no = 100; | |
226 | } | |
227 | ||
228 | /* If the port name contains a number, try to assign that port number. | |
229 | * This can make writing unit tests easier because port numbers are | |
230 | * predictable. */ | |
231 | for (p = name; *p != '\0'; p++) { | |
232 | if (isdigit((unsigned char) *p)) { | |
233 | port_no = start_no + strtol(p, NULL, 10); | |
234 | if (port_no > 0 && port_no < MAX_PORTS | |
235 | && !dp->ports[port_no]) { | |
236 | return port_no; | |
237 | } | |
238 | break; | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | for (port_no = 1; port_no < MAX_PORTS; port_no++) { | |
244 | if (!dp->ports[port_no]) { | |
245 | return port_no; | |
246 | } | |
247 | } | |
248 | ||
249 | return -1; | |
250 | } | |
251 | ||
72865317 | 252 | static int |
614c4892 BP |
253 | create_dp_netdev(const char *name, const struct dpif_class *class, |
254 | struct dp_netdev **dpp) | |
72865317 BP |
255 | { |
256 | struct dp_netdev *dp; | |
257 | int error; | |
258 | int i; | |
259 | ||
462278db | 260 | dp = xzalloc(sizeof *dp); |
614c4892 | 261 | dp->class = class; |
462278db | 262 | dp->name = xstrdup(name); |
72865317 | 263 | dp->open_cnt = 0; |
72865317 | 264 | for (i = 0; i < N_QUEUES; i++) { |
856081f6 | 265 | dp->queues[i].head = dp->queues[i].tail = 0; |
72865317 BP |
266 | } |
267 | hmap_init(&dp->flow_table); | |
72865317 | 268 | list_init(&dp->port_list); |
e44768b7 | 269 | |
29c743b6 | 270 | error = do_add_port(dp, name, "internal", OVSP_LOCAL); |
72865317 BP |
271 | if (error) { |
272 | dp_netdev_free(dp); | |
462278db | 273 | return error; |
72865317 BP |
274 | } |
275 | ||
462278db BP |
276 | shash_add(&dp_netdevs, name, dp); |
277 | ||
278 | *dpp = dp; | |
72865317 BP |
279 | return 0; |
280 | } | |
281 | ||
282 | static int | |
614c4892 | 283 | dpif_netdev_open(const struct dpif_class *class, const char *name, |
4a387741 | 284 | bool create, struct dpif **dpifp) |
72865317 | 285 | { |
462278db BP |
286 | struct dp_netdev *dp; |
287 | ||
288 | dp = shash_find_data(&dp_netdevs, name); | |
289 | if (!dp) { | |
290 | if (!create) { | |
291 | return ENODEV; | |
72865317 | 292 | } else { |
614c4892 | 293 | int error = create_dp_netdev(name, class, &dp); |
462278db BP |
294 | if (error) { |
295 | return error; | |
72865317 | 296 | } |
cb22974d | 297 | ovs_assert(dp != NULL); |
72865317 BP |
298 | } |
299 | } else { | |
614c4892 BP |
300 | if (dp->class != class) { |
301 | return EINVAL; | |
302 | } else if (create) { | |
462278db | 303 | return EEXIST; |
72865317 BP |
304 | } |
305 | } | |
462278db BP |
306 | |
307 | *dpifp = create_dpif_netdev(dp); | |
308 | return 0; | |
72865317 BP |
309 | } |
310 | ||
311 | static void | |
1ba530f4 | 312 | dp_netdev_purge_queues(struct dp_netdev *dp) |
72865317 BP |
313 | { |
314 | int i; | |
315 | ||
72865317 | 316 | for (i = 0; i < N_QUEUES; i++) { |
856081f6 | 317 | struct dp_netdev_queue *q = &dp->queues[i]; |
856081f6 | 318 | |
1ba530f4 | 319 | while (q->tail != q->head) { |
d88b629b BP |
320 | struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK]; |
321 | ofpbuf_uninit(&u->buf); | |
856081f6 | 322 | } |
72865317 | 323 | } |
1ba530f4 BP |
324 | } |
325 | ||
326 | static void | |
327 | dp_netdev_free(struct dp_netdev *dp) | |
328 | { | |
4ad28026 BP |
329 | struct dp_netdev_port *port, *next; |
330 | ||
1ba530f4 | 331 | dp_netdev_flow_flush(dp); |
4ad28026 | 332 | LIST_FOR_EACH_SAFE (port, next, node, &dp->port_list) { |
1ba530f4 BP |
333 | do_del_port(dp, port->port_no); |
334 | } | |
335 | dp_netdev_purge_queues(dp); | |
72865317 | 336 | hmap_destroy(&dp->flow_table); |
462278db | 337 | free(dp->name); |
72865317 BP |
338 | free(dp); |
339 | } | |
340 | ||
341 | static void | |
342 | dpif_netdev_close(struct dpif *dpif) | |
343 | { | |
344 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
cb22974d | 345 | ovs_assert(dp->open_cnt > 0); |
7dab847a | 346 | if (--dp->open_cnt == 0 && dp->destroyed) { |
462278db | 347 | shash_find_and_delete(&dp_netdevs, dp->name); |
72865317 BP |
348 | dp_netdev_free(dp); |
349 | } | |
350 | free(dpif); | |
351 | } | |
352 | ||
353 | static int | |
7dab847a | 354 | dpif_netdev_destroy(struct dpif *dpif) |
72865317 BP |
355 | { |
356 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
7dab847a | 357 | dp->destroyed = true; |
72865317 BP |
358 | return 0; |
359 | } | |
360 | ||
361 | static int | |
a8d9304d | 362 | dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats) |
72865317 BP |
363 | { |
364 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
f180c2e2 | 365 | stats->n_flows = hmap_count(&dp->flow_table); |
72865317 BP |
366 | stats->n_hit = dp->n_hit; |
367 | stats->n_missed = dp->n_missed; | |
368 | stats->n_lost = dp->n_lost; | |
72865317 BP |
369 | return 0; |
370 | } | |
371 | ||
72865317 | 372 | static int |
c3827f61 | 373 | do_add_port(struct dp_netdev *dp, const char *devname, const char *type, |
9b56fe13 | 374 | uint32_t port_no) |
72865317 | 375 | { |
72865317 BP |
376 | struct dp_netdev_port *port; |
377 | struct netdev *netdev; | |
0cbfe35d | 378 | const char *open_type; |
72865317 BP |
379 | int mtu; |
380 | int error; | |
381 | ||
382 | /* XXX reject devices already in some dp_netdev. */ | |
383 | ||
384 | /* Open and validate network device. */ | |
0aeaabc8 | 385 | open_type = dpif_netdev_port_open_type(dp->class, type); |
0cbfe35d | 386 | error = netdev_open(devname, open_type, &netdev); |
72865317 BP |
387 | if (error) { |
388 | return error; | |
389 | } | |
390 | /* XXX reject loopback devices */ | |
391 | /* XXX reject non-Ethernet devices */ | |
392 | ||
7b6b0ef4 | 393 | error = netdev_listen(netdev); |
add90f6f EJ |
394 | if (error |
395 | && !(error == EOPNOTSUPP && dpif_netdev_class_is_dummy(dp->class))) { | |
7b6b0ef4 BP |
396 | VLOG_ERR("%s: cannot receive packets on this network device (%s)", |
397 | devname, strerror(errno)); | |
398 | netdev_close(netdev); | |
399 | return error; | |
400 | } | |
401 | ||
72865317 BP |
402 | error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, false); |
403 | if (error) { | |
404 | netdev_close(netdev); | |
405 | return error; | |
406 | } | |
407 | ||
408 | port = xmalloc(sizeof *port); | |
409 | port->port_no = port_no; | |
410 | port->netdev = netdev; | |
0cbfe35d | 411 | port->type = xstrdup(type); |
72865317 | 412 | |
9b020780 PS |
413 | error = netdev_get_mtu(netdev, &mtu); |
414 | if (!error) { | |
72865317 BP |
415 | max_mtu = mtu; |
416 | } | |
417 | ||
418 | list_push_back(&dp->port_list, &port->node); | |
419 | dp->ports[port_no] = port; | |
72865317 BP |
420 | dp->serial++; |
421 | ||
422 | return 0; | |
423 | } | |
424 | ||
247527db BP |
425 | static int |
426 | dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev, | |
9b56fe13 | 427 | uint32_t *port_nop) |
247527db BP |
428 | { |
429 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
430 | int port_no; | |
431 | ||
9b56fe13 | 432 | if (*port_nop != UINT32_MAX) { |
232dfa4a JP |
433 | if (*port_nop >= MAX_PORTS) { |
434 | return EFBIG; | |
435 | } else if (dp->ports[*port_nop]) { | |
436 | return EBUSY; | |
437 | } | |
438 | port_no = *port_nop; | |
439 | } else { | |
e44768b7 | 440 | port_no = choose_port(dp, netdev_get_name(netdev)); |
232dfa4a | 441 | } |
247527db BP |
442 | if (port_no >= 0) { |
443 | *port_nop = port_no; | |
444 | return do_add_port(dp, netdev_get_name(netdev), | |
445 | netdev_get_type(netdev), port_no); | |
446 | } | |
3c71830a | 447 | return EFBIG; |
72865317 BP |
448 | } |
449 | ||
450 | static int | |
9b56fe13 | 451 | dpif_netdev_port_del(struct dpif *dpif, uint32_t port_no) |
72865317 BP |
452 | { |
453 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
df2c07f4 | 454 | return port_no == OVSP_LOCAL ? EINVAL : do_del_port(dp, port_no); |
72865317 BP |
455 | } |
456 | ||
457 | static bool | |
9b56fe13 | 458 | is_valid_port_number(uint32_t port_no) |
72865317 BP |
459 | { |
460 | return port_no < MAX_PORTS; | |
461 | } | |
462 | ||
463 | static int | |
464 | get_port_by_number(struct dp_netdev *dp, | |
9b56fe13 | 465 | uint32_t port_no, struct dp_netdev_port **portp) |
72865317 BP |
466 | { |
467 | if (!is_valid_port_number(port_no)) { | |
468 | *portp = NULL; | |
469 | return EINVAL; | |
470 | } else { | |
471 | *portp = dp->ports[port_no]; | |
472 | return *portp ? 0 : ENOENT; | |
473 | } | |
474 | } | |
475 | ||
476 | static int | |
477 | get_port_by_name(struct dp_netdev *dp, | |
478 | const char *devname, struct dp_netdev_port **portp) | |
479 | { | |
480 | struct dp_netdev_port *port; | |
481 | ||
4e8e4213 | 482 | LIST_FOR_EACH (port, node, &dp->port_list) { |
72865317 BP |
483 | if (!strcmp(netdev_get_name(port->netdev), devname)) { |
484 | *portp = port; | |
485 | return 0; | |
486 | } | |
487 | } | |
488 | return ENOENT; | |
489 | } | |
490 | ||
491 | static int | |
9b56fe13 | 492 | do_del_port(struct dp_netdev *dp, uint32_t port_no) |
72865317 BP |
493 | { |
494 | struct dp_netdev_port *port; | |
6c88d577 | 495 | char *name; |
72865317 BP |
496 | int error; |
497 | ||
498 | error = get_port_by_number(dp, port_no, &port); | |
499 | if (error) { | |
500 | return error; | |
501 | } | |
502 | ||
503 | list_remove(&port->node); | |
504 | dp->ports[port->port_no] = NULL; | |
72865317 BP |
505 | dp->serial++; |
506 | ||
6c88d577 | 507 | name = xstrdup(netdev_get_name(port->netdev)); |
72865317 | 508 | netdev_close(port->netdev); |
0cbfe35d | 509 | free(port->type); |
149f577a | 510 | |
6c88d577 | 511 | free(name); |
72865317 BP |
512 | free(port); |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
517 | static void | |
4c738a8d BP |
518 | answer_port_query(const struct dp_netdev_port *port, |
519 | struct dpif_port *dpif_port) | |
72865317 | 520 | { |
4c738a8d | 521 | dpif_port->name = xstrdup(netdev_get_name(port->netdev)); |
0cbfe35d | 522 | dpif_port->type = xstrdup(port->type); |
4c738a8d | 523 | dpif_port->port_no = port->port_no; |
72865317 BP |
524 | } |
525 | ||
526 | static int | |
9b56fe13 | 527 | dpif_netdev_port_query_by_number(const struct dpif *dpif, uint32_t port_no, |
4c738a8d | 528 | struct dpif_port *dpif_port) |
72865317 BP |
529 | { |
530 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
531 | struct dp_netdev_port *port; | |
532 | int error; | |
533 | ||
534 | error = get_port_by_number(dp, port_no, &port); | |
4afba28d | 535 | if (!error && dpif_port) { |
4c738a8d | 536 | answer_port_query(port, dpif_port); |
72865317 BP |
537 | } |
538 | return error; | |
539 | } | |
540 | ||
541 | static int | |
542 | dpif_netdev_port_query_by_name(const struct dpif *dpif, const char *devname, | |
4c738a8d | 543 | struct dpif_port *dpif_port) |
72865317 BP |
544 | { |
545 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
546 | struct dp_netdev_port *port; | |
547 | int error; | |
548 | ||
549 | error = get_port_by_name(dp, devname, &port); | |
4afba28d | 550 | if (!error && dpif_port) { |
4c738a8d | 551 | answer_port_query(port, dpif_port); |
72865317 BP |
552 | } |
553 | return error; | |
554 | } | |
555 | ||
996c1b3d BP |
556 | static int |
557 | dpif_netdev_get_max_ports(const struct dpif *dpif OVS_UNUSED) | |
558 | { | |
559 | return MAX_PORTS; | |
560 | } | |
561 | ||
72865317 BP |
562 | static void |
563 | dp_netdev_free_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow) | |
564 | { | |
565 | hmap_remove(&dp->flow_table, &flow->node); | |
566 | free(flow->actions); | |
567 | free(flow); | |
568 | } | |
569 | ||
570 | static void | |
571 | dp_netdev_flow_flush(struct dp_netdev *dp) | |
572 | { | |
573 | struct dp_netdev_flow *flow, *next; | |
574 | ||
4e8e4213 | 575 | HMAP_FOR_EACH_SAFE (flow, next, node, &dp->flow_table) { |
72865317 BP |
576 | dp_netdev_free_flow(dp, flow); |
577 | } | |
578 | } | |
579 | ||
580 | static int | |
581 | dpif_netdev_flow_flush(struct dpif *dpif) | |
582 | { | |
583 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
584 | dp_netdev_flow_flush(dp); | |
585 | return 0; | |
586 | } | |
587 | ||
b0ec0f27 BP |
588 | struct dp_netdev_port_state { |
589 | uint32_t port_no; | |
4c738a8d | 590 | char *name; |
b0ec0f27 BP |
591 | }; |
592 | ||
593 | static int | |
594 | dpif_netdev_port_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep) | |
595 | { | |
596 | *statep = xzalloc(sizeof(struct dp_netdev_port_state)); | |
597 | return 0; | |
598 | } | |
599 | ||
72865317 | 600 | static int |
b0ec0f27 | 601 | dpif_netdev_port_dump_next(const struct dpif *dpif, void *state_, |
4c738a8d | 602 | struct dpif_port *dpif_port) |
72865317 | 603 | { |
b0ec0f27 | 604 | struct dp_netdev_port_state *state = state_; |
72865317 | 605 | struct dp_netdev *dp = get_dp_netdev(dpif); |
b0ec0f27 | 606 | uint32_t port_no; |
72865317 | 607 | |
b0ec0f27 BP |
608 | for (port_no = state->port_no; port_no < MAX_PORTS; port_no++) { |
609 | struct dp_netdev_port *port = dp->ports[port_no]; | |
610 | if (port) { | |
4c738a8d BP |
611 | free(state->name); |
612 | state->name = xstrdup(netdev_get_name(port->netdev)); | |
613 | dpif_port->name = state->name; | |
0cbfe35d | 614 | dpif_port->type = port->type; |
4c738a8d | 615 | dpif_port->port_no = port->port_no; |
b0ec0f27 BP |
616 | state->port_no = port_no + 1; |
617 | return 0; | |
72865317 | 618 | } |
72865317 | 619 | } |
b0ec0f27 BP |
620 | return EOF; |
621 | } | |
622 | ||
623 | static int | |
4c738a8d | 624 | dpif_netdev_port_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) |
b0ec0f27 | 625 | { |
4c738a8d BP |
626 | struct dp_netdev_port_state *state = state_; |
627 | free(state->name); | |
b0ec0f27 BP |
628 | free(state); |
629 | return 0; | |
72865317 BP |
630 | } |
631 | ||
632 | static int | |
67a4917b | 633 | dpif_netdev_port_poll(const struct dpif *dpif_, char **devnamep OVS_UNUSED) |
72865317 BP |
634 | { |
635 | struct dpif_netdev *dpif = dpif_netdev_cast(dpif_); | |
636 | if (dpif->dp_serial != dpif->dp->serial) { | |
637 | dpif->dp_serial = dpif->dp->serial; | |
638 | return ENOBUFS; | |
639 | } else { | |
640 | return EAGAIN; | |
641 | } | |
642 | } | |
643 | ||
644 | static void | |
645 | dpif_netdev_port_poll_wait(const struct dpif *dpif_) | |
646 | { | |
647 | struct dpif_netdev *dpif = dpif_netdev_cast(dpif_); | |
648 | if (dpif->dp_serial != dpif->dp->serial) { | |
649 | poll_immediate_wake(); | |
650 | } | |
651 | } | |
652 | ||
72865317 | 653 | static struct dp_netdev_flow * |
14608a15 | 654 | dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct flow *key) |
72865317 BP |
655 | { |
656 | struct dp_netdev_flow *flow; | |
657 | ||
4e8e4213 | 658 | HMAP_FOR_EACH_WITH_HASH (flow, node, flow_hash(key, 0), &dp->flow_table) { |
72865317 BP |
659 | if (flow_equal(&flow->key, key)) { |
660 | return flow; | |
661 | } | |
662 | } | |
663 | return NULL; | |
664 | } | |
665 | ||
666 | static void | |
c97fb132 | 667 | get_dpif_flow_stats(struct dp_netdev_flow *flow, struct dpif_flow_stats *stats) |
feebdea2 BP |
668 | { |
669 | stats->n_packets = flow->packet_count; | |
670 | stats->n_bytes = flow->byte_count; | |
c97fb132 | 671 | stats->used = flow->used; |
734ec5ec | 672 | stats->tcp_flags = flow->tcp_flags; |
72865317 BP |
673 | } |
674 | ||
36956a7d BP |
675 | static int |
676 | dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, | |
677 | struct flow *flow) | |
678 | { | |
0135dc8b | 679 | if (odp_flow_key_to_flow(key, key_len, flow) != ODP_FIT_PERFECT) { |
36956a7d BP |
680 | /* This should not happen: it indicates that odp_flow_key_from_flow() |
681 | * and odp_flow_key_to_flow() disagree on the acceptable form of a | |
682 | * flow. Log the problem as an error, with enough details to enable | |
683 | * debugging. */ | |
684 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
685 | ||
686 | if (!VLOG_DROP_ERR(&rl)) { | |
687 | struct ds s; | |
688 | ||
689 | ds_init(&s); | |
690 | odp_flow_key_format(key, key_len, &s); | |
691 | VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s)); | |
692 | ds_destroy(&s); | |
693 | } | |
694 | ||
695 | return EINVAL; | |
696 | } | |
697 | ||
18886b60 BP |
698 | if (flow->in_port < OFPP_MAX |
699 | ? flow->in_port >= MAX_PORTS | |
700 | : flow->in_port != OFPP_LOCAL && flow->in_port != OFPP_NONE) { | |
701 | return EINVAL; | |
702 | } | |
703 | ||
36956a7d BP |
704 | return 0; |
705 | } | |
706 | ||
72865317 | 707 | static int |
693c4a01 | 708 | dpif_netdev_flow_get(const struct dpif *dpif, |
feebdea2 | 709 | const struct nlattr *nl_key, size_t nl_key_len, |
c97fb132 | 710 | struct ofpbuf **actionsp, struct dpif_flow_stats *stats) |
72865317 BP |
711 | { |
712 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
bc4a05c6 BP |
713 | struct dp_netdev_flow *flow; |
714 | struct flow key; | |
715 | int error; | |
36956a7d | 716 | |
feebdea2 | 717 | error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key); |
bc4a05c6 BP |
718 | if (error) { |
719 | return error; | |
720 | } | |
14608a15 | 721 | |
bc4a05c6 BP |
722 | flow = dp_netdev_lookup_flow(dp, &key); |
723 | if (!flow) { | |
724 | return ENOENT; | |
72865317 | 725 | } |
bc4a05c6 | 726 | |
feebdea2 | 727 | if (stats) { |
c97fb132 | 728 | get_dpif_flow_stats(flow, stats); |
feebdea2 BP |
729 | } |
730 | if (actionsp) { | |
731 | *actionsp = ofpbuf_clone_data(flow->actions, flow->actions_len); | |
732 | } | |
72865317 BP |
733 | return 0; |
734 | } | |
735 | ||
72865317 | 736 | static int |
feebdea2 BP |
737 | set_flow_actions(struct dp_netdev_flow *flow, |
738 | const struct nlattr *actions, size_t actions_len) | |
72865317 | 739 | { |
feebdea2 BP |
740 | flow->actions = xrealloc(flow->actions, actions_len); |
741 | flow->actions_len = actions_len; | |
742 | memcpy(flow->actions, actions, actions_len); | |
72865317 BP |
743 | return 0; |
744 | } | |
745 | ||
746 | static int | |
e1fef0f9 AS |
747 | dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *key, |
748 | const struct nlattr *actions, size_t actions_len) | |
72865317 | 749 | { |
72865317 BP |
750 | struct dp_netdev_flow *flow; |
751 | int error; | |
752 | ||
ec6fde61 | 753 | flow = xzalloc(sizeof *flow); |
36956a7d | 754 | flow->key = *key; |
72865317 | 755 | |
feebdea2 | 756 | error = set_flow_actions(flow, actions, actions_len); |
72865317 BP |
757 | if (error) { |
758 | free(flow); | |
759 | return error; | |
760 | } | |
761 | ||
762 | hmap_insert(&dp->flow_table, &flow->node, flow_hash(&flow->key, 0)); | |
763 | return 0; | |
764 | } | |
765 | ||
766 | static void | |
767 | clear_stats(struct dp_netdev_flow *flow) | |
768 | { | |
c97fb132 | 769 | flow->used = 0; |
72865317 BP |
770 | flow->packet_count = 0; |
771 | flow->byte_count = 0; | |
734ec5ec | 772 | flow->tcp_flags = 0; |
72865317 BP |
773 | } |
774 | ||
775 | static int | |
89625d1e | 776 | dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) |
72865317 BP |
777 | { |
778 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
779 | struct dp_netdev_flow *flow; | |
14608a15 | 780 | struct flow key; |
36956a7d BP |
781 | int error; |
782 | ||
89625d1e | 783 | error = dpif_netdev_flow_from_nlattrs(put->key, put->key_len, &key); |
36956a7d BP |
784 | if (error) { |
785 | return error; | |
786 | } | |
72865317 | 787 | |
14608a15 | 788 | flow = dp_netdev_lookup_flow(dp, &key); |
72865317 | 789 | if (!flow) { |
89625d1e | 790 | if (put->flags & DPIF_FP_CREATE) { |
72865317 | 791 | if (hmap_count(&dp->flow_table) < MAX_FLOWS) { |
89625d1e BP |
792 | if (put->stats) { |
793 | memset(put->stats, 0, sizeof *put->stats); | |
feebdea2 | 794 | } |
e1fef0f9 AS |
795 | return dp_netdev_flow_add(dp, &key, put->actions, |
796 | put->actions_len); | |
72865317 | 797 | } else { |
3c71830a | 798 | return EFBIG; |
72865317 BP |
799 | } |
800 | } else { | |
801 | return ENOENT; | |
802 | } | |
803 | } else { | |
89625d1e BP |
804 | if (put->flags & DPIF_FP_MODIFY) { |
805 | int error = set_flow_actions(flow, put->actions, put->actions_len); | |
feebdea2 | 806 | if (!error) { |
89625d1e BP |
807 | if (put->stats) { |
808 | get_dpif_flow_stats(flow, put->stats); | |
feebdea2 | 809 | } |
89625d1e | 810 | if (put->flags & DPIF_FP_ZERO_STATS) { |
feebdea2 BP |
811 | clear_stats(flow); |
812 | } | |
72865317 BP |
813 | } |
814 | return error; | |
815 | } else { | |
816 | return EEXIST; | |
817 | } | |
818 | } | |
819 | } | |
820 | ||
72865317 | 821 | static int |
b99d3cee | 822 | dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del) |
72865317 BP |
823 | { |
824 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
825 | struct dp_netdev_flow *flow; | |
14608a15 | 826 | struct flow key; |
36956a7d BP |
827 | int error; |
828 | ||
b99d3cee | 829 | error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key); |
36956a7d BP |
830 | if (error) { |
831 | return error; | |
832 | } | |
72865317 | 833 | |
14608a15 | 834 | flow = dp_netdev_lookup_flow(dp, &key); |
72865317 | 835 | if (flow) { |
b99d3cee BP |
836 | if (del->stats) { |
837 | get_dpif_flow_stats(flow, del->stats); | |
feebdea2 | 838 | } |
72865317 BP |
839 | dp_netdev_free_flow(dp, flow); |
840 | return 0; | |
841 | } else { | |
842 | return ENOENT; | |
843 | } | |
844 | } | |
845 | ||
704a1e09 BP |
846 | struct dp_netdev_flow_state { |
847 | uint32_t bucket; | |
848 | uint32_t offset; | |
feebdea2 | 849 | struct nlattr *actions; |
19cf4069 | 850 | struct odputil_keybuf keybuf; |
c97fb132 | 851 | struct dpif_flow_stats stats; |
704a1e09 BP |
852 | }; |
853 | ||
72865317 | 854 | static int |
704a1e09 | 855 | dpif_netdev_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep) |
72865317 | 856 | { |
feebdea2 BP |
857 | struct dp_netdev_flow_state *state; |
858 | ||
859 | *statep = state = xmalloc(sizeof *state); | |
860 | state->bucket = 0; | |
861 | state->offset = 0; | |
862 | state->actions = NULL; | |
704a1e09 BP |
863 | return 0; |
864 | } | |
865 | ||
866 | static int | |
867 | dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_, | |
feebdea2 BP |
868 | const struct nlattr **key, size_t *key_len, |
869 | const struct nlattr **actions, size_t *actions_len, | |
c97fb132 | 870 | const struct dpif_flow_stats **stats) |
704a1e09 BP |
871 | { |
872 | struct dp_netdev_flow_state *state = state_; | |
72865317 BP |
873 | struct dp_netdev *dp = get_dp_netdev(dpif); |
874 | struct dp_netdev_flow *flow; | |
704a1e09 | 875 | struct hmap_node *node; |
14608a15 | 876 | |
704a1e09 BP |
877 | node = hmap_at_position(&dp->flow_table, &state->bucket, &state->offset); |
878 | if (!node) { | |
879 | return EOF; | |
72865317 | 880 | } |
704a1e09 BP |
881 | |
882 | flow = CONTAINER_OF(node, struct dp_netdev_flow, node); | |
36956a7d | 883 | |
feebdea2 BP |
884 | if (key) { |
885 | struct ofpbuf buf; | |
886 | ||
19cf4069 | 887 | ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf); |
ddbfda84 | 888 | odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port); |
36956a7d | 889 | |
feebdea2 BP |
890 | *key = buf.data; |
891 | *key_len = buf.size; | |
892 | } | |
893 | ||
894 | if (actions) { | |
895 | free(state->actions); | |
896 | state->actions = xmemdup(flow->actions, flow->actions_len); | |
897 | ||
898 | *actions = state->actions; | |
899 | *actions_len = flow->actions_len; | |
900 | } | |
901 | ||
902 | if (stats) { | |
c97fb132 | 903 | get_dpif_flow_stats(flow, &state->stats); |
feebdea2 BP |
904 | *stats = &state->stats; |
905 | } | |
704a1e09 BP |
906 | |
907 | return 0; | |
908 | } | |
909 | ||
910 | static int | |
feebdea2 | 911 | dpif_netdev_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) |
704a1e09 | 912 | { |
feebdea2 BP |
913 | struct dp_netdev_flow_state *state = state_; |
914 | ||
915 | free(state->actions); | |
704a1e09 BP |
916 | free(state); |
917 | return 0; | |
72865317 BP |
918 | } |
919 | ||
920 | static int | |
89625d1e | 921 | dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute) |
72865317 BP |
922 | { |
923 | struct dp_netdev *dp = get_dp_netdev(dpif); | |
924 | struct ofpbuf copy; | |
ae412e7d | 925 | struct flow key; |
72865317 BP |
926 | int error; |
927 | ||
89625d1e BP |
928 | if (execute->packet->size < ETH_HEADER_LEN || |
929 | execute->packet->size > UINT16_MAX) { | |
72865317 BP |
930 | return EINVAL; |
931 | } | |
932 | ||
109ee281 | 933 | /* Make a deep copy of 'packet', because we might modify its data. */ |
89625d1e | 934 | ofpbuf_init(©, DP_NETDEV_HEADROOM + execute->packet->size); |
109ee281 | 935 | ofpbuf_reserve(©, DP_NETDEV_HEADROOM); |
89625d1e | 936 | ofpbuf_put(©, execute->packet->data, execute->packet->size); |
80e5eed9 | 937 | |
72e8bf28 | 938 | flow_extract(©, 0, 0, NULL, -1, &key); |
89625d1e BP |
939 | error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, |
940 | &key); | |
18886b60 | 941 | if (!error) { |
4edb9ae9 | 942 | dp_netdev_execute_actions(dp, ©, &key, |
89625d1e | 943 | execute->actions, execute->actions_len); |
18886b60 | 944 | } |
109ee281 BP |
945 | |
946 | ofpbuf_uninit(©); | |
72865317 BP |
947 | return error; |
948 | } | |
949 | ||
950 | static int | |
a12b3ead | 951 | dpif_netdev_recv_set(struct dpif *dpif OVS_UNUSED, bool enable OVS_UNUSED) |
72865317 | 952 | { |
82272ede | 953 | return 0; |
72865317 BP |
954 | } |
955 | ||
5bf93d67 EJ |
956 | static int |
957 | dpif_netdev_queue_to_priority(const struct dpif *dpif OVS_UNUSED, | |
958 | uint32_t queue_id, uint32_t *priority) | |
959 | { | |
960 | *priority = queue_id; | |
961 | return 0; | |
962 | } | |
963 | ||
856081f6 | 964 | static struct dp_netdev_queue * |
72865317 BP |
965 | find_nonempty_queue(struct dpif *dpif) |
966 | { | |
72865317 | 967 | struct dp_netdev *dp = get_dp_netdev(dpif); |
72865317 BP |
968 | int i; |
969 | ||
970 | for (i = 0; i < N_QUEUES; i++) { | |
856081f6 | 971 | struct dp_netdev_queue *q = &dp->queues[i]; |
a12b3ead | 972 | if (q->head != q->tail) { |
856081f6 | 973 | return q; |
72865317 BP |
974 | } |
975 | } | |
856081f6 | 976 | return NULL; |
72865317 BP |
977 | } |
978 | ||
979 | static int | |
90a7c55e BP |
980 | dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall, |
981 | struct ofpbuf *buf) | |
72865317 | 982 | { |
856081f6 BP |
983 | struct dp_netdev_queue *q = find_nonempty_queue(dpif); |
984 | if (q) { | |
d88b629b BP |
985 | struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK]; |
986 | ||
987 | *upcall = u->upcall; | |
988 | upcall->packet = buf; | |
b3907fbc | 989 | |
90a7c55e | 990 | ofpbuf_uninit(buf); |
d88b629b | 991 | *buf = u->buf; |
90a7c55e | 992 | |
72865317 BP |
993 | return 0; |
994 | } else { | |
995 | return EAGAIN; | |
996 | } | |
997 | } | |
998 | ||
999 | static void | |
1000 | dpif_netdev_recv_wait(struct dpif *dpif) | |
1001 | { | |
856081f6 | 1002 | if (find_nonempty_queue(dpif)) { |
72865317 BP |
1003 | poll_immediate_wake(); |
1004 | } else { | |
1005 | /* No messages ready to be received, and dp_wait() will ensure that we | |
1006 | * wake up to queue new messages, so there is nothing to do. */ | |
1007 | } | |
1008 | } | |
1ba530f4 BP |
1009 | |
1010 | static void | |
1011 | dpif_netdev_recv_purge(struct dpif *dpif) | |
1012 | { | |
1013 | struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif); | |
1014 | dp_netdev_purge_queues(dpif_netdev->dp); | |
1015 | } | |
72865317 BP |
1016 | \f |
1017 | static void | |
c1fe014d | 1018 | dp_netdev_flow_used(struct dp_netdev_flow *flow, const struct ofpbuf *packet) |
72865317 | 1019 | { |
c97fb132 | 1020 | flow->used = time_msec(); |
72865317 BP |
1021 | flow->packet_count++; |
1022 | flow->byte_count += packet->size; | |
c1fe014d | 1023 | flow->tcp_flags |= packet_get_tcp_flags(packet, &flow->key); |
72865317 BP |
1024 | } |
1025 | ||
1026 | static void | |
1027 | dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port, | |
1028 | struct ofpbuf *packet) | |
1029 | { | |
1030 | struct dp_netdev_flow *flow; | |
14608a15 | 1031 | struct flow key; |
72865317 | 1032 | |
1805876e BP |
1033 | if (packet->size < ETH_HEADER_LEN) { |
1034 | return; | |
1035 | } | |
72e8bf28 | 1036 | flow_extract(packet, 0, 0, NULL, port->port_no, &key); |
72865317 BP |
1037 | flow = dp_netdev_lookup_flow(dp, &key); |
1038 | if (flow) { | |
c1fe014d | 1039 | dp_netdev_flow_used(flow, packet); |
72865317 | 1040 | dp_netdev_execute_actions(dp, packet, &key, |
cdee00fd | 1041 | flow->actions, flow->actions_len); |
72865317 BP |
1042 | dp->n_hit++; |
1043 | } else { | |
1044 | dp->n_missed++; | |
b85d8d61 | 1045 | dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0); |
72865317 BP |
1046 | } |
1047 | } | |
1048 | ||
1049 | static void | |
640e1b20 | 1050 | dpif_netdev_run(struct dpif *dpif) |
72865317 | 1051 | { |
640e1b20 BP |
1052 | struct dp_netdev *dp = get_dp_netdev(dpif); |
1053 | struct dp_netdev_port *port; | |
72865317 | 1054 | struct ofpbuf packet; |
72865317 | 1055 | |
ecf9ebff | 1056 | ofpbuf_init(&packet, DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + max_mtu); |
72865317 | 1057 | |
640e1b20 BP |
1058 | LIST_FOR_EACH (port, node, &dp->port_list) { |
1059 | int error; | |
1060 | ||
1061 | /* Reset packet contents. */ | |
1062 | ofpbuf_clear(&packet); | |
1063 | ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM); | |
1064 | ||
1065 | error = netdev_recv(port->netdev, &packet); | |
1066 | if (!error) { | |
1067 | dp_netdev_port_input(dp, port, &packet); | |
1068 | } else if (error != EAGAIN && error != EOPNOTSUPP) { | |
1069 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
1070 | VLOG_ERR_RL(&rl, "error receiving data from %s: %s", | |
1071 | netdev_get_name(port->netdev), strerror(error)); | |
72865317 BP |
1072 | } |
1073 | } | |
1074 | ofpbuf_uninit(&packet); | |
1075 | } | |
1076 | ||
1077 | static void | |
640e1b20 | 1078 | dpif_netdev_wait(struct dpif *dpif) |
72865317 | 1079 | { |
640e1b20 BP |
1080 | struct dp_netdev *dp = get_dp_netdev(dpif); |
1081 | struct dp_netdev_port *port; | |
462278db | 1082 | |
640e1b20 BP |
1083 | LIST_FOR_EACH (port, node, &dp->port_list) { |
1084 | netdev_recv_wait(port->netdev); | |
72865317 BP |
1085 | } |
1086 | } | |
1087 | ||
72865317 | 1088 | static void |
4edb9ae9 | 1089 | dp_netdev_set_dl(struct ofpbuf *packet, const struct ovs_key_ethernet *eth_key) |
72865317 BP |
1090 | { |
1091 | struct eth_header *eh = packet->l2; | |
4edb9ae9 PS |
1092 | |
1093 | memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src); | |
1094 | memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst); | |
72865317 BP |
1095 | } |
1096 | ||
72865317 BP |
1097 | static void |
1098 | dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet, | |
9b56fe13 | 1099 | uint32_t out_port) |
72865317 | 1100 | { |
2105ccc8 | 1101 | struct dp_netdev_port *p = dp->ports[out_port]; |
72865317 BP |
1102 | if (p) { |
1103 | netdev_send(p->netdev, packet); | |
1104 | } | |
1105 | } | |
1106 | ||
72865317 | 1107 | static int |
b85d8d61 | 1108 | dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet, |
856081f6 | 1109 | int queue_no, const struct flow *flow, uint64_t arg) |
72865317 | 1110 | { |
856081f6 | 1111 | struct dp_netdev_queue *q = &dp->queues[queue_no]; |
d88b629b | 1112 | struct dp_netdev_upcall *u; |
856081f6 BP |
1113 | struct dpif_upcall *upcall; |
1114 | struct ofpbuf *buf; | |
1115 | size_t key_len; | |
72865317 | 1116 | |
856081f6 | 1117 | if (q->head - q->tail >= MAX_QUEUE_LEN) { |
72865317 BP |
1118 | dp->n_lost++; |
1119 | return ENOBUFS; | |
1120 | } | |
1121 | ||
d88b629b BP |
1122 | u = &q->upcalls[q->head++ & QUEUE_MASK]; |
1123 | ||
1124 | buf = &u->buf; | |
1125 | ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size); | |
ddbfda84 | 1126 | odp_flow_key_from_flow(buf, flow, flow->in_port); |
856081f6 BP |
1127 | key_len = buf->size; |
1128 | ofpbuf_pull(buf, key_len); | |
1129 | ofpbuf_reserve(buf, 2); | |
1130 | ofpbuf_put(buf, packet->data, packet->size); | |
1131 | ||
d88b629b | 1132 | upcall = &u->upcall; |
856081f6 BP |
1133 | upcall->type = queue_no; |
1134 | upcall->packet = buf; | |
1135 | upcall->key = buf->base; | |
1136 | upcall->key_len = key_len; | |
1137 | upcall->userdata = arg; | |
1138 | ||
72865317 BP |
1139 | return 0; |
1140 | } | |
1141 | ||
26c6b6cd BP |
1142 | static void |
1143 | dp_netdev_sample(struct dp_netdev *dp, | |
1144 | struct ofpbuf *packet, struct flow *key, | |
1145 | const struct nlattr *action) | |
1146 | { | |
1147 | const struct nlattr *subactions = NULL; | |
1148 | const struct nlattr *a; | |
1149 | size_t left; | |
1150 | ||
1151 | NL_NESTED_FOR_EACH_UNSAFE (a, left, action) { | |
1152 | int type = nl_attr_type(a); | |
1153 | ||
1154 | switch ((enum ovs_sample_attr) type) { | |
1155 | case OVS_SAMPLE_ATTR_PROBABILITY: | |
1156 | if (random_uint32() >= nl_attr_get_u32(a)) { | |
1157 | return; | |
1158 | } | |
1159 | break; | |
1160 | ||
1161 | case OVS_SAMPLE_ATTR_ACTIONS: | |
1162 | subactions = a; | |
1163 | break; | |
1164 | ||
1165 | case OVS_SAMPLE_ATTR_UNSPEC: | |
1166 | case __OVS_SAMPLE_ATTR_MAX: | |
1167 | default: | |
1168 | NOT_REACHED(); | |
1169 | } | |
1170 | } | |
1171 | ||
1172 | dp_netdev_execute_actions(dp, packet, key, nl_attr_get(subactions), | |
1173 | nl_attr_get_size(subactions)); | |
1174 | } | |
1175 | ||
98403001 BP |
1176 | static void |
1177 | dp_netdev_action_userspace(struct dp_netdev *dp, | |
1178 | struct ofpbuf *packet, struct flow *key, | |
1179 | const struct nlattr *a) | |
1180 | { | |
1181 | const struct nlattr *userdata_attr; | |
1182 | uint64_t userdata; | |
1183 | ||
1184 | userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); | |
1185 | userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0; | |
1186 | dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata); | |
1187 | } | |
1188 | ||
4edb9ae9 PS |
1189 | static void |
1190 | execute_set_action(struct ofpbuf *packet, const struct nlattr *a) | |
1191 | { | |
1192 | enum ovs_key_attr type = nl_attr_type(a); | |
c97664b3 | 1193 | const struct ovs_key_ipv4 *ipv4_key; |
bc7a5acd | 1194 | const struct ovs_key_ipv6 *ipv6_key; |
c97664b3 EJ |
1195 | const struct ovs_key_tcp *tcp_key; |
1196 | const struct ovs_key_udp *udp_key; | |
1197 | ||
4edb9ae9 PS |
1198 | switch (type) { |
1199 | case OVS_KEY_ATTR_TUN_ID: | |
abff858b | 1200 | case OVS_KEY_ATTR_PRIORITY: |
72e8bf28 | 1201 | case OVS_KEY_ATTR_SKB_MARK: |
9b405f1a | 1202 | case OVS_KEY_ATTR_TUNNEL: |
abff858b | 1203 | /* not implemented */ |
4edb9ae9 PS |
1204 | break; |
1205 | ||
1206 | case OVS_KEY_ATTR_ETHERNET: | |
1207 | dp_netdev_set_dl(packet, | |
1208 | nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); | |
1209 | break; | |
1210 | ||
1211 | case OVS_KEY_ATTR_IPV4: | |
c97664b3 EJ |
1212 | ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); |
1213 | packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst, | |
1214 | ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl); | |
4edb9ae9 PS |
1215 | break; |
1216 | ||
bc7a5acd AA |
1217 | case OVS_KEY_ATTR_IPV6: |
1218 | ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6)); | |
1219 | packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src, | |
1220 | ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass, | |
1221 | ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit); | |
1222 | break; | |
1223 | ||
4edb9ae9 | 1224 | case OVS_KEY_ATTR_TCP: |
c97664b3 EJ |
1225 | tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp)); |
1226 | packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst); | |
4edb9ae9 PS |
1227 | break; |
1228 | ||
1229 | case OVS_KEY_ATTR_UDP: | |
c97664b3 EJ |
1230 | udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)); |
1231 | packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst); | |
4edb9ae9 PS |
1232 | break; |
1233 | ||
1234 | case OVS_KEY_ATTR_UNSPEC: | |
fea393b1 | 1235 | case OVS_KEY_ATTR_ENCAP: |
4edb9ae9 | 1236 | case OVS_KEY_ATTR_ETHERTYPE: |
4edb9ae9 | 1237 | case OVS_KEY_ATTR_IN_PORT: |
fea393b1 | 1238 | case OVS_KEY_ATTR_VLAN: |
4edb9ae9 PS |
1239 | case OVS_KEY_ATTR_ICMP: |
1240 | case OVS_KEY_ATTR_ICMPV6: | |
1241 | case OVS_KEY_ATTR_ARP: | |
1242 | case OVS_KEY_ATTR_ND: | |
1243 | case __OVS_KEY_ATTR_MAX: | |
1244 | default: | |
1245 | NOT_REACHED(); | |
1246 | } | |
1247 | } | |
1248 | ||
1249 | static void | |
72865317 | 1250 | dp_netdev_execute_actions(struct dp_netdev *dp, |
14608a15 | 1251 | struct ofpbuf *packet, struct flow *key, |
cdee00fd | 1252 | const struct nlattr *actions, |
cf22f8cb | 1253 | size_t actions_len) |
72865317 | 1254 | { |
cdee00fd BP |
1255 | const struct nlattr *a; |
1256 | unsigned int left; | |
72865317 | 1257 | |
cdee00fd | 1258 | NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { |
26c6b6cd BP |
1259 | int type = nl_attr_type(a); |
1260 | ||
09ded0ad | 1261 | switch ((enum ovs_action_attr) type) { |
df2c07f4 | 1262 | case OVS_ACTION_ATTR_OUTPUT: |
cdee00fd | 1263 | dp_netdev_output_port(dp, packet, nl_attr_get_u32(a)); |
2105ccc8 | 1264 | break; |
72865317 | 1265 | |
df2c07f4 | 1266 | case OVS_ACTION_ATTR_USERSPACE: |
98403001 | 1267 | dp_netdev_action_userspace(dp, packet, key, a); |
2105ccc8 | 1268 | break; |
72865317 | 1269 | |
f150da5e SH |
1270 | case OVS_ACTION_ATTR_PUSH_VLAN: { |
1271 | const struct ovs_action_push_vlan *vlan = nl_attr_get(a); | |
2f4ca41b | 1272 | eth_push_vlan(packet, vlan->vlan_tci); |
72865317 | 1273 | break; |
f150da5e | 1274 | } |
72865317 | 1275 | |
fea393b1 | 1276 | case OVS_ACTION_ATTR_POP_VLAN: |
f4ebc25e | 1277 | eth_pop_vlan(packet); |
2105ccc8 | 1278 | break; |
72865317 | 1279 | |
4edb9ae9 PS |
1280 | case OVS_ACTION_ATTR_SET: |
1281 | execute_set_action(packet, nl_attr_get(a)); | |
2105ccc8 | 1282 | break; |
26c6b6cd BP |
1283 | |
1284 | case OVS_ACTION_ATTR_SAMPLE: | |
1285 | dp_netdev_sample(dp, packet, key, a); | |
1286 | break; | |
1287 | ||
26c6b6cd BP |
1288 | case OVS_ACTION_ATTR_UNSPEC: |
1289 | case __OVS_ACTION_ATTR_MAX: | |
1290 | NOT_REACHED(); | |
2105ccc8 BP |
1291 | } |
1292 | } | |
72865317 BP |
1293 | } |
1294 | ||
1295 | const struct dpif_class dpif_netdev_class = { | |
72865317 | 1296 | "netdev", |
2197d7ab | 1297 | dpif_netdev_enumerate, |
0aeaabc8 | 1298 | dpif_netdev_port_open_type, |
72865317 BP |
1299 | dpif_netdev_open, |
1300 | dpif_netdev_close, | |
7dab847a | 1301 | dpif_netdev_destroy, |
640e1b20 BP |
1302 | dpif_netdev_run, |
1303 | dpif_netdev_wait, | |
72865317 | 1304 | dpif_netdev_get_stats, |
72865317 BP |
1305 | dpif_netdev_port_add, |
1306 | dpif_netdev_port_del, | |
1307 | dpif_netdev_port_query_by_number, | |
1308 | dpif_netdev_port_query_by_name, | |
996c1b3d | 1309 | dpif_netdev_get_max_ports, |
98403001 | 1310 | NULL, /* port_get_pid */ |
b0ec0f27 BP |
1311 | dpif_netdev_port_dump_start, |
1312 | dpif_netdev_port_dump_next, | |
1313 | dpif_netdev_port_dump_done, | |
72865317 BP |
1314 | dpif_netdev_port_poll, |
1315 | dpif_netdev_port_poll_wait, | |
72865317 BP |
1316 | dpif_netdev_flow_get, |
1317 | dpif_netdev_flow_put, | |
1318 | dpif_netdev_flow_del, | |
1319 | dpif_netdev_flow_flush, | |
704a1e09 BP |
1320 | dpif_netdev_flow_dump_start, |
1321 | dpif_netdev_flow_dump_next, | |
1322 | dpif_netdev_flow_dump_done, | |
72865317 | 1323 | dpif_netdev_execute, |
6bc60024 | 1324 | NULL, /* operate */ |
a12b3ead | 1325 | dpif_netdev_recv_set, |
5bf93d67 | 1326 | dpif_netdev_queue_to_priority, |
72865317 BP |
1327 | dpif_netdev_recv, |
1328 | dpif_netdev_recv_wait, | |
1ba530f4 | 1329 | dpif_netdev_recv_purge, |
72865317 | 1330 | }; |
614c4892 | 1331 | |
0cbfe35d BP |
1332 | static void |
1333 | dpif_dummy_register__(const char *type) | |
1334 | { | |
1335 | struct dpif_class *class; | |
1336 | ||
1337 | class = xmalloc(sizeof *class); | |
1338 | *class = dpif_netdev_class; | |
1339 | class->type = xstrdup(type); | |
1340 | dp_register_provider(class); | |
1341 | } | |
1342 | ||
614c4892 | 1343 | void |
0cbfe35d | 1344 | dpif_dummy_register(bool override) |
614c4892 | 1345 | { |
0cbfe35d BP |
1346 | if (override) { |
1347 | struct sset types; | |
1348 | const char *type; | |
1349 | ||
1350 | sset_init(&types); | |
1351 | dp_enumerate_types(&types); | |
1352 | SSET_FOR_EACH (type, &types) { | |
1353 | if (!dp_unregister_provider(type)) { | |
1354 | dpif_dummy_register__(type); | |
1355 | } | |
1356 | } | |
1357 | sset_destroy(&types); | |
614c4892 | 1358 | } |
0cbfe35d BP |
1359 | |
1360 | dpif_dummy_register__("dummy"); | |
614c4892 | 1361 | } |