]>
git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/raft-private.c
2 * Copyright (c) 2017, 2018 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "raft-private.h"
21 #include "openvswitch/dynamic-string.h"
22 #include "ovsdb-error.h"
23 #include "ovsdb-parser.h"
24 #include "socket-util.h"
27 /* Addresses of Raft servers. */
29 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
30 raft_address_validate(const char *address
)
32 if (!strncmp(address
, "unix:", 5)) {
34 } else if (!strncmp(address
, "ssl:", 4) || !strncmp(address
, "tcp:", 4)) {
35 struct sockaddr_storage ss
;
36 if (!inet_parse_active(address
+ 4, -1, &ss
, true)) {
37 return ovsdb_error(NULL
, "%s: syntax error in address", address
);
41 return ovsdb_error(NULL
, "%s: expected \"tcp\" or \"ssl\" address",
46 static struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
47 raft_address_validate_json(const struct json
*address
)
49 if (address
->type
!= JSON_STRING
) {
50 return ovsdb_syntax_error(address
, NULL
,
51 "server address is not string");
53 return raft_address_validate(json_string(address
));
56 /* Constructs and returns a "nickname" for a Raft server based on its 'address'
57 * and server ID 'sid'. The nickname is just a short name for the server to
58 * use in log messages, to make them more readable.
60 * The caller must eventually free the returned string. */
62 raft_address_to_nickname(const char *address
, const struct uuid
*sid
)
64 if (!strncmp(address
, "unix:", 5)) {
65 const char *p
= address
+ 5;
67 const char *slash
= strrchr(p
, '/');
72 int len
= strcspn(p
, ".");
74 return xmemdup0(p
, len
);
78 return xasprintf(SID_FMT
, SID_ARGS(sid
));
81 /* Sets of Raft server addresses. */
83 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
84 raft_addresses_from_json(const struct json
*json
, struct sset
*addresses
)
88 const struct json_array
*array
= json_array(json
);
90 return ovsdb_syntax_error(json
, NULL
,
91 "at least one remote address is required");
93 for (size_t i
= 0; i
< array
->n
; i
++) {
94 const struct json
*address
= array
->elems
[i
];
95 struct ovsdb_error
*error
= raft_address_validate_json(address
);
97 sset_destroy(addresses
);
101 sset_add(addresses
, json_string(address
));
107 raft_addresses_to_json(const struct sset
*sset
)
112 array
= json_array_create_empty();
113 SSET_FOR_EACH (s
, sset
) {
114 json_array_add(array
, json_string_create(s
));
122 raft_server_phase_to_string(enum raft_server_phase phase
)
125 case RAFT_PHASE_STABLE
: return "stable";
126 case RAFT_PHASE_CATCHUP
: return "adding: catchup";
127 case RAFT_PHASE_CAUGHT_UP
: return "adding: caught up";
128 case RAFT_PHASE_COMMITTING
: return "adding: committing";
129 case RAFT_PHASE_REMOVE
: return "removing";
130 default: return "<error>";
135 raft_server_destroy(struct raft_server
*s
)
145 raft_servers_destroy(struct hmap
*servers
)
147 struct raft_server
*s
, *next
;
148 HMAP_FOR_EACH_SAFE (s
, next
, hmap_node
, servers
) {
149 hmap_remove(servers
, &s
->hmap_node
);
150 raft_server_destroy(s
);
152 hmap_destroy(servers
);
156 raft_server_add(struct hmap
*servers
, const struct uuid
*sid
,
159 struct raft_server
*s
= xzalloc(sizeof *s
);
161 s
->address
= xstrdup(address
);
162 s
->nickname
= raft_address_to_nickname(address
, sid
);
163 s
->phase
= RAFT_PHASE_STABLE
;
164 hmap_insert(servers
, &s
->hmap_node
, uuid_hash(sid
));
170 raft_server_find(const struct hmap
*servers
, const struct uuid
*sid
)
172 struct raft_server
*s
;
173 HMAP_FOR_EACH_IN_BUCKET (s
, hmap_node
, uuid_hash(sid
), servers
) {
174 if (uuid_equals(sid
, &s
->sid
)) {
182 raft_servers_get_nickname__(const struct hmap
*servers
, const struct uuid
*sid
)
184 const struct raft_server
*s
= raft_server_find(servers
, sid
);
185 return s
? s
->nickname
: NULL
;
189 raft_servers_get_nickname(const struct hmap
*servers
,
190 const struct uuid
*sid
,
191 char buf
[SID_LEN
+ 1], size_t bufsize
)
193 const char *s
= raft_servers_get_nickname__(servers
, sid
);
197 snprintf(buf
, bufsize
, SID_FMT
, SID_ARGS(sid
));
201 static struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
202 raft_servers_from_json__(const struct json
*json
, struct hmap
*servers
)
204 if (!json
|| json
->type
!= JSON_OBJECT
) {
205 return ovsdb_syntax_error(json
, NULL
, "servers must be JSON object");
206 } else if (shash_is_empty(json_object(json
))) {
207 return ovsdb_syntax_error(json
, NULL
, "must have at least one server");
210 /* Parse new servers. */
211 struct shash_node
*node
;
212 SHASH_FOR_EACH (node
, json_object(json
)) {
213 /* Parse server UUID. */
215 if (!uuid_from_string(&sid
, node
->name
)) {
216 return ovsdb_syntax_error(json
, NULL
, "%s is not a UUID",
220 const struct json
*address
= node
->data
;
221 struct ovsdb_error
*error
= raft_address_validate_json(address
);
226 raft_server_add(servers
, &sid
, json_string(address
));
232 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
233 raft_servers_from_json(const struct json
*json
, struct hmap
*servers
)
236 struct ovsdb_error
*error
= raft_servers_from_json__(json
, servers
);
238 raft_servers_destroy(servers
);
243 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
244 raft_servers_validate_json(const struct json
*json
)
246 struct hmap servers
= HMAP_INITIALIZER(&servers
);
247 struct ovsdb_error
*error
= raft_servers_from_json__(json
, &servers
);
248 raft_servers_destroy(&servers
);
253 raft_servers_to_json(const struct hmap
*servers
)
255 struct json
*json
= json_object_create();
256 struct raft_server
*s
;
257 HMAP_FOR_EACH (s
, hmap_node
, servers
) {
258 char sid_s
[UUID_LEN
+ 1];
259 sprintf(sid_s
, UUID_FMT
, UUID_ARGS(&s
->sid
));
260 json_object_put_string(json
, sid_s
, s
->address
);
266 raft_servers_format(const struct hmap
*servers
, struct ds
*ds
)
269 const struct raft_server
*s
;
270 HMAP_FOR_EACH (s
, hmap_node
, servers
) {
272 ds_put_cstr(ds
, ", ");
274 ds_put_format(ds
, SID_FMT
"(%s)", SID_ARGS(&s
->sid
), s
->address
);
278 /* Raft log entries. */
281 raft_entry_clone(struct raft_entry
*dst
, const struct raft_entry
*src
)
283 dst
->term
= src
->term
;
284 dst
->data
= json_nullable_clone(src
->data
);
286 dst
->servers
= json_nullable_clone(src
->servers
);
290 raft_entry_uninit(struct raft_entry
*e
)
293 json_destroy(e
->data
);
294 json_destroy(e
->servers
);
299 raft_entry_to_json(const struct raft_entry
*e
)
301 struct json
*json
= json_object_create();
302 raft_put_uint64(json
, "term", e
->term
);
304 json_object_put(json
, "data", json_clone(e
->data
));
305 json_object_put_format(json
, "eid", UUID_FMT
, UUID_ARGS(&e
->eid
));
308 json_object_put(json
, "servers", json_clone(e
->servers
));
313 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
314 raft_entry_from_json(struct json
*json
, struct raft_entry
*e
)
316 memset(e
, 0, sizeof *e
);
318 struct ovsdb_parser p
;
319 ovsdb_parser_init(&p
, json
, "raft log entry");
320 e
->term
= raft_parse_required_uint64(&p
, "term");
321 e
->data
= json_nullable_clone(
322 ovsdb_parser_member(&p
, "data", OP_OBJECT
| OP_ARRAY
| OP_OPTIONAL
));
323 e
->eid
= e
->data
? raft_parse_required_uuid(&p
, "eid") : UUID_ZERO
;
324 e
->servers
= json_nullable_clone(
325 ovsdb_parser_member(&p
, "servers", OP_OBJECT
| OP_OPTIONAL
));
327 ovsdb_parser_put_error(&p
, raft_servers_validate_json(e
->servers
));
330 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
332 raft_entry_uninit(e
);
338 raft_entry_equals(const struct raft_entry
*a
, const struct raft_entry
*b
)
340 return (a
->term
== b
->term
341 && json_equal(a
->data
, b
->data
)
342 && uuid_equals(&a
->eid
, &b
->eid
)
343 && json_equal(a
->servers
, b
->servers
));
347 raft_header_uninit(struct raft_header
*h
)
354 free(h
->local_address
);
355 sset_destroy(&h
->remote_addresses
);
356 raft_entry_uninit(&h
->snap
);
360 raft_header_from_json__(struct raft_header
*h
, struct ovsdb_parser
*p
)
362 /* Parse always-required fields. */
363 h
->sid
= raft_parse_required_uuid(p
, "server_id");
364 h
->name
= nullable_xstrdup(raft_parse_required_string(p
, "name"));
365 h
->local_address
= nullable_xstrdup(
366 raft_parse_required_string(p
, "local_address"));
368 /* Parse "remote_addresses", if present.
370 * If this is present, then this database file is for the special case of a
371 * server that was created with "ovsdb-tool join-cluster" and has not yet
372 * joined its cluster, */
373 const struct json
*remote_addresses
374 = ovsdb_parser_member(p
, "remote_addresses", OP_ARRAY
| OP_OPTIONAL
);
375 h
->joining
= remote_addresses
!= NULL
;
377 struct ovsdb_error
*error
= raft_addresses_from_json(
378 remote_addresses
, &h
->remote_addresses
);
380 ovsdb_parser_put_error(p
, error
);
381 } else if (sset_find_and_delete(&h
->remote_addresses
, h
->local_address
)
382 && sset_is_empty(&h
->remote_addresses
)) {
383 ovsdb_parser_raise_error(p
, "at least one remote address (other "
384 "than the local address) is required");
387 /* The set of servers is mandatory. */
388 h
->snap
.servers
= json_nullable_clone(
389 ovsdb_parser_member(p
, "prev_servers", OP_OBJECT
));
390 if (h
->snap
.servers
) {
391 ovsdb_parser_put_error(p
, raft_servers_validate_json(
395 /* Term, index, and snapshot are optional, but if any of them is
396 * present, all of them must be. */
397 h
->snap_index
= raft_parse_optional_uint64(p
, "prev_index");
399 h
->snap
.data
= json_nullable_clone(
400 ovsdb_parser_member(p
, "prev_data", OP_ANY
));
401 h
->snap
.eid
= raft_parse_required_uuid(p
, "prev_eid");
402 h
->snap
.term
= raft_parse_required_uint64(p
, "prev_term");
406 /* Parse cluster ID. If we're joining a cluster, this is optional,
407 * otherwise it is mandatory. */
408 raft_parse_uuid(p
, "cluster_id", h
->joining
, &h
->cid
);
411 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
412 raft_header_from_json(struct raft_header
*h
, const struct json
*json
)
414 struct ovsdb_parser p
;
415 ovsdb_parser_init(&p
, json
, "raft header");
416 memset(h
, 0, sizeof *h
);
417 sset_init(&h
->remote_addresses
);
418 raft_header_from_json__(h
, &p
);
419 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
421 raft_header_uninit(h
);
427 raft_header_to_json(const struct raft_header
*h
)
429 struct json
*json
= json_object_create();
431 json_object_put_format(json
, "server_id", UUID_FMT
, UUID_ARGS(&h
->sid
));
432 if (!uuid_is_zero(&h
->cid
)) {
433 json_object_put_format(json
, "cluster_id",
434 UUID_FMT
, UUID_ARGS(&h
->cid
));
436 json_object_put_string(json
, "local_address", h
->local_address
);
437 json_object_put_string(json
, "name", h
->name
);
439 if (!sset_is_empty(&h
->remote_addresses
)) {
440 json_object_put(json
, "remote_addresses",
441 raft_addresses_to_json(&h
->remote_addresses
));
444 if (h
->snap
.servers
) {
445 json_object_put(json
, "prev_servers", json_clone(h
->snap
.servers
));
448 raft_put_uint64(json
, "prev_index", h
->snap_index
);
449 raft_put_uint64(json
, "prev_term", h
->snap
.term
);
451 json_object_put(json
, "prev_data", json_clone(h
->snap
.data
));
453 json_object_put_format(json
, "prev_eid",
454 UUID_FMT
, UUID_ARGS(&h
->snap
.eid
));
461 raft_record_uninit(struct raft_record
*r
)
471 json_destroy(r
->entry
.data
);
472 json_destroy(r
->entry
.servers
);
481 case RAFT_REC_COMMIT_INDEX
:
482 case RAFT_REC_LEADER
:
488 raft_record_from_json__(struct raft_record
*r
, struct ovsdb_parser
*p
)
490 r
->comment
= nullable_xstrdup(raft_parse_optional_string(p
, "comment"));
493 const char *note
= raft_parse_optional_string(p
, "note");
495 r
->type
= RAFT_REC_NOTE
;
497 r
->note
= xstrdup(note
);
501 /* Parse "commit_index". */
502 r
->commit_index
= raft_parse_optional_uint64(p
, "commit_index");
503 if (r
->commit_index
) {
504 r
->type
= RAFT_REC_COMMIT_INDEX
;
509 /* All remaining types of log records include "term", plus at most one of:
511 * - "index" plus zero or more of "data", "eid", and "servers". "data"
512 * and "eid" must be both present or both absent.
521 * A Raft leader can replicate entries from previous terms to the other
522 * servers in the cluster, retaining the original terms on those entries
523 * (see section 3.6.2 "Committing entries from previous terms" for more
524 * information), so it's OK for the term in a log record to precede the
526 r
->term
= raft_parse_required_uint64(p
, "term");
528 /* Parse "leader". */
529 if (raft_parse_optional_uuid(p
, "leader", &r
->sid
)) {
530 r
->type
= RAFT_REC_LEADER
;
531 if (uuid_is_zero(&r
->sid
)) {
532 ovsdb_parser_raise_error(p
, "record says leader is all-zeros SID");
538 if (raft_parse_optional_uuid(p
, "vote", &r
->sid
)) {
539 r
->type
= RAFT_REC_VOTE
;
540 if (uuid_is_zero(&r
->sid
)) {
541 ovsdb_parser_raise_error(p
, "record votes for all-zeros SID");
546 /* If "index" is present parse the rest of the entry, otherwise it's just a
548 r
->entry
.index
= raft_parse_optional_uint64(p
, "index");
549 if (!r
->entry
.index
) {
550 r
->type
= RAFT_REC_TERM
;
552 r
->type
= RAFT_REC_ENTRY
;
553 r
->entry
.servers
= json_nullable_clone(
554 ovsdb_parser_member(p
, "servers", OP_OBJECT
| OP_OPTIONAL
));
555 if (r
->entry
.servers
) {
556 ovsdb_parser_put_error(
557 p
, raft_servers_validate_json(r
->entry
.servers
));
559 r
->entry
.data
= json_nullable_clone(
560 ovsdb_parser_member(p
, "data",
561 OP_OBJECT
| OP_ARRAY
| OP_OPTIONAL
));
562 r
->entry
.eid
= (r
->entry
.data
563 ? raft_parse_required_uuid(p
, "eid")
568 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
569 raft_record_from_json(struct raft_record
*r
, const struct json
*json
)
571 struct ovsdb_parser p
;
572 ovsdb_parser_init(&p
, json
, "raft log record");
573 raft_record_from_json__(r
, &p
);
574 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
576 raft_record_uninit(r
);
582 raft_record_to_json(const struct raft_record
*r
)
584 struct json
*json
= json_object_create();
586 if (r
->comment
&& *r
->comment
) {
587 json_object_put_string(json
, "comment", r
->comment
);
592 raft_put_uint64(json
, "term", r
->term
);
593 raft_put_uint64(json
, "index", r
->entry
.index
);
595 json_object_put(json
, "data", json_clone(r
->entry
.data
));
597 if (r
->entry
.servers
) {
598 json_object_put(json
, "servers", json_clone(r
->entry
.servers
));
600 if (!uuid_is_zero(&r
->entry
.eid
)) {
601 json_object_put_format(json
, "eid",
602 UUID_FMT
, UUID_ARGS(&r
->entry
.eid
));
607 raft_put_uint64(json
, "term", r
->term
);
611 raft_put_uint64(json
, "term", r
->term
);
612 json_object_put_format(json
, "vote", UUID_FMT
, UUID_ARGS(&r
->sid
));
616 json_object_put(json
, "note", json_string_create(r
->note
));
619 case RAFT_REC_COMMIT_INDEX
:
620 raft_put_uint64(json
, "commit_index", r
->commit_index
);
623 case RAFT_REC_LEADER
:
624 raft_put_uint64(json
, "term", r
->term
);
625 json_object_put_format(json
, "leader", UUID_FMT
, UUID_ARGS(&r
->sid
));
634 /* Puts 'integer' into JSON 'object' with the given 'name'.
636 * The OVS JSON implementation only supports integers in the range
637 * INT64_MIN...INT64_MAX, which causes trouble for values from INT64_MAX+1 to
638 * UINT64_MAX. We map those into the negative range. */
640 raft_put_uint64(struct json
*object
, const char *name
, uint64_t integer
)
642 json_object_put(object
, name
, json_integer_create(integer
));
645 /* Parses an integer from parser 'p' with the given 'name'.
647 * The OVS JSON implementation only supports integers in the range
648 * INT64_MIN...INT64_MAX, which causes trouble for values from INT64_MAX+1 to
649 * UINT64_MAX. We map the negative range back into positive numbers. */
651 raft_parse_uint64__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
653 enum ovsdb_parser_types types
= OP_INTEGER
| (optional
? OP_OPTIONAL
: 0);
654 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
655 return json
? json_integer(json
) : 0;
659 raft_parse_optional_uint64(struct ovsdb_parser
*p
, const char *name
)
661 return raft_parse_uint64__(p
, name
, true);
665 raft_parse_required_uint64(struct ovsdb_parser
*p
, const char *name
)
667 return raft_parse_uint64__(p
, name
, false);
671 raft_parse_boolean__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
673 enum ovsdb_parser_types types
= OP_BOOLEAN
| (optional
? OP_OPTIONAL
: 0);
674 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
675 return json
? json_boolean(json
) : -1;
679 raft_parse_required_boolean(struct ovsdb_parser
*p
, const char *name
)
681 return raft_parse_boolean__(p
, name
, false);
684 /* Returns true or false if present, -1 if absent. */
686 raft_parse_optional_boolean(struct ovsdb_parser
*p
, const char *name
)
688 return raft_parse_boolean__(p
, name
, true);
692 raft_parse_string__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
694 enum ovsdb_parser_types types
= OP_STRING
| (optional
? OP_OPTIONAL
: 0);
695 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
696 return json
? json_string(json
) : NULL
;
700 raft_parse_required_string(struct ovsdb_parser
*p
, const char *name
)
702 return raft_parse_string__(p
, name
, false);
706 raft_parse_optional_string(struct ovsdb_parser
*p
, const char *name
)
708 return raft_parse_string__(p
, name
, true);
712 raft_parse_uuid(struct ovsdb_parser
*p
, const char *name
, bool optional
,
715 const char *s
= raft_parse_string__(p
, name
, optional
);
717 if (uuid_from_string(uuid
, s
)) {
720 ovsdb_parser_raise_error(p
, "%s is not a valid UUID", name
);
727 raft_parse_required_uuid(struct ovsdb_parser
*p
, const char *name
)
730 raft_parse_uuid(p
, name
, false, &uuid
);
735 raft_parse_optional_uuid(struct ovsdb_parser
*p
, const char *name
,
738 return raft_parse_uuid(p
, name
, true, uuid
);