Coverage Report

Created: 2026-01-17 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/dpctl.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2008-2019 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 <sys/types.h>
19
#include <netinet/in.h>
20
#include <arpa/inet.h>
21
#include <errno.h>
22
#include <inttypes.h>
23
#include <sys/socket.h>
24
#include <net/if.h>
25
#include <stdarg.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <unistd.h>
29
30
#include "command-line.h"
31
#include "compiler.h"
32
#include "ct-dpif.h"
33
#include "dirs.h"
34
#include "dpctl.h"
35
#include "dpif.h"
36
#include "dpif-offload.h"
37
#include "dpif-provider.h"
38
#include "openvswitch/dynamic-string.h"
39
#include "flow.h"
40
#include "openvswitch/match.h"
41
#include "netdev.h"
42
#include "netlink.h"
43
#include "odp-util.h"
44
#include "openvswitch/ofpbuf.h"
45
#include "openvswitch/ofp-ct.h"
46
#include "packets.h"
47
#include "openvswitch/shash.h"
48
#include "simap.h"
49
#include "smap.h"
50
#include "sset.h"
51
#include "timeval.h"
52
#include "unixctl.h"
53
#include "util.h"
54
#include "openvswitch/ofp-flow.h"
55
#include "openvswitch/ofp-port.h"
56
57
enum {
58
    DPCTL_FLOWS_ADD = 0,
59
    DPCTL_FLOWS_DEL,
60
    DPCTL_FLOWS_MOD
61
};
62
63
typedef int dpctl_command_handler(int argc, const char *argv[],
64
                                  struct dpctl_params *);
65
struct dpctl_command {
66
    const char *name;
67
    const char *usage;
68
    int min_args;
69
    int max_args;
70
    dpctl_command_handler *handler;
71
    enum { DP_RO, DP_RW} mode;
72
};
73
static const struct dpctl_command *get_all_dpctl_commands(void);
74
static void dpctl_print(struct dpctl_params *dpctl_p, const char *fmt, ...)
75
    OVS_PRINTF_FORMAT(2, 3);
76
static void dpctl_error(struct dpctl_params* dpctl_p, int err_no,
77
                        const char *fmt, ...)
78
    OVS_PRINTF_FORMAT(3, 4);
79
80
static void
81
dpctl_puts(struct dpctl_params *dpctl_p, bool error, const char *string)
82
0
{
83
0
    dpctl_p->output(dpctl_p->aux, error, string);
84
0
}
85
86
static void
87
dpctl_print(struct dpctl_params *dpctl_p, const char *fmt, ...)
88
0
{
89
0
    char *string;
90
0
    va_list args;
91
92
0
    va_start(args, fmt);
93
0
    string = xvasprintf(fmt, args);
94
0
    va_end(args);
95
96
0
    dpctl_puts(dpctl_p, false, string);
97
0
    free(string);
98
0
}
99
100
static void
101
dpctl_error(struct dpctl_params* dpctl_p, int err_no, const char *fmt, ...)
102
0
{
103
0
    const char *subprogram_name = get_subprogram_name();
104
0
    struct ds ds = DS_EMPTY_INITIALIZER;
105
0
    int save_errno = errno;
106
0
    va_list args;
107
108
109
0
    if (subprogram_name[0]) {
110
0
        ds_put_format(&ds, "%s(%s): ", program_name,subprogram_name);
111
0
    } else {
112
0
        ds_put_format(&ds, "%s: ", program_name);
113
0
    }
114
115
0
    va_start(args, fmt);
116
0
    ds_put_format_valist(&ds, fmt, args);
117
0
    va_end(args);
118
119
0
    if (err_no != 0) {
120
0
        ds_put_format(&ds, " (%s)", ovs_retval_to_string(err_no));
121
0
    }
122
0
    ds_put_cstr(&ds, "\n");
123
124
0
    dpctl_puts(dpctl_p, true, ds_cstr(&ds));
125
126
0
    ds_destroy(&ds);
127
128
0
    errno = save_errno;
129
0
}
130

131
static int dpctl_add_if(int argc, const char *argv[], struct dpctl_params *);
132
133
static int
134
if_up(struct netdev *netdev)
135
0
{
136
0
    return netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
137
0
}
138
139
/* Retrieve the name of the datapath if exactly one exists.  The caller
140
 * is responsible for freeing the returned string.  If a single datapath
141
 * name cannot be determined, returns NULL. */
142
static char *
143
get_one_dp(struct dpctl_params *dpctl_p)
144
0
{
145
0
    struct sset types;
146
0
    const char *type;
147
0
    char *dp_name = NULL;
148
0
    size_t count = 0;
149
150
0
    sset_init(&types);
151
0
    dp_enumerate_types(&types);
152
0
    SSET_FOR_EACH (type, &types) {
153
0
        struct sset names;
154
155
0
        sset_init(&names);
156
0
        if (!dp_enumerate_names(type, &names)) {
157
0
            count += sset_count(&names);
158
0
            if (!dp_name && count == 1) {
159
0
                dp_name = xasprintf("%s@%s", type, SSET_FIRST(&names));
160
0
            }
161
0
        }
162
0
        sset_destroy(&names);
163
0
    }
164
0
    sset_destroy(&types);
165
166
0
    if (!count) {
167
0
        dpctl_error(dpctl_p, 0, "no datapaths exist");
168
0
    } else if (count > 1) {
169
0
        dpctl_error(dpctl_p, 0, "multiple datapaths, specify one");
170
0
        free(dp_name);
171
0
        dp_name = NULL;
172
0
    }
173
174
0
    return dp_name;
175
0
}
176
177
static int
178
parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
179
0
{
180
0
    int result;
181
0
    char *name, *type;
182
183
0
    dp_parse_name(arg_, &name, &type);
184
185
0
    if (create) {
186
0
        result = dpif_create(name, type, dpifp);
187
0
    } else {
188
0
        result = dpif_open(name, type, dpifp);
189
0
    }
190
191
0
    free(name);
192
0
    free(type);
193
0
    return result;
194
0
}
195
196
static bool
197
dp_exists(const char *queried_dp)
198
0
{
199
0
    char *queried_name, *queried_type;
200
0
    dp_parse_name(queried_dp, &queried_name, &queried_type);
201
0
    struct sset dpif_names = SSET_INITIALIZER(&dpif_names),
202
0
                dpif_types = SSET_INITIALIZER(&dpif_types);
203
0
    dp_enumerate_types(&dpif_types);
204
205
0
    bool found = (sset_contains(&dpif_types, queried_type) &&
206
0
                  !dp_enumerate_names(queried_type, &dpif_names) &&
207
0
                  sset_contains(&dpif_names, queried_name));
208
209
0
    sset_destroy(&dpif_names);
210
0
    sset_destroy(&dpif_types);
211
0
    free(queried_name);
212
0
    free(queried_type);
213
0
    return found;
214
0
}
215
216
static bool
217
dp_arg_exists(int argc, const char *argv[])
218
0
{
219
0
    return argc > 1 && dp_exists(argv[1]);
220
0
}
221
222
/* Open a dpif with an optional name argument.
223
 *
224
 * The datapath name is not a mandatory parameter for this command.  If it is
225
 * not specified, we retrieve it from the current setup, assuming only one
226
 * exists.  On success stores the opened dpif in '*dpifp'.  */
227
static int
228
opt_dpif_open(int argc, const char *argv[], struct dpctl_params *dpctl_p,
229
              int max_args, struct dpif **dpifp)
230
0
{
231
0
    char *dpname;
232
233
0
    if (dp_arg_exists(argc, argv)) {
234
0
        dpname = xstrdup(argv[1]);
235
0
    } else if (argc != max_args) {
236
0
        dpname = get_one_dp(dpctl_p);
237
0
    } else {
238
        /* If the arguments are the maximum possible number and there is no
239
         * valid datapath argument, then we fall into the case of dpname is
240
         * NULL, since this is an error. */
241
0
        dpname = NULL;
242
0
    }
243
244
0
    int error = 0;
245
0
    if (!dpname) {
246
0
        error = EINVAL;
247
0
        dpctl_error(dpctl_p, error, "datapath not found");
248
0
    } else {
249
0
        error = parsed_dpif_open(dpname, false, dpifp);
250
0
        free(dpname);
251
0
        if (error) {
252
0
            dpctl_error(dpctl_p, error, "opening datapath");
253
0
        }
254
0
    }
255
0
    return error;
256
0
}
257
258
static int
259
dpctl_add_dp(int argc, const char *argv[],
260
             struct dpctl_params *dpctl_p)
261
0
{
262
0
    struct dpif *dpif;
263
0
    int error;
264
265
0
    error = parsed_dpif_open(argv[1], true, &dpif);
266
0
    if (error) {
267
0
        dpctl_error(dpctl_p, error, "add_dp");
268
0
        return error;
269
0
    }
270
0
    dpif_close(dpif);
271
0
    if (argc > 2) {
272
0
        error = dpctl_add_if(argc, argv, dpctl_p);
273
0
    }
274
0
    return error;
275
0
}
276
277
static int
278
dpctl_del_dp(int argc OVS_UNUSED, const char *argv[],
279
             struct dpctl_params *dpctl_p)
280
0
{
281
0
    struct dpif *dpif;
282
0
    int error;
283
284
0
    error = parsed_dpif_open(argv[1], false, &dpif);
285
0
    if (error) {
286
0
        dpctl_error(dpctl_p, error, "opening datapath");
287
0
        return error;
288
0
    }
289
0
    error = dpif_delete(dpif);
290
0
    if (error) {
291
0
        dpctl_error(dpctl_p, error, "del_dp");
292
0
    }
293
294
0
    dpif_close(dpif);
295
0
    return error;
296
0
}
297
298
static int
299
dpctl_add_if(int argc OVS_UNUSED, const char *argv[],
300
             struct dpctl_params *dpctl_p)
301
0
{
302
0
    struct dpif *dpif;
303
0
    int i, error, lasterror = 0;
304
305
0
    error = parsed_dpif_open(argv[1], false, &dpif);
306
0
    if (error) {
307
0
        dpctl_error(dpctl_p, error, "opening datapath");
308
0
        return error;
309
0
    }
310
0
    for (i = 2; i < argc; i++) {
311
0
        const char *name, *type;
312
0
        char *save_ptr = NULL, *argcopy;
313
0
        struct netdev *netdev = NULL;
314
0
        struct smap args;
315
0
        odp_port_t port_no = ODPP_NONE;
316
0
        char *option;
317
318
0
        argcopy = xstrdup(argv[i]);
319
0
        name = strtok_r(argcopy, ",", &save_ptr);
320
0
        type = "system";
321
322
0
        if (!name) {
323
0
            dpctl_error(dpctl_p, 0, "%s is not a valid network device name",
324
0
                        argv[i]);
325
0
            error = EINVAL;
326
0
            goto next;
327
0
        }
328
329
0
        smap_init(&args);
330
0
        while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
331
0
            char *save_ptr_2 = NULL;
332
0
            char *key, *value;
333
334
0
            key = strtok_r(option, "=", &save_ptr_2);
335
0
            value = strtok_r(NULL, "", &save_ptr_2);
336
0
            if (!value) {
337
0
                value = "";
338
0
            }
339
340
0
            if (!key) {
341
0
                dpctl_error(dpctl_p, 0, "Invalid option format");
342
0
                error = EINVAL;
343
0
                goto next;
344
0
            }
345
346
0
            if (!strcmp(key, "type")) {
347
0
                type = value;
348
0
            } else if (!strcmp(key, "port_no")) {
349
0
                port_no = u32_to_odp(atoi(value));
350
0
            } else if (!smap_add_once(&args, key, value)) {
351
0
                dpctl_error(dpctl_p, 0, "duplicate \"%s\" option", key);
352
0
            }
353
0
        }
354
355
0
        error = netdev_open(name, type, &netdev);
356
0
        if (error) {
357
0
            dpctl_error(dpctl_p, error, "%s: failed to open network device",
358
0
                        name);
359
0
            goto next_destroy_args;
360
0
        }
361
362
0
        error = netdev_set_config(netdev, &args, NULL);
363
0
        if (error) {
364
0
            goto next_destroy_args;
365
0
        }
366
367
0
        error = dpif_port_add(dpif, netdev, &port_no);
368
0
        if (error) {
369
0
            dpctl_error(dpctl_p, error, "adding %s to %s failed", name,
370
0
                        argv[1]);
371
0
            goto next_destroy_args;
372
0
        }
373
374
0
        error = if_up(netdev);
375
0
        if (error) {
376
0
            dpctl_error(dpctl_p, error, "%s: failed bringing interface up",
377
0
                        name);
378
0
        }
379
380
0
next_destroy_args:
381
0
        netdev_close(netdev);
382
0
        smap_destroy(&args);
383
0
next:
384
0
        free(argcopy);
385
0
        if (error) {
386
0
            lasterror = error;
387
0
        }
388
0
    }
389
0
    dpif_close(dpif);
390
391
0
    return lasterror;
392
0
}
393
394
static int
395
dpctl_set_if(int argc, const char *argv[], struct dpctl_params *dpctl_p)
396
0
{
397
0
    struct dpif *dpif;
398
0
    int i, error, lasterror = 0;
399
400
0
    error = parsed_dpif_open(argv[1], false, &dpif);
401
0
    if (error) {
402
0
        dpctl_error(dpctl_p, error, "opening datapath");
403
0
        return error;
404
0
    }
405
0
    for (i = 2; i < argc; i++) {
406
0
        struct netdev *netdev = NULL;
407
0
        struct dpif_port dpif_port;
408
0
        char *save_ptr = NULL;
409
0
        char *type = NULL;
410
0
        char *argcopy;
411
0
        const char *name;
412
0
        struct smap args;
413
0
        odp_port_t port_no;
414
0
        char *option;
415
416
0
        error = 0;
417
418
0
        argcopy = xstrdup(argv[i]);
419
0
        name = strtok_r(argcopy, ",", &save_ptr);
420
0
        if (!name) {
421
0
            dpctl_error(dpctl_p, 0, "%s is not a valid network device name",
422
0
                        argv[i]);
423
0
            goto next;
424
0
        }
425
426
        /* Get the port's type from the datapath. */
427
0
        error = dpif_port_query_by_name(dpif, name, &dpif_port);
428
0
        if (error) {
429
0
            dpctl_error(dpctl_p, error, "%s: failed to query port in %s", name,
430
0
                        argv[1]);
431
0
            goto next;
432
0
        }
433
0
        type = xstrdup(dpif_port.type);
434
0
        port_no = dpif_port.port_no;
435
0
        dpif_port_destroy(&dpif_port);
436
437
        /* Retrieve its existing configuration. */
438
0
        error = netdev_open(name, type, &netdev);
439
0
        if (error) {
440
0
            dpctl_error(dpctl_p, error, "%s: failed to open network device",
441
0
                        name);
442
0
            goto next;
443
0
        }
444
445
0
        smap_init(&args);
446
0
        error = netdev_get_config(netdev, &args);
447
0
        if (error) {
448
0
            dpctl_error(dpctl_p, error, "%s: failed to fetch configuration",
449
0
                        name);
450
0
            goto next_destroy_args;
451
0
        }
452
453
        /* Parse changes to configuration. */
454
0
        while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
455
0
            char *save_ptr_2 = NULL;
456
0
            char *key, *value;
457
458
0
            key = strtok_r(option, "=", &save_ptr_2);
459
0
            value = strtok_r(NULL, "", &save_ptr_2);
460
0
            if (!value) {
461
0
                value = "";
462
0
            }
463
464
0
            if (!key) {
465
0
                dpctl_error(dpctl_p, 0, "Invalid option format");
466
0
                error = EINVAL;
467
0
                goto next_destroy_args;
468
0
            }
469
470
0
            if (!strcmp(key, "type")) {
471
0
                if (strcmp(value, type)) {
472
0
                    dpctl_error(dpctl_p, 0,
473
0
                                "%s: can't change type from %s to %s",
474
0
                                 name, type, value);
475
0
                    error = EINVAL;
476
0
                    goto next_destroy_args;
477
0
                }
478
0
            } else if (!strcmp(key, "port_no")) {
479
0
                if (port_no != u32_to_odp(atoi(value))) {
480
0
                    dpctl_error(dpctl_p, 0, "%s: can't change port number from"
481
0
                              " %"PRIu32" to %d", name, port_no, atoi(value));
482
0
                    error = EINVAL;
483
0
                    goto next_destroy_args;
484
0
                }
485
0
            } else if (value[0] == '\0') {
486
0
                smap_remove(&args, key);
487
0
            } else {
488
0
                smap_replace(&args, key, value);
489
0
            }
490
0
        }
491
492
        /* Update configuration. */
493
0
        char *err_s = NULL;
494
0
        error = netdev_set_config(netdev, &args, &err_s);
495
0
        if (err_s || error) {
496
0
            dpctl_error(dpctl_p, error, "%s",
497
0
                        err_s ? err_s : "Error updating configuration");
498
0
            free(err_s);
499
0
        }
500
0
        if (error) {
501
0
            goto next_destroy_args;
502
0
        }
503
504
0
next_destroy_args:
505
0
        smap_destroy(&args);
506
0
next:
507
0
        netdev_close(netdev);
508
0
        free(type);
509
0
        free(argcopy);
510
0
        if (error) {
511
0
            lasterror = error;
512
0
        }
513
0
    }
514
0
    dpif_close(dpif);
515
516
0
    return lasterror;
517
0
}
518
519
static bool
520
get_port_number(struct dpif *dpif, const char *name, odp_port_t *port,
521
                struct dpctl_params *dpctl_p)
522
0
{
523
0
    struct dpif_port dpif_port;
524
525
0
    if (!dpif_port_query_by_name(dpif, name, &dpif_port)) {
526
0
        *port = dpif_port.port_no;
527
0
        dpif_port_destroy(&dpif_port);
528
0
        return true;
529
0
    } else {
530
0
        dpctl_error(dpctl_p, 0, "no port named %s", name);
531
0
        return false;
532
0
    }
533
0
}
534
535
static int
536
dpctl_del_if(int argc, const char *argv[], struct dpctl_params *dpctl_p)
537
0
{
538
0
    struct dpif *dpif;
539
0
    int i, error, lasterror = 0;
540
541
0
    error = parsed_dpif_open(argv[1], false, &dpif);
542
0
    if (error) {
543
0
        dpctl_error(dpctl_p, error, "opening datapath");
544
0
        return error;
545
0
    }
546
0
    for (i = 2; i < argc; i++) {
547
0
        const char *name = argv[i];
548
0
        odp_port_t port;
549
550
0
        if (!name[strspn(name, "0123456789")]) {
551
0
            port = u32_to_odp(atoi(name));
552
0
        } else if (!get_port_number(dpif, name, &port, dpctl_p)) {
553
0
            lasterror = ENOENT;
554
0
            continue;
555
0
        }
556
557
0
        error = dpif_port_del(dpif, port, false);
558
0
        if (error) {
559
0
            dpctl_error(dpctl_p, error, "deleting port %s from %s failed",
560
0
                        name, argv[1]);
561
0
            lasterror = error;
562
0
        }
563
0
    }
564
0
    dpif_close(dpif);
565
0
    return lasterror;
566
0
}
567
568
static void
569
print_stat(struct dpctl_params *dpctl_p, const char *leader, uint64_t value)
570
0
{
571
0
    dpctl_print(dpctl_p, "%s", leader);
572
0
    if (value != UINT64_MAX) {
573
0
        dpctl_print(dpctl_p, "%"PRIu64, value);
574
0
    } else {
575
0
        dpctl_print(dpctl_p, "?");
576
0
    }
577
0
}
578
579
static void
580
print_human_size(struct dpctl_params *dpctl_p, uint64_t value)
581
0
{
582
0
    if (value == UINT64_MAX) {
583
        /* Nothing to do. */
584
0
    } else if (value >= 1024ULL * 1024 * 1024 * 1024) {
585
0
        dpctl_print(dpctl_p, " (%.1f TiB)",
586
0
                    value / (1024.0 * 1024 * 1024 * 1024));
587
0
    } else if (value >= 1024ULL * 1024 * 1024) {
588
0
        dpctl_print(dpctl_p, " (%.1f GiB)", value / (1024.0 * 1024 * 1024));
589
0
    } else if (value >= 1024ULL * 1024) {
590
0
        dpctl_print(dpctl_p, " (%.1f MiB)", value / (1024.0 * 1024));
591
0
    } else if (value >= 1024) {
592
0
        dpctl_print(dpctl_p, " (%.1f KiB)", value / 1024.0);
593
0
    }
594
0
}
595
596
/* qsort comparison function. */
597
static int
598
compare_port_nos(const void *a_, const void *b_)
599
0
{
600
0
    const odp_port_t *ap = a_;
601
0
    const odp_port_t *bp = b_;
602
0
    uint32_t a = odp_to_u32(*ap);
603
0
    uint32_t b = odp_to_u32(*bp);
604
605
0
    return a < b ? -1 : a > b;
606
0
}
607
608
static void
609
show_dpif_cache__(struct dpif *dpif, struct dpctl_params *dpctl_p)
610
0
{
611
0
    uint32_t nr_caches;
612
0
    int error = dpif_cache_get_supported_levels(dpif, &nr_caches);
613
614
0
    if (error || nr_caches == 0) {
615
0
        return;
616
0
    }
617
618
0
    dpctl_print(dpctl_p, "  caches:\n");
619
0
    for (int i = 0; i < nr_caches; i++) {
620
0
        const char *name;
621
0
        uint32_t size;
622
623
0
        if (dpif_cache_get_name(dpif, i, &name) ||
624
0
            dpif_cache_get_size(dpif, i, &size)) {
625
0
            continue;
626
0
        }
627
0
        dpctl_print(dpctl_p, "    %s: size:%u\n", name, size);
628
0
    }
629
0
}
630
631
static void
632
show_dpif_cache(struct dpif *dpif, struct dpctl_params *dpctl_p)
633
0
{
634
0
    dpctl_print(dpctl_p, "%s:\n", dpif_name(dpif));
635
0
    show_dpif_cache__(dpif, dpctl_p);
636
0
}
637
638
static void
639
show_dpif(struct dpif *dpif, struct dpctl_params *dpctl_p)
640
0
{
641
0
    struct dpif_port_dump dump;
642
0
    struct dpif_port dpif_port;
643
0
    struct dpif_dp_stats stats;
644
0
    struct netdev *netdev;
645
646
0
    dpctl_print(dpctl_p, "%s:\n", dpif_name(dpif));
647
0
    if (!dpif_get_dp_stats(dpif, &stats)) {
648
0
        dpctl_print(dpctl_p, "  lookups: hit:%"PRIu64" missed:%"PRIu64
649
0
                             " lost:%"PRIu64"\n  flows: %"PRIu64"\n",
650
0
                    stats.n_hit, stats.n_missed, stats.n_lost, stats.n_flows);
651
0
        if (stats.n_masks != UINT32_MAX) {
652
0
            uint64_t n_pkts = stats.n_hit + stats.n_missed;
653
0
            double avg = n_pkts ? (double) stats.n_mask_hit / n_pkts : 0.0;
654
655
0
            dpctl_print(dpctl_p, "  masks: hit:%"PRIu64" total:%"PRIu32
656
0
                                 " hit/pkt:%.2f\n",
657
0
                        stats.n_mask_hit, stats.n_masks, avg);
658
659
0
            if (stats.n_cache_hit != UINT64_MAX) {
660
0
                double avg_hits = n_pkts ?
661
0
                    (double) stats.n_cache_hit / n_pkts * 100 : 0.0;
662
663
0
                dpctl_print(dpctl_p,
664
0
                            "  cache: hit:%"PRIu64" hit-rate:%.2f%%\n",
665
0
                            stats.n_cache_hit, avg_hits);
666
0
            }
667
0
        }
668
0
    }
669
670
0
    show_dpif_cache__(dpif, dpctl_p);
671
672
0
    odp_port_t *port_nos = NULL;
673
0
    size_t allocated_port_nos = 0, n_port_nos = 0;
674
0
    DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) {
675
0
        if (n_port_nos >= allocated_port_nos) {
676
0
            port_nos = x2nrealloc(port_nos, &allocated_port_nos,
677
0
                                  sizeof *port_nos);
678
0
        }
679
680
0
        port_nos[n_port_nos] = dpif_port.port_no;
681
0
        n_port_nos++;
682
0
    }
683
684
0
    if (port_nos) {
685
0
        qsort(port_nos, n_port_nos, sizeof *port_nos, compare_port_nos);
686
0
    }
687
688
0
    for (int i = 0; i < n_port_nos; i++) {
689
0
        if (dpif_port_query_by_number(dpif, port_nos[i], &dpif_port, true)) {
690
0
            continue;
691
0
        }
692
693
0
        dpctl_print(dpctl_p, "  port %u: %s",
694
0
                    dpif_port.port_no, dpif_port.name);
695
696
0
        if (strcmp(dpif_port.type, "system")) {
697
0
            int error;
698
699
0
            dpctl_print(dpctl_p, " (%s", dpif_port.type);
700
701
0
            error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
702
0
            if (!error) {
703
0
                struct smap config;
704
705
0
                smap_init(&config);
706
0
                error = netdev_get_config(netdev, &config);
707
0
                if (!error) {
708
0
                    const struct smap_node **nodes = smap_sort(&config);
709
0
                    for (size_t j = 0; j < smap_count(&config); j++) {
710
0
                        const struct smap_node *node = nodes[j];
711
0
                        dpctl_print(dpctl_p, "%c %s=%s", j ? ',' : ':',
712
0
                                    node->key, node->value);
713
0
                    }
714
0
                    free(nodes);
715
0
                } else {
716
0
                    dpctl_print(dpctl_p, ", could not retrieve configuration "
717
0
                                         "(%s)",  ovs_strerror(error));
718
0
                }
719
0
                smap_destroy(&config);
720
721
0
                netdev_close(netdev);
722
0
            } else {
723
0
                dpctl_print(dpctl_p, ": open failed (%s)",
724
0
                            ovs_strerror(error));
725
0
            }
726
0
            dpctl_print(dpctl_p, ")");
727
0
        }
728
0
        dpctl_print(dpctl_p, "\n");
729
730
0
        if (dpctl_p->print_statistics) {
731
0
            struct netdev_stats s;
732
0
            int error;
733
734
0
            error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
735
0
            if (error) {
736
0
                dpctl_print(dpctl_p, ", open failed (%s)",
737
0
                            ovs_strerror(error));
738
0
                dpif_port_destroy(&dpif_port);
739
0
                continue;
740
0
            }
741
0
            error = netdev_get_stats(netdev, &s);
742
0
            netdev_close(netdev);
743
0
            if (!error) {
744
0
                print_stat(dpctl_p, "    RX packets:", s.rx_packets);
745
0
                print_stat(dpctl_p, " errors:", s.rx_errors);
746
0
                print_stat(dpctl_p, " dropped:", s.rx_dropped);
747
0
                print_stat(dpctl_p, " overruns:", s.rx_over_errors);
748
0
                print_stat(dpctl_p, " frame:", s.rx_frame_errors);
749
0
                dpctl_print(dpctl_p, "\n");
750
751
0
                print_stat(dpctl_p, "    TX packets:", s.tx_packets);
752
0
                print_stat(dpctl_p, " errors:", s.tx_errors);
753
0
                print_stat(dpctl_p, " dropped:", s.tx_dropped);
754
0
                print_stat(dpctl_p, " aborted:", s.tx_aborted_errors);
755
0
                print_stat(dpctl_p, " carrier:", s.tx_carrier_errors);
756
0
                dpctl_print(dpctl_p, "\n");
757
758
0
                print_stat(dpctl_p, "    collisions:", s.collisions);
759
0
                dpctl_print(dpctl_p, "\n");
760
761
0
                print_stat(dpctl_p, "    RX bytes:", s.rx_bytes);
762
0
                print_human_size(dpctl_p, s.rx_bytes);
763
0
                print_stat(dpctl_p, "  TX bytes:", s.tx_bytes);
764
0
                print_human_size(dpctl_p, s.tx_bytes);
765
0
                dpctl_print(dpctl_p, "\n");
766
767
0
                print_stat(dpctl_p, "    UPCALL packets:", s.upcall_packets);
768
0
                print_stat(dpctl_p, " errors:", s.upcall_errors);
769
0
                dpctl_print(dpctl_p, "\n");
770
0
            } else {
771
0
                dpctl_print(dpctl_p, ", could not retrieve stats (%s)",
772
0
                            ovs_strerror(error));
773
0
            }
774
0
        }
775
0
        dpif_port_destroy(&dpif_port);
776
0
    }
777
778
0
    free(port_nos);
779
0
}
780
781
typedef void (*dps_for_each_cb)(struct dpif *, struct dpctl_params *);
782
783
static int
784
dps_for_each(struct dpctl_params *dpctl_p, dps_for_each_cb cb)
785
0
{
786
0
    struct sset dpif_names = SSET_INITIALIZER(&dpif_names),
787
0
                dpif_types = SSET_INITIALIZER(&dpif_types);
788
0
    int error, openerror = 0, enumerror = 0;
789
0
    const char *type, *name;
790
0
    bool at_least_one = false;
791
792
0
    dp_enumerate_types(&dpif_types);
793
794
0
    SSET_FOR_EACH (type, &dpif_types) {
795
0
        error = dp_enumerate_names(type, &dpif_names);
796
0
        if (error) {
797
0
            enumerror = error;
798
0
        }
799
800
0
        SSET_FOR_EACH (name, &dpif_names) {
801
0
            struct dpif *dpif;
802
803
0
            at_least_one = true;
804
0
            error = dpif_open(name, type, &dpif);
805
0
            if (!error) {
806
0
                cb(dpif, dpctl_p);
807
0
                dpif_close(dpif);
808
0
            } else {
809
0
                openerror = error;
810
0
                dpctl_error(dpctl_p, error, "opening datapath %s failed",
811
0
                            name);
812
0
            }
813
0
        }
814
0
    }
815
816
0
    sset_destroy(&dpif_names);
817
0
    sset_destroy(&dpif_types);
818
819
    /* If there has been an error while opening a datapath it should be
820
     * reported.  Otherwise, we want to ignore the errors generated by
821
     * dp_enumerate_names() if at least one datapath has been discovered,
822
     * because they're not interesting for the user.  This happens, for
823
     * example, if OVS is using a userspace datapath and the kernel module
824
     * is not loaded. */
825
0
    if (openerror) {
826
0
        return openerror;
827
0
    } else {
828
0
        return at_least_one ? 0 : enumerror;
829
0
    }
830
0
}
831
832
static int
833
dpctl_show(int argc, const char *argv[], struct dpctl_params *dpctl_p)
834
0
{
835
0
    int error, lasterror = 0;
836
0
    if (argc > 1) {
837
0
        int i;
838
0
        for (i = 1; i < argc; i++) {
839
0
            const char *name = argv[i];
840
0
            struct dpif *dpif;
841
842
0
            error = parsed_dpif_open(name, false, &dpif);
843
0
            if (!error) {
844
0
                show_dpif(dpif, dpctl_p);
845
0
                dpif_close(dpif);
846
0
            } else {
847
0
                dpctl_error(dpctl_p, error, "opening datapath %s failed",
848
0
                            name);
849
0
                lasterror = error;
850
0
            }
851
0
        }
852
0
    } else {
853
0
        lasterror = dps_for_each(dpctl_p, show_dpif);
854
0
    }
855
856
0
    return lasterror;
857
0
}
858
859
static void
860
dump_cb(struct dpif *dpif, struct dpctl_params *dpctl_p)
861
0
{
862
0
    dpctl_print(dpctl_p, "%s\n", dpif_name(dpif));
863
0
}
864
865
static int
866
dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
867
               struct dpctl_params *dpctl_p)
868
0
{
869
0
    return dps_for_each(dpctl_p, dump_cb);
870
0
}
871
872
static void
873
format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
874
                 struct dpctl_params *dpctl_p)
875
0
{
876
0
    if (dpctl_p->verbosity && f->ufid_present) {
877
0
        odp_format_ufid(&f->ufid, ds);
878
0
        ds_put_cstr(ds, ", ");
879
0
    }
880
0
    odp_flow_format(f->key, f->key_len, f->mask, f->mask_len, ports, ds,
881
0
                    dpctl_p->verbosity, false);
882
0
    ds_put_cstr(ds, ", ");
883
884
0
    dpif_flow_stats_format(&f->stats, ds);
885
0
    if (dpctl_p->verbosity && f->attrs.offloaded) {
886
0
        if (f->attrs.dp_layer && !strcmp(f->attrs.dp_layer, "ovs")) {
887
0
            ds_put_cstr(ds, ", offloaded:partial");
888
0
        } else {
889
0
            ds_put_cstr(ds, ", offloaded:yes");
890
0
        }
891
0
    }
892
0
    if (dpctl_p->verbosity && f->attrs.dp_layer) {
893
0
        ds_put_format(ds, ", dp:%s", f->attrs.dp_layer);
894
0
    }
895
0
    ds_put_cstr(ds, ", actions:");
896
0
    format_odp_actions(ds, f->actions, f->actions_len, ports);
897
0
    if (dpctl_p->verbosity && f->attrs.dp_extra_info) {
898
0
        ds_put_format(ds, ", dp-extra-info:%s", f->attrs.dp_extra_info);
899
0
    }
900
0
}
901
902
struct dump_types {
903
    bool ovs;
904
    bool tc;
905
    bool dpdk;
906
    bool offloaded;
907
    bool non_offloaded;
908
    bool partially_offloaded;
909
};
910
911
static void
912
enable_all_dump_types(struct dump_types *dump_types)
913
0
{
914
0
    dump_types->ovs = true;
915
0
    dump_types->tc = true;
916
0
    dump_types->dpdk = true;
917
0
    dump_types->offloaded = true;
918
0
    dump_types->non_offloaded = true;
919
0
    dump_types->partially_offloaded = true;
920
0
}
921
922
static int
923
populate_dump_types(char *types_list, struct dump_types *dump_types,
924
                    struct dpctl_params *dpctl_p)
925
0
{
926
0
    if (!types_list) {
927
0
        enable_all_dump_types(dump_types);
928
0
        return 0;
929
0
    }
930
931
0
    char *current_type;
932
933
0
    while (types_list && types_list[0] != '\0') {
934
0
        current_type = types_list;
935
0
        size_t type_len = strcspn(current_type, ",");
936
937
0
        types_list += type_len + (types_list[type_len] != '\0');
938
0
        current_type[type_len] = '\0';
939
940
0
        if (!strcmp(current_type, "ovs")) {
941
0
            dump_types->ovs = true;
942
0
        } else if (!strcmp(current_type, "tc")) {
943
0
            dump_types->tc = true;
944
0
        } else if (!strcmp(current_type, "dpdk")) {
945
0
            dump_types->dpdk = true;
946
0
        } else if (!strcmp(current_type, "offloaded")) {
947
0
            dump_types->offloaded = true;
948
0
        } else if (!strcmp(current_type, "non-offloaded")) {
949
0
            dump_types->non_offloaded = true;
950
0
        } else if (!strcmp(current_type, "partially-offloaded")) {
951
0
            dump_types->partially_offloaded = true;
952
0
        } else if (!strcmp(current_type, "all")) {
953
0
            enable_all_dump_types(dump_types);
954
0
        } else {
955
0
            dpctl_error(dpctl_p, EINVAL, "Failed to parse type (%s)",
956
0
                        current_type);
957
0
            return EINVAL;
958
0
        }
959
0
    }
960
0
    return 0;
961
0
}
962
963
static void
964
determine_dpif_flow_dump_types(struct dump_types *dump_types,
965
                               struct dpif_flow_dump_types *dpif_dump_types)
966
0
{
967
0
    dpif_dump_types->ovs_flows = dump_types->ovs || dump_types->non_offloaded;
968
0
    dpif_dump_types->offloaded_flows = dump_types->tc || dump_types->offloaded
969
0
                                       || dump_types->non_offloaded
970
0
                                       || dump_types->dpdk
971
0
                                       || dump_types->partially_offloaded;
972
0
}
973
974
static bool
975
flow_passes_type_filter(const struct dpif_flow *f,
976
                        struct dump_types *dump_types)
977
0
{
978
0
    if (dump_types->ovs && !strcmp(f->attrs.dp_layer, "ovs")) {
979
0
        return true;
980
0
    }
981
0
    if (dump_types->tc && !strcmp(f->attrs.dp_layer, "tc")) {
982
0
        return true;
983
0
    }
984
0
    if (dump_types->dpdk && !strcmp(f->attrs.dp_layer, "dpdk")) {
985
0
        return true;
986
0
    }
987
0
    if (dump_types->offloaded && f->attrs.offloaded &&
988
0
        strcmp(f->attrs.dp_layer, "ovs")) {
989
0
        return true;
990
0
    }
991
0
    if (dump_types->partially_offloaded && f->attrs.offloaded &&
992
0
        !strcmp(f->attrs.dp_layer, "ovs")) {
993
0
        return true;
994
0
    }
995
0
    if (dump_types->non_offloaded && !(f->attrs.offloaded)) {
996
0
        return true;
997
0
    }
998
0
    return false;
999
0
}
1000
1001
static struct hmap *
1002
dpctl_get_portno_names(struct dpif *dpif, const struct dpctl_params *dpctl_p)
1003
0
{
1004
0
    if (dpctl_p->names) {
1005
0
        struct hmap *portno_names = xmalloc(sizeof *portno_names);
1006
0
        hmap_init(portno_names);
1007
1008
0
        struct dpif_port_dump port_dump;
1009
0
        struct dpif_port dpif_port;
1010
0
        DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
1011
0
            odp_portno_names_set(portno_names, dpif_port.port_no,
1012
0
                                 dpif_port.name);
1013
0
        }
1014
1015
0
        return portno_names;
1016
0
    } else {
1017
0
        return NULL;
1018
0
    }
1019
0
}
1020
1021
static void
1022
dpctl_free_portno_names(struct hmap *portno_names)
1023
0
{
1024
0
    if (portno_names) {
1025
0
        odp_portno_names_destroy(portno_names);
1026
0
        hmap_destroy(portno_names);
1027
0
        free(portno_names);
1028
0
    }
1029
0
}
1030
1031
static int
1032
dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1033
0
{
1034
0
    struct dpif *dpif;
1035
0
    struct ds ds;
1036
1037
0
    char *filter = NULL;
1038
0
    struct flow flow_filter;
1039
0
    struct flow_wildcards wc_filter;
1040
0
    char *types_list = NULL;
1041
0
    struct dump_types dump_types;
1042
0
    struct dpif_flow_dump_types dpif_dump_types;
1043
1044
0
    struct dpif_flow_dump_thread *flow_dump_thread;
1045
0
    struct dpif_flow_dump *flow_dump;
1046
0
    struct dpif_flow f;
1047
0
    int pmd_id = PMD_ID_NULL;
1048
0
    bool pmd_id_filter = false;
1049
0
    int lastargc = 0;
1050
0
    int error;
1051
1052
0
    while (argc > 1 && lastargc != argc) {
1053
0
        lastargc = argc;
1054
0
        if (!strncmp(argv[argc - 1], "filter=", 7) && !filter) {
1055
0
            filter = xstrdup(argv[--argc] + 7);
1056
0
        } else if (!strncmp(argv[argc - 1], "type=", 5) && !types_list) {
1057
0
            if (!dpctl_p->is_appctl) {
1058
0
                dpctl_error(dpctl_p, 0,
1059
0
                            "Invalid argument 'type'. "
1060
0
                            "Use 'ovs-appctl dpctl/dump-flows' instead.");
1061
0
                error = EINVAL;
1062
0
                goto out_free;
1063
0
            }
1064
0
            types_list = xstrdup(argv[--argc] + 5);
1065
0
        } else if (!strncmp(argv[argc - 1], "pmd=", 4)) {
1066
0
            if (!ovs_scan(argv[--argc], "pmd=%d", &pmd_id)) {
1067
0
                error = EINVAL;
1068
0
                goto out_free;
1069
0
            }
1070
1071
0
            if (pmd_id == -1) {
1072
0
                pmd_id = NON_PMD_CORE_ID;
1073
0
            }
1074
0
            pmd_id_filter = true;
1075
0
        }
1076
0
    }
1077
1078
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1079
0
    if (error) {
1080
0
        goto out_free;
1081
0
    }
1082
1083
0
    struct hmap *portno_names = dpctl_get_portno_names(dpif, dpctl_p);
1084
1085
0
    if (filter) {
1086
0
        struct ofputil_port_map port_map;
1087
0
        ofputil_port_map_init(&port_map);
1088
1089
0
        struct dpif_port_dump port_dump;
1090
0
        struct dpif_port dpif_port;
1091
0
        DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
1092
0
            ofputil_port_map_put(&port_map,
1093
0
                                 u16_to_ofp(odp_to_u32(dpif_port.port_no)),
1094
0
                                 dpif_port.name);
1095
0
        }
1096
0
        char *err = parse_ofp_exact_flow(&flow_filter, &wc_filter, NULL,
1097
0
                                         filter, &port_map);
1098
0
        ofputil_port_map_destroy(&port_map);
1099
0
        if (err) {
1100
0
            dpctl_error(dpctl_p, 0, "Failed to parse filter (%s)", err);
1101
0
            free(err);
1102
0
            error = EINVAL;
1103
0
            goto out_dpifclose;
1104
0
        }
1105
0
    }
1106
1107
0
    memset(&dump_types, 0, sizeof dump_types);
1108
0
    error = populate_dump_types(types_list, &dump_types, dpctl_p);
1109
0
    if (error) {
1110
0
        goto out_dpifclose;
1111
0
    }
1112
0
    determine_dpif_flow_dump_types(&dump_types, &dpif_dump_types);
1113
1114
    /* Make sure that these values are different. PMD_ID_NULL means that the
1115
     * pmd is unspecified (e.g. because the datapath doesn't have different
1116
     * pmd threads), while NON_PMD_CORE_ID refers to every non pmd threads
1117
     * in the userspace datapath */
1118
0
    BUILD_ASSERT(PMD_ID_NULL != NON_PMD_CORE_ID);
1119
1120
0
    ds_init(&ds);
1121
0
    memset(&f, 0, sizeof f);
1122
0
    flow_dump = dpif_flow_dump_create(dpif, false, &dpif_dump_types);
1123
0
    flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
1124
0
    while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
1125
0
        if (filter) {
1126
0
            struct flow flow;
1127
0
            struct flow_wildcards wc;
1128
0
            struct match match, match_filter;
1129
0
            struct minimatch minimatch;
1130
1131
0
            odp_flow_key_to_flow(f.key, f.key_len, &flow, NULL);
1132
0
            odp_flow_key_to_mask(f.mask, f.mask_len, &wc, &flow, NULL);
1133
0
            match_init(&match, &flow, &wc);
1134
1135
0
            match_init(&match_filter, &flow_filter, &wc);
1136
0
            match_init(&match_filter, &match_filter.flow, &wc_filter);
1137
0
            minimatch_init(&minimatch, &match_filter);
1138
1139
0
            if (!minimatch_matches_flow(&minimatch, &match.flow)) {
1140
0
                minimatch_destroy(&minimatch);
1141
0
                continue;
1142
0
            }
1143
0
            minimatch_destroy(&minimatch);
1144
0
        }
1145
0
        ds_clear(&ds);
1146
        /* If 'pmd_id' is specified, overlapping flows could be dumped from
1147
         * different pmd threads.  So, separates dumps from different pmds
1148
         * by printing a title line. */
1149
0
        if (!pmd_id_filter && pmd_id != f.pmd_id) {
1150
0
            if (f.pmd_id == NON_PMD_CORE_ID) {
1151
0
                ds_put_format(&ds, "flow-dump from the main thread:\n");
1152
0
            } else {
1153
0
                ds_put_format(&ds, "flow-dump from pmd on cpu core: %d\n",
1154
0
                              f.pmd_id);
1155
0
            }
1156
0
            pmd_id = f.pmd_id;
1157
0
        }
1158
0
        if (pmd_id == f.pmd_id &&
1159
0
            flow_passes_type_filter(&f, &dump_types)) {
1160
0
            format_dpif_flow(&ds, &f, portno_names, dpctl_p);
1161
0
            dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
1162
0
        }
1163
0
    }
1164
0
    dpif_flow_dump_thread_destroy(flow_dump_thread);
1165
0
    error = dpif_flow_dump_destroy(flow_dump);
1166
1167
0
    if (error) {
1168
0
        dpctl_error(dpctl_p, error, "Failed to dump flows from datapath");
1169
0
    }
1170
0
    ds_destroy(&ds);
1171
1172
0
out_dpifclose:
1173
0
    dpctl_free_portno_names(portno_names);
1174
0
    dpif_close(dpif);
1175
0
out_free:
1176
0
    free(filter);
1177
0
    free(types_list);
1178
0
    return error;
1179
0
}
1180
1181
static int
1182
dpctl_put_flow_dpif(struct dpif *dpif, const char *key_s,
1183
                    const char *actions_s,
1184
                    enum dpif_flow_put_flags flags,
1185
                    struct dpctl_params *dpctl_p)
1186
0
{
1187
0
    struct dpif_flow_stats stats;
1188
0
    struct dpif_port dpif_port;
1189
0
    struct dpif_port_dump port_dump;
1190
0
    struct ofpbuf actions;
1191
0
    struct ofpbuf key;
1192
0
    struct ofpbuf mask;
1193
0
    ovs_u128 ufid;
1194
0
    bool ufid_present;
1195
0
    struct simap port_names;
1196
0
    int n, error;
1197
1198
0
    ufid_present = false;
1199
0
    n = odp_ufid_from_string(key_s, &ufid);
1200
0
    if (n < 0) {
1201
0
        dpctl_error(dpctl_p, -n, "parsing flow ufid");
1202
0
        return -n;
1203
0
    } else if (n) {
1204
0
        key_s += n;
1205
0
        ufid_present = true;
1206
0
    }
1207
1208
0
    simap_init(&port_names);
1209
0
    DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
1210
0
        simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
1211
0
    }
1212
1213
0
    ofpbuf_init(&key, 0);
1214
0
    ofpbuf_init(&mask, 0);
1215
0
    char *error_s;
1216
0
    error = odp_flow_from_string(key_s, &port_names, &key, &mask, &error_s);
1217
0
    simap_destroy(&port_names);
1218
0
    if (error) {
1219
0
        dpctl_error(dpctl_p, error, "parsing flow key (%s)", error_s);
1220
0
        free(error_s);
1221
0
        goto out_freekeymask;
1222
0
    }
1223
1224
0
    ofpbuf_init(&actions, 0);
1225
0
    error = odp_actions_from_string(actions_s, NULL, &actions);
1226
0
    if (error) {
1227
0
        dpctl_error(dpctl_p, error, "parsing actions");
1228
0
        goto out_freeactions;
1229
0
    }
1230
1231
0
    if (!ufid_present && dpctl_p->is_appctl) {
1232
        /* Generating UFID for this flow so it could be offloaded to HW.  We're
1233
         * not doing that if invoked from ovs-dpctl utility because
1234
         * odp_flow_key_hash() uses randomly generated base for flow hashes
1235
         * that will be different for each invocation.  And, anyway, offloading
1236
         * is only available via appctl. */
1237
0
        odp_flow_key_hash(key.data, key.size, &ufid);
1238
0
        ufid_present = true;
1239
0
    }
1240
1241
    /* The flow will be added on all pmds currently in the datapath. */
1242
0
    error = dpif_flow_put(dpif, flags,
1243
0
                          key.data, key.size,
1244
0
                          mask.size == 0 ? NULL : mask.data,
1245
0
                          mask.size, actions.data,
1246
0
                          actions.size, ufid_present ? &ufid : NULL,
1247
0
                          PMD_ID_NULL,
1248
0
                          dpctl_p->print_statistics ? &stats : NULL);
1249
1250
0
    if (error) {
1251
0
        dpctl_error(dpctl_p, error, "updating flow table");
1252
0
        goto out_freeactions;
1253
0
    }
1254
1255
0
    if (dpctl_p->print_statistics) {
1256
0
        struct ds s;
1257
1258
0
        ds_init(&s);
1259
0
        dpif_flow_stats_format(&stats, &s);
1260
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1261
0
        ds_destroy(&s);
1262
0
    }
1263
1264
0
out_freeactions:
1265
0
    ofpbuf_uninit(&actions);
1266
0
out_freekeymask:
1267
0
    ofpbuf_uninit(&mask);
1268
0
    ofpbuf_uninit(&key);
1269
0
    return error;
1270
0
}
1271
1272
static int
1273
dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
1274
               struct dpctl_params *dpctl_p)
1275
0
{
1276
0
    struct dpif *dpif;
1277
0
    int error;
1278
1279
0
    error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
1280
0
    if (error) {
1281
0
        return error;
1282
0
    }
1283
1284
0
    error = dpctl_put_flow_dpif(dpif, argv[argc - 2], argv[argc - 1], flags,
1285
0
                                dpctl_p);
1286
1287
0
    dpif_close(dpif);
1288
0
    return error;
1289
0
}
1290
1291
static int
1292
dpctl_add_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1293
0
{
1294
0
    return dpctl_put_flow(argc, argv, DPIF_FP_CREATE, dpctl_p);
1295
0
}
1296
1297
static int
1298
dpctl_mod_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1299
0
{
1300
0
    enum dpif_flow_put_flags flags;
1301
1302
0
    flags = DPIF_FP_MODIFY;
1303
0
    if (dpctl_p->may_create) {
1304
0
        flags |= DPIF_FP_CREATE;
1305
0
    }
1306
0
    if (dpctl_p->zero_statistics) {
1307
0
        flags |= DPIF_FP_ZERO_STATS;
1308
0
    }
1309
1310
0
    return dpctl_put_flow(argc, argv, flags, dpctl_p);
1311
0
}
1312
1313
static int
1314
dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1315
0
{
1316
0
    const char *key_s = argv[argc - 1];
1317
0
    struct dpif_flow flow;
1318
0
    struct dpif *dpif;
1319
0
    ovs_u128 ufid;
1320
0
    struct ofpbuf buf;
1321
0
    uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
1322
0
    struct ds ds;
1323
0
    int n, error;
1324
1325
0
    error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
1326
0
    if (error) {
1327
0
        return error;
1328
0
    }
1329
1330
0
    ofpbuf_use_stub(&buf, &stub, sizeof stub);
1331
1332
0
    struct hmap *portno_names = dpctl_get_portno_names(dpif, dpctl_p);
1333
1334
0
    n = odp_ufid_from_string(key_s, &ufid);
1335
0
    if (n <= 0) {
1336
0
        dpctl_error(dpctl_p, -n, "parsing flow ufid");
1337
0
        goto out;
1338
0
    }
1339
1340
    /* In case of PMD will be returned flow from first PMD thread with match. */
1341
0
    error = dpif_flow_get(dpif, NULL, 0, &ufid, PMD_ID_NULL, &buf, &flow);
1342
0
    if (error) {
1343
0
        dpctl_error(dpctl_p, error, "getting flow");
1344
0
        goto out;
1345
0
    }
1346
1347
0
    ds_init(&ds);
1348
0
    format_dpif_flow(&ds, &flow, portno_names, dpctl_p);
1349
0
    dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
1350
0
    ds_destroy(&ds);
1351
1352
0
out:
1353
0
    dpctl_free_portno_names(portno_names);
1354
0
    ofpbuf_uninit(&buf);
1355
0
    dpif_close(dpif);
1356
0
    return error;
1357
0
}
1358
1359
static int
1360
dpctl_del_flow_dpif(struct dpif *dpif, const char *key_s,
1361
                    struct dpctl_params *dpctl_p)
1362
0
{
1363
0
    struct dpif_port_dump port_dump;
1364
0
    struct dpif_flow_stats stats;
1365
0
    bool ufid_generated = false;
1366
0
    struct dpif_port dpif_port;
1367
0
    bool ufid_present = false;
1368
0
    struct simap port_names;
1369
0
    struct ofpbuf mask; /* To be ignored. */
1370
0
    struct ofpbuf key;
1371
0
    ovs_u128 ufid;
1372
0
    int n, error;
1373
1374
0
    n = odp_ufid_from_string(key_s, &ufid);
1375
0
    if (n < 0) {
1376
0
        dpctl_error(dpctl_p, -n, "parsing flow ufid");
1377
0
        return -n;
1378
0
    } else if (n) {
1379
0
        key_s += n;
1380
0
        ufid_present = true;
1381
0
    }
1382
1383
0
    simap_init(&port_names);
1384
0
    DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
1385
0
        simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
1386
0
    }
1387
1388
0
    ofpbuf_init(&key, 0);
1389
0
    ofpbuf_init(&mask, 0);
1390
1391
0
    char *error_s;
1392
0
    error = odp_flow_from_string(key_s, &port_names, &key, &mask, &error_s);
1393
0
    if (error) {
1394
0
        dpctl_error(dpctl_p, error, "%s", error_s);
1395
0
        free(error_s);
1396
0
        goto out;
1397
0
    }
1398
1399
0
    if (!ufid_present && dpctl_p->is_appctl) {
1400
        /* While adding flow via appctl we're generating UFID to make HW
1401
         * offloading possible.  Generating UFID here to be sure that such
1402
         * flows could be removed the same way they were added. */
1403
0
        odp_flow_key_hash(key.data, key.size, &ufid);
1404
0
        ufid_present = ufid_generated = true;
1405
0
    }
1406
1407
    /* The flow will be deleted from all pmds currently in the datapath. */
1408
0
    error = dpif_flow_del(dpif, key.data, key.size,
1409
0
                          ufid_present ? &ufid : NULL, PMD_ID_NULL,
1410
0
                          dpctl_p->print_statistics ? &stats : NULL);
1411
1412
0
    if (error) {
1413
0
        dpctl_error(dpctl_p, error, "deleting flow");
1414
0
        if (error == ENOENT && (!ufid_present || ufid_generated)) {
1415
0
            struct ds s;
1416
1417
0
            ds_init(&s);
1418
0
            ds_put_format(&s, "Perhaps you need to specify a UFID?");
1419
0
            dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1420
0
            ds_destroy(&s);
1421
0
        }
1422
0
        goto out;
1423
0
    }
1424
1425
0
    if (dpctl_p->print_statistics) {
1426
0
        struct ds s;
1427
1428
0
        ds_init(&s);
1429
0
        dpif_flow_stats_format(&stats, &s);
1430
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1431
0
        ds_destroy(&s);
1432
0
    }
1433
1434
0
out:
1435
0
    ofpbuf_uninit(&mask);
1436
0
    ofpbuf_uninit(&key);
1437
0
    simap_destroy(&port_names);
1438
0
    return error;
1439
0
}
1440
1441
static int
1442
dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1443
0
{
1444
0
    const char *key_s = argv[argc - 1];
1445
0
    struct dpif *dpif;
1446
0
    int error;
1447
1448
0
    error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
1449
0
    if (error) {
1450
0
        return error;
1451
0
    }
1452
1453
0
    error = dpctl_del_flow_dpif(dpif, key_s, dpctl_p);
1454
1455
0
    dpif_close(dpif);
1456
0
    return error;
1457
0
}
1458
1459
static int
1460
dpctl_parse_flow_line(int command, struct ds *s, char **flow, char **action)
1461
0
{
1462
0
    const char *line = ds_cstr(s);
1463
0
    size_t len;
1464
1465
    /* First figure out the command, or fallback to FLOWS_ADD. */
1466
0
    line += strspn(line, " \t\r\n");
1467
0
    len = strcspn(line, ", \t\r\n");
1468
1469
0
    if (!strncmp(line, "add", len)) {
1470
0
         command = DPCTL_FLOWS_ADD;
1471
0
    } else if (!strncmp(line, "delete", len)) {
1472
0
        command = DPCTL_FLOWS_DEL;
1473
0
    } else if (!strncmp(line, "modify", len)) {
1474
0
        command = DPCTL_FLOWS_MOD;
1475
0
    } else {
1476
0
        len = 0;
1477
0
    }
1478
0
    line += len;
1479
1480
    /* Isolate flow and action (for add/modify). */
1481
0
    line += strspn(line, " \t\r\n");
1482
0
    len = strcspn(line, " \t\r\n");
1483
1484
0
    if (len == 0) {
1485
0
        *flow = NULL;
1486
0
        *action = NULL;
1487
0
        return command;
1488
0
    }
1489
1490
0
    *flow = xzalloc(len + 1);
1491
0
    ovs_strlcpy(*flow, line, len + 1);
1492
1493
0
    line += len;
1494
0
    line += strspn(line, " \t\r\n");
1495
0
    if (strlen(line)) {
1496
0
        *action = xstrdup(line);
1497
0
    } else {
1498
0
        *action = NULL;
1499
0
    }
1500
1501
0
    return command;
1502
0
}
1503
1504
static int
1505
dpctl_process_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1506
0
{
1507
0
    const char *file_name = argv[argc - 1];
1508
0
    int line_number = 0;
1509
0
    struct dpif *dpif;
1510
0
    struct ds line;
1511
0
    FILE *stream;
1512
0
    int error;
1513
0
    int def_cmd = DPCTL_FLOWS_ADD;
1514
1515
0
    if (strstr(argv[0], "mod-flows")) {
1516
0
        def_cmd = DPCTL_FLOWS_MOD;
1517
0
    } else if (strstr(argv[0], "del-flows")) {
1518
0
        def_cmd = DPCTL_FLOWS_DEL;
1519
0
    }
1520
1521
0
    error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
1522
0
    if (error) {
1523
0
        return error;
1524
0
    }
1525
1526
0
    stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
1527
0
    if (!stream) {
1528
0
        error = errno;
1529
0
        dpctl_error(dpctl_p, error, "Opening file \"%s\" failed", file_name);
1530
0
        goto out_close_dpif;
1531
0
    }
1532
1533
0
    ds_init(&line);
1534
0
    while (!ds_get_preprocessed_line(&line, stream, &line_number)) {
1535
        /* We do not process all the lines first and then execute the actions
1536
         * as we would like to take commands as a continuous stream of
1537
         * commands from stdin.
1538
         */
1539
0
        char *flow = NULL;
1540
0
        char *action = NULL;
1541
0
        int cmd = dpctl_parse_flow_line(def_cmd, &line, &flow, &action);
1542
1543
0
        if ((!flow && !action)
1544
0
            || ((cmd == DPCTL_FLOWS_ADD || cmd == DPCTL_FLOWS_MOD) && !action)
1545
0
            || (cmd == DPCTL_FLOWS_DEL && action)) {
1546
0
            dpctl_error(dpctl_p, 0,
1547
0
                        "Failed parsing line number %u, skipped!",
1548
0
                        line_number);
1549
0
        } else {
1550
0
            switch (cmd) {
1551
0
            case DPCTL_FLOWS_ADD:
1552
0
                dpctl_put_flow_dpif(dpif, flow, action,
1553
0
                                    DPIF_FP_CREATE, dpctl_p);
1554
0
                break;
1555
0
            case DPCTL_FLOWS_MOD:
1556
0
                dpctl_put_flow_dpif(dpif, flow, action,
1557
0
                                    DPIF_FP_MODIFY, dpctl_p);
1558
0
                break;
1559
0
            case DPCTL_FLOWS_DEL:
1560
0
                dpctl_del_flow_dpif(dpif, flow, dpctl_p);
1561
0
                break;
1562
0
            }
1563
0
        }
1564
1565
0
        free(flow);
1566
0
        free(action);
1567
0
    }
1568
1569
0
    ds_destroy(&line);
1570
0
    if (stream != stdin) {
1571
0
        fclose(stream);
1572
0
    }
1573
0
out_close_dpif:
1574
0
    dpif_close(dpif);
1575
0
    return 0;
1576
0
}
1577
1578
static int
1579
dpctl_del_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1580
0
{
1581
0
    struct dpif *dpif;
1582
0
    int error;
1583
1584
0
    if ((!dp_arg_exists(argc, argv) && argc == 2) || argc > 2) {
1585
0
        return dpctl_process_flows(argc, argv, dpctl_p);
1586
0
    }
1587
1588
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1589
0
    if (error) {
1590
0
        return error;
1591
0
    }
1592
1593
0
    error = dpif_flow_flush(dpif);
1594
0
    if (error) {
1595
0
        dpctl_error(dpctl_p, error, "deleting all flows");
1596
0
    }
1597
0
    dpif_close(dpif);
1598
0
    return error;
1599
0
}
1600
1601
static int
1602
compare_custom_stats(const void *a, const void *b)
1603
0
{
1604
0
    const struct netdev_custom_stats *sa = a;
1605
0
    const struct netdev_custom_stats *sb = b;
1606
1607
0
    return sa->label && sb->label ? strcmp(sa->label, sb->label)
1608
0
                                  : (sa->label != NULL) - (sb->label != NULL);
1609
0
}
1610
1611
static int
1612
dpctl_offload_stats_show(int argc, const char *argv[],
1613
                         struct dpctl_params *dpctl_p)
1614
0
{
1615
0
    struct netdev_custom_stats *stats_array;
1616
0
    struct dpif *dpif;
1617
0
    size_t n_stats;
1618
0
    int error;
1619
1620
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1621
0
    if (error) {
1622
0
        return error;
1623
0
    }
1624
1625
0
    error = dpif_offload_stats_get(dpif, &stats_array, &n_stats);
1626
0
    if (error) {
1627
0
        dpctl_error(dpctl_p, error, "retrieving offload statistics");
1628
0
        goto close_dpif;
1629
0
    }
1630
1631
0
    if (stats_array && n_stats) {
1632
0
        qsort(stats_array, n_stats, sizeof *stats_array, compare_custom_stats);
1633
0
    }
1634
1635
0
    dpctl_print(dpctl_p, "HW Offload stats:\n");
1636
0
    for (size_t i = 0; i < n_stats; i++) {
1637
0
        struct netdev_custom_stats *stats = &stats_array[i];
1638
1639
0
        if (!stats) {
1640
0
            continue;
1641
0
        }
1642
1643
0
        if (stats->label) {
1644
0
            dpctl_print(dpctl_p, "  %s:\n", stats->label);
1645
0
        }
1646
0
        for (size_t j = 0; j < stats->size; j++) {
1647
0
            dpctl_print(dpctl_p, "    %s: %6" PRIu64 "\n",
1648
0
                        stats->counters[j].name, stats->counters[j].value);
1649
0
        }
1650
0
        netdev_free_custom_stats_counters(stats);
1651
0
    }
1652
1653
0
    free(stats_array);
1654
1655
0
close_dpif:
1656
0
    dpif_close(dpif);
1657
0
    return error;
1658
0
}
1659
1660
static int
1661
dpctl_help(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
1662
           struct dpctl_params *dpctl_p)
1663
0
{
1664
0
    if (dpctl_p->usage) {
1665
0
        dpctl_p->usage(dpctl_p->aux);
1666
0
    }
1667
1668
0
    return 0;
1669
0
}
1670
1671
static int
1672
dpctl_list_commands(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
1673
                    struct dpctl_params *dpctl_p)
1674
0
{
1675
0
    struct ds ds = DS_EMPTY_INITIALIZER;
1676
0
    const struct dpctl_command *commands = get_all_dpctl_commands();
1677
1678
0
    ds_put_cstr(&ds, "The available commands are:\n");
1679
0
    for (; commands->name; commands++) {
1680
0
        const struct dpctl_command *c = commands;
1681
1682
0
        if (dpctl_p->is_appctl && !strcmp(c->name, "help")) {
1683
0
            continue;
1684
0
        }
1685
1686
0
        ds_put_format(&ds, "  %s%-23s %s\n", dpctl_p->is_appctl ? "dpctl/" : "",
1687
0
                      c->name, c->usage);
1688
0
    }
1689
0
    dpctl_puts(dpctl_p, false, ds.string);
1690
0
    ds_destroy(&ds);
1691
1692
0
    return 0;
1693
0
}
1694

1695
1696
static int
1697
dpctl_dump_conntrack(int argc, const char *argv[],
1698
                     struct dpctl_params *dpctl_p)
1699
0
{
1700
0
    struct ct_dpif_dump_state *dump;
1701
0
    struct ct_dpif_entry cte;
1702
0
    uint16_t zone, *pzone = NULL;
1703
0
    int tot_bkts;
1704
0
    struct dpif *dpif;
1705
0
    int error;
1706
1707
0
    if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1708
0
        pzone = &zone;
1709
0
        argc--;
1710
0
    }
1711
1712
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1713
0
    if (error) {
1714
0
        return error;
1715
0
    }
1716
1717
0
    error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1718
0
    if (error) {
1719
0
        dpctl_error(dpctl_p, error, "starting conntrack dump");
1720
0
        dpif_close(dpif);
1721
0
        return error;
1722
0
    }
1723
1724
0
    while (!(error = ct_dpif_dump_next(dump, &cte))) {
1725
0
        struct ds s = DS_EMPTY_INITIALIZER;
1726
1727
0
        ct_dpif_format_entry(&cte, &s, dpctl_p->verbosity,
1728
0
                             dpctl_p->print_statistics);
1729
0
        ct_dpif_entry_uninit(&cte);
1730
1731
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1732
0
        ds_destroy(&s);
1733
0
    }
1734
0
    if (error == EOF) {
1735
        /* Any CT entry was dumped with no issue. */
1736
0
        error = 0;
1737
0
    } else if (error) {
1738
0
        dpctl_error(dpctl_p, error, "dumping conntrack entry");
1739
0
    }
1740
1741
0
    ct_dpif_dump_done(dump);
1742
0
    dpif_close(dpif);
1743
0
    return error;
1744
0
}
1745
1746
static int
1747
dpctl_dump_conntrack_exp(int argc, const char *argv[],
1748
                         struct dpctl_params *dpctl_p)
1749
0
{
1750
0
    struct ct_dpif_dump_state *dump;
1751
0
    uint16_t zone, *pzone = NULL;
1752
0
    struct ct_dpif_exp cte;
1753
0
    struct dpif *dpif;
1754
0
    int error;
1755
1756
0
    if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1757
0
        pzone = &zone;
1758
0
        argc--;
1759
0
    }
1760
1761
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1762
0
    if (error) {
1763
0
        return error;
1764
0
    }
1765
1766
0
    error = ct_exp_dpif_dump_start(dpif, &dump, pzone);
1767
0
    if (error) {
1768
0
        dpctl_error(dpctl_p, error, "starting conntrack expectations dump");
1769
0
        dpif_close(dpif);
1770
0
        return error;
1771
0
    }
1772
1773
0
    while (!(error = ct_exp_dpif_dump_next(dump, &cte))) {
1774
0
        struct ds s = DS_EMPTY_INITIALIZER;
1775
1776
0
        ct_dpif_format_exp_entry(&cte, &s);
1777
1778
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1779
0
        ds_destroy(&s);
1780
0
    }
1781
0
    if (error == EOF) {
1782
0
        error = 0;
1783
0
    } else if (error) {
1784
0
        dpctl_error(dpctl_p, error, "dumping conntrack expectation");
1785
0
    }
1786
1787
0
    ct_exp_dpif_dump_done(dump);
1788
0
    dpif_close(dpif);
1789
1790
0
    return error;
1791
0
}
1792
1793
static int
1794
dpctl_flush_conntrack(int argc, const char *argv[],
1795
                      struct dpctl_params *dpctl_p)
1796
0
{
1797
0
    struct dpif *dpif = NULL;
1798
0
    struct ofp_ct_match match = {0};
1799
0
    struct ds ds = DS_EMPTY_INITIALIZER;
1800
0
    uint16_t zone;
1801
0
    int error;
1802
0
    int args = argc - 1;
1803
0
    bool with_zone = false;
1804
1805
0
    if (dp_arg_exists(argc, argv)) {
1806
0
        args--;
1807
0
    }
1808
1809
0
    if (args && !ofp_ct_match_parse(&argv[argc - args], args, &ds, &match,
1810
0
                                    &with_zone, &zone)) {
1811
0
        error = EINVAL;
1812
0
        goto error;
1813
0
    }
1814
1815
0
    error = opt_dpif_open(argc, argv, dpctl_p, 5, &dpif);
1816
0
    if (error) {
1817
0
        dpctl_error(dpctl_p, error, "Cannot open dpif");
1818
0
        return error;
1819
0
    }
1820
1821
0
    error = ct_dpif_flush(dpif, with_zone ? &zone : NULL, &match);
1822
0
    if (!error) {
1823
0
        dpif_close(dpif);
1824
0
        return 0;
1825
0
    } else {
1826
0
        ds_put_cstr(&ds, "failed to flush conntrack");
1827
0
    }
1828
1829
0
error:
1830
0
    dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
1831
0
    ds_destroy(&ds);
1832
0
    dpif_close(dpif);
1833
0
    return error;
1834
0
}
1835
1836
static int
1837
dpctl_ct_stats_show(int argc, const char *argv[],
1838
                     struct dpctl_params *dpctl_p)
1839
0
{
1840
0
    struct dpif *dpif;
1841
0
    struct ct_dpif_dump_state *dump;
1842
0
    struct ct_dpif_entry cte;
1843
0
    uint16_t zone, *pzone = NULL;
1844
0
    int tot_bkts;
1845
0
    int lastargc = 0;
1846
1847
0
    int proto_stats[CT_STATS_MAX];
1848
0
    int tcp_conn_per_states[CT_DPIF_TCPS_MAX_NUM];
1849
0
    int error;
1850
1851
0
    bool verbose = dpctl_p->verbosity;
1852
1853
0
    while (argc > 1 && lastargc != argc) {
1854
0
        lastargc = argc;
1855
0
        if (!strncmp(argv[argc - 1], "verbose", 7)) {
1856
            /* Support "verbose" argument for backwards compatibility. */
1857
0
            verbose = true;
1858
0
            argc--;
1859
0
        } else if (!strncmp(argv[argc - 1], "zone=", 5)) {
1860
0
            if (ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1861
0
                pzone = &zone;
1862
0
                argc--;
1863
0
            }
1864
0
        }
1865
0
    }
1866
1867
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1868
0
    if (error) {
1869
0
        return error;
1870
0
    }
1871
1872
0
    memset(proto_stats, 0, sizeof(proto_stats));
1873
0
    memset(tcp_conn_per_states, 0, sizeof(tcp_conn_per_states));
1874
0
    error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1875
0
    if (error) {
1876
0
        dpctl_error(dpctl_p, error, "starting conntrack dump");
1877
0
        dpif_close(dpif);
1878
0
        return error;
1879
0
    }
1880
1881
0
    int tot_conn = 0;
1882
0
    while (!(error = ct_dpif_dump_next(dump, &cte))) {
1883
0
        ct_dpif_entry_uninit(&cte);
1884
0
        tot_conn++;
1885
0
        switch (cte.tuple_orig.ip_proto) {
1886
0
        case IPPROTO_ICMP:
1887
0
            proto_stats[CT_STATS_ICMP]++;
1888
0
            break;
1889
0
        case IPPROTO_ICMPV6:
1890
0
            proto_stats[CT_STATS_ICMPV6]++;
1891
0
            break;
1892
0
        case IPPROTO_TCP:
1893
0
            proto_stats[CT_STATS_TCP]++;
1894
0
            uint8_t tcp_state;
1895
            /* We keep two separate tcp states, but we print just one. The
1896
             * Linux kernel connection tracker internally keeps only one state,
1897
             * so 'state_orig' and 'state_reply', will be the same. */
1898
0
            tcp_state = MAX(cte.protoinfo.tcp.state_orig,
1899
0
                            cte.protoinfo.tcp.state_reply);
1900
0
            tcp_state = ct_dpif_coalesce_tcp_state(tcp_state);
1901
0
            tcp_conn_per_states[tcp_state]++;
1902
0
            break;
1903
0
        case IPPROTO_UDP:
1904
0
            proto_stats[CT_STATS_UDP]++;
1905
0
            break;
1906
0
        case IPPROTO_SCTP:
1907
0
            proto_stats[CT_STATS_SCTP]++;
1908
0
            break;
1909
0
        case IPPROTO_UDPLITE:
1910
0
            proto_stats[CT_STATS_UDPLITE]++;
1911
0
            break;
1912
0
        case IPPROTO_DCCP:
1913
0
            proto_stats[CT_STATS_DCCP]++;
1914
0
            break;
1915
0
        case IPPROTO_IGMP:
1916
0
            proto_stats[CT_STATS_IGMP]++;
1917
0
            break;
1918
0
        default:
1919
0
            proto_stats[CT_STATS_OTHER]++;
1920
0
            break;
1921
0
        }
1922
0
    }
1923
0
    if (error == EOF) {
1924
        /* All CT entries were dumped with no issue.  */
1925
0
        error = 0;
1926
0
    } else if (error) {
1927
0
        dpctl_error(dpctl_p, error, "dumping conntrack entry");
1928
        /* Fall through to show any other info we collected. */
1929
0
    }
1930
1931
0
    dpctl_print(dpctl_p, "Connections Stats:\n    Total: %d\n", tot_conn);
1932
0
    if (proto_stats[CT_STATS_TCP]) {
1933
0
        dpctl_print(dpctl_p, "  TCP: %d\n", proto_stats[CT_STATS_TCP]);
1934
0
        if (verbose) {
1935
0
            dpctl_print(dpctl_p, "    Conn per TCP states:\n");
1936
0
            for (int i = 0; i < CT_DPIF_TCPS_MAX_NUM; i++) {
1937
0
                if (tcp_conn_per_states[i]) {
1938
0
                    struct ds s = DS_EMPTY_INITIALIZER;
1939
0
                    ct_dpif_format_tcp_stat(&s, i, tcp_conn_per_states[i]);
1940
0
                    dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1941
0
                    ds_destroy(&s);
1942
0
                }
1943
0
            }
1944
0
        }
1945
0
    }
1946
0
    if (proto_stats[CT_STATS_UDP]) {
1947
0
        dpctl_print(dpctl_p, "  UDP: %d\n", proto_stats[CT_STATS_UDP]);
1948
0
    }
1949
0
    if (proto_stats[CT_STATS_UDPLITE]) {
1950
0
        dpctl_print(dpctl_p, "  UDPLITE: %d\n", proto_stats[CT_STATS_UDPLITE]);
1951
0
    }
1952
0
    if (proto_stats[CT_STATS_SCTP]) {
1953
0
        dpctl_print(dpctl_p, "  SCTP: %d\n", proto_stats[CT_STATS_SCTP]);
1954
0
    }
1955
0
    if (proto_stats[CT_STATS_ICMP]) {
1956
0
        dpctl_print(dpctl_p, "  ICMP: %d\n", proto_stats[CT_STATS_ICMP]);
1957
0
    }
1958
0
    if (proto_stats[CT_STATS_DCCP]) {
1959
0
        dpctl_print(dpctl_p, "  DCCP: %d\n", proto_stats[CT_STATS_DCCP]);
1960
0
    }
1961
0
    if (proto_stats[CT_STATS_IGMP]) {
1962
0
        dpctl_print(dpctl_p, "  IGMP: %d\n", proto_stats[CT_STATS_IGMP]);
1963
0
    }
1964
0
    if (proto_stats[CT_STATS_OTHER]) {
1965
0
        dpctl_print(dpctl_p, "  Other: %d\n", proto_stats[CT_STATS_OTHER]);
1966
0
    }
1967
1968
0
    ct_dpif_dump_done(dump);
1969
0
    dpif_close(dpif);
1970
0
    return error;
1971
0
}
1972
1973
0
#define CT_BKTS_GT "gt="
1974
static int
1975
dpctl_ct_bkts(int argc, const char *argv[],
1976
                     struct dpctl_params *dpctl_p)
1977
0
{
1978
0
    struct dpif *dpif;
1979
0
    struct ct_dpif_dump_state *dump;
1980
0
    struct ct_dpif_entry cte;
1981
0
    uint16_t gt = 0; /* Threshold: display value when greater than gt. */
1982
0
    uint16_t *pzone = NULL;
1983
0
    int tot_bkts = 0;
1984
0
    int error;
1985
1986
0
    if (argc > 1 && !strncmp(argv[argc - 1], CT_BKTS_GT, strlen(CT_BKTS_GT))) {
1987
0
        if (ovs_scan(argv[argc - 1], CT_BKTS_GT"%"SCNu16, &gt)) {
1988
0
            argc--;
1989
0
        }
1990
0
    }
1991
1992
0
    error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1993
0
    if (error) {
1994
0
        return error;
1995
0
    }
1996
1997
0
    error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1998
0
    if (error) {
1999
0
        dpctl_error(dpctl_p, error, "starting conntrack dump");
2000
0
        dpif_close(dpif);
2001
0
        return error;
2002
0
    }
2003
0
    if (tot_bkts == -1) {
2004
         /* Command not available when called by kernel OvS. */
2005
0
         dpctl_print(dpctl_p,
2006
0
             "Command is available for UserSpace ConnTracker only.\n");
2007
0
         ct_dpif_dump_done(dump);
2008
0
         dpif_close(dpif);
2009
0
         return 0;
2010
0
    }
2011
2012
0
    dpctl_print(dpctl_p, "Total Buckets: %d\n", tot_bkts);
2013
2014
0
    int tot_conn = 0;
2015
0
    uint32_t *conn_per_bkts = xzalloc(tot_bkts * sizeof(uint32_t));
2016
2017
0
    while (!(error = ct_dpif_dump_next(dump, &cte))) {
2018
0
        ct_dpif_entry_uninit(&cte);
2019
0
        tot_conn++;
2020
0
        if (tot_bkts > 0) {
2021
0
            if (cte.bkt < tot_bkts) {
2022
0
                conn_per_bkts[cte.bkt]++;
2023
0
            } else {
2024
0
                dpctl_print(dpctl_p, "Bucket nr out of range: %d >= %d\n",
2025
0
                        cte.bkt, tot_bkts);
2026
0
            }
2027
0
        }
2028
0
    }
2029
0
    if (error == EOF) {
2030
        /* All CT entries were dumped with no issue.  */
2031
0
        error = 0;
2032
0
    } else if (error) {
2033
0
        dpctl_error(dpctl_p, error, "dumping conntrack entry");
2034
        /* Fall through and display all the collected info.  */
2035
0
    }
2036
2037
0
    dpctl_print(dpctl_p, "Current Connections: %d\n", tot_conn);
2038
0
    dpctl_print(dpctl_p, "\n");
2039
0
    if (tot_bkts && tot_conn) {
2040
0
        dpctl_print(dpctl_p, "+-----------+"
2041
0
                "-----------------------------------------+\n");
2042
0
        dpctl_print(dpctl_p, "|  Buckets  |"
2043
0
                "         Connections per Buckets         |\n");
2044
0
        dpctl_print(dpctl_p, "+-----------+"
2045
0
                "-----------------------------------------+");
2046
0
#define NUM_BKTS_DIPLAYED_PER_ROW 8
2047
0
        for (int i = 0; i < tot_bkts; i++) {
2048
0
            if (i % NUM_BKTS_DIPLAYED_PER_ROW == 0) {
2049
0
                 dpctl_print(dpctl_p, "\n %3d..%3d   | ",
2050
0
                         i, i + NUM_BKTS_DIPLAYED_PER_ROW - 1);
2051
0
            }
2052
0
            if (conn_per_bkts[i] > gt) {
2053
0
                dpctl_print(dpctl_p, "%5d", conn_per_bkts[i]);
2054
0
            } else {
2055
0
                dpctl_print(dpctl_p, "%5s", ".");
2056
0
            }
2057
0
        }
2058
0
        dpctl_print(dpctl_p, "\n\n");
2059
0
    }
2060
2061
0
    ct_dpif_dump_done(dump);
2062
0
    dpif_close(dpif);
2063
0
    free(conn_per_bkts);
2064
0
    return error;
2065
0
}
2066

2067
static int
2068
dpctl_ct_set_maxconns(int argc, const char *argv[],
2069
                      struct dpctl_params *dpctl_p)
2070
0
{
2071
0
    struct dpif *dpif;
2072
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
2073
0
    if (!error) {
2074
0
        uint32_t maxconns;
2075
0
        if (ovs_scan(argv[argc - 1], "%"SCNu32, &maxconns)) {
2076
0
            error = ct_dpif_set_maxconns(dpif, maxconns);
2077
2078
0
            if (!error) {
2079
0
                dpctl_print(dpctl_p, "setting maxconns successful");
2080
0
            } else {
2081
0
                dpctl_error(dpctl_p, error, "ct set maxconns failed");
2082
0
            }
2083
0
        } else {
2084
0
            error = EINVAL;
2085
0
            dpctl_error(dpctl_p, error, "maxconns missing or malformed");
2086
0
        }
2087
0
        dpif_close(dpif);
2088
0
    }
2089
2090
0
    return error;
2091
0
}
2092
2093
static int
2094
dpctl_ct_get_maxconns(int argc, const char *argv[],
2095
                    struct dpctl_params *dpctl_p)
2096
0
{
2097
0
    struct dpif *dpif;
2098
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
2099
0
    if (!error) {
2100
0
        uint32_t maxconns;
2101
0
        error = ct_dpif_get_maxconns(dpif, &maxconns);
2102
2103
0
        if (!error) {
2104
0
            dpctl_print(dpctl_p, "%u\n", maxconns);
2105
0
        } else {
2106
0
            dpctl_error(dpctl_p, error, "maxconns could not be retrieved");
2107
0
        }
2108
0
        dpif_close(dpif);
2109
0
    }
2110
2111
0
    return error;
2112
0
}
2113
2114
static int
2115
dpctl_ct_get_nconns(int argc, const char *argv[],
2116
                    struct dpctl_params *dpctl_p)
2117
0
{
2118
0
    struct dpif *dpif;
2119
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
2120
0
    if (!error) {
2121
0
        uint32_t nconns;
2122
0
        error = ct_dpif_get_nconns(dpif, &nconns);
2123
2124
0
        if (!error) {
2125
0
            dpctl_print(dpctl_p, "%u\n", nconns);
2126
0
        } else {
2127
0
            dpctl_error(dpctl_p, error, "nconns could not be retrieved");
2128
0
        }
2129
0
        dpif_close(dpif);
2130
0
    }
2131
2132
0
    return error;
2133
0
}
2134
2135
static int
2136
dpctl_ct_set_tcp_seq_chk__(int argc, const char *argv[],
2137
                           struct dpctl_params *dpctl_p, bool enabled)
2138
0
{
2139
0
    struct dpif *dpif;
2140
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
2141
0
    if (!error) {
2142
0
        error = ct_dpif_set_tcp_seq_chk(dpif, enabled);
2143
0
        if (!error) {
2144
0
            dpctl_print(dpctl_p,
2145
0
                        "%s TCP sequence checking successful",
2146
0
                        enabled ? "enabling" : "disabling");
2147
0
        } else {
2148
0
            dpctl_error(dpctl_p, error,
2149
0
                        "%s TCP sequence checking failed",
2150
0
                        enabled ? "enabling" : "disabling");
2151
0
        }
2152
0
        dpif_close(dpif);
2153
0
    }
2154
0
    return error;
2155
0
}
2156
2157
static int
2158
dpctl_ct_enable_tcp_seq_chk(int argc, const char *argv[],
2159
                            struct dpctl_params *dpctl_p)
2160
0
{
2161
0
    return dpctl_ct_set_tcp_seq_chk__(argc, argv, dpctl_p, true);
2162
0
}
2163
2164
static int
2165
dpctl_ct_disable_tcp_seq_chk(int argc, const char *argv[],
2166
                             struct dpctl_params *dpctl_p)
2167
0
{
2168
0
    return dpctl_ct_set_tcp_seq_chk__(argc, argv, dpctl_p, false);
2169
0
}
2170
2171
static int
2172
dpctl_ct_get_tcp_seq_chk(int argc, const char *argv[],
2173
                         struct dpctl_params *dpctl_p)
2174
0
{
2175
0
    struct dpif *dpif;
2176
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
2177
0
    if (!error) {
2178
0
        bool enabled;
2179
0
        error = ct_dpif_get_tcp_seq_chk(dpif, &enabled);
2180
0
        if (!error) {
2181
0
            dpctl_print(dpctl_p, "TCP sequence checking: %s\n",
2182
0
                        enabled ? "enabled" : "disabled");
2183
0
        } else {
2184
0
            dpctl_error(dpctl_p, error, "TCP sequence checking query failed");
2185
0
        }
2186
0
        dpif_close(dpif);
2187
0
    }
2188
0
    return error;
2189
0
}
2190
2191
static int
2192
dpctl_ct_set_limits(int argc, const char *argv[],
2193
                    struct dpctl_params *dpctl_p)
2194
0
{
2195
0
    struct ovs_list zone_limits = OVS_LIST_INITIALIZER(&zone_limits);
2196
0
    int i =  dp_arg_exists(argc, argv) ? 2 : 1;
2197
0
    struct ds ds = DS_EMPTY_INITIALIZER;
2198
0
    unsigned long long default_limit;
2199
0
    struct dpif *dpif = NULL;
2200
0
    int error;
2201
2202
0
    if (i >= argc) {
2203
0
        ds_put_cstr(&ds, "too few arguments");
2204
0
        error = EINVAL;
2205
0
        goto error;
2206
0
    }
2207
2208
0
    error = opt_dpif_open(argc, argv, dpctl_p, INT_MAX, &dpif);
2209
0
    if (error) {
2210
0
        return error;
2211
0
    }
2212
2213
    /* Parse default limit */
2214
0
    if (!strncmp(argv[i], "default=", 8)) {
2215
0
        if (str_to_ullong(argv[i] + 8, 10, &default_limit) &&
2216
0
            default_limit <= UINT32_MAX) {
2217
0
            ct_dpif_push_zone_limit(&zone_limits, OVS_ZONE_LIMIT_DEFAULT_ZONE,
2218
0
                                    default_limit, 0);
2219
0
            i++;
2220
0
        } else {
2221
0
            ds_put_cstr(&ds, "invalid default limit");
2222
0
            error = EINVAL;
2223
0
            goto error;
2224
0
        }
2225
0
    }
2226
2227
    /* Parse ct zone limit tuples */
2228
0
    while (i < argc) {
2229
0
        uint16_t zone;
2230
0
        uint32_t limit;
2231
0
        if (!ct_dpif_parse_zone_limit_tuple(argv[i++], &zone, &limit, &ds)) {
2232
0
            error = EINVAL;
2233
0
            goto error;
2234
0
        }
2235
0
        ct_dpif_push_zone_limit(&zone_limits, zone, limit, 0);
2236
0
    }
2237
2238
0
    if (ct_dpif_is_zone_limit_protected(dpif)) {
2239
0
        ds_put_cstr(&ds, "the zone limits are set via database, "
2240
0
                         "use 'ovs-vsctl set-zone-limit <...>' instead.");
2241
0
        error = EPERM;
2242
0
        goto error;
2243
0
    }
2244
2245
0
    error = ct_dpif_set_limits(dpif, &zone_limits);
2246
0
    if (!error) {
2247
0
        ct_dpif_free_zone_limits(&zone_limits);
2248
0
        dpif_close(dpif);
2249
0
        return 0;
2250
0
    } else {
2251
0
        ds_put_cstr(&ds, "failed to set conntrack limit");
2252
0
    }
2253
2254
0
error:
2255
0
    dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
2256
0
    ds_destroy(&ds);
2257
0
    ct_dpif_free_zone_limits(&zone_limits);
2258
0
    dpif_close(dpif);
2259
0
    return error;
2260
0
}
2261
2262
static int
2263
parse_ct_limit_zones(const char *argv, struct ovs_list *zone_limits,
2264
                     struct ds *ds)
2265
0
{
2266
0
    char *save_ptr = NULL, *argcopy, *next_zone;
2267
0
    uint16_t zone;
2268
2269
0
    if (strncmp(argv, "zone=", 5)) {
2270
0
        ds_put_format(ds, "invalid argument %s", argv);
2271
0
        return EINVAL;
2272
0
    }
2273
2274
0
    argcopy = xstrdup(argv + 5);
2275
0
    next_zone = strtok_r(argcopy, ",", &save_ptr);
2276
2277
0
    while (next_zone != NULL) {
2278
0
        if (ovs_scan(next_zone, "%"SCNu16, &zone)) {
2279
0
            ct_dpif_push_zone_limit(zone_limits, zone, 0, 0);
2280
0
        } else {
2281
0
            ds_put_cstr(ds, "invalid zone");
2282
0
            free(argcopy);
2283
0
            return EINVAL;
2284
0
        }
2285
0
        next_zone = strtok_r(NULL, ",", &save_ptr);
2286
0
    }
2287
2288
0
    free(argcopy);
2289
0
    return 0;
2290
0
}
2291
2292
static int
2293
dpctl_ct_del_limits(int argc, const char *argv[],
2294
                    struct dpctl_params *dpctl_p)
2295
0
{
2296
0
    struct ovs_list zone_limits = OVS_LIST_INITIALIZER(&zone_limits);
2297
0
    int i =  dp_arg_exists(argc, argv) ? 2 : 1;
2298
0
    struct ds ds = DS_EMPTY_INITIALIZER;
2299
0
    struct dpif *dpif = NULL;
2300
0
    int error;
2301
2302
0
    if (i >= argc) {
2303
0
        ds_put_cstr(&ds, "too few arguments");
2304
0
        error = EINVAL;
2305
0
        goto error;
2306
0
    }
2307
2308
0
    error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
2309
0
    if (error) {
2310
0
        return error;
2311
0
    }
2312
2313
    /* Parse default limit. */
2314
0
    if (!strcmp(argv[i], "default")) {
2315
0
        ct_dpif_push_zone_limit(&zone_limits, OVS_ZONE_LIMIT_DEFAULT_ZONE,
2316
0
                                0, 0);
2317
0
        i++;
2318
0
    }
2319
2320
0
    if (argc > i) {
2321
0
        error = parse_ct_limit_zones(argv[i], &zone_limits, &ds);
2322
0
        if (error) {
2323
0
            goto error;
2324
0
        }
2325
0
    }
2326
2327
0
    if (ct_dpif_is_zone_limit_protected(dpif)) {
2328
0
        ds_put_cstr(&ds, "the zone limits are set via database, "
2329
0
                         "use 'ovs-vsctl del-zone-limit <...>' instead.");
2330
0
        error = EPERM;
2331
0
        goto error;
2332
0
    }
2333
2334
0
    error = ct_dpif_del_limits(dpif, &zone_limits);
2335
0
    if (!error) {
2336
0
        goto out;
2337
0
    } else {
2338
0
        ds_put_cstr(&ds, "failed to delete conntrack limit");
2339
0
    }
2340
2341
0
error:
2342
0
    dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
2343
0
    ds_destroy(&ds);
2344
0
out:
2345
0
    ct_dpif_free_zone_limits(&zone_limits);
2346
0
    dpif_close(dpif);
2347
0
    return error;
2348
0
}
2349
2350
static int
2351
dpctl_ct_get_limits(int argc, const char *argv[],
2352
                    struct dpctl_params *dpctl_p)
2353
0
{
2354
0
    struct dpif *dpif;
2355
0
    struct ds ds = DS_EMPTY_INITIALIZER;
2356
0
    int i =  dp_arg_exists(argc, argv) ? 2 : 1;
2357
0
    struct ovs_list list_query = OVS_LIST_INITIALIZER(&list_query);
2358
0
    struct ovs_list list_reply = OVS_LIST_INITIALIZER(&list_reply);
2359
2360
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
2361
0
    if (error) {
2362
0
        return error;
2363
0
    }
2364
2365
0
    if (argc > i) {
2366
0
        ct_dpif_push_zone_limit(&list_query, OVS_ZONE_LIMIT_DEFAULT_ZONE,
2367
0
                                0, 0);
2368
0
        error = parse_ct_limit_zones(argv[i], &list_query, &ds);
2369
0
        if (error) {
2370
0
            goto error;
2371
0
        }
2372
0
    }
2373
2374
0
    error = ct_dpif_get_limits(dpif, &list_query, &list_reply);
2375
0
    if (!error) {
2376
0
        ct_dpif_format_zone_limits(&list_reply, &ds);
2377
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
2378
0
        goto out;
2379
0
    } else {
2380
0
        ds_put_format(&ds, "failed to get conntrack limit %s",
2381
0
                      ovs_strerror(error));
2382
0
    }
2383
2384
0
error:
2385
0
    dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
2386
0
out:
2387
0
    ds_destroy(&ds);
2388
0
    ct_dpif_free_zone_limits(&list_query);
2389
0
    ct_dpif_free_zone_limits(&list_reply);
2390
0
    dpif_close(dpif);
2391
0
    return error;
2392
0
}
2393
2394
static int
2395
dpctl_ct_get_sweep(int argc, const char *argv[],
2396
                   struct dpctl_params *dpctl_p)
2397
0
{
2398
0
    uint32_t sweep_ms = 0;
2399
0
    struct dpif *dpif;
2400
2401
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
2402
0
    if (error) {
2403
0
        return error;
2404
0
    }
2405
2406
0
    error = ct_dpif_sweep(dpif, &sweep_ms);
2407
0
    if (error) {
2408
0
        dpctl_error(dpctl_p, error, "failed to get the sweep interval");
2409
0
    } else {
2410
0
        dpctl_print(dpctl_p, "%"PRIu32, sweep_ms);
2411
0
    }
2412
2413
0
    dpif_close(dpif);
2414
0
    return error;
2415
0
}
2416
2417
static int
2418
dpctl_ct_set_sweep(int argc, const char *argv[],
2419
                   struct dpctl_params *dpctl_p)
2420
0
{
2421
0
    struct ds ds = DS_EMPTY_INITIALIZER;
2422
0
    uint32_t sweep_ms = 0;
2423
0
    struct dpif *dpif;
2424
2425
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
2426
0
    if (error) {
2427
0
        return error;
2428
0
    }
2429
2430
0
    if (!ovs_scan(argv[argc - 1], "%"SCNu32, &sweep_ms) ||
2431
0
        sweep_ms == 0) {
2432
0
        ds_put_format(&ds, "invalid sweep value");
2433
0
        error = EINVAL;
2434
0
        goto error;
2435
0
    }
2436
2437
0
    error = ct_dpif_sweep(dpif, &sweep_ms);
2438
0
    if (!error) {
2439
0
        dpctl_print(dpctl_p, "setting sweep interval successful\n");
2440
0
        goto out;
2441
0
    }
2442
2443
0
    ds_put_format(&ds, "failed to set the sweep interval");
2444
2445
0
error:
2446
0
    dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
2447
0
    ds_destroy(&ds);
2448
0
out:
2449
0
    dpif_close(dpif);
2450
0
    return error;
2451
0
}
2452
2453
static int
2454
ipf_set_enabled__(int argc, const char *argv[], struct dpctl_params *dpctl_p,
2455
                  bool enabled)
2456
0
{
2457
0
    struct dpif *dpif;
2458
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
2459
0
    if (!error) {
2460
0
        char v4_or_v6[3] = {0};
2461
0
        if (ovs_scan(argv[argc - 1], "%2s", v4_or_v6) &&
2462
0
            (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) {
2463
0
            error = ct_dpif_ipf_set_enabled(
2464
0
                        dpif, !strncmp(v4_or_v6, "v6", 2), enabled);
2465
0
            if (!error) {
2466
0
                dpctl_print(dpctl_p,
2467
0
                            "%s fragmentation reassembly successful",
2468
0
                            enabled ? "enabling" : "disabling");
2469
0
            } else {
2470
0
                dpctl_error(dpctl_p, error,
2471
0
                            "%s fragmentation reassembly failed",
2472
0
                            enabled ? "enabling" : "disabling");
2473
0
            }
2474
0
        } else {
2475
0
            error = EINVAL;
2476
0
            dpctl_error(dpctl_p, error,
2477
0
                        "parameter missing: 'v4' for IPv4 or 'v6' for IPv6");
2478
0
        }
2479
0
        dpif_close(dpif);
2480
0
    }
2481
0
    return error;
2482
0
}
2483
2484
static int
2485
dpctl_ipf_set_enabled(int argc, const char *argv[],
2486
                      struct dpctl_params *dpctl_p)
2487
0
{
2488
0
    return ipf_set_enabled__(argc, argv, dpctl_p, true);
2489
0
}
2490
2491
static int
2492
dpctl_ipf_set_disabled(int argc, const char *argv[],
2493
                       struct dpctl_params *dpctl_p)
2494
0
{
2495
0
    return ipf_set_enabled__(argc, argv, dpctl_p, false);
2496
0
}
2497
2498
static int
2499
dpctl_ipf_set_min_frag(int argc, const char *argv[],
2500
                       struct dpctl_params *dpctl_p)
2501
0
{
2502
0
    struct dpif *dpif;
2503
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
2504
0
    if (!error) {
2505
0
        char v4_or_v6[3] = {0};
2506
0
        if (ovs_scan(argv[argc - 2], "%2s", v4_or_v6) &&
2507
0
            (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) {
2508
0
            uint32_t min_fragment;
2509
0
            if (ovs_scan(argv[argc - 1], "%"SCNu32, &min_fragment)) {
2510
0
                error = ct_dpif_ipf_set_min_frag(
2511
0
                            dpif, !strncmp(v4_or_v6, "v6", 2), min_fragment);
2512
0
                if (!error) {
2513
0
                    dpctl_print(dpctl_p,
2514
0
                                "setting minimum fragment size successful");
2515
0
                } else {
2516
0
                    dpctl_error(dpctl_p, error,
2517
0
                                "requested minimum fragment size too small;"
2518
0
                                " see documentation");
2519
0
                }
2520
0
            } else {
2521
0
                error = EINVAL;
2522
0
                dpctl_error(dpctl_p, error,
2523
0
                            "parameter missing for minimum fragment size");
2524
0
            }
2525
0
        } else {
2526
0
            error = EINVAL;
2527
0
            dpctl_error(dpctl_p, error,
2528
0
                        "parameter missing: v4 for IPv4 or v6 for IPv6");
2529
0
        }
2530
0
        dpif_close(dpif);
2531
0
    }
2532
2533
0
    return error;
2534
0
}
2535
2536
static int
2537
dpctl_ipf_set_max_nfrags(int argc, const char *argv[],
2538
                         struct dpctl_params *dpctl_p)
2539
0
{
2540
0
    struct dpif *dpif;
2541
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
2542
0
    if (!error) {
2543
0
        uint32_t nfrags_max;
2544
0
        if (ovs_scan(argv[argc - 1], "%"SCNu32, &nfrags_max)) {
2545
0
            error = ct_dpif_ipf_set_max_nfrags(dpif, nfrags_max);
2546
0
            if (!error) {
2547
0
                dpctl_print(dpctl_p,
2548
0
                            "setting maximum fragments successful");
2549
0
            } else {
2550
0
                dpctl_error(dpctl_p, error,
2551
0
                            "setting maximum fragments failed");
2552
0
            }
2553
0
        } else {
2554
0
            error = EINVAL;
2555
0
            dpctl_error(dpctl_p, error,
2556
0
                        "parameter missing for maximum fragments");
2557
0
        }
2558
0
        dpif_close(dpif);
2559
0
    }
2560
2561
0
    return error;
2562
0
}
2563
2564
static void
2565
dpctl_dump_ipf(struct dpif *dpif, struct dpctl_params *dpctl_p)
2566
0
{
2567
0
    struct ipf_dump_ctx *dump_ctx;
2568
0
    char *dump;
2569
2570
0
    int error = ct_dpif_ipf_dump_start(dpif, &dump_ctx);
2571
0
    if (error) {
2572
0
        dpctl_error(dpctl_p, error, "starting ipf list dump");
2573
        /* Nothing to clean up, just return. */
2574
0
        return;
2575
0
    }
2576
2577
0
    dpctl_print(dpctl_p, "\n        Fragment Lists:\n\n");
2578
0
    while (!(error = ct_dpif_ipf_dump_next(dpif, dump_ctx, &dump))) {
2579
0
        dpctl_print(dpctl_p, "%s\n", dump);
2580
0
        free(dump);
2581
0
    }
2582
2583
0
    if (error && error != EOF) {
2584
0
        dpctl_error(dpctl_p, error, "dumping ipf lists failed");
2585
0
    }
2586
2587
0
    ct_dpif_ipf_dump_done(dpif, dump_ctx);
2588
0
}
2589
2590
static int
2591
dpctl_ct_ipf_get_status(int argc, const char *argv[],
2592
                        struct dpctl_params *dpctl_p)
2593
0
{
2594
0
    struct dpif *dpif;
2595
0
    int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
2596
2597
0
    if (!error) {
2598
0
        struct dpif_ipf_status dpif_ipf_status;
2599
0
        error = ct_dpif_ipf_get_status(dpif, &dpif_ipf_status);
2600
2601
0
        if (!error) {
2602
0
            dpctl_print(dpctl_p, "        Fragmentation Module Status\n");
2603
0
            dpctl_print(dpctl_p, "        ---------------------------\n");
2604
0
            dpctl_print(dpctl_p, "        v4 enabled: %u\n",
2605
0
                        dpif_ipf_status.v4.enabled);
2606
0
            dpctl_print(dpctl_p, "        v6 enabled: %u\n",
2607
0
                        dpif_ipf_status.v6.enabled);
2608
0
            dpctl_print(dpctl_p, "        max num frags (v4/v6): %u\n",
2609
0
                        dpif_ipf_status.nfrag_max);
2610
0
            dpctl_print(dpctl_p, "        num frag: %u\n",
2611
0
                        dpif_ipf_status.nfrag);
2612
0
            dpctl_print(dpctl_p, "        min v4 frag size: %u\n",
2613
0
                        dpif_ipf_status.v4.min_frag_size);
2614
0
            dpctl_print(dpctl_p, "        v4 frags accepted: %"PRIu64"\n",
2615
0
                        dpif_ipf_status.v4.nfrag_accepted);
2616
0
            dpctl_print(dpctl_p, "        v4 frags completed: %"PRIu64"\n",
2617
0
                        dpif_ipf_status.v4.nfrag_completed_sent);
2618
0
            dpctl_print(dpctl_p, "        v4 frags expired: %"PRIu64"\n",
2619
0
                        dpif_ipf_status.v4.nfrag_expired_sent);
2620
0
            dpctl_print(dpctl_p, "        v4 frags too small: %"PRIu64"\n",
2621
0
                        dpif_ipf_status.v4.nfrag_too_small);
2622
0
            dpctl_print(dpctl_p, "        v4 frags overlapped: %"PRIu64"\n",
2623
0
                        dpif_ipf_status.v4.nfrag_overlap);
2624
0
            dpctl_print(dpctl_p, "        v4 frags purged: %"PRIu64"\n",
2625
0
                        dpif_ipf_status.v4.nfrag_purged);
2626
2627
0
            dpctl_print(dpctl_p, "        min v6 frag size: %u\n",
2628
0
                        dpif_ipf_status.v6.min_frag_size);
2629
0
            dpctl_print(dpctl_p, "        v6 frags accepted: %"PRIu64"\n",
2630
0
                        dpif_ipf_status.v6.nfrag_accepted);
2631
0
            dpctl_print(dpctl_p, "        v6 frags completed: %"PRIu64"\n",
2632
0
                        dpif_ipf_status.v6.nfrag_completed_sent);
2633
0
            dpctl_print(dpctl_p, "        v6 frags expired: %"PRIu64"\n",
2634
0
                        dpif_ipf_status.v6.nfrag_expired_sent);
2635
0
            dpctl_print(dpctl_p, "        v6 frags too small: %"PRIu64"\n",
2636
0
                        dpif_ipf_status.v6.nfrag_too_small);
2637
0
            dpctl_print(dpctl_p, "        v6 frags overlapped: %"PRIu64"\n",
2638
0
                        dpif_ipf_status.v6.nfrag_overlap);
2639
0
            dpctl_print(dpctl_p, "        v6 frags purged: %"PRIu64"\n",
2640
0
                        dpif_ipf_status.v6.nfrag_purged);
2641
0
        } else {
2642
0
            dpctl_error(dpctl_p, error,
2643
0
                        "ipf status could not be retrieved");
2644
0
            return error;
2645
0
        }
2646
2647
0
        if (dpctl_p->verbosity) {
2648
0
            dpctl_dump_ipf(dpif, dpctl_p);
2649
0
        }
2650
2651
0
        dpif_close(dpif);
2652
0
    }
2653
2654
0
    return error;
2655
0
}
2656
2657
static int
2658
dpctl_cache_get_size(int argc, const char *argv[],
2659
                     struct dpctl_params *dpctl_p)
2660
0
{
2661
0
    int error;
2662
2663
0
    if (argc > 1) {
2664
0
        struct dpif *dpif;
2665
2666
0
        error = parsed_dpif_open(argv[1], false, &dpif);
2667
0
        if (!error) {
2668
0
            show_dpif_cache(dpif, dpctl_p);
2669
0
            dpif_close(dpif);
2670
0
        } else {
2671
0
            dpctl_error(dpctl_p, error, "Opening datapath %s failed", argv[1]);
2672
0
        }
2673
0
    } else {
2674
0
        error = dps_for_each(dpctl_p, show_dpif_cache);
2675
0
    }
2676
2677
0
    return error;
2678
0
}
2679
2680
static int
2681
dpctl_cache_set_size(int argc, const char *argv[],
2682
                     struct dpctl_params *dpctl_p)
2683
0
{
2684
0
    uint32_t nr_caches, size;
2685
0
    int i, error = EINVAL;
2686
0
    struct dpif *dpif;
2687
2688
0
    if (argc != 4) {
2689
0
        dpctl_error(dpctl_p, error, "Invalid number of arguments");
2690
0
        return error;
2691
0
    }
2692
2693
0
    if (!ovs_scan(argv[3], "%"SCNu32, &size)) {
2694
0
        dpctl_error(dpctl_p, error, "size is malformed");
2695
0
        return error;
2696
0
    }
2697
2698
0
    error = parsed_dpif_open(argv[1], false, &dpif);
2699
0
    if (error) {
2700
0
            dpctl_error(dpctl_p, error, "Opening datapath %s failed",
2701
0
                        argv[1]);
2702
0
            return error;
2703
0
    }
2704
2705
0
    error = dpif_cache_get_supported_levels(dpif, &nr_caches);
2706
0
    if (error || nr_caches == 0) {
2707
0
        dpctl_error(dpctl_p, error, "Setting caches not supported");
2708
0
        goto exit;
2709
0
    }
2710
2711
0
    for (i = 0; i < nr_caches; i++) {
2712
0
        const char *name;
2713
2714
0
        if (dpif_cache_get_name(dpif, i, &name)) {
2715
0
            continue;
2716
0
        }
2717
0
        if (!strcmp(argv[2], name)) {
2718
0
            break;
2719
0
        }
2720
0
    }
2721
2722
0
    if (i == nr_caches) {
2723
0
        error = EINVAL;
2724
0
        dpctl_error(dpctl_p, error, "Cache name \"%s\" not found on dpif",
2725
0
                    argv[2]);
2726
0
        goto exit;
2727
0
    }
2728
2729
0
    error = dpif_cache_set_size(dpif, i, size);
2730
0
    if (!error) {
2731
0
        dpif_cache_get_size(dpif, i, &size);
2732
0
        dpctl_print(dpctl_p, "Setting cache size successful, new size %u\n",
2733
0
                    size);
2734
0
    } else {
2735
0
        dpctl_error(dpctl_p, error, "Setting cache size failed");
2736
0
    }
2737
2738
0
exit:
2739
0
    dpif_close(dpif);
2740
0
    return error;
2741
0
}
2742
2743
/* Undocumented commands for unit testing. */
2744
2745
static int
2746
dpctl_parse_actions(int argc, const char *argv[], struct dpctl_params* dpctl_p)
2747
0
{
2748
0
    int i, error = 0;
2749
2750
0
    for (i = 1; i < argc; i++) {
2751
0
        struct ofpbuf actions;
2752
0
        struct ds s;
2753
2754
0
        ofpbuf_init(&actions, 0);
2755
0
        error = odp_actions_from_string(argv[i], NULL, &actions);
2756
2757
0
        if (error) {
2758
0
            ofpbuf_uninit(&actions);
2759
0
            dpctl_error(dpctl_p, error, "odp_actions_from_string");
2760
0
            return error;
2761
0
        }
2762
2763
0
        ds_init(&s);
2764
0
        format_odp_actions(&s, actions.data, actions.size, NULL);
2765
0
        dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
2766
0
        ds_destroy(&s);
2767
2768
0
        ofpbuf_uninit(&actions);
2769
0
    }
2770
2771
0
    return error;
2772
0
}
2773
2774
struct actions_for_flow {
2775
    struct hmap_node hmap_node;
2776
    struct flow flow;
2777
    struct ofpbuf actions;
2778
};
2779
2780
static struct actions_for_flow *
2781
get_actions_for_flow(struct hmap *actions_per_flow, const struct flow *flow)
2782
0
{
2783
0
    uint32_t hash = flow_hash(flow, 0);
2784
0
    struct actions_for_flow *af;
2785
2786
0
    HMAP_FOR_EACH_WITH_HASH (af, hmap_node, hash, actions_per_flow) {
2787
0
        if (flow_equal(&af->flow, flow)) {
2788
0
            return af;
2789
0
        }
2790
0
    }
2791
2792
0
    af = xmalloc(sizeof *af);
2793
0
    af->flow = *flow;
2794
0
    ofpbuf_init(&af->actions, 0);
2795
0
    hmap_insert(actions_per_flow, &af->hmap_node, hash);
2796
0
    return af;
2797
0
}
2798
2799
static int
2800
compare_actions_for_flow(const void *a_, const void *b_)
2801
0
{
2802
0
    struct actions_for_flow *const *a = a_;
2803
0
    struct actions_for_flow *const *b = b_;
2804
2805
0
    return flow_compare_3way(&(*a)->flow, &(*b)->flow);
2806
0
}
2807
2808
static int
2809
compare_output_actions(const void *a_, const void *b_)
2810
0
{
2811
0
    const struct nlattr *a = a_;
2812
0
    const struct nlattr *b = b_;
2813
0
    uint32_t a_port = nl_attr_get_u32(a);
2814
0
    uint32_t b_port = nl_attr_get_u32(b);
2815
2816
0
    return a_port < b_port ? -1 : a_port > b_port;
2817
0
}
2818
2819
static void
2820
sort_output_actions__(struct nlattr *first, struct nlattr *end)
2821
0
{
2822
0
    size_t bytes = (uint8_t *) end - (uint8_t *) first;
2823
0
    size_t n = bytes / NL_A_U32_SIZE;
2824
2825
0
    ovs_assert(bytes % NL_A_U32_SIZE == 0);
2826
0
    qsort(first, n, NL_A_U32_SIZE, compare_output_actions);
2827
0
}
2828
2829
static void
2830
sort_output_actions(struct nlattr *actions, size_t length)
2831
0
{
2832
0
    struct nlattr *first_output = NULL;
2833
0
    struct nlattr *a;
2834
0
    int left;
2835
2836
0
    NL_ATTR_FOR_EACH (a, left, actions, length) {
2837
0
        if (nl_attr_type(a) == OVS_ACTION_ATTR_OUTPUT) {
2838
0
            if (!first_output) {
2839
0
                first_output = a;
2840
0
            }
2841
0
        } else {
2842
0
            if (first_output) {
2843
0
                sort_output_actions__(first_output, a);
2844
0
                first_output = NULL;
2845
0
            }
2846
0
        }
2847
0
    }
2848
0
    if (first_output) {
2849
0
        uint8_t *end = (uint8_t *) actions + length;
2850
0
        sort_output_actions__(first_output,
2851
0
                              ALIGNED_CAST(struct nlattr *, end));
2852
0
    }
2853
0
}
2854
2855
/* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
2856
 * have the syntax used by "ovs-dpctl dump-flows".
2857
 *
2858
 * This command prints ACTIONS in a format that shows what happens for each
2859
 * VLAN, independent of the order of the ACTIONS.  For example, there is more
2860
 * than one way to output a packet on VLANs 9 and 11, but this command will
2861
 * print the same output for any form.
2862
 *
2863
 * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
2864
 * so far the implementation only covers VLANs. */
2865
static int
2866
dpctl_normalize_actions(int argc, const char *argv[],
2867
                        struct dpctl_params *dpctl_p)
2868
0
{
2869
0
    struct simap port_names;
2870
0
    struct ofpbuf keybuf;
2871
0
    struct flow flow;
2872
0
    struct ofpbuf odp_actions;
2873
0
    struct hmap actions_per_flow;
2874
0
    struct actions_for_flow **afs;
2875
0
    struct actions_for_flow *af;
2876
0
    struct nlattr *a;
2877
0
    size_t n_afs;
2878
0
    struct ds s;
2879
0
    int left;
2880
0
    int i, error;
2881
0
    int encaps = 0;
2882
2883
0
    ds_init(&s);
2884
2885
0
    simap_init(&port_names);
2886
0
    for (i = 3; i < argc; i++) {
2887
0
        char name[16];
2888
0
        int number;
2889
2890
0
        if (ovs_scan(argv[i], "%15[^=]=%d", name, &number)) {
2891
0
            uintptr_t n = number;
2892
0
            simap_put(&port_names, name, n);
2893
0
        } else {
2894
0
            dpctl_error(dpctl_p, 0, "%s: expected NAME=NUMBER", argv[i]);
2895
0
            error = EINVAL;
2896
0
            goto out;
2897
0
        }
2898
0
    }
2899
2900
    /* Parse flow key. */
2901
0
    ofpbuf_init(&keybuf, 0);
2902
0
    char *error_s;
2903
0
    error = odp_flow_from_string(argv[1], &port_names, &keybuf, NULL,
2904
0
                                 &error_s);
2905
0
    if (error) {
2906
0
        dpctl_error(dpctl_p, error, "odp_flow_key_from_string (%s)", error_s);
2907
0
        free(error_s);
2908
0
        goto out_freekeybuf;
2909
0
    }
2910
2911
0
    ds_clear(&s);
2912
0
    odp_flow_format(keybuf.data, keybuf.size, NULL, 0, NULL,
2913
0
                    &s, dpctl_p->verbosity, false);
2914
0
    dpctl_print(dpctl_p, "input flow: %s\n", ds_cstr(&s));
2915
2916
0
    error = odp_flow_key_to_flow(keybuf.data, keybuf.size, &flow, &error_s);
2917
0
    if (error) {
2918
0
        dpctl_error(dpctl_p, error, "odp_flow_key_to_flow failed (%s)",
2919
0
                    error_s ? error_s : "reason unknown");
2920
0
        free(error_s);
2921
0
        goto out_freekeybuf;
2922
0
    }
2923
2924
    /* Parse actions. */
2925
0
    ofpbuf_init(&odp_actions, 0);
2926
0
    error = odp_actions_from_string(argv[2], &port_names, &odp_actions);
2927
0
    if (error) {
2928
0
        dpctl_error(dpctl_p, error, "odp_actions_from_string");
2929
0
        goto out_freeactions;
2930
0
    }
2931
2932
0
    if (dpctl_p->verbosity) {
2933
0
        ds_clear(&s);
2934
0
        format_odp_actions(&s, odp_actions.data, odp_actions.size, NULL);
2935
0
        dpctl_print(dpctl_p, "input actions: %s\n", ds_cstr(&s));
2936
0
    }
2937
2938
0
    hmap_init(&actions_per_flow);
2939
0
    NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
2940
0
        const struct ovs_action_push_vlan *push;
2941
0
        switch(nl_attr_type(a)) {
2942
0
        case OVS_ACTION_ATTR_POP_VLAN:
2943
0
            flow_pop_vlan(&flow, NULL);
2944
0
            continue;
2945
2946
0
        case OVS_ACTION_ATTR_PUSH_VLAN:
2947
0
            flow_push_vlan_uninit(&flow, NULL);
2948
0
            push = nl_attr_get_unspec(a, sizeof *push);
2949
0
            flow.vlans[0].tpid = push->vlan_tpid;
2950
0
            flow.vlans[0].tci = push->vlan_tci;
2951
0
            continue;
2952
0
        }
2953
2954
0
        af = get_actions_for_flow(&actions_per_flow, &flow);
2955
0
        nl_msg_put_unspec(&af->actions, nl_attr_type(a),
2956
0
                          nl_attr_get(a), nl_attr_get_size(a));
2957
0
    }
2958
2959
0
    n_afs = hmap_count(&actions_per_flow);
2960
0
    afs = xmalloc(n_afs * sizeof *afs);
2961
0
    i = 0;
2962
0
    HMAP_FOR_EACH (af, hmap_node, &actions_per_flow) {
2963
0
        afs[i++] = af;
2964
0
    }
2965
2966
0
    ovs_assert(i == n_afs);
2967
0
    hmap_destroy(&actions_per_flow);
2968
2969
0
    qsort(afs, n_afs, sizeof *afs, compare_actions_for_flow);
2970
2971
0
    for (i = 0; i < n_afs; i++) {
2972
0
        af = afs[i];
2973
0
        sort_output_actions(af->actions.data, af->actions.size);
2974
2975
0
        for (encaps = 0; encaps < FLOW_MAX_VLAN_HEADERS; encaps ++) {
2976
0
            union flow_vlan_hdr *vlan = &af->flow.vlans[encaps];
2977
0
            if (vlan->tci != htons(0)) {
2978
0
                dpctl_print(dpctl_p, "vlan(");
2979
0
                if (vlan->tpid != htons(ETH_TYPE_VLAN)) {
2980
0
                    dpctl_print(dpctl_p, "tpid=0x%04"PRIx16",", vlan->tpid);
2981
0
                }
2982
0
                dpctl_print(dpctl_p, "vid=%"PRIu16",pcp=%d): ",
2983
0
                            vlan_tci_to_vid(vlan->tci),
2984
0
                            vlan_tci_to_pcp(vlan->tci));
2985
0
            } else {
2986
0
                if (encaps == 0) {
2987
0
                    dpctl_print(dpctl_p, "no vlan: ");
2988
0
                }
2989
0
                break;
2990
0
            }
2991
0
        }
2992
2993
0
        if (eth_type_mpls(af->flow.dl_type)) {
2994
0
            dpctl_print(dpctl_p, "mpls(label=%"PRIu32",tc=%d,ttl=%d): ",
2995
0
                        mpls_lse_to_label(af->flow.mpls_lse[0]),
2996
0
                        mpls_lse_to_tc(af->flow.mpls_lse[0]),
2997
0
                        mpls_lse_to_ttl(af->flow.mpls_lse[0]));
2998
0
        } else {
2999
0
            dpctl_print(dpctl_p, "no mpls: ");
3000
0
        }
3001
3002
0
        ds_clear(&s);
3003
0
        format_odp_actions(&s, af->actions.data, af->actions.size, NULL);
3004
0
        dpctl_puts(dpctl_p, false, ds_cstr(&s));
3005
3006
0
        ofpbuf_uninit(&af->actions);
3007
0
        free(af);
3008
0
    }
3009
0
    free(afs);
3010
3011
3012
0
out_freeactions:
3013
0
    ofpbuf_uninit(&odp_actions);
3014
0
out_freekeybuf:
3015
0
    ofpbuf_uninit(&keybuf);
3016
0
out:
3017
0
    simap_destroy(&port_names);
3018
0
    ds_destroy(&s);
3019
3020
0
    return error;
3021
0
}
3022

3023
static const struct dpctl_command all_commands[] = {
3024
    { "add-dp", "dp [iface...]", 1, INT_MAX, dpctl_add_dp, DP_RW },
3025
    { "del-dp", "dp", 1, 1, dpctl_del_dp, DP_RW },
3026
    { "add-if", "dp iface...", 2, INT_MAX, dpctl_add_if, DP_RW },
3027
    { "del-if", "dp iface...", 2, INT_MAX, dpctl_del_if, DP_RW },
3028
    { "set-if", "dp iface...", 2, INT_MAX, dpctl_set_if, DP_RW },
3029
    { "dump-dps", "", 0, 0, dpctl_dump_dps, DP_RO },
3030
    { "show", "[-s] [dp...]", 0, INT_MAX, dpctl_show, DP_RO },
3031
    { "dump-flows", "[-m] [--names] [dp] [filter=..] [type=..] [pmd=..]",
3032
      0, 6, dpctl_dump_flows, DP_RO },
3033
    { "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow, DP_RW },
3034
    { "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow, DP_RW },
3035
    { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO },
3036
    { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW },
3037
    { "add-flows", "[dp] file", 1, 2, dpctl_process_flows, DP_RW },
3038
    { "mod-flows", "[dp] file", 1, 2, dpctl_process_flows, DP_RW },
3039
    { "del-flows", "[dp] [file]", 0, 2, dpctl_del_flows, DP_RW },
3040
    { "offload-stats-show", "[dp]",
3041
      0, 1, dpctl_offload_stats_show, DP_RO },
3042
    { "dump-conntrack", "[-m] [-s] [dp] [zone=N]",
3043
      0, 4, dpctl_dump_conntrack, DP_RO },
3044
    { "dump-conntrack-exp", "[dp] [zone=N]",
3045
      0, 2, dpctl_dump_conntrack_exp, DP_RO },
3046
    { "flush-conntrack", "[dp] [zone=N] [mark=X[/M]] [labels=Y[/N]] "
3047
                         "[ct-orig-tuple [ct-reply-tuple]]",
3048
      0, 6, dpctl_flush_conntrack, DP_RW },
3049
    { "cache-get-size", "[dp]", 0, 1, dpctl_cache_get_size, DP_RO },
3050
    { "cache-set-size", "dp cache <size>", 3, 3, dpctl_cache_set_size, DP_RW },
3051
    { "ct-stats-show", "[dp] [zone=N]",
3052
      0, 3, dpctl_ct_stats_show, DP_RO },
3053
    { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO },
3054
    { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns,
3055
       DP_RW },
3056
    { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO },
3057
    { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO },
3058
    { "ct-enable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_enable_tcp_seq_chk,
3059
       DP_RW },
3060
    { "ct-disable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_disable_tcp_seq_chk,
3061
       DP_RW },
3062
    { "ct-get-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_get_tcp_seq_chk, DP_RO },
3063
    { "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX,
3064
        dpctl_ct_set_limits, DP_RO },
3065
    { "ct-del-limits", "[dp] [default] [zone=N1[,N2]...]", 1, 3,
3066
        dpctl_ct_del_limits, DP_RO },
3067
    { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits,
3068
        DP_RO },
3069
    { "ct-get-sweep-interval", "[dp]", 0, 1, dpctl_ct_get_sweep, DP_RO },
3070
    { "ct-set-sweep-interval", "[dp] ms", 1, 2, dpctl_ct_set_sweep, DP_RW },
3071
    { "ipf-set-enabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_enabled, DP_RW },
3072
    { "ipf-set-disabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_disabled, DP_RW },
3073
    { "ipf-set-min-frag", "[dp] v4|v6 minfragment", 2, 3,
3074
       dpctl_ipf_set_min_frag, DP_RW },
3075
    { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2,
3076
       dpctl_ipf_set_max_nfrags, DP_RW },
3077
    { "ipf-get-status", "[dp]", 0, 1, dpctl_ct_ipf_get_status,
3078
       DP_RO },
3079
    { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
3080
    { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
3081
3082
    /* Undocumented commands for testing. */
3083
    { "parse-actions", "actions", 1, INT_MAX, dpctl_parse_actions, DP_RO },
3084
    { "normalize-actions", "actions",
3085
      2, INT_MAX, dpctl_normalize_actions, DP_RO },
3086
3087
    { NULL, NULL, 0, 0, NULL, DP_RO },
3088
};
3089
3090
static const struct dpctl_command *get_all_dpctl_commands(void)
3091
0
{
3092
0
    return all_commands;
3093
0
}
3094
3095
/* Runs the command designated by argv[0] within the command table specified by
3096
 * 'commands', which must be terminated by a command whose 'name' member is a
3097
 * null pointer. */
3098
int
3099
dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p)
3100
0
{
3101
0
    const struct dpctl_command *p;
3102
0
    if (argc < 1) {
3103
0
        dpctl_error(dpctl_p, 0, "missing command name; use --help for help");
3104
0
        return EINVAL;
3105
0
    }
3106
3107
0
    for (p = all_commands; p->name != NULL; p++) {
3108
0
        if (!strcmp(p->name, argv[0])) {
3109
0
            int n_arg = argc - 1;
3110
0
            if (n_arg < p->min_args) {
3111
0
                dpctl_error(dpctl_p, 0,
3112
0
                            "'%s' command requires at least %d arguments",
3113
0
                            p->name, p->min_args);
3114
0
                return EINVAL;
3115
0
            } else if (n_arg > p->max_args) {
3116
0
                dpctl_error(dpctl_p, 0,
3117
0
                            "'%s' command takes at most %d arguments",
3118
0
                            p->name, p->max_args);
3119
0
                return EINVAL;
3120
0
            } else {
3121
0
                if (p->mode == DP_RW && dpctl_p->read_only) {
3122
0
                    dpctl_error(dpctl_p, 0,
3123
0
                                "'%s' command does not work in read only mode",
3124
0
                                p->name);
3125
0
                    return EINVAL;
3126
0
                }
3127
0
                return p->handler(argc, argv, dpctl_p);
3128
0
            }
3129
0
        }
3130
0
    }
3131
3132
0
    dpctl_error(dpctl_p, 0, "unknown command '%s'; use --help for help",
3133
0
                argv[0]);
3134
0
    return EINVAL;
3135
0
}
3136

3137
static void
3138
dpctl_unixctl_print(void *userdata, bool error OVS_UNUSED, const char *msg)
3139
0
{
3140
0
    struct ds *ds = userdata;
3141
0
    ds_put_cstr(ds, msg);
3142
0
}
3143
3144
static void
3145
dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[],
3146
                      void *aux)
3147
0
{
3148
0
    struct ds ds = DS_EMPTY_INITIALIZER;
3149
0
    bool error = false;
3150
3151
0
    struct dpctl_params dpctl_p = {
3152
0
        .is_appctl = true,
3153
0
        .output = dpctl_unixctl_print,
3154
0
        .aux = &ds,
3155
0
    };
3156
3157
    /* Parse options (like getopt). Unfortunately it does
3158
     * not seem a good idea to call getopt_long() here, since it uses global
3159
     * variables */
3160
0
    bool set_names = false;
3161
0
    while (argc > 1 && !error) {
3162
0
        const char *arg = argv[1];
3163
0
        if (!strncmp(arg, "--", 2)) {
3164
            /* Long option */
3165
0
            if (!strcmp(arg, "--statistics")) {
3166
0
                dpctl_p.print_statistics = true;
3167
0
            } else if (!strcmp(arg, "--clear")) {
3168
0
                dpctl_p.zero_statistics = true;
3169
0
            } else if (!strcmp(arg, "--may-create")) {
3170
0
                dpctl_p.may_create = true;
3171
0
            } else if (!strcmp(arg, "--more")) {
3172
0
                dpctl_p.verbosity++;
3173
0
            } else if (!strcmp(arg, "--names")) {
3174
0
                dpctl_p.names = true;
3175
0
                set_names = true;
3176
0
            } else if (!strcmp(arg, "--no-names")) {
3177
0
                dpctl_p.names = false;
3178
0
                set_names = true;
3179
0
            } else {
3180
0
                ds_put_format(&ds, "Unrecognized option %s", argv[1]);
3181
0
                error = true;
3182
0
            }
3183
0
        } else if (arg[0] == '-' && arg[1] != '\0') {
3184
            /* Short option[s] */
3185
0
            const char *opt = &arg[1];
3186
3187
0
            while (*opt && !error) {
3188
0
                switch (*opt) {
3189
0
                case 'm':
3190
0
                    dpctl_p.verbosity++;
3191
0
                    break;
3192
0
                case 's':
3193
0
                    dpctl_p.print_statistics = true;
3194
0
                    break;
3195
0
                default:
3196
0
                    ds_put_format(&ds, "Unrecognized option -%c", *opt);
3197
0
                    error = true;
3198
0
                    break;
3199
0
                }
3200
0
                opt++;
3201
0
            }
3202
0
        } else {
3203
            /* Doesn't start with -, not an option */
3204
0
            break;
3205
0
        }
3206
3207
0
        if (error) {
3208
0
            break;
3209
0
        }
3210
0
        argv++;
3211
0
        argc--;
3212
0
    }
3213
0
    if (!set_names) {
3214
0
        dpctl_p.names = dpctl_p.verbosity > 0;
3215
0
    }
3216
3217
0
    if (!error) {
3218
0
        dpctl_command_handler *handler = (dpctl_command_handler *) aux;
3219
0
        error = handler(argc, argv, &dpctl_p) != 0;
3220
0
    }
3221
3222
0
    if (error) {
3223
0
        unixctl_command_reply_error(conn, ds_cstr(&ds));
3224
0
    } else {
3225
0
        unixctl_command_reply(conn, ds_cstr(&ds));
3226
0
    }
3227
3228
0
    ds_destroy(&ds);
3229
0
}
3230
3231
void
3232
dpctl_unixctl_register(void)
3233
0
{
3234
0
    const struct dpctl_command *p;
3235
3236
0
    for (p = all_commands; p->name != NULL; p++) {
3237
0
        if (strcmp(p->name, "help")) {
3238
0
            char *cmd_name = xasprintf("dpctl/%s", p->name);
3239
0
            unixctl_command_register(cmd_name,
3240
0
                                     p->usage,
3241
0
                                     p->min_args,
3242
0
                                     p->max_args,
3243
0
                                     dpctl_unixctl_handler,
3244
0
                                     p->handler);
3245
0
            free(cmd_name);
3246
0
        }
3247
0
    }
3248
0
}