080b27fc42a0c96770053e6b62faaaa83d14f18e
[cascardo/ovs.git] / ovn / controller / lport.c
1 /* Copyright (c) 2015, 2016 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
16 #include <config.h>
17
18 #include "lport.h"
19 #include "hash.h"
20 #include "lflow.h"
21 #include "openvswitch/vlog.h"
22 #include "ovn/lib/ovn-sb-idl.h"
23
24 VLOG_DEFINE_THIS_MODULE(lport);
25
26 /* A logical port. */
27 struct lport {
28     struct hmap_node name_node;  /* Index by name. */
29     struct hmap_node key_node;   /* Index by (dp_key, port_key). */
30     struct hmap_node uuid_node;  /* Index by row uuid. */
31     struct uuid uuid;
32     const struct sbrec_port_binding *pb;
33 };
34
35 static bool full_lport_rebuild = false;
36
37 void
38 lport_index_reset(void)
39 {
40     full_lport_rebuild = true;
41 }
42
43 void
44 lport_index_init(struct lport_index *lports)
45 {
46     hmap_init(&lports->by_name);
47     hmap_init(&lports->by_key);
48     hmap_init(&lports->by_uuid);
49 }
50
51 void
52 lport_index_remove(struct lport_index *lports, const struct uuid *uuid)
53 {
54     const struct lport *port_ = lport_lookup_by_uuid(lports, uuid);
55     struct lport *port = CONST_CAST(struct lport *, port_);
56     if (port) {
57         hmap_remove(&lports->by_name, &port->name_node);
58         hmap_remove(&lports->by_key, &port->key_node);
59         hmap_remove(&lports->by_uuid, &port->uuid_node);
60         free(port);
61     }
62 }
63
64 void
65 lport_index_clear(struct lport_index *lports)
66 {
67     /* Destroy all of the "struct lport"s.
68      *
69      * We have to remove the node from all indexes. */
70     struct lport *port, *next;
71     HMAP_FOR_EACH_SAFE (port, next, name_node, &lports->by_name) {
72         hmap_remove(&lports->by_name, &port->name_node);
73         hmap_remove(&lports->by_key, &port->key_node);
74         hmap_remove(&lports->by_uuid, &port->uuid_node);
75         free(port);
76     }
77 }
78
79 static void
80 consider_lport_index(struct lport_index *lports,
81                      const struct sbrec_port_binding *pb)
82 {
83     if (lport_lookup_by_name(lports, pb->logical_port)) {
84         return;
85     }
86
87     struct lport *p = xmalloc(sizeof *p);
88     hmap_insert(&lports->by_name, &p->name_node,
89                 hash_string(pb->logical_port, 0));
90     hmap_insert(&lports->by_key, &p->key_node,
91                 hash_int(pb->tunnel_key, pb->datapath->tunnel_key));
92     hmap_insert(&lports->by_uuid, &p->uuid_node,
93                 uuid_hash(&pb->header_.uuid));
94     memcpy(&p->uuid, &pb->header_.uuid, sizeof p->uuid);
95     p->pb = pb;
96 }
97
98 void
99 lport_index_fill(struct lport_index *lports, struct ovsdb_idl *ovnsb_idl)
100 {
101     const struct sbrec_port_binding *pb;
102     if (full_lport_rebuild) {
103         lport_index_clear(lports);
104         SBREC_PORT_BINDING_FOR_EACH (pb, ovnsb_idl) {
105             consider_lport_index(lports, pb);
106         }
107         full_lport_rebuild = false;
108     } else {
109         SBREC_PORT_BINDING_FOR_EACH_TRACKED (pb, ovnsb_idl) {
110             if (sbrec_port_binding_is_deleted(pb)) {
111                 lport_index_remove(lports, &pb->header_.uuid);
112             } else {
113                 consider_lport_index(lports, pb);
114             }
115         }
116     }
117 }
118
119 void
120 lport_index_destroy(struct lport_index *lports)
121 {
122     lport_index_clear(lports);
123
124     hmap_destroy(&lports->by_name);
125     hmap_destroy(&lports->by_key);
126     hmap_destroy(&lports->by_uuid);
127 }
128
129 /* Finds and returns the lport with the given 'name', or NULL if no such lport
130  * exists. */
131 const struct sbrec_port_binding *
132 lport_lookup_by_name(const struct lport_index *lports, const char *name)
133 {
134     const struct lport *lport;
135     HMAP_FOR_EACH_WITH_HASH (lport, name_node, hash_string(name, 0),
136                              &lports->by_name) {
137         if (!strcmp(lport->pb->logical_port, name)) {
138             return lport->pb;
139         }
140     }
141     return NULL;
142 }
143
144 const struct lport *
145 lport_lookup_by_uuid(const struct lport_index *lports,
146                      const struct uuid *uuid)
147 {
148     const struct lport *lport;
149     HMAP_FOR_EACH_WITH_HASH (lport, uuid_node, uuid_hash(uuid),
150                              &lports->by_uuid) {
151         if (uuid_equals(uuid, &lport->uuid)) {
152             return lport;
153         }
154     }
155     return NULL;
156 }
157
158 const struct sbrec_port_binding *
159 lport_lookup_by_key(const struct lport_index *lports,
160                     uint32_t dp_key, uint16_t port_key)
161 {
162     const struct lport *lport;
163     HMAP_FOR_EACH_WITH_HASH (lport, key_node, hash_int(port_key, dp_key),
164                              &lports->by_key) {
165         if (port_key == lport->pb->tunnel_key
166             && dp_key == lport->pb->datapath->tunnel_key) {
167             return lport->pb;
168         }
169     }
170     return NULL;
171 }
172 \f
173 struct mcgroup {
174     struct hmap_node dp_name_node; /* Index by (logical datapath, name). */
175     struct hmap_node uuid_node;    /* Index by insert uuid. */
176     struct uuid uuid;
177     const struct sbrec_multicast_group *mg;
178 };
179
180 static bool full_mc_rebuild = false;
181
182 void
183 mcgroup_index_reset(void)
184 {
185     full_mc_rebuild = true;
186 }
187
188 void
189 mcgroup_index_init(struct mcgroup_index *mcgroups)
190 {
191     hmap_init(&mcgroups->by_dp_name);
192     hmap_init(&mcgroups->by_uuid);
193 }
194
195 void
196 mcgroup_index_remove(struct mcgroup_index *mcgroups, const struct uuid *uuid)
197 {
198     const struct mcgroup *mcgroup_ = mcgroup_lookup_by_uuid(mcgroups, uuid);
199     struct mcgroup *mcgroup = CONST_CAST(struct mcgroup *, mcgroup_);
200     if (mcgroup) {
201         hmap_remove(&mcgroups->by_dp_name, &mcgroup->dp_name_node);
202         hmap_remove(&mcgroups->by_uuid, &mcgroup->uuid_node);
203         free(mcgroup);
204     }
205 }
206
207 void
208 mcgroup_index_clear(struct mcgroup_index *mcgroups)
209 {
210     struct mcgroup *mcgroup, *next;
211     HMAP_FOR_EACH_SAFE (mcgroup, next, dp_name_node, &mcgroups->by_dp_name) {
212         hmap_remove(&mcgroups->by_dp_name, &mcgroup->dp_name_node);
213         hmap_remove(&mcgroups->by_uuid, &mcgroup->uuid_node);
214         free(mcgroup);
215     }
216 }
217
218 static void
219 consider_mcgroup_index(struct mcgroup_index *mcgroups,
220                        const struct sbrec_multicast_group *mg)
221 {
222     const struct uuid *dp_uuid = &mg->datapath->header_.uuid;
223     if (mcgroup_lookup_by_dp_name(mcgroups, mg->datapath, mg->name)) {
224         return;
225     }
226
227     struct mcgroup *m = xmalloc(sizeof *m);
228     hmap_insert(&mcgroups->by_dp_name, &m->dp_name_node,
229                 hash_string(mg->name, uuid_hash(dp_uuid)));
230     hmap_insert(&mcgroups->by_uuid, &m->uuid_node,
231                 uuid_hash(&mg->header_.uuid));
232     memcpy(&m->uuid, &mg->header_.uuid, sizeof m->uuid);
233     m->mg = mg;
234 }
235
236 void
237 mcgroup_index_fill(struct mcgroup_index *mcgroups, struct ovsdb_idl *ovnsb_idl)
238 {
239     const struct sbrec_multicast_group *mg;
240     if (full_mc_rebuild) {
241         mcgroup_index_clear(mcgroups);
242         SBREC_MULTICAST_GROUP_FOR_EACH (mg, ovnsb_idl) {
243             consider_mcgroup_index(mcgroups, mg);
244         }
245         full_mc_rebuild = false;
246     } else {
247         SBREC_MULTICAST_GROUP_FOR_EACH_TRACKED (mg, ovnsb_idl) {
248             if (sbrec_multicast_group_is_deleted(mg)) {
249                 mcgroup_index_remove(mcgroups, &mg->header_.uuid);
250             } else {
251                 consider_mcgroup_index(mcgroups, mg);
252             }
253         }
254     }
255 }
256
257 void
258 mcgroup_index_destroy(struct mcgroup_index *mcgroups)
259 {
260     mcgroup_index_clear(mcgroups);
261
262     hmap_destroy(&mcgroups->by_dp_name);
263 }
264
265 const struct mcgroup *
266 mcgroup_lookup_by_uuid(const struct mcgroup_index *mcgroups,
267                        const struct uuid *uuid)
268 {
269     const struct mcgroup *mcgroup;
270     HMAP_FOR_EACH_WITH_HASH (mcgroup, uuid_node, uuid_hash(uuid),
271                              &mcgroups->by_uuid) {
272         if (uuid_equals(&mcgroup->uuid, uuid)) {
273             return mcgroup;
274         }
275     }
276     return NULL;
277 }
278
279 const struct sbrec_multicast_group *
280 mcgroup_lookup_by_dp_name(const struct mcgroup_index *mcgroups,
281                           const struct sbrec_datapath_binding *dp,
282                           const char *name)
283 {
284     const struct uuid *dp_uuid = &dp->header_.uuid;
285     const struct mcgroup *mcgroup;
286     HMAP_FOR_EACH_WITH_HASH (mcgroup, dp_name_node,
287                              hash_string(name, uuid_hash(dp_uuid)),
288                              &mcgroups->by_dp_name) {
289         if (uuid_equals(&mcgroup->mg->datapath->header_.uuid, dp_uuid)
290             && !strcmp(mcgroup->mg->name, name)) {
291             return mcgroup->mg;
292         }
293     }
294     return NULL;
295 }