]>
git.proxmox.com Git - mirror_frr.git/blob - bfdd/config.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*********************************************************************
3 * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
5 * config.c: implements the BFD daemon configuration handling.
9 * Rafael Zalamena <rzalamena@opensourcerouting.org>
20 DEFINE_MTYPE_STATIC(BFDD
, BFDD_LABEL
, "long-lived label memory");
35 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
);
36 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
37 bpc_handle h
, void *arg
);
38 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
);
39 static int parse_peer_label_config(struct json_object
*jo
,
40 struct bfd_peer_cfg
*bpc
);
42 static int config_add(struct bfd_peer_cfg
*bpc
, void *arg
);
43 static int config_del(struct bfd_peer_cfg
*bpc
, void *arg
);
45 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
);
51 static int config_add(struct bfd_peer_cfg
*bpc
,
52 void *arg
__attribute__((unused
)))
54 return ptm_bfd_sess_new(bpc
) == NULL
;
57 static int config_del(struct bfd_peer_cfg
*bpc
,
58 void *arg
__attribute__((unused
)))
60 return ptm_bfd_sess_del(bpc
) != 0;
63 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
)
65 const char *key
, *sval
;
66 struct json_object
*jo_val
;
67 struct json_object_iterator joi
, join
;
70 JSON_FOREACH (jo
, joi
, join
) {
71 key
= json_object_iter_peek_name(&joi
);
72 jo_val
= json_object_iter_peek_value(&joi
);
74 if (strcmp(key
, "ipv4") == 0) {
75 error
+= parse_list(jo_val
, PLT_IPV4
, h
, arg
);
76 } else if (strcmp(key
, "ipv6") == 0) {
77 error
+= parse_list(jo_val
, PLT_IPV6
, h
, arg
);
78 } else if (strcmp(key
, "label") == 0) {
79 error
+= parse_list(jo_val
, PLT_LABEL
, h
, arg
);
81 sval
= json_object_get_string(jo_val
);
82 zlog_warn("%s:%d invalid configuration: %s", __func__
,
89 * Our callers never call free() on json_object and only expect
90 * the return value, so lets free() it here.
97 int parse_config(const char *fname
)
99 struct json_object
*jo
;
101 jo
= json_object_from_file(fname
);
105 return parse_config_json(jo
, config_add
, NULL
);
108 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
109 bpc_handle h
, void *arg
)
111 struct json_object
*jo_val
;
112 struct bfd_peer_cfg bpc
;
114 int error
= 0, result
;
116 allen
= json_object_array_length(jo
);
117 for (idx
= 0; idx
< allen
; idx
++) {
118 jo_val
= json_object_array_get_idx(jo
, idx
);
121 memset(&bpc
, 0, sizeof(bpc
));
122 bpc
.bpc_detectmultiplier
= BFD_DEFDETECTMULT
;
123 bpc
.bpc_recvinterval
= BFD_DEFREQUIREDMINRX
;
124 bpc
.bpc_txinterval
= BFD_DEFDESIREDMINTX
;
125 bpc
.bpc_echorecvinterval
= BFD_DEF_REQ_MIN_ECHO_RX
;
126 bpc
.bpc_echotxinterval
= BFD_DEF_DES_MIN_ECHO_TX
;
130 zlog_debug("ipv4 peers %d:", allen
);
134 zlog_debug("ipv6 peers %d:", allen
);
135 bpc
.bpc_ipv4
= false;
138 zlog_debug("label peers %d:", allen
);
139 if (parse_peer_label_config(jo_val
, &bpc
) != 0) {
147 zlog_err("%s:%d: unsupported peer type", __func__
,
152 result
= parse_peer_config(jo_val
, &bpc
);
155 error
+= (h(&bpc
, arg
) != 0);
161 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
)
163 const char *key
, *sval
;
164 struct json_object
*jo_val
;
165 struct json_object_iterator joi
, join
;
166 int family_type
= (bpc
->bpc_ipv4
) ? AF_INET
: AF_INET6
;
169 zlog_debug(" peer: %s", bpc
->bpc_ipv4
? "ipv4" : "ipv6");
171 JSON_FOREACH (jo
, joi
, join
) {
172 key
= json_object_iter_peek_name(&joi
);
173 jo_val
= json_object_iter_peek_value(&joi
);
175 if (strcmp(key
, "multihop") == 0) {
176 bpc
->bpc_mhop
= json_object_get_boolean(jo_val
);
177 zlog_debug(" multihop: %s",
178 bpc
->bpc_mhop
? "true" : "false");
179 } else if (strcmp(key
, "peer-address") == 0) {
180 sval
= json_object_get_string(jo_val
);
181 if (strtosa(sval
, &bpc
->bpc_peer
) != 0
182 || bpc
->bpc_peer
.sa_sin
.sin_family
!= family_type
) {
184 "%s:%d failed to parse peer-address '%s'",
185 __func__
, __LINE__
, sval
);
188 zlog_debug(" peer-address: %s", sval
);
189 } else if (strcmp(key
, "local-address") == 0) {
190 sval
= json_object_get_string(jo_val
);
191 if (strtosa(sval
, &bpc
->bpc_local
) != 0
192 || bpc
->bpc_local
.sa_sin
.sin_family
195 "%s:%d failed to parse local-address '%s'",
196 __func__
, __LINE__
, sval
);
199 zlog_debug(" local-address: %s", sval
);
200 } else if (strcmp(key
, "local-interface") == 0) {
201 bpc
->bpc_has_localif
= true;
202 sval
= json_object_get_string(jo_val
);
203 if (strlcpy(bpc
->bpc_localif
, sval
,
204 sizeof(bpc
->bpc_localif
))
205 > sizeof(bpc
->bpc_localif
)) {
207 " local-interface: %s (truncated)",
211 zlog_debug(" local-interface: %s", sval
);
213 } else if (strcmp(key
, "vrf-name") == 0) {
214 bpc
->bpc_has_vrfname
= true;
215 sval
= json_object_get_string(jo_val
);
216 if (strlcpy(bpc
->bpc_vrfname
, sval
,
217 sizeof(bpc
->bpc_vrfname
))
218 > sizeof(bpc
->bpc_vrfname
)) {
219 zlog_debug(" vrf-name: %s (truncated)",
223 zlog_debug(" vrf-name: %s", sval
);
225 } else if (strcmp(key
, "detect-multiplier") == 0) {
226 bpc
->bpc_detectmultiplier
=
227 json_object_get_int64(jo_val
);
228 bpc
->bpc_has_detectmultiplier
= true;
229 zlog_debug(" detect-multiplier: %u",
230 bpc
->bpc_detectmultiplier
);
231 } else if (strcmp(key
, "receive-interval") == 0) {
232 bpc
->bpc_recvinterval
= json_object_get_int64(jo_val
);
233 bpc
->bpc_has_recvinterval
= true;
234 zlog_debug(" receive-interval: %" PRIu64
,
235 bpc
->bpc_recvinterval
);
236 } else if (strcmp(key
, "transmit-interval") == 0) {
237 bpc
->bpc_txinterval
= json_object_get_int64(jo_val
);
238 bpc
->bpc_has_txinterval
= true;
239 zlog_debug(" transmit-interval: %" PRIu64
,
240 bpc
->bpc_txinterval
);
241 } else if (strcmp(key
, "echo-receive-interval") == 0) {
242 bpc
->bpc_echorecvinterval
= json_object_get_int64(jo_val
);
243 bpc
->bpc_has_echorecvinterval
= true;
244 zlog_debug(" echo-receive-interval: %" PRIu64
,
245 bpc
->bpc_echorecvinterval
);
246 } else if (strcmp(key
, "echo-transmit-interval") == 0) {
247 bpc
->bpc_echotxinterval
= json_object_get_int64(jo_val
);
248 bpc
->bpc_has_echotxinterval
= true;
249 zlog_debug(" echo-transmit-interval: %" PRIu64
,
250 bpc
->bpc_echotxinterval
);
251 } else if (strcmp(key
, "create-only") == 0) {
252 bpc
->bpc_createonly
= json_object_get_boolean(jo_val
);
253 zlog_debug(" create-only: %s",
254 bpc
->bpc_createonly
? "true" : "false");
255 } else if (strcmp(key
, "shutdown") == 0) {
256 bpc
->bpc_shutdown
= json_object_get_boolean(jo_val
);
257 zlog_debug(" shutdown: %s",
258 bpc
->bpc_shutdown
? "true" : "false");
259 } else if (strcmp(key
, "echo-mode") == 0) {
260 bpc
->bpc_echo
= json_object_get_boolean(jo_val
);
261 zlog_debug(" echo-mode: %s",
262 bpc
->bpc_echo
? "true" : "false");
263 } else if (strcmp(key
, "label") == 0) {
264 bpc
->bpc_has_label
= true;
265 sval
= json_object_get_string(jo_val
);
266 if (strlcpy(bpc
->bpc_label
, sval
,
267 sizeof(bpc
->bpc_label
))
268 > sizeof(bpc
->bpc_label
)) {
269 zlog_debug(" label: %s (truncated)",
273 zlog_debug(" label: %s", sval
);
276 sval
= json_object_get_string(jo_val
);
277 zlog_warn("%s:%d invalid configuration: '%s: %s'",
278 __func__
, __LINE__
, key
, sval
);
283 if (bpc
->bpc_peer
.sa_sin
.sin_family
== 0) {
284 zlog_debug("%s:%d no peer address provided", __func__
,
292 static int parse_peer_label_config(struct json_object
*jo
,
293 struct bfd_peer_cfg
*bpc
)
295 struct peer_label
*pl
;
296 struct json_object
*label
;
299 /* Get label and translate it to BFD daemon key. */
300 if (!json_object_object_get_ex(jo
, "label", &label
))
303 sval
= json_object_get_string(label
);
309 zlog_debug(" peer-label: %s", sval
);
311 /* Translate the label into BFD address keys. */
312 bs_to_bpc(pl
->pl_bs
, bpc
);
319 * Control socket JSON parsing.
321 int config_request_add(const char *jsonstr
)
323 struct json_object
*jo
;
325 jo
= json_tokener_parse(jsonstr
);
329 return parse_config_json(jo
, config_add
, NULL
);
332 int config_request_del(const char *jsonstr
)
334 struct json_object
*jo
;
336 jo
= json_tokener_parse(jsonstr
);
340 return parse_config_json(jo
, config_del
, NULL
);
343 char *config_response(const char *status
, const char *error
)
345 struct json_object
*resp
, *jo
;
348 resp
= json_object_new_object();
352 /* Add 'status' response key. */
353 jo
= json_object_new_string(status
);
355 json_object_put(resp
);
359 json_object_object_add(resp
, "status", jo
);
361 /* Add 'error' response key. */
363 jo
= json_object_new_string(error
);
365 json_object_put(resp
);
369 json_object_object_add(resp
, "error", jo
);
372 /* Generate JSON response. */
374 MTYPE_BFDD_NOTIFICATION
,
375 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
376 json_object_put(resp
);
381 char *config_notify(struct bfd_session
*bs
)
383 struct json_object
*resp
;
387 resp
= json_object_new_object();
391 json_object_string_add(resp
, "op", BCM_NOTIFY_PEER_STATUS
);
393 json_object_add_peer(resp
, bs
);
395 /* Add status information */
396 json_object_int_add(resp
, "id", bs
->discrs
.my_discr
);
397 json_object_int_add(resp
, "remote-id", bs
->discrs
.my_discr
);
399 switch (bs
->ses_state
) {
401 json_object_string_add(resp
, "state", "up");
403 now
= monotime(NULL
);
404 json_object_int_add(resp
, "uptime", now
- bs
->uptime
.tv_sec
);
406 case PTM_BFD_ADM_DOWN
:
407 json_object_string_add(resp
, "state", "adm-down");
410 json_object_string_add(resp
, "state", "down");
412 now
= monotime(NULL
);
413 json_object_int_add(resp
, "downtime",
414 now
- bs
->downtime
.tv_sec
);
417 json_object_string_add(resp
, "state", "init");
421 json_object_string_add(resp
, "state", "unknown");
425 json_object_int_add(resp
, "diagnostics", bs
->local_diag
);
426 json_object_int_add(resp
, "remote-diagnostics", bs
->remote_diag
);
428 /* Generate JSON response. */
430 MTYPE_BFDD_NOTIFICATION
,
431 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
432 json_object_put(resp
);
437 char *config_notify_config(const char *op
, struct bfd_session
*bs
)
439 struct json_object
*resp
;
442 resp
= json_object_new_object();
446 json_object_string_add(resp
, "op", op
);
448 json_object_add_peer(resp
, bs
);
450 /* On peer deletion we don't need to add any additional information. */
451 if (strcmp(op
, BCM_NOTIFY_CONFIG_DELETE
) == 0)
454 json_object_int_add(resp
, "detect-multiplier", bs
->detect_mult
);
455 json_object_int_add(resp
, "receive-interval",
456 bs
->timers
.required_min_rx
/ 1000);
457 json_object_int_add(resp
, "transmit-interval",
458 bs
->timers
.desired_min_tx
/ 1000);
459 json_object_int_add(resp
, "echo-receive-interval",
460 bs
->timers
.required_min_echo_rx
/ 1000);
461 json_object_int_add(resp
, "echo-transmit-interval",
462 bs
->timers
.desired_min_echo_tx
/ 1000);
464 json_object_int_add(resp
, "remote-detect-multiplier",
465 bs
->remote_detect_mult
);
466 json_object_int_add(resp
, "remote-receive-interval",
467 bs
->remote_timers
.required_min_rx
/ 1000);
468 json_object_int_add(resp
, "remote-transmit-interval",
469 bs
->remote_timers
.desired_min_tx
/ 1000);
470 json_object_int_add(resp
, "remote-echo-receive-interval",
471 bs
->remote_timers
.required_min_echo
/ 1000);
473 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
474 json_object_boolean_true_add(resp
, "echo-mode");
476 json_object_boolean_false_add(resp
, "echo-mode");
478 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
479 json_object_boolean_true_add(resp
, "shutdown");
481 json_object_boolean_false_add(resp
, "shutdown");
484 /* Generate JSON response. */
486 MTYPE_BFDD_NOTIFICATION
,
487 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
488 json_object_put(resp
);
493 int config_notify_request(struct bfd_control_socket
*bcs
, const char *jsonstr
,
496 struct json_object
*jo
;
498 jo
= json_tokener_parse(jsonstr
);
502 return parse_config_json(jo
, bh
, bcs
);
505 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
)
507 char addr_buf
[INET6_ADDRSTRLEN
];
509 /* Add peer 'key' information. */
510 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_IPV6
))
511 json_object_boolean_true_add(jo
, "ipv6");
513 json_object_boolean_false_add(jo
, "ipv6");
515 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
)) {
516 json_object_boolean_true_add(jo
, "multihop");
517 json_object_string_add(jo
, "peer-address",
518 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
519 addr_buf
, sizeof(addr_buf
)));
520 json_object_string_add(jo
, "local-address",
521 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
522 addr_buf
, sizeof(addr_buf
)));
523 if (bs
->key
.vrfname
[0])
524 json_object_string_add(jo
, "vrf-name", bs
->key
.vrfname
);
526 json_object_boolean_false_add(jo
, "multihop");
527 json_object_string_add(jo
, "peer-address",
528 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
529 addr_buf
, sizeof(addr_buf
)));
530 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
531 json_object_string_add(
533 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
534 addr_buf
, sizeof(addr_buf
)));
535 if (bs
->key
.ifname
[0])
536 json_object_string_add(jo
, "local-interface",
541 json_object_string_add(jo
, "label", bs
->pl
->pl_label
);
550 struct peer_label
*pl_find(const char *label
)
552 struct peer_label
*pl
;
554 TAILQ_FOREACH (pl
, &bglobal
.bg_pllist
, pl_entry
) {
555 if (strcmp(pl
->pl_label
, label
) != 0)
564 struct peer_label
*pl_new(const char *label
, struct bfd_session
*bs
)
566 struct peer_label
*pl
;
568 pl
= XCALLOC(MTYPE_BFDD_LABEL
, sizeof(*pl
));
570 if (strlcpy(pl
->pl_label
, label
, sizeof(pl
->pl_label
))
571 > sizeof(pl
->pl_label
))
572 zlog_warn("%s:%d: label was truncated", __func__
, __LINE__
);
577 TAILQ_INSERT_HEAD(&bglobal
.bg_pllist
, pl
, pl_entry
);
582 void pl_free(struct peer_label
*pl
)
587 /* Remove the pointer back. */
588 pl
->pl_bs
->pl
= NULL
;
590 TAILQ_REMOVE(&bglobal
.bg_pllist
, pl
, pl_entry
);
591 XFREE(MTYPE_BFDD_LABEL
, pl
);