Merge "master" into "ovn".
[cascardo/ovs.git] / ovn / controller / binding.c
1 /* Copyright (c) 2015 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 #include "binding.h"
18
19 #include "lib/sset.h"
20 #include "lib/util.h"
21 #include "lib/vswitch-idl.h"
22 #include "openvswitch/vlog.h"
23 #include "ovn/lib/ovn-sb-idl.h"
24 #include "ovn-controller.h"
25
26 VLOG_DEFINE_THIS_MODULE(binding);
27
28 void
29 binding_init(struct controller_ctx *ctx)
30 {
31     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch);
32     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_bridges);
33
34     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge);
35     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_name);
36     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports);
37
38     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port);
39     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_name);
40     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_interfaces);
41
42     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_interface);
43     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_name);
44     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
45 }
46
47 static void
48 get_local_iface_ids(struct controller_ctx *ctx, struct sset *lports)
49 {
50     int i;
51
52     for (i = 0; i < ctx->br_int->n_ports; i++) {
53         const struct ovsrec_port *port_rec = ctx->br_int->ports[i];
54         const char *iface_id;
55         int j;
56
57         if (!strcmp(port_rec->name, ctx->br_int_name)) {
58             continue;
59         }
60
61         for (j = 0; j < port_rec->n_interfaces; j++) {
62             const struct ovsrec_interface *iface_rec;
63
64             iface_rec = port_rec->interfaces[j];
65             iface_id = smap_get(&iface_rec->external_ids, "iface-id");
66             if (!iface_id) {
67                 continue;
68             }
69             sset_add(lports, iface_id);
70         }
71     }
72 }
73
74 void
75 binding_run(struct controller_ctx *ctx)
76 {
77     const struct sbrec_binding *binding_rec;
78     struct ovsdb_idl_txn *txn;
79     struct sset lports, all_lports;
80     const char *name;
81     int retval;
82
83     sset_init(&lports);
84     sset_init(&all_lports);
85     get_local_iface_ids(ctx, &lports);
86     sset_clone(&all_lports, &lports);
87
88     txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
89     ovsdb_idl_txn_add_comment(txn,
90                               "ovn-controller: updating bindings for '%s'",
91                               ctx->chassis_id);
92
93     SBREC_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
94         if (sset_find_and_delete(&lports, binding_rec->logical_port) ||
95                 (binding_rec->parent_port && binding_rec->parent_port[0] &&
96                  sset_contains(&all_lports, binding_rec->parent_port))) {
97             if (!strcmp(binding_rec->chassis, ctx->chassis_id)) {
98                 continue;
99             }
100             if (binding_rec->chassis[0]) {
101                 VLOG_INFO("Changing chassis for lport %s from %s to %s",
102                           binding_rec->logical_port, binding_rec->chassis,
103                           ctx->chassis_id);
104             }
105             sbrec_binding_set_chassis(binding_rec, ctx->chassis_id);
106         } else if (!strcmp(binding_rec->chassis, ctx->chassis_id)) {
107             sbrec_binding_set_chassis(binding_rec, "");
108         }
109     }
110
111     retval = ovsdb_idl_txn_commit_block(txn);
112     if (retval == TXN_ERROR) {
113         VLOG_INFO("Problem committing binding information: %s",
114                   ovsdb_idl_txn_status_to_string(retval));
115     }
116
117     ovsdb_idl_txn_destroy(txn);
118
119     SSET_FOR_EACH (name, &lports) {
120         VLOG_DBG("No binding record for lport %s", name);
121     }
122     sset_destroy(&lports);
123     sset_destroy(&all_lports);
124 }
125
126 void
127 binding_destroy(struct controller_ctx *ctx)
128 {
129     int retval = TXN_TRY_AGAIN;
130
131     ovs_assert(ctx->ovnsb_idl);
132
133     while (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
134         const struct sbrec_binding *binding_rec;
135         struct ovsdb_idl_txn *txn;
136
137         txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
138         ovsdb_idl_txn_add_comment(txn,
139                               "ovn-controller: removing all bindings for '%s'",
140                               ctx->chassis_id);
141
142         SBREC_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
143             if (!strcmp(binding_rec->chassis, ctx->chassis_id)) {
144                 sbrec_binding_set_chassis(binding_rec, "");
145             }
146         }
147
148         retval = ovsdb_idl_txn_commit_block(txn);
149         if (retval == TXN_ERROR) {
150             VLOG_INFO("Problem removing bindings: %s",
151                       ovsdb_idl_txn_status_to_string(retval));
152         }
153
154         ovsdb_idl_txn_destroy(txn);
155     }
156 }