dpif-netlink: add GENEVE creation support
[cascardo/ovs.git] / tests / test-netlink-conntrack.c
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 <linux/netfilter/nfnetlink.h>
20
21 #include "ct-dpif.h"
22 #include "netlink-conntrack.h"
23 #include "netlink-notifier.h"
24 #include "ovstest.h"
25 #include "poll-loop.h"
26
27 /* Monitor command */
28 struct test_change {
29     enum nl_ct_event_type type;
30     struct ct_dpif_entry entry;
31 };
32
33 static int
34 event_parse(struct ofpbuf *buf, void *change_)
35 {
36     struct test_change *change = change_;
37
38     if (nl_ct_parse_entry(buf, &change->entry, &change->type)) {
39         switch (change->type) {
40         case NL_CT_EVENT_NEW:
41             return NFNLGRP_CONNTRACK_NEW;
42         case NL_CT_EVENT_UPDATE:
43             return NFNLGRP_CONNTRACK_UPDATE;
44         case NL_CT_EVENT_DELETE:
45             return NFNLGRP_CONNTRACK_DESTROY;
46         }
47     }
48     return 0;
49 }
50
51 static void
52 event_print(const void *change_, void *aux OVS_UNUSED)
53 {
54     const struct test_change *change = change_;
55
56     if (change) {
57         struct ds ds = DS_EMPTY_INITIALIZER;
58
59         nl_ct_format_event_entry(&change->entry, change->type, &ds, true,
60                                  true);
61         printf("%s\n", ds_cstr(&ds));
62         ds_destroy(&ds);
63     }
64 }
65
66 static void
67 test_nl_ct_monitor(struct ovs_cmdl_context *ctx OVS_UNUSED)
68 {
69     int groups [] = {
70         NFNLGRP_CONNTRACK_DESTROY,
71         NFNLGRP_CONNTRACK_NEW,
72         NFNLGRP_CONNTRACK_UPDATE,
73     };
74
75     struct nln *nln;
76     struct nln_notifier *notifiers[ARRAY_SIZE(groups)];
77
78     struct test_change change;
79
80     unsigned i;
81
82     nln = nln_create(NETLINK_NETFILTER, event_parse, &change);
83
84     for (i = 0; i < ARRAY_SIZE(groups); i++) {
85         notifiers[i] = nln_notifier_create(nln, groups[i], event_print, NULL);
86     }
87
88     for (;;) {
89         nln_run(nln);
90         nln_wait(nln);
91         poll_block();
92     }
93
94     for (i = 0; i < ARRAY_SIZE(groups); i++) {
95         nln_notifier_destroy(notifiers[i]);
96     }
97     nln_destroy(nln);
98 }
99 \f
100 /* Dump command */
101 static void
102 test_nl_ct_dump(struct ovs_cmdl_context *ctx)
103 {
104     struct nl_ct_dump_state *dump;
105     uint16_t zone, *pzone = NULL;
106     struct ct_dpif_entry entry;
107     int err;
108
109     if (ctx->argc >= 2) {
110         if (!ovs_scan(ctx->argv[1], "zone=%"SCNu16, &zone)) {
111             ovs_fatal(0, "Error parsing zone= specifier");
112         }
113         pzone = &zone;
114     }
115     err = nl_ct_dump_start(&dump, pzone);
116     if (err) {
117         ovs_fatal(err, "Error creating conntrack netlink dump");
118     }
119
120     do {
121         err = nl_ct_dump_next(dump, &entry);
122         if (!err) {
123             struct ds ds = DS_EMPTY_INITIALIZER;
124
125             ct_dpif_format_entry(&entry, &ds, true, true);
126             printf("%s\n", ds_cstr(&ds));
127             ds_destroy(&ds);
128         }
129     } while (!err);
130
131     if (err != EOF) {
132         ovs_fatal(err, "Error dumping conntrack netlink entry");
133     }
134     nl_ct_dump_done(dump);
135 }
136 \f
137 /* Flush command */
138 static void
139 test_nl_ct_flush(struct ovs_cmdl_context *ctx OVS_UNUSED)
140 {
141     int err;
142
143     if (ctx->argc >= 2) {
144         uint16_t zone;
145
146         if (ovs_scan(ctx->argv[1], "zone=%"SCNu16, &zone)) {
147             err = nl_ct_flush_zone(zone);
148         } else {
149             ovs_fatal(0, "Error parsing zone= specifier");
150         }
151     } else {
152         err = nl_ct_flush();
153     }
154     if (err) {
155         ovs_fatal(err, "Error flushing conntrack netlink");
156     }
157 }
158 \f
159 static const struct ovs_cmdl_command commands[] = {
160     /* Linux netlink connection tracker interface test. */
161
162     /* Prints all the entries in the connection table and exits. */
163     {"dump", "[zone=zone]", 0, 1, test_nl_ct_dump},
164     /* Listens to all the connection tracking events and prints them to
165      * standard output until killed. */
166     {"monitor", "", 0, 0, test_nl_ct_monitor},
167     /* Flushes all the entries from all the tables.. */
168     {"flush", "[zone=zone]", 0, 1, test_nl_ct_flush},
169
170     {NULL, NULL, 0, 0, NULL},
171 };
172
173 static void
174 test_netlink_conntrack(int argc, char *argv[])
175 {
176     struct ovs_cmdl_context ctx = {
177         .argc = argc - 1,
178         .argv = argv + 1,
179     };
180     set_program_name(argv[0]);
181     ovs_cmdl_run_command(&ctx, commands);
182 }
183
184 OVSTEST_REGISTER("test-netlink-conntrack", test_netlink_conntrack);