]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ct-dpif.c
ovsdb-idl: Fix iteration over tracked rows with no actual data.
[mirror_ovs.git] / lib / ct-dpif.c
1 /*
2 * Copyright (c) 2015, 2018 Nicira, Inc.
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-provider.h"
19
20 #include <errno.h>
21
22 #include "ct-dpif.h"
23 #include "openvswitch/ofp-parse.h"
24 #include "openvswitch/vlog.h"
25
26 VLOG_DEFINE_THIS_MODULE(ct_dpif);
27
28 /* Declarations for conntrack entry formatting. */
29 struct flags {
30 uint32_t flag;
31 const char *name;
32 };
33
34 static void ct_dpif_format_counters(struct ds *,
35 const struct ct_dpif_counters *);
36 static void ct_dpif_format_timestamp(struct ds *,
37 const struct ct_dpif_timestamp *);
38 static void ct_dpif_format_flags(struct ds *, const char *title,
39 uint32_t flags, const struct flags *);
40 static void ct_dpif_format_protoinfo(struct ds *, const char *title,
41 const struct ct_dpif_protoinfo *,
42 bool verbose);
43 static void ct_dpif_format_helper(struct ds *, const char *title,
44 const struct ct_dpif_helper *);
45
46 static const struct flags ct_dpif_status_flags[] = {
47 #define CT_DPIF_STATUS_FLAG(FLAG) { CT_DPIF_STATUS_##FLAG, #FLAG },
48 CT_DPIF_STATUS_FLAGS
49 #undef CT_DPIF_STATUS_FLAG
50 { 0, NULL } /* End marker. */
51 };
52 \f
53 /* Dumping */
54
55 /* Start dumping the entries from the connection tracker used by 'dpif'.
56 *
57 * 'dump' must be the address of a pointer to a struct ct_dpif_dump_state,
58 * which should be passed (unaltered) to ct_dpif_dump_{next,done}().
59 *
60 * If 'zone' is not NULL, it should point to an integer identifing a
61 * conntrack zone to which the dump will be limited. If it is NULL,
62 * conntrack entries from all zones will be dumped.
63 *
64 * If there has been a problem the function returns a non-zero value
65 * that represents the error. Otherwise it returns zero. */
66 int
67 ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
68 const uint16_t *zone, int *ptot_bkts)
69 {
70 int err;
71
72 err = (dpif->dpif_class->ct_dump_start
73 ? dpif->dpif_class->ct_dump_start(dpif, dump, zone, ptot_bkts)
74 : EOPNOTSUPP);
75
76 if (!err) {
77 (*dump)->dpif = dpif;
78 }
79
80 return err;
81 }
82
83 /* Dump one connection from a tracker, and put it in 'entry'.
84 *
85 * 'dump' should have been initialized by ct_dpif_dump_start().
86 *
87 * The function returns 0, if an entry has been dumped succesfully.
88 * Otherwise it returns a non-zero value which can be:
89 * - EOF: meaning that there are no more entries to dump.
90 * - an error value.
91 * In both cases, the user should call ct_dpif_dump_done(). */
92 int
93 ct_dpif_dump_next(struct ct_dpif_dump_state *dump, struct ct_dpif_entry *entry)
94 {
95 struct dpif *dpif = dump->dpif;
96
97 return (dpif->dpif_class->ct_dump_next
98 ? dpif->dpif_class->ct_dump_next(dpif, dump, entry)
99 : EOPNOTSUPP);
100 }
101
102 /* Free resources used by 'dump' */
103 int
104 ct_dpif_dump_done(struct ct_dpif_dump_state *dump)
105 {
106 struct dpif *dpif = dump->dpif;
107
108 return (dpif->dpif_class->ct_dump_done
109 ? dpif->dpif_class->ct_dump_done(dpif, dump)
110 : EOPNOTSUPP);
111 }
112 \f
113 /* Flush the entries in the connection tracker used by 'dpif'. The
114 * arguments have the following behavior:
115 *
116 * - If both 'zone' and 'tuple' are NULL, flush all the conntrack entries.
117 * - If 'zone' is not NULL, and 'tuple' is NULL, flush all the conntrack
118 * entries in '*zone'.
119 * - If 'tuple' is not NULL, flush the conntrack entry specified by 'tuple'
120 * in '*zone'. If 'zone' is NULL, use the default zone (zone 0). */
121 int
122 ct_dpif_flush(struct dpif *dpif, const uint16_t *zone,
123 const struct ct_dpif_tuple *tuple)
124 {
125 if (tuple) {
126 struct ds ds = DS_EMPTY_INITIALIZER;
127 ct_dpif_format_tuple(&ds, tuple);
128 VLOG_DBG("%s: ct_flush: %s in zone %d", dpif_name(dpif), ds_cstr(&ds),
129 zone ? *zone : 0);
130 ds_destroy(&ds);
131 } else if (zone) {
132 VLOG_DBG("%s: ct_flush: zone %"PRIu16, dpif_name(dpif), *zone);
133 } else {
134 VLOG_DBG("%s: ct_flush: <all>", dpif_name(dpif));
135 }
136
137 return (dpif->dpif_class->ct_flush
138 ? dpif->dpif_class->ct_flush(dpif, zone, tuple)
139 : EOPNOTSUPP);
140 }
141
142 int
143 ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns)
144 {
145 return (dpif->dpif_class->ct_set_maxconns
146 ? dpif->dpif_class->ct_set_maxconns(dpif, maxconns)
147 : EOPNOTSUPP);
148 }
149
150 int
151 ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns)
152 {
153 return (dpif->dpif_class->ct_get_maxconns
154 ? dpif->dpif_class->ct_get_maxconns(dpif, maxconns)
155 : EOPNOTSUPP);
156 }
157
158 int
159 ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns)
160 {
161 return (dpif->dpif_class->ct_get_nconns
162 ? dpif->dpif_class->ct_get_nconns(dpif, nconns)
163 : EOPNOTSUPP);
164 }
165
166 int
167 ct_dpif_set_tcp_seq_chk(struct dpif *dpif, bool enabled)
168 {
169 return (dpif->dpif_class->ct_set_tcp_seq_chk
170 ? dpif->dpif_class->ct_set_tcp_seq_chk(dpif, enabled)
171 : EOPNOTSUPP);
172 }
173
174 int
175 ct_dpif_get_tcp_seq_chk(struct dpif *dpif, bool *enabled)
176 {
177 return (dpif->dpif_class->ct_get_tcp_seq_chk
178 ? dpif->dpif_class->ct_get_tcp_seq_chk(dpif, enabled)
179 : EOPNOTSUPP);
180 }
181
182 int
183 ct_dpif_set_limits(struct dpif *dpif, const uint32_t *default_limit,
184 const struct ovs_list *zone_limits)
185 {
186 return (dpif->dpif_class->ct_set_limits
187 ? dpif->dpif_class->ct_set_limits(dpif, default_limit,
188 zone_limits)
189 : EOPNOTSUPP);
190 }
191
192 int
193 ct_dpif_get_limits(struct dpif *dpif, uint32_t *default_limit,
194 const struct ovs_list *zone_limits_in,
195 struct ovs_list *zone_limits_out)
196 {
197 return (dpif->dpif_class->ct_get_limits
198 ? dpif->dpif_class->ct_get_limits(dpif, default_limit,
199 zone_limits_in,
200 zone_limits_out)
201 : EOPNOTSUPP);
202 }
203
204 int
205 ct_dpif_del_limits(struct dpif *dpif, const struct ovs_list *zone_limits)
206 {
207 return (dpif->dpif_class->ct_del_limits
208 ? dpif->dpif_class->ct_del_limits(dpif, zone_limits)
209 : EOPNOTSUPP);
210 }
211
212 int
213 ct_dpif_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable)
214 {
215 return (dpif->dpif_class->ipf_set_enabled
216 ? dpif->dpif_class->ipf_set_enabled(dpif, v6, enable)
217 : EOPNOTSUPP);
218 }
219
220 int
221 ct_dpif_ipf_set_min_frag(struct dpif *dpif, bool v6, uint32_t min_frag)
222 {
223 return (dpif->dpif_class->ipf_set_min_frag
224 ? dpif->dpif_class->ipf_set_min_frag(dpif, v6, min_frag)
225 : EOPNOTSUPP);
226 }
227
228 int
229 ct_dpif_ipf_set_max_nfrags(struct dpif *dpif, uint32_t max_frags)
230 {
231 return (dpif->dpif_class->ipf_set_max_nfrags
232 ? dpif->dpif_class->ipf_set_max_nfrags(dpif, max_frags)
233 : EOPNOTSUPP);
234 }
235
236 int ct_dpif_ipf_get_status(struct dpif *dpif,
237 struct dpif_ipf_status *dpif_ipf_status)
238 {
239 return (dpif->dpif_class->ipf_get_status
240 ? dpif->dpif_class->ipf_get_status(dpif, dpif_ipf_status)
241 : EOPNOTSUPP);
242 }
243
244 int
245 ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **dump_ctx)
246 {
247 return (dpif->dpif_class->ipf_dump_start
248 ? dpif->dpif_class->ipf_dump_start(dpif, dump_ctx)
249 : EOPNOTSUPP);
250 }
251
252 int
253 ct_dpif_ipf_dump_next(struct dpif *dpif, void *dump_ctx, char **dump)
254 {
255 return (dpif->dpif_class->ipf_dump_next
256 ? dpif->dpif_class->ipf_dump_next(dpif, dump_ctx, dump)
257 : EOPNOTSUPP);
258 }
259
260 int
261 ct_dpif_ipf_dump_done(struct dpif *dpif, void *dump_ctx)
262 {
263 return (dpif->dpif_class->ipf_dump_done
264 ? dpif->dpif_class->ipf_dump_done(dpif, dump_ctx)
265 : EOPNOTSUPP);
266 }
267
268 void
269 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
270 {
271 if (entry) {
272 if (entry->helper.name) {
273 free(entry->helper.name);
274 }
275 }
276 }
277 \f
278 void
279 ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds,
280 bool verbose, bool print_stats)
281 {
282 ct_dpif_format_ipproto(ds, entry->tuple_orig.ip_proto);
283
284 ds_put_cstr(ds, ",orig=(");
285 ct_dpif_format_tuple(ds, &entry->tuple_orig);
286 if (print_stats) {
287 ct_dpif_format_counters(ds, &entry->counters_orig);
288 }
289 ds_put_cstr(ds, ")");
290
291 ds_put_cstr(ds, ",reply=(");
292 ct_dpif_format_tuple(ds, &entry->tuple_reply);
293 if (print_stats) {
294 ct_dpif_format_counters(ds, &entry->counters_reply);
295 }
296 ds_put_cstr(ds, ")");
297
298 if (print_stats) {
299 ct_dpif_format_timestamp(ds, &entry->timestamp);
300 }
301 if (verbose) {
302 ds_put_format(ds, ",id=%"PRIu32, entry->id);
303 }
304 if (entry->zone) {
305 ds_put_format(ds, ",zone=%"PRIu16, entry->zone);
306 }
307 if (verbose) {
308 ct_dpif_format_flags(ds, ",status=", entry->status,
309 ct_dpif_status_flags);
310 }
311 if (print_stats) {
312 ds_put_format(ds, ",timeout=%"PRIu32, entry->timeout);
313 }
314 if (entry->mark) {
315 ds_put_format(ds, ",mark=%"PRIu32, entry->mark);
316 }
317 if (!ovs_u128_is_zero(entry->labels)) {
318 ovs_be128 value;
319
320 ds_put_cstr(ds, ",labels=");
321 value = hton128(entry->labels);
322 ds_put_hex(ds, &value, sizeof value);
323 }
324 ct_dpif_format_protoinfo(ds, ",protoinfo=", &entry->protoinfo, verbose);
325 ct_dpif_format_helper(ds, ",helper=", &entry->helper);
326 if (verbose && entry->tuple_parent.l3_type != 0) {
327 ds_put_cstr(ds, ",parent=(");
328 ct_dpif_format_tuple(ds, &entry->tuple_parent);
329 ds_put_cstr(ds, ")");
330 }
331 }
332
333 void
334 ct_dpif_format_ipproto(struct ds *ds, uint16_t ipproto)
335 {
336 const char *name;
337
338 name = (ipproto == IPPROTO_ICMP) ? "icmp"
339 : (ipproto == IPPROTO_ICMPV6) ? "icmpv6"
340 : (ipproto == IPPROTO_TCP) ? "tcp"
341 : (ipproto == IPPROTO_UDP) ? "udp"
342 : (ipproto == IPPROTO_SCTP) ? "sctp"
343 : (ipproto == IPPROTO_UDPLITE) ? "udplite"
344 : (ipproto == IPPROTO_DCCP) ? "dccp"
345 : (ipproto == IPPROTO_IGMP) ? "igmp"
346 : NULL;
347
348 if (name) {
349 ds_put_cstr(ds, name);
350 } else {
351 ds_put_format(ds, "%u", ipproto);
352 }
353 }
354
355 static void
356 ct_dpif_format_counters(struct ds *ds, const struct ct_dpif_counters *counters)
357 {
358 if (counters->packets || counters->bytes) {
359 ds_put_format(ds, ",packets=%"PRIu64",bytes=%"PRIu64,
360 counters->packets, counters->bytes);
361 }
362 }
363
364 static void
365 ct_dpif_format_timestamp(struct ds *ds,
366 const struct ct_dpif_timestamp *timestamp)
367 {
368 if (timestamp->start || timestamp->stop) {
369 ds_put_strftime_msec(ds, ",start=%Y-%m-%dT%H:%M:%S.###",
370 timestamp->start / UINT64_C(1000000), false);
371 if (timestamp->stop) {
372 ds_put_strftime_msec(ds, ",stop=%Y-%m-%dT%H:%M:%S.###",
373 timestamp->stop / UINT64_C(1000000), false);
374 }
375 }
376 }
377
378 static void
379 ct_dpif_format_tuple_icmp(struct ds *ds, const struct ct_dpif_tuple *tuple)
380 {
381 ds_put_format(ds, ",id=%u,type=%u,code=%u", ntohs(tuple->icmp_id),
382 tuple->icmp_type, tuple->icmp_code);
383 }
384
385 static void
386 ct_dpif_format_tuple_tp(struct ds *ds, const struct ct_dpif_tuple *tuple)
387 {
388 ds_put_format(ds, ",sport=%u,dport=%u",
389 ntohs(tuple->src_port), ntohs(tuple->dst_port));
390 }
391
392 void
393 ct_dpif_format_tuple(struct ds *ds, const struct ct_dpif_tuple *tuple)
394 {
395 if (tuple->l3_type == AF_INET) {
396 ds_put_format(ds, "src="IP_FMT",dst="IP_FMT,
397 IP_ARGS(tuple->src.ip), IP_ARGS(tuple->dst.ip));
398 } else if (tuple->l3_type == AF_INET6) {
399 ds_put_cstr(ds, "src=");
400 ipv6_format_addr(&tuple->src.in6, ds);
401 ds_put_cstr(ds, ",dst=");
402 ipv6_format_addr(&tuple->dst.in6, ds);
403 } else {
404 ds_put_format(ds, "Unsupported address family: %u. HEX:\n",
405 tuple->l3_type);
406 ds_put_hex_dump(ds, tuple, sizeof *tuple, 0, false);
407 return;
408 }
409
410 if (tuple->ip_proto == IPPROTO_ICMP
411 || tuple->ip_proto == IPPROTO_ICMPV6) {
412 ct_dpif_format_tuple_icmp(ds, tuple);
413 } else {
414 ct_dpif_format_tuple_tp(ds, tuple);
415 }
416 }
417
418 static void
419 ct_dpif_format_flags(struct ds *ds, const char *title, uint32_t flags,
420 const struct flags *table)
421 {
422 if (title) {
423 ds_put_cstr(ds, title);
424 }
425 for (; table->name; table++) {
426 if (flags & table->flag) {
427 ds_put_format(ds, "%s|", table->name);
428 }
429 }
430 ds_chomp(ds, '|');
431 }
432
433 static const struct flags tcp_flags[] = {
434 #define CT_DPIF_TCP_FLAG(FLAG) { CT_DPIF_TCPF_##FLAG, #FLAG },
435 CT_DPIF_TCP_FLAGS
436 #undef CT_DPIF_TCP_FLAG
437 { 0, NULL } /* End marker. */
438 };
439
440 const char *ct_dpif_tcp_state_string[] = {
441 #define CT_DPIF_TCP_STATE(STATE) [CT_DPIF_TCPS_##STATE] = #STATE,
442 CT_DPIF_TCP_STATES
443 #undef CT_DPIF_TCP_STATE
444 };
445
446 const char *ct_dpif_sctp_state_string[] = {
447 #define CT_DPIF_SCTP_STATE(STATE) [CT_DPIF_SCTP_STATE_##STATE] = #STATE,
448 CT_DPIF_SCTP_STATES
449 #undef CT_DPIF_SCTP_STATE
450 };
451
452 static void
453 ct_dpif_format_enum__(struct ds *ds, const char *title, unsigned int state,
454 const char *names[], unsigned int max)
455 {
456 if (title) {
457 ds_put_cstr(ds, title);
458 }
459 if (state < max) {
460 ds_put_cstr(ds, names[state]);
461 } else {
462 ds_put_format(ds, "[%u]", state);
463 }
464 }
465
466 #define ct_dpif_format_enum(DS, TITLE, STATE, NAMES) \
467 ct_dpif_format_enum__((DS), (TITLE), (STATE), (NAMES), ARRAY_SIZE(NAMES))
468
469 static uint8_t
470 coalesce_tcp_state(uint8_t state)
471 {
472 /* The Linux kernel connection tracker and the userspace view the
473 * tcp states differently in some situations. If we're formatting
474 * the entry without being verbose, it is worth to adjust the
475 * differences, to ease writing testcases. */
476 switch (state) {
477 case CT_DPIF_TCPS_FIN_WAIT_2:
478 return CT_DPIF_TCPS_TIME_WAIT;
479 case CT_DPIF_TCPS_SYN_RECV:
480 return CT_DPIF_TCPS_ESTABLISHED;
481 default:
482 return state;
483 }
484 }
485
486 static void
487 ct_dpif_format_protoinfo_tcp(struct ds *ds,
488 const struct ct_dpif_protoinfo *protoinfo)
489 {
490 uint8_t tcp_state;
491
492 /* We keep two separate tcp states, but we print just one. The Linux
493 * kernel connection tracker internally keeps only one state, so
494 * 'state_orig' and 'state_reply', will be the same. */
495 tcp_state = MAX(protoinfo->tcp.state_orig, protoinfo->tcp.state_reply);
496
497 tcp_state = coalesce_tcp_state(tcp_state);
498 ct_dpif_format_enum(ds, "state=", tcp_state, ct_dpif_tcp_state_string);
499 }
500
501 static void
502 ct_dpif_format_protoinfo_tcp_verbose(struct ds *ds,
503 const struct ct_dpif_protoinfo *protoinfo)
504 {
505 ct_dpif_format_enum(ds, "state_orig=", protoinfo->tcp.state_orig,
506 ct_dpif_tcp_state_string);
507 ct_dpif_format_enum(ds, ",state_reply=", protoinfo->tcp.state_reply,
508 ct_dpif_tcp_state_string);
509
510 if (protoinfo->tcp.wscale_orig || protoinfo->tcp.wscale_reply) {
511 ds_put_format(ds, ",wscale_orig=%u,wscale_reply=%u",
512 protoinfo->tcp.wscale_orig,
513 protoinfo->tcp.wscale_reply);
514 }
515 ct_dpif_format_flags(ds, ",flags_orig=", protoinfo->tcp.flags_orig,
516 tcp_flags);
517 ct_dpif_format_flags(ds, ",flags_reply=", protoinfo->tcp.flags_reply,
518 tcp_flags);
519 }
520
521 static void
522 ct_dpif_format_protoinfo_sctp(struct ds *ds,
523 const struct ct_dpif_protoinfo *protoinfo)
524 {
525 ct_dpif_format_enum(ds, "state=", protoinfo->sctp.state,
526 ct_dpif_sctp_state_string);
527 ds_put_format(ds, ",vtag_orig=%" PRIu32 ",vtag_reply=%" PRIu32,
528 protoinfo->sctp.vtag_orig, protoinfo->sctp.vtag_reply);
529 }
530
531 static void
532 ct_dpif_format_protoinfo(struct ds *ds, const char *title,
533 const struct ct_dpif_protoinfo *protoinfo,
534 bool verbose)
535 {
536 if (protoinfo->proto != 0) {
537 if (title) {
538 ds_put_format(ds, "%s(", title);
539 }
540 switch (protoinfo->proto) {
541 case IPPROTO_TCP:
542 if (verbose) {
543 ct_dpif_format_protoinfo_tcp_verbose(ds, protoinfo);
544 } else {
545 ct_dpif_format_protoinfo_tcp(ds, protoinfo);
546 }
547 break;
548 case IPPROTO_SCTP:
549 ct_dpif_format_protoinfo_sctp(ds, protoinfo);
550 break;
551 }
552 if (title) {
553 ds_put_cstr(ds, ")");
554 }
555 }
556 }
557
558 static void
559 ct_dpif_format_helper(struct ds *ds, const char *title,
560 const struct ct_dpif_helper *helper)
561 {
562 if (helper->name) {
563 if (title) {
564 ds_put_cstr(ds, title);
565 }
566 ds_put_cstr(ds, helper->name);
567 }
568 }
569
570 uint8_t
571 ct_dpif_coalesce_tcp_state(uint8_t state)
572 {
573 return coalesce_tcp_state(state);
574 }
575
576 void
577 ct_dpif_format_tcp_stat(struct ds * ds, int tcp_state, int conn_per_state)
578 {
579 ct_dpif_format_enum(ds, "\t [", tcp_state, ct_dpif_tcp_state_string);
580 ds_put_cstr(ds, "]");
581 ds_put_format(ds, "=%u", conn_per_state);
582 }
583
584 /* Parses a specification of a conntrack 5-tuple from 's' into 'tuple'.
585 * Returns true on success. Otherwise, returns false and puts the error
586 * message in 'ds'. */
587 bool
588 ct_dpif_parse_tuple(struct ct_dpif_tuple *tuple, const char *s, struct ds *ds)
589 {
590 char *pos, *key, *value, *copy;
591 memset(tuple, 0, sizeof *tuple);
592
593 pos = copy = xstrdup(s);
594 while (ofputil_parse_key_value(&pos, &key, &value)) {
595 if (!*value) {
596 ds_put_format(ds, "field %s missing value", key);
597 goto error;
598 }
599
600 if (!strcmp(key, "ct_nw_src") || !strcmp(key, "ct_nw_dst")) {
601 if (tuple->l3_type && tuple->l3_type != AF_INET) {
602 ds_put_cstr(ds, "L3 type set multiple times");
603 goto error;
604 } else {
605 tuple->l3_type = AF_INET;
606 }
607 if (!ip_parse(value, key[6] == 's' ? &tuple->src.ip :
608 &tuple->dst.ip)) {
609 goto error_with_msg;
610 }
611 } else if (!strcmp(key, "ct_ipv6_src") ||
612 !strcmp(key, "ct_ipv6_dst")) {
613 if (tuple->l3_type && tuple->l3_type != AF_INET6) {
614 ds_put_cstr(ds, "L3 type set multiple times");
615 goto error;
616 } else {
617 tuple->l3_type = AF_INET6;
618 }
619 if (!ipv6_parse(value, key[8] == 's' ? &tuple->src.in6 :
620 &tuple->dst.in6)) {
621 goto error_with_msg;
622 }
623 } else if (!strcmp(key, "ct_nw_proto")) {
624 char *err = str_to_u8(value, key, &tuple->ip_proto);
625 if (err) {
626 free(err);
627 goto error_with_msg;
628 }
629 } else if (!strcmp(key, "ct_tp_src") || !strcmp(key,"ct_tp_dst")) {
630 uint16_t port;
631 char *err = str_to_u16(value, key, &port);
632 if (err) {
633 free(err);
634 goto error_with_msg;
635 }
636 if (key[6] == 's') {
637 tuple->src_port = htons(port);
638 } else {
639 tuple->dst_port = htons(port);
640 }
641 } else if (!strcmp(key, "icmp_type") || !strcmp(key, "icmp_code") ||
642 !strcmp(key, "icmp_id") ) {
643 if (tuple->ip_proto != IPPROTO_ICMP &&
644 tuple->ip_proto != IPPROTO_ICMPV6) {
645 ds_put_cstr(ds, "invalid L4 fields");
646 goto error;
647 }
648 uint16_t icmp_id;
649 char *err;
650 if (key[5] == 't') {
651 err = str_to_u8(value, key, &tuple->icmp_type);
652 } else if (key[5] == 'c') {
653 err = str_to_u8(value, key, &tuple->icmp_code);
654 } else {
655 err = str_to_u16(value, key, &icmp_id);
656 tuple->icmp_id = htons(icmp_id);
657 }
658 if (err) {
659 free(err);
660 goto error_with_msg;
661 }
662 } else {
663 ds_put_format(ds, "invalid conntrack tuple field: %s", key);
664 goto error;
665 }
666 }
667
668 if (ipv6_is_zero(&tuple->src.in6) || ipv6_is_zero(&tuple->dst.in6) ||
669 !tuple->ip_proto) {
670 /* icmp_type, icmp_code, and icmp_id can be 0. */
671 if (tuple->ip_proto != IPPROTO_ICMP &&
672 tuple->ip_proto != IPPROTO_ICMPV6) {
673 if (!tuple->src_port || !tuple->dst_port) {
674 ds_put_cstr(ds, "at least one of the conntrack 5-tuple fields "
675 "is missing.");
676 goto error;
677 }
678 }
679 }
680
681 free(copy);
682 return true;
683
684 error_with_msg:
685 ds_put_format(ds, "failed to parse field %s", key);
686 error:
687 free(copy);
688 return false;
689 }
690
691 void
692 ct_dpif_push_zone_limit(struct ovs_list *zone_limits, uint16_t zone,
693 uint32_t limit, uint32_t count)
694 {
695 struct ct_dpif_zone_limit *zone_limit = xmalloc(sizeof *zone_limit);
696 zone_limit->zone = zone;
697 zone_limit->limit = limit;
698 zone_limit->count = count;
699 ovs_list_push_back(zone_limits, &zone_limit->node);
700 }
701
702 void
703 ct_dpif_free_zone_limits(struct ovs_list *zone_limits)
704 {
705 while (!ovs_list_is_empty(zone_limits)) {
706 struct ovs_list *entry = ovs_list_pop_front(zone_limits);
707 struct ct_dpif_zone_limit *cdzl;
708 cdzl = CONTAINER_OF(entry, struct ct_dpif_zone_limit, node);
709 free(cdzl);
710 }
711 }
712
713 /* Parses a specification of a conntrack zone limit from 's' into '*pzone'
714 * and '*plimit'. Returns true on success. Otherwise, returns false and
715 * and puts the error message in 'ds'. */
716 bool
717 ct_dpif_parse_zone_limit_tuple(const char *s, uint16_t *pzone,
718 uint32_t *plimit, struct ds *ds)
719 {
720 char *pos, *key, *value, *copy, *err;
721 bool parsed_limit = false, parsed_zone = false;
722
723 pos = copy = xstrdup(s);
724 while (ofputil_parse_key_value(&pos, &key, &value)) {
725 if (!*value) {
726 ds_put_format(ds, "field %s missing value", key);
727 goto error;
728 }
729
730 if (!strcmp(key, "zone")) {
731 err = str_to_u16(value, key, pzone);
732 if (err) {
733 free(err);
734 goto error_with_msg;
735 }
736 parsed_zone = true;
737 } else if (!strcmp(key, "limit")) {
738 err = str_to_u32(value, plimit);
739 if (err) {
740 free(err);
741 goto error_with_msg;
742 }
743 parsed_limit = true;
744 } else {
745 ds_put_format(ds, "invalid zone limit field: %s", key);
746 goto error;
747 }
748 }
749
750 if (!parsed_zone || !parsed_limit) {
751 ds_put_format(ds, "failed to parse zone limit");
752 goto error;
753 }
754
755 free(copy);
756 return true;
757
758 error_with_msg:
759 ds_put_format(ds, "failed to parse field %s", key);
760 error:
761 free(copy);
762 return false;
763 }
764
765 void
766 ct_dpif_format_zone_limits(uint32_t default_limit,
767 const struct ovs_list *zone_limits, struct ds *ds)
768 {
769 struct ct_dpif_zone_limit *zone_limit;
770
771 ds_put_format(ds, "default limit=%"PRIu32, default_limit);
772
773 LIST_FOR_EACH (zone_limit, node, zone_limits) {
774 ds_put_format(ds, "\nzone=%"PRIu16, zone_limit->zone);
775 ds_put_format(ds, ",limit=%"PRIu32, zone_limit->limit);
776 ds_put_format(ds, ",count=%"PRIu32, zone_limit->count);
777 }
778 }
779
780 static const char *const ct_dpif_tp_attr_string[] = {
781 #define CT_DPIF_TP_TCP_ATTR(ATTR) \
782 [CT_DPIF_TP_ATTR_TCP_##ATTR] = "TCP_"#ATTR,
783 CT_DPIF_TP_TCP_ATTRS
784 #undef CT_DPIF_TP_TCP_ATTR
785 #define CT_DPIF_TP_UDP_ATTR(ATTR) \
786 [CT_DPIF_TP_ATTR_UDP_##ATTR] = "UDP_"#ATTR,
787 CT_DPIF_TP_UDP_ATTRS
788 #undef CT_DPIF_TP_UDP_ATTR
789 #define CT_DPIF_TP_ICMP_ATTR(ATTR) \
790 [CT_DPIF_TP_ATTR_ICMP_##ATTR] = "ICMP_"#ATTR,
791 CT_DPIF_TP_ICMP_ATTRS
792 #undef CT_DPIF_TP_ICMP_ATTR
793 };
794
795 static bool
796 ct_dpif_set_timeout_policy_attr(struct ct_dpif_timeout_policy *tp,
797 uint32_t attr, uint32_t value)
798 {
799 if (tp->present & (1 << attr) && tp->attrs[attr] == value) {
800 return false;
801 }
802 tp->attrs[attr] = value;
803 tp->present |= 1 << attr;
804 return true;
805 }
806
807 /* Sets a timeout value identified by '*name' to 'value'.
808 * Returns true if the attribute is changed */
809 bool
810 ct_dpif_set_timeout_policy_attr_by_name(struct ct_dpif_timeout_policy *tp,
811 const char *name, uint32_t value)
812 {
813 for (uint32_t i = 0; i < CT_DPIF_TP_ATTR_MAX; ++i) {
814 if (!strcasecmp(name, ct_dpif_tp_attr_string[i])) {
815 return ct_dpif_set_timeout_policy_attr(tp, i, value);
816 }
817 }
818 return false;
819 }
820
821 bool
822 ct_dpif_timeout_policy_support_ipproto(uint8_t ipproto)
823 {
824 if (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP ||
825 ipproto == IPPROTO_ICMP || ipproto == IPPROTO_ICMPV6) {
826 return true;
827 }
828 return false;
829 }
830
831 int
832 ct_dpif_set_timeout_policy(struct dpif *dpif,
833 const struct ct_dpif_timeout_policy *tp)
834 {
835 return (dpif->dpif_class->ct_set_timeout_policy
836 ? dpif->dpif_class->ct_set_timeout_policy(dpif, tp)
837 : EOPNOTSUPP);
838 }
839
840 int
841 ct_dpif_del_timeout_policy(struct dpif *dpif, uint32_t tp_id)
842 {
843 return (dpif->dpif_class->ct_del_timeout_policy
844 ? dpif->dpif_class->ct_del_timeout_policy(dpif, tp_id)
845 : EOPNOTSUPP);
846 }
847
848 int
849 ct_dpif_get_timeout_policy(struct dpif *dpif, uint32_t tp_id,
850 struct ct_dpif_timeout_policy *tp)
851 {
852 return (dpif->dpif_class->ct_get_timeout_policy
853 ? dpif->dpif_class->ct_get_timeout_policy(
854 dpif, tp_id, tp) : EOPNOTSUPP);
855 }
856
857 int
858 ct_dpif_timeout_policy_dump_start(struct dpif *dpif, void **statep)
859 {
860 return (dpif->dpif_class->ct_timeout_policy_dump_start
861 ? dpif->dpif_class->ct_timeout_policy_dump_start(dpif, statep)
862 : EOPNOTSUPP);
863 }
864
865 int
866 ct_dpif_timeout_policy_dump_next(struct dpif *dpif, void *state,
867 struct ct_dpif_timeout_policy *tp)
868 {
869 return (dpif->dpif_class->ct_timeout_policy_dump_next
870 ? dpif->dpif_class->ct_timeout_policy_dump_next(dpif, state, tp)
871 : EOPNOTSUPP);
872 }
873
874 int
875 ct_dpif_timeout_policy_dump_done(struct dpif *dpif, void *state)
876 {
877 return (dpif->dpif_class->ct_timeout_policy_dump_done
878 ? dpif->dpif_class->ct_timeout_policy_dump_done(dpif, state)
879 : EOPNOTSUPP);
880 }
881
882 int
883 ct_dpif_get_timeout_policy_name(struct dpif *dpif, uint32_t tp_id,
884 uint16_t dl_type, uint8_t nw_proto,
885 char **tp_name, bool *is_generic)
886 {
887 return (dpif->dpif_class->ct_get_timeout_policy_name
888 ? dpif->dpif_class->ct_get_timeout_policy_name(
889 dpif, tp_id, dl_type, nw_proto, tp_name, is_generic)
890 : EOPNOTSUPP);
891 }