]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ct-dpif.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / ct-dpif.c
CommitLineData
3948eb54 1/*
4ea96698 2 * Copyright (c) 2015, 2018 Nicira, Inc.
3948eb54
DDP
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>
2a7c4805 18#include "dpif-provider.h"
3948eb54
DDP
19
20#include <errno.h>
21
22#include "ct-dpif.h"
c43a1331 23#include "openvswitch/ofp-parse.h"
2a7c4805 24#include "openvswitch/vlog.h"
3948eb54 25
2a7c4805 26VLOG_DEFINE_THIS_MODULE(ct_dpif);
b77d9629 27
3948eb54
DDP
28/* Declarations for conntrack entry formatting. */
29struct flags {
30 uint32_t flag;
31 const char *name;
32};
33
3948eb54
DDP
34static void ct_dpif_format_counters(struct ds *,
35 const struct ct_dpif_counters *);
36static void ct_dpif_format_timestamp(struct ds *,
37 const struct ct_dpif_timestamp *);
38static void ct_dpif_format_flags(struct ds *, const char *title,
39 uint32_t flags, const struct flags *);
40static void ct_dpif_format_protoinfo(struct ds *, const char *title,
41 const struct ct_dpif_protoinfo *,
42 bool verbose);
43static void ct_dpif_format_helper(struct ds *, const char *title,
44 const struct ct_dpif_helper *);
45
46static 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
b77d9629
DDP
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. */
66int
67ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
ded30c74 68 const uint16_t *zone, int *ptot_bkts)
b77d9629
DDP
69{
70 int err;
71
72 err = (dpif->dpif_class->ct_dump_start
ded30c74 73 ? dpif->dpif_class->ct_dump_start(dpif, dump, zone, ptot_bkts)
b77d9629
DDP
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(). */
92int
93ct_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' */
103int
104ct_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
817a7657
YHW
113/* Flush the entries in the connection tracker used by 'dpif'. The
114 * arguments have the following behavior:
a0f7b6d5 115 *
817a7657
YHW
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). */
a0f7b6d5 121int
817a7657
YHW
122ct_dpif_flush(struct dpif *dpif, const uint16_t *zone,
123 const struct ct_dpif_tuple *tuple)
a0f7b6d5 124{
817a7657
YHW
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);
2a7c4805
JP
133 } else {
134 VLOG_DBG("%s: ct_flush: <all>", dpif_name(dpif));
135 }
136
a0f7b6d5 137 return (dpif->dpif_class->ct_flush
817a7657 138 ? dpif->dpif_class->ct_flush(dpif, zone, tuple)
a0f7b6d5
DDP
139 : EOPNOTSUPP);
140}
141
c92339ad
DB
142int
143ct_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
150int
151ct_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
875075b3
DB
158int
159ct_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
64207120
DB
166int
167ct_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
174int
175ct_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
cd015a11
YHW
182int
183ct_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
192int
193ct_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
204int
205ct_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
4ea96698
DB
212int
213ct_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
220int
221ct_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
228int
229ct_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
236int 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
244int
245ct_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
252int
253ct_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
260int
261ct_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
3948eb54
DDP
268void
269ct_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
278void
279ct_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=(");
b269a122 285 ct_dpif_format_tuple(ds, &entry->tuple_orig);
3948eb54
DDP
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=(");
b269a122 292 ct_dpif_format_tuple(ds, &entry->tuple_reply);
3948eb54
DDP
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 }
2ff8484b 317 if (!ovs_u128_is_zero(entry->labels)) {
3948eb54
DDP
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);
f51cf36d
BP
326 if (verbose && entry->tuple_parent.l3_type != 0) {
327 ds_put_cstr(ds, ",parent=(");
328 ct_dpif_format_tuple(ds, &entry->tuple_parent);
3948eb54
DDP
329 ds_put_cstr(ds, ")");
330 }
331}
332
934f54a1 333void
3948eb54
DDP
334ct_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"
81f97b1e
JR
343 : (ipproto == IPPROTO_UDPLITE) ? "udplite"
344 : (ipproto == IPPROTO_DCCP) ? "dccp"
345 : (ipproto == IPPROTO_IGMP) ? "igmp"
3948eb54
DDP
346 : NULL;
347
348 if (name) {
349 ds_put_cstr(ds, name);
350 } else {
351 ds_put_format(ds, "%u", ipproto);
352 }
353}
354
355static void
356ct_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
364static void
365ct_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
378static void
b269a122 379ct_dpif_format_tuple_icmp(struct ds *ds, const struct ct_dpif_tuple *tuple)
3948eb54 380{
b269a122
DDP
381 ds_put_format(ds, ",id=%u,type=%u,code=%u", ntohs(tuple->icmp_id),
382 tuple->icmp_type, tuple->icmp_code);
3948eb54
DDP
383}
384
385static void
386ct_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
392void
b269a122 393ct_dpif_format_tuple(struct ds *ds, const struct ct_dpif_tuple *tuple)
3948eb54
DDP
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) {
b269a122 412 ct_dpif_format_tuple_icmp(ds, tuple);
3948eb54
DDP
413 } else {
414 ct_dpif_format_tuple_tp(ds, tuple);
415 }
416}
417
418static void
419ct_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
433static 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
440const 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
93346d88
AC
446const 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
3948eb54
DDP
452static void
453ct_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
469static uint8_t
470coalesce_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
486static void
487ct_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
501static void
502ct_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
93346d88
AC
521static void
522ct_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
3948eb54
DDP
531static void
532ct_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;
93346d88
AC
548 case IPPROTO_SCTP:
549 ct_dpif_format_protoinfo_sctp(ds, protoinfo);
550 break;
3948eb54
DDP
551 }
552 if (title) {
553 ds_put_cstr(ds, ")");
554 }
555 }
556}
557
558static void
559ct_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}
8a0d9d85
FA
569
570uint8_t
571ct_dpif_coalesce_tcp_state(uint8_t state)
572{
573 return coalesce_tcp_state(state);
574}
575
576void
577ct_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}
c43a1331
YHW
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'. */
587bool
588ct_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
684error_with_msg:
685 ds_put_format(ds, "failed to parse field %s", key);
686error:
687 free(copy);
688 return false;
689}
9bc339b6
YHW
690
691void
692ct_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
702void
703ct_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}
4eeec031
YHW
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'. */
716bool
717ct_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
758error_with_msg:
759 ds_put_format(ds, "failed to parse field %s", key);
760error:
761 free(copy);
762 return false;
763}
764
765void
766ct_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}
1f161318
YHW
779
780static 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
795static bool
796ct_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 */
809bool
810ct_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
821bool
822ct_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
831int
832ct_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
840int
841ct_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
848int
849ct_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
857int
858ct_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
865int
866ct_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
874int
875ct_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}
187bb41f
YHW
881
882int
883ct_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}