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