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