Skip to content

Commit 1a3fd5d

Browse files
almusildceara
authored andcommitted
lb: Make the LB validation consistent.
The LB validation allowed to mix template backends and explicit backends for IPv4, but not for IPv6. Make sure we allow mixing for both IP versions. This also fixes memory leak that could happen within the mixed IPv6 backends. Fixes: 7310a98 ("lb: Allow IPv6 template LBs to use explicit backends.") Signed-off-by: Ales Musil <[email protected]> Signed-off-by: Dumitru Ceara <[email protected]> (cherry picked from commit 894724d)
1 parent 5e2b1ec commit 1a3fd5d

File tree

3 files changed

+118
-103
lines changed

3 files changed

+118
-103
lines changed

lib/lb.c

+113-100
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,53 @@
2424

2525
VLOG_DEFINE_THIS_MODULE(lb);
2626

27-
static void ovn_lb_backends_clear(struct ovn_lb_vip *vip);
27+
static bool
28+
ovn_lb_backend_init_explicit(const struct ovn_lb_vip *lb_vip,
29+
struct ovn_lb_backend *backend,
30+
const char *token, struct ds *errors)
31+
{
32+
int backend_addr_family;
33+
if (!ip_address_and_port_from_lb_key(token, &backend->ip_str,
34+
&backend->ip, &backend->port,
35+
&backend_addr_family)) {
36+
if (lb_vip->port_str) {
37+
ds_put_format(errors, "%s: should be an IP address and a "
38+
"port number with : as a separator, ",
39+
token);
40+
} else {
41+
ds_put_format(errors, "%s: should be an IP address, ", token);
42+
}
43+
return false;
44+
}
45+
46+
if (lb_vip->address_family != backend_addr_family) {
47+
free(backend->ip_str);
48+
ds_put_format(errors, "%s: IP address family is different from "
49+
"VIP %s, ",
50+
token, lb_vip->vip_str);
51+
return false;
52+
}
53+
54+
if (lb_vip->port_str) {
55+
if (!backend->port) {
56+
free(backend->ip_str);
57+
ds_put_format(errors, "%s: should be an IP address and "
58+
"a port number with : as a separator, ",
59+
token);
60+
return false;
61+
}
62+
} else {
63+
if (backend->port) {
64+
free(backend->ip_str);
65+
ds_put_format(errors, "%s: should be an IP address, ", token);
66+
return false;
67+
}
68+
}
69+
70+
backend->port_str =
71+
backend->port ? xasprintf("%"PRIu16, backend->port) : NULL;
72+
return true;
73+
}
2874

2975
/* Format for backend ips: "IP1:port1,IP2:port2,...". */
3076
static char *
@@ -47,46 +93,10 @@ ovn_lb_backends_init_explicit(struct ovn_lb_vip *lb_vip, const char *value)
4793
}
4894

4995
struct ovn_lb_backend *backend = &lb_vip->backends[lb_vip->n_backends];
50-
int backend_addr_family;
51-
if (!ip_address_and_port_from_lb_key(token, &backend->ip_str,
52-
&backend->ip, &backend->port,
53-
&backend_addr_family)) {
54-
if (lb_vip->port_str) {
55-
ds_put_format(&errors, "%s: should be an IP address and a "
56-
"port number with : as a separator, ",
57-
token);
58-
} else {
59-
ds_put_format(&errors, "%s: should be an IP address, ", token);
60-
}
96+
if (!ovn_lb_backend_init_explicit(lb_vip, backend, token, &errors)) {
6197
continue;
6298
}
6399

64-
if (lb_vip->address_family != backend_addr_family) {
65-
free(backend->ip_str);
66-
ds_put_format(&errors, "%s: IP address family is different from "
67-
"VIP %s, ",
68-
token, lb_vip->vip_str);
69-
continue;
70-
}
71-
72-
if (lb_vip->port_str) {
73-
if (!backend->port) {
74-
free(backend->ip_str);
75-
ds_put_format(&errors, "%s: should be an IP address and "
76-
"a port number with : as a separator, ",
77-
token);
78-
continue;
79-
}
80-
} else {
81-
if (backend->port) {
82-
free(backend->ip_str);
83-
ds_put_format(&errors, "%s: should be an IP address, ", token);
84-
continue;
85-
}
86-
}
87-
88-
backend->port_str =
89-
backend->port ? xasprintf("%"PRIu16, backend->port) : NULL;
90100
lb_vip->n_backends++;
91101
}
92102
free(tokstr);
@@ -118,6 +128,47 @@ ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key,
118128
return ovn_lb_backends_init_explicit(lb_vip, lb_value);
119129
}
120130

131+
static bool
132+
ovn_lb_backend_init_template(struct ovn_lb_backend *backend, const char *token,
133+
struct ds *errors)
134+
{
135+
char *atom = xstrdup(token);
136+
char *save_ptr = NULL;
137+
bool success = false;
138+
char *backend_ip = NULL;
139+
char *backend_port = NULL;
140+
141+
for (char *subatom = strtok_r(atom, ":", &save_ptr); subatom;
142+
subatom = strtok_r(NULL, ":", &save_ptr)) {
143+
if (backend_ip && backend_port) {
144+
success = false;
145+
break;
146+
}
147+
success = true;
148+
if (!backend_ip) {
149+
backend_ip = xstrdup(subatom);
150+
} else {
151+
backend_port = xstrdup(subatom);
152+
}
153+
}
154+
155+
if (success) {
156+
backend->ip_str = backend_ip;
157+
backend->port_str = backend_port;
158+
backend->port = 0;
159+
memset(&backend->ip, 0, sizeof backend->ip);
160+
} else {
161+
ds_put_format(errors, "%s: should be a template of the form: "
162+
"'^backendip_variable1[:^port_variable1|:port]', ",
163+
atom);
164+
free(backend_port);
165+
free(backend_ip);
166+
}
167+
free(atom);
168+
169+
return success;
170+
}
171+
121172
/* Parses backends of a templated LB VIP.
122173
* For now only the following template forms are supported:
123174
* A.
@@ -130,6 +181,8 @@ ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key,
130181
* IP1_2:PORT1_2 on chassis-2
131182
* and 'backends_variable2' may expand to IP2_1:PORT2_1 on chassis-1
132183
* IP2_2:PORT2_2 on chassis-2
184+
* C.
185+
* backendip1[:port],backendip2[:port]
133186
*/
134187
static char *
135188
ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_)
@@ -140,50 +193,28 @@ ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_)
140193
size_t n_allocated_backends = 0;
141194
lb_vip->n_backends = 0;
142195

143-
for (char *backend = strtok_r(value, ",", &save_ptr); backend;
144-
backend = strtok_r(NULL, ",", &save_ptr)) {
145-
146-
char *atom = xstrdup(backend);
147-
char *save_ptr2 = NULL;
148-
bool success = false;
149-
char *backend_ip = NULL;
150-
char *backend_port = NULL;
196+
for (char *token = strtok_r(value, ",", &save_ptr); token;
197+
token = strtok_r(NULL, ",", &save_ptr)) {
151198

152-
for (char *subatom = strtok_r(atom, ":", &save_ptr2); subatom;
153-
subatom = strtok_r(NULL, ":", &save_ptr2)) {
154-
if (backend_ip && backend_port) {
155-
success = false;
156-
break;
157-
}
158-
success = true;
159-
if (!backend_ip) {
160-
backend_ip = xstrdup(subatom);
161-
} else {
162-
backend_port = xstrdup(subatom);
163-
}
199+
if (lb_vip->n_backends == n_allocated_backends) {
200+
lb_vip->backends = x2nrealloc(lb_vip->backends,
201+
&n_allocated_backends,
202+
sizeof *lb_vip->backends);
164203
}
165204

166-
if (success) {
167-
if (lb_vip->n_backends == n_allocated_backends) {
168-
lb_vip->backends = x2nrealloc(lb_vip->backends,
169-
&n_allocated_backends,
170-
sizeof *lb_vip->backends);
205+
struct ovn_lb_backend *backend = &lb_vip->backends[lb_vip->n_backends];
206+
if (token[0] && token[0] == '^') {
207+
if (!ovn_lb_backend_init_template(backend, token, &errors)) {
208+
continue;
171209
}
172-
173-
struct ovn_lb_backend *lb_backend =
174-
&lb_vip->backends[lb_vip->n_backends];
175-
lb_backend->ip_str = backend_ip;
176-
lb_backend->port_str = backend_port;
177-
lb_backend->port = 0;
178-
lb_vip->n_backends++;
179210
} else {
180-
ds_put_format(&errors, "%s: should be a template of the form: "
181-
"'^backendip_variable1[:^port_variable1|:port]', ",
182-
atom);
183-
free(backend_port);
184-
free(backend_ip);
211+
if (!ovn_lb_backend_init_explicit(lb_vip, backend,
212+
token, &errors)) {
213+
continue;
214+
}
185215
}
186-
free(atom);
216+
217+
lb_vip->n_backends++;
187218
}
188219

189220
free(value);
@@ -231,23 +262,13 @@ ovn_lb_vip_init_template(struct ovn_lb_vip *lb_vip, const char *lb_key_,
231262

232263
/* Backends can either be templates or explicit IPs and ports. */
233264
lb_vip->address_family = address_family;
234-
lb_vip->template_backends = true;
235265
char *template_error = ovn_lb_backends_init_template(lb_vip, lb_value);
236266

237267
if (template_error) {
238-
lb_vip->template_backends = false;
239-
ovn_lb_backends_clear(lb_vip);
240-
241-
char *explicit_error = ovn_lb_backends_init_explicit(lb_vip, lb_value);
242-
if (explicit_error) {
243-
char *error =
244-
xasprintf("invalid backend: template (%s) OR explicit (%s)",
245-
template_error, explicit_error);
246-
free(explicit_error);
268+
char *error = xasprintf("invalid backend: template (%s)",
269+
template_error);
247270
free(template_error);
248271
return error;
249-
}
250-
free(template_error);
251272
}
252273
return NULL;
253274
}
@@ -274,14 +295,7 @@ ovn_lb_backends_destroy(struct ovn_lb_vip *vip)
274295
free(vip->backends[i].ip_str);
275296
free(vip->backends[i].port_str);
276297
}
277-
}
278-
279-
static void
280-
ovn_lb_backends_clear(struct ovn_lb_vip *vip)
281-
{
282-
ovn_lb_backends_destroy(vip);
283-
vip->backends = NULL;
284-
vip->n_backends = 0;
298+
free(vip->backends);
285299
}
286300

287301
void
@@ -290,7 +304,6 @@ ovn_lb_vip_destroy(struct ovn_lb_vip *vip)
290304
free(vip->vip_str);
291305
free(vip->port_str);
292306
ovn_lb_backends_destroy(vip);
293-
free(vip->backends);
294307
}
295308

296309
static void
@@ -320,11 +333,11 @@ ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template)
320333
void
321334
ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s)
322335
{
323-
bool needs_brackets = vip->address_family == AF_INET6 && vip->port_str
324-
&& !vip->template_backends;
325336
for (size_t i = 0; i < vip->n_backends; i++) {
326337
struct ovn_lb_backend *backend = &vip->backends[i];
327-
338+
bool needs_brackets = vip->address_family == AF_INET6 &&
339+
vip->port_str &&
340+
!ipv6_addr_equals(&backend->ip, &in6addr_any);
328341
if (needs_brackets) {
329342
ds_put_char(s, '[');
330343
}

lib/lb.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ struct ovn_lb_vip {
3838
*/
3939
struct ovn_lb_backend *backends;
4040
size_t n_backends;
41-
bool template_backends; /* True if the backends are templates. False if
42-
* they're explicitly specified.
43-
*/
41+
4442
bool empty_backend_rej;
4543
int address_family;
4644
};

tests/ovn-nbctl.at

+4
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,8 @@ check ovn-nbctl --template lb-add lb4 ^vip:^vport ^backend:^bport udp ipv4
15941594
check ovn-nbctl --template lb-add lb5 ^vip:^vport ^backend:^bport udp ipv6
15951595
check ovn-nbctl --template lb-add lb6 ^vip:^vport 1.1.1.1:111 udp ipv4
15961596
check ovn-nbctl --template lb-add lb7 ^vip:^vport [[1::1]]:111 udp ipv6
1597+
check ovn-nbctl --template lb-add lb8 ^vip:^vport "^backend,^port,1.1.1.1:111" udp ipv4
1598+
check ovn-nbctl --template lb-add lb9 ^vip:^vport "^backend,^port,[[1::1]]:111" udp ipv6
15971599

15981600
AT_CHECK([ovn-nbctl lb-list | uuidfilt], [0], [dnl
15991601
UUID LB PROTO VIP IPs
@@ -1605,6 +1607,8 @@ UUID LB PROTO VIP
16051607
<5> lb5 udp ^vip:^vport ^backend:^bport
16061608
<6> lb6 udp ^vip:^vport 1.1.1.1:111
16071609
<7> lb7 udp ^vip:^vport [[1::1]]:111
1610+
<8> lb8 udp ^vip:^vport ^backend,^port,1.1.1.1:111
1611+
<9> lb9 udp ^vip:^vport ^backend,^port,[[1::1]]:111
16081612
])
16091613

16101614
])

0 commit comments

Comments
 (0)