]>
git.proxmox.com Git - 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
);
287 dst
->election_timer
= src
->election_timer
;
291 raft_entry_uninit(struct raft_entry
*e
)
294 json_destroy(e
->data
);
295 json_destroy(e
->servers
);
300 raft_entry_to_json(const struct raft_entry
*e
)
302 struct json
*json
= json_object_create();
303 raft_put_uint64(json
, "term", e
->term
);
305 json_object_put(json
, "data", json_clone(e
->data
));
306 json_object_put_format(json
, "eid", UUID_FMT
, UUID_ARGS(&e
->eid
));
309 json_object_put(json
, "servers", json_clone(e
->servers
));
311 if (e
->election_timer
) {
312 raft_put_uint64(json
, "election_timer", e
->election_timer
);
318 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
319 raft_entry_from_json(struct json
*json
, struct raft_entry
*e
)
321 memset(e
, 0, sizeof *e
);
323 struct ovsdb_parser p
;
324 ovsdb_parser_init(&p
, json
, "raft log entry");
325 e
->term
= raft_parse_required_uint64(&p
, "term");
326 e
->data
= json_nullable_clone(
327 ovsdb_parser_member(&p
, "data", OP_OBJECT
| OP_ARRAY
| OP_OPTIONAL
));
328 e
->eid
= e
->data
? raft_parse_required_uuid(&p
, "eid") : UUID_ZERO
;
329 e
->servers
= json_nullable_clone(
330 ovsdb_parser_member(&p
, "servers", OP_OBJECT
| OP_OPTIONAL
));
332 ovsdb_parser_put_error(&p
, raft_servers_validate_json(e
->servers
));
334 e
->election_timer
= raft_parse_optional_uint64(&p
, "election_timer");
336 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
338 raft_entry_uninit(e
);
344 raft_entry_equals(const struct raft_entry
*a
, const struct raft_entry
*b
)
346 return (a
->term
== b
->term
347 && json_equal(a
->data
, b
->data
)
348 && uuid_equals(&a
->eid
, &b
->eid
)
349 && json_equal(a
->servers
, b
->servers
));
353 raft_header_uninit(struct raft_header
*h
)
360 free(h
->local_address
);
361 sset_destroy(&h
->remote_addresses
);
362 raft_entry_uninit(&h
->snap
);
366 raft_header_from_json__(struct raft_header
*h
, struct ovsdb_parser
*p
)
368 /* Parse always-required fields. */
369 h
->sid
= raft_parse_required_uuid(p
, "server_id");
370 h
->name
= nullable_xstrdup(raft_parse_required_string(p
, "name"));
371 h
->local_address
= nullable_xstrdup(
372 raft_parse_required_string(p
, "local_address"));
374 /* Parse "remote_addresses", if present.
376 * If this is present, then this database file is for the special case of a
377 * server that was created with "ovsdb-tool join-cluster" and has not yet
378 * joined its cluster, */
379 const struct json
*remote_addresses
380 = ovsdb_parser_member(p
, "remote_addresses", OP_ARRAY
| OP_OPTIONAL
);
381 h
->joining
= remote_addresses
!= NULL
;
383 struct ovsdb_error
*error
= raft_addresses_from_json(
384 remote_addresses
, &h
->remote_addresses
);
386 ovsdb_parser_put_error(p
, error
);
387 } else if (sset_find_and_delete(&h
->remote_addresses
, h
->local_address
)
388 && sset_is_empty(&h
->remote_addresses
)) {
389 ovsdb_parser_raise_error(p
, "at least one remote address (other "
390 "than the local address) is required");
393 /* The set of servers is mandatory. */
394 h
->snap
.servers
= json_nullable_clone(
395 ovsdb_parser_member(p
, "prev_servers", OP_OBJECT
));
396 if (h
->snap
.servers
) {
397 ovsdb_parser_put_error(p
, raft_servers_validate_json(
401 /* Term, index, and snapshot are optional, but if any of them is
402 * present, all of them must be. */
403 h
->snap_index
= raft_parse_optional_uint64(p
, "prev_index");
405 h
->snap
.data
= json_nullable_clone(
406 ovsdb_parser_member(p
, "prev_data", OP_ANY
));
407 h
->snap
.eid
= raft_parse_required_uuid(p
, "prev_eid");
408 h
->snap
.term
= raft_parse_required_uint64(p
, "prev_term");
409 h
->snap
.election_timer
= raft_parse_optional_uint64(
410 p
, "prev_election_timer");
414 /* Parse cluster ID. If we're joining a cluster, this is optional,
415 * otherwise it is mandatory. */
416 raft_parse_uuid(p
, "cluster_id", h
->joining
, &h
->cid
);
419 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
420 raft_header_from_json(struct raft_header
*h
, const struct json
*json
)
422 struct ovsdb_parser p
;
423 ovsdb_parser_init(&p
, json
, "raft header");
424 memset(h
, 0, sizeof *h
);
425 sset_init(&h
->remote_addresses
);
426 raft_header_from_json__(h
, &p
);
427 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
429 raft_header_uninit(h
);
435 raft_header_to_json(const struct raft_header
*h
)
437 struct json
*json
= json_object_create();
439 json_object_put_format(json
, "server_id", UUID_FMT
, UUID_ARGS(&h
->sid
));
440 if (!uuid_is_zero(&h
->cid
)) {
441 json_object_put_format(json
, "cluster_id",
442 UUID_FMT
, UUID_ARGS(&h
->cid
));
444 json_object_put_string(json
, "local_address", h
->local_address
);
445 json_object_put_string(json
, "name", h
->name
);
447 if (!sset_is_empty(&h
->remote_addresses
)) {
448 json_object_put(json
, "remote_addresses",
449 raft_addresses_to_json(&h
->remote_addresses
));
452 if (h
->snap
.servers
) {
453 json_object_put(json
, "prev_servers", json_clone(h
->snap
.servers
));
456 raft_put_uint64(json
, "prev_index", h
->snap_index
);
457 raft_put_uint64(json
, "prev_term", h
->snap
.term
);
459 json_object_put(json
, "prev_data", json_clone(h
->snap
.data
));
461 json_object_put_format(json
, "prev_eid",
462 UUID_FMT
, UUID_ARGS(&h
->snap
.eid
));
463 if (h
->snap
.election_timer
) {
464 raft_put_uint64(json
, "prev_election_timer",
465 h
->snap
.election_timer
);
473 raft_record_uninit(struct raft_record
*r
)
483 json_destroy(r
->entry
.data
);
484 json_destroy(r
->entry
.servers
);
493 case RAFT_REC_COMMIT_INDEX
:
494 case RAFT_REC_LEADER
:
500 raft_record_from_json__(struct raft_record
*r
, struct ovsdb_parser
*p
)
502 r
->comment
= nullable_xstrdup(raft_parse_optional_string(p
, "comment"));
505 const char *note
= raft_parse_optional_string(p
, "note");
507 r
->type
= RAFT_REC_NOTE
;
509 r
->note
= xstrdup(note
);
513 /* Parse "commit_index". */
514 r
->commit_index
= raft_parse_optional_uint64(p
, "commit_index");
515 if (r
->commit_index
) {
516 r
->type
= RAFT_REC_COMMIT_INDEX
;
521 /* All remaining types of log records include "term", plus at most one of:
523 * - "index" plus zero or more of "data", "eid", and "servers". "data"
524 * and "eid" must be both present or both absent.
533 * A Raft leader can replicate entries from previous terms to the other
534 * servers in the cluster, retaining the original terms on those entries
535 * (see section 3.6.2 "Committing entries from previous terms" for more
536 * information), so it's OK for the term in a log record to precede the
538 r
->term
= raft_parse_required_uint64(p
, "term");
540 /* Parse "leader". */
541 if (raft_parse_optional_uuid(p
, "leader", &r
->sid
)) {
542 r
->type
= RAFT_REC_LEADER
;
543 if (uuid_is_zero(&r
->sid
)) {
544 ovsdb_parser_raise_error(p
, "record says leader is all-zeros SID");
550 if (raft_parse_optional_uuid(p
, "vote", &r
->sid
)) {
551 r
->type
= RAFT_REC_VOTE
;
552 if (uuid_is_zero(&r
->sid
)) {
553 ovsdb_parser_raise_error(p
, "record votes for all-zeros SID");
558 /* If "index" is present parse the rest of the entry, otherwise it's just a
560 r
->entry
.index
= raft_parse_optional_uint64(p
, "index");
561 if (!r
->entry
.index
) {
562 r
->type
= RAFT_REC_TERM
;
564 r
->type
= RAFT_REC_ENTRY
;
565 r
->entry
.servers
= json_nullable_clone(
566 ovsdb_parser_member(p
, "servers", OP_OBJECT
| OP_OPTIONAL
));
567 if (r
->entry
.servers
) {
568 ovsdb_parser_put_error(
569 p
, raft_servers_validate_json(r
->entry
.servers
));
571 r
->entry
.election_timer
= raft_parse_optional_uint64(
572 p
, "election_timer");
573 r
->entry
.data
= json_nullable_clone(
574 ovsdb_parser_member(p
, "data",
575 OP_OBJECT
| OP_ARRAY
| OP_OPTIONAL
));
576 r
->entry
.eid
= (r
->entry
.data
577 ? raft_parse_required_uuid(p
, "eid")
582 struct ovsdb_error
* OVS_WARN_UNUSED_RESULT
583 raft_record_from_json(struct raft_record
*r
, const struct json
*json
)
585 struct ovsdb_parser p
;
586 ovsdb_parser_init(&p
, json
, "raft log record");
587 raft_record_from_json__(r
, &p
);
588 struct ovsdb_error
*error
= ovsdb_parser_finish(&p
);
590 raft_record_uninit(r
);
596 raft_record_to_json(const struct raft_record
*r
)
598 struct json
*json
= json_object_create();
600 if (r
->comment
&& *r
->comment
) {
601 json_object_put_string(json
, "comment", r
->comment
);
606 raft_put_uint64(json
, "term", r
->term
);
607 raft_put_uint64(json
, "index", r
->entry
.index
);
609 json_object_put(json
, "data", json_clone(r
->entry
.data
));
611 if (r
->entry
.servers
) {
612 json_object_put(json
, "servers", json_clone(r
->entry
.servers
));
614 if (r
->entry
.election_timer
) {
615 raft_put_uint64(json
, "election_timer", r
->entry
.election_timer
);
617 if (!uuid_is_zero(&r
->entry
.eid
)) {
618 json_object_put_format(json
, "eid",
619 UUID_FMT
, UUID_ARGS(&r
->entry
.eid
));
624 raft_put_uint64(json
, "term", r
->term
);
628 raft_put_uint64(json
, "term", r
->term
);
629 json_object_put_format(json
, "vote", UUID_FMT
, UUID_ARGS(&r
->sid
));
633 json_object_put(json
, "note", json_string_create(r
->note
));
636 case RAFT_REC_COMMIT_INDEX
:
637 raft_put_uint64(json
, "commit_index", r
->commit_index
);
640 case RAFT_REC_LEADER
:
641 raft_put_uint64(json
, "term", r
->term
);
642 json_object_put_format(json
, "leader", UUID_FMT
, UUID_ARGS(&r
->sid
));
651 /* Puts 'integer' into JSON 'object' with the given 'name'.
653 * The OVS JSON implementation only supports integers in the range
654 * INT64_MIN...INT64_MAX, which causes trouble for values from INT64_MAX+1 to
655 * UINT64_MAX. We map those into the negative range. */
657 raft_put_uint64(struct json
*object
, const char *name
, uint64_t integer
)
659 json_object_put(object
, name
, json_integer_create(integer
));
662 /* Parses an integer from parser 'p' with the given 'name'.
664 * The OVS JSON implementation only supports integers in the range
665 * INT64_MIN...INT64_MAX, which causes trouble for values from INT64_MAX+1 to
666 * UINT64_MAX. We map the negative range back into positive numbers. */
668 raft_parse_uint64__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
670 enum ovsdb_parser_types types
= OP_INTEGER
| (optional
? OP_OPTIONAL
: 0);
671 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
672 return json
? json_integer(json
) : 0;
676 raft_parse_optional_uint64(struct ovsdb_parser
*p
, const char *name
)
678 return raft_parse_uint64__(p
, name
, true);
682 raft_parse_required_uint64(struct ovsdb_parser
*p
, const char *name
)
684 return raft_parse_uint64__(p
, name
, false);
688 raft_parse_boolean__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
690 enum ovsdb_parser_types types
= OP_BOOLEAN
| (optional
? OP_OPTIONAL
: 0);
691 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
692 return json
? json_boolean(json
) : -1;
696 raft_parse_required_boolean(struct ovsdb_parser
*p
, const char *name
)
698 return raft_parse_boolean__(p
, name
, false);
701 /* Returns true or false if present, -1 if absent. */
703 raft_parse_optional_boolean(struct ovsdb_parser
*p
, const char *name
)
705 return raft_parse_boolean__(p
, name
, true);
709 raft_parse_string__(struct ovsdb_parser
*p
, const char *name
, bool optional
)
711 enum ovsdb_parser_types types
= OP_STRING
| (optional
? OP_OPTIONAL
: 0);
712 const struct json
*json
= ovsdb_parser_member(p
, name
, types
);
713 return json
? json_string(json
) : NULL
;
717 raft_parse_required_string(struct ovsdb_parser
*p
, const char *name
)
719 return raft_parse_string__(p
, name
, false);
723 raft_parse_optional_string(struct ovsdb_parser
*p
, const char *name
)
725 return raft_parse_string__(p
, name
, true);
729 raft_parse_uuid(struct ovsdb_parser
*p
, const char *name
, bool optional
,
732 const char *s
= raft_parse_string__(p
, name
, optional
);
734 if (uuid_from_string(uuid
, s
)) {
737 ovsdb_parser_raise_error(p
, "%s is not a valid UUID", name
);
744 raft_parse_required_uuid(struct ovsdb_parser
*p
, const char *name
)
747 raft_parse_uuid(p
, name
, false, &uuid
);
752 raft_parse_optional_uuid(struct ovsdb_parser
*p
, const char *name
,
755 return raft_parse_uuid(p
, name
, true, uuid
);