2 * Copyright (c) 2015, 2018 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "dpif-provider.h"
23 #include "openvswitch/ofp-parse.h"
24 #include "openvswitch/vlog.h"
26 VLOG_DEFINE_THIS_MODULE(ct_dpif
);
28 /* Declarations for conntrack entry formatting. */
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
*,
43 static void ct_dpif_format_helper(struct ds
*, const char *title
,
44 const struct ct_dpif_helper
*);
46 static const struct flags ct_dpif_status_flags
[] = {
47 #define CT_DPIF_STATUS_FLAG(FLAG) { CT_DPIF_STATUS_##FLAG, #FLAG },
49 #undef CT_DPIF_STATUS_FLAG
50 { 0, NULL
} /* End marker. */
55 /* Start dumping the entries from the connection tracker used by 'dpif'.
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}().
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.
64 * If there has been a problem the function returns a non-zero value
65 * that represents the error. Otherwise it returns zero. */
67 ct_dpif_dump_start(struct dpif
*dpif
, struct ct_dpif_dump_state
**dump
,
68 const uint16_t *zone
, int *ptot_bkts
)
72 err
= (dpif
->dpif_class
->ct_dump_start
73 ? dpif
->dpif_class
->ct_dump_start(dpif
, dump
, zone
, ptot_bkts
)
83 /* Dump one connection from a tracker, and put it in 'entry'.
85 * 'dump' should have been initialized by ct_dpif_dump_start().
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.
91 * In both cases, the user should call ct_dpif_dump_done(). */
93 ct_dpif_dump_next(struct ct_dpif_dump_state
*dump
, struct ct_dpif_entry
*entry
)
95 struct dpif
*dpif
= dump
->dpif
;
97 return (dpif
->dpif_class
->ct_dump_next
98 ? dpif
->dpif_class
->ct_dump_next(dpif
, dump
, entry
)
102 /* Free resources used by 'dump' */
104 ct_dpif_dump_done(struct ct_dpif_dump_state
*dump
)
106 struct dpif
*dpif
= dump
->dpif
;
108 return (dpif
->dpif_class
->ct_dump_done
109 ? dpif
->dpif_class
->ct_dump_done(dpif
, dump
)
113 /* Flush the entries in the connection tracker used by 'dpif'. The
114 * arguments have the following behavior:
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). */
122 ct_dpif_flush(struct dpif
*dpif
, const uint16_t *zone
,
123 const struct ct_dpif_tuple
*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
),
132 VLOG_DBG("%s: ct_flush: zone %"PRIu16
, dpif_name(dpif
), *zone
);
134 VLOG_DBG("%s: ct_flush: <all>", dpif_name(dpif
));
137 return (dpif
->dpif_class
->ct_flush
138 ? dpif
->dpif_class
->ct_flush(dpif
, zone
, tuple
)
143 ct_dpif_set_maxconns(struct dpif
*dpif
, uint32_t maxconns
)
145 return (dpif
->dpif_class
->ct_set_maxconns
146 ? dpif
->dpif_class
->ct_set_maxconns(dpif
, maxconns
)
151 ct_dpif_get_maxconns(struct dpif
*dpif
, uint32_t *maxconns
)
153 return (dpif
->dpif_class
->ct_get_maxconns
154 ? dpif
->dpif_class
->ct_get_maxconns(dpif
, maxconns
)
159 ct_dpif_get_nconns(struct dpif
*dpif
, uint32_t *nconns
)
161 return (dpif
->dpif_class
->ct_get_nconns
162 ? dpif
->dpif_class
->ct_get_nconns(dpif
, nconns
)
167 ct_dpif_set_tcp_seq_chk(struct dpif
*dpif
, bool enabled
)
169 return (dpif
->dpif_class
->ct_set_tcp_seq_chk
170 ? dpif
->dpif_class
->ct_set_tcp_seq_chk(dpif
, enabled
)
175 ct_dpif_get_tcp_seq_chk(struct dpif
*dpif
, bool *enabled
)
177 return (dpif
->dpif_class
->ct_get_tcp_seq_chk
178 ? dpif
->dpif_class
->ct_get_tcp_seq_chk(dpif
, enabled
)
183 ct_dpif_set_limits(struct dpif
*dpif
, const uint32_t *default_limit
,
184 const struct ovs_list
*zone_limits
)
186 return (dpif
->dpif_class
->ct_set_limits
187 ? dpif
->dpif_class
->ct_set_limits(dpif
, default_limit
,
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
)
197 return (dpif
->dpif_class
->ct_get_limits
198 ? dpif
->dpif_class
->ct_get_limits(dpif
, default_limit
,
205 ct_dpif_del_limits(struct dpif
*dpif
, const struct ovs_list
*zone_limits
)
207 return (dpif
->dpif_class
->ct_del_limits
208 ? dpif
->dpif_class
->ct_del_limits(dpif
, zone_limits
)
213 ct_dpif_ipf_set_enabled(struct dpif
*dpif
, bool v6
, bool enable
)
215 return (dpif
->dpif_class
->ipf_set_enabled
216 ? dpif
->dpif_class
->ipf_set_enabled(dpif
, v6
, enable
)
221 ct_dpif_ipf_set_min_frag(struct dpif
*dpif
, bool v6
, uint32_t min_frag
)
223 return (dpif
->dpif_class
->ipf_set_min_frag
224 ? dpif
->dpif_class
->ipf_set_min_frag(dpif
, v6
, min_frag
)
229 ct_dpif_ipf_set_max_nfrags(struct dpif
*dpif
, uint32_t max_frags
)
231 return (dpif
->dpif_class
->ipf_set_max_nfrags
232 ? dpif
->dpif_class
->ipf_set_max_nfrags(dpif
, max_frags
)
236 int ct_dpif_ipf_get_status(struct dpif
*dpif
,
237 struct dpif_ipf_status
*dpif_ipf_status
)
239 return (dpif
->dpif_class
->ipf_get_status
240 ? dpif
->dpif_class
->ipf_get_status(dpif
, dpif_ipf_status
)
245 ct_dpif_ipf_dump_start(struct dpif
*dpif
, struct ipf_dump_ctx
**dump_ctx
)
247 return (dpif
->dpif_class
->ipf_dump_start
248 ? dpif
->dpif_class
->ipf_dump_start(dpif
, dump_ctx
)
253 ct_dpif_ipf_dump_next(struct dpif
*dpif
, void *dump_ctx
, char **dump
)
255 return (dpif
->dpif_class
->ipf_dump_next
256 ? dpif
->dpif_class
->ipf_dump_next(dpif
, dump_ctx
, dump
)
261 ct_dpif_ipf_dump_done(struct dpif
*dpif
, void *dump_ctx
)
263 return (dpif
->dpif_class
->ipf_dump_done
264 ? dpif
->dpif_class
->ipf_dump_done(dpif
, dump_ctx
)
269 ct_dpif_entry_uninit(struct ct_dpif_entry
*entry
)
272 if (entry
->helper
.name
) {
273 free(entry
->helper
.name
);
279 ct_dpif_format_entry(const struct ct_dpif_entry
*entry
, struct ds
*ds
,
280 bool verbose
, bool print_stats
)
282 ct_dpif_format_ipproto(ds
, entry
->tuple_orig
.ip_proto
);
284 ds_put_cstr(ds
, ",orig=(");
285 ct_dpif_format_tuple(ds
, &entry
->tuple_orig
);
287 ct_dpif_format_counters(ds
, &entry
->counters_orig
);
289 ds_put_cstr(ds
, ")");
291 ds_put_cstr(ds
, ",reply=(");
292 ct_dpif_format_tuple(ds
, &entry
->tuple_reply
);
294 ct_dpif_format_counters(ds
, &entry
->counters_reply
);
296 ds_put_cstr(ds
, ")");
299 ct_dpif_format_timestamp(ds
, &entry
->timestamp
);
302 ds_put_format(ds
, ",id=%"PRIu32
, entry
->id
);
305 ds_put_format(ds
, ",zone=%"PRIu16
, entry
->zone
);
308 ct_dpif_format_flags(ds
, ",status=", entry
->status
,
309 ct_dpif_status_flags
);
312 ds_put_format(ds
, ",timeout=%"PRIu32
, entry
->timeout
);
315 ds_put_format(ds
, ",mark=%"PRIu32
, entry
->mark
);
317 if (!ovs_u128_is_zero(entry
->labels
)) {
320 ds_put_cstr(ds
, ",labels=");
321 value
= hton128(entry
->labels
);
322 ds_put_hex(ds
, &value
, sizeof value
);
324 ct_dpif_format_protoinfo(ds
, ",protoinfo=", &entry
->protoinfo
, verbose
);
325 ct_dpif_format_helper(ds
, ",helper=", &entry
->helper
);
326 if (verbose
&& entry
->tuple_master
.l3_type
!= 0) {
327 ds_put_cstr(ds
, ",master=(");
328 ct_dpif_format_tuple(ds
, &entry
->tuple_master
);
329 ds_put_cstr(ds
, ")");
334 ct_dpif_format_ipproto(struct ds
*ds
, uint16_t ipproto
)
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"
349 ds_put_cstr(ds
, name
);
351 ds_put_format(ds
, "%u", ipproto
);
356 ct_dpif_format_counters(struct ds
*ds
, const struct ct_dpif_counters
*counters
)
358 if (counters
->packets
|| counters
->bytes
) {
359 ds_put_format(ds
, ",packets=%"PRIu64
",bytes=%"PRIu64
,
360 counters
->packets
, counters
->bytes
);
365 ct_dpif_format_timestamp(struct ds
*ds
,
366 const struct ct_dpif_timestamp
*timestamp
)
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);
379 ct_dpif_format_tuple_icmp(struct ds
*ds
, const struct ct_dpif_tuple
*tuple
)
381 ds_put_format(ds
, ",id=%u,type=%u,code=%u", ntohs(tuple
->icmp_id
),
382 tuple
->icmp_type
, tuple
->icmp_code
);
386 ct_dpif_format_tuple_tp(struct ds
*ds
, const struct ct_dpif_tuple
*tuple
)
388 ds_put_format(ds
, ",sport=%u,dport=%u",
389 ntohs(tuple
->src_port
), ntohs(tuple
->dst_port
));
393 ct_dpif_format_tuple(struct ds
*ds
, const struct ct_dpif_tuple
*tuple
)
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
);
404 ds_put_format(ds
, "Unsupported address family: %u. HEX:\n",
406 ds_put_hex_dump(ds
, tuple
, sizeof *tuple
, 0, false);
410 if (tuple
->ip_proto
== IPPROTO_ICMP
411 || tuple
->ip_proto
== IPPROTO_ICMPV6
) {
412 ct_dpif_format_tuple_icmp(ds
, tuple
);
414 ct_dpif_format_tuple_tp(ds
, tuple
);
419 ct_dpif_format_flags(struct ds
*ds
, const char *title
, uint32_t flags
,
420 const struct flags
*table
)
423 ds_put_cstr(ds
, title
);
425 for (; table
->name
; table
++) {
426 if (flags
& table
->flag
) {
427 ds_put_format(ds
, "%s|", table
->name
);
433 static const struct flags tcp_flags
[] = {
434 #define CT_DPIF_TCP_FLAG(FLAG) { CT_DPIF_TCPF_##FLAG, #FLAG },
436 #undef CT_DPIF_TCP_FLAG
437 { 0, NULL
} /* End marker. */
440 const char *ct_dpif_tcp_state_string
[] = {
441 #define CT_DPIF_TCP_STATE(STATE) [CT_DPIF_TCPS_##STATE] = #STATE,
443 #undef CT_DPIF_TCP_STATE
446 const char *ct_dpif_sctp_state_string
[] = {
447 #define CT_DPIF_SCTP_STATE(STATE) [CT_DPIF_SCTP_STATE_##STATE] = #STATE,
449 #undef CT_DPIF_SCTP_STATE
453 ct_dpif_format_enum__(struct ds
*ds
, const char *title
, unsigned int state
,
454 const char *names
[], unsigned int max
)
457 ds_put_cstr(ds
, title
);
460 ds_put_cstr(ds
, names
[state
]);
462 ds_put_format(ds
, "[%u]", state
);
466 #define ct_dpif_format_enum(DS, TITLE, STATE, NAMES) \
467 ct_dpif_format_enum__((DS), (TITLE), (STATE), (NAMES), ARRAY_SIZE(NAMES))
470 coalesce_tcp_state(uint8_t state
)
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. */
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
;
487 ct_dpif_format_protoinfo_tcp(struct ds
*ds
,
488 const struct ct_dpif_protoinfo
*protoinfo
)
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
);
497 tcp_state
= coalesce_tcp_state(tcp_state
);
498 ct_dpif_format_enum(ds
, "state=", tcp_state
, ct_dpif_tcp_state_string
);
502 ct_dpif_format_protoinfo_tcp_verbose(struct ds
*ds
,
503 const struct ct_dpif_protoinfo
*protoinfo
)
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
);
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
);
515 ct_dpif_format_flags(ds
, ",flags_orig=", protoinfo
->tcp
.flags_orig
,
517 ct_dpif_format_flags(ds
, ",flags_reply=", protoinfo
->tcp
.flags_reply
,
522 ct_dpif_format_protoinfo_sctp(struct ds
*ds
,
523 const struct ct_dpif_protoinfo
*protoinfo
)
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
);
532 ct_dpif_format_protoinfo(struct ds
*ds
, const char *title
,
533 const struct ct_dpif_protoinfo
*protoinfo
,
536 if (protoinfo
->proto
!= 0) {
538 ds_put_format(ds
, "%s(", title
);
540 switch (protoinfo
->proto
) {
543 ct_dpif_format_protoinfo_tcp_verbose(ds
, protoinfo
);
545 ct_dpif_format_protoinfo_tcp(ds
, protoinfo
);
549 ct_dpif_format_protoinfo_sctp(ds
, protoinfo
);
553 ds_put_cstr(ds
, ")");
559 ct_dpif_format_helper(struct ds
*ds
, const char *title
,
560 const struct ct_dpif_helper
*helper
)
564 ds_put_cstr(ds
, title
);
566 ds_put_cstr(ds
, helper
->name
);
571 ct_dpif_coalesce_tcp_state(uint8_t state
)
573 return coalesce_tcp_state(state
);
577 ct_dpif_format_tcp_stat(struct ds
* ds
, int tcp_state
, int conn_per_state
)
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
);
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'. */
588 ct_dpif_parse_tuple(struct ct_dpif_tuple
*tuple
, const char *s
, struct ds
*ds
)
590 char *pos
, *key
, *value
, *copy
;
591 memset(tuple
, 0, sizeof *tuple
);
593 pos
= copy
= xstrdup(s
);
594 while (ofputil_parse_key_value(&pos
, &key
, &value
)) {
596 ds_put_format(ds
, "field %s missing value", key
);
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");
605 tuple
->l3_type
= AF_INET
;
607 if (!ip_parse(value
, key
[6] == 's' ? &tuple
->src
.ip
:
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");
617 tuple
->l3_type
= AF_INET6
;
619 if (!ipv6_parse(value
, key
[8] == 's' ? &tuple
->src
.in6
:
623 } else if (!strcmp(key
, "ct_nw_proto")) {
624 char *err
= str_to_u8(value
, key
, &tuple
->ip_proto
);
629 } else if (!strcmp(key
, "ct_tp_src") || !strcmp(key
,"ct_tp_dst")) {
631 char *err
= str_to_u16(value
, key
, &port
);
637 tuple
->src_port
= htons(port
);
639 tuple
->dst_port
= htons(port
);
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");
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
);
655 err
= str_to_u16(value
, key
, &icmp_id
);
656 tuple
->icmp_id
= htons(icmp_id
);
663 ds_put_format(ds
, "invalid conntrack tuple field: %s", key
);
668 if (ipv6_is_zero(&tuple
->src
.in6
) || ipv6_is_zero(&tuple
->dst
.in6
) ||
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 "
685 ds_put_format(ds
, "failed to parse field %s", key
);
692 ct_dpif_push_zone_limit(struct ovs_list
*zone_limits
, uint16_t zone
,
693 uint32_t limit
, uint32_t count
)
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
);
703 ct_dpif_free_zone_limits(struct ovs_list
*zone_limits
)
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
);
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'. */
717 ct_dpif_parse_zone_limit_tuple(const char *s
, uint16_t *pzone
,
718 uint32_t *plimit
, struct ds
*ds
)
720 char *pos
, *key
, *value
, *copy
, *err
;
721 bool parsed_limit
= false, parsed_zone
= false;
723 pos
= copy
= xstrdup(s
);
724 while (ofputil_parse_key_value(&pos
, &key
, &value
)) {
726 ds_put_format(ds
, "field %s missing value", key
);
730 if (!strcmp(key
, "zone")) {
731 err
= str_to_u16(value
, key
, pzone
);
737 } else if (!strcmp(key
, "limit")) {
738 err
= str_to_u32(value
, plimit
);
745 ds_put_format(ds
, "invalid zone limit field: %s", key
);
750 if (!parsed_zone
|| !parsed_limit
) {
751 ds_put_format(ds
, "failed to parse zone limit");
759 ds_put_format(ds
, "failed to parse field %s", key
);
766 ct_dpif_format_zone_limits(uint32_t default_limit
,
767 const struct ovs_list
*zone_limits
, struct ds
*ds
)
769 struct ct_dpif_zone_limit
*zone_limit
;
771 ds_put_format(ds
, "default limit=%"PRIu32
, default_limit
);
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
);
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,
784 #undef CT_DPIF_TP_TCP_ATTR
785 #define CT_DPIF_TP_UDP_ATTR(ATTR) \
786 [CT_DPIF_TP_ATTR_UDP_##ATTR] = "UDP_"#ATTR,
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
796 ct_dpif_set_timeout_policy_attr(struct ct_dpif_timeout_policy
*tp
,
797 uint32_t attr
, uint32_t value
)
799 if (tp
->present
& (1 << attr
) && tp
->attrs
[attr
] == value
) {
802 tp
->attrs
[attr
] = value
;
803 tp
->present
|= 1 << attr
;
807 /* Sets a timeout value identified by '*name' to 'value'.
808 * Returns true if the attribute is changed */
810 ct_dpif_set_timeout_policy_attr_by_name(struct ct_dpif_timeout_policy
*tp
,
811 const char *name
, uint32_t value
)
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
);
822 ct_dpif_timeout_policy_support_ipproto(uint8_t ipproto
)
824 if (ipproto
== IPPROTO_TCP
|| ipproto
== IPPROTO_UDP
||
825 ipproto
== IPPROTO_ICMP
|| ipproto
== IPPROTO_ICMPV6
) {
832 ct_dpif_set_timeout_policy(struct dpif
*dpif
,
833 const struct ct_dpif_timeout_policy
*tp
)
835 return (dpif
->dpif_class
->ct_set_timeout_policy
836 ? dpif
->dpif_class
->ct_set_timeout_policy(dpif
, tp
)
841 ct_dpif_del_timeout_policy(struct dpif
*dpif
, uint32_t tp_id
)
843 return (dpif
->dpif_class
->ct_del_timeout_policy
844 ? dpif
->dpif_class
->ct_del_timeout_policy(dpif
, tp_id
)
849 ct_dpif_get_timeout_policy(struct dpif
*dpif
, uint32_t tp_id
,
850 struct ct_dpif_timeout_policy
*tp
)
852 return (dpif
->dpif_class
->ct_get_timeout_policy
853 ? dpif
->dpif_class
->ct_get_timeout_policy(
854 dpif
, tp_id
, tp
) : EOPNOTSUPP
);
858 ct_dpif_timeout_policy_dump_start(struct dpif
*dpif
, void **statep
)
860 return (dpif
->dpif_class
->ct_timeout_policy_dump_start
861 ? dpif
->dpif_class
->ct_timeout_policy_dump_start(dpif
, statep
)
866 ct_dpif_timeout_policy_dump_next(struct dpif
*dpif
, void *state
,
867 struct ct_dpif_timeout_policy
*tp
)
869 return (dpif
->dpif_class
->ct_timeout_policy_dump_next
870 ? dpif
->dpif_class
->ct_timeout_policy_dump_next(dpif
, state
, tp
)
875 ct_dpif_timeout_policy_dump_done(struct dpif
*dpif
, void *state
)
877 return (dpif
->dpif_class
->ct_timeout_policy_dump_done
878 ? dpif
->dpif_class
->ct_timeout_policy_dump_done(dpif
, state
)
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
)
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
)