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