Coverage Report

Created: 2025-07-01 06:50

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