2 * Copyright (c) 2014, 2015 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "classifier.h"
22 #include "dynamic-string.h"
26 #include "ovs-thread.h"
28 #include "tnl-arp-cache.h"
29 #include "tnl-ports.h"
30 #include "ovs-thread.h"
34 static struct ovs_mutex mutex
= OVS_MUTEX_INITIALIZER
;
35 static struct classifier cls
; /* Tunnel ports. */
43 char dev_name
[IFNAMSIZ
];
46 static struct ovs_list addr_list
;
51 char dev_name
[IFNAMSIZ
];
55 static struct ovs_list port_list
;
60 struct ovs_refcount ref_cnt
;
61 char dev_name
[IFNAMSIZ
];
64 static struct tnl_port_in
*
65 tnl_port_cast(const struct cls_rule
*cr
)
67 BUILD_ASSERT_DECL(offsetof(struct tnl_port_in
, cr
) == 0);
69 return CONTAINER_OF(cr
, struct tnl_port_in
, cr
);
73 tnl_port_free(struct tnl_port_in
*p
)
75 cls_rule_destroy(&p
->cr
);
80 tnl_port_init_flow(struct flow
*flow
, struct eth_addr mac
,
81 ovs_be32 addr
, ovs_be16 udp_port
)
83 memset(flow
, 0, sizeof *flow
);
85 flow
->dl_type
= htons(ETH_TYPE_IP
);
90 flow
->nw_proto
= IPPROTO_UDP
;
92 flow
->nw_proto
= IPPROTO_GRE
;
94 flow
->tp_dst
= udp_port
;
98 map_insert(odp_port_t port
, struct eth_addr mac
, ovs_be32 addr
,
99 ovs_be16 udp_port
, const char dev_name
[])
101 const struct cls_rule
*cr
;
102 struct tnl_port_in
*p
;
105 memset(&match
, 0, sizeof match
);
106 tnl_port_init_flow(&match
.flow
, mac
, addr
, udp_port
);
109 cr
= classifier_lookup(&cls
, CLS_MAX_VERSION
, &match
.flow
, NULL
);
110 p
= tnl_port_cast(cr
);
111 /* Try again if the rule was released before we get the reference. */
112 } while (p
&& !ovs_refcount_try_ref_rcu(&p
->ref_cnt
));
115 p
= xzalloc(sizeof *p
);
118 match
.wc
.masks
.dl_type
= OVS_BE16_MAX
;
119 match
.wc
.masks
.nw_proto
= 0xff;
120 match
.wc
.masks
.nw_frag
= 0xff; /* XXX: No fragments support. */
121 match
.wc
.masks
.tp_dst
= OVS_BE16_MAX
;
122 match
.wc
.masks
.nw_dst
= OVS_BE32_MAX
;
123 match
.wc
.masks
.vlan_tci
= OVS_BE16_MAX
;
124 memset(&match
.wc
.masks
.dl_dst
, 0xff, sizeof (struct eth_addr
));
126 cls_rule_init(&p
->cr
, &match
, 0); /* Priority == 0. */
127 ovs_refcount_init(&p
->ref_cnt
);
128 ovs_strlcpy(p
->dev_name
, dev_name
, sizeof p
->dev_name
);
130 classifier_insert(&cls
, &p
->cr
, CLS_MIN_VERSION
, NULL
, 0);
135 tnl_port_map_insert(odp_port_t port
,
136 ovs_be16 udp_port
, const char dev_name
[])
139 struct ip_device
*ip_dev
;
141 ovs_mutex_lock(&mutex
);
142 LIST_FOR_EACH(p
, node
, &port_list
) {
143 if (udp_port
== p
->udp_port
) {
148 p
= xzalloc(sizeof *p
);
150 p
->udp_port
= udp_port
;
151 ovs_strlcpy(p
->dev_name
, dev_name
, sizeof p
->dev_name
);
152 list_insert(&port_list
, &p
->node
);
154 LIST_FOR_EACH(ip_dev
, node
, &addr_list
) {
155 map_insert(p
->port
, ip_dev
->mac
, ip_dev
->addr
,
156 p
->udp_port
, p
->dev_name
);
160 ovs_mutex_unlock(&mutex
);
164 tnl_port_unref(const struct cls_rule
*cr
)
166 struct tnl_port_in
*p
= tnl_port_cast(cr
);
168 if (cr
&& ovs_refcount_unref_relaxed(&p
->ref_cnt
) == 1) {
169 if (classifier_remove(&cls
, cr
)) {
170 ovsrcu_postpone(tnl_port_free
, p
);
176 map_delete(struct eth_addr mac
, ovs_be32 addr
, ovs_be16 udp_port
)
178 const struct cls_rule
*cr
;
181 tnl_port_init_flow(&flow
, mac
, addr
, udp_port
);
183 cr
= classifier_lookup(&cls
, CLS_MAX_VERSION
, &flow
, NULL
);
188 tnl_port_map_delete(ovs_be16 udp_port
)
190 struct tnl_port
*p
, *next
;
191 struct ip_device
*ip_dev
;
194 ovs_mutex_lock(&mutex
);
195 LIST_FOR_EACH_SAFE(p
, next
, node
, &port_list
) {
196 if (p
->udp_port
== udp_port
) {
197 list_remove(&p
->node
);
206 LIST_FOR_EACH(ip_dev
, node
, &addr_list
) {
207 map_delete(ip_dev
->mac
, ip_dev
->addr
, udp_port
);
212 ovs_mutex_unlock(&mutex
);
215 /* 'flow' is non-const to allow for temporary modifications during the lookup.
216 * Any changes are restored before returning. */
218 tnl_port_map_lookup(struct flow
*flow
, struct flow_wildcards
*wc
)
220 const struct cls_rule
*cr
= classifier_lookup(&cls
, CLS_MAX_VERSION
, flow
,
223 return (cr
) ? tnl_port_cast(cr
)->portno
: ODPP_NONE
;
227 tnl_port_show_v(struct ds
*ds
)
229 const struct tnl_port_in
*p
;
231 CLS_FOR_EACH(p
, cr
, &cls
) {
232 struct odputil_keybuf keybuf
;
233 struct odputil_keybuf maskbuf
;
235 const struct nlattr
*key
, *mask
;
236 size_t key_len
, mask_len
;
237 struct flow_wildcards wc
;
239 struct odp_flow_key_parms odp_parms
= {
244 ds_put_format(ds
, "%s (%"PRIu32
") : ", p
->dev_name
, p
->portno
);
245 minimask_expand(p
->cr
.match
.mask
, &wc
);
246 miniflow_expand(p
->cr
.match
.flow
, &flow
);
249 odp_parms
.odp_in_port
= flow
.in_port
.odp_port
;
250 odp_parms
.support
.recirc
= true;
251 ofpbuf_use_stack(&buf
, &keybuf
, sizeof keybuf
);
252 odp_flow_key_from_flow(&odp_parms
, &buf
);
257 odp_parms
.odp_in_port
= wc
.masks
.in_port
.odp_port
;
258 odp_parms
.support
.recirc
= false;
259 ofpbuf_use_stack(&buf
, &maskbuf
, sizeof maskbuf
);
260 odp_flow_key_from_mask(&odp_parms
, &buf
);
265 odp_flow_format(key
, key_len
, mask
, mask_len
, NULL
, ds
, false);
266 ds_put_format(ds
, "\n");
271 tnl_port_show(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
272 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
274 struct ds ds
= DS_EMPTY_INITIALIZER
;
277 ds_put_format(&ds
, "Listening ports:\n");
278 ovs_mutex_lock(&mutex
);
280 if (!strcasecmp(argv
[1], "-v")) {
281 tnl_port_show_v(&ds
);
286 LIST_FOR_EACH(p
, node
, &port_list
) {
287 ds_put_format(&ds
, "%s (%"PRIu32
")\n", p
->dev_name
, p
->port
);
291 ovs_mutex_unlock(&mutex
);
292 unixctl_command_reply(conn
, ds_cstr(&ds
));
297 map_insert_ipdev(struct ip_device
*ip_dev
)
301 LIST_FOR_EACH(p
, node
, &port_list
) {
302 map_insert(p
->port
, ip_dev
->mac
, ip_dev
->addr
,
303 p
->udp_port
, p
->dev_name
);
308 insert_ipdev(const char dev_name
[])
310 struct ip_device
*ip_dev
;
311 enum netdev_flags flags
;
315 error
= netdev_open(dev_name
, NULL
, &dev
);
320 error
= netdev_get_flags(dev
, &flags
);
321 if (error
|| (flags
& NETDEV_LOOPBACK
)) {
326 ip_dev
= xzalloc(sizeof *ip_dev
);
328 ip_dev
->change_seq
= netdev_get_change_seq(dev
);
329 error
= netdev_get_etheraddr(ip_dev
->dev
, &ip_dev
->mac
);
333 error
= netdev_get_in4(ip_dev
->dev
, (struct in_addr
*)&ip_dev
->addr
, NULL
);
337 ovs_strlcpy(ip_dev
->dev_name
, netdev_get_name(dev
), sizeof ip_dev
->dev_name
);
339 list_insert(&addr_list
, &ip_dev
->node
);
340 map_insert_ipdev(ip_dev
);
344 delete_ipdev(struct ip_device
*ip_dev
)
348 LIST_FOR_EACH(p
, node
, &port_list
) {
349 map_delete(ip_dev
->mac
, ip_dev
->addr
, p
->udp_port
);
352 list_remove(&ip_dev
->node
);
353 netdev_close(ip_dev
->dev
);
358 tnl_port_map_insert_ipdev(const char dev_name
[])
360 struct ip_device
*ip_dev
, *next
;
362 ovs_mutex_lock(&mutex
);
364 LIST_FOR_EACH_SAFE(ip_dev
, next
, node
, &addr_list
) {
365 if (!strcmp(netdev_get_name(ip_dev
->dev
), dev_name
)) {
366 if (ip_dev
->change_seq
== netdev_get_change_seq(ip_dev
->dev
)) {
369 /* Address changed. */
370 delete_ipdev(ip_dev
);
374 insert_ipdev(dev_name
);
377 ovs_mutex_unlock(&mutex
);
381 tnl_port_map_delete_ipdev(const char dev_name
[])
383 struct ip_device
*ip_dev
, *next
;
385 ovs_mutex_lock(&mutex
);
386 LIST_FOR_EACH_SAFE(ip_dev
, next
, node
, &addr_list
) {
387 if (!strcmp(netdev_get_name(ip_dev
->dev
), dev_name
)) {
388 delete_ipdev(ip_dev
);
391 ovs_mutex_unlock(&mutex
);
395 tnl_port_map_run(void)
397 struct ip_device
*ip_dev
, *next
;
399 ovs_mutex_lock(&mutex
);
400 LIST_FOR_EACH_SAFE(ip_dev
, next
, node
, &addr_list
) {
401 char dev_name
[IFNAMSIZ
];
403 if (ip_dev
->change_seq
== netdev_get_change_seq(ip_dev
->dev
)) {
407 /* Address changed. */
408 ovs_strlcpy(dev_name
, ip_dev
->dev_name
, sizeof dev_name
);
409 delete_ipdev(ip_dev
);
410 insert_ipdev(dev_name
);
412 ovs_mutex_unlock(&mutex
);
416 tnl_port_map_init(void)
418 classifier_init(&cls
, flow_segment_u64s
);
419 list_init(&addr_list
);
420 list_init(&port_list
);
421 unixctl_command_register("tnl/ports/show", "-v", 0, 1, tnl_port_show
, NULL
);