Coverage Report

Created: 2023-03-26 07:41

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