]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_ptm.c
*: make consistent & update GPLv2 file headers
[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 #include <sys/un.h> /* for sockaddr_un */
23 #include <net/if.h>
24 #include "vty.h"
25 #include "zebra/zserv.h"
26 #include "zebra/interface.h"
27 #include "zebra/debug.h"
28 #include "zebra/zebra_ptm.h"
29 #include "if.h"
30 #include "command.h"
31 #include "stream.h"
32 #include "ptm_lib.h"
33 #include "network.h"
34 #include "buffer.h"
35 #include "zebra/zebra_ptm_redistribute.h"
36 #include "bfd.h"
37 #include "vrf.h"
38 #include "rib.h"
39 #include "zebra_vrf.h"
40 #include "version.h"
41
42 #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
43 #define ZEBRA_PTM_RECONNECT_TIME_MAX 300
44
45 #define PTM_MSG_LEN 4
46 #define PTM_HEADER_LEN 37
47
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";
53
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";
69
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";
82
83 static ptm_lib_handle_t *ptm_hdl;
84
85 struct zebra_ptm_cb ptm_cb;
86
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
95 const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
96
97 void
98 zebra_ptm_init (void)
99 {
100 char buf[64];
101
102 memset(&ptm_cb, 0, sizeof(struct zebra_ptm_cb));
103
104 ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
105 if (!ptm_cb.out_data)
106 {
107 zlog_warn("%s: Allocation of send data failed", __func__);
108 return;
109 }
110
111 ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
112 if (!ptm_cb.in_data)
113 {
114 zlog_warn("%s: Allocation of recv data failed", __func__);
115 free(ptm_cb.out_data);
116 return;
117 }
118
119 ptm_cb.pid = getpid();
120 zebra_ptm_install_commands();
121
122 sprintf(buf, "%s", FRR_PTM_NAME);
123 ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb,
124 zebra_ptm_handle_msg_cb);
125 ptm_cb.wb = buffer_new(0);
126
127 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
128
129 ptm_cb.ptm_sock = -1;
130 }
131
132 void
133 zebra_ptm_finish(void)
134 {
135 int proto;
136
137 for (proto = 0; proto < ZEBRA_ROUTE_MAX; proto++)
138 if (CHECK_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG))
139 zebra_ptm_bfd_client_deregister(proto);
140
141 buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock);
142
143 free (ptm_hdl);
144
145 if (ptm_cb.out_data)
146 free(ptm_cb.out_data);
147
148 if (ptm_cb.in_data)
149 free(ptm_cb.in_data);
150
151 /* Release threads. */
152 if (ptm_cb.t_read)
153 thread_cancel (ptm_cb.t_read);
154 if (ptm_cb.t_write)
155 thread_cancel (ptm_cb.t_write);
156 if (ptm_cb.t_timer)
157 thread_cancel (ptm_cb.t_timer);
158
159 if (ptm_cb.wb)
160 buffer_free(ptm_cb.wb);
161
162 if (ptm_cb.ptm_sock != -1)
163 close(ptm_cb.ptm_sock);
164 }
165
166 static int
167 zebra_ptm_flush_messages (struct thread *thread)
168 {
169 ptm_cb.t_write = NULL;
170
171 if (ptm_cb.ptm_sock == -1)
172 return -1;
173
174 errno = 0;
175
176 switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock))
177 {
178 case BUFFER_ERROR:
179 zlog_warn ("%s ptm socket error: %s", __func__,
180 safe_strerror (errno));
181 close(ptm_cb.ptm_sock);
182 ptm_cb.ptm_sock = -1;
183 zebra_ptm_reset_status(0);
184 ptm_cb.t_timer = NULL;
185 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
186 &ptm_cb.t_timer);
187 return (-1);
188 case BUFFER_PENDING:
189 ptm_cb.t_write = NULL;
190 thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock,
191 &ptm_cb.t_write);
192 break;
193 case BUFFER_EMPTY:
194 break;
195 }
196
197 return(0);
198 }
199
200 static int
201 zebra_ptm_send_message(char *data, int size)
202 {
203 errno = 0;
204 switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size))
205 {
206 case BUFFER_ERROR:
207 zlog_warn ("%s ptm socket error: %s", __func__, safe_strerror (errno));
208 close(ptm_cb.ptm_sock);
209 ptm_cb.ptm_sock = -1;
210 zebra_ptm_reset_status(0);
211 ptm_cb.t_timer = NULL;
212 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
213 &ptm_cb.t_timer);
214 return -1;
215 case BUFFER_EMPTY:
216 THREAD_OFF(ptm_cb.t_write);
217 break;
218 case BUFFER_PENDING:
219 thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL,
220 ptm_cb.ptm_sock, &ptm_cb.t_write);
221 break;
222 }
223
224 return 0;
225 }
226
227 int
228 zebra_ptm_connect (struct thread *t)
229 {
230 int init = 0;
231
232 if (ptm_cb.ptm_sock == -1) {
233 zebra_ptm_socket_init();
234 init = 1;
235 }
236
237 if (ptm_cb.ptm_sock != -1) {
238 if (init) {
239 ptm_cb.t_read = NULL;
240 thread_add_read(zebrad.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock,
241 &ptm_cb.t_read);
242 zebra_bfd_peer_replay_req();
243 }
244 zebra_ptm_send_status_req();
245 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
246 } else if (ptm_cb.reconnect_time < ZEBRA_PTM_RECONNECT_TIME_MAX){
247 ptm_cb.reconnect_time *= 2;
248 if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
249 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
250
251 ptm_cb.t_timer = NULL;
252 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
253 &ptm_cb.t_timer);
254 } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX){
255 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
256 }
257
258 return(errno);
259 }
260
261 DEFUN (zebra_ptm_enable,
262 zebra_ptm_enable_cmd,
263 "ptm-enable",
264 "Enable neighbor check with specified topology\n")
265 {
266 struct vrf *vrf;
267 struct listnode *i;
268 struct interface *ifp;
269 struct zebra_if *if_data;
270
271 ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
272
273 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
274 for (ALL_LIST_ELEMENTS_RO (vrf->iflist, i, ifp))
275 if (!ifp->ptm_enable)
276 {
277 if_data = (struct zebra_if *)ifp->info;
278 if (if_data &&
279 (if_data->ptm_enable == ZEBRA_IF_PTM_ENABLE_UNSPEC))
280 {
281 ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
282 }
283 /* Assign a default unknown status */
284 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
285 }
286
287 zebra_ptm_connect(NULL);
288
289 return CMD_SUCCESS;
290 }
291
292 DEFUN (no_zebra_ptm_enable,
293 no_zebra_ptm_enable_cmd,
294 "no ptm-enable",
295 NO_STR
296 "Enable neighbor check with specified topology\n")
297 {
298 ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
299 zebra_ptm_reset_status(1);
300 return CMD_SUCCESS;
301 }
302
303 DEFUN (zebra_ptm_enable_if,
304 zebra_ptm_enable_if_cmd,
305 "ptm-enable",
306 "Enable neighbor check with specified topology\n")
307 {
308 VTY_DECLVAR_CONTEXT (interface, ifp);
309 struct zebra_if *if_data;
310 int old_ptm_enable;
311 int send_linkdown = 0;
312
313 if (ifp->ifindex == IFINDEX_INTERNAL)
314 {
315 return CMD_SUCCESS;
316 }
317
318 old_ptm_enable = ifp->ptm_enable;
319 ifp->ptm_enable = ptm_cb.ptm_enable;
320
321 if (if_is_no_ptm_operative(ifp))
322 send_linkdown = 1;
323
324 if (!old_ptm_enable && ptm_cb.ptm_enable)
325 {
326 if (!if_is_operative (ifp) && send_linkdown)
327 {
328 if (IS_ZEBRA_DEBUG_EVENT)
329 zlog_debug ("%s: Bringing down interface %s\n", __func__,
330 ifp->name);
331 if_down (ifp);
332 }
333 }
334
335 if_data = ifp->info;
336 if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
337
338 return CMD_SUCCESS;
339 }
340
341 DEFUN (no_zebra_ptm_enable_if,
342 no_zebra_ptm_enable_if_cmd,
343 "no ptm-enable",
344 NO_STR
345 "Enable neighbor check with specified topology\n")
346 {
347 VTY_DECLVAR_CONTEXT (interface, ifp);
348 int send_linkup = 0;
349 struct zebra_if *if_data;
350
351 if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable))
352 {
353 if (!if_is_operative(ifp))
354 send_linkup = 1;
355
356 ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
357 if (if_is_no_ptm_operative (ifp) && send_linkup)
358 {
359 if (IS_ZEBRA_DEBUG_EVENT)
360 zlog_debug ("%s: Bringing up interface %s\n", __func__,
361 ifp->name);
362 if_up (ifp);
363 }
364 }
365
366 if_data = ifp->info;
367 if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
368
369 return CMD_SUCCESS;
370 }
371
372
373 void
374 zebra_ptm_write (struct vty *vty)
375 {
376 if (ptm_cb.ptm_enable)
377 vty_out (vty, "ptm-enable%s", VTY_NEWLINE);
378
379 return;
380 }
381
382 static int
383 zebra_ptm_socket_init (void)
384 {
385 int ret;
386 int sock;
387 struct sockaddr_un addr;
388
389 ptm_cb.ptm_sock = -1;
390
391 sock = socket (PF_UNIX, SOCK_STREAM, 0);
392 if (sock < 0)
393 return -1;
394 if (set_nonblocking(sock) < 0)
395 {
396 if (IS_ZEBRA_DEBUG_EVENT)
397 zlog_debug ("%s: Unable to set socket non blocking[%s]",
398 __PRETTY_FUNCTION__, safe_strerror (errno));
399 close (sock);
400 return -1;
401 }
402
403 /* Make server socket. */
404 memset (&addr, 0, sizeof (struct sockaddr_un));
405 addr.sun_family = AF_UNIX;
406 memcpy (&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
407 sizeof(ZEBRA_PTM_SOCK_NAME));
408
409 ret = connect(sock, (struct sockaddr *) &addr,
410 sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1);
411 if (ret < 0)
412 {
413 if (IS_ZEBRA_DEBUG_EVENT)
414 zlog_debug("%s: Unable to connect to socket %s [%s]",
415 __func__, ZEBRA_PTM_SOCK_NAME, safe_strerror(errno));
416 close (sock);
417 return -1;
418 }
419 ptm_cb.ptm_sock = sock;
420 return sock;
421 }
422
423 static void
424 zebra_ptm_install_commands (void)
425 {
426 install_element (CONFIG_NODE, &zebra_ptm_enable_cmd);
427 install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd);
428 install_element (INTERFACE_NODE, &zebra_ptm_enable_if_cmd);
429 install_element (INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd);
430 }
431
432 /* BFD session goes down, send message to the protocols. */
433 static void
434 if_bfd_session_update (struct interface *ifp, struct prefix *dp,
435 struct prefix *sp, int status, vrf_id_t vrf_id)
436 {
437 if (IS_ZEBRA_DEBUG_EVENT)
438 {
439 char buf[2][INET6_ADDRSTRLEN];
440
441 if (ifp)
442 {
443 zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s"
444 " %s event",
445 inet_ntop (dp->family, &dp->u.prefix, buf[0],
446 INET6_ADDRSTRLEN), dp->prefixlen, ifp->name,
447 bfd_get_status_str(status));
448 }
449 else
450 {
451 zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d "
452 "with src %s/%d and vrf %d %s event",
453 inet_ntop (dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN),
454 dp->prefixlen,
455 inet_ntop (sp->family, &sp->u.prefix, buf[1], INET6_ADDRSTRLEN),
456 sp->prefixlen, vrf_id, bfd_get_status_str(status));
457 }
458 }
459
460 zebra_interface_bfd_update (ifp, dp, sp, status, vrf_id);
461 }
462
463 static int
464 zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp)
465 {
466 char bfdst_str[32];
467 char dest_str[64];
468 char src_str[64];
469 char vrf_str[64];
470 struct prefix dest_prefix;
471 struct prefix src_prefix;
472 vrf_id_t vrf_id;
473
474 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
475
476 if (bfdst_str[0] == '\0') {
477 return -1;
478 }
479
480 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
481
482 if (dest_str[0] == '\0') {
483 zlog_debug("%s: Key %s not found in PTM msg", __func__,
484 ZEBRA_PTM_BFDDEST_STR);
485 return -1;
486 }
487
488 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
489
490 if (src_str[0] == '\0') {
491 zlog_debug("%s: Key %s not found in PTM msg", __func__,
492 ZEBRA_PTM_BFDSRC_STR);
493 return -1;
494 }
495
496 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str);
497
498 if (vrf_str[0] == '\0') {
499 zlog_debug("%s: Key %s not found in PTM msg", __func__,
500 ZEBRA_PTM_BFDVRF_STR);
501 return -1;
502 }
503
504 if (IS_ZEBRA_DEBUG_EVENT)
505 zlog_debug("%s: Recv Port [%s] bfd status [%s] vrf [%s]"
506 " peer [%s] local [%s]",
507 __func__, ifp ? ifp->name : "N/A", bfdst_str,
508 vrf_str, dest_str, src_str);
509
510 if (str2prefix(dest_str, &dest_prefix) == 0) {
511 zlog_err("%s: Peer addr %s not found", __func__,
512 dest_str);
513 return -1;
514 }
515
516 memset(&src_prefix, 0, sizeof(struct prefix));
517 if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
518 if (str2prefix(src_str, &src_prefix) == 0) {
519 zlog_err("%s: Local addr %s not found", __func__,
520 src_str);
521 return -1;
522 }
523 }
524
525 if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
526 vrf_id = ifp->vrf_id;
527 } else {
528 vrf_id = vrf_name_to_id(vrf_str);
529 }
530
531 if (!strcmp (bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
532 if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_DOWN,
533 vrf_id);
534 } else {
535 if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_UP,
536 vrf_id);
537 }
538
539 return 0;
540 }
541
542 static int
543 zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, struct interface *ifp,
544 char *cbl_str)
545 {
546 int send_linkup = 0;
547
548 if (IS_ZEBRA_DEBUG_EVENT)
549 zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
550 ifp->name, cbl_str);
551
552 if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR) &&
553 (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) {
554
555 if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)
556 send_linkup = 1;
557 ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
558 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp) && send_linkup)
559 if_up (ifp);
560 } else if (!strcmp (cbl_str, ZEBRA_PTM_FAIL_STR) &&
561 (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) {
562 ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN;
563 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp))
564 if_down (ifp);
565 }
566
567 return 0;
568 }
569
570 /*
571 * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle
572 * all the command responses and notifications received from PTM.
573 *
574 * Command responses: Upon establishing connection with PTM, Zebra requests
575 * status of all interfaces using 'get-status' command if global ptm-enable
576 * knob is enabled. As a response to the get-status command PTM sends status
577 * of all the interfaces as command responses. All other type of command
578 * responses with cmd_status key word are dropped. The sole purpose of
579 * registering this function as callback for the command responses is to
580 * handle the responses to get-status command.
581 *
582 * Notifications: Cable status and BFD session status changes are sent as
583 * notifications by PTM. So, this function is also the callback function for
584 * processing all the notifications from the PTM.
585 *
586 */
587 static int
588 zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
589 {
590 struct interface *ifp = NULL;
591 char port_str[128];
592 char cbl_str[32];
593 char cmd_status_str[32];
594
595 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR, cmd_status_str);
596
597 /* Drop command response messages */
598 if (cmd_status_str[0] != '\0') {
599 return 0;
600 }
601
602 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
603
604 if (port_str[0] == '\0') {
605 zlog_debug("%s: Key %s not found in PTM msg", __func__,
606 ZEBRA_PTM_PORT_STR);
607 return -1;
608 }
609
610 if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
611 ifp = if_lookup_by_name_all_vrf(port_str);
612
613 if (!ifp) {
614 zlog_err("%s: %s not found in interface list", __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, cbl_str);
626 } else {
627 return -1;
628 }
629 }
630 }
631
632 int
633 zebra_ptm_sock_read (struct thread *thread)
634 {
635 int sock, done = 0;
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 while(!done) {
646 rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data, ZEBRA_PTM_MAX_SOCKBUF,
647 NULL);
648 if (rc <= 0)
649 break;
650 }
651
652 if (rc <= 0) {
653 if (((rc == 0) && !errno) || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
654 zlog_warn ("%s routing socket error: %s(%d) bytes %d", __func__,
655 safe_strerror (errno), errno, rc);
656
657 close (ptm_cb.ptm_sock);
658 ptm_cb.ptm_sock = -1;
659 zebra_ptm_reset_status(0);
660 ptm_cb.t_timer = NULL;
661 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
662 &ptm_cb.t_timer);
663 return (-1);
664 }
665 }
666
667 ptm_cb.t_read = NULL;
668 thread_add_read(zebrad.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock,
669 &ptm_cb.t_read);
670
671 return 0;
672 }
673
674 /* BFD peer/dst register/update */
675 int
676 zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length,
677 int command, struct zebra_vrf *zvrf)
678 {
679 struct stream *s;
680 struct prefix src_p;
681 struct prefix dst_p;
682 u_char multi_hop;
683 u_char multi_hop_cnt;
684 u_char detect_mul;
685 unsigned int min_rx_timer;
686 unsigned int min_tx_timer;
687 char if_name[INTERFACE_NAMSIZ];
688 u_char len;
689 void *out_ctxt;
690 char buf[INET6_ADDRSTRLEN];
691 char tmp_buf[64];
692 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
693 unsigned int pid;
694
695 if (command == ZEBRA_BFD_DEST_UPDATE)
696 client->bfd_peer_upd8_cnt++;
697 else
698 client->bfd_peer_add_cnt++;
699
700 if (IS_ZEBRA_DEBUG_EVENT)
701 zlog_debug("bfd_dst_register msg from client %s: length=%d",
702 zebra_route_string(client->proto), length);
703
704 if (ptm_cb.ptm_sock == -1)
705 {
706 ptm_cb.t_timer = NULL;
707 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
708 &ptm_cb.t_timer);
709 return -1;
710 }
711
712 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
713 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_START_CMD);
714 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
715 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
716 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
717 tmp_buf);
718
719 s = client->ibuf;
720
721 pid = stream_getl(s);
722 sprintf(tmp_buf, "%d", pid);
723 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf);
724
725 dst_p.family = stream_getw(s);
726
727 if (dst_p.family == AF_INET)
728 dst_p.prefixlen = IPV4_MAX_BYTELEN;
729 else
730 dst_p.prefixlen = IPV6_MAX_BYTELEN;
731
732 stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
733 if (dst_p.family == AF_INET)
734 {
735 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
736 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
737 }
738 else
739 {
740 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
741 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
742 }
743
744 min_rx_timer = stream_getl(s);
745 sprintf(tmp_buf, "%d", min_rx_timer);
746 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
747 tmp_buf);
748 min_tx_timer = stream_getl(s);
749 sprintf(tmp_buf, "%d", min_tx_timer);
750 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
751 tmp_buf);
752 detect_mul = stream_getc(s);
753 sprintf(tmp_buf, "%d", detect_mul);
754 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
755 tmp_buf);
756
757 multi_hop = stream_getc(s);
758 if (multi_hop)
759 {
760 sprintf(tmp_buf, "%d", 1);
761 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
762 tmp_buf);
763 src_p.family = stream_getw(s);
764
765 if (src_p.family == AF_INET)
766 src_p.prefixlen = IPV4_MAX_BYTELEN;
767 else
768 src_p.prefixlen = IPV6_MAX_BYTELEN;
769
770 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
771 if (src_p.family == AF_INET)
772 {
773 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
774 ptm_lib_append_msg(ptm_hdl, out_ctxt,
775 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
776 }
777 else
778 {
779 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
780 ptm_lib_append_msg(ptm_hdl, out_ctxt,
781 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
782 }
783
784 multi_hop_cnt = stream_getc(s);
785 sprintf(tmp_buf, "%d", multi_hop_cnt);
786 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD,
787 tmp_buf);
788
789 if (zvrf_id (zvrf) != VRF_DEFAULT)
790 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD,
791 zvrf_name (zvrf));
792 }
793 else
794 {
795 if (dst_p.family == AF_INET6)
796 {
797 src_p.family = stream_getw(s);
798
799 if (src_p.family == AF_INET)
800 src_p.prefixlen = IPV4_MAX_BYTELEN;
801 else
802 src_p.prefixlen = IPV6_MAX_BYTELEN;
803
804 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
805 if (src_p.family == AF_INET)
806 {
807 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
808 ptm_lib_append_msg(ptm_hdl, out_ctxt,
809 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
810 }
811 else
812 {
813 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
814 ptm_lib_append_msg(ptm_hdl, out_ctxt,
815 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
816 }
817 }
818 len = stream_getc(s);
819 stream_get(if_name, s, len);
820 if_name[len] = '\0';
821
822 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
823 if_name);
824 }
825
826 sprintf(tmp_buf, "%d", 1);
827 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,
828 tmp_buf);
829
830 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
831
832 if (IS_ZEBRA_DEBUG_SEND)
833 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
834 ptm_cb.out_data);
835 zebra_ptm_send_message(ptm_cb.out_data, data_len);
836 return 0;
837 }
838
839 /* BFD peer/dst deregister */
840 int
841 zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length,
842 struct zebra_vrf *zvrf)
843 {
844 struct stream *s;
845 struct prefix src_p;
846 struct prefix dst_p;
847 u_char multi_hop;
848 char if_name[INTERFACE_NAMSIZ];
849 u_char len;
850 char buf[INET6_ADDRSTRLEN];
851 char tmp_buf[64];
852 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
853 void *out_ctxt;
854 unsigned int pid;
855
856 client->bfd_peer_del_cnt++;
857
858 if (IS_ZEBRA_DEBUG_EVENT)
859 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
860 zebra_route_string(client->proto), length);
861
862 if (ptm_cb.ptm_sock == -1)
863 {
864 ptm_cb.t_timer = NULL;
865 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
866 &ptm_cb.t_timer);
867 return -1;
868 }
869
870 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
871
872 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_STOP_CMD);
873 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
874
875 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
876 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
877 tmp_buf);
878
879 s = client->ibuf;
880
881 pid = stream_getl(s);
882 sprintf(tmp_buf, "%d", pid);
883 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf);
884
885 dst_p.family = stream_getw(s);
886
887 if (dst_p.family == AF_INET)
888 dst_p.prefixlen = IPV4_MAX_BYTELEN;
889 else
890 dst_p.prefixlen = IPV6_MAX_BYTELEN;
891
892 stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
893 if (dst_p.family == AF_INET)
894 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
895 else
896 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
897 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
898
899
900 multi_hop = stream_getc(s);
901 if (multi_hop)
902 {
903 sprintf(tmp_buf, "%d", 1);
904 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
905 tmp_buf);
906
907 src_p.family = stream_getw(s);
908
909 if (src_p.family == AF_INET)
910 src_p.prefixlen = IPV4_MAX_BYTELEN;
911 else
912 src_p.prefixlen = IPV6_MAX_BYTELEN;
913
914 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
915 if (src_p.family == AF_INET)
916 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
917 else
918 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
919 ptm_lib_append_msg(ptm_hdl, out_ctxt,
920 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
921
922 if (zvrf_id (zvrf) != VRF_DEFAULT)
923 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD,
924 zvrf_name (zvrf));
925 }
926 else
927 {
928 if (dst_p.family == AF_INET6)
929 {
930 src_p.family = stream_getw(s);
931
932 if (src_p.family == AF_INET)
933 src_p.prefixlen = IPV4_MAX_BYTELEN;
934 else
935 src_p.prefixlen = IPV6_MAX_BYTELEN;
936
937 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
938 if (src_p.family == AF_INET)
939 {
940 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
941 ptm_lib_append_msg(ptm_hdl, out_ctxt,
942 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
943 }
944 else
945 {
946 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
947 ptm_lib_append_msg(ptm_hdl, out_ctxt,
948 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
949 }
950 }
951
952 len = stream_getc(s);
953 stream_get(if_name, s, len);
954 if_name[len] = '\0';
955
956 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
957 if_name);
958 }
959
960 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
961 if (IS_ZEBRA_DEBUG_SEND)
962 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
963 ptm_cb.out_data);
964
965 zebra_ptm_send_message(ptm_cb.out_data, data_len);
966 return 0;
967 }
968
969 /* BFD client register */
970 int
971 zebra_ptm_bfd_client_register (struct zserv *client, int sock, u_short length)
972 {
973 struct stream *s;
974 unsigned int pid;
975 void *out_ctxt;
976 char tmp_buf[64];
977 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
978
979 client->bfd_client_reg_cnt++;
980
981 if (IS_ZEBRA_DEBUG_EVENT)
982 zlog_debug("bfd_client_register msg from client %s: length=%d",
983 zebra_route_string(client->proto), length);
984
985 if (ptm_cb.ptm_sock == -1)
986 {
987 ptm_cb.t_timer = NULL;
988 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
989 &ptm_cb.t_timer);
990 return -1;
991 }
992
993 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
994
995 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD);
996 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
997
998 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
999 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1000 tmp_buf);
1001
1002 s = client->ibuf;
1003
1004 pid = stream_getl(s);
1005 sprintf(tmp_buf, "%d", pid);
1006 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
1007 tmp_buf);
1008
1009 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1010
1011 if (IS_ZEBRA_DEBUG_SEND)
1012 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
1013 ptm_cb.out_data);
1014 zebra_ptm_send_message(ptm_cb.out_data, data_len);
1015
1016 SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1017 return 0;
1018 }
1019
1020 /* BFD client deregister */
1021 void
1022 zebra_ptm_bfd_client_deregister (int proto)
1023 {
1024 void *out_ctxt;
1025 char tmp_buf[64];
1026 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1027
1028 if (proto != ZEBRA_ROUTE_OSPF && proto != ZEBRA_ROUTE_BGP
1029 && proto != ZEBRA_ROUTE_OSPF6)
1030 return;
1031
1032 if (IS_ZEBRA_DEBUG_EVENT)
1033 zlog_err("bfd_client_deregister msg for client %s",
1034 zebra_route_string(proto));
1035
1036 if (ptm_cb.ptm_sock == -1)
1037 {
1038 ptm_cb.t_timer = NULL;
1039 thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time,
1040 &ptm_cb.t_timer);
1041 return;
1042 }
1043
1044 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
1045
1046 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD);
1047 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
1048
1049 sprintf(tmp_buf, "%s", zebra_route_string(proto));
1050 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1051 tmp_buf);
1052
1053 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1054
1055 if (IS_ZEBRA_DEBUG_SEND)
1056 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
1057 ptm_cb.out_data);
1058
1059 zebra_ptm_send_message(ptm_cb.out_data, data_len);
1060 UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1061 }
1062
1063 int
1064 zebra_ptm_get_enable_state(void)
1065 {
1066 return ptm_cb.ptm_enable;
1067 }
1068
1069 /*
1070 * zebra_ptm_get_status_str - Convert status to a display string.
1071 */
1072 static const char *
1073 zebra_ptm_get_status_str(int status)
1074 {
1075 switch (status)
1076 {
1077 case ZEBRA_PTM_STATUS_DOWN:
1078 return "fail";
1079 case ZEBRA_PTM_STATUS_UP:
1080 return "pass";
1081 case ZEBRA_PTM_STATUS_UNKNOWN:
1082 default:
1083 return "n/a";
1084 }
1085 }
1086
1087 void
1088 zebra_ptm_show_status(struct vty *vty, struct interface *ifp)
1089 {
1090 vty_out (vty, " PTM status: ");
1091 if (ifp->ptm_enable) {
1092 vty_out (vty, "%s%s", zebra_ptm_get_status_str (ifp->ptm_status),
1093 VTY_NEWLINE);
1094 } else {
1095 vty_out (vty, "disabled%s", VTY_NEWLINE);
1096 }
1097 }
1098
1099 void
1100 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 {
1107 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &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
1117 zebra_ptm_reset_status(int ptm_disable)
1118 {
1119 struct vrf *vrf;
1120 struct listnode *i;
1121 struct interface *ifp;
1122 int send_linkup;
1123
1124 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
1125 for (ALL_LIST_ELEMENTS_RO (vrf->iflist, i, ifp))
1126 {
1127 send_linkup = 0;
1128 if (ifp->ptm_enable)
1129 {
1130 if (!if_is_operative(ifp))
1131 send_linkup = 1;
1132
1133 if (ptm_disable)
1134 ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
1135 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
1136
1137 if (if_is_operative (ifp) && send_linkup)
1138 {
1139 if (IS_ZEBRA_DEBUG_EVENT)
1140 zlog_debug ("%s: Bringing up interface %s", __func__,
1141 ifp->name);
1142 if_up (ifp);
1143 }
1144 }
1145 }
1146 }
1147
1148 void
1149 zebra_ptm_if_init(struct zebra_if *zebra_ifp)
1150 {
1151 zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
1152 }
1153
1154 void
1155 zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp)
1156 {
1157 if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
1158 ifp->ptm_enable = zebra_ifp->ptm_enable;
1159 }
1160
1161 void
1162 zebra_ptm_if_write (struct vty *vty, struct zebra_if *zebra_ifp)
1163 {
1164 if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
1165 vty_out (vty, " no ptm-enable%s", VTY_NEWLINE);
1166 }