Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/netlink-conntrack.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2015 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
19
#include "netlink-conntrack.h"
20
21
#include <errno.h>
22
#include <linux/netfilter/nfnetlink.h>
23
#include <linux/netfilter/nfnetlink_conntrack.h>
24
#include <linux/netfilter/nf_conntrack_common.h>
25
#include <linux/netfilter/nf_conntrack_tcp.h>
26
#include <linux/netfilter/nf_conntrack_ftp.h>
27
#include <linux/netfilter/nf_conntrack_sctp.h>
28
29
#include "byte-order.h"
30
#include "compiler.h"
31
#include "openvswitch/dynamic-string.h"
32
#include "netlink.h"
33
#include "netlink-socket.h"
34
#include "openvswitch/ofpbuf.h"
35
#include "openvswitch/vlog.h"
36
#include "openvswitch/poll-loop.h"
37
#include "timeval.h"
38
#include "unixctl.h"
39
#include "util.h"
40
41
VLOG_DEFINE_THIS_MODULE(netlink_conntrack);
42
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
43
44
/* This module works only if conntrack modules and features are enabled in the
45
 * Linux kernel.  This can be done from a root shell like this:
46
 *
47
 * $ modprobe ip_conntrack
48
 * $ sysctl -w net.netfilter.nf_conntrack_acct=1
49
 * $ sysctl -w net.netfilter.nf_conntrack_timestamp=1
50
 *
51
 * Also, if testing conntrack label feature without conntrack-aware OVS kernel
52
 * module, there must be a connlabel rule in iptables for space to be reserved
53
 * for the labels (see kernel source connlabel_mt_check()).  Such a rule can be
54
 * inserted from a root shell like this:
55
 *
56
 * $ iptables -A INPUT -m conntrack -m connlabel \
57
 *   --ctstate NEW,ESTABLISHED,RELATED --label 127 -j ACCEPT
58
 */
59
60
/* Some attributes were introduced in later kernels: with these definitions
61
 * we should be able to compile userspace against Linux 2.6.32+. */
62
63
0
#define CTA_ZONE          (CTA_SECMARK + 1)
64
#define CTA_SECCTX        (CTA_SECMARK + 2)
65
0
#define CTA_TIMESTAMP     (CTA_SECMARK + 3)
66
#define CTA_MARK_MASK     (CTA_SECMARK + 4)
67
0
#define CTA_LABELS        (CTA_SECMARK + 5)
68
#define CTA_LABELS_MASK   (CTA_SECMARK + 6)
69
0
#define CTA_FILTER        (CTA_SECMARK + 8)
70
71
0
#define CTA_FILTER_ZONE   3
72
73
0
#define CTA_TIMESTAMP_START 1
74
0
#define CTA_TIMESTAMP_STOP  2
75
76
0
#define IPS_TEMPLATE_BIT 11
77
0
#define IPS_TEMPLATE (1 << IPS_TEMPLATE_BIT)
78
79
0
#define IPS_UNTRACKED_BIT 12
80
0
#define IPS_UNTRACKED (1 << IPS_UNTRACKED_BIT)
81
82
static const struct nl_policy nfnlgrp_conntrack_policy[] = {
83
    [CTA_TUPLE_ORIG] = { .type = NL_A_NESTED, .optional = false },
84
    [CTA_TUPLE_REPLY] = { .type = NL_A_NESTED, .optional = false },
85
    [CTA_ZONE] = { .type = NL_A_BE16, .optional = true },
86
    [CTA_STATUS] = { .type = NL_A_BE32, .optional = false },
87
    [CTA_TIMESTAMP] = { .type = NL_A_NESTED, .optional = true },
88
    [CTA_TIMEOUT] = { .type = NL_A_BE32, .optional = true },
89
    [CTA_COUNTERS_ORIG] = { .type = NL_A_NESTED, .optional = true },
90
    [CTA_COUNTERS_REPLY] = { .type = NL_A_NESTED, .optional = true },
91
    [CTA_PROTOINFO] = { .type = NL_A_NESTED, .optional = true },
92
    [CTA_HELP] = { .type = NL_A_NESTED, .optional = true },
93
    [CTA_MARK] = { .type = NL_A_BE32, .optional = true },
94
    [CTA_SECCTX] = { .type = NL_A_NESTED, .optional = true },
95
    [CTA_ID] = { .type = NL_A_BE32, .optional = false },
96
    [CTA_USE] = { .type = NL_A_BE32, .optional = true },
97
    [CTA_TUPLE_MASTER] = { .type = NL_A_NESTED, .optional = true },
98
    [CTA_NAT_SEQ_ADJ_ORIG] = { .type = NL_A_NESTED, .optional = true },
99
    [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NL_A_NESTED, .optional = true },
100
    [CTA_LABELS] = { .type = NL_A_UNSPEC, .optional = true },
101
    /* CTA_NAT_SRC, CTA_NAT_DST, CTA_TIMESTAMP, CTA_MARK_MASK, and
102
     * CTA_LABELS_MASK are not received from kernel. */
103
};
104
105
/* Declarations for conntrack netlink dumping. */
106
static void nl_msg_put_nfgenmsg(struct ofpbuf *msg, size_t expected_payload,
107
                                int family, uint8_t subsystem, uint8_t cmd,
108
                                uint32_t flags);
109
110
static bool nl_ct_parse_header_policy(struct ofpbuf *buf,
111
        enum nl_ct_event_type *event_type,
112
        uint8_t *nfgen_family,
113
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)]);
114
115
static bool nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
116
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
117
        uint8_t nfgen_family);
118
static bool nl_ct_put_ct_tuple(struct ofpbuf *buf,
119
        const struct ct_dpif_tuple *tuple, enum ctattr_type type);
120
121
struct nl_ct_dump_state {
122
    struct nl_dump dump;
123
    struct ofpbuf buf;
124
    bool filter_zone;
125
    uint16_t zone;
126
};
127
128
/* Conntrack netlink dumping. */
129
130
/* Initialize a conntrack netlink dump. */
131
int
132
nl_ct_dump_start(struct nl_ct_dump_state **statep, const uint16_t *zone,
133
        int *ptot_bkts)
134
0
{
135
0
    struct nl_ct_dump_state *state;
136
137
0
    *statep = state = xzalloc(sizeof *state);
138
0
    ofpbuf_init(&state->buf, NL_DUMP_BUFSIZE);
139
140
0
    if (zone) {
141
0
        state->filter_zone = true;
142
0
        state->zone = *zone;
143
0
    }
144
145
0
    nl_msg_put_nfgenmsg(&state->buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
146
0
                        IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
147
0
    if (zone) {
148
0
        nl_msg_put_be16(&state->buf, CTA_ZONE, htons(*zone));
149
0
    }
150
0
    nl_dump_start(&state->dump, NETLINK_NETFILTER, &state->buf);
151
0
    ofpbuf_clear(&state->buf);
152
153
    /* Buckets to store connections are not used. */
154
0
    *ptot_bkts = -1;
155
156
0
    return 0;
157
0
}
158
159
/* Receive the next 'entry' from the conntrack netlink dump with 'state'.
160
 * Returns 'EOF' when no more entries are available, 0 otherwise.  'entry' may
161
 * be uninitilized memory on entry, and must be uninitialized with
162
 * ct_dpif_entry_uninit() afterwards by the caller.  In case the same 'entry' is
163
 * passed to this function again, the entry must also be uninitialized before
164
 * the next call. */
165
int
166
nl_ct_dump_next(struct nl_ct_dump_state *state, struct ct_dpif_entry *entry)
167
0
{
168
0
    struct ofpbuf buf;
169
170
0
    memset(entry, 0, sizeof *entry);
171
0
    for (;;) {
172
0
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
173
0
        enum nl_ct_event_type type;
174
0
        uint8_t nfgen_family;
175
176
0
        if (!nl_dump_next(&state->dump, &buf, &state->buf)) {
177
0
            return EOF;
178
0
        }
179
180
0
        if (!nl_ct_parse_header_policy(&buf, &type, &nfgen_family, attrs)) {
181
0
            continue;
182
0
        };
183
184
0
        if (state->filter_zone) {
185
0
            uint16_t entry_zone = attrs[CTA_ZONE]
186
0
                                  ? ntohs(nl_attr_get_be16(attrs[CTA_ZONE]))
187
0
                                  : 0;
188
0
            if (entry_zone != state->zone) {
189
0
                continue;
190
0
            }
191
0
        }
192
193
0
        if (nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) {
194
0
            break;
195
0
        }
196
197
0
        ct_dpif_entry_uninit(entry);
198
0
        memset(entry, 0, sizeof *entry);
199
        /* Ignore the failed entry and get the next one. */
200
0
    }
201
202
0
    ofpbuf_uninit(&buf);
203
0
    return 0;
204
0
}
205
206
/* End a conntrack netlink dump. */
207
int
208
nl_ct_dump_done(struct nl_ct_dump_state *state)
209
0
{
210
0
    int error = nl_dump_done(&state->dump);
211
212
0
    ofpbuf_uninit(&state->buf);
213
0
    free(state);
214
0
    return error;
215
0
}
216
217
/* Format conntrack event 'entry' of 'type' to 'ds'. */
218
void
219
nl_ct_format_event_entry(const struct ct_dpif_entry *entry,
220
                         enum nl_ct_event_type type, struct ds *ds,
221
                         bool verbose, bool print_stats)
222
0
{
223
0
    ds_put_format(ds, "%s ",
224
0
                  type == NL_CT_EVENT_NEW ? "NEW"
225
0
                  : type == NL_CT_EVENT_UPDATE ? "UPDATE"
226
0
                  : type == NL_CT_EVENT_DELETE ? "DELETE"
227
0
                  : "UNKNOWN");
228
0
    ct_dpif_format_entry(entry, ds, verbose, print_stats);
229
0
}
230
231
int
232
nl_ct_flush(void)
233
0
{
234
0
    struct ofpbuf buf;
235
0
    int err;
236
237
0
    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
238
239
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
240
0
                        IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
241
242
0
    err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
243
0
    ofpbuf_uninit(&buf);
244
245
    /* Expectations are flushed automatically, because they do not
246
     * have a parent connection anymore */
247
248
0
    return err;
249
0
}
250
251
int
252
nl_ct_flush_tuple(const struct ct_dpif_tuple *tuple, uint16_t zone)
253
0
{
254
0
    int err;
255
0
    struct ofpbuf buf;
256
257
0
    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
258
0
    nl_msg_put_nfgenmsg(&buf, 0, tuple->l3_type, NFNL_SUBSYS_CTNETLINK,
259
0
                        IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
260
261
0
    nl_msg_put_be16(&buf, CTA_ZONE, htons(zone));
262
0
    if (!nl_ct_put_ct_tuple(&buf, tuple, CTA_TUPLE_ORIG)) {
263
0
        err = EOPNOTSUPP;
264
0
        goto out;
265
0
    }
266
0
    err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
267
0
out:
268
0
    ofpbuf_uninit(&buf);
269
0
    return err;
270
0
}
271
272
enum {
273
    CT_FLUSH_ZONE_UNSUPPORTED,
274
    CT_FLUSH_ZONE_CTA_ZONE,
275
    CT_FLUSH_ZONE_CTA_FILTER,
276
};
277
278
static int
279
nl_ct_flush_zone_filtered(uint16_t flush_zone, int mode)
280
0
{
281
0
    struct ofpbuf buf;
282
0
    size_t offset;
283
0
    int err;
284
285
0
    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
286
287
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
288
0
                        IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
289
0
    nl_msg_put_be16(&buf, CTA_ZONE, htons(flush_zone));
290
291
0
    if (mode == CT_FLUSH_ZONE_CTA_FILTER) {
292
0
        offset = nl_msg_start_nested_with_flag(&buf, CTA_FILTER);
293
0
        nl_msg_put_flag(&buf, CTA_FILTER_ZONE);
294
0
        nl_msg_end_nested(&buf, offset);
295
0
    }
296
297
0
    err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
298
0
    ofpbuf_uninit(&buf);
299
300
0
    return err;
301
0
}
302
303
static bool
304
nl_ct_probe_cta_filter_zone(void)
305
0
{
306
0
    struct ofpbuf buf, reply;
307
0
    struct nl_dump dump;
308
0
    size_t offset;
309
0
    int err;
310
311
0
    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
312
313
    /* GET and DELETE support CTA_FILTER_ZONE through a common kernel path.
314
     * We probe the GET to avoid accidental deletions. */
315
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
316
0
                        IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
317
    /* Using a high enough zone that is unlikely to have a lot of entries. */
318
0
    nl_msg_put_be16(&buf, CTA_ZONE, htons(60000));
319
320
0
    offset = nl_msg_start_nested_with_flag(&buf, CTA_FILTER);
321
0
    nl_msg_put_flag(&buf, CTA_FILTER_ZONE);
322
0
    nl_msg_end_nested(&buf, offset);
323
324
0
    nl_dump_start(&dump, NETLINK_NETFILTER, &buf);
325
0
    ofpbuf_clear(&buf);
326
327
0
    while (nl_dump_next(&dump, &reply, &buf)) {
328
        /* Nothing to do. */
329
0
    }
330
331
0
    err = nl_dump_done(&dump);
332
0
    ofpbuf_uninit(&buf);
333
334
0
    return err == 0 && (dump.nl_flags & NLM_F_DUMP_FILTERED);
335
0
}
336
337
static int
338
nl_ct_flush_zone_mode(void)
339
0
{
340
0
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
341
0
    static int mode = CT_FLUSH_ZONE_UNSUPPORTED;
342
343
0
    if (ovsthread_once_start(&once)) {
344
0
        if (nl_ct_probe_cta_filter_zone()) {
345
0
            mode = CT_FLUSH_ZONE_CTA_FILTER;
346
0
            VLOG_DBG("Conntrack flush by zone: using CTA_FILTER_ZONE.");
347
0
        } else if (ovs_kernel_is_version_or_newer(6, 8)) {
348
0
            mode = CT_FLUSH_ZONE_CTA_ZONE;
349
0
            VLOG_DBG("Conntrack flush by zone: using bare CTA_ZONE.");
350
0
        } else {
351
0
            VLOG_INFO("Disabling conntrack flush by zone. "
352
0
                      "Not supported in Linux kernel.");
353
0
        }
354
0
        ovsthread_once_done(&once);
355
0
    }
356
0
    return mode;
357
0
}
358
359
int
360
nl_ct_flush_zone(uint16_t flush_zone)
361
0
{
362
    /* In older kernels, there was no netlink interface to flush a specific
363
     * conntrack zone.
364
     * This code dumps every connection, checks the zone and eventually
365
     * delete the entry.
366
     * In newer kernels there is the option to specify a zone for filtering
367
     * during dumps.  Older kernels ignore this option. We set it here in the
368
     * hope we only get relevant entries back, but fall back to filtering here
369
     * to keep compatibility.
370
     *
371
     * This is race-prone, but it is better than using shell scripts.
372
     *
373
     * Additionally newer kernels also support flushing a zone without listing
374
     * it first. */
375
376
0
    struct ofpbuf buf, reply, delete;
377
0
    struct nl_dump dump;
378
0
    int mode;
379
380
0
    mode = nl_ct_flush_zone_mode();
381
0
    if (mode != CT_FLUSH_ZONE_UNSUPPORTED) {
382
0
        return nl_ct_flush_zone_filtered(flush_zone, mode);
383
0
    }
384
385
0
    ofpbuf_init(&buf, NL_DUMP_BUFSIZE);
386
0
    ofpbuf_init(&delete, NL_DUMP_BUFSIZE);
387
388
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK,
389
0
                        IPCTNL_MSG_CT_GET, NLM_F_REQUEST);
390
0
    nl_msg_put_be16(&buf, CTA_ZONE, htons(flush_zone));
391
0
    nl_dump_start(&dump, NETLINK_NETFILTER, &buf);
392
0
    ofpbuf_clear(&buf);
393
394
0
    for (;;) {
395
0
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
396
0
        enum nl_ct_event_type event_type;
397
0
        uint8_t nfgen_family;
398
0
        uint16_t zone = 0;
399
400
0
        if (!nl_dump_next(&dump, &reply, &buf)) {
401
0
            break;
402
0
        }
403
404
0
        if (!nl_ct_parse_header_policy(&reply, &event_type, &nfgen_family,
405
0
                                       attrs)) {
406
0
            continue;
407
0
        };
408
409
0
        if (attrs[CTA_ZONE]) {
410
0
            zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE]));
411
0
        }
412
413
0
        if (zone != flush_zone) {
414
            /* The entry is not in the zone we're flushing. */
415
0
            continue;
416
0
        }
417
0
        nl_msg_put_nfgenmsg(&delete, 0, nfgen_family, NFNL_SUBSYS_CTNETLINK,
418
0
                            IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST);
419
420
0
        nl_msg_put_be16(&delete, CTA_ZONE, htons(zone));
421
0
        nl_msg_put_unspec(&delete, CTA_TUPLE_ORIG, attrs[CTA_TUPLE_ORIG] + 1,
422
0
                          attrs[CTA_TUPLE_ORIG]->nla_len - NLA_HDRLEN);
423
0
        nl_msg_put_unspec(&delete, CTA_ID, attrs[CTA_ID] + 1,
424
0
                          attrs[CTA_ID]->nla_len - NLA_HDRLEN);
425
0
        nl_transact(NETLINK_NETFILTER, &delete, NULL);
426
0
        ofpbuf_clear(&delete);
427
0
    }
428
429
0
    nl_dump_done(&dump);
430
431
0
    ofpbuf_uninit(&delete);
432
0
    ofpbuf_uninit(&buf);
433
434
    /* Expectations are flushed automatically, because they do not
435
     * have a parent connection anymore */
436
0
    return 0;
437
0
}
438
439
/* Conntrack netlink parsing. */
440
441
static bool
442
nl_ct_parse_counters(struct nlattr *nla, struct ct_dpif_counters *counters)
443
0
{
444
0
    static const struct nl_policy policy[] = {
445
0
        [CTA_COUNTERS_PACKETS] = { .type = NL_A_BE64, .optional = false },
446
0
        [CTA_COUNTERS_BYTES] = { .type = NL_A_BE64, .optional = false },
447
0
    };
448
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
449
0
    bool parsed;
450
451
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
452
453
0
    if (parsed) {
454
0
        counters->packets
455
0
            = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_PACKETS]));
456
0
        counters->bytes = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_BYTES]));
457
0
    } else {
458
0
        VLOG_ERR_RL(&rl, "Could not parse nested counters. "
459
0
                    "Possibly incompatible Linux kernel version.");
460
0
    }
461
462
0
    return parsed;
463
0
}
464
465
static bool
466
nl_ct_parse_timestamp(struct nlattr *nla, struct ct_dpif_timestamp *timestamp)
467
0
{
468
0
    static const struct nl_policy policy[] = {
469
0
        [CTA_TIMESTAMP_START] = { .type = NL_A_BE64, .optional = false },
470
0
        [CTA_TIMESTAMP_STOP] = { .type = NL_A_BE64, .optional = true },
471
0
    };
472
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
473
0
    bool parsed;
474
475
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
476
477
0
    if (parsed) {
478
0
        timestamp->start
479
0
            = ntohll(nl_attr_get_be64(attrs[CTA_TIMESTAMP_START]));
480
0
        if (attrs[CTA_TIMESTAMP_STOP]) {
481
0
            timestamp->stop
482
0
                = ntohll(nl_attr_get_be64(attrs[CTA_TIMESTAMP_STOP]));
483
0
        }
484
0
    } else {
485
0
        VLOG_ERR_RL(&rl, "Could not parse nested timestamp. "
486
0
                    "Possibly incompatible Linux kernel version.");
487
0
    }
488
489
0
    return parsed;
490
0
}
491
492
static bool
493
nl_ct_parse_tuple_ip(struct nlattr *nla, struct ct_dpif_tuple *tuple)
494
0
{
495
0
    static const struct nl_policy policy[] = {
496
0
        [CTA_IP_V4_SRC] = { .type = NL_A_BE32, .optional = true },
497
0
        [CTA_IP_V4_DST] = { .type = NL_A_BE32, .optional = true },
498
0
        [CTA_IP_V6_SRC] = { NL_POLICY_FOR(struct in6_addr), .optional = true },
499
0
        [CTA_IP_V6_DST] = { NL_POLICY_FOR(struct in6_addr), .optional = true },
500
0
    };
501
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
502
0
    bool parsed;
503
504
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
505
506
0
    if (parsed) {
507
0
        if (tuple->l3_type == AF_INET) {
508
0
            if (attrs[CTA_IP_V4_SRC]) {
509
0
                tuple->src.ip = nl_attr_get_be32(attrs[CTA_IP_V4_SRC]);
510
0
            }
511
0
            if (attrs[CTA_IP_V4_DST]) {
512
0
                tuple->dst.ip = nl_attr_get_be32(attrs[CTA_IP_V4_DST]);
513
0
            }
514
0
        } else if (tuple->l3_type == AF_INET6) {
515
0
            if (attrs[CTA_IP_V6_SRC]) {
516
0
                memcpy(&tuple->src.in6, nl_attr_get(attrs[CTA_IP_V6_SRC]),
517
0
                       sizeof tuple->src.in6);
518
0
            }
519
0
            if (attrs[CTA_IP_V6_DST]) {
520
0
                memcpy(&tuple->dst.in6, nl_attr_get(attrs[CTA_IP_V6_DST]),
521
0
                       sizeof tuple->dst.in6);
522
0
            }
523
0
        } else {
524
0
            VLOG_WARN_RL(&rl, "Unsupported IP protocol: %u.", tuple->l3_type);
525
0
            return false;
526
0
        }
527
0
    } else {
528
0
        VLOG_ERR_RL(&rl, "Could not parse nested tuple IP options. "
529
0
                    "Possibly incompatible Linux kernel version.");
530
0
    }
531
532
0
    return parsed;
533
0
}
534
535
static bool
536
nl_ct_parse_tuple_proto(struct nlattr *nla, struct ct_dpif_tuple *tuple)
537
0
{
538
0
    static const struct nl_policy policy[] = {
539
0
        [CTA_PROTO_NUM] = { .type = NL_A_U8, .optional = false },
540
0
        [CTA_PROTO_SRC_PORT] = { .type = NL_A_BE16, .optional = true },
541
0
        [CTA_PROTO_DST_PORT] = { .type = NL_A_BE16, .optional = true },
542
0
        [CTA_PROTO_ICMP_ID] = { .type = NL_A_BE16, .optional = true },
543
0
        [CTA_PROTO_ICMP_TYPE] = { .type = NL_A_U8, .optional = true },
544
0
        [CTA_PROTO_ICMP_CODE] = { .type = NL_A_U8, .optional = true },
545
0
        [CTA_PROTO_ICMPV6_ID] = { .type = NL_A_BE16, .optional = true },
546
0
        [CTA_PROTO_ICMPV6_TYPE] = { .type = NL_A_U8, .optional = true },
547
0
        [CTA_PROTO_ICMPV6_CODE] = { .type = NL_A_U8, .optional = true },
548
0
    };
549
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
550
0
    bool parsed;
551
552
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
553
554
0
    if (parsed) {
555
0
        tuple->ip_proto = nl_attr_get_u8(attrs[CTA_PROTO_NUM]);
556
557
0
        if (tuple->l3_type == AF_INET && tuple->ip_proto == IPPROTO_ICMP) {
558
0
            if (!attrs[CTA_PROTO_ICMP_ID] || !attrs[CTA_PROTO_ICMP_TYPE]
559
0
                || !attrs[CTA_PROTO_ICMP_CODE]) {
560
0
                VLOG_ERR_RL(&rl, "Tuple ICMP data missing.");
561
0
                return false;
562
0
            }
563
0
            tuple->icmp_id = nl_attr_get_be16(attrs[CTA_PROTO_ICMP_ID]);
564
0
            tuple->icmp_type = nl_attr_get_u8(attrs[CTA_PROTO_ICMP_TYPE]);
565
0
            tuple->icmp_code = nl_attr_get_u8(attrs[CTA_PROTO_ICMP_CODE]);
566
0
        } else if (tuple->l3_type == AF_INET6 &&
567
0
                   tuple->ip_proto == IPPROTO_ICMPV6) {
568
0
            if (!attrs[CTA_PROTO_ICMPV6_ID] || !attrs[CTA_PROTO_ICMPV6_TYPE]
569
0
                || !attrs[CTA_PROTO_ICMPV6_CODE]) {
570
0
                VLOG_ERR_RL(&rl, "Tuple ICMPv6 data missing.");
571
0
                return false;
572
0
            }
573
0
            tuple->icmp_id = nl_attr_get_be16(attrs[CTA_PROTO_ICMPV6_ID]);
574
0
            tuple->icmp_type = nl_attr_get_u8(attrs[CTA_PROTO_ICMPV6_TYPE]);
575
0
            tuple->icmp_code = nl_attr_get_u8(attrs[CTA_PROTO_ICMPV6_CODE]);
576
0
        } else if (attrs[CTA_PROTO_SRC_PORT] && attrs[CTA_PROTO_DST_PORT]) {
577
0
            tuple->src_port = nl_attr_get_be16(attrs[CTA_PROTO_SRC_PORT]);
578
0
            tuple->dst_port = nl_attr_get_be16(attrs[CTA_PROTO_DST_PORT]);
579
0
        } else {
580
            /* Unsupported IPPROTO and no ports, leave them zeroed.
581
             * We have parsed the ip_proto, so this is not a failure. */
582
0
            VLOG_DBG_RL(&rl, "Unsupported L4 protocol: %u.", tuple->ip_proto);
583
0
        }
584
0
    } else {
585
0
        VLOG_ERR_RL(&rl, "Could not parse nested tuple protocol options. "
586
0
                    "Possibly incompatible Linux kernel version.");
587
0
    }
588
589
0
    return parsed;
590
0
}
591
592
static bool
593
nl_ct_parse_tuple(struct nlattr *nla, struct ct_dpif_tuple *tuple,
594
                  uint16_t l3_type)
595
0
{
596
0
    static const struct nl_policy policy[] = {
597
0
        [CTA_TUPLE_IP] = { .type = NL_A_NESTED, .optional = false },
598
0
        [CTA_TUPLE_PROTO] = { .type = NL_A_NESTED, .optional = false },
599
0
    };
600
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
601
0
    bool parsed;
602
603
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
604
605
0
    memset(tuple, 0, sizeof *tuple);
606
607
0
    if (parsed) {
608
0
        tuple->l3_type = l3_type;
609
610
0
        if (!nl_ct_parse_tuple_ip(attrs[CTA_TUPLE_IP], tuple)
611
0
            || !nl_ct_parse_tuple_proto(attrs[CTA_TUPLE_PROTO], tuple)) {
612
0
            struct ds ds;
613
614
0
            ds_init(&ds);
615
0
            ct_dpif_format_tuple(&ds, tuple);
616
617
0
            VLOG_ERR_RL(&rl, "Failed to parse tuple: %s", ds_cstr(&ds));
618
0
            ds_destroy(&ds);
619
620
0
            memset(tuple, 0, sizeof *tuple);
621
0
            return false;
622
0
        }
623
0
    } else {
624
0
        VLOG_ERR_RL(&rl, "Could not parse nested tuple options. "
625
0
                    "Possibly incompatible Linux kernel version.");
626
0
    }
627
628
0
    return parsed;
629
0
}
630
631
static bool
632
nl_ct_put_tuple_ip(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple)
633
0
{
634
0
    size_t offset = nl_msg_start_nested(buf, CTA_TUPLE_IP);
635
636
0
    if (tuple->l3_type == AF_INET) {
637
0
        nl_msg_put_be32(buf, CTA_IP_V4_SRC, tuple->src.ip);
638
0
        nl_msg_put_be32(buf, CTA_IP_V4_DST, tuple->dst.ip);
639
0
    } else if (tuple->l3_type == AF_INET6) {
640
0
        nl_msg_put_in6_addr(buf, CTA_IP_V6_SRC, &tuple->src.in6);
641
0
        nl_msg_put_in6_addr(buf, CTA_IP_V6_DST, &tuple->dst.in6);
642
0
    } else {
643
0
        VLOG_WARN_RL(&rl, "Unsupported IP protocol: %"PRIu16".",
644
0
                     tuple->l3_type);
645
0
        return false;
646
0
    }
647
648
0
    nl_msg_end_nested(buf, offset);
649
0
    return true;
650
0
}
651
652
static bool
653
nl_ct_put_tuple_proto(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple)
654
0
{
655
0
    size_t offset = nl_msg_start_nested(buf, CTA_TUPLE_PROTO);
656
657
0
    nl_msg_put_u8(buf, CTA_PROTO_NUM, tuple->ip_proto);
658
659
0
    if (tuple->l3_type == AF_INET && tuple->ip_proto == IPPROTO_ICMP) {
660
0
        nl_msg_put_be16(buf, CTA_PROTO_ICMP_ID, tuple->icmp_id);
661
0
        nl_msg_put_u8(buf, CTA_PROTO_ICMP_TYPE, tuple->icmp_type);
662
0
        nl_msg_put_u8(buf, CTA_PROTO_ICMP_CODE, tuple->icmp_code);
663
0
    } else if (tuple->l3_type == AF_INET6 &&
664
0
               tuple->ip_proto == IPPROTO_ICMPV6) {
665
0
        nl_msg_put_be16(buf, CTA_PROTO_ICMPV6_ID, tuple->icmp_id);
666
0
        nl_msg_put_u8(buf, CTA_PROTO_ICMPV6_TYPE, tuple->icmp_type);
667
0
        nl_msg_put_u8(buf, CTA_PROTO_ICMPV6_CODE, tuple->icmp_code);
668
0
    } else if (tuple->ip_proto == IPPROTO_TCP ||
669
0
               tuple->ip_proto == IPPROTO_UDP ||
670
0
               tuple->ip_proto == IPPROTO_SCTP) {
671
0
        nl_msg_put_be16(buf, CTA_PROTO_SRC_PORT, tuple->src_port);
672
0
        nl_msg_put_be16(buf, CTA_PROTO_DST_PORT, tuple->dst_port);
673
0
    } else {
674
0
        VLOG_WARN_RL(&rl, "Unsupported L4 protocol: %"PRIu8".",
675
0
                     tuple->ip_proto);
676
0
        return false;
677
0
    }
678
679
0
    nl_msg_end_nested(buf, offset);
680
0
    return true;
681
0
}
682
683
static bool
684
nl_ct_put_ct_tuple(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple,
685
                   enum ctattr_type type)
686
0
{
687
0
    if (type != CTA_TUPLE_ORIG && type != CTA_TUPLE_REPLY &&
688
0
        type != CTA_TUPLE_MASTER) {
689
0
        return false;
690
0
    }
691
692
0
    size_t offset = nl_msg_start_nested(buf, type);
693
694
0
    if (!nl_ct_put_tuple_ip(buf, tuple)) {
695
0
        return false;
696
0
    }
697
0
    if (!nl_ct_put_tuple_proto(buf, tuple)) {
698
0
        return false;
699
0
    }
700
701
0
    nl_msg_end_nested(buf, offset);
702
0
    return true;
703
0
}
704
705
/* Translate netlink TCP state to CT_DPIF_TCP state. */
706
static uint8_t
707
nl_ct_tcp_state_to_dpif(uint8_t state)
708
0
{
709
0
    switch (state) {
710
0
    case TCP_CONNTRACK_NONE:
711
0
        return CT_DPIF_TCPS_CLOSED;
712
0
    case TCP_CONNTRACK_SYN_SENT:
713
0
        return CT_DPIF_TCPS_SYN_SENT;
714
0
    case TCP_CONNTRACK_SYN_SENT2:
715
0
        return CT_DPIF_TCPS_SYN_SENT;
716
0
    case TCP_CONNTRACK_SYN_RECV:
717
0
        return CT_DPIF_TCPS_SYN_RECV;
718
0
    case TCP_CONNTRACK_ESTABLISHED:
719
0
        return CT_DPIF_TCPS_ESTABLISHED;
720
0
    case TCP_CONNTRACK_FIN_WAIT:
721
0
        return CT_DPIF_TCPS_FIN_WAIT_1;
722
0
    case TCP_CONNTRACK_CLOSE_WAIT:
723
0
        return CT_DPIF_TCPS_CLOSE_WAIT;
724
0
    case TCP_CONNTRACK_LAST_ACK:
725
0
        return CT_DPIF_TCPS_LAST_ACK;
726
0
    case TCP_CONNTRACK_TIME_WAIT:
727
0
        return CT_DPIF_TCPS_TIME_WAIT;
728
0
    case TCP_CONNTRACK_CLOSE:
729
0
        return CT_DPIF_TCPS_CLOSING;
730
0
    default:
731
0
        return CT_DPIF_TCPS_CLOSED;
732
0
    }
733
0
}
734
735
static uint8_t
736
ip_ct_tcp_flags_to_dpif(uint8_t flags)
737
0
{
738
0
    uint8_t ret = 0;
739
0
#define CT_DPIF_TCP_FLAG(FLAG) \
740
0
        ret |= (flags & IP_CT_TCP_FLAG_##FLAG) ? CT_DPIF_TCPF_##FLAG : 0;
741
0
    CT_DPIF_TCP_FLAGS
742
0
#undef CT_DPIF_TCP_FLAG
743
0
    return ret;
744
0
}
745
746
static bool
747
nl_ct_parse_protoinfo_tcp(struct nlattr *nla,
748
                          struct ct_dpif_protoinfo *protoinfo)
749
0
{
750
0
    static const struct nl_policy policy[] = {
751
0
        [CTA_PROTOINFO_TCP_STATE] = { .type = NL_A_U8, .optional = false },
752
0
        [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NL_A_U8,
753
0
                                                .optional = true },
754
0
        [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NL_A_U8,
755
0
                                             .optional = true },
756
0
        [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .type = NL_A_U16,
757
0
                                               .optional = true },
758
0
        [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .type = NL_A_U16,
759
0
                                            .optional = true },
760
0
    };
761
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
762
0
    bool parsed;
763
764
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
765
766
0
    if (parsed) {
767
0
        const struct nf_ct_tcp_flags *flags_orig, *flags_reply;
768
0
        uint8_t state;
769
0
        protoinfo->proto = IPPROTO_TCP;
770
0
        state = nl_ct_tcp_state_to_dpif(
771
0
            nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_STATE]));
772
        /* The connection tracker keeps only one tcp state for the
773
         * connection, but our structures store a separate state for
774
         * each endpoint.  Here we duplicate the state. */
775
0
        protoinfo->tcp.state_orig = protoinfo->tcp.state_reply = state;
776
777
0
        if (attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]) {
778
0
            protoinfo->tcp.wscale_orig =
779
0
                nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
780
0
        }
781
0
        if (attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]) {
782
0
            protoinfo->tcp.wscale_reply =
783
0
                nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
784
0
        }
785
0
        if (attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) {
786
0
            flags_orig =
787
0
                nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL],
788
0
                                   sizeof *flags_orig);
789
0
            protoinfo->tcp.flags_orig =
790
0
                ip_ct_tcp_flags_to_dpif(flags_orig->flags);
791
0
        }
792
0
        if (attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY]) {
793
0
            flags_reply =
794
0
                nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY],
795
0
                                   sizeof *flags_reply);
796
0
            protoinfo->tcp.flags_reply =
797
0
                ip_ct_tcp_flags_to_dpif(flags_reply->flags);
798
0
        }
799
0
    } else {
800
0
        VLOG_ERR_RL(&rl, "Could not parse nested TCP protoinfo options. "
801
0
                    "Possibly incompatible Linux kernel version.");
802
0
    }
803
804
0
    return parsed;
805
0
}
806
807
/* Translate netlink SCTP state to CT_DPIF_SCTP state. */
808
static uint8_t
809
nl_ct_sctp_state_to_dpif(uint8_t state)
810
0
{
811
0
    switch (state) {
812
0
    case SCTP_CONNTRACK_COOKIE_WAIT:
813
0
        return CT_DPIF_SCTP_STATE_COOKIE_WAIT;
814
0
    case SCTP_CONNTRACK_COOKIE_ECHOED:
815
0
        return CT_DPIF_SCTP_STATE_COOKIE_ECHOED;
816
0
    case SCTP_CONNTRACK_ESTABLISHED:
817
0
        return CT_DPIF_SCTP_STATE_ESTABLISHED;
818
0
    case SCTP_CONNTRACK_SHUTDOWN_SENT:
819
0
        return CT_DPIF_SCTP_STATE_SHUTDOWN_SENT;
820
0
    case SCTP_CONNTRACK_SHUTDOWN_RECD:
821
0
        return CT_DPIF_SCTP_STATE_SHUTDOWN_RECD;
822
0
    case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
823
0
        return CT_DPIF_SCTP_STATE_SHUTDOWN_ACK_SENT;
824
0
    case SCTP_CONNTRACK_HEARTBEAT_SENT:
825
0
        return CT_DPIF_SCTP_STATE_HEARTBEAT_SENT;
826
0
    case SCTP_CONNTRACK_HEARTBEAT_ACKED:
827
0
        return CT_DPIF_SCTP_STATE_HEARTBEAT_ACKED;
828
0
    case SCTP_CONNTRACK_CLOSED:
829
        /* Fall Through. */
830
0
    case SCTP_CONNTRACK_NONE:
831
        /* Fall Through. */
832
0
    default:
833
0
        return CT_DPIF_SCTP_STATE_CLOSED;
834
0
    }
835
0
}
836
837
static bool
838
nl_ct_parse_protoinfo_sctp(struct nlattr *nla,
839
                           struct ct_dpif_protoinfo *protoinfo)
840
0
{
841
0
    static const struct nl_policy policy[] = {
842
0
        [CTA_PROTOINFO_SCTP_STATE] = { .type = NL_A_U8, .optional = false },
843
0
        [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NL_A_U32,
844
0
                                               .optional = false },
845
0
        [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NL_A_U32,
846
0
                                            .optional = false },
847
0
    };
848
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
849
0
    bool parsed;
850
851
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
852
0
    if (parsed) {
853
0
        protoinfo->proto = IPPROTO_SCTP;
854
855
0
        protoinfo->sctp.state = nl_ct_sctp_state_to_dpif(
856
0
            nl_attr_get_u8(attrs[CTA_PROTOINFO_SCTP_STATE]));
857
0
        protoinfo->sctp.vtag_orig = nl_attr_get_u32(
858
0
            attrs[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]);
859
0
        protoinfo->sctp.vtag_reply = nl_attr_get_u32(
860
0
            attrs[CTA_PROTOINFO_SCTP_VTAG_REPLY]);
861
0
    } else {
862
0
        VLOG_ERR_RL(&rl, "Could not parse nested SCTP protoinfo options. "
863
0
                    "Possibly incompatible Linux kernel version.");
864
0
    }
865
866
0
    return parsed;
867
0
}
868
869
static bool
870
nl_ct_parse_protoinfo(struct nlattr *nla, struct ct_dpif_protoinfo *protoinfo)
871
0
{
872
    /* These are mutually exclusive. */
873
0
    static const struct nl_policy policy[] = {
874
0
        [CTA_PROTOINFO_TCP] = { .type = NL_A_NESTED, .optional = true },
875
0
        [CTA_PROTOINFO_SCTP] = { .type = NL_A_NESTED, .optional = true },
876
0
    };
877
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
878
0
    bool parsed;
879
880
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
881
882
0
    memset(protoinfo, 0, sizeof *protoinfo);
883
884
0
    if (parsed) {
885
0
        if (attrs[CTA_PROTOINFO_TCP]) {
886
0
            parsed = nl_ct_parse_protoinfo_tcp(attrs[CTA_PROTOINFO_TCP],
887
0
                                               protoinfo);
888
0
        } else if (attrs[CTA_PROTOINFO_SCTP]) {
889
0
            parsed = nl_ct_parse_protoinfo_sctp(attrs[CTA_PROTOINFO_SCTP],
890
0
                                                protoinfo);
891
0
        } else {
892
0
            VLOG_WARN_RL(&rl, "Empty protoinfo!");
893
0
        }
894
0
    } else {
895
0
        VLOG_ERR_RL(&rl, "Could not parse nested protoinfo options. "
896
0
                    "Possibly incompatible Linux kernel version.");
897
0
    }
898
899
0
    return parsed;
900
0
}
901
902
static bool
903
nl_ct_parse_helper(struct nlattr *nla, struct ct_dpif_helper *helper)
904
0
{
905
0
    static const struct nl_policy policy[] = {
906
0
        [CTA_HELP_NAME] = { .type = NL_A_STRING, .optional = false },
907
0
    };
908
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
909
0
    bool parsed;
910
911
0
    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));
912
913
0
    memset(helper, 0, sizeof *helper);
914
915
0
    if (parsed) {
916
0
        helper->name = xstrdup(nl_attr_get_string(attrs[CTA_HELP_NAME]));
917
0
    } else {
918
0
        VLOG_ERR_RL(&rl, "Could not parse nested helper options. "
919
0
                    "Possibly incompatible Linux kernel version.");
920
0
    }
921
922
0
    return parsed;
923
0
}
924
925
static int nl_ct_timeout_policy_max_attr[] = {
926
    [IPPROTO_TCP] = CTA_TIMEOUT_TCP_MAX,
927
    [IPPROTO_UDP] = CTA_TIMEOUT_UDP_MAX,
928
    [IPPROTO_ICMP] = CTA_TIMEOUT_ICMP_MAX,
929
    [IPPROTO_ICMPV6] = CTA_TIMEOUT_ICMPV6_MAX
930
};
931
932
static void
933
nl_ct_set_timeout_policy_attr(struct nl_ct_timeout_policy *nl_tp,
934
                              uint32_t attr, uint32_t val)
935
0
{
936
0
    nl_tp->present |= 1 << attr;
937
0
    nl_tp->attrs[attr] = val;
938
0
}
939
940
static int
941
nl_ct_parse_tcp_timeout_policy_data(struct nlattr *nla,
942
                                    struct nl_ct_timeout_policy *nl_tp)
943
0
{
944
0
    static const struct nl_policy policy[] = {
945
0
        [CTA_TIMEOUT_TCP_SYN_SENT] =    { .type = NL_A_BE32,
946
0
                                          .optional = false },
947
0
        [CTA_TIMEOUT_TCP_SYN_RECV] =    { .type = NL_A_BE32,
948
0
                                          .optional = false },
949
0
        [CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NL_A_BE32,
950
0
                                          .optional = false },
951
0
        [CTA_TIMEOUT_TCP_FIN_WAIT] =    { .type = NL_A_BE32,
952
0
                                          .optional = false },
953
0
        [CTA_TIMEOUT_TCP_CLOSE_WAIT] =  { .type = NL_A_BE32,
954
0
                                          .optional = false },
955
0
        [CTA_TIMEOUT_TCP_LAST_ACK] =    { .type = NL_A_BE32,
956
0
                                          .optional = false },
957
0
        [CTA_TIMEOUT_TCP_TIME_WAIT] =   { .type = NL_A_BE32,
958
0
                                          .optional = false },
959
0
        [CTA_TIMEOUT_TCP_CLOSE] =       { .type = NL_A_BE32,
960
0
                                          .optional = false },
961
0
        [CTA_TIMEOUT_TCP_SYN_SENT2] =   { .type = NL_A_BE32,
962
0
                                          .optional = false },
963
0
        [CTA_TIMEOUT_TCP_RETRANS] =     { .type = NL_A_BE32,
964
0
                                          .optional = false },
965
0
        [CTA_TIMEOUT_TCP_UNACK] =       { .type = NL_A_BE32,
966
0
                                          .optional = false },
967
0
    };
968
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
969
970
0
    if (!nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy))) {
971
0
        VLOG_ERR_RL(&rl, "Could not parse nested tcp timeout options. "
972
0
                    "Possibly incompatible Linux kernel version.");
973
0
        return EINVAL;
974
0
    }
975
976
0
    for (int i = CTA_TIMEOUT_TCP_SYN_SENT; i <= CTA_TIMEOUT_TCP_UNACK; i++) {
977
0
        nl_ct_set_timeout_policy_attr(nl_tp, i,
978
0
                                      ntohl(nl_attr_get_be32(attrs[i])));
979
0
    }
980
0
    return 0;
981
0
}
982
983
static int
984
nl_ct_parse_udp_timeout_policy_data(struct nlattr *nla,
985
                                    struct nl_ct_timeout_policy *nl_tp)
986
0
{
987
0
    static const struct nl_policy policy[] = {
988
0
        [CTA_TIMEOUT_UDP_UNREPLIED] =   { .type = NL_A_BE32,
989
0
                                          .optional = false },
990
0
        [CTA_TIMEOUT_UDP_REPLIED] =     { .type = NL_A_BE32,
991
0
                                          .optional = false },
992
0
    };
993
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
994
995
0
    if (!nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy))) {
996
0
        VLOG_ERR_RL(&rl, "Could not parse nested tcp timeout options. "
997
0
                    "Possibly incompatible Linux kernel version.");
998
0
        return EINVAL;
999
0
    }
1000
1001
0
    for (int i = CTA_TIMEOUT_UDP_UNREPLIED; i <= CTA_TIMEOUT_UDP_REPLIED;
1002
0
         i++) {
1003
0
        nl_ct_set_timeout_policy_attr(nl_tp, i,
1004
0
                                      ntohl(nl_attr_get_be32(attrs[i])));
1005
0
    }
1006
0
    return 0;
1007
0
}
1008
1009
static int
1010
nl_ct_parse_icmp_timeout_policy_data(struct nlattr *nla,
1011
                                     struct nl_ct_timeout_policy *nl_tp)
1012
0
{
1013
0
    static const struct nl_policy policy[] = {
1014
0
        [CTA_TIMEOUT_ICMP_TIMEOUT] =   { .type = NL_A_BE32,
1015
0
                                         .optional = false },
1016
0
    };
1017
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
1018
1019
0
    if (!nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy))) {
1020
0
        VLOG_ERR_RL(&rl, "Could not parse nested icmp timeout options. "
1021
0
                    "Possibly incompatible Linux kernel version.");
1022
0
        return EINVAL;
1023
0
    }
1024
1025
0
    nl_ct_set_timeout_policy_attr(
1026
0
        nl_tp, CTA_TIMEOUT_ICMP_TIMEOUT,
1027
0
        ntohl(nl_attr_get_be32(attrs[CTA_TIMEOUT_ICMP_TIMEOUT])));
1028
0
    return 0;
1029
0
}
1030
1031
static int
1032
nl_ct_parse_icmpv6_timeout_policy_data(struct nlattr *nla,
1033
                                       struct nl_ct_timeout_policy *nl_tp)
1034
0
{
1035
0
    static const struct nl_policy policy[] = {
1036
0
        [CTA_TIMEOUT_ICMPV6_TIMEOUT] =   { .type = NL_A_BE32,
1037
0
                                           .optional = false },
1038
0
    };
1039
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
1040
1041
0
    if (!nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy))) {
1042
0
        VLOG_ERR_RL(&rl, "Could not parse nested icmpv6 timeout options. "
1043
0
                    "Possibly incompatible Linux kernel version.");
1044
0
        return EINVAL;
1045
0
    }
1046
1047
0
    nl_ct_set_timeout_policy_attr(
1048
0
        nl_tp, CTA_TIMEOUT_ICMPV6_TIMEOUT,
1049
0
        ntohl(nl_attr_get_be32(attrs[CTA_TIMEOUT_ICMPV6_TIMEOUT])));
1050
0
    return 0;
1051
0
}
1052
1053
static int
1054
nl_ct_parse_timeout_policy_data(struct nlattr *nla,
1055
                                struct nl_ct_timeout_policy *nl_tp)
1056
0
{
1057
0
    switch (nl_tp->l4num) {
1058
0
        case IPPROTO_TCP:
1059
0
            return nl_ct_parse_tcp_timeout_policy_data(nla, nl_tp);
1060
0
        case IPPROTO_UDP:
1061
0
            return nl_ct_parse_udp_timeout_policy_data(nla, nl_tp);
1062
0
        case IPPROTO_ICMP:
1063
0
            return nl_ct_parse_icmp_timeout_policy_data(nla, nl_tp);
1064
0
        case IPPROTO_ICMPV6:
1065
0
            return nl_ct_parse_icmpv6_timeout_policy_data(nla, nl_tp);
1066
0
        default:
1067
0
            return EINVAL;
1068
0
    }
1069
0
}
1070
1071
static int
1072
nl_ct_timeout_policy_from_ofpbuf(struct ofpbuf *buf,
1073
                                 struct nl_ct_timeout_policy *nl_tp,
1074
                                 bool default_tp)
1075
0
{
1076
0
    static const struct nl_policy policy[] = {
1077
0
        [CTA_TIMEOUT_NAME] =    { .type = NL_A_STRING, .optional = false },
1078
0
        [CTA_TIMEOUT_L3PROTO] = { .type = NL_A_BE16, .optional = false },
1079
0
        [CTA_TIMEOUT_L4PROTO] = { .type = NL_A_U8, .optional = false },
1080
0
        [CTA_TIMEOUT_DATA] =    { .type = NL_A_NESTED, .optional = false }
1081
0
    };
1082
0
    static const struct nl_policy policy_default_tp[] = {
1083
0
        [CTA_TIMEOUT_L3PROTO] = { .type = NL_A_BE16, .optional = false },
1084
0
        [CTA_TIMEOUT_L4PROTO] = { .type = NL_A_U8, .optional = false },
1085
0
        [CTA_TIMEOUT_DATA] =    { .type = NL_A_NESTED, .optional = false }
1086
0
    };
1087
1088
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
1089
0
    struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
1090
0
    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
1091
0
    struct nfgenmsg *nfmsg = ofpbuf_try_pull(&b, sizeof *nfmsg);
1092
1093
0
    if (!nlmsg || !nfmsg
1094
0
        || NFNL_SUBSYS_ID(nlmsg->nlmsg_type) != NFNL_SUBSYS_CTNETLINK_TIMEOUT
1095
0
        || nfmsg->version != NFNETLINK_V0
1096
0
        || !nl_policy_parse(&b, 0, default_tp ? policy_default_tp : policy,
1097
0
                            attrs, default_tp ? ARRAY_SIZE(policy_default_tp) :
1098
0
                                                ARRAY_SIZE(policy))) {
1099
0
        return EINVAL;
1100
0
    }
1101
1102
0
    if (!default_tp) {
1103
0
        ovs_strlcpy(nl_tp->name, nl_attr_get_string(attrs[CTA_TIMEOUT_NAME]),
1104
0
                    sizeof nl_tp->name);
1105
0
    }
1106
0
    nl_tp->l3num = ntohs(nl_attr_get_be16(attrs[CTA_TIMEOUT_L3PROTO]));
1107
0
    nl_tp->l4num = nl_attr_get_u8(attrs[CTA_TIMEOUT_L4PROTO]);
1108
0
    nl_tp->present = 0;
1109
1110
0
    return nl_ct_parse_timeout_policy_data(attrs[CTA_TIMEOUT_DATA], nl_tp);
1111
0
}
1112
1113
int
1114
nl_ct_set_timeout_policy(const struct nl_ct_timeout_policy *nl_tp)
1115
0
{
1116
0
    struct ofpbuf buf;
1117
0
    size_t offset;
1118
1119
0
    ofpbuf_init(&buf, 512);
1120
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK_TIMEOUT,
1121
0
                        IPCTNL_MSG_TIMEOUT_NEW, NLM_F_REQUEST | NLM_F_CREATE
1122
0
                        | NLM_F_ACK | NLM_F_REPLACE);
1123
1124
0
    nl_msg_put_string(&buf, CTA_TIMEOUT_NAME, nl_tp->name);
1125
0
    nl_msg_put_be16(&buf, CTA_TIMEOUT_L3PROTO, htons(nl_tp->l3num));
1126
0
    nl_msg_put_u8(&buf, CTA_TIMEOUT_L4PROTO, nl_tp->l4num);
1127
1128
0
    offset = nl_msg_start_nested(&buf, CTA_TIMEOUT_DATA);
1129
0
    for (int i = 1; i <= nl_ct_timeout_policy_max_attr[nl_tp->l4num]; ++i) {
1130
0
        if (nl_tp->present & 1 << i) {
1131
0
            nl_msg_put_be32(&buf, i, htonl(nl_tp->attrs[i]));
1132
0
        }
1133
0
    }
1134
0
    nl_msg_end_nested(&buf, offset);
1135
1136
0
    int err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
1137
0
    ofpbuf_uninit(&buf);
1138
0
    return err;
1139
0
}
1140
1141
int
1142
nl_ct_get_timeout_policy(const char *tp_name,
1143
                         struct nl_ct_timeout_policy *nl_tp)
1144
0
{
1145
0
    struct ofpbuf request, *reply;
1146
1147
0
    ofpbuf_init(&request, 512);
1148
0
    nl_msg_put_nfgenmsg(&request, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK_TIMEOUT,
1149
0
                        IPCTNL_MSG_TIMEOUT_GET, NLM_F_REQUEST | NLM_F_ACK);
1150
0
    nl_msg_put_string(&request, CTA_TIMEOUT_NAME, tp_name);
1151
0
    int err = nl_transact(NETLINK_NETFILTER, &request, &reply);
1152
0
    if (err) {
1153
0
        goto out;
1154
0
    }
1155
1156
0
    err = nl_ct_timeout_policy_from_ofpbuf(reply, nl_tp, false);
1157
1158
0
out:
1159
0
    ofpbuf_uninit(&request);
1160
0
    ofpbuf_delete(reply);
1161
0
    return err;
1162
0
}
1163
1164
int
1165
nl_ct_del_timeout_policy(const char *tp_name)
1166
0
{
1167
0
    struct ofpbuf buf;
1168
1169
0
    ofpbuf_init(&buf, 64);
1170
0
    nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK_TIMEOUT,
1171
0
                        IPCTNL_MSG_TIMEOUT_DELETE, NLM_F_REQUEST | NLM_F_ACK);
1172
1173
0
    nl_msg_put_string(&buf, CTA_TIMEOUT_NAME, tp_name);
1174
0
    int err = nl_transact(NETLINK_NETFILTER, &buf, NULL);
1175
0
    ofpbuf_uninit(&buf);
1176
0
    return err;
1177
0
}
1178
1179
struct nl_ct_timeout_policy_dump_state {
1180
    struct nl_dump dump;
1181
    struct ofpbuf buf;
1182
};
1183
1184
int
1185
nl_ct_timeout_policy_dump_start(
1186
    struct nl_ct_timeout_policy_dump_state **statep)
1187
0
{
1188
0
    struct ofpbuf request;
1189
0
    struct nl_ct_timeout_policy_dump_state *state;
1190
1191
0
    *statep = state = xzalloc(sizeof *state);
1192
0
    ofpbuf_init(&request, 512);
1193
0
    nl_msg_put_nfgenmsg(&request, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK_TIMEOUT,
1194
0
                        IPCTNL_MSG_TIMEOUT_GET,
1195
0
                        NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
1196
1197
0
    nl_dump_start(&state->dump, NETLINK_NETFILTER, &request);
1198
0
    ofpbuf_uninit(&request);
1199
0
    ofpbuf_init(&state->buf, NL_DUMP_BUFSIZE);
1200
0
    return 0;
1201
0
}
1202
1203
int
1204
nl_ct_timeout_policy_dump_next(struct nl_ct_timeout_policy_dump_state *state,
1205
                               struct nl_ct_timeout_policy *nl_tp)
1206
0
{
1207
0
    struct ofpbuf reply;
1208
1209
0
    if (!nl_dump_next(&state->dump, &reply, &state->buf)) {
1210
0
        return EOF;
1211
0
    }
1212
0
    int err = nl_ct_timeout_policy_from_ofpbuf(&reply, nl_tp, false);
1213
0
    ofpbuf_uninit(&reply);
1214
0
    return err;
1215
0
}
1216
1217
int
1218
nl_ct_timeout_policy_dump_done(struct nl_ct_timeout_policy_dump_state *state)
1219
0
{
1220
0
    int err  = nl_dump_done(&state->dump);
1221
0
    ofpbuf_uninit(&state->buf);
1222
0
    free(state);
1223
0
    return err;
1224
0
}
1225
1226
/* Translate netlink entry status flags to CT_DPIF_TCP status flags. */
1227
static uint32_t
1228
ips_status_to_dpif_flags(uint32_t status)
1229
0
{
1230
0
    uint32_t ret = 0;
1231
0
#define CT_DPIF_STATUS_FLAG(FLAG) \
1232
0
        ret |= (status & IPS_##FLAG) ? CT_DPIF_STATUS_##FLAG : 0;
1233
0
    CT_DPIF_STATUS_FLAGS
1234
0
#undef CT_DPIF_STATUS_FLAG
1235
0
    return ret;
1236
0
}
1237
1238
static bool
1239
nl_ct_parse_header_policy(struct ofpbuf *buf,
1240
        enum nl_ct_event_type *event_type,
1241
        uint8_t *nfgen_family,
1242
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)])
1243
0
{
1244
0
    struct nlmsghdr *nlh;
1245
0
    struct nfgenmsg *nfm;
1246
0
    uint8_t type;
1247
1248
0
    nlh = ofpbuf_at(buf, 0, NLMSG_HDRLEN);
1249
0
    nfm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *nfm);
1250
0
    if (!nfm) {
1251
0
        VLOG_ERR_RL(&rl, "Received bad nfnl message (no nfgenmsg).");
1252
0
        return false;
1253
0
    }
1254
0
    if (NFNL_SUBSYS_ID(nlh->nlmsg_type) != NFNL_SUBSYS_CTNETLINK) {
1255
0
        VLOG_ERR_RL(&rl, "Received non-conntrack message (subsystem: %u).",
1256
0
                 NFNL_SUBSYS_ID(nlh->nlmsg_type));
1257
0
        return false;
1258
0
    }
1259
0
    if (nfm->version != NFNETLINK_V0) {
1260
0
        VLOG_ERR_RL(&rl, "Received unsupported nfnetlink version (%u).",
1261
0
                 NFNL_MSG_TYPE(nfm->version));
1262
0
        return false;
1263
0
    }
1264
1265
0
    if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof *nfm,
1266
0
                         nfnlgrp_conntrack_policy, attrs,
1267
0
                         ARRAY_SIZE(nfnlgrp_conntrack_policy))) {
1268
0
        VLOG_ERR_RL(&rl, "Received bad nfnl message (policy).");
1269
0
        return false;
1270
0
    }
1271
1272
0
    type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1273
0
    *nfgen_family = nfm->nfgen_family;
1274
1275
0
    switch (type) {
1276
0
    case IPCTNL_MSG_CT_NEW:
1277
0
        *event_type = nlh->nlmsg_flags & NLM_F_CREATE
1278
0
            ? NL_CT_EVENT_NEW : NL_CT_EVENT_UPDATE;
1279
0
        break;
1280
0
    case IPCTNL_MSG_CT_DELETE:
1281
0
        *event_type = NL_CT_EVENT_DELETE;
1282
0
        break;
1283
0
    default:
1284
0
        VLOG_ERR_RL(&rl, "Can't parse conntrack event type.");
1285
0
        return false;
1286
0
    }
1287
1288
0
    return true;
1289
0
}
1290
1291
static bool
1292
nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry,
1293
        struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)],
1294
        uint8_t nfgen_family)
1295
0
{
1296
0
    if (!nl_ct_parse_tuple(attrs[CTA_TUPLE_ORIG], &entry->tuple_orig,
1297
0
                           nfgen_family)) {
1298
0
        return false;
1299
0
    }
1300
0
    if (!nl_ct_parse_tuple(attrs[CTA_TUPLE_REPLY], &entry->tuple_reply,
1301
0
                           nfgen_family)) {
1302
0
        return false;
1303
0
    }
1304
0
    if (attrs[CTA_COUNTERS_ORIG] &&
1305
0
        !nl_ct_parse_counters(attrs[CTA_COUNTERS_ORIG],
1306
0
                              &entry->counters_orig)) {
1307
0
        return false;
1308
0
    }
1309
0
    if (attrs[CTA_COUNTERS_REPLY] &&
1310
0
        !nl_ct_parse_counters(attrs[CTA_COUNTERS_REPLY],
1311
0
                              &entry->counters_reply)) {
1312
0
        return false;
1313
0
    }
1314
0
    if (attrs[CTA_TIMESTAMP] &&
1315
0
        !nl_ct_parse_timestamp(attrs[CTA_TIMESTAMP], &entry->timestamp)) {
1316
0
        return false;
1317
0
    }
1318
0
    if (attrs[CTA_ID]) {
1319
0
        entry->id = ntohl(nl_attr_get_be32(attrs[CTA_ID]));
1320
0
    }
1321
0
    if (attrs[CTA_ZONE]) {
1322
0
        entry->zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE]));
1323
0
    }
1324
0
    if (attrs[CTA_STATUS]) {
1325
0
        entry->status = ips_status_to_dpif_flags(
1326
0
            ntohl(nl_attr_get_be32(attrs[CTA_STATUS])));
1327
0
    }
1328
0
    if (attrs[CTA_TIMEOUT]) {
1329
0
        entry->timeout = ntohl(nl_attr_get_be32(attrs[CTA_TIMEOUT]));
1330
0
    }
1331
0
    if (attrs[CTA_MARK]) {
1332
0
        entry->mark = ntohl(nl_attr_get_be32(attrs[CTA_MARK]));
1333
0
    }
1334
0
    if (attrs[CTA_LABELS]) {
1335
0
        entry->have_labels = true;
1336
0
        memcpy(&entry->labels, nl_attr_get(attrs[CTA_LABELS]),
1337
0
               MIN(sizeof entry->labels, nl_attr_get_size(attrs[CTA_LABELS])));
1338
0
    }
1339
0
    if (attrs[CTA_PROTOINFO] &&
1340
0
        !nl_ct_parse_protoinfo(attrs[CTA_PROTOINFO], &entry->protoinfo)) {
1341
0
        return false;
1342
0
    }
1343
0
    if (attrs[CTA_HELP] &&
1344
0
        !nl_ct_parse_helper(attrs[CTA_HELP], &entry->helper)) {
1345
0
        return false;
1346
0
    }
1347
0
    if (attrs[CTA_TUPLE_MASTER] &&
1348
0
        !nl_ct_parse_tuple(attrs[CTA_TUPLE_MASTER], &entry->tuple_parent,
1349
0
                           nfgen_family)) {
1350
0
        return false;
1351
0
    }
1352
0
    return true;
1353
0
}
1354
1355
bool
1356
nl_ct_parse_entry(struct ofpbuf *buf, struct ct_dpif_entry *entry,
1357
                  enum nl_ct_event_type *event_type)
1358
0
{
1359
0
    struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)];
1360
0
    uint8_t nfgen_family;
1361
1362
0
    memset(entry, 0, sizeof *entry);
1363
0
    if (!nl_ct_parse_header_policy(buf, event_type, &nfgen_family, attrs)) {
1364
0
        return false;
1365
0
    };
1366
1367
0
    if (!nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) {
1368
0
        ct_dpif_entry_uninit(entry);
1369
0
        memset(entry, 0, sizeof *entry);
1370
0
        return false;
1371
0
    }
1372
1373
0
    return true;
1374
0
}
1375
1376
/* NetFilter utility functions. */
1377
1378
/* Puts a nlmsghdr and nfgenmsg at the beginning of 'msg', which must be
1379
 * initially empty.  'expected_payload' should be an estimate of the number of
1380
 * payload bytes to be supplied; if the size of the payload is unknown a value
1381
 * of 0 is acceptable.
1382
 *
1383
 * Non-zero 'family' is the address family of items to get (e.g. AF_INET).
1384
 *
1385
 * 'flags' is a bit-mask that indicates what kind of request is being made.  It
1386
 * is often NLM_F_REQUEST indicating that a request is being made, commonly
1387
 * or'd with NLM_F_ACK to request an acknowledgement.  NLM_F_DUMP flag reguests
1388
 * a dump of the table.
1389
 *
1390
 * 'subsystem' is a netfilter subsystem id, e.g., NFNL_SUBSYS_CTNETLINK.
1391
 *
1392
 * 'cmd' is an enumerated value specific to the 'subsystem'.
1393
 *
1394
 * Sets the new nlmsghdr's nlmsg_pid field to 0 for now.  nl_sock_send() will
1395
 * fill it in just before sending the message.
1396
 *
1397
 * nl_msg_put_nlmsghdr() should be used to compose Netlink messages that are
1398
 * not NetFilter Netlink messages. */
1399
static void
1400
nl_msg_put_nfgenmsg(struct ofpbuf *msg, size_t expected_payload,
1401
                    int family, uint8_t subsystem, uint8_t cmd,
1402
                    uint32_t flags)
1403
0
{
1404
0
    struct nfgenmsg *nfm;
1405
1406
0
    nl_msg_put_nlmsghdr(msg, sizeof *nfm + expected_payload,
1407
0
                        subsystem << 8 | cmd, flags);
1408
0
    ovs_assert(msg->size == NLMSG_HDRLEN);
1409
0
    nfm = nl_msg_put_uninit(msg, sizeof *nfm);
1410
0
    nfm->nfgen_family = family;
1411
    nfm->version = NFNETLINK_V0;
1412
0
    nfm->res_id = 0;
1413
0
}