netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / lib / ct-dpif.c
1 /*
2  * Copyright (c) 2015 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
19 #include <errno.h>
20
21 #include "ct-dpif.h"
22
23 #include "dpif-provider.h"
24
25 /* Declarations for conntrack entry formatting. */
26 struct flags {
27     uint32_t flag;
28     const char *name;
29 };
30
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 *,
40                                      bool verbose);
41 static void ct_dpif_format_helper(struct ds *, const char *title,
42                                   const struct ct_dpif_helper *);
43
44 static const struct flags ct_dpif_status_flags[] = {
45 #define CT_DPIF_STATUS_FLAG(FLAG) { CT_DPIF_STATUS_##FLAG, #FLAG },
46     CT_DPIF_STATUS_FLAGS
47 #undef CT_DPIF_STATUS_FLAG
48     { 0, NULL } /* End marker. */
49 };
50 \f
51 /* Dumping */
52
53 /* Start dumping the entries from the connection tracker used by 'dpif'.
54  *
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}().
57  *
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.
61  *
62  * If there has been a problem the function returns a non-zero value
63  * that represents the error.  Otherwise it returns zero. */
64 int
65 ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
66                    const uint16_t *zone)
67 {
68     int err;
69
70     err = (dpif->dpif_class->ct_dump_start
71            ? dpif->dpif_class->ct_dump_start(dpif, dump, zone)
72            : EOPNOTSUPP);
73
74     if (!err) {
75         (*dump)->dpif = dpif;
76     }
77
78     return err;
79 }
80
81 /* Dump one connection from a tracker, and put it in 'entry'.
82  *
83  * 'dump' should have been initialized by ct_dpif_dump_start().
84  *
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.
88  * - an error value.
89  * In both cases, the user should call ct_dpif_dump_done(). */
90 int
91 ct_dpif_dump_next(struct ct_dpif_dump_state *dump, struct ct_dpif_entry *entry)
92 {
93     struct dpif *dpif = dump->dpif;
94
95     return (dpif->dpif_class->ct_dump_next
96             ? dpif->dpif_class->ct_dump_next(dpif, dump, entry)
97             : EOPNOTSUPP);
98 }
99
100 /* Free resources used by 'dump' */
101 int
102 ct_dpif_dump_done(struct ct_dpif_dump_state *dump)
103 {
104     struct dpif *dpif = dump->dpif;
105
106     return (dpif->dpif_class->ct_dump_done
107             ? dpif->dpif_class->ct_dump_done(dpif, dump)
108             : EOPNOTSUPP);
109 }
110 \f
111 /* Flush the entries in the connection tracker used by 'dpif'.
112  *
113  * If 'zone' is not NULL, flush only the entries in '*zone'. */
114 int
115 ct_dpif_flush(struct dpif *dpif, const uint16_t *zone)
116 {
117     return (dpif->dpif_class->ct_flush
118             ? dpif->dpif_class->ct_flush(dpif, zone)
119             : EOPNOTSUPP);
120 }
121
122 void
123 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
124 {
125     if (entry) {
126         if (entry->helper.name) {
127             free(entry->helper.name);
128         }
129     }
130 }
131 \f
132 void
133 ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds,
134                      bool verbose, bool print_stats)
135 {
136     ct_dpif_format_ipproto(ds, entry->tuple_orig.ip_proto);
137
138     ds_put_cstr(ds, ",orig=(");
139     ct_dpif_format_tuple(ds, &entry->tuple_orig, verbose);
140     if (print_stats) {
141         ct_dpif_format_counters(ds, &entry->counters_orig);
142     }
143     ds_put_cstr(ds, ")");
144
145     ds_put_cstr(ds, ",reply=(");
146     ct_dpif_format_tuple(ds, &entry->tuple_reply, verbose);
147     if (print_stats) {
148         ct_dpif_format_counters(ds, &entry->counters_reply);
149     }
150     ds_put_cstr(ds, ")");
151
152     if (print_stats) {
153         ct_dpif_format_timestamp(ds, &entry->timestamp);
154     }
155     if (verbose) {
156         ds_put_format(ds, ",id=%"PRIu32, entry->id);
157     }
158     if (entry->zone) {
159         ds_put_format(ds, ",zone=%"PRIu16, entry->zone);
160     }
161     if (verbose) {
162         ct_dpif_format_flags(ds, ",status=", entry->status,
163                              ct_dpif_status_flags);
164     }
165     if (print_stats) {
166         ds_put_format(ds, ",timeout=%"PRIu32, entry->timeout);
167     }
168     if (entry->mark) {
169         ds_put_format(ds, ",mark=%"PRIu32, entry->mark);
170     }
171     if (!ovs_u128_is_zero(&entry->labels)) {
172         ovs_be128 value;
173
174         ds_put_cstr(ds, ",labels=");
175         value = hton128(entry->labels);
176         ds_put_hex(ds, &value, sizeof value);
177     }
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, ")");
184     }
185 }
186
187 static void
188 ct_dpif_format_ipproto(struct ds *ds, uint16_t ipproto)
189 {
190     const char *name;
191
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"
197         : NULL;
198
199     if (name) {
200         ds_put_cstr(ds, name);
201     } else {
202         ds_put_format(ds, "%u", ipproto);
203     }
204 }
205
206 static void
207 ct_dpif_format_counters(struct ds *ds, const struct ct_dpif_counters *counters)
208 {
209     if (counters->packets || counters->bytes) {
210         ds_put_format(ds, ",packets=%"PRIu64",bytes=%"PRIu64,
211                       counters->packets, counters->bytes);
212     }
213 }
214
215 static void
216 ct_dpif_format_timestamp(struct ds *ds,
217                          const struct ct_dpif_timestamp *timestamp)
218 {
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);
225         }
226     }
227 }
228
229 static void
230 ct_dpif_format_tuple_icmp(struct ds *ds, const struct ct_dpif_tuple *tuple,
231                           bool verbose)
232 {
233     if (verbose) {
234         ds_put_format(ds, ",id=%u,type=%u,code=%u",
235                       ntohs(tuple->icmp_id),
236                       tuple->icmp_type,
237                       tuple->icmp_code);
238     } else {
239         ds_put_format(ds, ",id=%u", ntohs(tuple->icmp_id));
240     }
241 }
242
243 static void
244 ct_dpif_format_tuple_tp(struct ds *ds, const struct ct_dpif_tuple *tuple)
245 {
246     ds_put_format(ds, ",sport=%u,dport=%u",
247                   ntohs(tuple->src_port), ntohs(tuple->dst_port));
248 }
249
250 void
251 ct_dpif_format_tuple(struct ds *ds, const struct ct_dpif_tuple *tuple,
252                      bool verbose)
253 {
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);
262     } else {
263         ds_put_format(ds, "Unsupported address family: %u. HEX:\n",
264                       tuple->l3_type);
265         ds_put_hex_dump(ds, tuple, sizeof *tuple, 0, false);
266         return;
267     }
268
269     if (tuple->ip_proto == IPPROTO_ICMP
270         || tuple->ip_proto == IPPROTO_ICMPV6) {
271         ct_dpif_format_tuple_icmp(ds, tuple, verbose);
272     } else {
273         ct_dpif_format_tuple_tp(ds, tuple);
274     }
275 }
276
277 static void
278 ct_dpif_format_flags(struct ds *ds, const char *title, uint32_t flags,
279                      const struct flags *table)
280 {
281     if (title) {
282         ds_put_cstr(ds, title);
283     }
284     for (; table->name; table++) {
285         if (flags & table->flag) {
286             ds_put_format(ds, "%s|", table->name);
287         }
288     }
289     ds_chomp(ds, '|');
290 }
291
292 static const struct flags tcp_flags[] = {
293 #define CT_DPIF_TCP_FLAG(FLAG)  { CT_DPIF_TCPF_##FLAG, #FLAG },
294     CT_DPIF_TCP_FLAGS
295 #undef CT_DPIF_TCP_FLAG
296     { 0, NULL } /* End marker. */
297 };
298
299 const char *ct_dpif_tcp_state_string[] = {
300 #define CT_DPIF_TCP_STATE(STATE) [CT_DPIF_TCPS_##STATE] = #STATE,
301     CT_DPIF_TCP_STATES
302 #undef CT_DPIF_TCP_STATE
303 };
304
305 static void
306 ct_dpif_format_enum__(struct ds *ds, const char *title, unsigned int state,
307                       const char *names[], unsigned int max)
308 {
309     if (title) {
310         ds_put_cstr(ds, title);
311     }
312     if (state < max) {
313         ds_put_cstr(ds, names[state]);
314     } else {
315         ds_put_format(ds, "[%u]", state);
316     }
317 }
318
319 #define ct_dpif_format_enum(DS, TITLE, STATE, NAMES) \
320     ct_dpif_format_enum__((DS), (TITLE), (STATE), (NAMES), ARRAY_SIZE(NAMES))
321
322 static uint8_t
323 coalesce_tcp_state(uint8_t state)
324 {
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. */
329     switch (state) {
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;
334         default:
335             return state;
336     }
337 }
338
339 static void
340 ct_dpif_format_protoinfo_tcp(struct ds *ds,
341                              const struct ct_dpif_protoinfo *protoinfo)
342 {
343     uint8_t tcp_state;
344
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);
349
350     tcp_state = coalesce_tcp_state(tcp_state);
351     ct_dpif_format_enum(ds, "state=", tcp_state, ct_dpif_tcp_state_string);
352 }
353
354 static void
355 ct_dpif_format_protoinfo_tcp_verbose(struct ds *ds,
356                                      const struct ct_dpif_protoinfo *protoinfo)
357 {
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);
362
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);
367     }
368     ct_dpif_format_flags(ds, ",flags_orig=", protoinfo->tcp.flags_orig,
369                          tcp_flags);
370     ct_dpif_format_flags(ds, ",flags_reply=", protoinfo->tcp.flags_reply,
371                          tcp_flags);
372 }
373
374 static void
375 ct_dpif_format_protoinfo(struct ds *ds, const char *title,
376                          const struct ct_dpif_protoinfo *protoinfo,
377                          bool verbose)
378 {
379     if (protoinfo->proto != 0) {
380         if (title) {
381             ds_put_format(ds, "%s(", title);
382         }
383         switch (protoinfo->proto) {
384         case IPPROTO_TCP:
385             if (verbose) {
386                 ct_dpif_format_protoinfo_tcp_verbose(ds, protoinfo);
387             } else {
388                 ct_dpif_format_protoinfo_tcp(ds, protoinfo);
389             }
390             break;
391         }
392         if (title) {
393             ds_put_cstr(ds, ")");
394         }
395     }
396 }
397
398 static void
399 ct_dpif_format_helper(struct ds *ds, const char *title,
400                     const struct ct_dpif_helper *helper)
401 {
402     if (helper->name) {
403         if (title) {
404             ds_put_cstr(ds, title);
405         }
406         ds_put_cstr(ds, helper->name);
407     }
408 }