Coverage Report

Created: 2023-03-26 07:42

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