]>
git.proxmox.com Git - mirror_frr.git/blob - bfdd/config.c
1 /*********************************************************************
2 * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * config.c: implements the BFD daemon configuration handling.
22 * Rafael Zalamena <rzalamena@opensourcerouting.org>
33 DEFINE_MTYPE_STATIC(BFDD
, BFDD_LABEL
, "long-lived label memory")
48 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
);
49 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
50 bpc_handle h
, void *arg
);
51 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
);
52 static int parse_peer_label_config(struct json_object
*jo
,
53 struct bfd_peer_cfg
*bpc
);
55 static int config_add(struct bfd_peer_cfg
*bpc
, void *arg
);
56 static int config_del(struct bfd_peer_cfg
*bpc
, void *arg
);
58 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
);
64 static int config_add(struct bfd_peer_cfg
*bpc
,
65 void *arg
__attribute__((unused
)))
67 return ptm_bfd_sess_new(bpc
) == NULL
;
70 static int config_del(struct bfd_peer_cfg
*bpc
,
71 void *arg
__attribute__((unused
)))
73 return ptm_bfd_sess_del(bpc
) != 0;
76 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
)
78 const char *key
, *sval
;
79 struct json_object
*jo_val
;
80 struct json_object_iterator joi
, join
;
83 JSON_FOREACH (jo
, joi
, join
) {
84 key
= json_object_iter_peek_name(&joi
);
85 jo_val
= json_object_iter_peek_value(&joi
);
87 if (strcmp(key
, "ipv4") == 0) {
88 error
+= parse_list(jo_val
, PLT_IPV4
, h
, arg
);
89 } else if (strcmp(key
, "ipv6") == 0) {
90 error
+= parse_list(jo_val
, PLT_IPV6
, h
, arg
);
91 } else if (strcmp(key
, "label") == 0) {
92 error
+= parse_list(jo_val
, PLT_LABEL
, h
, arg
);
94 sval
= json_object_get_string(jo_val
);
95 log_warning("%s:%d invalid configuration: %s", __func__
,
102 * Our callers never call free() on json_object and only expect
103 * the return value, so lets free() it here.
110 int parse_config(const char *fname
)
112 struct json_object
*jo
;
114 jo
= json_object_from_file(fname
);
118 return parse_config_json(jo
, config_add
, NULL
);
121 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
122 bpc_handle h
, void *arg
)
124 struct json_object
*jo_val
;
125 struct bfd_peer_cfg bpc
;
127 int error
= 0, result
;
129 allen
= json_object_array_length(jo
);
130 for (idx
= 0; idx
< allen
; idx
++) {
131 jo_val
= json_object_array_get_idx(jo
, idx
);
134 memset(&bpc
, 0, sizeof(bpc
));
135 bpc
.bpc_detectmultiplier
= BFD_DEFDETECTMULT
;
136 bpc
.bpc_recvinterval
= BFD_DEFREQUIREDMINRX
;
137 bpc
.bpc_txinterval
= BFD_DEFDESIREDMINTX
;
138 bpc
.bpc_echointerval
= BFD_DEF_REQ_MIN_ECHO
;
142 log_debug("ipv4 peers %d:", allen
);
146 log_debug("ipv6 peers %d:", allen
);
147 bpc
.bpc_ipv4
= false;
150 log_debug("label peers %d:", allen
);
151 if (parse_peer_label_config(jo_val
, &bpc
) != 0) {
159 log_error("%s:%d: unsupported peer type", __func__
,
164 result
= parse_peer_config(jo_val
, &bpc
);
167 error
+= (h(&bpc
, arg
) != 0);
173 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
)
175 const char *key
, *sval
;
176 struct json_object
*jo_val
;
177 struct json_object_iterator joi
, join
;
178 int family_type
= (bpc
->bpc_ipv4
) ? AF_INET
: AF_INET6
;
181 log_debug("\tpeer: %s", bpc
->bpc_ipv4
? "ipv4" : "ipv6");
183 JSON_FOREACH (jo
, joi
, join
) {
184 key
= json_object_iter_peek_name(&joi
);
185 jo_val
= json_object_iter_peek_value(&joi
);
187 if (strcmp(key
, "multihop") == 0) {
188 bpc
->bpc_mhop
= json_object_get_boolean(jo_val
);
189 log_debug("\tmultihop: %s",
190 bpc
->bpc_mhop
? "true" : "false");
191 } else if (strcmp(key
, "peer-address") == 0) {
192 sval
= json_object_get_string(jo_val
);
193 if (strtosa(sval
, &bpc
->bpc_peer
) != 0
194 || bpc
->bpc_peer
.sa_sin
.sin_family
!= family_type
) {
196 "%s:%d failed to parse peer-address '%s'",
197 __func__
, __LINE__
, sval
);
200 log_debug("\tpeer-address: %s", sval
);
201 } else if (strcmp(key
, "local-address") == 0) {
202 sval
= json_object_get_string(jo_val
);
203 if (strtosa(sval
, &bpc
->bpc_local
) != 0
204 || bpc
->bpc_local
.sa_sin
.sin_family
207 "%s:%d failed to parse local-address '%s'",
208 __func__
, __LINE__
, sval
);
211 log_debug("\tlocal-address: %s", sval
);
212 } else if (strcmp(key
, "local-interface") == 0) {
213 bpc
->bpc_has_localif
= true;
214 sval
= json_object_get_string(jo_val
);
215 if (strlcpy(bpc
->bpc_localif
, sval
,
216 sizeof(bpc
->bpc_localif
))
217 > sizeof(bpc
->bpc_localif
)) {
218 log_debug("\tlocal-interface: %s (truncated)",
222 log_debug("\tlocal-interface: %s", sval
);
224 } else if (strcmp(key
, "vrf-name") == 0) {
225 bpc
->bpc_has_vrfname
= true;
226 sval
= json_object_get_string(jo_val
);
227 if (strlcpy(bpc
->bpc_vrfname
, sval
,
228 sizeof(bpc
->bpc_vrfname
))
229 > sizeof(bpc
->bpc_vrfname
)) {
230 log_debug("\tvrf-name: %s (truncated)", sval
);
233 log_debug("\tvrf-name: %s", sval
);
235 } else if (strcmp(key
, "detect-multiplier") == 0) {
236 bpc
->bpc_detectmultiplier
=
237 json_object_get_int64(jo_val
);
238 bpc
->bpc_has_detectmultiplier
= true;
239 log_debug("\tdetect-multiplier: %u",
240 bpc
->bpc_detectmultiplier
);
241 } else if (strcmp(key
, "receive-interval") == 0) {
242 bpc
->bpc_recvinterval
= json_object_get_int64(jo_val
);
243 bpc
->bpc_has_recvinterval
= true;
244 log_debug("\treceive-interval: %llu",
245 bpc
->bpc_recvinterval
);
246 } else if (strcmp(key
, "transmit-interval") == 0) {
247 bpc
->bpc_txinterval
= json_object_get_int64(jo_val
);
248 bpc
->bpc_has_txinterval
= true;
249 log_debug("\ttransmit-interval: %llu",
250 bpc
->bpc_txinterval
);
251 } else if (strcmp(key
, "echo-interval") == 0) {
252 bpc
->bpc_echointerval
= json_object_get_int64(jo_val
);
253 bpc
->bpc_has_echointerval
= true;
254 log_debug("\techo-interval: %llu",
255 bpc
->bpc_echointerval
);
256 } else if (strcmp(key
, "create-only") == 0) {
257 bpc
->bpc_createonly
= json_object_get_boolean(jo_val
);
258 log_debug("\tcreate-only: %s",
259 bpc
->bpc_createonly
? "true" : "false");
260 } else if (strcmp(key
, "shutdown") == 0) {
261 bpc
->bpc_shutdown
= json_object_get_boolean(jo_val
);
262 log_debug("\tshutdown: %s",
263 bpc
->bpc_shutdown
? "true" : "false");
264 } else if (strcmp(key
, "echo-mode") == 0) {
265 bpc
->bpc_echo
= json_object_get_boolean(jo_val
);
266 log_debug("\techo-mode: %s",
267 bpc
->bpc_echo
? "true" : "false");
268 } else if (strcmp(key
, "label") == 0) {
269 bpc
->bpc_has_label
= true;
270 sval
= json_object_get_string(jo_val
);
271 if (strlcpy(bpc
->bpc_label
, sval
,
272 sizeof(bpc
->bpc_label
))
273 > sizeof(bpc
->bpc_label
)) {
274 log_debug("\tlabel: %s (truncated)", sval
);
277 log_debug("\tlabel: %s", sval
);
280 sval
= json_object_get_string(jo_val
);
281 log_warning("%s:%d invalid configuration: '%s: %s'",
282 __func__
, __LINE__
, key
, sval
);
287 if (bpc
->bpc_peer
.sa_sin
.sin_family
== 0) {
288 log_debug("%s:%d no peer address provided", __func__
, __LINE__
);
295 static int parse_peer_label_config(struct json_object
*jo
,
296 struct bfd_peer_cfg
*bpc
)
298 struct peer_label
*pl
;
299 struct json_object
*label
;
302 /* Get label and translate it to BFD daemon key. */
303 if (!json_object_object_get_ex(jo
, "label", &label
))
306 sval
= json_object_get_string(label
);
312 log_debug("\tpeer-label: %s", sval
);
314 /* Translate the label into BFD address keys. */
315 bs_to_bpc(pl
->pl_bs
, bpc
);
322 * Control socket JSON parsing.
324 int config_request_add(const char *jsonstr
)
326 struct json_object
*jo
;
328 jo
= json_tokener_parse(jsonstr
);
332 return parse_config_json(jo
, config_add
, NULL
);
335 int config_request_del(const char *jsonstr
)
337 struct json_object
*jo
;
339 jo
= json_tokener_parse(jsonstr
);
343 return parse_config_json(jo
, config_del
, NULL
);
346 char *config_response(const char *status
, const char *error
)
348 struct json_object
*resp
, *jo
;
351 resp
= json_object_new_object();
355 /* Add 'status' response key. */
356 jo
= json_object_new_string(status
);
358 json_object_put(resp
);
362 json_object_object_add(resp
, "status", jo
);
364 /* Add 'error' response key. */
366 jo
= json_object_new_string(error
);
368 json_object_put(resp
);
372 json_object_object_add(resp
, "error", jo
);
375 /* Generate JSON response. */
377 MTYPE_BFDD_NOTIFICATION
,
378 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
379 json_object_put(resp
);
384 char *config_notify(struct bfd_session
*bs
)
386 struct json_object
*resp
;
390 resp
= json_object_new_object();
394 json_object_string_add(resp
, "op", BCM_NOTIFY_PEER_STATUS
);
396 json_object_add_peer(resp
, bs
);
398 /* Add status information */
399 json_object_int_add(resp
, "id", bs
->discrs
.my_discr
);
400 json_object_int_add(resp
, "remote-id", bs
->discrs
.my_discr
);
402 switch (bs
->ses_state
) {
404 json_object_string_add(resp
, "state", "up");
406 now
= monotime(NULL
);
407 json_object_int_add(resp
, "uptime", now
- bs
->uptime
.tv_sec
);
409 case PTM_BFD_ADM_DOWN
:
410 json_object_string_add(resp
, "state", "adm-down");
413 json_object_string_add(resp
, "state", "down");
415 now
= monotime(NULL
);
416 json_object_int_add(resp
, "downtime",
417 now
- bs
->downtime
.tv_sec
);
420 json_object_string_add(resp
, "state", "init");
424 json_object_string_add(resp
, "state", "unknown");
428 json_object_int_add(resp
, "diagnostics", bs
->local_diag
);
429 json_object_int_add(resp
, "remote-diagnostics", bs
->remote_diag
);
431 /* Generate JSON response. */
433 MTYPE_BFDD_NOTIFICATION
,
434 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
435 json_object_put(resp
);
440 char *config_notify_config(const char *op
, struct bfd_session
*bs
)
442 struct json_object
*resp
;
445 resp
= json_object_new_object();
449 json_object_string_add(resp
, "op", op
);
451 json_object_add_peer(resp
, bs
);
453 /* On peer deletion we don't need to add any additional information. */
454 if (strcmp(op
, BCM_NOTIFY_CONFIG_DELETE
) == 0)
457 json_object_int_add(resp
, "detect-multiplier", bs
->detect_mult
);
458 json_object_int_add(resp
, "receive-interval",
459 bs
->timers
.required_min_rx
/ 1000);
460 json_object_int_add(resp
, "transmit-interval",
461 bs
->timers
.desired_min_tx
/ 1000);
462 json_object_int_add(resp
, "echo-interval",
463 bs
->timers
.required_min_echo
/ 1000);
465 json_object_int_add(resp
, "remote-detect-multiplier",
466 bs
->remote_detect_mult
);
467 json_object_int_add(resp
, "remote-receive-interval",
468 bs
->remote_timers
.required_min_rx
/ 1000);
469 json_object_int_add(resp
, "remote-transmit-interval",
470 bs
->remote_timers
.desired_min_tx
/ 1000);
471 json_object_int_add(resp
, "remote-echo-interval",
472 bs
->remote_timers
.required_min_echo
/ 1000);
474 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
475 json_object_boolean_true_add(resp
, "echo-mode");
477 json_object_boolean_false_add(resp
, "echo-mode");
479 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
480 json_object_boolean_true_add(resp
, "shutdown");
482 json_object_boolean_false_add(resp
, "shutdown");
485 /* Generate JSON response. */
487 MTYPE_BFDD_NOTIFICATION
,
488 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
489 json_object_put(resp
);
494 int config_notify_request(struct bfd_control_socket
*bcs
, const char *jsonstr
,
497 struct json_object
*jo
;
499 jo
= json_tokener_parse(jsonstr
);
503 return parse_config_json(jo
, bh
, bcs
);
506 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
)
508 char addr_buf
[INET6_ADDRSTRLEN
];
510 /* Add peer 'key' information. */
511 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_IPV6
))
512 json_object_boolean_true_add(jo
, "ipv6");
514 json_object_boolean_false_add(jo
, "ipv6");
516 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
)) {
517 json_object_boolean_true_add(jo
, "multihop");
518 json_object_string_add(jo
, "peer-address",
519 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
520 addr_buf
, sizeof(addr_buf
)));
521 json_object_string_add(jo
, "local-address",
522 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
523 addr_buf
, sizeof(addr_buf
)));
524 if (bs
->key
.vrfname
[0])
525 json_object_string_add(jo
, "vrf-name", bs
->key
.vrfname
);
527 json_object_boolean_false_add(jo
, "multihop");
528 json_object_string_add(jo
, "peer-address",
529 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
530 addr_buf
, sizeof(addr_buf
)));
531 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
532 json_object_string_add(
534 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
535 addr_buf
, sizeof(addr_buf
)));
536 if (bs
->key
.ifname
[0])
537 json_object_string_add(jo
, "local-interface",
542 json_object_string_add(jo
, "label", bs
->pl
->pl_label
);
551 struct peer_label
*pl_find(const char *label
)
553 struct peer_label
*pl
;
555 TAILQ_FOREACH (pl
, &bglobal
.bg_pllist
, pl_entry
) {
556 if (strcmp(pl
->pl_label
, label
) != 0)
565 struct peer_label
*pl_new(const char *label
, struct bfd_session
*bs
)
567 struct peer_label
*pl
;
569 pl
= XCALLOC(MTYPE_BFDD_LABEL
, sizeof(*pl
));
571 if (strlcpy(pl
->pl_label
, label
, sizeof(pl
->pl_label
))
572 > sizeof(pl
->pl_label
))
573 log_warning("%s:%d: label was truncated", __func__
, __LINE__
);
578 TAILQ_INSERT_HEAD(&bglobal
.bg_pllist
, pl
, pl_entry
);
583 void pl_free(struct peer_label
*pl
)
588 /* Remove the pointer back. */
589 pl
->pl_bs
->pl
= NULL
;
591 TAILQ_REMOVE(&bglobal
.bg_pllist
, pl
, pl_entry
);
592 XFREE(MTYPE_BFDD_LABEL
, pl
);