1 /* Kernel routing table updates using netlink over GNU/Linux system.
2 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
22 #include <sys/un.h> /* for sockaddr_un */
25 #include "zebra/zserv.h"
26 #include "zebra/interface.h"
27 #include "zebra/debug.h"
28 #include "zebra/zebra_ptm.h"
35 #include "zebra/zebra_ptm_redistribute.h"
39 #include "zebra_vrf.h"
42 #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
43 #define ZEBRA_PTM_RECONNECT_TIME_MAX 300
46 #define PTM_HEADER_LEN 37
48 const char ZEBRA_PTM_GET_STATUS_CMD
[] = "get-status";
49 const char ZEBRA_PTM_BFD_START_CMD
[] = "start-bfd-sess";
50 const char ZEBRA_PTM_BFD_STOP_CMD
[] = "stop-bfd-sess";
51 const char ZEBRA_PTM_BFD_CLIENT_REG_CMD
[] = "reg-bfd-client";
52 const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD
[] = "dereg-bfd-client";
54 const char ZEBRA_PTM_CMD_STR
[] = "cmd";
55 const char ZEBRA_PTM_CMD_STATUS_STR
[] = "cmd_status";
56 const char ZEBRA_PTM_PORT_STR
[] = "port";
57 const char ZEBRA_PTM_CBL_STR
[] = "cbl status";
58 const char ZEBRA_PTM_PASS_STR
[] = "pass";
59 const char ZEBRA_PTM_FAIL_STR
[] = "fail";
60 const char ZEBRA_PTM_BFDSTATUS_STR
[] = "state";
61 const char ZEBRA_PTM_BFDSTATUS_UP_STR
[] = "Up";
62 const char ZEBRA_PTM_BFDSTATUS_DOWN_STR
[] = "Down";
63 const char ZEBRA_PTM_BFDDEST_STR
[] = "peer";
64 const char ZEBRA_PTM_BFDSRC_STR
[] = "local";
65 const char ZEBRA_PTM_BFDVRF_STR
[] = "vrf";
66 const char ZEBRA_PTM_INVALID_PORT_NAME
[] = "N/A";
67 const char ZEBRA_PTM_INVALID_SRC_IP
[] = "N/A";
68 const char ZEBRA_PTM_INVALID_VRF
[] = "N/A";
70 const char ZEBRA_PTM_BFD_DST_IP_FIELD
[] = "dstIPaddr";
71 const char ZEBRA_PTM_BFD_SRC_IP_FIELD
[] = "srcIPaddr";
72 const char ZEBRA_PTM_BFD_MIN_RX_FIELD
[] = "requiredMinRx";
73 const char ZEBRA_PTM_BFD_MIN_TX_FIELD
[] = "upMinTx";
74 const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD
[] = "detectMult";
75 const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD
[] = "multiHop";
76 const char ZEBRA_PTM_BFD_CLIENT_FIELD
[] = "client";
77 const char ZEBRA_PTM_BFD_SEQID_FIELD
[] = "seqid";
78 const char ZEBRA_PTM_BFD_IFNAME_FIELD
[] = "ifName";
79 const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD
[] = "maxHopCnt";
80 const char ZEBRA_PTM_BFD_SEND_EVENT
[] = "sendEvent";
81 const char ZEBRA_PTM_BFD_VRF_NAME_FIELD
[] = "vrfName";
83 static ptm_lib_handle_t
*ptm_hdl
;
85 struct zebra_ptm_cb ptm_cb
;
87 static int zebra_ptm_socket_init(void);
88 int zebra_ptm_sock_read(struct thread
*);
89 static void zebra_ptm_install_commands(void);
90 static int zebra_ptm_handle_msg_cb(void *arg
, void *in_ctxt
);
91 void zebra_bfd_peer_replay_req(void);
92 void zebra_ptm_send_status_req(void);
93 void zebra_ptm_reset_status(int ptm_disable
);
94 static int zebra_ptm_bfd_client_deregister(struct zserv
*client
);
96 const char ZEBRA_PTM_SOCK_NAME
[] = "\0/var/run/ptmd.socket";
98 void zebra_ptm_init(void)
102 memset(&ptm_cb
, 0, sizeof(struct zebra_ptm_cb
));
104 ptm_cb
.out_data
= calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF
);
105 if (!ptm_cb
.out_data
) {
106 zlog_warn("%s: Allocation of send data failed", __func__
);
110 ptm_cb
.in_data
= calloc(1, ZEBRA_PTM_MAX_SOCKBUF
);
111 if (!ptm_cb
.in_data
) {
112 zlog_warn("%s: Allocation of recv data failed", __func__
);
113 free(ptm_cb
.out_data
);
117 ptm_cb
.pid
= getpid();
118 zebra_ptm_install_commands();
120 sprintf(buf
, "%s", FRR_PTM_NAME
);
121 ptm_hdl
= ptm_lib_register(buf
, NULL
, zebra_ptm_handle_msg_cb
,
122 zebra_ptm_handle_msg_cb
);
123 ptm_cb
.wb
= buffer_new(0);
125 ptm_cb
.reconnect_time
= ZEBRA_PTM_RECONNECT_TIME_INITIAL
;
127 ptm_cb
.ptm_sock
= -1;
129 hook_register(zserv_client_close
, zebra_ptm_bfd_client_deregister
);
132 void zebra_ptm_finish(void)
134 buffer_flush_all(ptm_cb
.wb
, ptm_cb
.ptm_sock
);
139 free(ptm_cb
.out_data
);
142 free(ptm_cb
.in_data
);
144 /* Release threads. */
146 thread_cancel(ptm_cb
.t_read
);
148 thread_cancel(ptm_cb
.t_write
);
150 thread_cancel(ptm_cb
.t_timer
);
153 buffer_free(ptm_cb
.wb
);
155 if (ptm_cb
.ptm_sock
>= 0)
156 close(ptm_cb
.ptm_sock
);
159 static int zebra_ptm_flush_messages(struct thread
*thread
)
161 ptm_cb
.t_write
= NULL
;
163 if (ptm_cb
.ptm_sock
== -1)
168 switch (buffer_flush_available(ptm_cb
.wb
, ptm_cb
.ptm_sock
)) {
170 zlog_warn("%s ptm socket error: %s", __func__
,
171 safe_strerror(errno
));
172 close(ptm_cb
.ptm_sock
);
173 ptm_cb
.ptm_sock
= -1;
174 zebra_ptm_reset_status(0);
175 ptm_cb
.t_timer
= NULL
;
176 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
177 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
180 ptm_cb
.t_write
= NULL
;
181 thread_add_write(zebrad
.master
, zebra_ptm_flush_messages
, NULL
,
182 ptm_cb
.ptm_sock
, &ptm_cb
.t_write
);
191 static int zebra_ptm_send_message(char *data
, int size
)
194 switch (buffer_write(ptm_cb
.wb
, ptm_cb
.ptm_sock
, data
, size
)) {
196 zlog_warn("%s ptm socket error: %s", __func__
,
197 safe_strerror(errno
));
198 close(ptm_cb
.ptm_sock
);
199 ptm_cb
.ptm_sock
= -1;
200 zebra_ptm_reset_status(0);
201 ptm_cb
.t_timer
= NULL
;
202 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
203 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
206 THREAD_OFF(ptm_cb
.t_write
);
209 thread_add_write(zebrad
.master
, zebra_ptm_flush_messages
, NULL
,
210 ptm_cb
.ptm_sock
, &ptm_cb
.t_write
);
217 int zebra_ptm_connect(struct thread
*t
)
221 if (ptm_cb
.ptm_sock
== -1) {
222 zebra_ptm_socket_init();
226 if (ptm_cb
.ptm_sock
!= -1) {
228 ptm_cb
.t_read
= NULL
;
229 thread_add_read(zebrad
.master
, zebra_ptm_sock_read
,
230 NULL
, ptm_cb
.ptm_sock
, &ptm_cb
.t_read
);
231 zebra_bfd_peer_replay_req();
233 zebra_ptm_send_status_req();
234 ptm_cb
.reconnect_time
= ZEBRA_PTM_RECONNECT_TIME_INITIAL
;
235 } else if (ptm_cb
.reconnect_time
< ZEBRA_PTM_RECONNECT_TIME_MAX
) {
236 ptm_cb
.reconnect_time
*= 2;
237 if (ptm_cb
.reconnect_time
> ZEBRA_PTM_RECONNECT_TIME_MAX
)
238 ptm_cb
.reconnect_time
= ZEBRA_PTM_RECONNECT_TIME_MAX
;
240 ptm_cb
.t_timer
= NULL
;
241 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
242 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
243 } else if (ptm_cb
.reconnect_time
>= ZEBRA_PTM_RECONNECT_TIME_MAX
) {
244 ptm_cb
.reconnect_time
= ZEBRA_PTM_RECONNECT_TIME_INITIAL
;
250 DEFUN (zebra_ptm_enable
,
251 zebra_ptm_enable_cmd
,
253 "Enable neighbor check with specified topology\n")
256 struct interface
*ifp
;
257 struct zebra_if
*if_data
;
259 ptm_cb
.ptm_enable
= ZEBRA_IF_PTM_ENABLE_ON
;
261 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
)
262 FOR_ALL_INTERFACES (vrf
, ifp
)
263 if (!ifp
->ptm_enable
) {
264 if_data
= (struct zebra_if
*)ifp
->info
;
266 && (if_data
->ptm_enable
267 == ZEBRA_IF_PTM_ENABLE_UNSPEC
)) {
269 ZEBRA_IF_PTM_ENABLE_ON
;
271 /* Assign a default unknown status */
272 ifp
->ptm_status
= ZEBRA_PTM_STATUS_UNKNOWN
;
275 zebra_ptm_connect(NULL
);
280 DEFUN (no_zebra_ptm_enable
,
281 no_zebra_ptm_enable_cmd
,
284 "Enable neighbor check with specified topology\n")
286 ptm_cb
.ptm_enable
= ZEBRA_IF_PTM_ENABLE_OFF
;
287 zebra_ptm_reset_status(1);
291 DEFUN (zebra_ptm_enable_if
,
292 zebra_ptm_enable_if_cmd
,
294 "Enable neighbor check with specified topology\n")
296 VTY_DECLVAR_CONTEXT(interface
, ifp
);
297 struct zebra_if
*if_data
;
299 int send_linkdown
= 0;
302 if_data
->ptm_enable
= ZEBRA_IF_PTM_ENABLE_UNSPEC
;
304 if (ifp
->ifindex
== IFINDEX_INTERNAL
) {
308 old_ptm_enable
= ifp
->ptm_enable
;
309 ifp
->ptm_enable
= ptm_cb
.ptm_enable
;
311 if (if_is_no_ptm_operative(ifp
))
314 if (!old_ptm_enable
&& ptm_cb
.ptm_enable
) {
315 if (!if_is_operative(ifp
) && send_linkdown
) {
316 if (IS_ZEBRA_DEBUG_EVENT
)
317 zlog_debug("%s: Bringing down interface %s\n",
318 __func__
, ifp
->name
);
326 DEFUN (no_zebra_ptm_enable_if
,
327 no_zebra_ptm_enable_if_cmd
,
330 "Enable neighbor check with specified topology\n")
332 VTY_DECLVAR_CONTEXT(interface
, ifp
);
334 struct zebra_if
*if_data
;
336 if ((ifp
->ifindex
!= IFINDEX_INTERNAL
) && (ifp
->ptm_enable
)) {
337 if (!if_is_operative(ifp
))
340 ifp
->ptm_enable
= ZEBRA_IF_PTM_ENABLE_OFF
;
341 if (if_is_no_ptm_operative(ifp
) && send_linkup
) {
342 if (IS_ZEBRA_DEBUG_EVENT
)
343 zlog_debug("%s: Bringing up interface %s\n",
344 __func__
, ifp
->name
);
350 if_data
->ptm_enable
= ZEBRA_IF_PTM_ENABLE_OFF
;
356 void zebra_ptm_write(struct vty
*vty
)
358 if (ptm_cb
.ptm_enable
)
359 vty_out(vty
, "ptm-enable\n");
364 static int zebra_ptm_socket_init(void)
368 struct sockaddr_un addr
;
370 ptm_cb
.ptm_sock
= -1;
372 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
375 if (set_nonblocking(sock
) < 0) {
376 if (IS_ZEBRA_DEBUG_EVENT
)
377 zlog_debug("%s: Unable to set socket non blocking[%s]",
378 __PRETTY_FUNCTION__
, safe_strerror(errno
));
383 /* Make server socket. */
384 memset(&addr
, 0, sizeof(struct sockaddr_un
));
385 addr
.sun_family
= AF_UNIX
;
386 memcpy(&addr
.sun_path
, ZEBRA_PTM_SOCK_NAME
,
387 sizeof(ZEBRA_PTM_SOCK_NAME
));
389 ret
= connect(sock
, (struct sockaddr
*)&addr
,
390 sizeof(addr
.sun_family
) + sizeof(ZEBRA_PTM_SOCK_NAME
)
393 if (IS_ZEBRA_DEBUG_EVENT
)
394 zlog_debug("%s: Unable to connect to socket %s [%s]",
395 __func__
, ZEBRA_PTM_SOCK_NAME
,
396 safe_strerror(errno
));
400 ptm_cb
.ptm_sock
= sock
;
404 static void zebra_ptm_install_commands(void)
406 install_element(CONFIG_NODE
, &zebra_ptm_enable_cmd
);
407 install_element(CONFIG_NODE
, &no_zebra_ptm_enable_cmd
);
408 install_element(INTERFACE_NODE
, &zebra_ptm_enable_if_cmd
);
409 install_element(INTERFACE_NODE
, &no_zebra_ptm_enable_if_cmd
);
412 /* BFD session goes down, send message to the protocols. */
413 static void if_bfd_session_update(struct interface
*ifp
, struct prefix
*dp
,
414 struct prefix
*sp
, int status
,
417 if (IS_ZEBRA_DEBUG_EVENT
) {
418 char buf
[2][INET6_ADDRSTRLEN
];
422 "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s"
424 inet_ntop(dp
->family
, &dp
->u
.prefix
, buf
[0],
426 dp
->prefixlen
, ifp
->name
,
427 bfd_get_status_str(status
));
430 "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d "
431 "with src %s/%d and vrf %u %s event",
432 inet_ntop(dp
->family
, &dp
->u
.prefix
, buf
[0],
435 inet_ntop(sp
->family
, &sp
->u
.prefix
, buf
[1],
437 sp
->prefixlen
, vrf_id
,
438 bfd_get_status_str(status
));
442 zebra_interface_bfd_update(ifp
, dp
, sp
, status
, vrf_id
);
445 static int zebra_ptm_handle_bfd_msg(void *arg
, void *in_ctxt
,
446 struct interface
*ifp
)
452 struct prefix dest_prefix
;
453 struct prefix src_prefix
;
456 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_BFDSTATUS_STR
, bfdst_str
);
458 if (bfdst_str
[0] == '\0') {
462 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_BFDDEST_STR
, dest_str
);
464 if (dest_str
[0] == '\0') {
465 zlog_debug("%s: Key %s not found in PTM msg", __func__
,
466 ZEBRA_PTM_BFDDEST_STR
);
470 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_BFDSRC_STR
, src_str
);
472 if (src_str
[0] == '\0') {
473 zlog_debug("%s: Key %s not found in PTM msg", __func__
,
474 ZEBRA_PTM_BFDSRC_STR
);
478 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_BFDVRF_STR
, vrf_str
);
480 if (vrf_str
[0] == '\0') {
481 zlog_debug("%s: Key %s not found in PTM msg", __func__
,
482 ZEBRA_PTM_BFDVRF_STR
);
486 if (IS_ZEBRA_DEBUG_EVENT
)
488 "%s: Recv Port [%s] bfd status [%s] vrf [%s]"
489 " peer [%s] local [%s]",
490 __func__
, ifp
? ifp
->name
: "N/A", bfdst_str
, vrf_str
,
493 if (str2prefix(dest_str
, &dest_prefix
) == 0) {
494 zlog_err("%s: Peer addr %s not found", __func__
, dest_str
);
498 memset(&src_prefix
, 0, sizeof(struct prefix
));
499 if (strcmp(ZEBRA_PTM_INVALID_SRC_IP
, src_str
)) {
500 if (str2prefix(src_str
, &src_prefix
) == 0) {
501 zlog_err("%s: Local addr %s not found", __func__
,
507 if (!strcmp(ZEBRA_PTM_INVALID_VRF
, vrf_str
) && ifp
) {
508 vrf_id
= ifp
->vrf_id
;
510 vrf_id
= vrf_name_to_id(vrf_str
);
513 if (!strcmp(bfdst_str
, ZEBRA_PTM_BFDSTATUS_DOWN_STR
)) {
514 if_bfd_session_update(ifp
, &dest_prefix
, &src_prefix
,
515 BFD_STATUS_DOWN
, vrf_id
);
517 if_bfd_session_update(ifp
, &dest_prefix
, &src_prefix
,
518 BFD_STATUS_UP
, vrf_id
);
524 static int zebra_ptm_handle_cbl_msg(void *arg
, void *in_ctxt
,
525 struct interface
*ifp
, char *cbl_str
)
529 if (IS_ZEBRA_DEBUG_EVENT
)
530 zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__
,
533 if (!strcmp(cbl_str
, ZEBRA_PTM_PASS_STR
)
534 && (ifp
->ptm_status
!= ZEBRA_PTM_STATUS_UP
)) {
536 if (ifp
->ptm_status
== ZEBRA_PTM_STATUS_DOWN
)
538 ifp
->ptm_status
= ZEBRA_PTM_STATUS_UP
;
539 if (ifp
->ptm_enable
&& if_is_no_ptm_operative(ifp
)
542 } else if (!strcmp(cbl_str
, ZEBRA_PTM_FAIL_STR
)
543 && (ifp
->ptm_status
!= ZEBRA_PTM_STATUS_DOWN
)) {
544 ifp
->ptm_status
= ZEBRA_PTM_STATUS_DOWN
;
545 if (ifp
->ptm_enable
&& if_is_no_ptm_operative(ifp
))
553 * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle
554 * all the command responses and notifications received from PTM.
556 * Command responses: Upon establishing connection with PTM, Zebra requests
557 * status of all interfaces using 'get-status' command if global ptm-enable
558 * knob is enabled. As a response to the get-status command PTM sends status
559 * of all the interfaces as command responses. All other type of command
560 * responses with cmd_status key word are dropped. The sole purpose of
561 * registering this function as callback for the command responses is to
562 * handle the responses to get-status command.
564 * Notifications: Cable status and BFD session status changes are sent as
565 * notifications by PTM. So, this function is also the callback function for
566 * processing all the notifications from the PTM.
569 static int zebra_ptm_handle_msg_cb(void *arg
, void *in_ctxt
)
571 struct interface
*ifp
= NULL
;
574 char cmd_status_str
[32];
576 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_CMD_STATUS_STR
,
579 /* Drop command response messages */
580 if (cmd_status_str
[0] != '\0') {
584 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_PORT_STR
, port_str
);
586 if (port_str
[0] == '\0') {
587 zlog_debug("%s: Key %s not found in PTM msg", __func__
,
592 if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME
, port_str
)) {
593 ifp
= if_lookup_by_name_all_vrf(port_str
);
596 zlog_err("%s: %s not found in interface list", __func__
,
602 ptm_lib_find_key_in_msg(in_ctxt
, ZEBRA_PTM_CBL_STR
, cbl_str
);
604 if (cbl_str
[0] == '\0') {
605 return zebra_ptm_handle_bfd_msg(arg
, in_ctxt
, ifp
);
608 return zebra_ptm_handle_cbl_msg(arg
, in_ctxt
, ifp
,
616 int zebra_ptm_sock_read(struct thread
*thread
)
622 sock
= THREAD_FD(thread
);
627 /* PTM communicates in CSV format */
629 rc
= ptm_lib_process_msg(ptm_hdl
, sock
, ptm_cb
.in_data
,
630 ZEBRA_PTM_MAX_SOCKBUF
, NULL
);
633 if (((rc
== 0) && !errno
)
634 || (errno
&& (errno
!= EWOULDBLOCK
) && (errno
!= EAGAIN
))) {
635 zlog_warn("%s routing socket error: %s(%d) bytes %d",
636 __func__
, safe_strerror(errno
), errno
, rc
);
638 close(ptm_cb
.ptm_sock
);
639 ptm_cb
.ptm_sock
= -1;
640 zebra_ptm_reset_status(0);
641 ptm_cb
.t_timer
= NULL
;
642 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
643 ptm_cb
.reconnect_time
,
648 ptm_cb
.t_read
= NULL
;
649 thread_add_read(zebrad
.master
, zebra_ptm_sock_read
, NULL
,
650 ptm_cb
.ptm_sock
, &ptm_cb
.t_read
);
655 /* BFD peer/dst register/update */
656 void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS
)
662 uint8_t multi_hop_cnt
;
664 unsigned int min_rx_timer
;
665 unsigned int min_tx_timer
;
666 char if_name
[INTERFACE_NAMSIZ
];
669 char buf
[INET6_ADDRSTRLEN
];
671 int data_len
= ZEBRA_PTM_SEND_MAX_SOCKBUF
;
674 if (hdr
->command
== ZEBRA_BFD_DEST_UPDATE
)
675 client
->bfd_peer_upd8_cnt
++;
677 client
->bfd_peer_add_cnt
++;
679 if (IS_ZEBRA_DEBUG_EVENT
)
680 zlog_debug("bfd_dst_register msg from client %s: length=%d",
681 zebra_route_string(client
->proto
), hdr
->length
);
683 if (ptm_cb
.ptm_sock
== -1) {
684 ptm_cb
.t_timer
= NULL
;
685 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
686 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
690 ptm_lib_init_msg(ptm_hdl
, 0, PTMLIB_MSG_TYPE_CMD
, NULL
, &out_ctxt
);
691 sprintf(tmp_buf
, "%s", ZEBRA_PTM_BFD_START_CMD
);
692 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_CMD_STR
, tmp_buf
);
693 sprintf(tmp_buf
, "%s", zebra_route_string(client
->proto
));
694 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_CLIENT_FIELD
,
700 sprintf(tmp_buf
, "%d", pid
);
701 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_SEQID_FIELD
,
704 STREAM_GETW(s
, dst_p
.family
);
706 if (dst_p
.family
== AF_INET
)
707 dst_p
.prefixlen
= IPV4_MAX_BYTELEN
;
709 dst_p
.prefixlen
= IPV6_MAX_BYTELEN
;
711 STREAM_GET(&dst_p
.u
.prefix
, s
, dst_p
.prefixlen
);
712 if (dst_p
.family
== AF_INET
) {
713 inet_ntop(AF_INET
, &dst_p
.u
.prefix4
, buf
, sizeof(buf
));
714 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
715 ZEBRA_PTM_BFD_DST_IP_FIELD
, buf
);
717 inet_ntop(AF_INET6
, &dst_p
.u
.prefix6
, buf
, sizeof(buf
));
718 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
719 ZEBRA_PTM_BFD_DST_IP_FIELD
, buf
);
722 STREAM_GETL(s
, min_rx_timer
);
723 sprintf(tmp_buf
, "%d", min_rx_timer
);
724 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_MIN_RX_FIELD
,
726 STREAM_GETL(s
, min_tx_timer
);
727 sprintf(tmp_buf
, "%d", min_tx_timer
);
728 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_MIN_TX_FIELD
,
730 STREAM_GETC(s
, detect_mul
);
731 sprintf(tmp_buf
, "%d", detect_mul
);
732 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_DETECT_MULT_FIELD
,
735 STREAM_GETC(s
, multi_hop
);
737 sprintf(tmp_buf
, "%d", 1);
738 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
739 ZEBRA_PTM_BFD_MULTI_HOP_FIELD
, tmp_buf
);
740 STREAM_GETW(s
, src_p
.family
);
742 if (src_p
.family
== AF_INET
)
743 src_p
.prefixlen
= IPV4_MAX_BYTELEN
;
745 src_p
.prefixlen
= IPV6_MAX_BYTELEN
;
747 STREAM_GET(&src_p
.u
.prefix
, s
, src_p
.prefixlen
);
748 if (src_p
.family
== AF_INET
) {
749 inet_ntop(AF_INET
, &src_p
.u
.prefix4
, buf
, sizeof(buf
));
750 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
751 ZEBRA_PTM_BFD_SRC_IP_FIELD
, buf
);
753 inet_ntop(AF_INET6
, &src_p
.u
.prefix6
, buf
, sizeof(buf
));
754 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
755 ZEBRA_PTM_BFD_SRC_IP_FIELD
, buf
);
758 STREAM_GETC(s
, multi_hop_cnt
);
759 sprintf(tmp_buf
, "%d", multi_hop_cnt
);
760 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
761 ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD
, tmp_buf
);
763 if (zvrf_id(zvrf
) != VRF_DEFAULT
)
764 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
765 ZEBRA_PTM_BFD_VRF_NAME_FIELD
,
768 if (dst_p
.family
== AF_INET6
) {
769 STREAM_GETW(s
, src_p
.family
);
771 if (src_p
.family
== AF_INET
)
772 src_p
.prefixlen
= IPV4_MAX_BYTELEN
;
774 src_p
.prefixlen
= IPV6_MAX_BYTELEN
;
776 STREAM_GET(&src_p
.u
.prefix
, s
, src_p
.prefixlen
);
777 if (src_p
.family
== AF_INET
) {
778 inet_ntop(AF_INET
, &src_p
.u
.prefix4
, buf
,
780 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
781 ZEBRA_PTM_BFD_SRC_IP_FIELD
,
784 inet_ntop(AF_INET6
, &src_p
.u
.prefix6
, buf
,
786 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
787 ZEBRA_PTM_BFD_SRC_IP_FIELD
,
792 STREAM_GET(if_name
, s
, len
);
795 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
796 ZEBRA_PTM_BFD_IFNAME_FIELD
, if_name
);
799 sprintf(tmp_buf
, "%d", 1);
800 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_SEND_EVENT
,
803 ptm_lib_complete_msg(ptm_hdl
, out_ctxt
, ptm_cb
.out_data
, &data_len
);
805 if (IS_ZEBRA_DEBUG_SEND
)
806 zlog_debug("%s: Sent message (%d) %s", __func__
, data_len
,
808 zebra_ptm_send_message(ptm_cb
.out_data
, data_len
);
813 ptm_lib_cleanup_msg(ptm_hdl
, out_ctxt
);
816 /* BFD peer/dst deregister */
817 void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS
)
823 char if_name
[INTERFACE_NAMSIZ
];
825 char buf
[INET6_ADDRSTRLEN
];
827 int data_len
= ZEBRA_PTM_SEND_MAX_SOCKBUF
;
831 client
->bfd_peer_del_cnt
++;
833 if (IS_ZEBRA_DEBUG_EVENT
)
834 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
835 zebra_route_string(client
->proto
), hdr
->length
);
837 if (ptm_cb
.ptm_sock
== -1) {
838 ptm_cb
.t_timer
= NULL
;
839 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
840 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
844 ptm_lib_init_msg(ptm_hdl
, 0, PTMLIB_MSG_TYPE_CMD
, NULL
, &out_ctxt
);
846 sprintf(tmp_buf
, "%s", ZEBRA_PTM_BFD_STOP_CMD
);
847 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_CMD_STR
, tmp_buf
);
849 sprintf(tmp_buf
, "%s", zebra_route_string(client
->proto
));
850 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_CLIENT_FIELD
,
856 sprintf(tmp_buf
, "%d", pid
);
857 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_SEQID_FIELD
,
860 STREAM_GETW(s
, dst_p
.family
);
862 if (dst_p
.family
== AF_INET
)
863 dst_p
.prefixlen
= IPV4_MAX_BYTELEN
;
865 dst_p
.prefixlen
= IPV6_MAX_BYTELEN
;
867 STREAM_GET(&dst_p
.u
.prefix
, s
, dst_p
.prefixlen
);
868 if (dst_p
.family
== AF_INET
)
869 inet_ntop(AF_INET
, &dst_p
.u
.prefix4
, buf
, sizeof(buf
));
871 inet_ntop(AF_INET6
, &dst_p
.u
.prefix6
, buf
, sizeof(buf
));
872 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_DST_IP_FIELD
, buf
);
875 STREAM_GETC(s
, multi_hop
);
877 sprintf(tmp_buf
, "%d", 1);
878 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
879 ZEBRA_PTM_BFD_MULTI_HOP_FIELD
, tmp_buf
);
881 STREAM_GETW(s
, src_p
.family
);
883 if (src_p
.family
== AF_INET
)
884 src_p
.prefixlen
= IPV4_MAX_BYTELEN
;
886 src_p
.prefixlen
= IPV6_MAX_BYTELEN
;
888 STREAM_GET(&src_p
.u
.prefix
, s
, src_p
.prefixlen
);
889 if (src_p
.family
== AF_INET
)
890 inet_ntop(AF_INET
, &src_p
.u
.prefix4
, buf
, sizeof(buf
));
892 inet_ntop(AF_INET6
, &src_p
.u
.prefix6
, buf
, sizeof(buf
));
893 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
894 ZEBRA_PTM_BFD_SRC_IP_FIELD
, buf
);
896 if (zvrf_id(zvrf
) != VRF_DEFAULT
)
897 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
898 ZEBRA_PTM_BFD_VRF_NAME_FIELD
,
901 if (dst_p
.family
== AF_INET6
) {
902 STREAM_GETW(s
, src_p
.family
);
904 if (src_p
.family
== AF_INET
)
905 src_p
.prefixlen
= IPV4_MAX_BYTELEN
;
907 src_p
.prefixlen
= IPV6_MAX_BYTELEN
;
909 STREAM_GET(&src_p
.u
.prefix
, s
, src_p
.prefixlen
);
910 if (src_p
.family
== AF_INET
) {
911 inet_ntop(AF_INET
, &src_p
.u
.prefix4
, buf
,
913 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
914 ZEBRA_PTM_BFD_SRC_IP_FIELD
,
917 inet_ntop(AF_INET6
, &src_p
.u
.prefix6
, buf
,
919 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
920 ZEBRA_PTM_BFD_SRC_IP_FIELD
,
926 STREAM_GET(if_name
, s
, len
);
929 ptm_lib_append_msg(ptm_hdl
, out_ctxt
,
930 ZEBRA_PTM_BFD_IFNAME_FIELD
, if_name
);
933 ptm_lib_complete_msg(ptm_hdl
, out_ctxt
, ptm_cb
.out_data
, &data_len
);
934 if (IS_ZEBRA_DEBUG_SEND
)
935 zlog_debug("%s: Sent message (%d) %s", __func__
, data_len
,
938 zebra_ptm_send_message(ptm_cb
.out_data
, data_len
);
943 ptm_lib_cleanup_msg(ptm_hdl
, out_ctxt
);
946 /* BFD client register */
947 void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS
)
951 void *out_ctxt
= NULL
;
953 int data_len
= ZEBRA_PTM_SEND_MAX_SOCKBUF
;
955 client
->bfd_client_reg_cnt
++;
957 if (IS_ZEBRA_DEBUG_EVENT
)
958 zlog_debug("bfd_client_register msg from client %s: length=%d",
959 zebra_route_string(client
->proto
), hdr
->length
);
964 if (ptm_cb
.ptm_sock
== -1) {
965 ptm_cb
.t_timer
= NULL
;
966 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
967 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
971 ptm_lib_init_msg(ptm_hdl
, 0, PTMLIB_MSG_TYPE_CMD
, NULL
, &out_ctxt
);
973 sprintf(tmp_buf
, "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD
);
974 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_CMD_STR
, tmp_buf
);
976 sprintf(tmp_buf
, "%s", zebra_route_string(client
->proto
));
977 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_CLIENT_FIELD
,
980 sprintf(tmp_buf
, "%d", pid
);
981 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_SEQID_FIELD
,
984 ptm_lib_complete_msg(ptm_hdl
, out_ctxt
, ptm_cb
.out_data
, &data_len
);
986 if (IS_ZEBRA_DEBUG_SEND
)
987 zlog_debug("%s: Sent message (%d) %s", __func__
, data_len
,
989 zebra_ptm_send_message(ptm_cb
.out_data
, data_len
);
991 SET_FLAG(ptm_cb
.client_flags
[client
->proto
],
992 ZEBRA_PTM_BFD_CLIENT_FLAG_REG
);
998 * IF we ever add more STREAM_GETXXX functions after the out_ctxt
999 * is allocated then we need to add this code back in
1002 * ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
1007 /* BFD client deregister */
1008 int zebra_ptm_bfd_client_deregister(struct zserv
*client
)
1010 uint8_t proto
= client
->proto
;
1013 int data_len
= ZEBRA_PTM_SEND_MAX_SOCKBUF
;
1015 if (proto
!= ZEBRA_ROUTE_OSPF
&& proto
!= ZEBRA_ROUTE_BGP
1016 && proto
!= ZEBRA_ROUTE_OSPF6
&& proto
!= ZEBRA_ROUTE_PIM
)
1019 if (IS_ZEBRA_DEBUG_EVENT
)
1020 zlog_err("bfd_client_deregister msg for client %s",
1021 zebra_route_string(proto
));
1023 if (ptm_cb
.ptm_sock
== -1) {
1024 ptm_cb
.t_timer
= NULL
;
1025 thread_add_timer(zebrad
.master
, zebra_ptm_connect
, NULL
,
1026 ptm_cb
.reconnect_time
, &ptm_cb
.t_timer
);
1030 ptm_lib_init_msg(ptm_hdl
, 0, PTMLIB_MSG_TYPE_CMD
, NULL
, &out_ctxt
);
1032 sprintf(tmp_buf
, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD
);
1033 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_CMD_STR
, tmp_buf
);
1035 sprintf(tmp_buf
, "%s", zebra_route_string(proto
));
1036 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_BFD_CLIENT_FIELD
,
1039 ptm_lib_complete_msg(ptm_hdl
, out_ctxt
, ptm_cb
.out_data
, &data_len
);
1041 if (IS_ZEBRA_DEBUG_SEND
)
1042 zlog_debug("%s: Sent message (%d) %s", __func__
, data_len
,
1045 zebra_ptm_send_message(ptm_cb
.out_data
, data_len
);
1046 UNSET_FLAG(ptm_cb
.client_flags
[proto
], ZEBRA_PTM_BFD_CLIENT_FLAG_REG
);
1051 int zebra_ptm_get_enable_state(void)
1053 return ptm_cb
.ptm_enable
;
1057 * zebra_ptm_get_status_str - Convert status to a display string.
1059 static const char *zebra_ptm_get_status_str(int status
)
1062 case ZEBRA_PTM_STATUS_DOWN
:
1064 case ZEBRA_PTM_STATUS_UP
:
1066 case ZEBRA_PTM_STATUS_UNKNOWN
:
1072 void zebra_ptm_show_status(struct vty
*vty
, struct interface
*ifp
)
1074 vty_out(vty
, " PTM status: ");
1075 if (ifp
->ptm_enable
) {
1076 vty_out(vty
, "%s\n", zebra_ptm_get_status_str(ifp
->ptm_status
));
1078 vty_out(vty
, "disabled\n");
1082 void zebra_ptm_send_status_req(void)
1085 int len
= ZEBRA_PTM_SEND_MAX_SOCKBUF
;
1087 if (ptm_cb
.ptm_enable
) {
1088 ptm_lib_init_msg(ptm_hdl
, 0, PTMLIB_MSG_TYPE_CMD
, NULL
,
1090 ptm_lib_append_msg(ptm_hdl
, out_ctxt
, ZEBRA_PTM_CMD_STR
,
1091 ZEBRA_PTM_GET_STATUS_CMD
);
1092 ptm_lib_complete_msg(ptm_hdl
, out_ctxt
, ptm_cb
.out_data
, &len
);
1094 zebra_ptm_send_message(ptm_cb
.out_data
, len
);
1098 void zebra_ptm_reset_status(int ptm_disable
)
1101 struct interface
*ifp
;
1104 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
)
1105 FOR_ALL_INTERFACES (vrf
, ifp
) {
1107 if (ifp
->ptm_enable
) {
1108 if (!if_is_operative(ifp
))
1113 ZEBRA_IF_PTM_ENABLE_OFF
;
1114 ifp
->ptm_status
= ZEBRA_PTM_STATUS_UNKNOWN
;
1116 if (if_is_operative(ifp
) && send_linkup
) {
1117 if (IS_ZEBRA_DEBUG_EVENT
)
1119 "%s: Bringing up interface %s",
1120 __func__
, ifp
->name
);
1127 void zebra_ptm_if_init(struct zebra_if
*zebra_ifp
)
1129 zebra_ifp
->ptm_enable
= ZEBRA_IF_PTM_ENABLE_UNSPEC
;
1132 void zebra_ptm_if_set_ptm_state(struct interface
*ifp
,
1133 struct zebra_if
*zebra_ifp
)
1135 if (zebra_ifp
&& zebra_ifp
->ptm_enable
!= ZEBRA_IF_PTM_ENABLE_UNSPEC
)
1136 ifp
->ptm_enable
= zebra_ifp
->ptm_enable
;
1139 void zebra_ptm_if_write(struct vty
*vty
, struct zebra_if
*zebra_ifp
)
1141 if (zebra_ifp
->ptm_enable
== ZEBRA_IF_PTM_ENABLE_OFF
)
1142 vty_out(vty
, " no ptm-enable\n");