]>
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>
46 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
);
47 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
48 bpc_handle h
, void *arg
);
49 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
);
50 static int parse_peer_label_config(struct json_object
*jo
,
51 struct bfd_peer_cfg
*bpc
);
53 static int config_add(struct bfd_peer_cfg
*bpc
, void *arg
);
54 static int config_del(struct bfd_peer_cfg
*bpc
, void *arg
);
56 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
);
62 static int config_add(struct bfd_peer_cfg
*bpc
,
63 void *arg
__attribute__((unused
)))
65 return ptm_bfd_sess_new(bpc
) == NULL
;
68 static int config_del(struct bfd_peer_cfg
*bpc
,
69 void *arg
__attribute__((unused
)))
71 return ptm_bfd_ses_del(bpc
) != 0;
74 static int parse_config_json(struct json_object
*jo
, bpc_handle h
, void *arg
)
76 const char *key
, *sval
;
77 struct json_object
*jo_val
;
78 struct json_object_iterator joi
, join
;
81 JSON_FOREACH (jo
, joi
, join
) {
82 key
= json_object_iter_peek_name(&joi
);
83 jo_val
= json_object_iter_peek_value(&joi
);
85 if (strcmp(key
, "ipv4") == 0) {
86 error
+= parse_list(jo_val
, PLT_IPV4
, h
, arg
);
87 } else if (strcmp(key
, "ipv6") == 0) {
88 error
+= parse_list(jo_val
, PLT_IPV6
, h
, arg
);
89 } else if (strcmp(key
, "label") == 0) {
90 error
+= parse_list(jo_val
, PLT_LABEL
, h
, arg
);
92 sval
= json_object_get_string(jo_val
);
93 log_warning("%s:%d invalid configuration: %s", __func__
,
100 * Our callers never call free() on json_object and only expect
101 * the return value, so lets free() it here.
108 int parse_config(const char *fname
)
110 struct json_object
*jo
;
112 jo
= json_object_from_file(fname
);
116 return parse_config_json(jo
, config_add
, NULL
);
119 static int parse_list(struct json_object
*jo
, enum peer_list_type plt
,
120 bpc_handle h
, void *arg
)
122 struct json_object
*jo_val
;
123 struct bfd_peer_cfg bpc
;
125 int error
= 0, result
;
127 allen
= json_object_array_length(jo
);
128 for (idx
= 0; idx
< allen
; idx
++) {
129 jo_val
= json_object_array_get_idx(jo
, idx
);
132 memset(&bpc
, 0, sizeof(bpc
));
133 bpc
.bpc_detectmultiplier
= BFD_DEFDETECTMULT
;
134 bpc
.bpc_recvinterval
= BFD_DEFREQUIREDMINRX
;
135 bpc
.bpc_txinterval
= BFD_DEFDESIREDMINTX
;
136 bpc
.bpc_echointerval
= BFD_DEF_REQ_MIN_ECHO
;
140 log_debug("ipv4 peers %d:", allen
);
144 log_debug("ipv6 peers %d:", allen
);
145 bpc
.bpc_ipv4
= false;
148 log_debug("label peers %d:", allen
);
149 if (parse_peer_label_config(jo_val
, &bpc
) != 0) {
157 log_error("%s:%d: unsupported peer type", __func__
,
162 result
= parse_peer_config(jo_val
, &bpc
);
165 error
+= (h(&bpc
, arg
) != 0);
171 static int parse_peer_config(struct json_object
*jo
, struct bfd_peer_cfg
*bpc
)
173 const char *key
, *sval
;
174 struct json_object
*jo_val
;
175 struct json_object_iterator joi
, join
;
176 int family_type
= (bpc
->bpc_ipv4
) ? AF_INET
: AF_INET6
;
179 log_debug("\tpeer: %s", bpc
->bpc_ipv4
? "ipv4" : "ipv6");
181 JSON_FOREACH (jo
, joi
, join
) {
182 key
= json_object_iter_peek_name(&joi
);
183 jo_val
= json_object_iter_peek_value(&joi
);
185 if (strcmp(key
, "multihop") == 0) {
186 bpc
->bpc_mhop
= json_object_get_boolean(jo_val
);
187 log_debug("\tmultihop: %s",
188 bpc
->bpc_mhop
? "true" : "false");
189 } else if (strcmp(key
, "peer-address") == 0) {
190 sval
= json_object_get_string(jo_val
);
191 if (strtosa(sval
, &bpc
->bpc_peer
) != 0
192 || bpc
->bpc_peer
.sa_sin
.sin_family
!= family_type
) {
194 "%s:%d failed to parse peer-address '%s'",
195 __func__
, __LINE__
, sval
);
198 log_debug("\tpeer-address: %s", sval
);
199 } else if (strcmp(key
, "local-address") == 0) {
200 sval
= json_object_get_string(jo_val
);
201 if (strtosa(sval
, &bpc
->bpc_local
) != 0
202 || bpc
->bpc_local
.sa_sin
.sin_family
205 "%s:%d failed to parse local-address '%s'",
206 __func__
, __LINE__
, sval
);
209 log_debug("\tlocal-address: %s", sval
);
210 } else if (strcmp(key
, "local-interface") == 0) {
211 bpc
->bpc_has_localif
= true;
212 sval
= json_object_get_string(jo_val
);
213 if (strlcpy(bpc
->bpc_localif
, sval
,
214 sizeof(bpc
->bpc_localif
))
215 > sizeof(bpc
->bpc_localif
)) {
216 log_debug("\tlocal-interface: %s (truncated)");
219 log_debug("\tlocal-interface: %s", sval
);
221 } else if (strcmp(key
, "vxlan") == 0) {
222 bpc
->bpc_vxlan
= json_object_get_int64(jo_val
);
223 bpc
->bpc_has_vxlan
= true;
224 log_debug("\tvxlan: %ld", bpc
->bpc_vxlan
);
225 } else if (strcmp(key
, "vrf-name") == 0) {
226 bpc
->bpc_has_vrfname
= true;
227 sval
= json_object_get_string(jo_val
);
228 if (strlcpy(bpc
->bpc_vrfname
, sval
,
229 sizeof(bpc
->bpc_vrfname
))
230 > sizeof(bpc
->bpc_vrfname
)) {
231 log_debug("\tvrf-name: %s (truncated)", sval
);
234 log_debug("\tvrf-name: %s", sval
);
236 } else if (strcmp(key
, "detect-multiplier") == 0) {
237 bpc
->bpc_detectmultiplier
=
238 json_object_get_int64(jo_val
);
239 bpc
->bpc_has_detectmultiplier
= true;
240 log_debug("\tdetect-multiplier: %llu",
241 bpc
->bpc_detectmultiplier
);
242 } else if (strcmp(key
, "receive-interval") == 0) {
243 bpc
->bpc_recvinterval
= json_object_get_int64(jo_val
);
244 bpc
->bpc_has_recvinterval
= true;
245 log_debug("\treceive-interval: %llu",
246 bpc
->bpc_recvinterval
);
247 } else if (strcmp(key
, "transmit-interval") == 0) {
248 bpc
->bpc_txinterval
= json_object_get_int64(jo_val
);
249 bpc
->bpc_has_txinterval
= true;
250 log_debug("\ttransmit-interval: %llu",
251 bpc
->bpc_txinterval
);
252 } else if (strcmp(key
, "echo-interval") == 0) {
253 bpc
->bpc_echointerval
= json_object_get_int64(jo_val
);
254 bpc
->bpc_has_echointerval
= true;
255 log_debug("\techo-interval: %llu",
256 bpc
->bpc_echointerval
);
257 } else if (strcmp(key
, "create-only") == 0) {
258 bpc
->bpc_createonly
= json_object_get_boolean(jo_val
);
259 log_debug("\tcreate-only: %s",
260 bpc
->bpc_createonly
? "true" : "false");
261 } else if (strcmp(key
, "shutdown") == 0) {
262 bpc
->bpc_shutdown
= json_object_get_boolean(jo_val
);
263 log_debug("\tshutdown: %s",
264 bpc
->bpc_shutdown
? "true" : "false");
265 } else if (strcmp(key
, "echo-mode") == 0) {
266 bpc
->bpc_echo
= json_object_get_boolean(jo_val
);
267 log_debug("\techo-mode: %s",
268 bpc
->bpc_echo
? "true" : "false");
269 } else if (strcmp(key
, "label") == 0) {
270 bpc
->bpc_has_label
= true;
271 sval
= json_object_get_string(jo_val
);
272 if (strlcpy(bpc
->bpc_label
, sval
,
273 sizeof(bpc
->bpc_label
))
274 > sizeof(bpc
->bpc_label
)) {
275 log_debug("\tlabel: %s (truncated)", sval
);
278 log_debug("\tlabel: %s", sval
);
281 sval
= json_object_get_string(jo_val
);
282 log_warning("%s:%d invalid configuration: '%s: %s'",
283 __func__
, __LINE__
, key
, sval
);
288 if (bpc
->bpc_peer
.sa_sin
.sin_family
== 0) {
289 log_debug("%s:%d no peer address provided", __func__
, __LINE__
);
296 static int parse_peer_label_config(struct json_object
*jo
,
297 struct bfd_peer_cfg
*bpc
)
299 struct peer_label
*pl
;
300 struct json_object
*label
;
303 /* Get label and translate it to BFD daemon key. */
304 if (!json_object_object_get_ex(jo
, "label", &label
))
307 sval
= json_object_get_string(label
);
313 log_debug("\tpeer-label: %s", sval
);
315 /* Translate the label into BFD address keys. */
316 bpc
->bpc_ipv4
= !BFD_CHECK_FLAG(pl
->pl_bs
->flags
, BFD_SESS_FLAG_IPV6
);
317 bpc
->bpc_mhop
= BFD_CHECK_FLAG(pl
->pl_bs
->flags
, BFD_SESS_FLAG_MH
);
319 bpc
->bpc_peer
= pl
->pl_bs
->mhop
.peer
;
320 bpc
->bpc_local
= pl
->pl_bs
->mhop
.local
;
321 if (pl
->pl_bs
->mhop
.vrf_name
[0]) {
322 bpc
->bpc_has_vrfname
= true;
323 strlcpy(bpc
->bpc_vrfname
, pl
->pl_bs
->mhop
.vrf_name
,
324 sizeof(bpc
->bpc_vrfname
));
327 bpc
->bpc_peer
= pl
->pl_bs
->shop
.peer
;
328 if (pl
->pl_bs
->shop
.port_name
[0]) {
329 bpc
->bpc_has_localif
= true;
330 strlcpy(bpc
->bpc_localif
, pl
->pl_bs
->shop
.port_name
,
331 sizeof(bpc
->bpc_localif
));
340 * Control socket JSON parsing.
342 int config_request_add(const char *jsonstr
)
344 struct json_object
*jo
;
346 jo
= json_tokener_parse(jsonstr
);
350 return parse_config_json(jo
, config_add
, NULL
);
353 int config_request_del(const char *jsonstr
)
355 struct json_object
*jo
;
357 jo
= json_tokener_parse(jsonstr
);
361 return parse_config_json(jo
, config_del
, NULL
);
364 char *config_response(const char *status
, const char *error
)
366 struct json_object
*resp
, *jo
;
369 resp
= json_object_new_object();
373 /* Add 'status' response key. */
374 jo
= json_object_new_string(status
);
376 json_object_put(resp
);
380 json_object_object_add(resp
, "status", jo
);
382 /* Add 'error' response key. */
384 jo
= json_object_new_string(error
);
386 json_object_put(resp
);
390 json_object_object_add(resp
, "error", jo
);
393 /* Generate JSON response. */
395 MTYPE_BFDD_NOTIFICATION
,
396 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
397 json_object_put(resp
);
402 char *config_notify(struct bfd_session
*bs
)
404 struct json_object
*resp
;
408 resp
= json_object_new_object();
412 json_object_string_add(resp
, "op", BCM_NOTIFY_PEER_STATUS
);
414 json_object_add_peer(resp
, bs
);
416 /* Add status information */
417 json_object_int_add(resp
, "id", bs
->discrs
.my_discr
);
418 json_object_int_add(resp
, "remote-id", bs
->discrs
.my_discr
);
420 switch (bs
->ses_state
) {
422 json_object_string_add(resp
, "state", "up");
424 now
= monotime(NULL
);
425 json_object_int_add(resp
, "uptime", now
- bs
->uptime
.tv_sec
);
427 case PTM_BFD_ADM_DOWN
:
428 json_object_string_add(resp
, "state", "adm-down");
431 json_object_string_add(resp
, "state", "down");
433 now
= monotime(NULL
);
434 json_object_int_add(resp
, "downtime",
435 now
- bs
->downtime
.tv_sec
);
438 json_object_string_add(resp
, "state", "init");
442 json_object_string_add(resp
, "state", "unknown");
446 json_object_int_add(resp
, "diagnostics", bs
->local_diag
);
447 json_object_int_add(resp
, "remote-diagnostics", bs
->remote_diag
);
449 /* Generate JSON response. */
451 MTYPE_BFDD_NOTIFICATION
,
452 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
453 json_object_put(resp
);
458 char *config_notify_config(const char *op
, struct bfd_session
*bs
)
460 struct json_object
*resp
;
463 resp
= json_object_new_object();
467 json_object_string_add(resp
, "op", op
);
469 json_object_add_peer(resp
, bs
);
471 /* On peer deletion we don't need to add any additional information. */
472 if (strcmp(op
, BCM_NOTIFY_CONFIG_DELETE
) == 0)
475 json_object_int_add(resp
, "detect-multiplier", bs
->detect_mult
);
476 json_object_int_add(resp
, "receive-interval",
477 bs
->timers
.required_min_rx
/ 1000);
478 json_object_int_add(resp
, "transmit-interval", bs
->up_min_tx
/ 1000);
479 json_object_int_add(resp
, "echo-interval",
480 bs
->timers
.required_min_echo
/ 1000);
482 json_object_int_add(resp
, "remote-detect-multiplier",
483 bs
->remote_detect_mult
);
484 json_object_int_add(resp
, "remote-receive-interval",
485 bs
->remote_timers
.required_min_rx
/ 1000);
486 json_object_int_add(resp
, "remote-transmit-interval",
487 bs
->remote_timers
.desired_min_tx
/ 1000);
488 json_object_int_add(resp
, "remote-echo-interval",
489 bs
->remote_timers
.required_min_echo
/ 1000);
491 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
492 json_object_boolean_true_add(resp
, "echo-mode");
494 json_object_boolean_false_add(resp
, "echo-mode");
496 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
497 json_object_boolean_true_add(resp
, "shutdown");
499 json_object_boolean_false_add(resp
, "shutdown");
502 /* Generate JSON response. */
504 MTYPE_BFDD_NOTIFICATION
,
505 json_object_to_json_string_ext(resp
, BFDD_JSON_CONV_OPTIONS
));
506 json_object_put(resp
);
511 int config_notify_request(struct bfd_control_socket
*bcs
, const char *jsonstr
,
514 struct json_object
*jo
;
516 jo
= json_tokener_parse(jsonstr
);
520 return parse_config_json(jo
, bh
, bcs
);
523 static int json_object_add_peer(struct json_object
*jo
, struct bfd_session
*bs
)
525 /* Add peer 'key' information. */
526 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_IPV6
))
527 json_object_boolean_true_add(jo
, "ipv6");
529 json_object_boolean_false_add(jo
, "ipv6");
531 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
)) {
532 json_object_boolean_true_add(jo
, "multihop");
533 json_object_string_add(jo
, "peer-address",
534 satostr(&bs
->mhop
.peer
));
535 json_object_string_add(jo
, "local-address",
536 satostr(&bs
->mhop
.local
));
537 if (strlen(bs
->mhop
.vrf_name
) > 0)
538 json_object_string_add(jo
, "vrf-name",
541 json_object_boolean_false_add(jo
, "multihop");
542 json_object_string_add(jo
, "peer-address",
543 satostr(&bs
->shop
.peer
));
544 if (bs
->local_address
.sa_sin
.sin_family
!= AF_UNSPEC
)
545 json_object_string_add(jo
, "local-address",
546 satostr(&bs
->local_address
));
547 if (strlen(bs
->shop
.port_name
) > 0)
548 json_object_string_add(jo
, "local-interface",
553 json_object_string_add(jo
, "label", bs
->pl
->pl_label
);
562 struct peer_label
*pl_find(const char *label
)
564 struct peer_label
*pl
;
566 TAILQ_FOREACH (pl
, &bglobal
.bg_pllist
, pl_entry
) {
567 if (strcmp(pl
->pl_label
, label
) != 0)
576 struct peer_label
*pl_new(const char *label
, struct bfd_session
*bs
)
578 struct peer_label
*pl
;
580 pl
= XCALLOC(MTYPE_BFDD_LABEL
, sizeof(*pl
));
584 if (strlcpy(pl
->pl_label
, label
, sizeof(pl
->pl_label
))
585 > sizeof(pl
->pl_label
))
586 log_warning("%s:%d: label was truncated", __func__
, __LINE__
);
591 TAILQ_INSERT_HEAD(&bglobal
.bg_pllist
, pl
, pl_entry
);
596 void pl_free(struct peer_label
*pl
)
601 /* Remove the pointer back. */
602 pl
->pl_bs
->pl
= NULL
;
604 TAILQ_REMOVE(&bglobal
.bg_pllist
, pl
, pl_entry
);
605 XFREE(MTYPE_BFDD_LABEL
, pl
);