Coverage Report

Created: 2025-08-26 06:20

/src/openvswitch/lib/ofp-table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008-2017 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 "openvswitch/ofp-table.h"
19
#include "bitmap.h"
20
#include "nx-match.h"
21
#include "openvswitch/dynamic-string.h"
22
#include "openvswitch/json.h"
23
#include "openvswitch/ofp-actions.h"
24
#include "openvswitch/ofp-msgs.h"
25
#include "openvswitch/ofp-print.h"
26
#include "openvswitch/ofp-prop.h"
27
#include "openvswitch/ofpbuf.h"
28
#include "openvswitch/vlog.h"
29
#include "util.h"
30
31
VLOG_DEFINE_THIS_MODULE(ofp_table);
32
33
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
34
35
static ovs_be32 ofputil_encode_table_config(enum ofputil_table_miss,
36
                                            enum ofputil_table_eviction,
37
                                            enum ofputil_table_vacancy,
38
                                            enum ofp_version);
39
static enum ofputil_table_vacancy ofputil_decode_table_vacancy(
40
    ovs_be32 config, enum ofp_version);
41
static enum ofputil_table_eviction ofputil_decode_table_eviction(
42
    ovs_be32 config, enum ofp_version);
43
44
const char *
45
ofputil_table_miss_to_string(enum ofputil_table_miss miss)
46
20.3k
{
47
20.3k
    switch (miss) {
48
0
    case OFPUTIL_TABLE_MISS_DEFAULT: return "default";
49
15.7k
    case OFPUTIL_TABLE_MISS_CONTROLLER: return "controller";
50
2.56k
    case OFPUTIL_TABLE_MISS_CONTINUE: return "continue";
51
2.10k
    case OFPUTIL_TABLE_MISS_DROP: return "drop";
52
0
    default: return "***error***";
53
20.3k
    }
54
20.3k
}
55
56
const char *
57
ofputil_table_eviction_to_string(enum ofputil_table_eviction eviction)
58
5.36k
{
59
5.36k
    switch (eviction) {
60
0
    case OFPUTIL_TABLE_EVICTION_DEFAULT: return "default";
61
1.42k
    case OFPUTIL_TABLE_EVICTION_ON: return "on";
62
3.66k
    case OFPUTIL_TABLE_EVICTION_OFF: return "off";
63
278
    default: return "***error***";
64
5.36k
    }
65
5.36k
}
66
67
const char *
68
ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy)
69
5.36k
{
70
5.36k
    switch (vacancy) {
71
0
    case OFPUTIL_TABLE_VACANCY_DEFAULT: return "default";
72
2.40k
    case OFPUTIL_TABLE_VACANCY_ON: return "on";
73
2.96k
    case OFPUTIL_TABLE_VACANCY_OFF: return "off";
74
0
    default: return "***error***";
75
5.36k
    }
76
5.36k
}
77
78
static bool
79
ofp15_table_features_command_is_valid(enum ofp15_table_features_command cmd)
80
11.8k
{
81
11.8k
    switch (cmd) {
82
8.47k
    case OFPTFC15_REPLACE:
83
8.71k
    case OFPTFC15_MODIFY:
84
11.5k
    case OFPTFC15_ENABLE:
85
11.6k
    case OFPTFC15_DISABLE:
86
11.6k
        return true;
87
88
234
    default:
89
234
        return false;
90
11.8k
    }
91
11.8k
}
92
93
static const char *
94
ofp15_table_features_command_to_string(enum ofp15_table_features_command cmd)
95
176
{
96
176
    switch (cmd) {
97
0
    case OFPTFC15_REPLACE: return "replace";
98
86
    case OFPTFC15_MODIFY: return "modify";
99
49
    case OFPTFC15_ENABLE: return "enable";
100
41
    case OFPTFC15_DISABLE: return "disable";
101
0
    default: return "***bad command***";
102
176
    }
103
176
}
104

105
/* ofputil_table_map.  */
106
107
void
108
ofputil_table_map_init(struct ofputil_table_map *map)
109
0
{
110
0
    namemap_init(&map->map);
111
0
}
112
113
void
114
ofputil_table_map_put(struct ofputil_table_map *map,
115
                      uint8_t table_id, const char *name)
116
0
{
117
0
    namemap_put(&map->map, table_id, name);
118
0
}
119
120
const char *
121
ofputil_table_map_get_name(const struct ofputil_table_map *map,
122
                           uint8_t table_id)
123
191k
{
124
191k
    struct namemap_node *node
125
191k
        = map ? namemap_find_by_number(&map->map, table_id) : NULL;
126
191k
    return node && !node->duplicate ? node->name : NULL;
127
191k
}
128
129
uint8_t
130
ofputil_table_map_get_number(const struct ofputil_table_map *map,
131
                             const char *name)
132
0
{
133
0
    struct namemap_node *node
134
0
        = map ? namemap_find_by_name(&map->map, name) : NULL;
135
0
    return node && !node->duplicate ? node->number : UINT8_MAX;
136
0
}
137
138
void
139
ofputil_table_map_destroy(struct ofputil_table_map *map)
140
0
{
141
0
    namemap_destroy(&map->map);
142
0
}
143

144
/* Table numbers. */
145
146
/* Stores the table number represented by 's' into '*tablep'.  's' may be an
147
 * integer or, if 'table_map' is nonnull, a name (quoted or unquoted).
148
 *
149
 * Returns true if successful, false if 's' is not a valid OpenFlow table
150
 * number or name.  The caller should issue an error message in this case,
151
 * because this function usually does not.  (This gives the caller an
152
 * opportunity to look up the table name another way, e.g. by contacting the
153
 * switch and listing the names of all its tables). */
154
bool
155
ofputil_table_from_string(const char *s,
156
                          const struct ofputil_table_map *table_map,
157
                          uint8_t *tablep)
158
0
{
159
0
    *tablep = 0;
160
0
    if (*s == '-') {
161
0
        VLOG_WARN("Negative value %s is not a valid table number.", s);
162
0
        return false;
163
0
    }
164
165
0
    unsigned int table;
166
0
    if (str_to_uint(s, 10, &table)) {
167
0
        if (table > 255) {
168
0
            VLOG_WARN("table %u is outside the supported range 0 through 255",
169
0
                      table);
170
0
            return false;
171
0
        }
172
0
        *tablep = table;
173
0
        return true;
174
0
    } else {
175
0
        if (s[0] != '"') {
176
0
            table = ofputil_table_map_get_number(table_map, s);
177
0
        } else {
178
0
            size_t length = strlen(s);
179
0
            char *name = NULL;
180
0
            if (length > 1
181
0
                && s[length - 1] == '"'
182
0
                && json_string_unescape(s + 1, length - 2, &name)) {
183
0
                table = ofputil_table_map_get_number(table_map, name);
184
0
            }
185
0
            free(name);
186
0
        }
187
0
        if (table != UINT8_MAX) {
188
0
            *tablep = table;
189
0
            return true;
190
0
        }
191
192
0
        return false;
193
0
    }
194
0
}
195
196
/* Appends to 's' a string representation of the OpenFlow table number 'table',
197
 * either the table number or a name drawn from 'table_map'. */
198
void
199
ofputil_format_table(uint8_t table, const struct ofputil_table_map *table_map,
200
                     struct ds *s)
201
96.2k
{
202
96.2k
    const char *table_name = ofputil_table_map_get_name(table_map, table);
203
96.2k
    if (table_name) {
204
0
        namemap_put_name(table_name, s);
205
96.2k
    } else {
206
96.2k
        ds_put_format(s, "%"PRIu8, table);
207
96.2k
    }
208
96.2k
}
209
210
/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
211
 * representation of OpenFlow table number 'table', either the table's number
212
 * or a name drawn from 'table_map'. */
213
void
214
ofputil_table_to_string(uint8_t table,
215
                        const struct ofputil_table_map *table_map,
216
                        char *namebuf, size_t bufsize)
217
0
{
218
0
    const char *table_name = ofputil_table_map_get_name(table_map, table);
219
0
    if (table_name) {
220
0
        struct ds s = DS_EMPTY_INITIALIZER;
221
0
        namemap_put_name(table_name, &s);
222
0
        ovs_strlcpy(namebuf, ds_cstr(&s), bufsize);
223
0
        ds_destroy(&s);
224
0
        return;
225
0
    }
226
227
0
    snprintf(namebuf, bufsize, "%"PRIu8, table);
228
0
}
229

230
/* Table features. */
231
232
static enum ofperr
233
pull_table_feature_property(struct ofpbuf *msg, struct ofpbuf *payload,
234
                            uint64_t *typep)
235
22.8k
{
236
22.8k
    enum ofperr error;
237
238
22.8k
    error = ofpprop_pull(msg, payload, typep);
239
22.8k
    if (payload && !error) {
240
20.4k
        ofpbuf_pull(payload, (char *)payload->msg - (char *)payload->header);
241
20.4k
    }
242
22.8k
    return error;
243
22.8k
}
244
245
static enum ofperr
246
parse_action_bitmap(struct ofpbuf *payload, enum ofp_version ofp_version,
247
                    uint64_t *ofpacts)
248
1.89k
{
249
1.89k
    uint32_t types = 0;
250
251
5.25k
    while (payload->size > 0) {
252
4.79k
        enum ofperr error;
253
4.79k
        uint64_t type;
254
255
4.79k
        error = ofpprop_pull__(payload, NULL, 1, 0x10000, &type);
256
4.79k
        if (error) {
257
1.43k
            return error;
258
1.43k
        }
259
3.35k
        if (type < CHAR_BIT * sizeof types) {
260
1.75k
            types |= 1u << type;
261
1.75k
        }
262
3.35k
    }
263
264
460
    *ofpacts = ofpact_bitmap_from_openflow(htonl(types), ofp_version);
265
460
    return 0;
266
1.89k
}
267
268
static enum ofperr
269
parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts)
270
5.18k
{
271
5.18k
    *insts = 0;
272
8.54k
    while (payload->size > 0) {
273
5.28k
        enum ovs_instruction_type inst;
274
5.28k
        enum ofperr error;
275
5.28k
        uint64_t ofpit;
276
277
        /* OF1.3 and OF1.4 aren't clear about padding in the instruction IDs.
278
         * It seems clear that they aren't padded to 8 bytes, though, because
279
         * both standards say that "non-experimenter instructions are 4 bytes"
280
         * and do not mention any padding before the first instruction ID.
281
         * (There wouldn't be any point in padding to 8 bytes if the IDs were
282
         * aligned on an odd 4-byte boundary.)
283
         *
284
         * Anyway, we just assume they're all glommed together on byte
285
         * boundaries. */
286
5.28k
        error = ofpprop_pull__(payload, NULL, 1, 0x10000, &ofpit);
287
5.28k
        if (error) {
288
1.92k
            return error;
289
1.92k
        }
290
291
3.36k
        error = ovs_instruction_type_from_inst_type(&inst, ofpit);
292
3.36k
        if (!error) {
293
1.17k
            *insts |= 1u << inst;
294
2.18k
        } else if (!loose) {
295
0
            return error;
296
0
        }
297
3.36k
    }
298
3.25k
    return 0;
299
5.18k
}
300
301
static enum ofperr
302
parse_table_features_next_table(struct ofpbuf *payload,
303
                                unsigned long int *next_tables)
304
4.32k
{
305
4.32k
    size_t i;
306
307
4.32k
    memset(next_tables, 0, bitmap_n_bytes(255));
308
45.1k
    for (i = 0; i < payload->size; i++) {
309
41.9k
        uint8_t id = ((const uint8_t *) payload->data)[i];
310
41.9k
        if (id >= 255) {
311
1.09k
            return OFPERR_OFPBPC_BAD_VALUE;
312
1.09k
        }
313
40.8k
        bitmap_set1(next_tables, id);
314
40.8k
    }
315
3.23k
    return 0;
316
4.32k
}
317
318
static enum ofperr
319
parse_oxms(struct ofpbuf *payload, bool loose,
320
           struct mf_bitmap *exactp, struct mf_bitmap *maskedp)
321
4.11k
{
322
4.11k
    struct mf_bitmap exact = MF_BITMAP_INITIALIZER;
323
4.11k
    struct mf_bitmap masked = MF_BITMAP_INITIALIZER;
324
325
67.6k
    while (payload->size > 0) {
326
64.2k
        const struct mf_field *field;
327
64.2k
        enum ofperr error;
328
64.2k
        bool hasmask;
329
330
64.2k
        error = nx_pull_header(payload, NULL, &field, &hasmask);
331
64.2k
        if (!error) {
332
2.53k
            bitmap_set1(hasmask ? masked.bm : exact.bm, field->id);
333
61.7k
        } else if (error != OFPERR_OFPBMC_BAD_FIELD || !loose) {
334
777
            return error;
335
777
        }
336
64.2k
    }
337
3.33k
    if (exactp) {
338
3.33k
        *exactp = exact;
339
3.33k
    } else if (!bitmap_is_all_zeros(exact.bm, MFF_N_IDS)) {
340
0
        return OFPERR_OFPBMC_BAD_MASK;
341
0
    }
342
3.33k
    if (maskedp) {
343
641
        *maskedp = masked;
344
2.69k
    } else if (!bitmap_is_all_zeros(masked.bm, MFF_N_IDS)) {
345
1.16k
        return OFPERR_OFPBMC_BAD_MASK;
346
1.16k
    }
347
2.17k
    return 0;
348
3.33k
}
349
350
/* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract
351
 * ofputil_table_features in 'tf'.
352
 *
353
 * If 'raw_properties' is nonnull, this function ignores properties and values
354
 * that it does not understand, as a controller would want to do when
355
 * interpreting capabilities provided by a switch.  In this mode, on success,
356
 * it initializes 'raw_properties' to contain the properties that were parsed;
357
 * this allows the caller to later re-serialize the same properties without
358
 * change.
359
 *
360
 * If 'raw_properties' is null, this function treats unknown properties and
361
 * values as an error, as a switch would want to do when interpreting a
362
 * configuration request made by a controller.
363
 *
364
 * A single OpenFlow message can specify features for multiple tables.  Calling
365
 * this function multiple times for a single 'msg' iterates through the tables
366
 * in the message.  The caller must initially leave 'msg''s layer pointers null
367
 * and not modify them between calls.
368
 *
369
 * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise
370
 * a positive "enum ofperr" value. */
371
int
372
ofputil_decode_table_features(struct ofpbuf *msg,
373
                              struct ofputil_table_features *tf,
374
                              struct ofpbuf *raw_properties)
375
15.6k
{
376
15.6k
    bool loose = raw_properties != NULL;
377
378
15.6k
    memset(tf, 0, sizeof *tf);
379
380
15.6k
    if (!msg->header) {
381
14.3k
        ofpraw_pull_assert(msg);
382
14.3k
    }
383
384
15.6k
    if (!msg->size) {
385
330
        return EOF;
386
330
    }
387
388
15.2k
    const struct ofp_header *oh = msg->header;
389
15.2k
    struct ofp13_table_features *otf = msg->data;
390
15.2k
    if (msg->size < sizeof *otf) {
391
574
        return OFPERR_OFPBPC_BAD_LEN;
392
574
    }
393
394
14.7k
    unsigned int len = ntohs(otf->length);
395
14.7k
    if (len < sizeof *otf || len % 8 || len > msg->size) {
396
1.36k
        return OFPERR_OFPBPC_BAD_LEN;
397
1.36k
    }
398
399
13.3k
    if (oh->version >= OFP15_VERSION) {
400
11.8k
        if (!ofp15_table_features_command_is_valid(otf->command)) {
401
234
            return OFPERR_OFPTFFC_BAD_COMMAND;
402
234
        }
403
11.6k
        tf->command = otf->command;
404
11.6k
    } else {
405
1.48k
        tf->command = OFPTFC15_REPLACE;
406
1.48k
    }
407
408
13.1k
    tf->table_id = otf->table_id;
409
13.1k
    if (tf->table_id == OFPTT_ALL) {
410
10
        return OFPERR_OFPTFFC_BAD_TABLE;
411
10
    }
412
413
13.1k
    ovs_strlcpy_arrays(tf->name, otf->name);
414
13.1k
    tf->metadata_match = otf->metadata_match;
415
13.1k
    tf->metadata_write = otf->metadata_write;
416
13.1k
    tf->miss_config = OFPUTIL_TABLE_MISS_DEFAULT;
417
13.1k
    if (oh->version >= OFP14_VERSION) {
418
13.0k
        uint32_t caps = ntohl(otf->capabilities);
419
13.0k
        tf->supports_eviction = (caps & OFPTC14_EVICTION) != 0;
420
13.0k
        tf->supports_vacancy_events = (caps & OFPTC14_VACANCY_EVENTS) != 0;
421
13.0k
    } else {
422
47
        tf->supports_eviction = -1;
423
47
        tf->supports_vacancy_events = -1;
424
47
    }
425
13.1k
    tf->max_entries = ntohl(otf->max_entries);
426
427
13.1k
    struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
428
13.1k
                                                        len);
429
13.1k
    ofpbuf_pull(&properties, sizeof *otf);
430
13.1k
    tf->any_properties = properties.size > 0;
431
13.1k
    if (raw_properties) {
432
13.1k
        *raw_properties = properties;
433
13.1k
    }
434
13.1k
    uint32_t seen = 0;
435
26.5k
    while (properties.size > 0) {
436
22.8k
        struct ofpbuf payload;
437
22.8k
        enum ofperr error;
438
22.8k
        uint64_t type;
439
440
22.8k
        error = pull_table_feature_property(&properties, &payload, &type);
441
22.8k
        if (error) {
442
2.49k
            return error;
443
2.49k
        }
444
445
20.4k
        if (type < 32) {
446
16.0k
            uint32_t bit = 1u << type;
447
16.0k
            if (seen & bit) {
448
530
                return OFPERR_OFPTFFC_BAD_FEATURES;
449
530
            }
450
15.5k
            seen |= bit;
451
15.5k
        }
452
453
19.8k
        switch ((enum ofp13_table_feature_prop_type) type) {
454
2.45k
        case OFPTFPT13_INSTRUCTIONS:
455
2.45k
            error = parse_instruction_ids(&payload, loose,
456
2.45k
                                          &tf->nonmiss.instructions);
457
2.45k
            break;
458
2.73k
        case OFPTFPT13_INSTRUCTIONS_MISS:
459
2.73k
            error = parse_instruction_ids(&payload, loose,
460
2.73k
                                          &tf->miss.instructions);
461
2.73k
            break;
462
463
3.18k
        case OFPTFPT13_NEXT_TABLES:
464
3.18k
            error = parse_table_features_next_table(&payload,
465
3.18k
                                                    tf->nonmiss.next);
466
3.18k
            break;
467
1.14k
        case OFPTFPT13_NEXT_TABLES_MISS:
468
1.14k
            error = parse_table_features_next_table(&payload, tf->miss.next);
469
1.14k
            break;
470
471
28
        case OFPTFPT13_WRITE_ACTIONS:
472
28
            error = parse_action_bitmap(&payload, oh->version,
473
28
                                        &tf->nonmiss.write.ofpacts);
474
28
            break;
475
89
        case OFPTFPT13_WRITE_ACTIONS_MISS:
476
89
            error = parse_action_bitmap(&payload, oh->version,
477
89
                                        &tf->miss.write.ofpacts);
478
89
            break;
479
480
1.13k
        case OFPTFPT13_APPLY_ACTIONS:
481
1.13k
            error = parse_action_bitmap(&payload, oh->version,
482
1.13k
                                        &tf->nonmiss.apply.ofpacts);
483
1.13k
            break;
484
648
        case OFPTFPT13_APPLY_ACTIONS_MISS:
485
648
            error = parse_action_bitmap(&payload, oh->version,
486
648
                                        &tf->miss.apply.ofpacts);
487
648
            break;
488
489
1.33k
        case OFPTFPT13_MATCH:
490
1.33k
            error = parse_oxms(&payload, loose, &tf->match, &tf->mask);
491
1.33k
            break;
492
568
        case OFPTFPT13_WILDCARDS:
493
568
            error = parse_oxms(&payload, loose, &tf->wildcard, NULL);
494
568
            break;
495
496
1.08k
        case OFPTFPT13_WRITE_SETFIELD:
497
1.08k
            error = parse_oxms(&payload, loose,
498
1.08k
                               &tf->nonmiss.write.set_fields, NULL);
499
1.08k
            break;
500
242
        case OFPTFPT13_WRITE_SETFIELD_MISS:
501
242
            error = parse_oxms(&payload, loose,
502
242
                               &tf->miss.write.set_fields, NULL);
503
242
            break;
504
734
        case OFPTFPT13_APPLY_SETFIELD:
505
734
            error = parse_oxms(&payload, loose,
506
734
                               &tf->nonmiss.apply.set_fields, NULL);
507
734
            break;
508
150
        case OFPTFPT13_APPLY_SETFIELD_MISS:
509
150
            error = parse_oxms(&payload, loose,
510
150
                               &tf->miss.apply.set_fields, NULL);
511
150
            break;
512
513
0
        case OFPTFPT13_EXPERIMENTER:
514
0
        case OFPTFPT13_EXPERIMENTER_MISS:
515
4.34k
        default:
516
4.34k
            error = OFPPROP_UNKNOWN(loose, "table features", type);
517
4.34k
            break;
518
19.8k
        }
519
19.8k
        if (error) {
520
6.40k
            return error;
521
6.40k
        }
522
19.8k
    }
523
524
    /* OpenFlow 1.3 and 1.4 always require all of the required properties.
525
     * OpenFlow 1.5 requires all of them if any property is present. */
526
3.68k
    unsigned int missing = (seen & OFPTFPT13_REQUIRED) ^ OFPTFPT13_REQUIRED;
527
3.68k
    if (missing && (tf->any_properties || oh->version < OFP15_VERSION)) {
528
2.37k
        VLOG_WARN_RL(&rl,
529
2.37k
                     "table features message missing %u required "
530
2.37k
                     "properties, including property %d",
531
2.37k
                     count_1bits(missing), rightmost_1bit_idx(missing));
532
2.37k
        return OFPERR_OFPTFFC_BAD_FEATURES;
533
2.37k
    }
534
535
    /* Copy nonmiss to miss when appropriate. */
536
1.31k
    if (tf->any_properties) {
537
0
        if (!(seen & (1u << OFPTFPT13_INSTRUCTIONS_MISS))) {
538
0
            tf->miss.instructions = tf->nonmiss.instructions;
539
0
        }
540
0
        if (!(seen & (1u << OFPTFPT13_NEXT_TABLES_MISS))) {
541
0
            memcpy(tf->miss.next, tf->nonmiss.next, sizeof tf->miss.next);
542
0
        }
543
0
        if (!(seen & (1u << OFPTFPT13_WRITE_ACTIONS_MISS))) {
544
0
            tf->miss.write.ofpacts = tf->nonmiss.write.ofpacts;
545
0
        }
546
0
        if (!(seen & (1u << OFPTFPT13_APPLY_ACTIONS_MISS))) {
547
0
            tf->miss.apply.ofpacts = tf->nonmiss.apply.ofpacts;
548
0
        }
549
0
        if (!(seen & (1u << OFPTFPT13_WRITE_SETFIELD_MISS))) {
550
0
            tf->miss.write.set_fields = tf->nonmiss.write.set_fields;
551
0
        }
552
0
        if (!(seen & (1u << OFPTFPT13_APPLY_SETFIELD_MISS))) {
553
0
            tf->miss.apply.set_fields = tf->nonmiss.apply.set_fields;
554
0
        }
555
0
    }
556
557
    /* Fix inconsistencies:
558
     *
559
     *     - Turn on 'match' bits that are set in 'mask', because maskable
560
     *       fields are matchable.
561
     *
562
     *     - Turn on 'wildcard' bits that are set in 'mask', because a field
563
     *       that is arbitrarily maskable can be wildcarded entirely.
564
     *
565
     *     - Turn off 'wildcard' bits that are not in 'match', because a field
566
     *       must be matchable for it to be meaningfully wildcarded. */
567
1.31k
    bitmap_or(tf->match.bm, tf->mask.bm, MFF_N_IDS);
568
1.31k
    bitmap_or(tf->wildcard.bm, tf->mask.bm, MFF_N_IDS);
569
1.31k
    bitmap_and(tf->wildcard.bm, tf->match.bm, MFF_N_IDS);
570
571
1.31k
    return 0;
572
3.68k
}
573
574
/* Encodes and returns a request to obtain the table features of a switch.
575
 * The message is encoded for OpenFlow version 'ofp_version'. */
576
struct ofpbuf *
577
ofputil_encode_table_features_request(enum ofp_version ofp_version)
578
0
{
579
0
    struct ofpbuf *request = NULL;
580
581
0
    switch (ofp_version) {
582
0
    case OFP10_VERSION:
583
0
    case OFP11_VERSION:
584
0
    case OFP12_VERSION:
585
0
        ovs_fatal(0, "dump-table-features needs OpenFlow 1.3 or later "
586
0
                     "(\'-O OpenFlow13\')");
587
0
    case OFP13_VERSION:
588
0
    case OFP14_VERSION:
589
0
    case OFP15_VERSION:
590
0
        request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
591
0
                               ofp_version, 0);
592
0
        break;
593
0
    default:
594
0
        OVS_NOT_REACHED();
595
0
    }
596
597
0
    return request;
598
0
}
599
600
static void
601
put_fields_property(struct ofpbuf *reply,
602
                    const struct mf_bitmap *fields,
603
                    const struct mf_bitmap *masks,
604
                    enum ofp13_table_feature_prop_type property,
605
                    enum ofp_version version)
606
0
{
607
0
    enum mf_field_id field;
608
0
    size_t start_ofs;
609
610
0
    start_ofs = ofpprop_start(reply, property);
611
0
    BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) {
612
0
        nx_put_header(reply, field, version,
613
0
                      masks && bitmap_is_set(masks->bm, field));
614
0
    }
615
0
    ofpprop_end(reply, start_ofs);
616
0
}
617
618
static void
619
put_table_action_features(struct ofpbuf *reply,
620
                          const struct ofputil_table_action_features *taf,
621
                          enum ofp13_table_feature_prop_type actions_type,
622
                          enum ofp13_table_feature_prop_type set_fields_type,
623
                          int miss_offset, enum ofp_version version)
624
0
{
625
0
    ofpprop_put_bitmap(reply, actions_type + miss_offset,
626
0
                       ntohl(ofpact_bitmap_to_openflow(taf->ofpacts,
627
0
                                                       version)));
628
0
    put_fields_property(reply, &taf->set_fields, NULL,
629
0
                        set_fields_type + miss_offset, version);
630
0
}
631
632
static void
633
put_table_instruction_features(
634
    struct ofpbuf *reply, const struct ofputil_table_instruction_features *tif,
635
    int miss_offset, enum ofp_version version)
636
0
{
637
0
    size_t start_ofs;
638
0
    uint8_t table_id;
639
640
0
    ofpprop_put_bitmap(reply, OFPTFPT13_INSTRUCTIONS + miss_offset,
641
0
                       ntohl(ovsinst_bitmap_to_openflow(tif->instructions,
642
0
                                                        version)));
643
644
0
    start_ofs = ofpprop_start(reply, OFPTFPT13_NEXT_TABLES + miss_offset);
645
0
    BITMAP_FOR_EACH_1 (table_id, 255, tif->next) {
646
0
        ofpbuf_put(reply, &table_id, 1);
647
0
    }
648
0
    ofpprop_end(reply, start_ofs);
649
650
0
    put_table_action_features(reply, &tif->write,
651
0
                              OFPTFPT13_WRITE_ACTIONS,
652
0
                              OFPTFPT13_WRITE_SETFIELD, miss_offset, version);
653
0
    put_table_action_features(reply, &tif->apply,
654
0
                              OFPTFPT13_APPLY_ACTIONS,
655
0
                              OFPTFPT13_APPLY_SETFIELD, miss_offset, version);
656
0
}
657
658
/* Appends a table features record to 'msgs', which must be a
659
 * OFPT_TABLE_FEATURES request or reply.  If 'raw_properties' is nonnull, then
660
 * it uses its contents verbatim as the table features properties, ignoring the
661
 * corresponding members of 'tf'. */
662
void
663
ofputil_append_table_features(const struct ofputil_table_features *tf,
664
                              const struct ofpbuf *raw_properties,
665
                              struct ovs_list *msgs)
666
0
{
667
0
    struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(msgs));
668
0
    enum ofp_version version = ofpmp_version(msgs);
669
0
    size_t start_ofs = msg->size;
670
0
    struct ofp13_table_features *otf;
671
672
0
    otf = ofpbuf_put_zeros(msg, sizeof *otf);
673
0
    otf->table_id = tf->table_id;
674
0
    otf->command = version >= OFP15_VERSION ? tf->command : 0;
675
0
    ovs_strlcpy_arrays(otf->name, tf->name);
676
0
    otf->metadata_match = tf->metadata_match;
677
0
    otf->metadata_write = tf->metadata_write;
678
0
    if (version >= OFP14_VERSION) {
679
0
        if (tf->supports_eviction) {
680
0
            otf->capabilities |= htonl(OFPTC14_EVICTION);
681
0
        }
682
0
        if (tf->supports_vacancy_events) {
683
0
            otf->capabilities |= htonl(OFPTC14_VACANCY_EVENTS);
684
0
        }
685
0
    }
686
0
    otf->max_entries = htonl(tf->max_entries);
687
688
0
    if (raw_properties) {
689
0
        ofpbuf_put(msg, raw_properties->data, raw_properties->size);
690
0
    } else if (tf->any_properties) {
691
0
        put_table_instruction_features(msg, &tf->nonmiss, 0, version);
692
0
        put_table_instruction_features(msg, &tf->miss, 1, version);
693
694
0
        put_fields_property(msg, &tf->match, &tf->mask,
695
0
                            OFPTFPT13_MATCH, version);
696
0
        put_fields_property(msg, &tf->wildcard, NULL,
697
0
                            OFPTFPT13_WILDCARDS, version);
698
0
    }
699
700
0
    otf = ofpbuf_at_assert(msg, start_ofs, sizeof *otf);
701
0
    otf->length = htons(msg->size - start_ofs);
702
0
    ofpmp_postappend(msgs, start_ofs);
703
0
}
704
705
static enum ofperr
706
parse_table_desc_vacancy_property(struct ofpbuf *property,
707
                                  struct ofputil_table_desc *td)
708
49
{
709
49
    struct ofp14_table_mod_prop_vacancy *otv = property->data;
710
711
49
    if (property->size != sizeof *otv) {
712
11
        return OFPERR_OFPBPC_BAD_LEN;
713
11
    }
714
715
38
    td->table_vacancy.vacancy_down = otv->vacancy_down;
716
38
    td->table_vacancy.vacancy_up = otv->vacancy_up;
717
38
    td->table_vacancy.vacancy = otv->vacancy;
718
38
    return 0;
719
49
}
720
721
/* Decodes the next OpenFlow "table desc" message (of possibly several) from
722
 * 'msg' into an abstract form in '*td'.  Returns 0 if successful, EOF if the
723
 * last "table desc" in 'msg' was already decoded, otherwise an OFPERR_*
724
 * value. */
725
int
726
ofputil_decode_table_desc(struct ofpbuf *msg,
727
                          struct ofputil_table_desc *td,
728
                          enum ofp_version version)
729
7.57k
{
730
7.57k
    memset(td, 0, sizeof *td);
731
732
7.57k
    if (!msg->header) {
733
3.49k
        ofpraw_pull_assert(msg);
734
3.49k
    }
735
736
7.57k
    if (!msg->size) {
737
1.56k
        return EOF;
738
1.56k
    }
739
740
6.01k
    struct ofp14_table_desc *otd = ofpbuf_try_pull(msg, sizeof *otd);
741
6.01k
    if (!otd) {
742
0
        VLOG_WARN_RL(&rl, "OFP14_TABLE_DESC reply has %"PRIu32" "
743
0
                     "leftover bytes at end", msg->size);
744
0
        return OFPERR_OFPBRC_BAD_LEN;
745
0
    }
746
747
6.01k
    td->table_id = otd->table_id;
748
6.01k
    size_t length = ntohs(otd->length);
749
6.01k
    if (length < sizeof *otd || length - sizeof *otd > msg->size) {
750
1.59k
        VLOG_WARN_RL(&rl, "OFP14_TABLE_DESC reply claims invalid "
751
1.59k
                     "length %"PRIuSIZE, length);
752
1.59k
        return OFPERR_OFPBRC_BAD_LEN;
753
1.59k
    }
754
4.41k
    length -= sizeof *otd;
755
756
4.41k
    td->eviction = ofputil_decode_table_eviction(otd->config, version);
757
4.41k
    td->vacancy = ofputil_decode_table_vacancy(otd->config, version);
758
4.41k
    td->eviction_flags = UINT32_MAX;
759
760
4.41k
    struct ofpbuf properties = ofpbuf_const_initializer(
761
4.41k
        ofpbuf_pull(msg, length), length);
762
6.06k
    while (properties.size > 0) {
763
2.34k
        struct ofpbuf payload;
764
2.34k
        enum ofperr error;
765
2.34k
        uint64_t type;
766
767
2.34k
        error = ofpprop_pull(&properties, &payload, &type);
768
2.34k
        if (error) {
769
680
            return error;
770
680
        }
771
772
1.66k
        switch (type) {
773
1.19k
        case OFPTMPT14_EVICTION:
774
1.19k
            error = ofpprop_parse_u32(&payload, &td->eviction_flags);
775
1.19k
            break;
776
777
49
        case OFPTMPT14_VACANCY:
778
49
            error = parse_table_desc_vacancy_property(&payload, td);
779
49
            break;
780
781
427
        default:
782
427
            error = OFPPROP_UNKNOWN(true, "table_desc", type);
783
427
            break;
784
1.66k
        }
785
786
1.66k
        if (error) {
787
11
            return error;
788
11
        }
789
1.66k
    }
790
791
3.72k
    return 0;
792
4.41k
}
793
794
/* Encodes and returns a request to obtain description of tables of a switch.
795
 * The message is encoded for OpenFlow version 'ofp_version'. */
796
struct ofpbuf *
797
ofputil_encode_table_desc_request(enum ofp_version ofp_version)
798
0
{
799
0
    struct ofpbuf *request = NULL;
800
801
0
    if (ofp_version >= OFP14_VERSION) {
802
0
        request = ofpraw_alloc(OFPRAW_OFPST14_TABLE_DESC_REQUEST,
803
0
                               ofp_version, 0);
804
0
    } else {
805
0
        ovs_fatal(0, "dump-table-desc needs OpenFlow 1.4 or later "
806
0
                  "(\'-O OpenFlow14\')");
807
0
    }
808
809
0
    return request;
810
0
}
811
812
/* Function to append Table desc information in a reply list. */
813
void
814
ofputil_append_table_desc_reply(const struct ofputil_table_desc *td,
815
                                struct ovs_list *replies,
816
                                enum ofp_version version)
817
0
{
818
0
    struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
819
0
    size_t start_otd;
820
0
    struct ofp14_table_desc *otd;
821
822
0
    start_otd = reply->size;
823
0
    ofpbuf_put_zeros(reply, sizeof *otd);
824
0
    if (td->eviction_flags != UINT32_MAX) {
825
0
        ofpprop_put_u32(reply, OFPTMPT14_EVICTION, td->eviction_flags);
826
0
    }
827
0
    if (td->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
828
0
        struct ofp14_table_mod_prop_vacancy *otv;
829
830
0
        otv = ofpprop_put_zeros(reply, OFPTMPT14_VACANCY, sizeof *otv);
831
0
        otv->vacancy_down = td->table_vacancy.vacancy_down;
832
0
        otv->vacancy_up = td->table_vacancy.vacancy_up;
833
0
        otv->vacancy = td->table_vacancy.vacancy;
834
0
    }
835
836
0
    otd = ofpbuf_at_assert(reply, start_otd, sizeof *otd);
837
0
    otd->length = htons(reply->size - start_otd);
838
0
    otd->table_id = td->table_id;
839
0
    otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT,
840
0
                                              td->eviction, td->vacancy,
841
0
                                              version);
842
0
    ofpmp_postappend(replies, start_otd);
843
0
}
844
845
static const char *
846
ofputil_eviction_flag_to_string(uint32_t bit)
847
11.3k
{
848
11.3k
    enum ofp14_table_mod_prop_eviction_flag eviction_flag = bit;
849
850
11.3k
    switch (eviction_flag) {
851
703
    case OFPTMPEF14_OTHER:      return "OTHER";
852
710
    case OFPTMPEF14_IMPORTANCE: return "IMPORTANCE";
853
136
    case OFPTMPEF14_LIFETIME:   return "LIFETIME";
854
11.3k
    }
855
856
9.78k
    return NULL;
857
11.3k
}
858
859
/* Appends to 'string' a description of the bitmap of OFPTMPEF14_* values in
860
 * 'eviction_flags'. */
861
static void
862
ofputil_put_eviction_flags(struct ds *string, uint32_t eviction_flags)
863
3.72k
{
864
3.72k
    if (eviction_flags != UINT32_MAX) {
865
1.18k
        ofp_print_bit_names(string, eviction_flags,
866
1.18k
                            ofputil_eviction_flag_to_string, '|');
867
2.53k
    } else {
868
2.53k
        ds_put_cstr(string, "(default)");
869
2.53k
    }
870
3.72k
}
871
872
void
873
ofputil_table_desc_format(struct ds *s, const struct ofputil_table_desc *td,
874
                          const struct ofputil_table_map *table_map)
875
3.72k
{
876
3.72k
    ds_put_format(s, "\n  table ");
877
3.72k
    ofputil_format_table(td->table_id, table_map, s);
878
3.72k
    ds_put_cstr(s, ":\n");
879
3.72k
    ds_put_format(s, "   eviction=%s eviction_flags=",
880
3.72k
                  ofputil_table_eviction_to_string(td->eviction));
881
3.72k
    ofputil_put_eviction_flags(s, td->eviction_flags);
882
3.72k
    ds_put_char(s, '\n');
883
3.72k
    ds_put_format(s, "   vacancy=%s",
884
3.72k
                  ofputil_table_vacancy_to_string(td->vacancy));
885
3.72k
    if (td->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
886
1.78k
        ds_put_format(s, " vacancy_down=%"PRIu8"%%",
887
1.78k
                      td->table_vacancy.vacancy_down);
888
1.78k
        ds_put_format(s, " vacancy_up=%"PRIu8"%%",
889
1.78k
                      td->table_vacancy.vacancy_up);
890
1.78k
        ds_put_format(s, " vacancy=%"PRIu8"%%",
891
1.78k
                      td->table_vacancy.vacancy);
892
1.78k
    }
893
3.72k
    ds_put_char(s, '\n');
894
3.72k
}
895
896
/* This function parses Vacancy property, and decodes the
897
 * ofp14_table_mod_prop_vacancy in ofputil_table_mod.
898
 * Returns OFPERR_OFPBPC_BAD_VALUE error code when vacancy_down is
899
 * greater than vacancy_up and also when current vacancy has non-zero
900
 * value. Returns 0 on success. */
901
static enum ofperr
902
parse_table_mod_vacancy_property(struct ofpbuf *property,
903
                                 struct ofputil_table_mod *tm)
904
682
{
905
682
    struct ofp14_table_mod_prop_vacancy *otv = property->data;
906
907
682
    if (property->size != sizeof *otv) {
908
35
        return OFPERR_OFPBPC_BAD_LEN;
909
35
    }
910
647
    tm->table_vacancy.vacancy_down = otv->vacancy_down;
911
647
    tm->table_vacancy.vacancy_up = otv->vacancy_up;
912
647
    if (tm->table_vacancy.vacancy_down > tm->table_vacancy.vacancy_up) {
913
152
        OFPPROP_LOG(&rl, false,
914
152
                    "Value of vacancy_down is greater than vacancy_up");
915
152
        return OFPERR_OFPBPC_BAD_VALUE;
916
152
    }
917
495
    if (tm->table_vacancy.vacancy_down > 100 ||
918
495
        tm->table_vacancy.vacancy_up > 100) {
919
424
        OFPPROP_LOG(&rl, false, "Vacancy threshold percentage "
920
424
                    "should not be greater than 100");
921
424
        return OFPERR_OFPBPC_BAD_VALUE;
922
424
    }
923
71
    tm->table_vacancy.vacancy = otv->vacancy;
924
71
    if (tm->table_vacancy.vacancy) {
925
37
        OFPPROP_LOG(&rl, false,
926
37
                    "Vacancy value should be zero for table-mod messages");
927
37
        return OFPERR_OFPBPC_BAD_VALUE;
928
37
    }
929
34
    return 0;
930
71
}
931
932
/* Given 'config', taken from an OpenFlow 'version' message that specifies
933
 * table configuration (a table mod, table stats, or table features message),
934
 * returns the table vacancy configuration that it specifies.
935
 *
936
 * Only OpenFlow 1.4 and later specify table vacancy configuration this way,
937
 * so for other 'version' this function always returns
938
 * OFPUTIL_TABLE_VACANCY_DEFAULT. */
939
static enum ofputil_table_vacancy
940
ofputil_decode_table_vacancy(ovs_be32 config, enum ofp_version version)
941
7.29k
{
942
7.29k
    return (version < OFP14_VERSION ? OFPUTIL_TABLE_VACANCY_DEFAULT
943
7.29k
            : config & htonl(OFPTC14_VACANCY_EVENTS) ? OFPUTIL_TABLE_VACANCY_ON
944
7.29k
            : OFPUTIL_TABLE_VACANCY_OFF);
945
7.29k
}
946
947
/* Given 'config', taken from an OpenFlow 'version' message that specifies
948
 * table configuration (a table mod, table stats, or table features message),
949
 * returns the table eviction configuration that it specifies.
950
 *
951
 * Only OpenFlow 1.4 and later specify table eviction configuration this way,
952
 * so for other 'version' values this function always returns
953
 * OFPUTIL_TABLE_EVICTION_DEFAULT. */
954
static enum ofputil_table_eviction
955
ofputil_decode_table_eviction(ovs_be32 config, enum ofp_version version)
956
7.29k
{
957
7.29k
    return (version < OFP14_VERSION ? OFPUTIL_TABLE_EVICTION_DEFAULT
958
7.29k
            : config & htonl(OFPTC14_EVICTION) ? OFPUTIL_TABLE_EVICTION_ON
959
7.29k
            : OFPUTIL_TABLE_EVICTION_OFF);
960
7.29k
}
961
962
/* Returns a bitmap of OFPTC* values suitable for 'config' fields in various
963
 * OpenFlow messages of the given 'version', based on the provided 'miss' and
964
 * 'eviction' values. */
965
static ovs_be32
966
ofputil_encode_table_config(enum ofputil_table_miss miss,
967
                            enum ofputil_table_eviction eviction,
968
                            enum ofputil_table_vacancy vacancy,
969
                            enum ofp_version version)
970
0
{
971
0
    uint32_t config = 0;
972
    /* Search for "OFPTC_* Table Configuration" in the documentation for more
973
     * information on the crazy evolution of this field. */
974
0
    switch (version) {
975
0
    case OFP10_VERSION:
976
        /* OpenFlow 1.0 didn't have such a field, any value ought to do. */
977
0
        return htonl(0);
978
979
0
    case OFP11_VERSION:
980
0
    case OFP12_VERSION:
981
        /* OpenFlow 1.1 and 1.2 define only OFPTC11_TABLE_MISS_*. */
982
0
        switch (miss) {
983
0
        case OFPUTIL_TABLE_MISS_DEFAULT:
984
            /* Really this shouldn't be used for encoding (the caller should
985
             * provide a specific value) but I can't imagine that defaulting to
986
             * the fall-through case here will hurt. */
987
0
        case OFPUTIL_TABLE_MISS_CONTROLLER:
988
0
        default:
989
0
            return htonl(OFPTC11_TABLE_MISS_CONTROLLER);
990
0
        case OFPUTIL_TABLE_MISS_CONTINUE:
991
0
            return htonl(OFPTC11_TABLE_MISS_CONTINUE);
992
0
        case OFPUTIL_TABLE_MISS_DROP:
993
0
            return htonl(OFPTC11_TABLE_MISS_DROP);
994
0
        }
995
0
        OVS_NOT_REACHED();
996
997
0
    case OFP13_VERSION:
998
        /* OpenFlow 1.3 removed OFPTC11_TABLE_MISS_* and didn't define any new
999
         * flags, so this is correct. */
1000
0
        return htonl(0);
1001
1002
0
    case OFP14_VERSION:
1003
0
    case OFP15_VERSION:
1004
        /* OpenFlow 1.4 introduced OFPTC14_EVICTION and
1005
         * OFPTC14_VACANCY_EVENTS. */
1006
0
        if (eviction == OFPUTIL_TABLE_EVICTION_ON) {
1007
0
            config |= OFPTC14_EVICTION;
1008
0
        }
1009
0
        if (vacancy == OFPUTIL_TABLE_VACANCY_ON) {
1010
0
            config |= OFPTC14_VACANCY_EVENTS;
1011
0
        }
1012
0
        return htonl(config);
1013
0
    }
1014
1015
0
    OVS_NOT_REACHED();
1016
0
}
1017
1018
/* Given 'config', taken from an OpenFlow 'version' message that specifies
1019
 * table configuration (a table mod, table stats, or table features message),
1020
 * returns the table miss configuration that it specifies.
1021
 *
1022
 * Only OpenFlow 1.1 and 1.2 specify table miss configurations this way, so for
1023
 * other 'version' values this function always returns
1024
 * OFPUTIL_TABLE_MISS_DEFAULT. */
1025
static enum ofputil_table_miss
1026
ofputil_decode_table_miss(ovs_be32 config_, enum ofp_version version)
1027
24.0k
{
1028
24.0k
    uint32_t config = ntohl(config_);
1029
1030
24.0k
    if (version == OFP11_VERSION || version == OFP12_VERSION) {
1031
21.1k
        switch (config & OFPTC11_TABLE_MISS_MASK) {
1032
12.4k
        case OFPTC11_TABLE_MISS_CONTROLLER:
1033
12.4k
            return OFPUTIL_TABLE_MISS_CONTROLLER;
1034
1035
2.57k
        case OFPTC11_TABLE_MISS_CONTINUE:
1036
2.57k
            return OFPUTIL_TABLE_MISS_CONTINUE;
1037
1038
2.12k
        case OFPTC11_TABLE_MISS_DROP:
1039
2.12k
            return OFPUTIL_TABLE_MISS_DROP;
1040
1041
3.99k
        default:
1042
3.99k
            VLOG_WARN_RL(&rl, "bad table miss config %d", config);
1043
3.99k
            return OFPUTIL_TABLE_MISS_CONTROLLER;
1044
21.1k
        }
1045
21.1k
    } else {
1046
2.89k
        return OFPUTIL_TABLE_MISS_DEFAULT;
1047
2.89k
    }
1048
24.0k
}
1049
1050
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
1051
 * '*pm'.  Returns 0 if successful, otherwise an OFPERR_* value. */
1052
enum ofperr
1053
ofputil_decode_table_mod(const struct ofp_header *oh,
1054
                         struct ofputil_table_mod *pm)
1055
4.30k
{
1056
4.30k
    memset(pm, 0, sizeof *pm);
1057
4.30k
    pm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
1058
4.30k
    pm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
1059
4.30k
    pm->eviction_flags = UINT32_MAX;
1060
4.30k
    pm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
1061
1062
4.30k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1063
4.30k
    enum ofpraw raw = ofpraw_pull_assert(&b);
1064
4.30k
    if (raw == OFPRAW_OFPT11_TABLE_MOD) {
1065
1.42k
        const struct ofp11_table_mod *otm = b.data;
1066
1067
1.42k
        pm->table_id = otm->table_id;
1068
1.42k
        pm->miss = ofputil_decode_table_miss(otm->config, oh->version);
1069
2.87k
    } else if (raw == OFPRAW_OFPT14_TABLE_MOD) {
1070
2.87k
        const struct ofp14_table_mod *otm = ofpbuf_pull(&b, sizeof *otm);
1071
1072
2.87k
        pm->table_id = otm->table_id;
1073
2.87k
        pm->miss = ofputil_decode_table_miss(otm->config, oh->version);
1074
2.87k
        pm->eviction = ofputil_decode_table_eviction(otm->config, oh->version);
1075
2.87k
        pm->vacancy = ofputil_decode_table_vacancy(otm->config, oh->version);
1076
3.19k
        while (b.size > 0) {
1077
1.55k
            struct ofpbuf property;
1078
1.55k
            enum ofperr error;
1079
1.55k
            uint64_t type;
1080
1081
1.55k
            error = ofpprop_pull(&b, &property, &type);
1082
1.55k
            if (error) {
1083
452
                return error;
1084
452
            }
1085
1086
1.10k
            switch (type) {
1087
323
            case OFPTMPT14_EVICTION:
1088
323
                error = ofpprop_parse_u32(&property, &pm->eviction);
1089
323
                break;
1090
1091
682
            case OFPTMPT14_VACANCY:
1092
682
                error = parse_table_mod_vacancy_property(&property, pm);
1093
682
                break;
1094
1095
95
            default:
1096
95
                error = OFPERR_OFPBRC_BAD_TYPE;
1097
95
                break;
1098
1.10k
            }
1099
1100
1.10k
            if (error) {
1101
779
                return error;
1102
779
            }
1103
1.10k
        }
1104
2.87k
    } else {
1105
0
        return OFPERR_OFPBRC_BAD_TYPE;
1106
0
    }
1107
1108
3.06k
    return 0;
1109
4.30k
}
1110
1111
/* Converts the abstract form of a "table mod" message in '*tm' into an
1112
 * OpenFlow message suitable for 'protocol', and returns that encoded form in a
1113
 * buffer owned by the caller. */
1114
struct ofpbuf *
1115
ofputil_encode_table_mod(const struct ofputil_table_mod *tm,
1116
                        enum ofputil_protocol protocol)
1117
0
{
1118
0
    enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
1119
0
    struct ofpbuf *b;
1120
1121
0
    switch (ofp_version) {
1122
0
    case OFP10_VERSION: {
1123
0
        ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
1124
0
                     "(\'-O OpenFlow11\')");
1125
0
        break;
1126
0
    }
1127
0
    case OFP11_VERSION:
1128
0
    case OFP12_VERSION:
1129
0
    case OFP13_VERSION: {
1130
0
        struct ofp11_table_mod *otm;
1131
1132
0
        b = ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD, ofp_version, 0);
1133
0
        otm = ofpbuf_put_zeros(b, sizeof *otm);
1134
0
        otm->table_id = tm->table_id;
1135
0
        otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
1136
0
                                                  tm->vacancy, ofp_version);
1137
0
        break;
1138
0
    }
1139
0
    case OFP14_VERSION:
1140
0
    case OFP15_VERSION: {
1141
0
        struct ofp14_table_mod *otm;
1142
1143
0
        b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
1144
0
        otm = ofpbuf_put_zeros(b, sizeof *otm);
1145
0
        otm->table_id = tm->table_id;
1146
0
        otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
1147
0
                                                  tm->vacancy, ofp_version);
1148
1149
0
        if (tm->eviction_flags != UINT32_MAX) {
1150
0
            ofpprop_put_u32(b, OFPTMPT14_EVICTION, tm->eviction_flags);
1151
0
        }
1152
0
        if (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
1153
0
            struct ofp14_table_mod_prop_vacancy *otv;
1154
1155
0
            otv = ofpprop_put_zeros(b, OFPTMPT14_VACANCY, sizeof *otv);
1156
0
            otv->vacancy_down = tm->table_vacancy.vacancy_down;
1157
0
            otv->vacancy_up = tm->table_vacancy.vacancy_up;
1158
0
        }
1159
0
        break;
1160
0
    }
1161
0
    default:
1162
0
        OVS_NOT_REACHED();
1163
0
    }
1164
1165
0
    return b;
1166
0
}
1167
1168
void
1169
ofputil_table_mod_format(struct ds *s, const struct ofputil_table_mod *tm,
1170
                         const struct ofputil_table_map *table_map)
1171
3.06k
{
1172
3.06k
    if (tm->table_id == 0xff) {
1173
997
        ds_put_cstr(s, " table_id: ALL_TABLES");
1174
2.07k
    } else {
1175
2.07k
        ds_put_format(s, " table_id=");
1176
2.07k
        ofputil_format_table(tm->table_id, table_map, s);
1177
2.07k
    }
1178
1179
3.06k
    if (tm->miss != OFPUTIL_TABLE_MISS_DEFAULT) {
1180
1.40k
        ds_put_format(s, ", flow_miss_config=%s",
1181
1.40k
                      ofputil_table_miss_to_string(tm->miss));
1182
1.40k
    }
1183
3.06k
    if (tm->eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) {
1184
1.64k
        ds_put_format(s, ", eviction=%s",
1185
1.64k
                      ofputil_table_eviction_to_string(tm->eviction));
1186
1.64k
    }
1187
3.06k
    if (tm->eviction_flags != UINT32_MAX) {
1188
0
        ds_put_cstr(s, "eviction_flags=");
1189
0
        ofputil_put_eviction_flags(s, tm->eviction_flags);
1190
0
    }
1191
3.06k
    if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
1192
1.64k
        ds_put_format(s, ", vacancy=%s",
1193
1.64k
                      ofputil_table_vacancy_to_string(tm->vacancy));
1194
1.64k
        if (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
1195
622
            ds_put_format(s, " vacancy:%"PRIu8""
1196
622
                          ",%"PRIu8"", tm->table_vacancy.vacancy_down,
1197
622
                          tm->table_vacancy.vacancy_up);
1198
622
        }
1199
1.64k
    }
1200
3.06k
}
1201
1202
/* Convert 'setting' (as described for the "mod-table" command
1203
 * in ovs-ofctl man page) into 'tm->table_vacancy->vacancy_up' and
1204
 * 'tm->table_vacancy->vacancy_down' threshold values.
1205
 * For the two threshold values, value of vacancy_up is always greater
1206
 * than value of vacancy_down.
1207
 *
1208
 * Returns NULL if successful, otherwise a malloc()'d string describing the
1209
 * error.  The caller is responsible for freeing the returned string. */
1210
static char * OVS_WARN_UNUSED_RESULT
1211
parse_ofp_table_vacancy(struct ofputil_table_mod *tm, const char *setting)
1212
0
{
1213
0
    char *save_ptr = NULL;
1214
0
    char *vac_up, *vac_down;
1215
0
    char *value = xstrdup(setting);
1216
0
    char *ret_msg;
1217
0
    int vacancy_up, vacancy_down;
1218
1219
0
    strtok_r(value, ":", &save_ptr);
1220
0
    vac_down = strtok_r(NULL, ",", &save_ptr);
1221
0
    if (!vac_down) {
1222
0
        ret_msg = xasprintf("Vacancy down value missing");
1223
0
        goto exit;
1224
0
    }
1225
0
    if (!str_to_int(vac_down, 0, &vacancy_down) ||
1226
0
        vacancy_down < 0 || vacancy_down > 100) {
1227
0
        ret_msg = xasprintf("Invalid vacancy down value \"%s\"", vac_down);
1228
0
        goto exit;
1229
0
    }
1230
0
    vac_up = strtok_r(NULL, ",", &save_ptr);
1231
0
    if (!vac_up) {
1232
0
        ret_msg = xasprintf("Vacancy up value missing");
1233
0
        goto exit;
1234
0
    }
1235
0
    if (!str_to_int(vac_up, 0, &vacancy_up) ||
1236
0
        vacancy_up < 0 || vacancy_up > 100) {
1237
0
        ret_msg = xasprintf("Invalid vacancy up value \"%s\"", vac_up);
1238
0
        goto exit;
1239
0
    }
1240
0
    if (vacancy_down > vacancy_up) {
1241
0
        ret_msg = xasprintf("Invalid vacancy range, vacancy up should be "
1242
0
                            "greater than vacancy down (%s)",
1243
0
                            ofperr_to_string(OFPERR_OFPBPC_BAD_VALUE));
1244
0
        goto exit;
1245
0
    }
1246
1247
0
    free(value);
1248
0
    tm->table_vacancy.vacancy_down = vacancy_down;
1249
0
    tm->table_vacancy.vacancy_up = vacancy_up;
1250
0
    return NULL;
1251
1252
0
exit:
1253
0
    free(value);
1254
0
    return ret_msg;
1255
0
}
1256
1257
/* Convert 'table_id' and 'setting' (as described for the "mod-table" command
1258
 * in the ovs-ofctl man page) into 'tm' for sending a table_mod command to a
1259
 * switch.  If 'setting' sets the name of the table, puts the new name in
1260
 * '*namep' (a suffix of 'setting'), otherwise stores NULL.
1261
 *
1262
 * Stores a bitmap of the OpenFlow versions that are usable for 'tm' into
1263
 * '*usable_versions'.
1264
 *
1265
 * Returns NULL if successful, otherwise a malloc()'d string describing the
1266
 * error.  The caller is responsible for freeing the returned string. */
1267
char * OVS_WARN_UNUSED_RESULT
1268
parse_ofp_table_mod(struct ofputil_table_mod *tm, const char **namep,
1269
                    const char *table_id, const char *setting,
1270
                    const struct ofputil_table_map *table_map,
1271
                    uint32_t *usable_versions)
1272
0
{
1273
0
    *usable_versions = 0;
1274
0
    *namep = NULL;
1275
0
    if (!strcasecmp(table_id, "all")) {
1276
0
        tm->table_id = OFPTT_ALL;
1277
0
    } else if (!ofputil_table_from_string(table_id, table_map,
1278
0
                                          &tm->table_id)) {
1279
0
        return xasprintf("unknown table \"%s\"", table_id);
1280
0
    }
1281
1282
0
    tm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
1283
0
    tm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
1284
0
    tm->eviction_flags = UINT32_MAX;
1285
0
    tm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
1286
0
    tm->table_vacancy.vacancy_down = 0;
1287
0
    tm->table_vacancy.vacancy_up = 0;
1288
0
    tm->table_vacancy.vacancy = 0;
1289
    /* Only OpenFlow 1.1 and 1.2 can configure table-miss via table_mod.
1290
     * Only OpenFlow 1.4+ can configure eviction and vacancy events
1291
     * via table_mod.
1292
     */
1293
0
    if (!strcmp(setting, "controller")) {
1294
0
        tm->miss = OFPUTIL_TABLE_MISS_CONTROLLER;
1295
0
        *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
1296
0
    } else if (!strcmp(setting, "continue")) {
1297
0
        tm->miss = OFPUTIL_TABLE_MISS_CONTINUE;
1298
0
        *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
1299
0
    } else if (!strcmp(setting, "drop")) {
1300
0
        tm->miss = OFPUTIL_TABLE_MISS_DROP;
1301
0
        *usable_versions = (1u << OFP11_VERSION) | (1u << OFP12_VERSION);
1302
0
    } else if (!strcmp(setting, "evict")) {
1303
0
        tm->eviction = OFPUTIL_TABLE_EVICTION_ON;
1304
0
        *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
1305
0
    } else if (!strcmp(setting, "noevict")) {
1306
0
        tm->eviction = OFPUTIL_TABLE_EVICTION_OFF;
1307
0
        *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
1308
0
    } else if (!strncmp(setting, "vacancy", strcspn(setting, ":"))) {
1309
0
        tm->vacancy = OFPUTIL_TABLE_VACANCY_ON;
1310
0
        *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
1311
0
        char *error = parse_ofp_table_vacancy(tm, setting);
1312
0
        if (error) {
1313
0
            return error;
1314
0
        }
1315
0
    } else if (!strcmp(setting, "novacancy")) {
1316
0
        tm->vacancy = OFPUTIL_TABLE_VACANCY_OFF;
1317
0
        *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
1318
0
    } else if (tm->table_id != OFPTT_ALL && !strncmp(setting, "name:", 5)) {
1319
0
        *namep = setting + 5;
1320
0
        *usable_versions = ((1 << OFP13_VERSION) | (1u << OFP14_VERSION)
1321
0
                            | (1u << OFP15_VERSION));
1322
0
    } else {
1323
0
        return xasprintf("invalid table_mod setting %s", setting);
1324
0
    }
1325
1326
0
    if (tm->table_id == 0xfe
1327
0
        && tm->miss == OFPUTIL_TABLE_MISS_CONTINUE) {
1328
0
        return xstrdup("last table's flow miss handling can not be continue");
1329
0
    }
1330
1331
0
    return NULL;
1332
0
}
1333
1334
/* Returns true if 's' consists of only ASCII digits (and at least one). */
1335
static bool
1336
is_all_digits(const char *s)
1337
348k
{
1338
348k
    return s[0] && s[strspn(s, "0123456789")] == '\0';
1339
348k
}
1340
1341
/* Returns true if 'a' and 'b' are the same except 'b' ends in a number one
1342
 * larger than 'a', for example, "reg0" and "reg1" */
1343
static bool
1344
are_names_sequential(const char *a, const char *b)
1345
348k
{
1346
    /* Skip common prefix. */
1347
1.30M
    for (; *a == *b; a++, b++) {
1348
959k
        if (!*a) {
1349
            /* 'a' and 'b' are the same.  Weird, but not sequential. */
1350
0
            return false;
1351
0
        }
1352
959k
    }
1353
1354
348k
    return (is_all_digits(a)
1355
348k
            && is_all_digits(b)
1356
348k
            && strlen(a) < 10
1357
348k
            && strlen(b) < 10
1358
348k
            && atoi(a) + 1 == atoi(b));
1359
348k
}
1360
1361
/* Returns the number of sequential names at the start of the 'n' strings in
1362
 * 'ids'.  Returns at least 1 (if 'n' > 0). */
1363
static size_t
1364
count_sequential_suffix_run(const char *ids[], size_t n)
1365
473k
{
1366
473k
    for (size_t i = 1; ; i++) {
1367
473k
        if (i >= n || !are_names_sequential(ids[i - 1], ids[i])) {
1368
            /* "x0...x1" is worse than "x0 x1", so suppress it. */
1369
473k
            return i == 2 ? 1 : i;
1370
473k
        }
1371
473k
    }
1372
473k
}
1373
1374
/* Counts the length of the longest common prefix (that ends in "_") between
1375
 * strings 'a' and 'b'.  Returns 0 if they have no common prefix. */
1376
static size_t
1377
count_common_prefix(const char *a, const char *b)
1378
454k
{
1379
454k
    size_t retval = 0;
1380
1.03M
    for (size_t i = 0; ; i++) {
1381
1.03M
        if (a[i] != b[i] || !a[i]) {
1382
454k
            return retval;
1383
578k
        } else if (a[i] == '_') {
1384
122k
            retval = i + 1;
1385
122k
        }
1386
1.03M
    }
1387
454k
}
1388
1389
/* Returns the number of strings in the longest run of strings with a common
1390
 * prefix (that ends in "_") at the beginning of the 'n' strings in 'ids'.
1391
 * This is at least 1, if 'n' > 0.  All the strings are already known to have a
1392
 * common prefix of length 'prefix_len', so that's not of interest; only an
1393
 * additional common prefix is interesting.
1394
 *
1395
 * If this returns 'n' > 1, then '*extra_prefix_lenp' receives the length of
1396
 * the additional common prefix.  Otherwise '*extra_prefix_lenp' receives 0. */
1397
static size_t
1398
count_common_prefix_run(const char *ids[], size_t n,
1399
                        size_t prefix_len, size_t *extra_prefix_lenp)
1400
473k
{
1401
473k
    *extra_prefix_lenp = 0;
1402
473k
    if (n < 2) {
1403
125k
        return n;
1404
125k
    }
1405
1406
348k
    size_t extra_prefix_len = count_common_prefix(ids[0] + prefix_len,
1407
348k
                                                  ids[1] + prefix_len);
1408
348k
    if (!extra_prefix_len) {
1409
253k
        return 1;
1410
253k
    }
1411
1412
94.7k
    size_t i = 2;
1413
122k
    while (i < n) {
1414
106k
        size_t next = count_common_prefix(ids[0] + prefix_len,
1415
106k
                                          ids[i] + prefix_len);
1416
106k
        if (!next) {
1417
78.8k
            break;
1418
78.8k
        } else if (next < extra_prefix_len) {
1419
0
            extra_prefix_len = next;
1420
0
        }
1421
27.3k
        i++;
1422
27.3k
    }
1423
94.7k
    *extra_prefix_lenp = extra_prefix_len;
1424
94.7k
    return i;
1425
348k
}
1426
1427
/* Appends the 'n' names in 'ids' to 's', omitting the first 'prefix_len' bytes
1428
 * of each name (which should all be the same), separating them from each other
1429
 * with spaces.
1430
 *
1431
 * Two kinds of abbreviation are implemented:
1432
 *
1433
 *     - Common prefixes: "eth_src eth_dst eth_type" => "eth_{src,dst,type}".
1434
 *
1435
 *     - Sequential suffixes: "reg0 reg1 reg2 reg3" => "reg0...reg3".
1436
 */
1437
static void
1438
print_names(struct ds *s, const char *ids[], size_t n, size_t prefix_len)
1439
141k
{
1440
141k
    int group = 0;
1441
614k
    while (n > 0) {
1442
473k
        if (group++) {
1443
332k
            ds_put_char(s, prefix_len ? ',' : ' ');
1444
332k
        }
1445
1446
        /* Count the prefix and suffix runs at the beginning of 'ids'.  As of
1447
         * this writing we don't have any sequentially numbered fields whose
1448
         * names contain "_", so we should only have one or the other at a
1449
         * time.  However, if we end up with something like "a_0 a_1 a_2"
1450
         * someday, we want to render it as a_0...a_2, not as a_{0...2}, so
1451
         * given equal suffix and prefix runs, prefer the suffix. */
1452
473k
        size_t extra_prefix_len;
1453
473k
        size_t prefix_run = count_common_prefix_run(ids, n, prefix_len,
1454
473k
                                                    &extra_prefix_len);
1455
473k
        size_t suffix_run = count_sequential_suffix_run(ids, n);
1456
473k
        size_t run = MAX(prefix_run, suffix_run);
1457
473k
        if (suffix_run >= prefix_run) {
1458
378k
            ds_put_format(s, "%s", ids[0] + prefix_len);
1459
378k
            if (run > 1) {
1460
0
                ds_put_format(s, "...%s", ids[run - 1] + prefix_len);
1461
0
            }
1462
378k
        } else {
1463
94.7k
            ds_put_format(s, "%.*s{", (int) extra_prefix_len,
1464
94.7k
                          ids[0] + prefix_len);
1465
94.7k
            print_names(s, ids, run, prefix_len + extra_prefix_len);
1466
94.7k
            ds_put_char(s, '}');
1467
94.7k
        }
1468
1469
473k
        ids += run;
1470
473k
        n -= run;
1471
473k
    }
1472
141k
}
1473
1474
static void
1475
print_mf_bitmap(struct ds *s, const struct mf_bitmap *mfb)
1476
46.4k
{
1477
46.4k
    const char *ids[MFF_N_IDS];
1478
46.4k
    size_t n = 0;
1479
1480
46.4k
    int i;
1481
378k
    BITMAP_FOR_EACH_1 (i, MFF_N_IDS, mfb->bm) {
1482
378k
        ids[n++] = mf_from_id(i)->name;
1483
378k
    }
1484
1485
46.4k
    if (n > 0) {
1486
46.4k
        ds_put_char(s, ' ');
1487
46.4k
        print_names(s, ids, n, 0);
1488
46.4k
    }
1489
46.4k
}
1490
1491
static void
1492
print_table_action_features(struct ds *s,
1493
                            const struct ofputil_table_action_features *taf)
1494
25.9k
{
1495
25.9k
    if (taf->ofpacts) {
1496
19.3k
        ds_put_cstr(s, "        actions: ");
1497
19.3k
        ofpact_bitmap_format(taf->ofpacts, s);
1498
19.3k
        ds_put_char(s, '\n');
1499
19.3k
    }
1500
1501
25.9k
    if (!bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS)) {
1502
18.6k
        ds_put_cstr(s, "        supported on Set-Field:");
1503
18.6k
        print_mf_bitmap(s, &taf->set_fields);
1504
18.6k
        ds_put_char(s, '\n');
1505
18.6k
    }
1506
25.9k
}
1507
1508
static bool
1509
table_action_features_equal(const struct ofputil_table_action_features *a,
1510
                            const struct ofputil_table_action_features *b)
1511
125k
{
1512
125k
    return (a->ofpacts == b->ofpacts
1513
125k
            && bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS));
1514
125k
}
1515
1516
static bool
1517
table_action_features_empty(const struct ofputil_table_action_features *taf)
1518
31.1k
{
1519
31.1k
    return !taf->ofpacts && bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS);
1520
31.1k
}
1521
1522
static void
1523
print_table_instruction_features(
1524
    struct ds *s,
1525
    const struct ofputil_table_instruction_features *tif,
1526
    const struct ofputil_table_instruction_features *prev_tif)
1527
16.8k
{
1528
16.8k
    int start, end;
1529
1530
16.8k
    if (!bitmap_is_all_zeros(tif->next, 255)) {
1531
0
        ds_put_cstr(s, "      next tables: ");
1532
0
        for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255;
1533
0
             start = bitmap_scan(tif->next, 1, end, 255)) {
1534
0
            end = bitmap_scan(tif->next, 0, start + 1, 255);
1535
0
            if (end == start + 1) {
1536
0
                ds_put_format(s, "%d,", start);
1537
0
            } else {
1538
0
                ds_put_format(s, "%d-%d,", start, end - 1);
1539
0
            }
1540
0
        }
1541
0
        ds_chomp(s, ',');
1542
0
        if (ds_last(s) == ' ') {
1543
0
            ds_put_cstr(s, "none");
1544
0
        }
1545
0
        ds_put_char(s, '\n');
1546
0
    }
1547
1548
16.8k
    if (tif->instructions) {
1549
10.6k
        if (prev_tif && tif->instructions == prev_tif->instructions) {
1550
2.65k
            ds_put_cstr(s, "      (same instructions)\n");
1551
8.00k
        } else {
1552
8.00k
            ds_put_cstr(s, "      instructions: ");
1553
8.00k
            int i;
1554
1555
264k
            for (i = 0; i < 32; i++) {
1556
256k
                if (tif->instructions & (1u << i)) {
1557
20.8k
                    const char *name = ovs_instruction_name_from_type(i);
1558
20.8k
                    if (name) {
1559
20.8k
                        ds_put_cstr(s, name);
1560
20.8k
                    } else {
1561
0
                        ds_put_format(s, "%d", i);
1562
0
                    }
1563
20.8k
                    ds_put_char(s, ' ');
1564
20.8k
                }
1565
256k
            }
1566
8.00k
            ds_chomp(s, ' ');
1567
8.00k
            ds_put_char(s, '\n');
1568
8.00k
        }
1569
10.6k
    }
1570
1571
16.8k
    if (prev_tif
1572
16.8k
        && table_action_features_equal(&tif->write, &prev_tif->write)
1573
16.8k
        && table_action_features_equal(&tif->apply, &prev_tif->apply)
1574
16.8k
        && !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
1575
804
        ds_put_cstr(s, "      (same actions)\n");
1576
16.0k
    } else if (!table_action_features_equal(&tif->write, &tif->apply)) {
1577
10.5k
        ds_put_cstr(s, "      Write-Actions features:\n");
1578
10.5k
        print_table_action_features(s, &tif->write);
1579
10.5k
        ds_put_cstr(s, "      Apply-Actions features:\n");
1580
10.5k
        print_table_action_features(s, &tif->apply);
1581
10.5k
    } else if (tif->write.ofpacts
1582
5.51k
               || !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
1583
4.92k
        ds_put_cstr(s, "      Write-Actions and Apply-Actions features:\n");
1584
4.92k
        print_table_action_features(s, &tif->write);
1585
4.92k
    }
1586
16.8k
}
1587
1588
static void
1589
print_matches(struct ds *s, const struct ofputil_table_features *f,
1590
              bool mask, bool wc, const char *title)
1591
55.9k
{
1592
55.9k
    const struct mf_bitmap m = mask ? f->mask : mf_bitmap_not(f->mask);
1593
55.9k
    const struct mf_bitmap w = wc ? f->wildcard : mf_bitmap_not(f->wildcard);
1594
55.9k
    const struct mf_bitmap bm = mf_bitmap_and(f->match, mf_bitmap_and(m, w));
1595
1596
55.9k
    if (!bitmap_is_all_zeros(bm.bm, MFF_N_IDS)) {
1597
27.8k
        ds_put_format(s, "      %s:", title);
1598
27.8k
        print_mf_bitmap(s, &bm);
1599
27.8k
        ds_put_char(s, '\n');
1600
27.8k
    }
1601
55.9k
}
1602
1603
/* Compares bitmaps of next tables 'a' and 'b', for tables 'a_table_id' and
1604
 * 'b_table_id', respectively.  Returns true if the bitmaps are equal.
1605
 *
1606
 * The bitmaps are considered equal if b_table_id == a_table_id + 1 and the bit
1607
 * for 'b_table_id' is set in 'a' but not in 'b'.  This is because OpenFlow
1608
 * requires that a table not be able to do a goto_table back to its own table
1609
 * or an earlier one.  Without considering these equivalent, every table will
1610
 * be different from every one in some way, which just isn't useful in printing
1611
 * table features. */
1612
static bool
1613
table_instruction_features_next_equal(const unsigned long *a, int a_table_id,
1614
                                      const unsigned long *b, int b_table_id)
1615
58.7k
{
1616
58.7k
    if (b_table_id == a_table_id + 1
1617
58.7k
        && bitmap_is_set(a, b_table_id)
1618
58.7k
        && !bitmap_is_set(b, b_table_id)) {
1619
0
        for (size_t i = 0; i < BITMAP_N_LONGS(255); i++) {
1620
0
            unsigned long diff = a[i] ^ b[i];
1621
0
            if (i == b_table_id / BITMAP_ULONG_BITS) {
1622
0
                diff &= ~bitmap_bit__(b_table_id);
1623
0
            }
1624
0
            if (diff) {
1625
0
                return false;
1626
0
            }
1627
0
        }
1628
0
        return true;
1629
58.7k
    } else if (a_table_id == b_table_id + 1) {
1630
719
        return table_instruction_features_next_equal(b, b_table_id,
1631
719
                                                     a, a_table_id);
1632
58.0k
    } else {
1633
58.0k
        return bitmap_equal(a, b, 255);
1634
58.0k
    }
1635
58.7k
}
1636
1637
static bool
1638
table_instruction_features_equal(
1639
    const struct ofputil_table_instruction_features *a, int a_table_id,
1640
    const struct ofputil_table_instruction_features *b, int b_table_id)
1641
58.0k
{
1642
58.0k
    return (table_instruction_features_next_equal(a->next, a_table_id,
1643
58.0k
                                                  b->next, b_table_id)
1644
58.0k
            && a->instructions == b->instructions
1645
58.0k
            && table_action_features_equal(&a->write, &b->write)
1646
58.0k
            && table_action_features_equal(&a->apply, &b->apply));
1647
58.0k
}
1648
1649
static bool
1650
table_instruction_features_empty(
1651
    const struct ofputil_table_instruction_features *tif)
1652
29.8k
{
1653
29.8k
    return (bitmap_is_all_zeros(tif->next, 255)
1654
29.8k
            && !tif->instructions
1655
29.8k
            && table_action_features_empty(&tif->write)
1656
29.8k
            && table_action_features_empty(&tif->apply));
1657
29.8k
}
1658
1659
static bool
1660
table_features_equal(const struct ofputil_table_features *a,
1661
                     const struct ofputil_table_features *b)
1662
25.1k
{
1663
25.1k
    return (a->metadata_match == b->metadata_match
1664
25.1k
            && a->metadata_write == b->metadata_write
1665
25.1k
            && a->miss_config == b->miss_config
1666
25.1k
            && a->supports_eviction == b->supports_eviction
1667
25.1k
            && a->supports_vacancy_events == b->supports_vacancy_events
1668
25.1k
            && a->max_entries == b->max_entries
1669
25.1k
            && table_instruction_features_equal(&a->nonmiss, a->table_id,
1670
6.75k
                                                &b->nonmiss, b->table_id)
1671
25.1k
            && table_instruction_features_equal(&a->miss, a->table_id,
1672
5.23k
                                                &b->miss, b->table_id)
1673
25.1k
            && bitmap_equal(a->match.bm, b->match.bm, MFF_N_IDS));
1674
25.1k
}
1675
1676
static bool
1677
table_features_empty(const struct ofputil_table_features *tf)
1678
3.31k
{
1679
3.31k
    return (!tf->metadata_match
1680
3.31k
            && !tf->metadata_write
1681
3.31k
            && tf->miss_config == OFPUTIL_TABLE_MISS_DEFAULT
1682
3.31k
            && tf->supports_eviction < 0
1683
3.31k
            && tf->supports_vacancy_events < 0
1684
3.31k
            && !tf->max_entries
1685
3.31k
            && table_instruction_features_empty(&tf->nonmiss)
1686
3.31k
            && table_instruction_features_empty(&tf->miss)
1687
3.31k
            && bitmap_is_all_zeros(tf->match.bm, MFF_N_IDS));
1688
3.31k
}
1689
1690
static bool
1691
table_stats_equal(const struct ofputil_table_stats *a,
1692
                  const struct ofputil_table_stats *b)
1693
24.6k
{
1694
24.6k
    return (a->active_count == b->active_count
1695
24.6k
            && a->lookup_count == b->lookup_count
1696
24.6k
            && a->matched_count == b->matched_count);
1697
24.6k
}
1698
1699
void
1700
ofputil_table_features_format(
1701
    struct ds *s,
1702
    const struct ofputil_table_features *features,
1703
    const struct ofputil_table_features *prev_features,
1704
    const struct ofputil_table_stats *stats,
1705
    const struct ofputil_table_stats *prev_stats,
1706
    int *first_ditto, int *last_ditto)
1707
29.9k
{
1708
29.9k
    if (!prev_features && features->command != OFPTFC15_REPLACE) {
1709
176
        ds_put_format(s, "\n  command: %s",
1710
176
                      ofp15_table_features_command_to_string(
1711
176
                          features->command));
1712
176
    }
1713
1714
29.9k
    int table = features->table_id;
1715
29.9k
    int prev_table = prev_features ? prev_features->table_id : 0;
1716
1717
29.9k
    bool same_stats = !stats || (prev_stats
1718
28.6k
                                 && table_stats_equal(stats, prev_stats));
1719
29.9k
    bool same_features = prev_features && table_features_equal(features,
1720
25.1k
                                                               prev_features);
1721
29.9k
    if (same_stats && same_features && !features->name[0]) {
1722
618
        if (*first_ditto < 0) {
1723
255
            *first_ditto = table;
1724
255
        }
1725
618
        *last_ditto = table;
1726
618
        return;
1727
618
    }
1728
29.3k
    ofputil_table_features_format_finish(s, *first_ditto, *last_ditto);
1729
29.3k
    *first_ditto = -1;
1730
1731
29.3k
    ds_put_format(s, "\n  table %d", table);
1732
29.3k
    if (features->name[0]) {
1733
17.4k
        ds_put_format(s, " (\"%s\")", features->name);
1734
17.4k
    }
1735
29.3k
    ds_put_char(s, ':');
1736
1737
29.3k
    if (same_stats && same_features) {
1738
603
        ds_put_cstr(s, " ditto");
1739
603
        return;
1740
603
    }
1741
28.7k
    ds_put_char(s, '\n');
1742
28.7k
    if (stats) {
1743
27.5k
        ds_put_format(s, "    active=%"PRIu32", ", stats->active_count);
1744
27.5k
        ds_put_format(s, "lookup=%"PRIu64", ", stats->lookup_count);
1745
27.5k
        ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count);
1746
27.5k
    }
1747
28.7k
    if (same_features) {
1748
3.31k
        if (!table_features_empty(features)) {
1749
1.33k
            ds_put_cstr(s, "    (same features)\n");
1750
1.33k
        }
1751
3.31k
        return;
1752
3.31k
    }
1753
25.4k
    if (features->metadata_match || features->metadata_write) {
1754
14.3k
        ds_put_format(s, "    metadata: match=%#"PRIx64" write=%#"PRIx64"\n",
1755
14.3k
                      ntohll(features->metadata_match),
1756
14.3k
                      ntohll(features->metadata_write));
1757
14.3k
    }
1758
1759
25.4k
    if (features->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) {
1760
18.9k
        ds_put_format(s, "    config=%s\n",
1761
18.9k
                      ofputil_table_miss_to_string(features->miss_config));
1762
18.9k
    }
1763
1764
25.4k
    if (features->supports_eviction >= 0) {
1765
1.21k
        ds_put_format(s, "    eviction: %ssupported\n",
1766
1.21k
                      features->supports_eviction ? "" : "not ");
1767
1768
1.21k
    }
1769
25.4k
    if (features->supports_vacancy_events >= 0) {
1770
1.21k
        ds_put_format(s, "    vacancy events: %ssupported\n",
1771
1.21k
                      features->supports_vacancy_events ? "" : "not ");
1772
1773
1.21k
    }
1774
1775
25.4k
    if (features->max_entries) {
1776
21.6k
        ds_put_format(s, "    max_entries=%"PRIu32"\n", features->max_entries);
1777
21.6k
    }
1778
1779
25.4k
    const struct ofputil_table_instruction_features *prev_nonmiss
1780
25.4k
        = prev_features ? &prev_features->nonmiss : NULL;
1781
25.4k
    const struct ofputil_table_instruction_features *prev_miss
1782
25.4k
        = prev_features ? &prev_features->miss : NULL;
1783
25.4k
    if (prev_features
1784
25.4k
        && table_instruction_features_equal(&features->nonmiss, table,
1785
20.6k
                                            prev_nonmiss, prev_table)
1786
25.4k
        && table_instruction_features_equal(&features->miss, table,
1787
6.33k
                                            prev_miss, prev_table)) {
1788
6.33k
        if (!table_instruction_features_empty(&features->nonmiss)) {
1789
1.85k
            ds_put_cstr(s, "    (same instructions)\n");
1790
1.85k
        }
1791
19.0k
    } else if (!table_instruction_features_equal(&features->nonmiss, table,
1792
19.0k
                                                 &features->miss, table)) {
1793
0
        ds_put_cstr(s, "    instructions (other than table miss):\n");
1794
0
        print_table_instruction_features(s, &features->nonmiss, prev_nonmiss);
1795
0
        ds_put_cstr(s, "    instructions (table miss):\n");
1796
0
        print_table_instruction_features(s, &features->miss, prev_miss);
1797
19.0k
    } else if (!table_instruction_features_empty(&features->nonmiss)) {
1798
16.8k
        ds_put_cstr(s, "    instructions (table miss and others):\n");
1799
16.8k
        print_table_instruction_features(s, &features->nonmiss, prev_nonmiss);
1800
16.8k
    }
1801
1802
25.4k
    if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)) {
1803
22.6k
        if (prev_features
1804
22.6k
            && bitmap_equal(features->match.bm, prev_features->match.bm,
1805
19.1k
                            MFF_N_IDS)) {
1806
3.96k
            ds_put_cstr(s, "    (same matching)\n");
1807
18.6k
        } else {
1808
18.6k
            ds_put_cstr(s, "    matching:\n");
1809
1810
18.6k
            print_matches(s, features, true, true, "arbitrary mask");
1811
18.6k
            print_matches(s, features, false, true, "exact match or wildcard");
1812
18.6k
            print_matches(s, features, false, false, "must exact match");
1813
18.6k
        }
1814
22.6k
    }
1815
25.4k
}
1816
1817
void
1818
ofputil_table_features_format_finish(struct ds *s,
1819
                                     int first_ditto, int last_ditto)
1820
48.6k
{
1821
48.6k
    if (first_ditto < 0) {
1822
48.4k
        return;
1823
48.4k
    }
1824
1825
255
    ds_put_char(s, '\n');
1826
255
    if (first_ditto == last_ditto) {
1827
198
        ds_put_format(s, "  table %d: ditto\n", first_ditto);
1828
198
    } else {
1829
57
        ds_put_format(s, "  tables %d...%d: ditto\n", first_ditto, last_ditto);
1830
57
    }
1831
255
}
1832
1833
/* Returns true if 'super' is a superset of 'sub', false otherwise. */
1834
static bool
1835
ofputil_table_action_features_is_superset(
1836
    const struct ofputil_table_action_features *super,
1837
    const struct ofputil_table_action_features *sub)
1838
0
{
1839
0
    return (uint_is_superset(super->ofpacts, sub->ofpacts)
1840
0
            && mf_bitmap_is_superset(&super->set_fields, &sub->set_fields));
1841
0
}
1842
1843
/* Returns true if 'super' is a superset of 'sub', false otherwise. */
1844
static bool
1845
ofputil_table_instruction_features_is_superset(
1846
    const struct ofputil_table_instruction_features *super,
1847
    const struct ofputil_table_instruction_features *sub)
1848
0
{
1849
0
    return (bitmap_is_superset(super->next, sub->next, 255)
1850
0
            && uint_is_superset(super->instructions, sub->instructions)
1851
0
            && ofputil_table_action_features_is_superset(&super->write,
1852
0
                                                         &sub->write)
1853
0
            && ofputil_table_action_features_is_superset(&super->apply,
1854
0
                                                         &sub->apply));
1855
0
}
1856
1857
/* Returns true if 'super' is a superset of 'sub', false otherwise. */
1858
bool
1859
ofputil_table_features_are_superset(
1860
    const struct ofputil_table_features *super,
1861
    const struct ofputil_table_features *sub)
1862
0
{
1863
0
    return (be64_is_superset(super->metadata_match, sub->metadata_match)
1864
0
            && be64_is_superset(super->metadata_write, sub->metadata_write)
1865
0
            && super->max_entries >= sub->max_entries
1866
0
            && super->supports_eviction >= sub->supports_eviction
1867
0
            && super->supports_vacancy_events >= sub->supports_vacancy_events
1868
0
            && ofputil_table_instruction_features_is_superset(&super->nonmiss,
1869
0
                                                              &sub->nonmiss)
1870
0
            && ofputil_table_instruction_features_is_superset(&super->miss,
1871
0
                                                              &sub->miss)
1872
0
            && mf_bitmap_is_superset(&super->match, &sub->match)
1873
0
            && mf_bitmap_is_superset(&super->mask, &sub->mask)
1874
0
            && mf_bitmap_is_superset(&super->wildcard, &sub->wildcard));
1875
0
}
1876

1877
/* Table stats. */
1878
1879
/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
1880
 * matched and a field that must be wildcarded.  This function returns a bitmap
1881
 * that contains both kinds of fields. */
1882
static struct mf_bitmap
1883
wild_or_nonmatchable_fields(const struct ofputil_table_features *features)
1884
0
{
1885
0
    struct mf_bitmap wc = features->match;
1886
0
    bitmap_not(wc.bm, MFF_N_IDS);
1887
0
    bitmap_or(wc.bm, features->wildcard.bm, MFF_N_IDS);
1888
0
    return wc;
1889
0
}
1890
1891
struct ofp10_wc_map {
1892
    enum ofp10_flow_wildcards wc10;
1893
    enum mf_field_id mf;
1894
};
1895
1896
static const struct ofp10_wc_map ofp10_wc_map[] = {
1897
    { OFPFW10_IN_PORT,     MFF_IN_PORT },
1898
    { OFPFW10_DL_VLAN,     MFF_VLAN_VID },
1899
    { OFPFW10_DL_SRC,      MFF_ETH_SRC },
1900
    { OFPFW10_DL_DST,      MFF_ETH_DST},
1901
    { OFPFW10_DL_TYPE,     MFF_ETH_TYPE },
1902
    { OFPFW10_NW_PROTO,    MFF_IP_PROTO },
1903
    { OFPFW10_TP_SRC,      MFF_TCP_SRC },
1904
    { OFPFW10_TP_DST,      MFF_TCP_DST },
1905
    { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC },
1906
    { OFPFW10_NW_DST_MASK, MFF_IPV4_DST },
1907
    { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP },
1908
    { OFPFW10_NW_TOS,      MFF_IP_DSCP },
1909
};
1910
1911
static ovs_be32
1912
mf_bitmap_to_of10(const struct mf_bitmap *fields)
1913
0
{
1914
0
    const struct ofp10_wc_map *p;
1915
0
    uint32_t wc10 = 0;
1916
1917
0
    for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
1918
0
        if (bitmap_is_set(fields->bm, p->mf)) {
1919
0
            wc10 |= p->wc10;
1920
0
        }
1921
0
    }
1922
0
    return htonl(wc10);
1923
0
}
1924
1925
static struct mf_bitmap
1926
mf_bitmap_from_of10(ovs_be32 wc10_)
1927
6.16k
{
1928
6.16k
    struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
1929
6.16k
    const struct ofp10_wc_map *p;
1930
6.16k
    uint32_t wc10 = ntohl(wc10_);
1931
1932
80.0k
    for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
1933
73.9k
        if (wc10 & p->wc10) {
1934
28.7k
            bitmap_set1(fields.bm, p->mf);
1935
28.7k
        }
1936
73.9k
    }
1937
6.16k
    return fields;
1938
6.16k
}
1939
1940
static void
1941
ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *stats,
1942
                              const struct ofputil_table_features *features,
1943
                              struct ofpbuf *buf)
1944
0
{
1945
0
    struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
1946
0
    struct ofp10_table_stats *out;
1947
1948
0
    out = ofpbuf_put_zeros(buf, sizeof *out);
1949
0
    out->table_id = features->table_id;
1950
0
    ovs_strlcpy_arrays(out->name, features->name);
1951
0
    out->wildcards = mf_bitmap_to_of10(&wc);
1952
0
    out->max_entries = htonl(features->max_entries);
1953
0
    out->active_count = htonl(stats->active_count);
1954
0
    put_32aligned_be64(&out->lookup_count, htonll(stats->lookup_count));
1955
0
    put_32aligned_be64(&out->matched_count, htonll(stats->matched_count));
1956
0
}
1957
1958
struct ofp11_wc_map {
1959
    enum ofp11_flow_match_fields wc11;
1960
    enum mf_field_id mf;
1961
};
1962
1963
static const struct ofp11_wc_map ofp11_wc_map[] = {
1964
    { OFPFMF11_IN_PORT,     MFF_IN_PORT },
1965
    { OFPFMF11_DL_VLAN,     MFF_VLAN_VID },
1966
    { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP },
1967
    { OFPFMF11_DL_TYPE,     MFF_ETH_TYPE },
1968
    { OFPFMF11_NW_TOS,      MFF_IP_DSCP },
1969
    { OFPFMF11_NW_PROTO,    MFF_IP_PROTO },
1970
    { OFPFMF11_TP_SRC,      MFF_TCP_SRC },
1971
    { OFPFMF11_TP_DST,      MFF_TCP_DST },
1972
    { OFPFMF11_MPLS_LABEL,  MFF_MPLS_LABEL },
1973
    { OFPFMF11_MPLS_TC,     MFF_MPLS_TC },
1974
    /* I don't know what OFPFMF11_TYPE means. */
1975
    { OFPFMF11_DL_SRC,      MFF_ETH_SRC },
1976
    { OFPFMF11_DL_DST,      MFF_ETH_DST },
1977
    { OFPFMF11_NW_SRC,      MFF_IPV4_SRC },
1978
    { OFPFMF11_NW_DST,      MFF_IPV4_DST },
1979
    { OFPFMF11_METADATA,    MFF_METADATA },
1980
};
1981
1982
static ovs_be32
1983
mf_bitmap_to_of11(const struct mf_bitmap *fields)
1984
0
{
1985
0
    const struct ofp11_wc_map *p;
1986
0
    uint32_t wc11 = 0;
1987
1988
0
    for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
1989
0
        if (bitmap_is_set(fields->bm, p->mf)) {
1990
0
            wc11 |= p->wc11;
1991
0
        }
1992
0
    }
1993
0
    return htonl(wc11);
1994
0
}
1995
1996
static struct mf_bitmap
1997
mf_bitmap_from_of11(ovs_be32 wc11_)
1998
11.9k
{
1999
11.9k
    struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
2000
11.9k
    const struct ofp11_wc_map *p;
2001
11.9k
    uint32_t wc11 = ntohl(wc11_);
2002
2003
191k
    for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
2004
179k
        if (wc11 & p->wc11) {
2005
68.6k
            bitmap_set1(fields.bm, p->mf);
2006
68.6k
        }
2007
179k
    }
2008
11.9k
    return fields;
2009
11.9k
}
2010
2011
static void
2012
ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *stats,
2013
                              const struct ofputil_table_features *features,
2014
                              struct ofpbuf *buf)
2015
0
{
2016
0
    struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
2017
0
    struct ofp11_table_stats *out;
2018
2019
0
    out = ofpbuf_put_zeros(buf, sizeof *out);
2020
0
    out->table_id = features->table_id;
2021
0
    ovs_strlcpy_arrays(out->name, features->name);
2022
0
    out->wildcards = mf_bitmap_to_of11(&wc);
2023
0
    out->match = mf_bitmap_to_of11(&features->match);
2024
0
    out->instructions = ovsinst_bitmap_to_openflow(
2025
0
        features->nonmiss.instructions, OFP11_VERSION);
2026
0
    out->write_actions = ofpact_bitmap_to_openflow(
2027
0
        features->nonmiss.write.ofpacts, OFP11_VERSION);
2028
0
    out->apply_actions = ofpact_bitmap_to_openflow(
2029
0
        features->nonmiss.apply.ofpacts, OFP11_VERSION);
2030
0
    out->config = htonl(features->miss_config);
2031
0
    out->max_entries = htonl(features->max_entries);
2032
0
    out->active_count = htonl(stats->active_count);
2033
0
    out->lookup_count = htonll(stats->lookup_count);
2034
0
    out->matched_count = htonll(stats->matched_count);
2035
0
}
2036
2037
static void
2038
ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
2039
                              const struct ofputil_table_features *features,
2040
                              struct ofpbuf *buf)
2041
0
{
2042
0
    struct ofp12_table_stats *out;
2043
2044
0
    out = ofpbuf_put_zeros(buf, sizeof *out);
2045
0
    out->table_id = features->table_id;
2046
0
    ovs_strlcpy_arrays(out->name, features->name);
2047
0
    out->match = oxm_bitmap_from_mf_bitmap(&features->match, OFP12_VERSION);
2048
0
    out->wildcards = oxm_bitmap_from_mf_bitmap(&features->wildcard,
2049
0
                                             OFP12_VERSION);
2050
0
    out->write_actions = ofpact_bitmap_to_openflow(
2051
0
        features->nonmiss.write.ofpacts, OFP12_VERSION);
2052
0
    out->apply_actions = ofpact_bitmap_to_openflow(
2053
0
        features->nonmiss.apply.ofpacts, OFP12_VERSION);
2054
0
    out->write_setfields = oxm_bitmap_from_mf_bitmap(
2055
0
        &features->nonmiss.write.set_fields, OFP12_VERSION);
2056
0
    out->apply_setfields = oxm_bitmap_from_mf_bitmap(
2057
0
        &features->nonmiss.apply.set_fields, OFP12_VERSION);
2058
0
    out->metadata_match = features->metadata_match;
2059
0
    out->metadata_write = features->metadata_write;
2060
0
    out->instructions = ovsinst_bitmap_to_openflow(
2061
0
        features->nonmiss.instructions, OFP12_VERSION);
2062
0
    out->config = ofputil_encode_table_config(features->miss_config,
2063
0
                                              OFPUTIL_TABLE_EVICTION_DEFAULT,
2064
0
                                              OFPUTIL_TABLE_VACANCY_DEFAULT,
2065
0
                                              OFP12_VERSION);
2066
0
    out->max_entries = htonl(features->max_entries);
2067
0
    out->active_count = htonl(stats->active_count);
2068
0
    out->lookup_count = htonll(stats->lookup_count);
2069
0
    out->matched_count = htonll(stats->matched_count);
2070
0
}
2071
2072
static void
2073
ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *stats,
2074
                              struct ofpbuf *buf)
2075
0
{
2076
0
    struct ofp13_table_stats *out;
2077
2078
0
    out = ofpbuf_put_zeros(buf, sizeof *out);
2079
0
    out->table_id = stats->table_id;
2080
0
    out->active_count = htonl(stats->active_count);
2081
0
    out->lookup_count = htonll(stats->lookup_count);
2082
0
    out->matched_count = htonll(stats->matched_count);
2083
0
}
2084
2085
struct ofpbuf *
2086
ofputil_encode_table_stats_reply(const struct ofp_header *request)
2087
0
{
2088
0
    return ofpraw_alloc_stats_reply(request, 0);
2089
0
}
2090
2091
void
2092
ofputil_append_table_stats_reply(struct ofpbuf *reply,
2093
                                 const struct ofputil_table_stats *stats,
2094
                                 const struct ofputil_table_features *features)
2095
0
{
2096
0
    struct ofp_header *oh = reply->header;
2097
2098
0
    ovs_assert(stats->table_id == features->table_id);
2099
2100
0
    switch ((enum ofp_version) oh->version) {
2101
0
    case OFP10_VERSION:
2102
0
        ofputil_put_ofp10_table_stats(stats, features, reply);
2103
0
        break;
2104
2105
0
    case OFP11_VERSION:
2106
0
        ofputil_put_ofp11_table_stats(stats, features, reply);
2107
0
        break;
2108
2109
0
    case OFP12_VERSION:
2110
0
        ofputil_put_ofp12_table_stats(stats, features, reply);
2111
0
        break;
2112
2113
0
    case OFP13_VERSION:
2114
0
    case OFP14_VERSION:
2115
0
    case OFP15_VERSION:
2116
0
        ofputil_put_ofp13_table_stats(stats, reply);
2117
0
        break;
2118
2119
0
    default:
2120
0
        OVS_NOT_REACHED();
2121
0
    }
2122
0
}
2123
2124
static int
2125
ofputil_decode_ofp10_table_stats(struct ofpbuf *msg,
2126
                                 struct ofputil_table_stats *stats,
2127
                                 struct ofputil_table_features *features)
2128
6.16k
{
2129
6.16k
    struct ofp10_table_stats *ots;
2130
2131
6.16k
    ots = ofpbuf_try_pull(msg, sizeof *ots);
2132
6.16k
    if (!ots) {
2133
0
        return OFPERR_OFPBRC_BAD_LEN;
2134
0
    }
2135
2136
6.16k
    features->table_id = ots->table_id;
2137
6.16k
    ovs_strlcpy_arrays(features->name, ots->name);
2138
6.16k
    features->max_entries = ntohl(ots->max_entries);
2139
6.16k
    features->match = features->wildcard = mf_bitmap_from_of10(ots->wildcards);
2140
2141
6.16k
    stats->table_id = ots->table_id;
2142
6.16k
    stats->active_count = ntohl(ots->active_count);
2143
6.16k
    stats->lookup_count = ntohll(get_32aligned_be64(&ots->lookup_count));
2144
6.16k
    stats->matched_count = ntohll(get_32aligned_be64(&ots->matched_count));
2145
2146
6.16k
    return 0;
2147
6.16k
}
2148
2149
static int
2150
ofputil_decode_ofp11_table_stats(struct ofpbuf *msg,
2151
                                 struct ofputil_table_stats *stats,
2152
                                 struct ofputil_table_features *features)
2153
5.99k
{
2154
5.99k
    struct ofp11_table_stats *ots;
2155
2156
5.99k
    ots = ofpbuf_try_pull(msg, sizeof *ots);
2157
5.99k
    if (!ots) {
2158
0
        return OFPERR_OFPBRC_BAD_LEN;
2159
0
    }
2160
2161
5.99k
    features->table_id = ots->table_id;
2162
5.99k
    ovs_strlcpy_arrays(features->name, ots->name);
2163
5.99k
    features->max_entries = ntohl(ots->max_entries);
2164
5.99k
    features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
2165
5.99k
        ots->instructions, OFP11_VERSION);
2166
5.99k
    features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
2167
5.99k
        ots->write_actions, OFP11_VERSION);
2168
5.99k
    features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
2169
5.99k
        ots->write_actions, OFP11_VERSION);
2170
5.99k
    features->miss = features->nonmiss;
2171
5.99k
    features->miss_config = ofputil_decode_table_miss(ots->config,
2172
5.99k
                                                      OFP11_VERSION);
2173
5.99k
    features->match = mf_bitmap_from_of11(ots->match);
2174
5.99k
    features->wildcard = mf_bitmap_from_of11(ots->wildcards);
2175
5.99k
    bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
2176
2177
5.99k
    stats->table_id = ots->table_id;
2178
5.99k
    stats->active_count = ntohl(ots->active_count);
2179
5.99k
    stats->lookup_count = ntohll(ots->lookup_count);
2180
5.99k
    stats->matched_count = ntohll(ots->matched_count);
2181
2182
5.99k
    return 0;
2183
5.99k
}
2184
2185
static int
2186
ofputil_decode_ofp12_table_stats(struct ofpbuf *msg,
2187
                                 struct ofputil_table_stats *stats,
2188
                                 struct ofputil_table_features *features)
2189
13.7k
{
2190
13.7k
    struct ofp12_table_stats *ots;
2191
2192
13.7k
    ots = ofpbuf_try_pull(msg, sizeof *ots);
2193
13.7k
    if (!ots) {
2194
0
        return OFPERR_OFPBRC_BAD_LEN;
2195
0
    }
2196
2197
13.7k
    features->table_id = ots->table_id;
2198
13.7k
    ovs_strlcpy_arrays(features->name, ots->name);
2199
13.7k
    features->metadata_match = ots->metadata_match;
2200
13.7k
    features->metadata_write = ots->metadata_write;
2201
13.7k
    features->miss_config = ofputil_decode_table_miss(ots->config,
2202
13.7k
                                                      OFP12_VERSION);
2203
13.7k
    features->max_entries = ntohl(ots->max_entries);
2204
2205
13.7k
    features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
2206
13.7k
        ots->instructions, OFP12_VERSION);
2207
13.7k
    features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
2208
13.7k
        ots->write_actions, OFP12_VERSION);
2209
13.7k
    features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
2210
13.7k
        ots->apply_actions, OFP12_VERSION);
2211
13.7k
    features->nonmiss.write.set_fields = oxm_bitmap_to_mf_bitmap(
2212
13.7k
        ots->write_setfields, OFP12_VERSION);
2213
13.7k
    features->nonmiss.apply.set_fields = oxm_bitmap_to_mf_bitmap(
2214
13.7k
        ots->apply_setfields, OFP12_VERSION);
2215
13.7k
    features->miss = features->nonmiss;
2216
2217
13.7k
    features->match = oxm_bitmap_to_mf_bitmap(ots->match, OFP12_VERSION);
2218
13.7k
    features->wildcard = oxm_bitmap_to_mf_bitmap(ots->wildcards,
2219
13.7k
                                                 OFP12_VERSION);
2220
13.7k
    bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
2221
2222
13.7k
    stats->table_id = ots->table_id;
2223
13.7k
    stats->active_count = ntohl(ots->active_count);
2224
13.7k
    stats->lookup_count = ntohll(ots->lookup_count);
2225
13.7k
    stats->matched_count = ntohll(ots->matched_count);
2226
2227
13.7k
    return 0;
2228
13.7k
}
2229
2230
static int
2231
ofputil_decode_ofp13_table_stats(struct ofpbuf *msg,
2232
                                 struct ofputil_table_stats *stats,
2233
                                 struct ofputil_table_features *features)
2234
2.77k
{
2235
2.77k
    struct ofp13_table_stats *ots;
2236
2237
2.77k
    ots = ofpbuf_try_pull(msg, sizeof *ots);
2238
2.77k
    if (!ots) {
2239
0
        return OFPERR_OFPBRC_BAD_LEN;
2240
0
    }
2241
2242
2.77k
    features->table_id = ots->table_id;
2243
2244
2.77k
    stats->table_id = ots->table_id;
2245
2.77k
    stats->active_count = ntohl(ots->active_count);
2246
2.77k
    stats->lookup_count = ntohll(ots->lookup_count);
2247
2.77k
    stats->matched_count = ntohll(ots->matched_count);
2248
2249
2.77k
    return 0;
2250
2.77k
}
2251
2252
int
2253
ofputil_decode_table_stats_reply(struct ofpbuf *msg,
2254
                                 struct ofputil_table_stats *stats,
2255
                                 struct ofputil_table_features *features)
2256
33.6k
{
2257
33.6k
    const struct ofp_header *oh;
2258
2259
33.6k
    if (!msg->header) {
2260
0
        ofpraw_pull_assert(msg);
2261
0
    }
2262
33.6k
    oh = msg->header;
2263
2264
33.6k
    if (!msg->size) {
2265
5.02k
        return EOF;
2266
5.02k
    }
2267
2268
28.6k
    memset(stats, 0, sizeof *stats);
2269
28.6k
    memset(features, 0, sizeof *features);
2270
28.6k
    features->supports_eviction = -1;
2271
28.6k
    features->supports_vacancy_events = -1;
2272
2273
28.6k
    switch ((enum ofp_version) oh->version) {
2274
6.16k
    case OFP10_VERSION:
2275
6.16k
        return ofputil_decode_ofp10_table_stats(msg, stats, features);
2276
2277
5.99k
    case OFP11_VERSION:
2278
5.99k
        return ofputil_decode_ofp11_table_stats(msg, stats, features);
2279
2280
13.7k
    case OFP12_VERSION:
2281
13.7k
        return ofputil_decode_ofp12_table_stats(msg, stats, features);
2282
2283
535
    case OFP13_VERSION:
2284
984
    case OFP14_VERSION:
2285
2.77k
    case OFP15_VERSION:
2286
2.77k
        return ofputil_decode_ofp13_table_stats(msg, stats, features);
2287
2288
0
    default:
2289
0
        OVS_NOT_REACHED();
2290
28.6k
    }
2291
28.6k
}
2292

2293
/* Returns a string form of 'reason'.  The return value is either a statically
2294
 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2295
 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
2296
const char *
2297
ofp_table_reason_to_string(enum ofp14_table_reason reason,
2298
                           char *reasonbuf, size_t bufsize)
2299
4.25k
{
2300
4.25k
    switch (reason) {
2301
2.10k
    case OFPTR_VACANCY_DOWN:
2302
2.10k
        return "vacancy_down";
2303
2304
2.15k
    case OFPTR_VACANCY_UP:
2305
2.15k
        return "vacancy_up";
2306
2307
0
    default:
2308
0
        snprintf(reasonbuf, bufsize, "%d", (int) reason);
2309
0
        return reasonbuf;
2310
4.25k
    }
2311
4.25k
}
2312
2313
static void
2314
ofputil_put_ofp14_table_desc(const struct ofputil_table_desc *td,
2315
                             struct ofpbuf *b, enum ofp_version version)
2316
0
{
2317
0
    struct ofp14_table_desc *otd;
2318
0
    struct ofp14_table_mod_prop_vacancy *otv;
2319
0
    size_t start_otd;
2320
2321
0
    start_otd = b->size;
2322
0
    ofpbuf_put_zeros(b, sizeof *otd);
2323
2324
0
    ofpprop_put_u32(b, OFPTMPT14_EVICTION, td->eviction_flags);
2325
2326
0
    otv = ofpbuf_put_zeros(b, sizeof *otv);
2327
0
    otv->type = htons(OFPTMPT14_VACANCY);
2328
0
    otv->length = htons(sizeof *otv);
2329
0
    otv->vacancy_down = td->table_vacancy.vacancy_down;
2330
0
    otv->vacancy_up = td->table_vacancy.vacancy_up;
2331
0
    otv->vacancy = td->table_vacancy.vacancy;
2332
2333
0
    otd = ofpbuf_at_assert(b, start_otd, sizeof *otd);
2334
0
    otd->length = htons(b->size - start_otd);
2335
0
    otd->table_id = td->table_id;
2336
0
    otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT,
2337
0
                                              td->eviction, td->vacancy,
2338
0
                                              version);
2339
0
}
2340
2341
/* Converts the abstract form of a "table status" message in '*ts' into an
2342
 * OpenFlow message suitable for 'protocol', and returns that encoded form in
2343
 * a buffer owned by the caller. */
2344
struct ofpbuf *
2345
ofputil_encode_table_status(const struct ofputil_table_status *ts,
2346
                            enum ofputil_protocol protocol)
2347
0
{
2348
0
    enum ofp_version version;
2349
0
    struct ofpbuf *b;
2350
2351
0
    version = ofputil_protocol_to_ofp_version(protocol);
2352
0
    if (version >= OFP14_VERSION) {
2353
0
        enum ofpraw raw;
2354
0
        struct ofp14_table_status *ots;
2355
2356
0
        raw = OFPRAW_OFPT14_TABLE_STATUS;
2357
0
        b = ofpraw_alloc_xid(raw, version, htonl(0), 0);
2358
0
        ots = ofpbuf_put_zeros(b, sizeof *ots);
2359
0
        ots->reason = ts->reason;
2360
0
        ofputil_put_ofp14_table_desc(&ts->desc, b, version);
2361
0
        ofpmsg_update_length(b);
2362
0
        return b;
2363
0
    } else {
2364
0
        return NULL;
2365
0
    }
2366
0
}
2367
2368
/* Decodes the OpenFlow "table status" message in '*ots' into an abstract form
2369
 * in '*ts'.  Returns 0 if successful, otherwise an OFPERR_* value. */
2370
enum ofperr
2371
ofputil_decode_table_status(const struct ofp_header *oh,
2372
                            struct ofputil_table_status *ts)
2373
1.26k
{
2374
1.26k
    const struct ofp14_table_status *ots;
2375
1.26k
    struct ofpbuf b;
2376
1.26k
    enum ofperr error;
2377
1.26k
    enum ofpraw raw;
2378
2379
1.26k
    ofpbuf_use_const(&b, oh, ntohs(oh->length));
2380
1.26k
    raw = ofpraw_pull_assert(&b);
2381
1.26k
    ots = ofpbuf_pull(&b, sizeof *ots);
2382
2383
1.26k
    if (raw == OFPRAW_OFPT14_TABLE_STATUS) {
2384
1.26k
        if (ots->reason != OFPTR_VACANCY_DOWN
2385
1.26k
            && ots->reason != OFPTR_VACANCY_UP) {
2386
276
            return OFPERR_OFPBPC_BAD_VALUE;
2387
276
        }
2388
992
        ts->reason = ots->reason;
2389
2390
992
        error = ofputil_decode_table_desc(&b, &ts->desc, oh->version);
2391
992
        return error;
2392
1.26k
    } else {
2393
0
        return OFPERR_OFPBRC_BAD_VERSION;
2394
0
    }
2395
2396
0
    return 0;
2397
1.26k
}
2398
2399
void
2400
ofputil_format_table_status(struct ds *string,
2401
                            const struct ofputil_table_status *ts,
2402
                            const struct ofputil_table_map *table_map)
2403
633
{
2404
633
    if (ts->reason == OFPTR_VACANCY_DOWN) {
2405
134
        ds_put_format(string, " reason=VACANCY_DOWN");
2406
499
    } else if (ts->reason == OFPTR_VACANCY_UP) {
2407
499
        ds_put_format(string, " reason=VACANCY_UP");
2408
499
    }
2409
2410
633
    ds_put_format(string, "\ntable_desc:-");
2411
633
    ofputil_table_desc_format(string, &ts->desc, table_map);
2412
633
}