]>
git.proxmox.com Git - ovs.git/blob - ofproto/ofproto-dpif-monitor.c
2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 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.
18 #include "ofproto-dpif-monitor.h"
24 #include "dp-packet.h"
25 #include "guarded-list.h"
31 #include "ofproto-dpif.h"
33 #include "ovs-thread.h"
34 #include "poll-loop.h"
38 #include "openvswitch/vlog.h"
40 VLOG_DEFINE_THIS_MODULE(ofproto_dpif_monitor
);
42 /* Converts the time in millisecond to heap priority. */
43 #define MSEC_TO_PRIO(TIME) (LLONG_MAX - (TIME))
44 /* Converts the heap priority to time in millisecond. */
45 #define PRIO_TO_MSEC(PRIO) (LLONG_MAX - (PRIO))
47 /* Monitored port. It owns references to ofport, bfd, cfm, and lldp structs. */
49 struct hmap_node hmap_node
; /* In monitor_hmap. */
50 struct heap_node heap_node
; /* In monitor_heap. */
51 const struct ofport_dpif
*ofport
; /* The corresponding ofport. */
53 struct cfm
*cfm
; /* Reference to cfm. */
54 struct bfd
*bfd
; /* Reference to bfd. */
55 struct lldp
*lldp
; /* Reference to lldp. */
56 struct eth_addr hw_addr
; /* Hardware address. */
59 /* Entry of the 'send_soon' list. Contains the pointer to the
60 * 'ofport_dpif'. Note, the pointed object is not protected, so
61 * users should always use the mport_find() to convert it to 'mport'. */
62 struct send_soon_entry
{
63 struct ovs_list list_node
; /* In send_soon. */
64 const struct ofport_dpif
*ofport
;
67 /* hmap that contains "struct mport"s. */
68 static struct hmap monitor_hmap
= HMAP_INITIALIZER(&monitor_hmap
);
70 /* heap for ordering mport based on bfd/cfm wakeup time. */
71 static struct heap monitor_heap
;
73 /* guarded-list for storing the mports that need to send bfd/cfm control
75 static struct guarded_list send_soon
= GUARDED_OVS_LIST_INITIALIZER(&send_soon
);
77 /* The monitor thread id. */
78 static pthread_t monitor_tid
;
79 /* True if the monitor thread is running. */
80 static bool monitor_running
;
82 static struct latch monitor_exit_latch
;
83 static struct ovs_mutex monitor_mutex
= OVS_MUTEX_INITIALIZER
;
85 static void *monitor_main(void *);
86 static void monitor_check_send_soon(struct dp_packet
*);
87 static void monitor_run(void);
88 static void monitor_mport_run(struct mport
*, struct dp_packet
*);
90 static void mport_register(const struct ofport_dpif
*, struct bfd
*,
91 struct cfm
*, struct lldp
*,
92 const struct eth_addr
*)
93 OVS_REQUIRES(monitor_mutex
);
94 static void mport_unregister(const struct ofport_dpif
*)
95 OVS_REQUIRES(monitor_mutex
);
96 static void mport_update(struct mport
*, struct bfd
*, struct cfm
*,
97 struct lldp
*, const struct eth_addr
*)
98 OVS_REQUIRES(monitor_mutex
);
99 static struct mport
*mport_find(const struct ofport_dpif
*)
100 OVS_REQUIRES(monitor_mutex
);
102 /* Tries finding and returning the 'mport' from the monitor_hmap.
103 * If there is no such 'mport', returns NULL. */
104 static struct mport
*
105 mport_find(const struct ofport_dpif
*ofport
) OVS_REQUIRES(monitor_mutex
)
109 HMAP_FOR_EACH_WITH_HASH (node
, hmap_node
, hash_pointer(ofport
, 0),
111 if (node
->ofport
== ofport
) {
118 /* Creates a new mport and inserts it into monitor_hmap and monitor_heap,
119 * if it doesn't exist. Otherwise, just updates its fields. */
121 mport_register(const struct ofport_dpif
*ofport
, struct bfd
*bfd
,
122 struct cfm
*cfm
, struct lldp
*lldp
,
123 const struct eth_addr
*hw_addr
)
124 OVS_REQUIRES(monitor_mutex
)
126 struct mport
*mport
= mport_find(ofport
);
129 mport
= xzalloc(sizeof *mport
);
130 mport
->ofport
= ofport
;
131 hmap_insert(&monitor_hmap
, &mport
->hmap_node
, hash_pointer(ofport
, 0));
132 heap_insert(&monitor_heap
, &mport
->heap_node
, 0);
134 mport_update(mport
, bfd
, cfm
, lldp
, hw_addr
);
137 /* Removes mport from monitor_hmap and monitor_heap and frees it. */
139 mport_unregister(const struct ofport_dpif
*ofport
)
140 OVS_REQUIRES(monitor_mutex
)
142 struct mport
*mport
= mport_find(ofport
);
145 mport_update(mport
, NULL
, NULL
, NULL
, NULL
);
146 hmap_remove(&monitor_hmap
, &mport
->hmap_node
);
147 heap_remove(&monitor_heap
, &mport
->heap_node
);
152 /* Updates the fields of an existing mport struct. */
154 mport_update(struct mport
*mport
, struct bfd
*bfd
, struct cfm
*cfm
,
155 struct lldp
*lldp
, const struct eth_addr
*hw_addr
)
156 OVS_REQUIRES(monitor_mutex
)
160 if (mport
->cfm
!= cfm
) {
161 cfm_unref(mport
->cfm
);
162 mport
->cfm
= cfm_ref(cfm
);
164 if (mport
->bfd
!= bfd
) {
165 bfd_unref(mport
->bfd
);
166 mport
->bfd
= bfd_ref(bfd
);
168 if (mport
->lldp
!= lldp
) {
169 lldp_unref(mport
->lldp
);
170 mport
->lldp
= lldp_ref(lldp
);
172 if (hw_addr
&& !eth_addr_equals(mport
->hw_addr
, *hw_addr
)) {
173 mport
->hw_addr
= *hw_addr
;
175 /* If bfd/cfm/lldp is added or reconfigured, move the mport on top of the heap
176 * so that the monitor thread can run the mport next time it wakes up. */
177 if (mport
->bfd
|| mport
->cfm
|| mport
->lldp
) {
178 heap_change(&monitor_heap
, &mport
->heap_node
, LLONG_MAX
);
183 /* The 'main' function for the monitor thread. */
185 monitor_main(void * args OVS_UNUSED
)
187 VLOG_INFO("monitor thread created");
188 while (!latch_is_set(&monitor_exit_latch
)) {
190 latch_wait(&monitor_exit_latch
);
193 VLOG_INFO("monitor thread terminated");
197 /* The monitor thread should wake up this often to ensure that newly added or
198 * reconfigured monitoring ports are run in a timely manner. */
199 #define MONITOR_INTERVAL_MSEC 100
201 /* Checks the 'send_soon' list and the heap for mports that have timed
202 * out bfd/cfm sessions. */
206 uint32_t stub
[512 / 4];
207 long long int prio_now
;
208 struct dp_packet packet
;
210 dp_packet_use_stub(&packet
, stub
, sizeof stub
);
211 ovs_mutex_lock(&monitor_mutex
);
213 /* The monitor_check_send_soon() needs to be run twice. The first
214 * time is for preventing the same 'mport' from being processed twice
215 * (i.e. once from heap, the other from the 'send_soon' array).
216 * The second run is to cover the case when the control packet is sent
217 * via patch port and the other end needs to send back immediately. */
218 monitor_check_send_soon(&packet
);
220 prio_now
= MSEC_TO_PRIO(time_msec());
221 /* Peeks the top of heap and checks if we should run this mport. */
222 while (!heap_is_empty(&monitor_heap
)
223 && heap_max(&monitor_heap
)->priority
>= prio_now
) {
226 mport
= CONTAINER_OF(heap_max(&monitor_heap
), struct mport
, heap_node
);
227 monitor_mport_run(mport
, &packet
);
230 monitor_check_send_soon(&packet
);
232 /* Waits on the earliest next wakeup time. */
233 if (!heap_is_empty(&monitor_heap
)) {
234 long long int next_timeout
, next_mport_wakeup
;
236 next_timeout
= time_msec() + MONITOR_INTERVAL_MSEC
;
237 next_mport_wakeup
= PRIO_TO_MSEC(heap_max(&monitor_heap
)->priority
);
238 poll_timer_wait_until(MIN(next_timeout
, next_mport_wakeup
));
240 ovs_mutex_unlock(&monitor_mutex
);
241 dp_packet_uninit(&packet
);
244 /* Checks the 'send_soon' list for any mport that needs to send cfm/bfd
245 * control packet immediately, and calls monitor_mport_run(). */
247 monitor_check_send_soon(struct dp_packet
*packet
)
248 OVS_REQUIRES(monitor_mutex
)
250 while (!guarded_list_is_empty(&send_soon
)) {
251 struct send_soon_entry
*entry
;
254 entry
= CONTAINER_OF(guarded_list_pop_front(&send_soon
),
255 struct send_soon_entry
, list_node
);
256 mport
= mport_find(entry
->ofport
);
258 monitor_mport_run(mport
, packet
);
264 /* Checks the sending of control packet on 'mport'. Sends the control
265 * packet if needed. Executes bfd and cfm periodic functions (run, wait)
266 * on 'mport'. And changes the location of 'mport' in heap based on next
269 monitor_mport_run(struct mport
*mport
, struct dp_packet
*packet
)
270 OVS_REQUIRES(monitor_mutex
)
272 long long int next_wake_time
;
273 long long int bfd_wake_time
= LLONG_MAX
;
274 long long int cfm_wake_time
= LLONG_MAX
;
275 long long int lldp_wake_time
= LLONG_MAX
;
277 if (mport
->cfm
&& cfm_should_send_ccm(mport
->cfm
)) {
278 dp_packet_clear(packet
);
279 cfm_compose_ccm(mport
->cfm
, packet
, mport
->hw_addr
);
280 ofproto_dpif_send_packet(mport
->ofport
, packet
);
282 if (mport
->bfd
&& bfd_should_send_packet(mport
->bfd
)) {
283 dp_packet_clear(packet
);
284 bfd_put_packet(mport
->bfd
, packet
, mport
->hw_addr
);
285 ofproto_dpif_send_packet(mport
->ofport
, packet
);
287 if (mport
->lldp
&& lldp_should_send_packet(mport
->lldp
)) {
288 dp_packet_clear(packet
);
289 lldp_put_packet(mport
->lldp
, packet
, mport
->hw_addr
);
290 ofproto_dpif_send_packet(mport
->ofport
, packet
);
295 cfm_wake_time
= cfm_wait(mport
->cfm
);
299 bfd_wake_time
= bfd_wait(mport
->bfd
);
302 lldp_wake_time
= lldp_wait(mport
->lldp
);
304 /* Computes the next wakeup time for this mport. */
305 next_wake_time
= MIN(bfd_wake_time
,
307 next_wake_time
= MIN(next_wake_time
, lldp_wake_time
);
308 heap_change(&monitor_heap
, &mport
->heap_node
,
309 MSEC_TO_PRIO(next_wake_time
));
313 /* Creates the mport in monitor module if either bfd or cfm
314 * is configured. Otherwise, deletes the mport.
315 * Also checks whether the monitor thread should be started
318 ofproto_dpif_monitor_port_update(const struct ofport_dpif
*ofport
,
319 struct bfd
*bfd
, struct cfm
*cfm
,
321 const struct eth_addr
*hw_addr
)
323 ovs_mutex_lock(&monitor_mutex
);
324 if (!cfm
&& !bfd
&& !lldp
) {
325 mport_unregister(ofport
);
327 mport_register(ofport
, bfd
, cfm
, lldp
, hw_addr
);
329 ovs_mutex_unlock(&monitor_mutex
);
331 /* If the monitor thread is not running and the hmap
332 * is not empty, starts it. If it is and the hmap is empty,
334 if (!monitor_running
&& !hmap_is_empty(&monitor_hmap
)) {
335 latch_init(&monitor_exit_latch
);
336 monitor_tid
= ovs_thread_create("monitor", monitor_main
, NULL
);
337 monitor_running
= true;
338 } else if (monitor_running
&& hmap_is_empty(&monitor_hmap
)) {
339 latch_set(&monitor_exit_latch
);
340 xpthread_join(monitor_tid
, NULL
);
341 latch_destroy(&monitor_exit_latch
);
342 monitor_running
= false;
346 /* Registers the 'ofport' in the 'send_soon' list. We cannot directly
347 * insert the corresponding mport to the 'send_soon' list, since the
348 * 'send_soon' list is not updated when the mport is removed.
350 * Reader of the 'send_soon' list is responsible for freeing the entry. */
352 ofproto_dpif_monitor_port_send_soon(const struct ofport_dpif
*ofport
)
354 struct send_soon_entry
*entry
= xzalloc(sizeof *entry
);
355 entry
->ofport
= ofport
;
357 guarded_list_push_back(&send_soon
, &entry
->list_node
, SIZE_MAX
);