30
29
#include "tunnel.h"
35
* Disallow netdevs with names like "gre64_system" to prevent collisions. */
37
32
VLOG_DEFINE_THIS_MODULE(tunnel);
46
struct hmap_node ofport_node;
49
47
struct hmap_node match_node;
51
const struct ofport *ofport;
49
const struct ofport_dpif *ofport;
52
50
unsigned int netdev_seq;
51
struct netdev *netdev;
53
53
struct tnl_match match;
56
static struct hmap tnl_match_map = HMAP_INITIALIZER(&tnl_match_map);
58
/* Returned to callers when their ofport will never be used to receive or send
59
* tunnel traffic. Alternatively, we could ask the caller to delete their
60
* ofport, but this would be unclean in the reconfguration case. For the first
61
* time, an ofproto provider would have to call ofproto_port_del() on itself.*/
62
static struct tnl_port void_tnl_port;
56
static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
58
static struct hmap tnl_match_map__ = HMAP_INITIALIZER(&tnl_match_map__);
59
static struct hmap *tnl_match_map OVS_GUARDED_BY(rwlock) = &tnl_match_map__;
61
static struct hmap ofport_map__ = HMAP_INITIALIZER(&ofport_map__);
62
static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
64
64
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
65
65
static struct vlog_rate_limit dbg_rl = VLOG_RATE_LIMIT_INIT(60, 60);
67
static struct tnl_port *tnl_find(struct tnl_match *);
68
static struct tnl_port *tnl_find_exact(struct tnl_match *);
67
static struct tnl_port *tnl_find(struct tnl_match *) OVS_REQ_RDLOCK(&rwlock);
68
static struct tnl_port *tnl_find_exact(struct tnl_match *)
69
OVS_REQ_RDLOCK(&rwlock);
70
static struct tnl_port *tnl_find_ofport(const struct ofport_dpif *)
71
OVS_REQ_RDLOCK(&rwlock);
69
73
static uint32_t tnl_hash(struct tnl_match *);
70
74
static void tnl_match_fmt(const struct tnl_match *, struct ds *);
71
static char *tnl_port_fmt(const struct tnl_port *);
72
static void tnl_port_mod_log(const struct tnl_port *, const char *action);
73
static const char *tnl_port_get_name(const struct tnl_port *);
75
static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(&rwlock);
76
static void tnl_port_mod_log(const struct tnl_port *, const char *action)
77
OVS_REQ_RDLOCK(&rwlock);
78
static const char *tnl_port_get_name(const struct tnl_port *)
79
OVS_REQ_RDLOCK(&rwlock);
80
static void tnl_port_del__(const struct ofport_dpif *) OVS_REQ_WRLOCK(&rwlock);
75
static struct tnl_port *
76
tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
83
tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
84
odp_port_t odp_port, bool warn)
85
OVS_REQ_WRLOCK(&rwlock)
79
87
const struct netdev_tunnel_config *cfg;
80
88
struct tnl_port *existing_port;
81
89
struct tnl_port *tnl_port;
83
cfg = netdev_get_tunnel_config(ofport->netdev);
91
cfg = netdev_get_tunnel_config(netdev);
86
94
tnl_port = xzalloc(sizeof *tnl_port);
87
95
tnl_port->ofport = ofport;
88
tnl_port->netdev_seq = netdev_change_seq(tnl_port->ofport->netdev);
96
tnl_port->netdev = netdev_ref(netdev);
97
tnl_port->netdev_seq = netdev_change_seq(tnl_port->netdev);
90
99
tnl_port->match.in_key = cfg->in_key;
91
100
tnl_port->match.ip_src = cfg->ip_src;
92
101
tnl_port->match.ip_dst = cfg->ip_dst;
102
tnl_port->match.ip_src_flow = cfg->ip_src_flow;
103
tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
93
104
tnl_port->match.skb_mark = cfg->ipsec ? IPSEC_MARK : 0;
94
105
tnl_port->match.in_key_flow = cfg->in_key_flow;
95
106
tnl_port->match.odp_port = odp_port;
108
return &void_tnl_port;
111
hmap_insert(&tnl_match_map, &tnl_port->match_node,
122
hmap_insert(ofport_map, &tnl_port->ofport_node, hash_pointer(ofport, 0));
123
hmap_insert(tnl_match_map, &tnl_port->match_node,
112
124
tnl_hash(&tnl_port->match));
113
125
tnl_port_mod_log(tnl_port, "adding");
117
129
/* Adds 'ofport' to the module with datapath port number 'odp_port'. 'ofport's
118
130
* must be added before they can be used by the module. 'ofport' must be a
121
tnl_port_add(const struct ofport *ofport, uint32_t odp_port)
133
tnl_port_add(const struct ofport_dpif *ofport, const struct netdev *netdev,
134
odp_port_t odp_port) OVS_EXCLUDED(rwlock)
123
return tnl_port_add__(ofport, odp_port, true);
136
ovs_rwlock_wrlock(&rwlock);
137
tnl_port_add__(ofport, netdev, odp_port, true);
138
ovs_rwlock_unlock(&rwlock);
126
/* Checks if the tnl_port pointed to by 'tnl_portp' needs reconfiguration due
127
* to changes in its netdev_tunnel_config. If it does, updates 'tnl_portp' to
128
* point to a new tnl_port and returns true. Otherwise, returns false.
129
* 'ofport' and 'odp_port' should be the same as would be passed to
141
/* Checks if the tunnel represented by 'ofport' reconfiguration due to changes
142
* in its netdev_tunnel_config. If it does, returns true. Otherwise, returns
143
* false. 'ofport' and 'odp_port' should be the same as would be passed to
130
144
* tnl_port_add(). */
132
tnl_port_reconfigure(const struct ofport *ofport, uint32_t odp_port,
133
struct tnl_port **tnl_portp)
146
tnl_port_reconfigure(const struct ofport_dpif *ofport,
147
const struct netdev *netdev, odp_port_t odp_port)
135
struct tnl_port *tnl_port = *tnl_portp;
150
struct tnl_port *tnl_port;
151
bool changed = false;
137
if (tnl_port == &void_tnl_port) {
138
*tnl_portp = tnl_port_add__(ofport, odp_port, false);
139
return *tnl_portp != &void_tnl_port;
140
} else if (tnl_port->ofport != ofport
153
ovs_rwlock_wrlock(&rwlock);
154
tnl_port = tnl_find_ofport(ofport);
156
changed = tnl_port_add__(ofport, netdev, odp_port, false);
157
} else if (tnl_port->netdev != netdev
141
158
|| tnl_port->match.odp_port != odp_port
142
|| tnl_port->netdev_seq != netdev_change_seq(ofport->netdev)) {
159
|| tnl_port->netdev_seq != netdev_change_seq(netdev)) {
143
160
VLOG_DBG("reconfiguring %s", tnl_port_get_name(tnl_port));
144
tnl_port_del(tnl_port);
145
*tnl_portp = tnl_port_add(ofport, odp_port);
161
tnl_port_del__(ofport);
162
tnl_port_add__(ofport, netdev, odp_port, true);
165
ovs_rwlock_unlock(&rwlock);
151
/* Removes 'tnl_port' from the module. */
153
tnl_port_del(struct tnl_port *tnl_port)
170
tnl_port_del__(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(rwlock)
155
if (tnl_port && tnl_port != &void_tnl_port) {
172
struct tnl_port *tnl_port;
178
tnl_port = tnl_find_ofport(ofport);
156
180
tnl_port_mod_log(tnl_port, "removing");
157
hmap_remove(&tnl_match_map, &tnl_port->match_node);
181
hmap_remove(tnl_match_map, &tnl_port->match_node);
182
hmap_remove(ofport_map, &tnl_port->ofport_node);
183
netdev_close(tnl_port->netdev);
162
/* Transforms 'flow' so that it appears to have been received by a tunnel
163
* OpenFlow port controlled by this module instead of the datapath port it
164
* actually came in on. Sets 'flow''s in_port to the appropriate OpenFlow port
165
* number. Returns the 'ofport' corresponding to the new in_port.
188
/* Removes 'ofport' from the module. */
190
tnl_port_del(const struct ofport_dpif *ofport) OVS_EXCLUDED(rwlock)
192
ovs_rwlock_wrlock(&rwlock);
193
tnl_port_del__(ofport);
194
ovs_rwlock_unlock(&rwlock);
197
/* Looks in the table of tunnels for a tunnel matching the metadata in 'flow'.
198
* Returns the 'ofport' corresponding to the new in_port, or a null pointer if
167
201
* Callers should verify that 'flow' needs to be received by calling
168
* tnl_port_should_receive() before this function.
170
* Leaves 'flow' untouched and returns null if unsuccessful. */
171
const struct ofport *
172
tnl_port_receive(struct flow *flow)
202
* tnl_port_should_receive() before this function. */
203
const struct ofport_dpif *
204
tnl_port_receive(const struct flow *flow) OVS_EXCLUDED(rwlock)
174
206
char *pre_flow_str = NULL;
207
const struct ofport_dpif *ofport;
175
208
struct tnl_port *tnl_port;
176
209
struct tnl_match match;
178
211
memset(&match, 0, sizeof match);
179
match.odp_port = flow->in_port;
212
match.odp_port = flow->in_port.odp_port;
180
213
match.ip_src = flow->tunnel.ip_dst;
181
214
match.ip_dst = flow->tunnel.ip_src;
182
215
match.in_key = flow->tunnel.tun_id;
183
216
match.skb_mark = flow->skb_mark;
218
ovs_rwlock_rdlock(&rwlock);
185
219
tnl_port = tnl_find(&match);
220
ofport = tnl_port ? tnl_port->ofport : NULL;
187
222
struct ds ds = DS_EMPTY_INITIALIZER;
189
224
tnl_match_fmt(&match, &ds);
190
225
VLOG_WARN_RL(&rl, "receive tunnel port not found (%s)", ds_cstr(&ds));
195
230
if (!VLOG_DROP_DBG(&dbg_rl)) {
196
231
pre_flow_str = flow_to_string(flow);
199
flow->in_port = tnl_port->ofport->ofp_port;
200
memset(&flow->tunnel, 0, sizeof flow->tunnel);
201
flow->tunnel.tun_id = match.in_key;
203
234
if (pre_flow_str) {
204
235
char *post_flow_str = flow_to_string(flow);
205
236
char *tnl_str = tnl_port_fmt(tnl_port);
212
243
free(pre_flow_str);
213
244
free(post_flow_str);
215
return tnl_port->ofport;
248
ovs_rwlock_unlock(&rwlock);
218
252
/* Given that 'flow' should be output to the ofport corresponding to
219
253
* 'tnl_port', updates 'flow''s tunnel headers and returns the actual datapath
220
* port that the output should happen on. May return OVSP_NONE if the output
254
* port that the output should happen on. May return ODPP_NONE if the output
221
255
* shouldn't occur. */
223
tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
257
tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
258
struct flow_wildcards *wc) OVS_EXCLUDED(rwlock)
225
260
const struct netdev_tunnel_config *cfg;
261
struct tnl_port *tnl_port;
226
262
char *pre_flow_str = NULL;
228
if (tnl_port == &void_tnl_port) {
265
ovs_rwlock_rdlock(&rwlock);
266
tnl_port = tnl_find_ofport(ofport);
267
out_port = tnl_port ? tnl_port->match.odp_port : ODPP_NONE;
232
cfg = netdev_get_tunnel_config(tnl_port->ofport->netdev);
272
cfg = netdev_get_tunnel_config(tnl_port->netdev);
235
275
if (!VLOG_DROP_DBG(&dbg_rl)) {
236
276
pre_flow_str = flow_to_string(flow);
239
flow->tunnel.ip_src = tnl_port->match.ip_src;
240
flow->tunnel.ip_dst = tnl_port->match.ip_dst;
279
if (!cfg->ip_src_flow) {
280
flow->tunnel.ip_src = tnl_port->match.ip_src;
282
if (!cfg->ip_dst_flow) {
283
flow->tunnel.ip_dst = tnl_port->match.ip_dst;
241
285
flow->skb_mark = tnl_port->match.skb_mark;
243
287
if (!cfg->out_key_flow) {