]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_ptm.c
Merge pull request #2992 from opensourcerouting/large_as_path_fix
[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 (proto != ZEBRA_ROUTE_OSPF && proto != ZEBRA_ROUTE_BGP
1034 && proto != ZEBRA_ROUTE_OSPF6 && proto != ZEBRA_ROUTE_PIM)
1035 return 0;
1036
1037 if (IS_ZEBRA_DEBUG_EVENT)
1038 zlog_debug("bfd_client_deregister msg for client %s",
1039 zebra_route_string(proto));
1040
1041 if (ptm_cb.ptm_sock == -1) {
1042 ptm_cb.t_timer = NULL;
1043 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
1044 ptm_cb.reconnect_time, &ptm_cb.t_timer);
1045 return 0;
1046 }
1047
1048 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
1049
1050 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD);
1051 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
1052
1053 sprintf(tmp_buf, "%s", zebra_route_string(proto));
1054 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1055 tmp_buf);
1056
1057 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1058
1059 if (IS_ZEBRA_DEBUG_SEND)
1060 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1061 ptm_cb.out_data);
1062
1063 zebra_ptm_send_message(ptm_cb.out_data, data_len);
1064 UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1065
1066 return 0;
1067 }
1068
1069 int zebra_ptm_get_enable_state(void)
1070 {
1071 return ptm_cb.ptm_enable;
1072 }
1073
1074 /*
1075 * zebra_ptm_get_status_str - Convert status to a display string.
1076 */
1077 static const char *zebra_ptm_get_status_str(int status)
1078 {
1079 switch (status) {
1080 case ZEBRA_PTM_STATUS_DOWN:
1081 return "fail";
1082 case ZEBRA_PTM_STATUS_UP:
1083 return "pass";
1084 case ZEBRA_PTM_STATUS_UNKNOWN:
1085 default:
1086 return "n/a";
1087 }
1088 }
1089
1090 void zebra_ptm_show_status(struct vty *vty, struct interface *ifp)
1091 {
1092 vty_out(vty, " PTM status: ");
1093 if (ifp->ptm_enable) {
1094 vty_out(vty, "%s\n", zebra_ptm_get_status_str(ifp->ptm_status));
1095 } else {
1096 vty_out(vty, "disabled\n");
1097 }
1098 }
1099
1100 void zebra_ptm_send_status_req(void)
1101 {
1102 void *out_ctxt;
1103 int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1104
1105 if (ptm_cb.ptm_enable) {
1106 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL,
1107 &out_ctxt);
1108 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
1109 ZEBRA_PTM_GET_STATUS_CMD);
1110 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
1111
1112 zebra_ptm_send_message(ptm_cb.out_data, len);
1113 }
1114 }
1115
1116 void zebra_ptm_reset_status(int ptm_disable)
1117 {
1118 struct vrf *vrf;
1119 struct interface *ifp;
1120 int send_linkup;
1121
1122 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
1123 FOR_ALL_INTERFACES (vrf, ifp) {
1124 send_linkup = 0;
1125 if (ifp->ptm_enable) {
1126 if (!if_is_operative(ifp))
1127 send_linkup = 1;
1128
1129 if (ptm_disable)
1130 ifp->ptm_enable =
1131 ZEBRA_IF_PTM_ENABLE_OFF;
1132 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
1133
1134 if (if_is_operative(ifp) && send_linkup) {
1135 if (IS_ZEBRA_DEBUG_EVENT)
1136 zlog_debug(
1137 "%s: Bringing up interface %s",
1138 __func__, ifp->name);
1139 if_up(ifp);
1140 }
1141 }
1142 }
1143 }
1144
1145 void zebra_ptm_if_init(struct zebra_if *zebra_ifp)
1146 {
1147 zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
1148 }
1149
1150 void zebra_ptm_if_set_ptm_state(struct interface *ifp,
1151 struct zebra_if *zebra_ifp)
1152 {
1153 if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
1154 ifp->ptm_enable = zebra_ifp->ptm_enable;
1155 }
1156
1157 void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
1158 {
1159 if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
1160 vty_out(vty, " no ptm-enable\n");
1161 }
1162
1163 #else /* HAVE_BFDD */
1164
1165 #include "zebra/zebra_memory.h"
1166
1167 /*
1168 * Data structures.
1169 */
1170 struct ptm_process {
1171 struct zserv *pp_zs;
1172 pid_t pp_pid;
1173
1174 TAILQ_ENTRY(ptm_process) pp_entry;
1175 };
1176 TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
1177
1178 DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
1179 "PTM BFD process registration table.");
1180
1181 /*
1182 * Prototypes.
1183 */
1184 static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
1185 static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
1186 static void pp_free(struct ptm_process *pp);
1187 static void pp_free_all(void);
1188
1189 static void zebra_ptm_send_bfdd(struct stream *msg);
1190 static void zebra_ptm_send_clients(struct stream *msg);
1191 static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
1192 static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
1193 uint32_t command);
1194
1195
1196 /*
1197 * Process PID registration.
1198 */
1199 static struct ptm_process *pp_new(pid_t pid, struct zserv *zs)
1200 {
1201 struct ptm_process *pp;
1202
1203 #ifdef PTM_DEBUG
1204 /* Sanity check: more than one client can't have the same PID. */
1205 TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1206 if (pp->pp_pid == pid && pp->pp_zs != zs)
1207 zlog_err("%s:%d pid and client pointer doesn't match",
1208 __FILE__, __LINE__);
1209 }
1210 #endif /* PTM_DEBUG */
1211
1212 /* Lookup for duplicates. */
1213 pp = pp_lookup_byzs(zs);
1214 if (pp != NULL)
1215 return pp;
1216
1217 /* Allocate and register new process. */
1218 pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
1219 if (pp == NULL)
1220 return NULL;
1221
1222 pp->pp_pid = pid;
1223 pp->pp_zs = zs;
1224 TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
1225
1226 return pp;
1227 }
1228
1229 static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
1230 {
1231 struct ptm_process *pp;
1232
1233 TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1234 if (pp->pp_zs != zs)
1235 continue;
1236
1237 break;
1238 }
1239
1240 return pp;
1241 }
1242
1243 static void pp_free(struct ptm_process *pp)
1244 {
1245 if (pp == NULL)
1246 return;
1247
1248 TAILQ_REMOVE(&ppqueue, pp, pp_entry);
1249 XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
1250 }
1251
1252 static void pp_free_all(void)
1253 {
1254 struct ptm_process *pp;
1255
1256 while (!TAILQ_EMPTY(&ppqueue)) {
1257 pp = TAILQ_FIRST(&ppqueue);
1258 pp_free(pp);
1259 }
1260 }
1261
1262
1263 /*
1264 * Use the FRR's internal daemon implementation.
1265 */
1266 static void zebra_ptm_send_bfdd(struct stream *msg)
1267 {
1268 struct listnode *node;
1269 struct zserv *client;
1270 struct stream *msgc;
1271
1272 /* Create copy for replication. */
1273 msgc = stream_dup(msg);
1274 if (msgc == NULL) {
1275 zlog_debug("%s: not enough memory", __func__);
1276 return;
1277 }
1278
1279 /* Send message to all running BFDd daemons. */
1280 for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
1281 if (client->proto != ZEBRA_ROUTE_BFD)
1282 continue;
1283
1284 zserv_send_message(client, msg);
1285
1286 /* Allocate more messages. */
1287 msg = stream_dup(msgc);
1288 if (msg == NULL) {
1289 zlog_debug("%s: not enough memory", __func__);
1290 return;
1291 }
1292 }
1293
1294 stream_free(msgc);
1295 stream_free(msg);
1296 }
1297
1298 static void zebra_ptm_send_clients(struct stream *msg)
1299 {
1300 struct listnode *node;
1301 struct zserv *client;
1302 struct stream *msgc;
1303
1304 /* Create copy for replication. */
1305 msgc = stream_dup(msg);
1306 if (msgc == NULL) {
1307 zlog_debug("%s: not enough memory", __func__);
1308 return;
1309 }
1310
1311 /* Send message to all running client daemons. */
1312 for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
1313 switch (client->proto) {
1314 case ZEBRA_ROUTE_BGP:
1315 case ZEBRA_ROUTE_OSPF:
1316 case ZEBRA_ROUTE_OSPF6:
1317 case ZEBRA_ROUTE_PIM:
1318 break;
1319
1320 default:
1321 /* NOTHING: skip this daemon. */
1322 continue;
1323 }
1324
1325 zserv_send_message(client, msg);
1326
1327 /* Allocate more messages. */
1328 msg = stream_dup(msgc);
1329 if (msg == NULL) {
1330 zlog_debug("%s: not enough memory", __func__);
1331 return;
1332 }
1333 }
1334
1335 stream_free(msgc);
1336 stream_free(msg);
1337 }
1338
1339 static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
1340 {
1341 struct stream *msg;
1342 struct ptm_process *pp;
1343
1344 /* Filter daemons that must receive this treatment. */
1345 switch (zs->proto) {
1346 case ZEBRA_ROUTE_BGP:
1347 case ZEBRA_ROUTE_OSPF:
1348 case ZEBRA_ROUTE_OSPF6:
1349 case ZEBRA_ROUTE_PIM:
1350 break;
1351
1352 case ZEBRA_ROUTE_BFD:
1353 /* Don't try to send BFDd messages to itself. */
1354 return 0;
1355
1356 default:
1357 /* Unsupported daemon. */
1358 return 0;
1359 }
1360
1361 /* Find daemon pid by zebra connection pointer. */
1362 pp = pp_lookup_byzs(zs);
1363 if (pp == NULL) {
1364 zlog_err("%s:%d failed to find process pid registration",
1365 __FILE__, __LINE__);
1366 return -1;
1367 }
1368
1369 /* Generate, send message and free() daemon related data. */
1370 msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
1371 if (msg == NULL) {
1372 zlog_debug("%s: not enough memory", __func__);
1373 return 0;
1374 }
1375
1376 /*
1377 * The message type will be BFD_DEST_REPLY so we can use only
1378 * one callback at the `bfdd` side, however the real command
1379 * number will be included right after the zebra header.
1380 */
1381 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
1382 stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
1383
1384 /* Put process PID. */
1385 stream_putl(msg, pp->pp_pid);
1386
1387 /* Update the data pointers. */
1388 stream_putw_at(msg, 0, stream_get_endp(msg));
1389
1390 zebra_ptm_send_bfdd(msg);
1391
1392 pp_free(pp);
1393
1394 return 0;
1395 }
1396
1397 void zebra_ptm_init(void)
1398 {
1399 /* Initialize the ptm process information list. */
1400 TAILQ_INIT(&ppqueue);
1401
1402 /*
1403 * Send deregistration messages to BFD daemon when some other
1404 * daemon closes. This will help avoid sending daemons
1405 * unnecessary notification messages.
1406 */
1407 hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1408 }
1409
1410 void zebra_ptm_finish(void)
1411 {
1412 /* Remove the client disconnect hook and free all memory. */
1413 hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1414 pp_free_all();
1415 }
1416
1417
1418 /*
1419 * Message handling.
1420 */
1421 static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
1422 uint32_t command)
1423 {
1424 struct stream *msgc;
1425 size_t zmsglen, zhdrlen;
1426 pid_t ppid;
1427
1428 /*
1429 * Don't modify message in the zebra API. In order to do that we
1430 * need to allocate a new message stream and copy the message
1431 * provided by zebra.
1432 */
1433 msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1434 if (msgc == NULL) {
1435 zlog_debug("%s: not enough memory", __func__);
1436 return;
1437 }
1438
1439 /* Calculate our header size plus the message contents. */
1440 zhdrlen = ZEBRA_HEADER_SIZE + sizeof(uint32_t);
1441 zmsglen = msg->endp - msg->getp;
1442 memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
1443
1444 /*
1445 * The message type will be BFD_DEST_REPLY so we can use only
1446 * one callback at the `bfdd` side, however the real command
1447 * number will be included right after the zebra header.
1448 */
1449 zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
1450 stream_putl(msgc, command);
1451
1452 /* Update the data pointers. */
1453 msgc->getp = 0;
1454 msgc->endp = zhdrlen + zmsglen;
1455 stream_putw_at(msgc, 0, stream_get_endp(msgc));
1456
1457 zebra_ptm_send_bfdd(msgc);
1458
1459 /* Registrate process PID for shutdown hook. */
1460 STREAM_GETL(msg, ppid);
1461 pp_new(ppid, zs);
1462
1463 return;
1464
1465 stream_failure:
1466 zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
1467 }
1468
1469 void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
1470 {
1471 if (IS_ZEBRA_DEBUG_EVENT)
1472 zlog_debug("bfd_dst_register msg from client %s: length=%d",
1473 zebra_route_string(client->proto), hdr->length);
1474
1475 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
1476 }
1477
1478 void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
1479 {
1480 if (IS_ZEBRA_DEBUG_EVENT)
1481 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
1482 zebra_route_string(client->proto), hdr->length);
1483
1484 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
1485 }
1486
1487 void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
1488 {
1489 if (IS_ZEBRA_DEBUG_EVENT)
1490 zlog_debug("bfd_client_register msg from client %s: length=%d",
1491 zebra_route_string(client->proto), hdr->length);
1492
1493 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
1494 }
1495
1496 void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
1497 {
1498 struct stream *msgc;
1499 size_t zmsglen, zhdrlen;
1500 uint32_t cmd;
1501
1502 /*
1503 * NOTE:
1504 * Replay messages with HAVE_BFDD are meant to be replayed to
1505 * the client daemons. These messages are composed and
1506 * originated from the `bfdd` daemon.
1507 */
1508 if (IS_ZEBRA_DEBUG_EVENT)
1509 zlog_debug("bfd_dst_update msg from client %s: length=%d",
1510 zebra_route_string(client->proto), hdr->length);
1511
1512 /*
1513 * Client messages must be re-routed, otherwise do the `bfdd`
1514 * special treatment.
1515 */
1516 if (client->proto != ZEBRA_ROUTE_BFD) {
1517 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
1518 return;
1519 }
1520
1521 /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
1522 if (stream_getl2(msg, &cmd) == false) {
1523 zlog_err("%s: expected at least 4 bytes (command)", __func__);
1524 return;
1525 }
1526
1527 /*
1528 * Don't modify message in the zebra API. In order to do that we
1529 * need to allocate a new message stream and copy the message
1530 * provided by zebra.
1531 */
1532 msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1533 if (msgc == NULL) {
1534 zlog_debug("%s: not enough memory", __func__);
1535 return;
1536 }
1537
1538 /* Calculate our header size plus the message contents. */
1539 if (cmd != ZEBRA_BFD_DEST_REPLAY) {
1540 zhdrlen = ZEBRA_HEADER_SIZE;
1541 zmsglen = msg->endp - msg->getp;
1542 memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
1543
1544 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1545
1546 msgc->getp = 0;
1547 msgc->endp = zhdrlen + zmsglen;
1548 } else
1549 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1550
1551 /* Update the data pointers. */
1552 stream_putw_at(msgc, 0, stream_get_endp(msgc));
1553
1554 zebra_ptm_send_clients(msgc);
1555 }
1556
1557 /*
1558 * Unused functions.
1559 */
1560 void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
1561 {
1562 /* NOTHING */
1563 }
1564
1565 int zebra_ptm_get_enable_state(void)
1566 {
1567 return 0;
1568 }
1569
1570 void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
1571 struct interface *ifp __attribute__((__unused__)))
1572 {
1573 /* NOTHING */
1574 }
1575
1576 void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
1577 {
1578 /* NOTHING */
1579 }
1580
1581 void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
1582 struct zebra_if *zifp __attribute__((__unused__)))
1583 {
1584 /* NOTHING */
1585 }
1586 void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
1587 struct zebra_if *zi __attribute__((__unused__)))
1588 {
1589 /* NOTHING */
1590 }
1591
1592 #endif /* HAVE_BFDD */