]> git.proxmox.com Git - ovs.git/blob - ovn/controller/gchassis.c
ovn: l3ha, make is_chassis_active aware of gateway_chassis
[ovs.git] / ovn / controller / gchassis.c
1 /* Copyright (c) 2017, Red Hat, 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 "gchassis.h"
19 #include "lport.h"
20 #include "lib/sset.h"
21 #include "openvswitch/vlog.h"
22 #include "ovn/lib/chassis-index.h"
23 #include "ovn/lib/ovn-sb-idl.h"
24
25 VLOG_DEFINE_THIS_MODULE(gchassis);
26
27 /* gateway_chassis ordering
28 */
29 static int
30 compare_chassis_prio_(const void *a_, const void *b_)
31 {
32 const struct gateway_chassis *gc_a = a_;
33 const struct gateway_chassis *gc_b = b_;
34 int prio_diff = gc_b->db->priority - gc_a->db->priority;
35 if (!prio_diff) {
36 return strcmp(gc_b->db->name, gc_a->db->name);
37 }
38 return prio_diff;
39 }
40
41 struct ovs_list*
42 gateway_chassis_get_ordered(const struct sbrec_port_binding *binding,
43 const struct chassis_index *chassis_index)
44 {
45 const char *redir_chassis_str;
46 const struct sbrec_chassis *redirect_chassis = NULL;
47
48 /* XXX: redirect-chassis SBDB option handling is supported for backwards
49 * compatibility with N-1 version of ovn-northd. This support can
50 * be removed in OVS 2.9 where Gateway_Chassis list on the port binding
51 * will always be populated by northd */
52 redir_chassis_str = smap_get(&binding->options, "redirect-chassis");
53
54 if (redir_chassis_str) {
55 redirect_chassis = chassis_lookup_by_name(chassis_index,
56 redir_chassis_str);
57 if (!redirect_chassis) {
58 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
59 VLOG_WARN_RL(&rl, "chassis name (%s) in redirect-chassis option "
60 "of logical port %s not known",
61 redir_chassis_str, binding->logical_port);
62 }
63 }
64
65 if (!redirect_chassis && binding->n_gateway_chassis == 0) {
66 return NULL;
67 }
68
69 struct gateway_chassis *gateway_chassis = NULL;
70 int n = 0;
71
72 if (binding->n_gateway_chassis) {
73 gateway_chassis = xmalloc(sizeof *gateway_chassis *
74 binding->n_gateway_chassis);
75 for (n = 0; n < binding->n_gateway_chassis; n++) {
76 gateway_chassis[n].db = binding->gateway_chassis[n];
77 gateway_chassis[n].virtual_gwc = false;
78 }
79 qsort(gateway_chassis, n, sizeof *gateway_chassis,
80 compare_chassis_prio_);
81 } else if (redirect_chassis) {
82 /* When only redirect_chassis is available, return a single
83 * virtual entry that it's not on OVSDB, this way the code
84 * handling the returned list will be uniform, regardless
85 * of gateway_chassis being populated or redirect-chassis option
86 * being used */
87 gateway_chassis = xmalloc(sizeof *gateway_chassis);
88 struct sbrec_gateway_chassis *gwc =
89 xzalloc(sizeof *gateway_chassis->db);
90 sbrec_gateway_chassis_init(gwc);
91 gwc->name = xasprintf("%s_%s", binding->logical_port,
92 redirect_chassis->name);
93 gwc->chassis = CONST_CAST(struct sbrec_chassis *, redirect_chassis);
94 gateway_chassis->db = gwc;
95 gateway_chassis->virtual_gwc = true;
96 n++;
97 }
98
99 struct ovs_list *list = NULL;
100 if (n) {
101 list = xmalloc(sizeof *list);
102 ovs_list_init(list);
103
104 int i;
105 for (i = 0; i < n; i++) {
106 ovs_list_push_back(list, &gateway_chassis[i].node);
107 }
108 }
109
110 return list;
111 }
112
113 bool
114 gateway_chassis_contains(const struct ovs_list *gateway_chassis,
115 const struct sbrec_chassis *chassis) {
116 struct gateway_chassis *chassis_item;
117 if (gateway_chassis) {
118 LIST_FOR_EACH (chassis_item, node, gateway_chassis) {
119 if (chassis_item->db->chassis
120 && !strcmp(chassis_item->db->chassis->name, chassis->name)) {
121 return true;
122 }
123 }
124 }
125 return false;
126 }
127
128 void
129 gateway_chassis_destroy(struct ovs_list *list)
130 {
131 if (!list) {
132 return;
133 }
134
135 /* XXX: This loop is for backwards compatibility with redirect-chassis
136 * which we insert as a single virtual Gateway_Chassis on the ordered
137 * list */
138 struct gateway_chassis *chassis_item;
139 LIST_FOR_EACH (chassis_item, node, list) {
140 if (chassis_item->virtual_gwc) {
141 free(chassis_item->db->name);
142 free(CONST_CAST(struct sbrec_gateway_chassis *, chassis_item->db));
143 }
144 }
145
146 free(ovs_list_front(list));
147 free(list);
148 }
149
150 bool
151 gateway_chassis_in_pb_contains(const struct sbrec_port_binding *binding,
152 const struct sbrec_chassis *chassis)
153 {
154 if (!binding || !chassis) {
155 return false;
156 }
157
158 /* XXX: redirect-chassis handling for backwards compatibility,
159 * with older ovs-northd during upgrade phase, can be removed
160 * for OVS 2.9 */
161 const char *redirect_chassis = smap_get(&binding->options,
162 "redirect-chassis");
163 if (binding->n_gateway_chassis) {
164 int n;
165 for (n = 0; n < binding->n_gateway_chassis; n++) {
166 if (binding->gateway_chassis[n]->chassis
167 && !strcmp(binding->gateway_chassis[n]->chassis->name,
168 chassis->name)) {
169 return true;
170 }
171 }
172 } else if (redirect_chassis) {
173 return !strcmp(redirect_chassis, chassis->name);
174 }
175
176 return false;
177 }
178
179 bool
180 gateway_chassis_is_active(const struct ovs_list *gateway_chassis,
181 const struct sbrec_chassis *local_chassis,
182 const struct sset *active_tunnels)
183 {
184 struct gateway_chassis *gwc;
185
186 if (!gateway_chassis
187 || (gateway_chassis && ovs_list_is_empty(gateway_chassis))) {
188 return false;
189 }
190 /* if there's only one chassis, and local chassis is on the list
191 * it's not HA and it's the equivalent of being active */
192 if (ovs_list_is_singleton(gateway_chassis) &&
193 gateway_chassis_contains(gateway_chassis, local_chassis)) {
194 return true;
195 }
196
197 /* if there are no other tunnels active, we assume that the
198 * connection providing tunneling is down, hence we're down */
199 if (sset_is_empty(active_tunnels)) {
200 return false;
201 }
202
203 /* gateway_chassis is an ordered list, by priority, of chassis
204 * hosting the redirect of the port */
205 LIST_FOR_EACH (gwc, node, gateway_chassis) {
206 if (!gwc->db->chassis) {
207 continue;
208 }
209 /* if we found the chassis on the list, and we didn't exit before
210 * on the active_tunnels check for other higher priority chassis
211 * being active, then this chassis is master. */
212 if (!strcmp(gwc->db->chassis->name, local_chassis->name)) {
213 return true;
214 }
215 /* if we find this specific chassis on the list to have an active
216 * tunnel, then 'local_chassis' is not master */
217 if (sset_contains(active_tunnels, gwc->db->chassis->name)) {
218 return false;
219 }
220 }
221 return false;
222 }