7d45930b3bfd2213216db9a2d76ff23b69f84edc
[sliver-openvswitch.git] / ofproto / tunnel.c
1 /* Copyright (c) 2013 Nicira, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License. */
14
15 #include <config.h>
16 #include "tunnel.h"
17
18 #include <errno.h>
19
20 #include "ofproto/ofproto-provider.h"
21 #include "byte-order.h"
22 #include "dynamic-string.h"
23 #include "hash.h"
24 #include "hmap.h"
25 #include "netdev-vport.h"
26 #include "odp-util.h"
27 #include "packets.h"
28 #include "smap.h"
29 #include "socket-util.h"
30 #include "tunnel.h"
31 #include "vlog.h"
32
33 /* XXX:
34  *
35  * Ability to generate actions on input for ECN
36  * Ability to generate metadata for packet-outs
37  * VXLAN.
38  * Multicast group management (possibly).
39  * Disallow netdevs with names like "gre64_system" to prevent collisions. */
40
41 VLOG_DEFINE_THIS_MODULE(tunnel);
42
43 /* skb mark used for IPsec tunnel packets */
44 #define IPSEC_MARK 1
45
46 struct tnl_match {
47     ovs_be64 in_key;
48     ovs_be32 ip_src;
49     ovs_be32 ip_dst;
50     uint32_t odp_port;
51     uint32_t skb_mark;
52     bool in_key_flow;
53 };
54
55 struct tnl_port {
56     struct hmap_node match_node;
57
58     const struct ofport *ofport;
59     unsigned int netdev_seq;
60     struct tnl_match match;
61 };
62
63 static struct hmap tnl_match_map = HMAP_INITIALIZER(&tnl_match_map);
64
65 /* Returned to callers when their ofport will never be used to receive or send
66  * tunnel traffic. Alternatively, we could ask the caller to delete their
67  * ofport, but this would be unclean in the reconfguration case.  For the first
68  * time, an ofproto provider would have to call ofproto_port_del() on itself.*/
69 static struct tnl_port void_tnl_port;
70
71 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
72 static struct vlog_rate_limit dbg_rl = VLOG_RATE_LIMIT_INIT(60, 60);
73
74 static struct tnl_port *tnl_find(struct tnl_match *);
75 static struct tnl_port *tnl_find_exact(struct tnl_match *);
76 static uint32_t tnl_hash(struct tnl_match *);
77 static void tnl_match_fmt(const struct tnl_match *, struct ds *);
78 static char *tnl_port_fmt(const struct tnl_port *);
79 static void tnl_port_mod_log(const struct tnl_port *, const char *action);
80 static const char *tnl_port_get_name(const struct tnl_port *);
81
82 static struct tnl_port *
83 tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
84                bool warn)
85 {
86     const struct netdev_tunnel_config *cfg;
87     struct tnl_port *existing_port;
88     struct tnl_port *tnl_port;
89
90     cfg = netdev_get_tunnel_config(ofport->netdev);
91     ovs_assert(cfg);
92
93     tnl_port = xzalloc(sizeof *tnl_port);
94     tnl_port->ofport = ofport;
95     tnl_port->netdev_seq = netdev_change_seq(tnl_port->ofport->netdev);
96
97     tnl_port->match.in_key = cfg->in_key;
98     tnl_port->match.ip_src = cfg->ip_src;
99     tnl_port->match.ip_dst = cfg->ip_dst;
100     tnl_port->match.skb_mark = cfg->ipsec ? IPSEC_MARK : 0;
101     tnl_port->match.in_key_flow = cfg->in_key_flow;
102     tnl_port->match.odp_port = odp_port;
103
104     existing_port = tnl_find_exact(&tnl_port->match);
105     if (existing_port) {
106         if (warn) {
107             struct ds ds = DS_EMPTY_INITIALIZER;
108             tnl_match_fmt(&tnl_port->match, &ds);
109             VLOG_WARN("%s: attempting to add tunnel port with same config as "
110                       "port '%s' (%s)", tnl_port_get_name(tnl_port),
111                       tnl_port_get_name(existing_port), ds_cstr(&ds));
112             ds_destroy(&ds);
113             free(tnl_port);
114         }
115         return &void_tnl_port;
116     }
117
118     hmap_insert(&tnl_match_map, &tnl_port->match_node,
119                 tnl_hash(&tnl_port->match));
120     tnl_port_mod_log(tnl_port, "adding");
121     return tnl_port;
122 }
123
124 /* Adds 'ofport' to the module with datapath port number 'odp_port'. 'ofport's
125  * must be added before they can be used by the module. 'ofport' must be a
126  * tunnel. */
127 struct tnl_port *
128 tnl_port_add(const struct ofport *ofport, uint32_t odp_port)
129 {
130     return tnl_port_add__(ofport, odp_port, true);
131 }
132
133 /* Checks if the tnl_port pointed to by 'tnl_portp' needs reconfiguration due
134  * to changes in its netdev_tunnel_config.  If it does, updates 'tnl_portp' to
135  * point to a new tnl_port and returns true.  Otherwise, returns false.
136  * 'ofport' and 'odp_port' should be the same as would be passed to
137  * tnl_port_add(). */
138 bool
139 tnl_port_reconfigure(const struct ofport *ofport, uint32_t odp_port,
140                      struct tnl_port **tnl_portp)
141 {
142     struct tnl_port *tnl_port = *tnl_portp;
143
144     if (tnl_port == &void_tnl_port) {
145         *tnl_portp = tnl_port_add__(ofport, odp_port, false);
146         return *tnl_portp != &void_tnl_port;
147     } else if (tnl_port->ofport != ofport
148                || tnl_port->match.odp_port != odp_port
149                || tnl_port->netdev_seq != netdev_change_seq(ofport->netdev)) {
150         VLOG_DBG("reconfiguring %s", tnl_port_get_name(tnl_port));
151         tnl_port_del(tnl_port);
152         *tnl_portp = tnl_port_add(ofport, odp_port);
153         return true;
154     }
155     return false;
156 }
157
158 /* Removes 'tnl_port' from the module. */
159 void
160 tnl_port_del(struct tnl_port *tnl_port)
161 {
162     if (tnl_port && tnl_port != &void_tnl_port) {
163         tnl_port_mod_log(tnl_port, "removing");
164         hmap_remove(&tnl_match_map, &tnl_port->match_node);
165         free(tnl_port);
166     }
167 }
168
169 /* Transforms 'flow' so that it appears to have been received by a tunnel
170  * OpenFlow port controlled by this module instead of the datapath port it
171  * actually came in on.  Sets 'flow''s in_port to the appropriate OpenFlow port
172  * number.  Returns the 'ofport' corresponding to the new in_port.
173  *
174  * Callers should verify that 'flow' needs to be received by calling
175  * tnl_port_should_receive() before this function.
176  *
177  * Leaves 'flow' untouched and returns null if unsuccessful. */
178 const struct ofport *
179 tnl_port_receive(struct flow *flow)
180 {
181     char *pre_flow_str = NULL;
182     struct tnl_port *tnl_port;
183     struct tnl_match match;
184
185     memset(&match, 0, sizeof match);
186     match.odp_port = flow->in_port;
187     match.ip_src = flow->tunnel.ip_dst;
188     match.ip_dst = flow->tunnel.ip_src;
189     match.in_key = flow->tunnel.tun_id;
190     match.skb_mark = flow->skb_mark;
191
192     tnl_port = tnl_find(&match);
193     if (!tnl_port) {
194         struct ds ds = DS_EMPTY_INITIALIZER;
195
196         tnl_match_fmt(&match, &ds);
197         VLOG_WARN_RL(&rl, "receive tunnel port not found (%s)", ds_cstr(&ds));
198         ds_destroy(&ds);
199         return NULL;
200     }
201
202     if (is_ip_any(flow)
203         && ((flow->tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE)
204         && (flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
205         VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE but is not ECN"
206                      " capable");
207         return NULL;
208     }
209
210     if (!VLOG_DROP_DBG(&dbg_rl)) {
211         pre_flow_str = flow_to_string(flow);
212     }
213
214     flow->in_port = tnl_port->ofport->ofp_port;
215     memset(&flow->tunnel, 0, sizeof flow->tunnel);
216     flow->tunnel.tun_id = match.in_key;
217
218     if (pre_flow_str) {
219         char *post_flow_str = flow_to_string(flow);
220         char *tnl_str = tnl_port_fmt(tnl_port);
221         VLOG_DBG("flow received\n"
222                  "%s"
223                  " pre: %s\n"
224                  "post: %s",
225                  tnl_str, pre_flow_str, post_flow_str);
226         free(tnl_str);
227         free(pre_flow_str);
228         free(post_flow_str);
229     }
230     return tnl_port->ofport;
231 }
232
233 /* Given that 'flow' should be output to the ofport corresponding to
234  * 'tnl_port', updates 'flow''s tunnel headers and returns the actual datapath
235  * port that the output should happen on.  May return OVSP_NONE if the output
236  * shouldn't occur. */
237 uint32_t
238 tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
239 {
240     const struct netdev_tunnel_config *cfg;
241     char *pre_flow_str = NULL;
242
243     if (tnl_port == &void_tnl_port) {
244         return OVSP_NONE;
245     }
246
247     cfg = netdev_get_tunnel_config(tnl_port->ofport->netdev);
248     ovs_assert(cfg);
249
250     if (!VLOG_DROP_DBG(&dbg_rl)) {
251         pre_flow_str = flow_to_string(flow);
252     }
253
254     flow->tunnel.ip_src = tnl_port->match.ip_src;
255     flow->tunnel.ip_dst = tnl_port->match.ip_dst;
256     flow->skb_mark = tnl_port->match.skb_mark;
257
258     if (!cfg->out_key_flow) {
259         flow->tunnel.tun_id = cfg->out_key;
260     }
261
262     if (cfg->ttl_inherit && is_ip_any(flow)) {
263         flow->tunnel.ip_ttl = flow->nw_ttl;
264     } else {
265         flow->tunnel.ip_ttl = cfg->ttl;
266     }
267
268     if (cfg->tos_inherit && is_ip_any(flow)) {
269         flow->tunnel.ip_tos = flow->nw_tos & IP_DSCP_MASK;
270     } else {
271         flow->tunnel.ip_tos = cfg->tos;
272     }
273
274     if ((flow->nw_tos & IP_ECN_MASK) == IP_ECN_CE) {
275         flow->tunnel.ip_tos |= IP_ECN_ECT_0;
276     } else {
277         flow->tunnel.ip_tos |= flow->nw_tos & IP_ECN_MASK;
278     }
279
280     flow->tunnel.flags = (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
281         | (cfg->csum ? FLOW_TNL_F_CSUM : 0)
282         | (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
283
284     if (pre_flow_str) {
285         char *post_flow_str = flow_to_string(flow);
286         char *tnl_str = tnl_port_fmt(tnl_port);
287         VLOG_DBG("flow sent\n"
288                  "%s"
289                  " pre: %s\n"
290                  "post: %s",
291                  tnl_str, pre_flow_str, post_flow_str);
292         free(tnl_str);
293         free(pre_flow_str);
294         free(post_flow_str);
295     }
296
297     return tnl_port->match.odp_port;
298 }
299
300 static uint32_t
301 tnl_hash(struct tnl_match *match)
302 {
303     BUILD_ASSERT_DECL(sizeof *match % sizeof(uint32_t) == 0);
304     return hash_words((uint32_t *) match, sizeof *match / sizeof(uint32_t), 0);
305 }
306
307 static struct tnl_port *
308 tnl_find_exact(struct tnl_match *match)
309 {
310     struct tnl_port *tnl_port;
311
312     HMAP_FOR_EACH_WITH_HASH (tnl_port, match_node, tnl_hash(match),
313                              &tnl_match_map) {
314         if (!memcmp(match, &tnl_port->match, sizeof *match)) {
315             return tnl_port;
316         }
317     }
318     return NULL;
319 }
320
321 static struct tnl_port *
322 tnl_find(struct tnl_match *match_)
323 {
324     struct tnl_match match = *match_;
325     bool is_multicast = ip_is_multicast(match.ip_src);
326     struct tnl_port *tnl_port;
327
328     /* remote_ip, local_ip, in_key */
329     if (!is_multicast) {
330         tnl_port = tnl_find_exact(&match);
331         if (tnl_port) {
332             return tnl_port;
333         }
334     }
335
336     /* remote_ip, in_key */
337     match.ip_src = 0;
338     tnl_port = tnl_find_exact(&match);
339     if (tnl_port) {
340         return tnl_port;
341     }
342     match.ip_src = match_->ip_src;
343
344     /* remote_ip, local_ip */
345     if (!is_multicast) {
346         match.in_key = 0;
347         match.in_key_flow = true;
348         tnl_port = tnl_find_exact(&match);
349         if (tnl_port) {
350             return tnl_port;
351         }
352         match.in_key = match_->in_key;
353         match.in_key_flow = false;
354     }
355
356     /* remote_ip */
357     match.ip_src = 0;
358     match.in_key = 0;
359     match.in_key_flow = true;
360     tnl_port = tnl_find_exact(&match);
361     if (tnl_port) {
362         return tnl_port;
363     }
364     match.ip_src = match_->ip_src;
365     match.in_key = match_->in_key;
366     match.in_key_flow = false;
367
368     if (is_multicast) {
369         match.ip_src = 0;
370         match.ip_dst = match_->ip_src;
371
372         /* multicast remote_ip, in_key */
373         tnl_port = tnl_find_exact(&match);
374         if (tnl_port) {
375             return tnl_port;
376         }
377
378         /* multicast remote_ip */
379         match.in_key = 0;
380         match.in_key_flow = true;
381         tnl_port = tnl_find_exact(&match);
382         if (tnl_port) {
383             return tnl_port;
384         }
385     }
386     return NULL;
387 }
388
389 static void
390 tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
391 {
392     ds_put_format(ds, IP_FMT"->"IP_FMT, IP_ARGS(match->ip_src),
393                   IP_ARGS(match->ip_dst));
394
395     if (match->in_key_flow) {
396         ds_put_cstr(ds, ", key=flow");
397     } else {
398         ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
399     }
400
401     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
402     ds_put_format(ds, ", skb mark=%"PRIu32, match->skb_mark);
403 }
404
405 static void
406 tnl_port_mod_log(const struct tnl_port *tnl_port, const char *action)
407 {
408     if (VLOG_IS_DBG_ENABLED()) {
409         struct ds ds = DS_EMPTY_INITIALIZER;
410
411         tnl_match_fmt(&tnl_port->match, &ds);
412         VLOG_INFO("%s tunnel port %s (%s)", action,
413                   tnl_port_get_name(tnl_port), ds_cstr(&ds));
414         ds_destroy(&ds);
415     }
416 }
417
418 static char *
419 tnl_port_fmt(const struct tnl_port *tnl_port)
420 {
421     const struct netdev_tunnel_config *cfg =
422         netdev_get_tunnel_config(tnl_port->ofport->netdev);
423     struct ds ds = DS_EMPTY_INITIALIZER;
424
425     ds_put_format(&ds, "port %"PRIu32": %s (%s: ", tnl_port->match.odp_port,
426                   tnl_port_get_name(tnl_port),
427                   netdev_get_type(tnl_port->ofport->netdev));
428     tnl_match_fmt(&tnl_port->match, &ds);
429
430     if (cfg->out_key != cfg->in_key ||
431         cfg->out_key_present != cfg->in_key_present ||
432         cfg->out_key_flow != cfg->in_key_flow) {
433         ds_put_cstr(&ds, ", out_key=");
434         if (!cfg->out_key_present) {
435             ds_put_cstr(&ds, "none");
436         } else if (cfg->out_key_flow) {
437             ds_put_cstr(&ds, "flow");
438         } else {
439             ds_put_format(&ds, "%#"PRIx64, ntohll(cfg->out_key));
440         }
441     }
442
443     if (cfg->ttl_inherit) {
444         ds_put_cstr(&ds, ", ttl=inherit");
445     } else {
446         ds_put_format(&ds, ", ttl=%"PRIu8, cfg->ttl);
447     }
448
449     if (cfg->tos_inherit) {
450         ds_put_cstr(&ds, ", tos=inherit");
451     } else if (cfg->tos) {
452         ds_put_format(&ds, ", tos=%#"PRIx8, cfg->tos);
453     }
454
455     if (!cfg->dont_fragment) {
456         ds_put_cstr(&ds, ", df=false");
457     }
458
459     if (cfg->csum) {
460         ds_put_cstr(&ds, ", csum=true");
461     }
462
463     ds_put_cstr(&ds, ")\n");
464
465     return ds_steal_cstr(&ds);
466 }
467
468 static const char *
469 tnl_port_get_name(const struct tnl_port *tnl_port)
470 {
471     return netdev_get_name(tnl_port->ofport->netdev);
472 }