Line data Source code
1 : /* Kernel routing table updates using netlink over GNU/Linux system.
2 : * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include <sys/un.h> /* for sockaddr_un */
24 : #include <net/if.h>
25 :
26 : #include "bfd.h"
27 : #include "buffer.h"
28 : #include "command.h"
29 : #include "if.h"
30 : #include "network.h"
31 : #include "ptm_lib.h"
32 : #include "rib.h"
33 : #include "stream.h"
34 : #include "lib/version.h"
35 : #include "vrf.h"
36 : #include "vty.h"
37 : #include "lib_errors.h"
38 :
39 : #include "zebra/debug.h"
40 : #include "zebra/interface.h"
41 : #include "zebra/zebra_errors.h"
42 : #include "zebra/zebra_ptm.h"
43 : #include "zebra/zebra_ptm_redistribute.h"
44 : #include "zebra/zebra_router.h"
45 : #include "zebra_vrf.h"
46 :
47 : /*
48 : * Choose the BFD implementation that we'll use.
49 : *
50 : * There are two implementations:
51 : * - PTM BFD: which uses an external daemon;
52 : * - bfdd: FRR's own BFD daemon;
53 : */
54 : #if HAVE_BFDD == 0
55 :
56 : #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
57 : #define ZEBRA_PTM_RECONNECT_TIME_MAX 300
58 :
59 : #define PTM_MSG_LEN 4
60 : #define PTM_HEADER_LEN 37
61 :
62 : const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
63 : const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
64 : const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
65 : const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client";
66 : const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD[] = "dereg-bfd-client";
67 :
68 : const char ZEBRA_PTM_CMD_STR[] = "cmd";
69 : const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status";
70 : const char ZEBRA_PTM_PORT_STR[] = "port";
71 : const char ZEBRA_PTM_CBL_STR[] = "cbl status";
72 : const char ZEBRA_PTM_PASS_STR[] = "pass";
73 : const char ZEBRA_PTM_FAIL_STR[] = "fail";
74 : const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
75 : const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
76 : const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
77 : const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
78 : const char ZEBRA_PTM_BFDSRC_STR[] = "local";
79 : const char ZEBRA_PTM_BFDVRF_STR[] = "vrf";
80 : const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
81 : const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
82 : const char ZEBRA_PTM_INVALID_VRF[] = "N/A";
83 :
84 : const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
85 : const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
86 : const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
87 : const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
88 : const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
89 : const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
90 : const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
91 : const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
92 : const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
93 : const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
94 : const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
95 : const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
96 : const char ZEBRA_PTM_BFD_CBIT_FIELD[] = "bfdcbit";
97 :
98 : static ptm_lib_handle_t *ptm_hdl;
99 :
100 : struct zebra_ptm_cb ptm_cb;
101 :
102 : static int zebra_ptm_socket_init(void);
103 : void zebra_ptm_sock_read(struct thread *thread);
104 : static void zebra_ptm_install_commands(void);
105 : static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt);
106 : void zebra_bfd_peer_replay_req(void);
107 : void zebra_ptm_send_status_req(void);
108 : void zebra_ptm_reset_status(int ptm_disable);
109 : static int zebra_ptm_bfd_client_deregister(struct zserv *client);
110 :
111 : const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
112 :
113 : void zebra_ptm_init(void)
114 : {
115 : char buf[64];
116 :
117 : memset(&ptm_cb, 0, sizeof(ptm_cb));
118 :
119 : ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
120 : if (!ptm_cb.out_data) {
121 : zlog_debug("%s: Allocation of send data failed", __func__);
122 : return;
123 : }
124 :
125 : ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
126 : if (!ptm_cb.in_data) {
127 : zlog_debug("%s: Allocation of recv data failed", __func__);
128 : free(ptm_cb.out_data);
129 : return;
130 : }
131 :
132 : ptm_cb.pid = getpid();
133 : zebra_ptm_install_commands();
134 :
135 : snprintf(buf, sizeof(buf), "%s", FRR_PTM_NAME);
136 : ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb,
137 : zebra_ptm_handle_msg_cb);
138 : ptm_cb.wb = buffer_new(0);
139 :
140 : ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
141 :
142 : ptm_cb.ptm_sock = -1;
143 :
144 : hook_register(zserv_client_close, zebra_ptm_bfd_client_deregister);
145 : }
146 :
147 : void zebra_ptm_finish(void)
148 : {
149 : buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock);
150 :
151 : free(ptm_hdl);
152 :
153 : if (ptm_cb.out_data)
154 : free(ptm_cb.out_data);
155 :
156 : if (ptm_cb.in_data)
157 : free(ptm_cb.in_data);
158 :
159 : /* Cancel events. */
160 : THREAD_OFF(ptm_cb.t_read);
161 : THREAD_OFF(ptm_cb.t_write);
162 : THREAD_OFF(ptm_cb.t_timer);
163 :
164 : if (ptm_cb.wb)
165 : buffer_free(ptm_cb.wb);
166 :
167 : if (ptm_cb.ptm_sock >= 0)
168 : close(ptm_cb.ptm_sock);
169 : }
170 :
171 : static void zebra_ptm_flush_messages(struct thread *thread)
172 : {
173 : ptm_cb.t_write = NULL;
174 :
175 : if (ptm_cb.ptm_sock == -1)
176 : return;
177 :
178 : errno = 0;
179 :
180 : switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock)) {
181 : case BUFFER_ERROR:
182 : flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
183 : safe_strerror(errno));
184 : close(ptm_cb.ptm_sock);
185 : ptm_cb.ptm_sock = -1;
186 : zebra_ptm_reset_status(0);
187 : ptm_cb.t_timer = NULL;
188 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
189 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
190 : return;
191 : case BUFFER_PENDING:
192 : ptm_cb.t_write = NULL;
193 : thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
194 : ptm_cb.ptm_sock, &ptm_cb.t_write);
195 : break;
196 : case BUFFER_EMPTY:
197 : break;
198 : }
199 : }
200 :
201 : static int zebra_ptm_send_message(char *data, int size)
202 : {
203 : errno = 0;
204 : switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size)) {
205 : case BUFFER_ERROR:
206 : flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
207 : safe_strerror(errno));
208 : close(ptm_cb.ptm_sock);
209 : ptm_cb.ptm_sock = -1;
210 : zebra_ptm_reset_status(0);
211 : ptm_cb.t_timer = NULL;
212 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
213 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
214 : return -1;
215 : case BUFFER_EMPTY:
216 : THREAD_OFF(ptm_cb.t_write);
217 : break;
218 : case BUFFER_PENDING:
219 : thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
220 : ptm_cb.ptm_sock, &ptm_cb.t_write);
221 : break;
222 : }
223 :
224 : return 0;
225 : }
226 :
227 : void zebra_ptm_connect(struct thread *t)
228 : {
229 : int init = 0;
230 :
231 : if (ptm_cb.ptm_sock == -1) {
232 : zebra_ptm_socket_init();
233 : init = 1;
234 : }
235 :
236 : if (ptm_cb.ptm_sock != -1) {
237 : if (init) {
238 : ptm_cb.t_read = NULL;
239 : thread_add_read(zrouter.master, zebra_ptm_sock_read,
240 : NULL, ptm_cb.ptm_sock, &ptm_cb.t_read);
241 : zebra_bfd_peer_replay_req();
242 : }
243 : zebra_ptm_send_status_req();
244 : ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
245 : } else if (ptm_cb.reconnect_time < ZEBRA_PTM_RECONNECT_TIME_MAX) {
246 : ptm_cb.reconnect_time *= 2;
247 : if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
248 : ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
249 :
250 : ptm_cb.t_timer = NULL;
251 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
252 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
253 : } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) {
254 : ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
255 : }
256 : }
257 :
258 : DEFUN (zebra_ptm_enable,
259 : zebra_ptm_enable_cmd,
260 : "ptm-enable",
261 : "Enable neighbor check with specified topology\n")
262 : {
263 : struct vrf *vrf;
264 : struct interface *ifp;
265 : struct zebra_if *if_data;
266 :
267 : ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
268 :
269 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
270 : FOR_ALL_INTERFACES (vrf, ifp)
271 : if (!ifp->ptm_enable) {
272 : if_data = (struct zebra_if *)ifp->info;
273 : if (if_data
274 : && (if_data->ptm_enable
275 : == ZEBRA_IF_PTM_ENABLE_UNSPEC)) {
276 : ifp->ptm_enable =
277 : ZEBRA_IF_PTM_ENABLE_ON;
278 : }
279 : /* Assign a default unknown status */
280 : ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
281 : }
282 :
283 : zebra_ptm_connect(NULL);
284 :
285 : return CMD_SUCCESS;
286 : }
287 :
288 : DEFUN (no_zebra_ptm_enable,
289 : no_zebra_ptm_enable_cmd,
290 : "no ptm-enable",
291 : NO_STR
292 : "Enable neighbor check with specified topology\n")
293 : {
294 : ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
295 : zebra_ptm_reset_status(1);
296 : return CMD_SUCCESS;
297 : }
298 :
299 : DEFUN (zebra_ptm_enable_if,
300 : zebra_ptm_enable_if_cmd,
301 : "ptm-enable",
302 : "Enable neighbor check with specified topology\n")
303 : {
304 : VTY_DECLVAR_CONTEXT(interface, ifp);
305 : struct zebra_if *if_data;
306 : int old_ptm_enable;
307 : int send_linkdown = 0;
308 :
309 : if_data = ifp->info;
310 : if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
311 :
312 : if (ifp->ifindex == IFINDEX_INTERNAL) {
313 : return CMD_SUCCESS;
314 : }
315 :
316 : old_ptm_enable = ifp->ptm_enable;
317 : ifp->ptm_enable = ptm_cb.ptm_enable;
318 :
319 : if (if_is_no_ptm_operative(ifp))
320 : send_linkdown = 1;
321 :
322 : if (!old_ptm_enable && ptm_cb.ptm_enable) {
323 : if (!if_is_operative(ifp) && send_linkdown) {
324 : if (IS_ZEBRA_DEBUG_EVENT)
325 : zlog_debug("%s: Bringing down interface %s",
326 : __func__, ifp->name);
327 : if_down(ifp);
328 : }
329 : }
330 :
331 : return CMD_SUCCESS;
332 : }
333 :
334 : DEFUN (no_zebra_ptm_enable_if,
335 : no_zebra_ptm_enable_if_cmd,
336 : "no ptm-enable",
337 : NO_STR
338 : "Enable neighbor check with specified topology\n")
339 : {
340 : VTY_DECLVAR_CONTEXT(interface, ifp);
341 : int send_linkup = 0;
342 : struct zebra_if *if_data;
343 :
344 : if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) {
345 : if (!if_is_operative(ifp))
346 : send_linkup = 1;
347 :
348 : ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
349 : if (if_is_no_ptm_operative(ifp) && send_linkup) {
350 : if (IS_ZEBRA_DEBUG_EVENT)
351 : zlog_debug("%s: Bringing up interface %s",
352 : __func__, ifp->name);
353 : if_up(ifp, true);
354 : }
355 : }
356 :
357 : if_data = ifp->info;
358 : if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
359 :
360 : return CMD_SUCCESS;
361 : }
362 :
363 :
364 : void zebra_ptm_write(struct vty *vty)
365 : {
366 : if (ptm_cb.ptm_enable)
367 : vty_out(vty, "ptm-enable\n");
368 :
369 : return;
370 : }
371 :
372 : static int zebra_ptm_socket_init(void)
373 : {
374 : int ret;
375 : int sock;
376 : struct sockaddr_un addr;
377 :
378 : ptm_cb.ptm_sock = -1;
379 :
380 : sock = socket(PF_UNIX, SOCK_STREAM, 0);
381 : if (sock < 0)
382 : return -1;
383 : if (set_nonblocking(sock) < 0) {
384 : if (IS_ZEBRA_DEBUG_EVENT)
385 : zlog_debug("%s: Unable to set socket non blocking[%s]",
386 : __func__, safe_strerror(errno));
387 : close(sock);
388 : return -1;
389 : }
390 :
391 : /* Make server socket. */
392 : memset(&addr, 0, sizeof(addr));
393 : addr.sun_family = AF_UNIX;
394 : memcpy(&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
395 : sizeof(ZEBRA_PTM_SOCK_NAME));
396 :
397 : ret = connect(sock, (struct sockaddr *)&addr,
398 : sizeof(addr.sun_family) + sizeof(ZEBRA_PTM_SOCK_NAME)
399 : - 1);
400 : if (ret < 0) {
401 : if (IS_ZEBRA_DEBUG_EVENT)
402 : zlog_debug("%s: Unable to connect to socket %s [%s]",
403 : __func__, ZEBRA_PTM_SOCK_NAME,
404 : safe_strerror(errno));
405 : close(sock);
406 : return -1;
407 : }
408 : ptm_cb.ptm_sock = sock;
409 : return sock;
410 : }
411 :
412 : static void zebra_ptm_install_commands(void)
413 : {
414 : install_element(CONFIG_NODE, &zebra_ptm_enable_cmd);
415 : install_element(CONFIG_NODE, &no_zebra_ptm_enable_cmd);
416 : install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd);
417 : install_element(INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd);
418 : }
419 :
420 : /* BFD session goes down, send message to the protocols. */
421 : static void if_bfd_session_update(struct interface *ifp, struct prefix *dp,
422 : struct prefix *sp, int status,
423 : vrf_id_t vrf_id)
424 : {
425 : if (IS_ZEBRA_DEBUG_EVENT) {
426 : char buf[2][INET6_ADDRSTRLEN];
427 :
428 : if (ifp) {
429 : zlog_debug(
430 : "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s %s event",
431 : inet_ntop(dp->family, &dp->u.prefix, buf[0],
432 : INET6_ADDRSTRLEN),
433 : dp->prefixlen, ifp->name,
434 : bfd_get_status_str(status));
435 : } else {
436 : struct vrf *vrf = vrf_lookup_by_id(vrf_id);
437 :
438 : zlog_debug(
439 : "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d with src %s/%d and vrf %s(%u) %s event",
440 : inet_ntop(dp->family, &dp->u.prefix, buf[0],
441 : INET6_ADDRSTRLEN),
442 : dp->prefixlen,
443 : inet_ntop(sp->family, &sp->u.prefix, buf[1],
444 : INET6_ADDRSTRLEN),
445 : sp->prefixlen, VRF_LOGNAME(vrf), vrf_id,
446 : bfd_get_status_str(status));
447 : }
448 : }
449 :
450 : zebra_interface_bfd_update(ifp, dp, sp, status, vrf_id);
451 : }
452 :
453 : static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
454 : struct interface *ifp)
455 : {
456 : char bfdst_str[32];
457 : char dest_str[64];
458 : char src_str[64];
459 : char vrf_str[64];
460 : struct prefix dest_prefix;
461 : struct prefix src_prefix;
462 : vrf_id_t vrf_id;
463 :
464 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
465 :
466 : if (bfdst_str[0] == '\0') {
467 : return -1;
468 : }
469 :
470 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
471 :
472 : if (dest_str[0] == '\0') {
473 : zlog_debug("%s: Key %s not found in PTM msg", __func__,
474 : ZEBRA_PTM_BFDDEST_STR);
475 : return -1;
476 : }
477 :
478 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
479 :
480 : if (src_str[0] == '\0') {
481 : zlog_debug("%s: Key %s not found in PTM msg", __func__,
482 : ZEBRA_PTM_BFDSRC_STR);
483 : return -1;
484 : }
485 :
486 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str);
487 :
488 : if (vrf_str[0] == '\0') {
489 : zlog_debug("%s: Key %s not found in PTM msg", __func__,
490 : ZEBRA_PTM_BFDVRF_STR);
491 : return -1;
492 : }
493 :
494 : if (IS_ZEBRA_DEBUG_EVENT)
495 : zlog_debug(
496 : "%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]",
497 : __func__, ifp ? ifp->name : "N/A", bfdst_str, vrf_str,
498 : dest_str, src_str);
499 :
500 : if (str2prefix(dest_str, &dest_prefix) == 0) {
501 : flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
502 : "%s: Peer addr %s not found", __func__, dest_str);
503 : return -1;
504 : }
505 :
506 : memset(&src_prefix, 0, sizeof(src_prefix));
507 : if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
508 : if (str2prefix(src_str, &src_prefix) == 0) {
509 : flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
510 : "%s: Local addr %s not found", __func__,
511 : src_str);
512 : return -1;
513 : }
514 : }
515 :
516 : if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
517 : vrf_id = ifp->vrf->vrf_id;
518 : } else {
519 : struct vrf *pVrf;
520 :
521 : pVrf = vrf_lookup_by_name(vrf_str);
522 : if (pVrf)
523 : vrf_id = pVrf->vrf_id;
524 : else
525 : vrf_id = VRF_DEFAULT;
526 : }
527 :
528 : if (!strcmp(bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
529 : if_bfd_session_update(ifp, &dest_prefix, &src_prefix,
530 : BFD_STATUS_DOWN, vrf_id);
531 : } else {
532 : if_bfd_session_update(ifp, &dest_prefix, &src_prefix,
533 : BFD_STATUS_UP, vrf_id);
534 : }
535 :
536 : return 0;
537 : }
538 :
539 : static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt,
540 : struct interface *ifp, char *cbl_str)
541 : {
542 : int send_linkup = 0;
543 :
544 : if (IS_ZEBRA_DEBUG_EVENT)
545 : zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
546 : ifp->name, cbl_str);
547 :
548 : if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR)
549 : && (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) {
550 :
551 : if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)
552 : send_linkup = 1;
553 : ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
554 : if (ifp->ptm_enable && if_is_no_ptm_operative(ifp)
555 : && send_linkup)
556 : if_up(ifp, true);
557 : } else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR)
558 : && (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) {
559 : ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN;
560 : if (ifp->ptm_enable && if_is_no_ptm_operative(ifp))
561 : if_down(ifp);
562 : }
563 :
564 : return 0;
565 : }
566 :
567 : /*
568 : * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle
569 : * all the command responses and notifications received from PTM.
570 : *
571 : * Command responses: Upon establishing connection with PTM, Zebra requests
572 : * status of all interfaces using 'get-status' command if global ptm-enable
573 : * knob is enabled. As a response to the get-status command PTM sends status
574 : * of all the interfaces as command responses. All other type of command
575 : * responses with cmd_status key word are dropped. The sole purpose of
576 : * registering this function as callback for the command responses is to
577 : * handle the responses to get-status command.
578 : *
579 : * Notifications: Cable status and BFD session status changes are sent as
580 : * notifications by PTM. So, this function is also the callback function for
581 : * processing all the notifications from the PTM.
582 : *
583 : */
584 : static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
585 : {
586 : struct interface *ifp = NULL;
587 : char port_str[128];
588 : char cbl_str[32];
589 : char cmd_status_str[32];
590 :
591 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR,
592 : cmd_status_str);
593 :
594 : /* Drop command response messages */
595 : if (cmd_status_str[0] != '\0') {
596 : return 0;
597 : }
598 :
599 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
600 :
601 : if (port_str[0] == '\0') {
602 : zlog_debug("%s: Key %s not found in PTM msg", __func__,
603 : ZEBRA_PTM_PORT_STR);
604 : return -1;
605 : }
606 :
607 : if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
608 : struct vrf *vrf;
609 : int count = 0;
610 :
611 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
612 : ifp = if_lookup_by_name_vrf(port_str, vrf);
613 : if (ifp) {
614 : count++;
615 : if (!vrf_is_backend_netns())
616 : break;
617 : }
618 : }
619 :
620 : if (!ifp) {
621 : flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
622 : "%s: %s not found in interface list",
623 : __func__, port_str);
624 : return -1;
625 : }
626 : if (count > 1) {
627 : flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
628 : "%s: multiple interface with name %s",
629 : __func__, port_str);
630 : return -1;
631 : }
632 : }
633 :
634 : ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str);
635 :
636 : if (cbl_str[0] == '\0') {
637 : return zebra_ptm_handle_bfd_msg(arg, in_ctxt, ifp);
638 : } else {
639 : if (ifp) {
640 : return zebra_ptm_handle_cbl_msg(arg, in_ctxt, ifp,
641 : cbl_str);
642 : } else {
643 : return -1;
644 : }
645 : }
646 : }
647 :
648 : void zebra_ptm_sock_read(struct thread *thread)
649 : {
650 : int sock;
651 : int rc;
652 :
653 : errno = 0;
654 : sock = THREAD_FD(thread);
655 :
656 : if (sock == -1)
657 : return;
658 :
659 : /* PTM communicates in CSV format */
660 : do {
661 : rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
662 : ZEBRA_PTM_MAX_SOCKBUF, NULL);
663 : } while (rc > 0);
664 :
665 : if (((rc == 0) && !errno)
666 : || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
667 : flog_err_sys(EC_LIB_SOCKET,
668 : "%s routing socket error: %s(%d) bytes %d",
669 : __func__, safe_strerror(errno), errno, rc);
670 :
671 : close(ptm_cb.ptm_sock);
672 : ptm_cb.ptm_sock = -1;
673 : zebra_ptm_reset_status(0);
674 : ptm_cb.t_timer = NULL;
675 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
676 : ptm_cb.reconnect_time,
677 : &ptm_cb.t_timer);
678 : return;
679 : }
680 :
681 : ptm_cb.t_read = NULL;
682 : thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL,
683 : ptm_cb.ptm_sock, &ptm_cb.t_read);
684 : }
685 :
686 : /* BFD peer/dst register/update */
687 : void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
688 : {
689 : struct stream *s;
690 : struct prefix src_p;
691 : struct prefix dst_p;
692 : uint8_t multi_hop;
693 : uint8_t multi_hop_cnt;
694 : uint8_t detect_mul;
695 : unsigned int min_rx_timer;
696 : unsigned int min_tx_timer;
697 : char if_name[INTERFACE_NAMSIZ];
698 : uint8_t len;
699 : void *out_ctxt;
700 : char buf[INET6_ADDRSTRLEN];
701 : char tmp_buf[64];
702 : int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
703 : unsigned int pid;
704 : uint8_t cbit_set;
705 :
706 : if (hdr->command == ZEBRA_BFD_DEST_UPDATE)
707 : client->bfd_peer_upd8_cnt++;
708 : else
709 : client->bfd_peer_add_cnt++;
710 :
711 : if (IS_ZEBRA_DEBUG_EVENT)
712 : zlog_debug("bfd_dst_register msg from client %s: length=%d",
713 : zebra_route_string(client->proto), hdr->length);
714 :
715 : if (ptm_cb.ptm_sock == -1) {
716 : ptm_cb.t_timer = NULL;
717 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
718 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
719 : return;
720 : }
721 :
722 : ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
723 : snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_START_CMD);
724 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
725 : snprintf(tmp_buf, sizeof(tmp_buf), "%s",
726 : zebra_route_string(client->proto));
727 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
728 : tmp_buf);
729 :
730 : s = msg;
731 :
732 : STREAM_GETL(s, pid);
733 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
734 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
735 : tmp_buf);
736 :
737 : STREAM_GETW(s, dst_p.family);
738 :
739 : if (dst_p.family == AF_INET)
740 : dst_p.prefixlen = IPV4_MAX_BYTELEN;
741 : else
742 : dst_p.prefixlen = IPV6_MAX_BYTELEN;
743 :
744 : STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
745 : if (dst_p.family == AF_INET) {
746 : inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
747 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
748 : ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
749 : } else {
750 : inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
751 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
752 : ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
753 : }
754 :
755 : STREAM_GETL(s, min_rx_timer);
756 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_rx_timer);
757 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
758 : tmp_buf);
759 : STREAM_GETL(s, min_tx_timer);
760 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_tx_timer);
761 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
762 : tmp_buf);
763 : STREAM_GETC(s, detect_mul);
764 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", detect_mul);
765 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
766 : tmp_buf);
767 :
768 : STREAM_GETC(s, multi_hop);
769 : if (multi_hop) {
770 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
771 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
772 : ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
773 : STREAM_GETW(s, src_p.family);
774 :
775 : if (src_p.family == AF_INET)
776 : src_p.prefixlen = IPV4_MAX_BYTELEN;
777 : else
778 : src_p.prefixlen = IPV6_MAX_BYTELEN;
779 :
780 : STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
781 : if (src_p.family == AF_INET) {
782 : inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
783 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
784 : ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
785 : } else {
786 : inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
787 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
788 : ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
789 : }
790 :
791 : STREAM_GETC(s, multi_hop_cnt);
792 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", multi_hop_cnt);
793 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
794 : ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD, tmp_buf);
795 :
796 : if (zvrf_id(zvrf) != VRF_DEFAULT)
797 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
798 : ZEBRA_PTM_BFD_VRF_NAME_FIELD,
799 : zvrf_name(zvrf));
800 : } else {
801 : if (dst_p.family == AF_INET6) {
802 : STREAM_GETW(s, src_p.family);
803 :
804 : if (src_p.family == AF_INET)
805 : src_p.prefixlen = IPV4_MAX_BYTELEN;
806 : else
807 : src_p.prefixlen = IPV6_MAX_BYTELEN;
808 :
809 : STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
810 : if (src_p.family == AF_INET) {
811 : inet_ntop(AF_INET, &src_p.u.prefix4, buf,
812 : sizeof(buf));
813 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
814 : ZEBRA_PTM_BFD_SRC_IP_FIELD,
815 : buf);
816 : } else {
817 : inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
818 : sizeof(buf));
819 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
820 : ZEBRA_PTM_BFD_SRC_IP_FIELD,
821 : buf);
822 : }
823 : }
824 : STREAM_GETC(s, len);
825 : STREAM_GET(if_name, s, len);
826 : if_name[len] = '\0';
827 :
828 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
829 : ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
830 : }
831 : STREAM_GETC(s, cbit_set);
832 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", cbit_set);
833 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
834 : ZEBRA_PTM_BFD_CBIT_FIELD, tmp_buf);
835 :
836 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
837 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,
838 : tmp_buf);
839 :
840 : ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
841 :
842 : if (IS_ZEBRA_DEBUG_SEND)
843 : zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
844 : ptm_cb.out_data);
845 : zebra_ptm_send_message(ptm_cb.out_data, data_len);
846 :
847 : return;
848 :
849 : stream_failure:
850 : ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
851 : }
852 :
853 : /* BFD peer/dst deregister */
854 : void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
855 : {
856 : struct stream *s;
857 : struct prefix src_p;
858 : struct prefix dst_p;
859 : uint8_t multi_hop;
860 : char if_name[INTERFACE_NAMSIZ];
861 : uint8_t len;
862 : char buf[INET6_ADDRSTRLEN];
863 : char tmp_buf[64];
864 : int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
865 : void *out_ctxt;
866 : unsigned int pid;
867 :
868 : client->bfd_peer_del_cnt++;
869 :
870 : if (IS_ZEBRA_DEBUG_EVENT)
871 : zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
872 : zebra_route_string(client->proto), hdr->length);
873 :
874 : if (ptm_cb.ptm_sock == -1) {
875 : ptm_cb.t_timer = NULL;
876 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
877 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
878 : return;
879 : }
880 :
881 : ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
882 :
883 : snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_STOP_CMD);
884 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
885 :
886 : snprintf(tmp_buf, sizeof(tmp_buf), "%s",
887 : zebra_route_string(client->proto));
888 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
889 : tmp_buf);
890 :
891 : s = msg;
892 :
893 : STREAM_GETL(s, pid);
894 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
895 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
896 : tmp_buf);
897 :
898 : STREAM_GETW(s, dst_p.family);
899 :
900 : if (dst_p.family == AF_INET)
901 : dst_p.prefixlen = IPV4_MAX_BYTELEN;
902 : else
903 : dst_p.prefixlen = IPV6_MAX_BYTELEN;
904 :
905 : STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
906 : if (dst_p.family == AF_INET)
907 : inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
908 : else
909 : inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
910 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
911 :
912 :
913 : STREAM_GETC(s, multi_hop);
914 : if (multi_hop) {
915 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
916 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
917 : ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
918 :
919 : STREAM_GETW(s, src_p.family);
920 :
921 : if (src_p.family == AF_INET)
922 : src_p.prefixlen = IPV4_MAX_BYTELEN;
923 : else
924 : src_p.prefixlen = IPV6_MAX_BYTELEN;
925 :
926 : STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
927 : if (src_p.family == AF_INET)
928 : inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
929 : else
930 : inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
931 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
932 : ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
933 :
934 : if (zvrf_id(zvrf) != VRF_DEFAULT)
935 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
936 : ZEBRA_PTM_BFD_VRF_NAME_FIELD,
937 : zvrf_name(zvrf));
938 : } else {
939 : if (dst_p.family == AF_INET6) {
940 : STREAM_GETW(s, src_p.family);
941 :
942 : if (src_p.family == AF_INET)
943 : src_p.prefixlen = IPV4_MAX_BYTELEN;
944 : else
945 : src_p.prefixlen = IPV6_MAX_BYTELEN;
946 :
947 : STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
948 : if (src_p.family == AF_INET) {
949 : inet_ntop(AF_INET, &src_p.u.prefix4, buf,
950 : sizeof(buf));
951 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
952 : ZEBRA_PTM_BFD_SRC_IP_FIELD,
953 : buf);
954 : } else {
955 : inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
956 : sizeof(buf));
957 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
958 : ZEBRA_PTM_BFD_SRC_IP_FIELD,
959 : buf);
960 : }
961 : }
962 :
963 : STREAM_GETC(s, len);
964 : STREAM_GET(if_name, s, len);
965 : if_name[len] = '\0';
966 :
967 : ptm_lib_append_msg(ptm_hdl, out_ctxt,
968 : ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
969 : }
970 :
971 : ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
972 : if (IS_ZEBRA_DEBUG_SEND)
973 : zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
974 : ptm_cb.out_data);
975 :
976 : zebra_ptm_send_message(ptm_cb.out_data, data_len);
977 :
978 : return;
979 :
980 : stream_failure:
981 : ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
982 : }
983 :
984 : /* BFD client register */
985 : void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
986 : {
987 : struct stream *s;
988 : unsigned int pid;
989 : void *out_ctxt = NULL;
990 : char tmp_buf[64];
991 : int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
992 :
993 : client->bfd_client_reg_cnt++;
994 :
995 : if (IS_ZEBRA_DEBUG_EVENT)
996 : zlog_debug("bfd_client_register msg from client %s: length=%d",
997 : zebra_route_string(client->proto), hdr->length);
998 :
999 : s = msg;
1000 : STREAM_GETL(s, pid);
1001 :
1002 : if (ptm_cb.ptm_sock == -1) {
1003 : ptm_cb.t_timer = NULL;
1004 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
1005 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
1006 : return;
1007 : }
1008 :
1009 : ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
1010 :
1011 : snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD);
1012 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
1013 :
1014 : snprintf(tmp_buf, sizeof(tmp_buf), "%s",
1015 : zebra_route_string(client->proto));
1016 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1017 : tmp_buf);
1018 :
1019 : snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
1020 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
1021 : tmp_buf);
1022 :
1023 : ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1024 :
1025 : if (IS_ZEBRA_DEBUG_SEND)
1026 : zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1027 : ptm_cb.out_data);
1028 : zebra_ptm_send_message(ptm_cb.out_data, data_len);
1029 :
1030 : SET_FLAG(ptm_cb.client_flags[client->proto],
1031 : ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1032 :
1033 : return;
1034 :
1035 : stream_failure:
1036 : /*
1037 : * IF we ever add more STREAM_GETXXX functions after the out_ctxt
1038 : * is allocated then we need to add this code back in
1039 : *
1040 : * if (out_ctxt)
1041 : * ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
1042 : */
1043 : return;
1044 : }
1045 :
1046 : /* BFD client deregister */
1047 : int zebra_ptm_bfd_client_deregister(struct zserv *client)
1048 : {
1049 : uint8_t proto = client->proto;
1050 : void *out_ctxt;
1051 : char tmp_buf[64];
1052 : int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1053 :
1054 : if (!IS_BFD_ENABLED_PROTOCOL(proto))
1055 : return 0;
1056 :
1057 : if (IS_ZEBRA_DEBUG_EVENT)
1058 : zlog_debug("bfd_client_deregister msg for client %s",
1059 : zebra_route_string(proto));
1060 :
1061 : if (ptm_cb.ptm_sock == -1) {
1062 : ptm_cb.t_timer = NULL;
1063 : thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
1064 : ptm_cb.reconnect_time, &ptm_cb.t_timer);
1065 : return 0;
1066 : }
1067 :
1068 : ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
1069 :
1070 : snprintf(tmp_buf, sizeof(tmp_buf), "%s",
1071 : ZEBRA_PTM_BFD_CLIENT_DEREG_CMD);
1072 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
1073 :
1074 : snprintf(tmp_buf, sizeof(tmp_buf), "%s", zebra_route_string(proto));
1075 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1076 : tmp_buf);
1077 :
1078 : ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1079 :
1080 : if (IS_ZEBRA_DEBUG_SEND)
1081 : zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1082 : ptm_cb.out_data);
1083 :
1084 : zebra_ptm_send_message(ptm_cb.out_data, data_len);
1085 : UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1086 :
1087 : return 0;
1088 : }
1089 :
1090 : int zebra_ptm_get_enable_state(void)
1091 : {
1092 : return ptm_cb.ptm_enable;
1093 : }
1094 :
1095 : /*
1096 : * zebra_ptm_get_status_str - Convert status to a display string.
1097 : */
1098 : static const char *zebra_ptm_get_status_str(int status)
1099 : {
1100 : switch (status) {
1101 : case ZEBRA_PTM_STATUS_DOWN:
1102 : return "fail";
1103 : case ZEBRA_PTM_STATUS_UP:
1104 : return "pass";
1105 : case ZEBRA_PTM_STATUS_UNKNOWN:
1106 : default:
1107 : return "n/a";
1108 : }
1109 : }
1110 :
1111 : void zebra_ptm_show_status(struct vty *vty, json_object *json,
1112 : struct interface *ifp)
1113 : {
1114 : const char *status;
1115 :
1116 : if (ifp->ptm_enable)
1117 : status = zebra_ptm_get_status_str(ifp->ptm_status);
1118 : else
1119 : status = "disabled";
1120 :
1121 : if (json)
1122 : json_object_string_add(json, "ptmStatus", status);
1123 : else
1124 : vty_out(vty, " PTM status: %s\n", status);
1125 : }
1126 :
1127 : void zebra_ptm_send_status_req(void)
1128 : {
1129 : void *out_ctxt;
1130 : int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1131 :
1132 : if (ptm_cb.ptm_enable) {
1133 : ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL,
1134 : &out_ctxt);
1135 : ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
1136 : ZEBRA_PTM_GET_STATUS_CMD);
1137 : ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
1138 :
1139 : zebra_ptm_send_message(ptm_cb.out_data, len);
1140 : }
1141 : }
1142 :
1143 : void zebra_ptm_reset_status(int ptm_disable)
1144 : {
1145 : struct vrf *vrf;
1146 : struct interface *ifp;
1147 : int send_linkup;
1148 :
1149 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
1150 : FOR_ALL_INTERFACES (vrf, ifp) {
1151 : send_linkup = 0;
1152 : if (ifp->ptm_enable) {
1153 : if (!if_is_operative(ifp))
1154 : send_linkup = 1;
1155 :
1156 : if (ptm_disable)
1157 : ifp->ptm_enable =
1158 : ZEBRA_IF_PTM_ENABLE_OFF;
1159 : ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
1160 :
1161 : if (if_is_operative(ifp) && send_linkup) {
1162 : if (IS_ZEBRA_DEBUG_EVENT)
1163 : zlog_debug(
1164 : "%s: Bringing up interface %s",
1165 : __func__, ifp->name);
1166 : if_up(ifp, true);
1167 : }
1168 : }
1169 : }
1170 : }
1171 :
1172 : void zebra_ptm_if_init(struct zebra_if *zebra_ifp)
1173 : {
1174 : zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
1175 : }
1176 :
1177 : void zebra_ptm_if_set_ptm_state(struct interface *ifp,
1178 : struct zebra_if *zebra_ifp)
1179 : {
1180 : if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
1181 : ifp->ptm_enable = zebra_ifp->ptm_enable;
1182 : }
1183 :
1184 : void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
1185 : {
1186 : if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
1187 : vty_out(vty, " no ptm-enable\n");
1188 : }
1189 :
1190 : #else /* HAVE_BFDD */
1191 :
1192 : /*
1193 : * Data structures.
1194 : */
1195 : struct ptm_process {
1196 : struct zserv *pp_zs;
1197 : pid_t pp_pid;
1198 :
1199 : TAILQ_ENTRY(ptm_process) pp_entry;
1200 : };
1201 : TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
1202 :
1203 12 : DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
1204 : "PTM BFD process registration table.");
1205 :
1206 : /*
1207 : * Prototypes.
1208 : */
1209 : static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
1210 : static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
1211 : static void pp_free(struct ptm_process *pp);
1212 : static void pp_free_all(void);
1213 :
1214 : static void zebra_ptm_send_bfdd(struct stream *msg);
1215 : static void zebra_ptm_send_clients(struct stream *msg);
1216 : static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
1217 : static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
1218 : struct stream *msg, uint32_t command);
1219 :
1220 :
1221 : /*
1222 : * Process PID registration.
1223 : */
1224 0 : static struct ptm_process *pp_new(pid_t pid, struct zserv *zs)
1225 : {
1226 0 : struct ptm_process *pp;
1227 :
1228 : #ifdef PTM_DEBUG
1229 : /* Sanity check: more than one client can't have the same PID. */
1230 : TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1231 : if (pp->pp_pid == pid && pp->pp_zs != zs)
1232 : zlog_err("%s:%d pid and client pointer doesn't match",
1233 : __FILE__, __LINE__);
1234 : }
1235 : #endif /* PTM_DEBUG */
1236 :
1237 : /* Lookup for duplicates. */
1238 0 : pp = pp_lookup_byzs(zs);
1239 0 : if (pp != NULL)
1240 : return pp;
1241 :
1242 : /* Allocate and register new process. */
1243 0 : pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
1244 :
1245 0 : pp->pp_pid = pid;
1246 0 : pp->pp_zs = zs;
1247 0 : TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
1248 :
1249 0 : return pp;
1250 : }
1251 :
1252 4 : static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
1253 : {
1254 4 : struct ptm_process *pp;
1255 :
1256 4 : TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1257 0 : if (pp->pp_zs != zs)
1258 0 : continue;
1259 :
1260 : break;
1261 : }
1262 :
1263 0 : return pp;
1264 : }
1265 :
1266 0 : static void pp_free(struct ptm_process *pp)
1267 : {
1268 0 : if (pp == NULL)
1269 : return;
1270 :
1271 0 : TAILQ_REMOVE(&ppqueue, pp, pp_entry);
1272 0 : XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
1273 : }
1274 :
1275 4 : static void pp_free_all(void)
1276 : {
1277 4 : struct ptm_process *pp;
1278 :
1279 4 : while (!TAILQ_EMPTY(&ppqueue)) {
1280 0 : pp = TAILQ_FIRST(&ppqueue);
1281 0 : pp_free(pp);
1282 : }
1283 4 : }
1284 :
1285 :
1286 : /*
1287 : * Use the FRR's internal daemon implementation.
1288 : */
1289 0 : static void zebra_ptm_send_bfdd(struct stream *msg)
1290 : {
1291 0 : struct listnode *node;
1292 0 : struct zserv *client;
1293 0 : struct stream *msgc;
1294 :
1295 : /* Create copy for replication. */
1296 0 : msgc = stream_dup(msg);
1297 :
1298 : /* Send message to all running BFDd daemons. */
1299 0 : for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
1300 0 : if (client->proto != ZEBRA_ROUTE_BFD)
1301 0 : continue;
1302 :
1303 0 : zserv_send_message(client, msg);
1304 :
1305 : /* Allocate more messages. */
1306 0 : msg = stream_dup(msgc);
1307 : }
1308 :
1309 0 : stream_free(msgc);
1310 0 : stream_free(msg);
1311 0 : }
1312 :
1313 0 : static void zebra_ptm_send_clients(struct stream *msg)
1314 : {
1315 0 : struct listnode *node;
1316 0 : struct zserv *client;
1317 0 : struct stream *msgc;
1318 :
1319 : /* Create copy for replication. */
1320 0 : msgc = stream_dup(msg);
1321 :
1322 : /* Send message to all running client daemons. */
1323 0 : for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
1324 0 : if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
1325 0 : continue;
1326 :
1327 0 : zserv_send_message(client, msg);
1328 :
1329 : /* Allocate more messages. */
1330 0 : msg = stream_dup(msgc);
1331 : }
1332 :
1333 0 : stream_free(msgc);
1334 0 : stream_free(msg);
1335 0 : }
1336 :
1337 8 : static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
1338 : {
1339 8 : struct stream *msg;
1340 8 : struct ptm_process *pp;
1341 :
1342 8 : if (!IS_BFD_ENABLED_PROTOCOL(zs->proto))
1343 : return 0;
1344 :
1345 : /* Find daemon pid by zebra connection pointer. */
1346 4 : pp = pp_lookup_byzs(zs);
1347 4 : if (pp == NULL) {
1348 4 : zlog_err("%s:%d failed to find process pid registration",
1349 : __FILE__, __LINE__);
1350 4 : return -1;
1351 : }
1352 :
1353 : /* Generate, send message and free() daemon related data. */
1354 0 : msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
1355 0 : if (msg == NULL) {
1356 0 : zlog_debug("%s: not enough memory", __func__);
1357 0 : return 0;
1358 : }
1359 :
1360 : /*
1361 : * The message type will be ZEBRA_BFD_DEST_REPLAY so we can use only
1362 : * one callback at the `bfdd` side, however the real command
1363 : * number will be included right after the zebra header.
1364 : */
1365 0 : zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
1366 0 : stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
1367 :
1368 : /* Put process PID. */
1369 0 : stream_putl(msg, pp->pp_pid);
1370 :
1371 : /* Update the data pointers. */
1372 0 : stream_putw_at(msg, 0, stream_get_endp(msg));
1373 :
1374 0 : zebra_ptm_send_bfdd(msg);
1375 :
1376 0 : pp_free(pp);
1377 :
1378 0 : return 0;
1379 : }
1380 :
1381 4 : void zebra_ptm_init(void)
1382 : {
1383 : /* Initialize the ptm process information list. */
1384 4 : TAILQ_INIT(&ppqueue);
1385 :
1386 : /*
1387 : * Send deregistration messages to BFD daemon when some other
1388 : * daemon closes. This will help avoid sending daemons
1389 : * unnecessary notification messages.
1390 : */
1391 4 : hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1392 4 : }
1393 :
1394 4 : void zebra_ptm_finish(void)
1395 : {
1396 : /* Remove the client disconnect hook and free all memory. */
1397 4 : hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1398 4 : pp_free_all();
1399 4 : }
1400 :
1401 :
1402 : /*
1403 : * Message handling.
1404 : */
1405 0 : static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
1406 : struct stream *msg, uint32_t command)
1407 : {
1408 0 : struct stream *msgc;
1409 0 : char buf[ZEBRA_MAX_PACKET_SIZ];
1410 0 : pid_t ppid;
1411 :
1412 : /* Create BFD header */
1413 0 : msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1414 0 : zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
1415 0 : stream_putl(msgc, command);
1416 :
1417 0 : if (STREAM_READABLE(msg) > STREAM_WRITEABLE(msgc)) {
1418 0 : zlog_warn("Cannot fit extended BFD header plus original message contents into ZAPI packet; dropping message");
1419 0 : goto stream_failure;
1420 : }
1421 :
1422 : /* Copy original message, excluding header, into new message */
1423 0 : stream_get_from(buf, msg, stream_get_getp(msg), STREAM_READABLE(msg));
1424 0 : stream_put(msgc, buf, STREAM_READABLE(msg));
1425 :
1426 : /* Update length field */
1427 0 : stream_putw_at(msgc, 0, STREAM_READABLE(msgc));
1428 :
1429 0 : zebra_ptm_send_bfdd(msgc);
1430 0 : msgc = NULL;
1431 :
1432 : /* Registrate process PID for shutdown hook. */
1433 0 : STREAM_GETL(msg, ppid);
1434 0 : pp_new(ppid, zs);
1435 :
1436 0 : return;
1437 :
1438 0 : stream_failure:
1439 0 : if (msgc)
1440 0 : stream_free(msgc);
1441 0 : zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
1442 : }
1443 :
1444 0 : void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
1445 : {
1446 0 : if (IS_ZEBRA_DEBUG_EVENT)
1447 0 : zlog_debug("bfd_dst_register msg from client %s: length=%d",
1448 : zebra_route_string(client->proto), hdr->length);
1449 :
1450 0 : _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
1451 0 : }
1452 :
1453 0 : void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
1454 : {
1455 0 : if (IS_ZEBRA_DEBUG_EVENT)
1456 0 : zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
1457 : zebra_route_string(client->proto), hdr->length);
1458 :
1459 0 : _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
1460 0 : }
1461 :
1462 0 : void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
1463 : {
1464 0 : if (IS_ZEBRA_DEBUG_EVENT)
1465 0 : zlog_debug("bfd_client_register msg from client %s: length=%d",
1466 : zebra_route_string(client->proto), hdr->length);
1467 :
1468 0 : _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
1469 0 : }
1470 :
1471 0 : void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
1472 : {
1473 0 : struct stream *msgc;
1474 0 : size_t zmsglen, zhdrlen;
1475 0 : uint32_t cmd;
1476 :
1477 : /*
1478 : * NOTE:
1479 : * Replay messages with HAVE_BFDD are meant to be replayed to
1480 : * the client daemons. These messages are composed and
1481 : * originated from the `bfdd` daemon.
1482 : */
1483 0 : if (IS_ZEBRA_DEBUG_EVENT)
1484 0 : zlog_debug("bfd_dst_update msg from client %s: length=%d",
1485 : zebra_route_string(client->proto), hdr->length);
1486 :
1487 : /*
1488 : * Client messages must be re-routed, otherwise do the `bfdd`
1489 : * special treatment.
1490 : */
1491 0 : if (client->proto != ZEBRA_ROUTE_BFD) {
1492 0 : _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
1493 0 : return;
1494 : }
1495 :
1496 : /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
1497 0 : if (stream_getl2(msg, &cmd) == false) {
1498 0 : zlog_err("%s: expected at least 4 bytes (command)", __func__);
1499 0 : return;
1500 : }
1501 :
1502 : /*
1503 : * Don't modify message in the zebra API. In order to do that we
1504 : * need to allocate a new message stream and copy the message
1505 : * provided by zebra.
1506 : */
1507 0 : msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1508 0 : if (msgc == NULL) {
1509 0 : zlog_debug("%s: not enough memory", __func__);
1510 0 : return;
1511 : }
1512 :
1513 : /* Calculate our header size plus the message contents. */
1514 0 : if (cmd != ZEBRA_BFD_DEST_REPLAY) {
1515 0 : zhdrlen = ZEBRA_HEADER_SIZE;
1516 0 : zmsglen = msg->endp - msg->getp;
1517 0 : memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
1518 :
1519 0 : zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1520 :
1521 0 : msgc->getp = 0;
1522 0 : msgc->endp = zhdrlen + zmsglen;
1523 : } else
1524 0 : zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1525 :
1526 : /* Update the data pointers. */
1527 0 : stream_putw_at(msgc, 0, stream_get_endp(msgc));
1528 :
1529 0 : zebra_ptm_send_clients(msgc);
1530 : }
1531 :
1532 : /*
1533 : * Unused functions.
1534 : */
1535 14 : void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
1536 : {
1537 : /* NOTHING */
1538 14 : }
1539 :
1540 14 : int zebra_ptm_get_enable_state(void)
1541 : {
1542 14 : return 0;
1543 : }
1544 :
1545 0 : void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
1546 : json_object *json __attribute__((__unused__)),
1547 : struct interface *ifp __attribute__((__unused__)))
1548 : {
1549 : /* NOTHING */
1550 0 : }
1551 :
1552 0 : void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
1553 : {
1554 : /* NOTHING */
1555 0 : }
1556 :
1557 0 : void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
1558 : struct zebra_if *zifp __attribute__((__unused__)))
1559 : {
1560 : /* NOTHING */
1561 0 : }
1562 14 : void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
1563 : struct zebra_if *zi __attribute__((__unused__)))
1564 : {
1565 : /* NOTHING */
1566 14 : }
1567 :
1568 : #endif /* HAVE_BFDD */
|