Branch data Line data Source code
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 : : #include <unistd.h>
18 : :
19 : : #include "chassis.h"
20 : :
21 : : #include "lib/smap.h"
22 : : #include "lib/vswitch-idl.h"
23 : : #include "openvswitch/dynamic-string.h"
24 : : #include "openvswitch/vlog.h"
25 : : #include "ovn/lib/ovn-sb-idl.h"
26 : : #include "ovn-controller.h"
27 : : #include "lib/util.h"
28 : :
29 : 94 : VLOG_DEFINE_THIS_MODULE(chassis);
30 : :
31 : : #ifndef HOST_NAME_MAX
32 : : /* For windows. */
33 : : #define HOST_NAME_MAX 255
34 : : #endif /* HOST_NAME_MAX */
35 : :
36 : : void
37 : 44 : chassis_register_ovs_idl(struct ovsdb_idl *ovs_idl)
38 : : {
39 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch);
40 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids);
41 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_iface_types);
42 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge);
43 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_datapath_type);
44 : 44 : }
45 : :
46 : : static const char *
47 : 85 : pop_tunnel_name(uint32_t *type)
48 : : {
49 [ + + ]: 85 : if (*type & GENEVE) {
50 : 45 : *type &= ~GENEVE;
51 : 45 : return "geneve";
52 [ - + ]: 40 : } else if (*type & STT) {
53 : 0 : *type &= ~STT;
54 : 0 : return "stt";
55 [ + - ]: 40 : } else if (*type & VXLAN) {
56 : 40 : *type &= ~VXLAN;
57 : 40 : return "vxlan";
58 : : }
59 : :
60 : 0 : OVS_NOT_REACHED();
61 : : }
62 : :
63 : : static const char *
64 : 5295 : get_bridge_mappings(const struct smap *ext_ids)
65 : : {
66 : 5295 : return smap_get_def(ext_ids, "ovn-bridge-mappings", "");
67 : : }
68 : :
69 : : /* Returns this chassis's Chassis record, if it is available and is currently
70 : : * amenable to a transaction. */
71 : : const struct sbrec_chassis *
72 : 3167 : chassis_run(struct controller_ctx *ctx, const char *chassis_id,
73 : : const struct ovsrec_bridge *br_int)
74 : : {
75 [ + + ]: 3167 : if (!ctx->ovnsb_idl_txn) {
76 : 497 : return NULL;
77 : : }
78 : :
79 : : const struct ovsrec_open_vswitch *cfg;
80 : : const char *encap_type, *encap_ip;
81 : : static bool inited = false;
82 : :
83 : 2670 : cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
84 [ - + ]: 2670 : if (!cfg) {
85 [ # # ]: 0 : VLOG_INFO("No Open_vSwitch row defined.");
86 : 0 : return NULL;
87 : : }
88 : :
89 : 2670 : encap_type = smap_get(&cfg->external_ids, "ovn-encap-type");
90 : 2670 : encap_ip = smap_get(&cfg->external_ids, "ovn-encap-ip");
91 [ + - ][ - + ]: 2670 : if (!encap_type || !encap_ip) {
92 [ # # ]: 0 : VLOG_INFO("Need to specify an encap type and ip");
93 : 0 : return NULL;
94 : : }
95 : :
96 : 2670 : char *tokstr = xstrdup(encap_type);
97 : 2670 : char *save_ptr = NULL;
98 : : char *token;
99 : 2670 : uint32_t req_tunnels = 0;
100 [ + + ]: 7704 : for (token = strtok_r(tokstr, ",", &save_ptr); token != NULL;
101 : 5034 : token = strtok_r(NULL, ",", &save_ptr)) {
102 : 5034 : uint32_t type = get_tunnel_type(token);
103 [ - + ]: 5034 : if (!type) {
104 [ # # ]: 0 : VLOG_INFO("Unknown tunnel type: %s", token);
105 : : }
106 : 5034 : req_tunnels |= type;
107 : : }
108 : 2670 : free(tokstr);
109 : :
110 : 2670 : const char *hostname = smap_get_def(&cfg->external_ids, "hostname", "");
111 : : char hostname_[HOST_NAME_MAX + 1];
112 [ + - ]: 2670 : if (!hostname[0]) {
113 [ - + ]: 2670 : if (gethostname(hostname_, sizeof hostname_)) {
114 : 0 : hostname_[0] = '\0';
115 : : }
116 : 2670 : hostname = hostname_;
117 : : }
118 : :
119 : 2670 : const char *bridge_mappings = get_bridge_mappings(&cfg->external_ids);
120 : 2670 : const char *datapath_type =
121 [ + - ][ + - ]: 2670 : br_int && br_int->datapath_type ? br_int->datapath_type : "";
122 : :
123 : 2670 : struct ds iface_types = DS_EMPTY_INITIALIZER;
124 : 2670 : ds_put_cstr(&iface_types, "");
125 [ + + ]: 36462 : for (int j = 0; j < cfg->n_iface_types; j++) {
126 : 33792 : ds_put_format(&iface_types, "%s,", cfg->iface_types[j]);
127 : : }
128 : 2670 : ds_chomp(&iface_types, ',');
129 : 2670 : const char *iface_types_str = ds_cstr(&iface_types);
130 : :
131 : 2670 : const struct sbrec_chassis *chassis_rec
132 : 2670 : = get_chassis(ctx->ovnsb_idl, chassis_id);
133 : :
134 [ + + ]: 2670 : if (chassis_rec) {
135 [ - + ]: 2625 : if (strcmp(hostname, chassis_rec->hostname)) {
136 : 0 : sbrec_chassis_set_hostname(chassis_rec, hostname);
137 : : }
138 : :
139 : : /* Determine new values for Chassis external-ids. */
140 : 2625 : const char *chassis_bridge_mappings
141 : 2625 : = get_bridge_mappings(&chassis_rec->external_ids);
142 : 2625 : const char *chassis_datapath_type
143 : 2625 : = smap_get_def(&chassis_rec->external_ids, "datapath-type", "");
144 : 2625 : const char *chassis_iface_types
145 : 2625 : = smap_get_def(&chassis_rec->external_ids, "iface-types", "");
146 : :
147 : : /* If any of the external-ids should change, update them. */
148 [ + + ][ + + ]: 2625 : if (strcmp(bridge_mappings, chassis_bridge_mappings) ||
149 [ + + ]: 2617 : strcmp(datapath_type, chassis_datapath_type) ||
150 : 2617 : strcmp(iface_types_str, chassis_iface_types)) {
151 : : struct smap new_ids;
152 : 9 : smap_clone(&new_ids, &chassis_rec->external_ids);
153 : 9 : smap_replace(&new_ids, "ovn-bridge-mappings", bridge_mappings);
154 : 9 : smap_replace(&new_ids, "datapath-type", datapath_type);
155 : 9 : smap_replace(&new_ids, "iface-types", iface_types_str);
156 : 9 : sbrec_chassis_verify_external_ids(chassis_rec);
157 : 9 : sbrec_chassis_set_external_ids(chassis_rec, &new_ids);
158 : 9 : smap_destroy(&new_ids);
159 : : }
160 : :
161 : : /* Compare desired tunnels against those currently in the database. */
162 : 2625 : uint32_t cur_tunnels = 0;
163 : 2625 : bool same = true;
164 [ + + ]: 7574 : for (int i = 0; i < chassis_rec->n_encaps; i++) {
165 : 4949 : cur_tunnels |= get_tunnel_type(chassis_rec->encaps[i]->type);
166 [ + - ][ + - ]: 4949 : same = same && !strcmp(chassis_rec->encaps[i]->ip, encap_ip);
167 : :
168 [ + - ][ + - ]: 4949 : same = same && smap_get_bool(&chassis_rec->encaps[i]->options,
169 : : "csum", false);
170 : : }
171 [ + - ][ + - ]: 2625 : same = same && req_tunnels == cur_tunnels;
172 : :
173 [ + - ]: 2625 : if (same) {
174 : : /* Nothing changed. */
175 : 2625 : inited = true;
176 : 2625 : ds_destroy(&iface_types);
177 : 2625 : return chassis_rec;
178 [ # # ]: 0 : } else if (!inited) {
179 : 0 : struct ds cur_encaps = DS_EMPTY_INITIALIZER;
180 [ # # ]: 0 : for (int i = 0; i < chassis_rec->n_encaps; i++) {
181 : 0 : ds_put_format(&cur_encaps, "%s,",
182 : 0 : chassis_rec->encaps[i]->type);
183 : : }
184 : 0 : ds_chomp(&cur_encaps, ',');
185 : :
186 [ # # ]: 0 : VLOG_WARN("Chassis config changing on startup, make sure "
187 : : "multiple chassis are not configured : %s/%s->%s/%s",
188 : : ds_cstr(&cur_encaps),
189 : : chassis_rec->encaps[0]->ip,
190 : : encap_type, encap_ip);
191 : 0 : ds_destroy(&cur_encaps);
192 : : }
193 : : }
194 : :
195 : 45 : ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
196 : : "ovn-controller: registering chassis '%s'",
197 : : chassis_id);
198 : :
199 [ + - ]: 45 : if (!chassis_rec) {
200 : 45 : struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
201 : 45 : smap_add(&ext_ids, "ovn-bridge-mappings", bridge_mappings);
202 : 45 : smap_add(&ext_ids, "datapath-type", datapath_type);
203 : 45 : smap_add(&ext_ids, "iface-types", iface_types_str);
204 : 45 : chassis_rec = sbrec_chassis_insert(ctx->ovnsb_idl_txn);
205 : 45 : sbrec_chassis_set_name(chassis_rec, chassis_id);
206 : 45 : sbrec_chassis_set_hostname(chassis_rec, hostname);
207 : 45 : sbrec_chassis_set_external_ids(chassis_rec, &ext_ids);
208 : 45 : smap_destroy(&ext_ids);
209 : : }
210 : :
211 : 45 : ds_destroy(&iface_types);
212 : 45 : int n_encaps = count_1bits(req_tunnels);
213 : 45 : struct sbrec_encap **encaps = xmalloc(n_encaps * sizeof *encaps);
214 : 45 : const struct smap options = SMAP_CONST1(&options, "csum", "true");
215 : :
216 [ + + ]: 130 : for (int i = 0; i < n_encaps; i++) {
217 : 85 : const char *type = pop_tunnel_name(&req_tunnels);
218 : :
219 : 85 : encaps[i] = sbrec_encap_insert(ctx->ovnsb_idl_txn);
220 : :
221 : 85 : sbrec_encap_set_type(encaps[i], type);
222 : 85 : sbrec_encap_set_ip(encaps[i], encap_ip);
223 : 85 : sbrec_encap_set_options(encaps[i], &options);
224 : : }
225 : :
226 : 45 : sbrec_chassis_set_encaps(chassis_rec, encaps, n_encaps);
227 : 45 : free(encaps);
228 : :
229 : 45 : inited = true;
230 : 3167 : return chassis_rec;
231 : : }
232 : :
233 : : /* Returns true if the database is all cleaned up, false if more work is
234 : : * required. */
235 : : bool
236 : 138 : chassis_cleanup(struct controller_ctx *ctx, const char *chassis_id)
237 : : {
238 [ - + ]: 138 : if (!chassis_id) {
239 : 0 : return true;
240 : : }
241 : :
242 : : /* Delete Chassis row. */
243 : 138 : const struct sbrec_chassis *chassis_rec
244 : 138 : = get_chassis(ctx->ovnsb_idl, chassis_id);
245 [ + + ]: 138 : if (!chassis_rec) {
246 : 94 : return true;
247 : : }
248 [ + - ]: 44 : if (ctx->ovnsb_idl_txn) {
249 : 44 : ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
250 : : "ovn-controller: unregistering chassis '%s'",
251 : : chassis_id);
252 : 44 : sbrec_chassis_delete(chassis_rec);
253 : : }
254 : 44 : return false;
255 : : }
|