]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_ptm.c
Merge pull request #5455 from donaldsharp/7.1_bgp_rpki_crash
[mirror_frr.git] / zebra / zebra_ptm.c
CommitLineData
244c1cdc
DS
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 *
896014f4
DL
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
244c1cdc
DS
19 */
20
21#include <zebra.h>
43e52561 22
d62a17ae 23#include <sys/un.h> /* for sockaddr_un */
244c1cdc 24#include <net/if.h>
43e52561
QY
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"
c8ed14dd 36#include "vty.h"
364fed6b 37#include "lib_errors.h"
43e52561 38
244c1cdc 39#include "zebra/debug.h"
43e52561
QY
40#include "zebra/interface.h"
41#include "zebra/zebra_errors.h"
244c1cdc 42#include "zebra/zebra_ptm.h"
c43ed2e4 43#include "zebra/zebra_ptm_redistribute.h"
161e9ab7 44#include "zebra/zebra_router.h"
7c551956 45#include "zebra_vrf.h"
244c1cdc 46
d3af6147
RZ
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
244c1cdc
DS
56#define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
57#define ZEBRA_PTM_RECONNECT_TIME_MAX 300
c01acf98 58
c01acf98 59#define PTM_MSG_LEN 4
0a56c844 60#define PTM_HEADER_LEN 37
c43ed2e4
DS
61
62const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
63const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
64const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
055c4dfc 65const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client";
567b877d 66const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD[] = "dereg-bfd-client";
c43ed2e4 67
c8ed14dd 68const char ZEBRA_PTM_CMD_STR[] = "cmd";
b255a4b1 69const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status";
c43ed2e4
DS
70const char ZEBRA_PTM_PORT_STR[] = "port";
71const char ZEBRA_PTM_CBL_STR[] = "cbl status";
72const char ZEBRA_PTM_PASS_STR[] = "pass";
73const char ZEBRA_PTM_FAIL_STR[] = "fail";
74const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
75const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
76const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
77const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
78const char ZEBRA_PTM_BFDSRC_STR[] = "local";
d553294e 79const char ZEBRA_PTM_BFDVRF_STR[] = "vrf";
c43ed2e4
DS
80const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
81const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
d553294e 82const char ZEBRA_PTM_INVALID_VRF[] = "N/A";
c43ed2e4
DS
83
84const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
85const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
86const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
87const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
88const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
89const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
90const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
91const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
92const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
93const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
68fe91d6 94const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
d553294e 95const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
c01acf98 96
c43ed2e4 97static ptm_lib_handle_t *ptm_hdl;
244c1cdc 98
c8ed14dd
DS
99struct zebra_ptm_cb ptm_cb;
100
244c1cdc 101static int zebra_ptm_socket_init(void);
244c1cdc 102int zebra_ptm_sock_read(struct thread *);
d62a17ae 103static void zebra_ptm_install_commands(void);
b255a4b1 104static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt);
d62a17ae 105void zebra_bfd_peer_replay_req(void);
950bd436 106void zebra_ptm_send_status_req(void);
107void zebra_ptm_reset_status(int ptm_disable);
8b1766b1 108static int zebra_ptm_bfd_client_deregister(struct zserv *client);
244c1cdc
DS
109
110const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
111
d62a17ae 112void zebra_ptm_init(void)
244c1cdc 113{
d62a17ae 114 char buf[64];
c43ed2e4 115
d62a17ae 116 memset(&ptm_cb, 0, sizeof(struct zebra_ptm_cb));
c8ed14dd 117
d62a17ae 118 ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
119 if (!ptm_cb.out_data) {
9df414fe 120 zlog_debug("%s: Allocation of send data failed", __func__);
d62a17ae 121 return;
122 }
c8ed14dd 123
d62a17ae 124 ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
125 if (!ptm_cb.in_data) {
9df414fe 126 zlog_debug("%s: Allocation of recv data failed", __func__);
d62a17ae 127 free(ptm_cb.out_data);
128 return;
129 }
c8ed14dd 130
d62a17ae 131 ptm_cb.pid = getpid();
132 zebra_ptm_install_commands();
c43ed2e4 133
d62a17ae 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);
c8ed14dd 138
d62a17ae 139 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
c8ed14dd 140
d62a17ae 141 ptm_cb.ptm_sock = -1;
453844ab 142
21ccc0cf 143 hook_register(zserv_client_close, zebra_ptm_bfd_client_deregister);
c8ed14dd
DS
144}
145
d62a17ae 146void zebra_ptm_finish(void)
c8ed14dd 147{
d62a17ae 148 buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock);
c8ed14dd 149
d62a17ae 150 free(ptm_hdl);
58ac32e2 151
d62a17ae 152 if (ptm_cb.out_data)
153 free(ptm_cb.out_data);
c8ed14dd 154
d62a17ae 155 if (ptm_cb.in_data)
156 free(ptm_cb.in_data);
c8ed14dd 157
d62a17ae 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);
2376c3f2 165
d62a17ae 166 if (ptm_cb.wb)
167 buffer_free(ptm_cb.wb);
2376c3f2 168
1e9f448f 169 if (ptm_cb.ptm_sock >= 0)
d62a17ae 170 close(ptm_cb.ptm_sock);
c8ed14dd
DS
171}
172
d62a17ae 173static int zebra_ptm_flush_messages(struct thread *thread)
c8ed14dd 174{
d62a17ae 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:
1c50c1c0
QY
184 flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
185 safe_strerror(errno));
d62a17ae 186 close(ptm_cb.ptm_sock);
187 ptm_cb.ptm_sock = -1;
188 zebra_ptm_reset_status(0);
189 ptm_cb.t_timer = NULL;
3801e764 190 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 191 ptm_cb.reconnect_time, &ptm_cb.t_timer);
192 return (-1);
193 case BUFFER_PENDING:
194 ptm_cb.t_write = NULL;
3801e764 195 thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
d62a17ae 196 ptm_cb.ptm_sock, &ptm_cb.t_write);
197 break;
198 case BUFFER_EMPTY:
199 break;
200 }
201
202 return (0);
c8ed14dd
DS
203}
204
d62a17ae 205static int zebra_ptm_send_message(char *data, int size)
c8ed14dd 206{
d62a17ae 207 errno = 0;
208 switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size)) {
209 case BUFFER_ERROR:
1c50c1c0
QY
210 flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
211 safe_strerror(errno));
d62a17ae 212 close(ptm_cb.ptm_sock);
213 ptm_cb.ptm_sock = -1;
214 zebra_ptm_reset_status(0);
215 ptm_cb.t_timer = NULL;
3801e764 216 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 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:
3801e764 223 thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
d62a17ae 224 ptm_cb.ptm_sock, &ptm_cb.t_write);
225 break;
226 }
227
228 return 0;
244c1cdc
DS
229}
230
d62a17ae 231int zebra_ptm_connect(struct thread *t)
244c1cdc 232{
d62a17ae 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;
3801e764 243 thread_add_read(zrouter.master, zebra_ptm_sock_read,
d62a17ae 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;
3801e764 255 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 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);
244c1cdc
DS
262}
263
244c1cdc
DS
264DEFUN (zebra_ptm_enable,
265 zebra_ptm_enable_cmd,
266 "ptm-enable",
267 "Enable neighbor check with specified topology\n")
268{
d62a17ae 269 struct vrf *vrf;
d62a17ae 270 struct interface *ifp;
271 struct zebra_if *if_data;
272
273 ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
274
a2addae8 275 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
451fda4f 276 FOR_ALL_INTERFACES (vrf, ifp)
a2addae8
RW
277 if (!ifp->ptm_enable) {
278 if_data = (struct zebra_if *)ifp->info;
279 if (if_data
280 && (if_data->ptm_enable
9d303b37 281 == ZEBRA_IF_PTM_ENABLE_UNSPEC)) {
a2addae8
RW
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;
d62a17ae 287 }
d62a17ae 288
289 zebra_ptm_connect(NULL);
290
291 return CMD_SUCCESS;
244c1cdc
DS
292}
293
294DEFUN (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{
d62a17ae 300 ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
301 zebra_ptm_reset_status(1);
302 return CMD_SUCCESS;
244c1cdc
DS
303}
304
986aa00f 305DEFUN (zebra_ptm_enable_if,
306 zebra_ptm_enable_if_cmd,
307 "ptm-enable",
308 "Enable neighbor check with specified topology\n")
309{
d62a17ae 310 VTY_DECLVAR_CONTEXT(interface, ifp);
311 struct zebra_if *if_data;
312 int old_ptm_enable;
313 int send_linkdown = 0;
314
a2023fab 315 if_data = ifp->info;
316 if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
317
d62a17ae 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)
9165c5f5 331 zlog_debug("%s: Bringing down interface %s",
d62a17ae 332 __func__, ifp->name);
333 if_down(ifp);
334 }
335 }
336
d62a17ae 337 return CMD_SUCCESS;
986aa00f 338}
339
340DEFUN (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{
d62a17ae 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)
9165c5f5 357 zlog_debug("%s: Bringing up interface %s",
d62a17ae 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;
986aa00f 367}
368
369
d62a17ae 370void zebra_ptm_write(struct vty *vty)
244c1cdc 371{
d62a17ae 372 if (ptm_cb.ptm_enable)
373 vty_out(vty, "ptm-enable\n");
244c1cdc 374
d62a17ae 375 return;
244c1cdc
DS
376}
377
d62a17ae 378static int zebra_ptm_socket_init(void)
244c1cdc 379{
d62a17ae 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;
244c1cdc
DS
416}
417
d62a17ae 418static void zebra_ptm_install_commands(void)
244c1cdc 419{
d62a17ae 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);
244c1cdc
DS
424}
425
c43ed2e4 426/* BFD session goes down, send message to the protocols. */
d62a17ae 427static void if_bfd_session_update(struct interface *ifp, struct prefix *dp,
428 struct prefix *sp, int status,
429 vrf_id_t vrf_id)
c01acf98 430{
d62a17ae 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 "
a9ff90c4 445 "with src %s/%d and vrf %u %s event",
d62a17ae 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);
c01acf98
DS
457}
458
d62a17ae 459static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
460 struct interface *ifp)
244c1cdc 461{
d62a17ae 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) {
e914ccbe 508 flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
1c50c1c0 509 "%s: Peer addr %s not found", __func__, dest_str);
d62a17ae 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) {
e914ccbe 516 flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
1c50c1c0
QY
517 "%s: Local addr %s not found", __func__,
518 src_str);
d62a17ae 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;
c01acf98
DS
538}
539
d62a17ae 540static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt,
541 struct interface *ifp, char *cbl_str)
c01acf98 542{
d62a17ae 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;
b255a4b1 566}
950bd436 567
b255a4b1 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 */
d62a17ae 585static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
b255a4b1 586{
d62a17ae 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) {
e914ccbe 612 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 613 "%s: %s not found in interface list",
43e52561 614 __func__, port_str);
d62a17ae 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 }
c01acf98
DS
631}
632
d62a17ae 633int zebra_ptm_sock_read(struct thread *thread)
c01acf98 634{
2e1cc436 635 int sock;
d62a17ae 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 */
2e1cc436 645 do {
d62a17ae 646 rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
647 ZEBRA_PTM_MAX_SOCKBUF, NULL);
2e1cc436 648 } while (rc > 0);
d62a17ae 649
2e1cc436
A
650 if (((rc == 0) && !errno)
651 || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
450971aa 652 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
653 "%s routing socket error: %s(%d) bytes %d",
654 __func__, safe_strerror(errno), errno, rc);
2e1cc436
A
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;
3801e764 660 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
2e1cc436
A
661 ptm_cb.reconnect_time,
662 &ptm_cb.t_timer);
663 return (-1);
d62a17ae 664 }
665
666 ptm_cb.t_read = NULL;
3801e764 667 thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL,
d62a17ae 668 ptm_cb.ptm_sock, &ptm_cb.t_read);
669
670 return 0;
c43ed2e4
DS
671}
672
673/* BFD peer/dst register/update */
89f4e507 674void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
c43ed2e4 675{
d62a17ae 676 struct stream *s;
677 struct prefix src_p;
678 struct prefix dst_p;
d7c0a89a
QY
679 uint8_t multi_hop;
680 uint8_t multi_hop_cnt;
681 uint8_t detect_mul;
d62a17ae 682 unsigned int min_rx_timer;
683 unsigned int min_tx_timer;
684 char if_name[INTERFACE_NAMSIZ];
d7c0a89a 685 uint8_t len;
d62a17ae 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
89f4e507 692 if (hdr->command == ZEBRA_BFD_DEST_UPDATE)
d62a17ae 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",
89f4e507 699 zebra_route_string(client->proto), hdr->length);
d62a17ae 700
701 if (ptm_cb.ptm_sock == -1) {
702 ptm_cb.t_timer = NULL;
3801e764 703 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 704 ptm_cb.reconnect_time, &ptm_cb.t_timer);
8068a649 705 return;
d62a17ae 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
1002497a 715 s = msg;
d62a17ae 716
ec93aa12 717 STREAM_GETL(s, pid);
d62a17ae 718 sprintf(tmp_buf, "%d", pid);
719 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
720 tmp_buf);
721
ec93aa12 722 STREAM_GETW(s, dst_p.family);
d62a17ae 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
ec93aa12 729 STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
d62a17ae 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
ec93aa12 740 STREAM_GETL(s, min_rx_timer);
d62a17ae 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);
ec93aa12 744 STREAM_GETL(s, min_tx_timer);
d62a17ae 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);
ec93aa12 748 STREAM_GETC(s, detect_mul);
d62a17ae 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
ec93aa12 753 STREAM_GETC(s, multi_hop);
d62a17ae 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);
ec93aa12 758 STREAM_GETW(s, src_p.family);
d62a17ae 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
ec93aa12 765 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
d62a17ae 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
ec93aa12 776 STREAM_GETC(s, multi_hop_cnt);
d62a17ae 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) {
ec93aa12 787 STREAM_GETW(s, src_p.family);
d62a17ae 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
ec93aa12 794 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
d62a17ae 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 }
ec93aa12
DS
809 STREAM_GETC(s, len);
810 STREAM_GET(if_name, s, len);
d62a17ae 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);
ec93aa12 827
8068a649 828 return;
9cc46248 829
ec93aa12 830stream_failure:
a928d464 831 ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
c43ed2e4
DS
832}
833
834/* BFD peer/dst deregister */
89f4e507 835void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
c43ed2e4 836{
d62a17ae 837 struct stream *s;
838 struct prefix src_p;
839 struct prefix dst_p;
d7c0a89a 840 uint8_t multi_hop;
d62a17ae 841 char if_name[INTERFACE_NAMSIZ];
d7c0a89a 842 uint8_t len;
d62a17ae 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",
89f4e507 853 zebra_route_string(client->proto), hdr->length);
d62a17ae 854
855 if (ptm_cb.ptm_sock == -1) {
856 ptm_cb.t_timer = NULL;
3801e764 857 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 858 ptm_cb.reconnect_time, &ptm_cb.t_timer);
8068a649 859 return;
d62a17ae 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
1002497a 871 s = msg;
d62a17ae 872
ec93aa12 873 STREAM_GETL(s, pid);
d62a17ae 874 sprintf(tmp_buf, "%d", pid);
875 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
876 tmp_buf);
877
ec93aa12 878 STREAM_GETW(s, dst_p.family);
d62a17ae 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
ec93aa12 885 STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
d62a17ae 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
ec93aa12 893 STREAM_GETC(s, multi_hop);
d62a17ae 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
ec93aa12 899 STREAM_GETW(s, src_p.family);
d62a17ae 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
ec93aa12 906 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
d62a17ae 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) {
ec93aa12 920 STREAM_GETW(s, src_p.family);
d62a17ae 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
ec93aa12 927 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
d62a17ae 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
ec93aa12
DS
943 STREAM_GETC(s, len);
944 STREAM_GET(if_name, s, len);
d62a17ae 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);
ec93aa12 957
8068a649 958 return;
9cc46248 959
ec93aa12 960stream_failure:
a928d464 961 ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
c01acf98 962}
c8ed14dd 963
055c4dfc 964/* BFD client register */
89f4e507 965void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
055c4dfc 966{
d62a17ae 967 struct stream *s;
968 unsigned int pid;
9cc46248 969 void *out_ctxt = NULL;
d62a17ae 970 char tmp_buf[64];
971 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
055c4dfc 972
d62a17ae 973 client->bfd_client_reg_cnt++;
055c4dfc 974
d62a17ae 975 if (IS_ZEBRA_DEBUG_EVENT)
976 zlog_debug("bfd_client_register msg from client %s: length=%d",
89f4e507 977 zebra_route_string(client->proto), hdr->length);
055c4dfc 978
1002497a 979 s = msg;
ec93aa12 980 STREAM_GETL(s, pid);
bf6e101c 981
d62a17ae 982 if (ptm_cb.ptm_sock == -1) {
983 ptm_cb.t_timer = NULL;
3801e764 984 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 985 ptm_cb.reconnect_time, &ptm_cb.t_timer);
8068a649 986 return;
d62a17ae 987 }
055c4dfc 988
d62a17ae 989 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
055c4dfc 990
d62a17ae 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);
055c4dfc 993
d62a17ae 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);
055c4dfc 997
d62a17ae 998 sprintf(tmp_buf, "%d", pid);
999 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
1000 tmp_buf);
055c4dfc 1001
d62a17ae 1002 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
055c4dfc 1003
d62a17ae 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);
2376c3f2 1008
d62a17ae 1009 SET_FLAG(ptm_cb.client_flags[client->proto],
1010 ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
9cc46248 1011
8068a649 1012 return;
9cc46248 1013
ec93aa12 1014stream_failure:
6447dbb3
DS
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 */
8068a649 1022 return;
055c4dfc 1023}
1024
567b877d 1025/* BFD client deregister */
453844ab 1026int zebra_ptm_bfd_client_deregister(struct zserv *client)
567b877d 1027{
453844ab 1028 uint8_t proto = client->proto;
d62a17ae 1029 void *out_ctxt;
1030 char tmp_buf[64];
1031 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
567b877d 1032
4943f243 1033 if (!IS_BFD_ENABLED_PROTOCOL(proto))
453844ab 1034 return 0;
567b877d 1035
d62a17ae 1036 if (IS_ZEBRA_DEBUG_EVENT)
9df414fe
QY
1037 zlog_debug("bfd_client_deregister msg for client %s",
1038 zebra_route_string(proto));
567b877d 1039
d62a17ae 1040 if (ptm_cb.ptm_sock == -1) {
1041 ptm_cb.t_timer = NULL;
3801e764 1042 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
d62a17ae 1043 ptm_cb.reconnect_time, &ptm_cb.t_timer);
453844ab 1044 return 0;
d62a17ae 1045 }
567b877d 1046
d62a17ae 1047 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
567b877d 1048
d62a17ae 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);
567b877d 1051
d62a17ae 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);
567b877d 1055
d62a17ae 1056 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
567b877d 1057
d62a17ae 1058 if (IS_ZEBRA_DEBUG_SEND)
1059 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1060 ptm_cb.out_data);
2376c3f2 1061
d62a17ae 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);
453844ab
QY
1064
1065 return 0;
567b877d 1066}
1067
d62a17ae 1068int zebra_ptm_get_enable_state(void)
c8ed14dd 1069{
d62a17ae 1070 return ptm_cb.ptm_enable;
c8ed14dd 1071}
950bd436 1072
1073/*
1074 * zebra_ptm_get_status_str - Convert status to a display string.
1075 */
d62a17ae 1076static const char *zebra_ptm_get_status_str(int status)
950bd436 1077{
d62a17ae 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 }
950bd436 1087}
1088
d62a17ae 1089void zebra_ptm_show_status(struct vty *vty, struct interface *ifp)
950bd436 1090{
d62a17ae 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 }
950bd436 1097}
1098
d62a17ae 1099void zebra_ptm_send_status_req(void)
950bd436 1100{
d62a17ae 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 }
950bd436 1113}
1114
d62a17ae 1115void zebra_ptm_reset_status(int ptm_disable)
950bd436 1116{
d62a17ae 1117 struct vrf *vrf;
d62a17ae 1118 struct interface *ifp;
1119 int send_linkup;
1120
a2addae8 1121 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
451fda4f 1122 FOR_ALL_INTERFACES (vrf, ifp) {
a2addae8
RW
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 }
d62a17ae 1140 }
1141 }
950bd436 1142}
986aa00f 1143
d62a17ae 1144void zebra_ptm_if_init(struct zebra_if *zebra_ifp)
986aa00f 1145{
d62a17ae 1146 zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
986aa00f 1147}
1148
d62a17ae 1149void zebra_ptm_if_set_ptm_state(struct interface *ifp,
1150 struct zebra_if *zebra_ifp)
986aa00f 1151{
d62a17ae 1152 if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
1153 ifp->ptm_enable = zebra_ifp->ptm_enable;
986aa00f 1154}
1155
d62a17ae 1156void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
986aa00f 1157{
d62a17ae 1158 if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
1159 vty_out(vty, " no ptm-enable\n");
986aa00f 1160}
d3af6147
RZ
1161
1162#else /* HAVE_BFDD */
1163
1164#include "zebra/zebra_memory.h"
1165
1166/*
1167 * Data structures.
1168 */
1169struct ptm_process {
1170 struct zserv *pp_zs;
1171 pid_t pp_pid;
1172
1173 TAILQ_ENTRY(ptm_process) pp_entry;
1174};
1175TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
1176
1177DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
1178 "PTM BFD process registration table.");
1179
1180/*
1181 * Prototypes.
1182 */
1183static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
1184static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
1185static void pp_free(struct ptm_process *pp);
788378fe 1186static void pp_free_all(void);
d3af6147
RZ
1187
1188static void zebra_ptm_send_bfdd(struct stream *msg);
1189static void zebra_ptm_send_clients(struct stream *msg);
1190static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
1191static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
1192 uint32_t command);
1193
1194
1195/*
1196 * Process PID registration.
1197 */
1198static 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));
d3af6147
RZ
1218
1219 pp->pp_pid = pid;
1220 pp->pp_zs = zs;
1221 TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
1222
1223 return pp;
1224}
1225
1226static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
1227{
1228 struct ptm_process *pp;
1229
1230 TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1231 if (pp->pp_zs != zs)
1232 continue;
1233
1234 break;
1235 }
1236
1237 return pp;
1238}
1239
1240static void pp_free(struct ptm_process *pp)
1241{
1242 if (pp == NULL)
1243 return;
1244
1245 TAILQ_REMOVE(&ppqueue, pp, pp_entry);
1246 XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
1247}
1248
788378fe
RZ
1249static void pp_free_all(void)
1250{
1251 struct ptm_process *pp;
1252
1253 while (!TAILQ_EMPTY(&ppqueue)) {
1254 pp = TAILQ_FIRST(&ppqueue);
1255 pp_free(pp);
1256 }
1257}
1258
d3af6147
RZ
1259
1260/*
1261 * Use the FRR's internal daemon implementation.
1262 */
1263static void zebra_ptm_send_bfdd(struct stream *msg)
1264{
1265 struct listnode *node;
1266 struct zserv *client;
1267 struct stream *msgc;
1268
1269 /* Create copy for replication. */
1270 msgc = stream_dup(msg);
1271 if (msgc == NULL) {
9df414fe 1272 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1273 return;
1274 }
1275
1276 /* Send message to all running BFDd daemons. */
161e9ab7 1277 for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
d3af6147
RZ
1278 if (client->proto != ZEBRA_ROUTE_BFD)
1279 continue;
1280
1281 zserv_send_message(client, msg);
1282
1283 /* Allocate more messages. */
1284 msg = stream_dup(msgc);
1285 if (msg == NULL) {
9df414fe 1286 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1287 return;
1288 }
1289 }
1290
1291 stream_free(msgc);
7efe273a 1292 stream_free(msg);
d3af6147
RZ
1293}
1294
1295static void zebra_ptm_send_clients(struct stream *msg)
1296{
1297 struct listnode *node;
1298 struct zserv *client;
1299 struct stream *msgc;
1300
1301 /* Create copy for replication. */
1302 msgc = stream_dup(msg);
1303 if (msgc == NULL) {
9df414fe 1304 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1305 return;
1306 }
1307
1308 /* Send message to all running client daemons. */
161e9ab7 1309 for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
4943f243 1310 if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
d3af6147 1311 continue;
d3af6147
RZ
1312
1313 zserv_send_message(client, msg);
1314
1315 /* Allocate more messages. */
1316 msg = stream_dup(msgc);
1317 if (msg == NULL) {
9df414fe 1318 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1319 return;
1320 }
1321 }
1322
1323 stream_free(msgc);
7efe273a 1324 stream_free(msg);
d3af6147
RZ
1325}
1326
1327static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
1328{
1329 struct stream *msg;
1330 struct ptm_process *pp;
1331
4943f243 1332 if (!IS_BFD_ENABLED_PROTOCOL(zs->proto))
d3af6147
RZ
1333 return 0;
1334
d3af6147
RZ
1335 /* Find daemon pid by zebra connection pointer. */
1336 pp = pp_lookup_byzs(zs);
1337 if (pp == NULL) {
1338 zlog_err("%s:%d failed to find process pid registration",
1339 __FILE__, __LINE__);
1340 return -1;
1341 }
1342
1343 /* Generate, send message and free() daemon related data. */
1344 msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
1345 if (msg == NULL) {
9df414fe 1346 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1347 return 0;
1348 }
1349
1350 /*
1351 * The message type will be BFD_DEST_REPLY so we can use only
1352 * one callback at the `bfdd` side, however the real command
1353 * number will be included right after the zebra header.
1354 */
1355 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
1356 stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
1357
1358 /* Put process PID. */
1359 stream_putl(msg, pp->pp_pid);
1360
1361 /* Update the data pointers. */
1362 stream_putw_at(msg, 0, stream_get_endp(msg));
1363
1364 zebra_ptm_send_bfdd(msg);
1365
1366 pp_free(pp);
1367
1368 return 0;
1369}
1370
1371void zebra_ptm_init(void)
1372{
1373 /* Initialize the ptm process information list. */
1374 TAILQ_INIT(&ppqueue);
1375
1376 /*
1377 * Send deregistration messages to BFD daemon when some other
1378 * daemon closes. This will help avoid sending daemons
1379 * unnecessary notification messages.
1380 */
1381 hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1382}
1383
788378fe
RZ
1384void zebra_ptm_finish(void)
1385{
1386 /* Remove the client disconnect hook and free all memory. */
1387 hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1388 pp_free_all();
1389}
1390
d3af6147
RZ
1391
1392/*
1393 * Message handling.
1394 */
1395static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
1396 uint32_t command)
1397{
1398 struct stream *msgc;
1399 size_t zmsglen, zhdrlen;
1400 pid_t ppid;
1401
1402 /*
1403 * Don't modify message in the zebra API. In order to do that we
1404 * need to allocate a new message stream and copy the message
1405 * provided by zebra.
1406 */
1407 msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1408 if (msgc == NULL) {
9df414fe 1409 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1410 return;
1411 }
1412
1413 /* Calculate our header size plus the message contents. */
1414 zhdrlen = ZEBRA_HEADER_SIZE + sizeof(uint32_t);
1415 zmsglen = msg->endp - msg->getp;
1416 memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
1417
1418 /*
1419 * The message type will be BFD_DEST_REPLY so we can use only
1420 * one callback at the `bfdd` side, however the real command
1421 * number will be included right after the zebra header.
1422 */
1423 zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
1424 stream_putl(msgc, command);
1425
1426 /* Update the data pointers. */
1427 msgc->getp = 0;
1428 msgc->endp = zhdrlen + zmsglen;
1429 stream_putw_at(msgc, 0, stream_get_endp(msgc));
1430
1431 zebra_ptm_send_bfdd(msgc);
1432
1433 /* Registrate process PID for shutdown hook. */
1434 STREAM_GETL(msg, ppid);
1435 pp_new(ppid, zs);
1436
1437 return;
1438
1439stream_failure:
1440 zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
1441}
1442
1443void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
1444{
1445 if (IS_ZEBRA_DEBUG_EVENT)
1446 zlog_debug("bfd_dst_register msg from client %s: length=%d",
1447 zebra_route_string(client->proto), hdr->length);
1448
1449 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
1450}
1451
1452void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
1453{
1454 if (IS_ZEBRA_DEBUG_EVENT)
1455 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
1456 zebra_route_string(client->proto), hdr->length);
1457
1458 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
1459}
1460
1461void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
1462{
1463 if (IS_ZEBRA_DEBUG_EVENT)
1464 zlog_debug("bfd_client_register msg from client %s: length=%d",
1465 zebra_route_string(client->proto), hdr->length);
1466
1467 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
1468}
1469
1470void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
1471{
1472 struct stream *msgc;
1473 size_t zmsglen, zhdrlen;
971532e2 1474 uint32_t cmd;
d3af6147
RZ
1475
1476 /*
1477 * NOTE:
1478 * Replay messages with HAVE_BFDD are meant to be replayed to
1479 * the client daemons. These messages are composed and
1480 * originated from the `bfdd` daemon.
1481 */
1482 if (IS_ZEBRA_DEBUG_EVENT)
1483 zlog_debug("bfd_dst_update msg from client %s: length=%d",
1484 zebra_route_string(client->proto), hdr->length);
1485
971532e2
RZ
1486 /*
1487 * Client messages must be re-routed, otherwise do the `bfdd`
1488 * special treatment.
1489 */
1490 if (client->proto != ZEBRA_ROUTE_BFD) {
1491 _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
1492 return;
1493 }
1494
1495 /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
1496 if (stream_getl2(msg, &cmd) == false) {
1497 zlog_err("%s: expected at least 4 bytes (command)", __func__);
1498 return;
1499 }
1500
d3af6147
RZ
1501 /*
1502 * Don't modify message in the zebra API. In order to do that we
1503 * need to allocate a new message stream and copy the message
1504 * provided by zebra.
1505 */
1506 msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1507 if (msgc == NULL) {
9df414fe 1508 zlog_debug("%s: not enough memory", __func__);
d3af6147
RZ
1509 return;
1510 }
1511
1512 /* Calculate our header size plus the message contents. */
971532e2
RZ
1513 if (cmd != ZEBRA_BFD_DEST_REPLAY) {
1514 zhdrlen = ZEBRA_HEADER_SIZE;
1515 zmsglen = msg->endp - msg->getp;
1516 memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
d3af6147 1517
971532e2
RZ
1518 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1519
1520 msgc->getp = 0;
1521 msgc->endp = zhdrlen + zmsglen;
1522 } else
1523 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
d3af6147
RZ
1524
1525 /* Update the data pointers. */
d3af6147
RZ
1526 stream_putw_at(msgc, 0, stream_get_endp(msgc));
1527
1528 zebra_ptm_send_clients(msgc);
1529}
1530
1531/*
1532 * Unused functions.
1533 */
d3af6147
RZ
1534void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
1535{
1536 /* NOTHING */
1537}
1538
1539int zebra_ptm_get_enable_state(void)
1540{
5efdb801 1541 return 0;
d3af6147
RZ
1542}
1543
1544void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
1545 struct interface *ifp __attribute__((__unused__)))
1546{
1547 /* NOTHING */
1548}
1549
1550void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
1551{
1552 /* NOTHING */
1553}
1554
1555void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
1556 struct zebra_if *zifp __attribute__((__unused__)))
1557{
1558 /* NOTHING */
1559}
1560void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
1561 struct zebra_if *zi __attribute__((__unused__)))
1562{
1563 /* NOTHING */
1564}
1565
1566#endif /* HAVE_BFDD */