Merge branch 'mainstream'
[sliver-openvswitch.git] / ofproto / ofproto-dpif-monitor.c
1 /*
2  * Copyright (c) 2009, 2010, 2011, 2012, 2013 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 #include "ofproto-dpif-monitor.h"
19
20 #include <string.h>
21
22 #include "bfd.h"
23 #include "cfm.h"
24 #include "hash.h"
25 #include "hmap.h"
26 #include "ofpbuf.h"
27 #include "ofproto-dpif.h"
28 #include "util.h"
29 #include "vlog.h"
30
31 /* Monitored port.  It owns references to ofport, bfd, cfm structs. */
32 struct mport {
33     struct hmap_node hmap_node;       /* In monitor_hmap. */
34     const struct ofport_dpif *ofport; /* The corresponding ofport. */
35
36     struct cfm *cfm;                  /* Reference to cfm. */
37     struct bfd *bfd;                  /* Reference to bfd. */
38     uint8_t hw_addr[OFP_ETH_ALEN];    /* Hardware address. */
39 };
40
41 /* hmap that contains "struct mport"s. */
42 static struct hmap monitor_hmap = HMAP_INITIALIZER(&monitor_hmap);
43
44 static struct ovs_rwlock monitor_rwlock = OVS_RWLOCK_INITIALIZER;
45
46 static void mport_register(const struct ofport_dpif *, struct bfd *,
47                            struct cfm *, uint8_t[ETH_ADDR_LEN])
48     OVS_REQ_WRLOCK(monitor_rwlock);
49 static void mport_unregister(const struct ofport_dpif *)
50     OVS_REQ_WRLOCK(monitor_rwlock);
51 static void mport_update(struct mport *, struct bfd *, struct cfm *,
52                          uint8_t[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock);
53 static struct mport *mport_find(const struct ofport_dpif *)
54     OVS_REQ_WRLOCK(monitor_rwlock);
55
56 /* Tries finding and returning the 'mport' from the monitor_hmap.
57  * If there is no such 'mport', returns NULL. */
58 static struct mport *
59 mport_find(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(monitor_rwlock)
60 {
61     struct mport *node;
62
63     HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_pointer(ofport, 0),
64                              &monitor_hmap) {
65         if (node->ofport == ofport) {
66             return node;
67         }
68     }
69     return NULL;
70 }
71
72 /* Creates a new mport and inserts it into monitor_hmap, if it doesn't exist.
73  * Otherwise, just updates its fields. */
74 static void
75 mport_register(const struct ofport_dpif *ofport, struct bfd *bfd,
76                struct cfm *cfm, uint8_t *hw_addr)
77     OVS_REQ_WRLOCK(monitor_rwlock)
78 {
79     struct mport *mport = mport_find(ofport);
80
81     if (!mport) {
82         mport = xzalloc(sizeof *mport);
83         mport->ofport = ofport;
84         hmap_insert(&monitor_hmap, &mport->hmap_node, hash_pointer(ofport, 0));
85     }
86     mport_update(mport, bfd, cfm, hw_addr);
87 }
88
89 /* Removes mport from monitor_hmap and frees it. */
90 static void
91 mport_unregister(const struct ofport_dpif *ofport)
92     OVS_REQ_WRLOCK(monitor_rwlock)
93 {
94     struct mport *mport = mport_find(ofport);
95
96     if (mport) {
97         mport_update(mport, NULL, NULL, NULL);
98         hmap_remove(&monitor_hmap, &mport->hmap_node);
99         free(mport);
100     }
101 }
102
103 /* Updates the fields of an existing mport struct. */
104 static void
105 mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm,
106              uint8_t hw_addr[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock)
107 {
108     ovs_assert(mport);
109
110     if (mport->cfm != cfm) {
111         cfm_unref(mport->cfm);
112         mport->cfm = cfm_ref(cfm);
113     }
114     if (mport->bfd != bfd) {
115         bfd_unref(mport->bfd);
116         mport->bfd = bfd_ref(bfd);
117     }
118     if (hw_addr && memcmp(mport->hw_addr, hw_addr, ETH_ADDR_LEN)) {
119         memcpy(mport->hw_addr, hw_addr, ETH_ADDR_LEN);
120     }
121 }
122 \f
123
124 /* Creates the mport in monitor module if either bfd or cfm
125  * is configured.  Otherwise, deletes the mport. */
126 void
127 ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport,
128                                  struct bfd *bfd, struct cfm *cfm,
129                                  uint8_t hw_addr[ETH_ADDR_LEN])
130 {
131     ovs_rwlock_wrlock(&monitor_rwlock);
132     if (!cfm && !bfd) {
133         mport_unregister(ofport);
134     } else {
135         mport_register(ofport, bfd, cfm, hw_addr);
136     }
137     ovs_rwlock_unlock(&monitor_rwlock);
138 }
139
140 /* Checks the sending of control packets on all mports.  Sends the control
141  * packets if needed. */
142 void
143 ofproto_dpif_monitor_run_fast(void)
144 {
145     uint32_t stub[512 / 4];
146     struct ofpbuf packet;
147     struct mport *mport;
148
149     ofpbuf_use_stub(&packet, stub, sizeof stub);
150     ovs_rwlock_rdlock(&monitor_rwlock);
151     HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) {
152         if (mport->cfm && cfm_should_send_ccm(mport->cfm)) {
153             ofpbuf_clear(&packet);
154             cfm_compose_ccm(mport->cfm, &packet, mport->hw_addr);
155             ofproto_dpif_send_packet(mport->ofport, &packet);
156         }
157         if (mport->bfd && bfd_should_send_packet(mport->bfd)) {
158             ofpbuf_clear(&packet);
159             bfd_put_packet(mport->bfd, &packet, mport->hw_addr);
160             ofproto_dpif_send_packet(mport->ofport, &packet);
161         }
162     }
163     ovs_rwlock_unlock(&monitor_rwlock);
164     ofpbuf_uninit(&packet);
165 }
166
167 /* Executes bfd_run(), cfm_run() on all mports. */
168 void
169 ofproto_dpif_monitor_run(void)
170 {
171     struct mport *mport;
172
173     ovs_rwlock_rdlock(&monitor_rwlock);
174     HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) {
175         if (mport->cfm) {
176             cfm_run(mport->cfm);
177         }
178         if (mport->bfd) {
179             bfd_run(mport->bfd);
180         }
181     }
182     ovs_rwlock_unlock(&monitor_rwlock);
183 }
184
185 /* Executes the bfd_wait() and cfm_wait() functions on all mports. */
186 void
187 ofproto_dpif_monitor_wait(void)
188 {
189     struct mport *mport;
190
191     ovs_rwlock_rdlock(&monitor_rwlock);
192     HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) {
193         if (mport->cfm) {
194             cfm_wait(mport->cfm);
195         }
196         if (mport->bfd) {
197             bfd_wait(mport->bfd);
198         }
199     }
200     ovs_rwlock_unlock(&monitor_rwlock);
201 }