Branch data Line data Source code
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 "gateway.h"
18 : :
19 : : #include "lib/poll-loop.h"
20 : : #include "lib/simap.h"
21 : : #include "lib/sset.h"
22 : : #include "lib/util.h"
23 : : #include "openvswitch/vlog.h"
24 : : #include "ovn/lib/ovn-sb-idl.h"
25 : : #include "vtep/vtep-idl.h"
26 : : #include "ovn-controller-vtep.h"
27 : :
28 : 14 : VLOG_DEFINE_THIS_MODULE(gateway);
29 : :
30 : : /*
31 : : * Registers the physical switches in vtep to ovnsb as chassis. For each
32 : : * physical switch in the vtep database, finds all vtep logical switches that
33 : : * are associated with the physical switch, and updates the corresponding
34 : : * chassis's 'vtep_logical_switches' column.
35 : : *
36 : : */
37 : :
38 : : /* Global revalidation sequence number, incremented at each call to
39 : : * 'revalidate_gateway()'. */
40 : : static unsigned int gw_reval_seq;
41 : :
42 : : /* Maps all chassis created by the gateway module to their own reval_seq. */
43 : : static struct simap gw_chassis_map = SIMAP_INITIALIZER(&gw_chassis_map);
44 : :
45 : : /* Creates and returns a new instance of 'struct sbrec_chassis'. */
46 : : static const struct sbrec_chassis *
47 : 10 : create_chassis_rec(struct ovsdb_idl_txn *txn, const char *name,
48 : : const char *encap_ip)
49 : : {
50 : : const struct sbrec_chassis *chassis_rec;
51 : : struct sbrec_encap *encap_rec;
52 : :
53 [ + - ]: 10 : VLOG_INFO("add Chassis row for VTEP physical switch (%s)", name);
54 : :
55 : 10 : chassis_rec = sbrec_chassis_insert(txn);
56 : 10 : sbrec_chassis_set_name(chassis_rec, name);
57 : 10 : encap_rec = sbrec_encap_insert(txn);
58 : 10 : sbrec_encap_set_type(encap_rec, OVN_SB_ENCAP_TYPE);
59 : 10 : sbrec_encap_set_ip(encap_rec, encap_ip);
60 : 10 : const struct smap options = SMAP_CONST1(&options, "csum", "false");
61 : 10 : sbrec_encap_set_options(encap_rec, &options);
62 : 10 : sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1);
63 : :
64 : 10 : return chassis_rec;
65 : : }
66 : :
67 : : /* Revalidates chassis in ovnsb against vtep database. Creates chassis for
68 : : * new vtep physical switch. And removes chassis which no longer have
69 : : * physical switch in vtep.
70 : : *
71 : : * xxx: Support multiple tunnel encaps.
72 : : *
73 : : * */
74 : : static void
75 : 224 : revalidate_gateway(struct controller_vtep_ctx *ctx)
76 : : {
77 : : const struct vteprec_physical_switch *pswitch;
78 : :
79 : : /* Increments the global revalidation sequence number. */
80 : 224 : gw_reval_seq++;
81 : :
82 : 224 : ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
83 : : "ovn-controller-vtep: updating vtep chassis");
84 : :
85 [ + + ]: 462 : VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
86 : : const struct sbrec_chassis *chassis_rec;
87 : : struct simap_node *gw_node;
88 : : const char *encap_ip;
89 : :
90 [ + + ]: 238 : encap_ip = pswitch->n_tunnel_ips ? pswitch->tunnel_ips[0] : "";
91 : 238 : gw_node = simap_find(&gw_chassis_map, pswitch->name);
92 : 238 : chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
93 [ + + ]: 238 : if (chassis_rec) {
94 [ - + ][ # # ]: 228 : if (!gw_node &&
95 : 0 : (strcmp(chassis_rec->encaps[0]->type, OVN_SB_ENCAP_TYPE)
96 [ # # ]: 0 : || strcmp(chassis_rec->encaps[0]->ip, encap_ip))) {
97 [ # # ]: 0 : VLOG_WARN("Chassis config changing on startup, make sure "
98 : : "multiple chassis are not configured : %s/%s->%s/%s",
99 : : chassis_rec->encaps[0]->type,
100 : : chassis_rec->encaps[0]->ip,
101 : : OVN_SB_ENCAP_TYPE, encap_ip);
102 : : }
103 : : /* Updates chassis's encap if anything changed. */
104 [ - + ]: 228 : if (strcmp(chassis_rec->encaps[0]->type, OVN_SB_ENCAP_TYPE)) {
105 [ # # ]: 0 : VLOG_WARN("Chassis for VTEP physical switch (%s) can only have "
106 : : "encap type \"%s\"", pswitch->name, OVN_SB_ENCAP_TYPE);
107 : 0 : sbrec_encap_set_type(chassis_rec->encaps[0], OVN_SB_ENCAP_TYPE);
108 : : }
109 [ + + ]: 228 : if (strcmp(chassis_rec->encaps[0]->ip, encap_ip)) {
110 : 1 : sbrec_encap_set_ip(chassis_rec->encaps[0], encap_ip);
111 : : }
112 [ - + ]: 228 : if (smap_get_bool(&chassis_rec->encaps[0]->options, "csum", true)) {
113 : 0 : const struct smap options = SMAP_CONST1(&options, "csum",
114 : : "false");
115 : 228 : sbrec_encap_set_options(chassis_rec->encaps[0], &options);
116 : : }
117 : : } else {
118 [ + + ]: 10 : if (gw_node) {
119 [ + - ]: 1 : VLOG_WARN("Chassis for VTEP physical switch (%s) disappears, "
120 : : "maybe deleted by ovn-sbctl, adding it back",
121 : : pswitch->name);
122 : : }
123 : : /* Creates a new chassis for the VTEP physical switch. */
124 : 10 : create_chassis_rec(ctx->ovnsb_idl_txn, pswitch->name, encap_ip);
125 : : }
126 : : /* Updates or creates the simap node for 'pswitch->name'. */
127 : 238 : simap_put(&gw_chassis_map, pswitch->name, gw_reval_seq);
128 : : }
129 : :
130 : : struct simap_node *iter, *next;
131 : : /* For 'gw_node' in 'gw_chassis_map' whose data is not
132 : : * 'gw_reval_seq', it means the corresponding physical switch no
133 : : * longer exist. So, garbage collects them. */
134 [ + + ][ - + ]: 464 : SIMAP_FOR_EACH_SAFE (iter, next, &gw_chassis_map) {
[ + + ]
135 [ + + ]: 240 : if (iter->data != gw_reval_seq) {
136 : : const struct sbrec_chassis *chassis_rec;
137 : :
138 : 2 : chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, iter->name);
139 [ + - ]: 2 : if (chassis_rec) {
140 : 2 : sbrec_chassis_delete(chassis_rec);
141 : : }
142 : 2 : simap_delete(&gw_chassis_map, iter);
143 : : }
144 : : }
145 : 224 : }
146 : :
147 : : /* Updates the 'vtep_logical_switches' column in the Chassis table based
148 : : * on vtep database configuration. */
149 : : static void
150 : 224 : update_vtep_logical_switches(struct controller_vtep_ctx *ctx)
151 : : {
152 : : const struct vteprec_physical_switch *pswitch;
153 : :
154 : 224 : ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, "ovn-controller-vtep: "
155 : : "updating chassis's vtep_logical_switches");
156 : :
157 [ + + ]: 462 : VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
158 : 238 : const struct sbrec_chassis *chassis_rec =
159 : 238 : get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
160 : 238 : struct sset lswitches = SSET_INITIALIZER(&lswitches);
161 : : size_t i;
162 : :
163 [ + + ]: 644 : for (i = 0; i < pswitch->n_ports; i++) {
164 : 406 : const struct vteprec_physical_port *port = pswitch->ports[i];
165 : : size_t j;
166 : :
167 [ + + ]: 682 : for (j = 0; j < port->n_vlan_bindings; j++) {
168 : : const struct vteprec_logical_switch *vtep_lswitch;
169 : :
170 : 276 : vtep_lswitch = port->value_vlan_bindings[j];
171 : : /* If not already in 'lswitches', records it. */
172 [ + + ]: 276 : if (!sset_find(&lswitches, vtep_lswitch->name)) {
173 : 230 : sset_add(&lswitches, vtep_lswitch->name);
174 : : }
175 : : }
176 : : }
177 : :
178 : 238 : const char **ls_arr = sset_array(&lswitches);
179 : 238 : sbrec_chassis_set_vtep_logical_switches(chassis_rec, ls_arr,
180 : : sset_count(&lswitches));
181 : 238 : free(ls_arr);
182 : 238 : sset_destroy(&lswitches);
183 : : }
184 : 224 : }
185 : :
186 : :
187 : : void
188 : 269 : gateway_run(struct controller_vtep_ctx *ctx)
189 : : {
190 [ + + ]: 269 : if (!ctx->ovnsb_idl_txn) {
191 : 45 : return;
192 : : }
193 : :
194 : 224 : revalidate_gateway(ctx);
195 : 224 : update_vtep_logical_switches(ctx);
196 : : }
197 : :
198 : : /* Destroys the chassis table entries for vtep physical switches.
199 : : * Returns true when done (i.e. there is no change made to 'ctx->ovnsb_idl'),
200 : : * otherwise returns false. */
201 : : bool
202 : 27 : gateway_cleanup(struct controller_vtep_ctx *ctx)
203 : : {
204 : : static bool simap_destroyed = false;
205 : : const struct vteprec_physical_switch *pswitch;
206 : :
207 [ + + ]: 27 : if (!ctx->ovnsb_idl_txn) {
208 : 13 : return false;
209 : : }
210 : :
211 : 14 : bool all_done = true;
212 : 14 : ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, "ovn-controller-vtep: "
213 : : "unregistering vtep chassis");
214 [ + + ]: 28 : VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
215 : : const struct sbrec_chassis *chassis_rec;
216 : :
217 : 14 : chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
218 [ + + ]: 14 : if (!chassis_rec) {
219 : 7 : continue;
220 : : }
221 : 7 : all_done = false;
222 : 7 : sbrec_chassis_delete(chassis_rec);
223 : : }
224 [ + + ]: 14 : if (!simap_destroyed) {
225 : 7 : simap_destroy(&gw_chassis_map);
226 : 7 : simap_destroyed = true;
227 : : }
228 : :
229 : 14 : return all_done;
230 : : }
|