2 * Copyright (c) 2015 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.
23 #include "dpif-provider.h"
25 /* Declarations for conntrack entry formatting. */
31 static void ct_dpif_format_ipproto(struct ds *, uint16_t ipproto);
32 static void ct_dpif_format_counters(struct ds *,
33 const struct ct_dpif_counters *);
34 static void ct_dpif_format_timestamp(struct ds *,
35 const struct ct_dpif_timestamp *);
36 static void ct_dpif_format_flags(struct ds *, const char *title,
37 uint32_t flags, const struct flags *);
38 static void ct_dpif_format_protoinfo(struct ds *, const char *title,
39 const struct ct_dpif_protoinfo *,
41 static void ct_dpif_format_helper(struct ds *, const char *title,
42 const struct ct_dpif_helper *);
44 static const struct flags ct_dpif_status_flags[] = {
45 #define CT_DPIF_STATUS_FLAG(FLAG) { CT_DPIF_STATUS_##FLAG, #FLAG },
47 #undef CT_DPIF_STATUS_FLAG
48 { 0, NULL } /* End marker. */
53 /* Start dumping the entries from the connection tracker used by 'dpif'.
55 * 'dump' must be the address of a pointer to a struct ct_dpif_dump_state,
56 * which should be passed (unaltered) to ct_dpif_dump_{next,done}().
58 * If 'zone' is not NULL, it should point to an integer identifing a
59 * conntrack zone to which the dump will be limited. If it is NULL,
60 * conntrack entries from all zones will be dumped.
62 * If there has been a problem the function returns a non-zero value
63 * that represents the error. Otherwise it returns zero. */
65 ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
70 err = (dpif->dpif_class->ct_dump_start
71 ? dpif->dpif_class->ct_dump_start(dpif, dump, zone)
81 /* Dump one connection from a tracker, and put it in 'entry'.
83 * 'dump' should have been initialized by ct_dpif_dump_start().
85 * The function returns 0, if an entry has been dumped succesfully.
86 * Otherwise it returns a non-zero value which can be:
87 * - EOF: meaning that there are no more entries to dump.
89 * In both cases, the user should call ct_dpif_dump_done(). */
91 ct_dpif_dump_next(struct ct_dpif_dump_state *dump, struct ct_dpif_entry *entry)
93 struct dpif *dpif = dump->dpif;
95 return (dpif->dpif_class->ct_dump_next
96 ? dpif->dpif_class->ct_dump_next(dpif, dump, entry)
100 /* Free resources used by 'dump' */
102 ct_dpif_dump_done(struct ct_dpif_dump_state *dump)
104 struct dpif *dpif = dump->dpif;
106 return (dpif->dpif_class->ct_dump_done
107 ? dpif->dpif_class->ct_dump_done(dpif, dump)
111 /* Flush the entries in the connection tracker used by 'dpif'.
113 * If 'zone' is not NULL, flush only the entries in '*zone'. */
115 ct_dpif_flush(struct dpif *dpif, const uint16_t *zone)
117 return (dpif->dpif_class->ct_flush
118 ? dpif->dpif_class->ct_flush(dpif, zone)
123 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
126 if (entry->helper.name) {
127 free(entry->helper.name);
133 ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds,
134 bool verbose, bool print_stats)
136 ct_dpif_format_ipproto(ds, entry->tuple_orig.ip_proto);
138 ds_put_cstr(ds, ",orig=(");
139 ct_dpif_format_tuple(ds, &entry->tuple_orig, verbose);
141 ct_dpif_format_counters(ds, &entry->counters_orig);
143 ds_put_cstr(ds, ")");
145 ds_put_cstr(ds, ",reply=(");
146 ct_dpif_format_tuple(ds, &entry->tuple_reply, verbose);
148 ct_dpif_format_counters(ds, &entry->counters_reply);
150 ds_put_cstr(ds, ")");
153 ct_dpif_format_timestamp(ds, &entry->timestamp);
156 ds_put_format(ds, ",id=%"PRIu32, entry->id);
159 ds_put_format(ds, ",zone=%"PRIu16, entry->zone);
162 ct_dpif_format_flags(ds, ",status=", entry->status,
163 ct_dpif_status_flags);
166 ds_put_format(ds, ",timeout=%"PRIu32, entry->timeout);
169 ds_put_format(ds, ",mark=%"PRIu32, entry->mark);
171 if (!ovs_u128_is_zero(entry->labels)) {
174 ds_put_cstr(ds, ",labels=");
175 value = hton128(entry->labels);
176 ds_put_hex(ds, &value, sizeof value);
178 ct_dpif_format_protoinfo(ds, ",protoinfo=", &entry->protoinfo, verbose);
179 ct_dpif_format_helper(ds, ",helper=", &entry->helper);
180 if (verbose && entry->tuple_master.l3_type != 0) {
181 ds_put_cstr(ds, ",master=(");
182 ct_dpif_format_tuple(ds, &entry->tuple_master, verbose);
183 ds_put_cstr(ds, ")");
188 ct_dpif_format_ipproto(struct ds *ds, uint16_t ipproto)
192 name = (ipproto == IPPROTO_ICMP) ? "icmp"
193 : (ipproto == IPPROTO_ICMPV6) ? "icmpv6"
194 : (ipproto == IPPROTO_TCP) ? "tcp"
195 : (ipproto == IPPROTO_UDP) ? "udp"
196 : (ipproto == IPPROTO_SCTP) ? "sctp"
200 ds_put_cstr(ds, name);
202 ds_put_format(ds, "%u", ipproto);
207 ct_dpif_format_counters(struct ds *ds, const struct ct_dpif_counters *counters)
209 if (counters->packets || counters->bytes) {
210 ds_put_format(ds, ",packets=%"PRIu64",bytes=%"PRIu64,
211 counters->packets, counters->bytes);
216 ct_dpif_format_timestamp(struct ds *ds,
217 const struct ct_dpif_timestamp *timestamp)
219 if (timestamp->start || timestamp->stop) {
220 ds_put_strftime_msec(ds, ",start=%Y-%m-%dT%H:%M:%S.###",
221 timestamp->start / UINT64_C(1000000), false);
222 if (timestamp->stop) {
223 ds_put_strftime_msec(ds, ",stop=%Y-%m-%dT%H:%M:%S.###",
224 timestamp->stop / UINT64_C(1000000), false);
230 ct_dpif_format_tuple_icmp(struct ds *ds, const struct ct_dpif_tuple *tuple,
234 ds_put_format(ds, ",id=%u,type=%u,code=%u",
235 ntohs(tuple->icmp_id),
239 ds_put_format(ds, ",id=%u", ntohs(tuple->icmp_id));
244 ct_dpif_format_tuple_tp(struct ds *ds, const struct ct_dpif_tuple *tuple)
246 ds_put_format(ds, ",sport=%u,dport=%u",
247 ntohs(tuple->src_port), ntohs(tuple->dst_port));
251 ct_dpif_format_tuple(struct ds *ds, const struct ct_dpif_tuple *tuple,
254 if (tuple->l3_type == AF_INET) {
255 ds_put_format(ds, "src="IP_FMT",dst="IP_FMT,
256 IP_ARGS(tuple->src.ip), IP_ARGS(tuple->dst.ip));
257 } else if (tuple->l3_type == AF_INET6) {
258 ds_put_cstr(ds, "src=");
259 ipv6_format_addr(&tuple->src.in6, ds);
260 ds_put_cstr(ds, ",dst=");
261 ipv6_format_addr(&tuple->dst.in6, ds);
263 ds_put_format(ds, "Unsupported address family: %u. HEX:\n",
265 ds_put_hex_dump(ds, tuple, sizeof *tuple, 0, false);
269 if (tuple->ip_proto == IPPROTO_ICMP
270 || tuple->ip_proto == IPPROTO_ICMPV6) {
271 ct_dpif_format_tuple_icmp(ds, tuple, verbose);
273 ct_dpif_format_tuple_tp(ds, tuple);
278 ct_dpif_format_flags(struct ds *ds, const char *title, uint32_t flags,
279 const struct flags *table)
282 ds_put_cstr(ds, title);
284 for (; table->name; table++) {
285 if (flags & table->flag) {
286 ds_put_format(ds, "%s|", table->name);
292 static const struct flags tcp_flags[] = {
293 #define CT_DPIF_TCP_FLAG(FLAG) { CT_DPIF_TCPF_##FLAG, #FLAG },
295 #undef CT_DPIF_TCP_FLAG
296 { 0, NULL } /* End marker. */
299 const char *ct_dpif_tcp_state_string[] = {
300 #define CT_DPIF_TCP_STATE(STATE) [CT_DPIF_TCPS_##STATE] = #STATE,
302 #undef CT_DPIF_TCP_STATE
306 ct_dpif_format_enum__(struct ds *ds, const char *title, unsigned int state,
307 const char *names[], unsigned int max)
310 ds_put_cstr(ds, title);
313 ds_put_cstr(ds, names[state]);
315 ds_put_format(ds, "[%u]", state);
319 #define ct_dpif_format_enum(DS, TITLE, STATE, NAMES) \
320 ct_dpif_format_enum__((DS), (TITLE), (STATE), (NAMES), ARRAY_SIZE(NAMES))
323 coalesce_tcp_state(uint8_t state)
325 /* The Linux kernel connection tracker and the userspace view the
326 * tcp states differently in some situations. If we're formatting
327 * the entry without being verbose, it is worth to adjust the
328 * differences, to ease writing testcases. */
330 case CT_DPIF_TCPS_FIN_WAIT_2:
331 return CT_DPIF_TCPS_TIME_WAIT;
332 case CT_DPIF_TCPS_SYN_RECV:
333 return CT_DPIF_TCPS_ESTABLISHED;
340 ct_dpif_format_protoinfo_tcp(struct ds *ds,
341 const struct ct_dpif_protoinfo *protoinfo)
345 /* We keep two separate tcp states, but we print just one. The Linux
346 * kernel connection tracker internally keeps only one state, so
347 * 'state_orig' and 'state_reply', will be the same. */
348 tcp_state = MAX(protoinfo->tcp.state_orig, protoinfo->tcp.state_reply);
350 tcp_state = coalesce_tcp_state(tcp_state);
351 ct_dpif_format_enum(ds, "state=", tcp_state, ct_dpif_tcp_state_string);
355 ct_dpif_format_protoinfo_tcp_verbose(struct ds *ds,
356 const struct ct_dpif_protoinfo *protoinfo)
358 ct_dpif_format_enum(ds, "state_orig=", protoinfo->tcp.state_orig,
359 ct_dpif_tcp_state_string);
360 ct_dpif_format_enum(ds, ",state_reply=", protoinfo->tcp.state_reply,
361 ct_dpif_tcp_state_string);
363 if (protoinfo->tcp.wscale_orig || protoinfo->tcp.wscale_reply) {
364 ds_put_format(ds, ",wscale_orig=%u,wscale_reply=%u",
365 protoinfo->tcp.wscale_orig,
366 protoinfo->tcp.wscale_reply);
368 ct_dpif_format_flags(ds, ",flags_orig=", protoinfo->tcp.flags_orig,
370 ct_dpif_format_flags(ds, ",flags_reply=", protoinfo->tcp.flags_reply,
375 ct_dpif_format_protoinfo(struct ds *ds, const char *title,
376 const struct ct_dpif_protoinfo *protoinfo,
379 if (protoinfo->proto != 0) {
381 ds_put_format(ds, "%s(", title);
383 switch (protoinfo->proto) {
386 ct_dpif_format_protoinfo_tcp_verbose(ds, protoinfo);
388 ct_dpif_format_protoinfo_tcp(ds, protoinfo);
393 ds_put_cstr(ds, ")");
399 ct_dpif_format_helper(struct ds *ds, const char *title,
400 const struct ct_dpif_helper *helper)
404 ds_put_cstr(ds, title);
406 ds_put_cstr(ds, helper->name);