Coverage Report

Created: 2025-08-26 06:20

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