]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_ptm.c
quagga-reload broken for 'neighbor swpX interface peer-group FOO'
[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 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23#include <sys/un.h> /* for sockaddr_un */
24#include <net/if.h>
c8ed14dd 25#include "vty.h"
244c1cdc
DS
26#include "zebra/zserv.h"
27#include "zebra/interface.h"
28#include "zebra/debug.h"
29#include "zebra/zebra_ptm.h"
30#include "if.h"
31#include "command.h"
c43ed2e4
DS
32#include "stream.h"
33#include "ptm_lib.h"
c8ed14dd 34#include "buffer.h"
c43ed2e4 35#include "zebra/zebra_ptm_redistribute.h"
68fe91d6 36#include "bfd.h"
d553294e 37#include "vrf.h"
7c551956
DS
38#include "rib.h"
39#include "zebra_vrf.h"
244c1cdc
DS
40
41#define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
42#define ZEBRA_PTM_RECONNECT_TIME_MAX 300
c01acf98 43
c01acf98 44#define PTM_MSG_LEN 4
0a56c844 45#define PTM_HEADER_LEN 37
c43ed2e4
DS
46
47const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
48const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
49const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
055c4dfc 50const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client";
c43ed2e4 51
c8ed14dd 52const char ZEBRA_PTM_CMD_STR[] = "cmd";
b255a4b1 53const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status";
c43ed2e4
DS
54const char ZEBRA_PTM_PORT_STR[] = "port";
55const char ZEBRA_PTM_CBL_STR[] = "cbl status";
56const char ZEBRA_PTM_PASS_STR[] = "pass";
57const char ZEBRA_PTM_FAIL_STR[] = "fail";
58const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
59const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
60const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
61const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
62const char ZEBRA_PTM_BFDSRC_STR[] = "local";
d553294e 63const char ZEBRA_PTM_BFDVRF_STR[] = "vrf";
c43ed2e4
DS
64const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
65const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
d553294e 66const char ZEBRA_PTM_INVALID_VRF[] = "N/A";
c43ed2e4
DS
67
68const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
69const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
70const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
71const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
72const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
73const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
74const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
75const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
76const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
77const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
68fe91d6 78const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
d553294e 79const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
c01acf98 80
c43ed2e4 81static ptm_lib_handle_t *ptm_hdl;
244c1cdc 82
c8ed14dd
DS
83struct zebra_ptm_cb ptm_cb;
84
244c1cdc 85static int zebra_ptm_socket_init(void);
244c1cdc
DS
86int zebra_ptm_sock_read(struct thread *);
87static void zebra_ptm_install_commands (void);
b255a4b1 88static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt);
c43ed2e4 89void zebra_bfd_peer_replay_req (void);
950bd436 90void zebra_ptm_send_status_req(void);
91void zebra_ptm_reset_status(int ptm_disable);
244c1cdc
DS
92
93const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
94
244c1cdc
DS
95void
96zebra_ptm_init (void)
97{
c43ed2e4
DS
98 char buf[64];
99
c8ed14dd
DS
100 memset(&ptm_cb, 0, sizeof(struct zebra_ptm_cb));
101
102 ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
103 if (!ptm_cb.out_data)
104 {
105 zlog_warn("%s: Allocation of send data failed", __func__);
106 return;
107 }
108
109 ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
110 if (!ptm_cb.in_data)
111 {
112 zlog_warn("%s: Allocation of recv data failed", __func__);
113 free(ptm_cb.out_data);
114 return;
115 }
116
117 ptm_cb.pid = getpid();
244c1cdc 118 zebra_ptm_install_commands();
c43ed2e4
DS
119
120 sprintf(buf, "%s", "quagga");
b255a4b1 121 ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb,
122 zebra_ptm_handle_msg_cb);
c8ed14dd
DS
123 ptm_cb.wb = buffer_new(0);
124
125 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
126
127 ptm_cb.ptm_sock = -1;
128}
129
130void
131zebra_ptm_finish(void)
132{
133 if (ptm_cb.ptm_sock != -1)
134 close(ptm_cb.ptm_sock);
135
136 if (ptm_cb.wb)
137 buffer_free(ptm_cb.wb);
138
139 if (ptm_cb.out_data)
140 free(ptm_cb.out_data);
141
142 if (ptm_cb.in_data)
143 free(ptm_cb.in_data);
144
145 /* Release threads. */
146 if (ptm_cb.t_read)
147 thread_cancel (ptm_cb.t_read);
148 if (ptm_cb.t_write)
149 thread_cancel (ptm_cb.t_write);
150 if (ptm_cb.t_timer)
151 thread_cancel (ptm_cb.t_timer);
152}
153
154static int
155zebra_ptm_flush_messages (struct thread *thread)
156{
157 ptm_cb.t_write = NULL;
158
159 if (ptm_cb.ptm_sock == -1)
160 return -1;
161
162 errno = 0;
163
164 switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock))
165 {
166 case BUFFER_ERROR:
167 zlog_warn ("%s ptm socket error: %s", __func__,
168 safe_strerror (errno));
169 close(ptm_cb.ptm_sock);
170 ptm_cb.ptm_sock = -1;
950bd436 171 zebra_ptm_reset_status(0);
c8ed14dd
DS
172 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
173 NULL, ptm_cb.reconnect_time);
174 return (-1);
175 case BUFFER_PENDING:
176 ptm_cb.t_write = thread_add_write(zebrad.master, zebra_ptm_flush_messages,
177 NULL, ptm_cb.ptm_sock);
178 break;
179 case BUFFER_EMPTY:
180 break;
181 }
182
183 return(0);
184}
185
186static int
187zebra_ptm_send_message(char *data, int size)
188{
189 errno = 0;
190 switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size))
191 {
192 case BUFFER_ERROR:
193 zlog_warn ("%s ptm socket error: %s", __func__, safe_strerror (errno));
194 close(ptm_cb.ptm_sock);
195 ptm_cb.ptm_sock = -1;
950bd436 196 zebra_ptm_reset_status(0);
c8ed14dd
DS
197 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
198 NULL, ptm_cb.reconnect_time);
199 return -1;
200 case BUFFER_EMPTY:
201 THREAD_OFF(ptm_cb.t_write);
202 break;
203 case BUFFER_PENDING:
204 THREAD_WRITE_ON(zebrad.master, ptm_cb.t_write,
205 zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock);
206 break;
207 }
208
209 return 0;
244c1cdc
DS
210}
211
212int
213zebra_ptm_connect (struct thread *t)
214{
c43ed2e4 215 int init = 0;
c43ed2e4 216
c8ed14dd 217 if (ptm_cb.ptm_sock == -1) {
c43ed2e4
DS
218 zebra_ptm_socket_init();
219 init = 1;
220 }
244c1cdc 221
c8ed14dd 222 if (ptm_cb.ptm_sock != -1) {
c43ed2e4 223 if (init) {
c8ed14dd
DS
224 ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read,
225 NULL, ptm_cb.ptm_sock);
c43ed2e4
DS
226 zebra_bfd_peer_replay_req();
227 }
950bd436 228 zebra_ptm_send_status_req();
c8ed14dd 229 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
244c1cdc 230 } else {
c8ed14dd
DS
231 ptm_cb.reconnect_time *= 2;
232 if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
233 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
244c1cdc 234
c8ed14dd
DS
235 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL,
236 ptm_cb.reconnect_time);
244c1cdc
DS
237 }
238
239 return(errno);
240}
241
244c1cdc
DS
242DEFUN (zebra_ptm_enable,
243 zebra_ptm_enable_cmd,
244 "ptm-enable",
245 "Enable neighbor check with specified topology\n")
246{
247 struct listnode *i;
248 struct interface *ifp;
b2d7c082 249 vrf_iter_t iter;
244c1cdc 250
c8ed14dd 251 ptm_cb.ptm_enable = 1;
244c1cdc 252
b2d7c082
DS
253 for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
254 for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), i, ifp))
255 if (!ifp->ptm_enable)
256 {
257 ifp->ptm_enable = 1;
258 /* Assign a default unknown status */
259 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
260 }
244c1cdc
DS
261
262 zebra_ptm_connect(NULL);
263
264 return CMD_SUCCESS;
265}
266
267DEFUN (no_zebra_ptm_enable,
268 no_zebra_ptm_enable_cmd,
269 "no ptm-enable",
270 NO_STR
271 "Enable neighbor check with specified topology\n")
272{
c8ed14dd 273 ptm_cb.ptm_enable = 0;
950bd436 274 zebra_ptm_reset_status(1);
244c1cdc
DS
275 return CMD_SUCCESS;
276}
277
278void
279zebra_ptm_write (struct vty *vty)
280{
c8ed14dd 281 if (ptm_cb.ptm_enable)
244c1cdc
DS
282 vty_out (vty, "ptm-enable%s", VTY_NEWLINE);
283
284 return;
285}
286
287static int
288zebra_ptm_socket_init (void)
289{
290 int ret;
291 int sock;
292 struct sockaddr_un addr;
293
c8ed14dd 294 ptm_cb.ptm_sock = -1;
c01acf98 295
0a56c844 296 sock = socket (PF_UNIX, (SOCK_STREAM | SOCK_NONBLOCK), 0);
244c1cdc
DS
297 if (sock < 0)
298 return -1;
299
300 /* Make server socket. */
301 memset (&addr, 0, sizeof (struct sockaddr_un));
302 addr.sun_family = AF_UNIX;
303 memcpy (&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
304 sizeof(ZEBRA_PTM_SOCK_NAME));
305
306 ret = connect(sock, (struct sockaddr *) &addr,
c01acf98 307 sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1);
244c1cdc
DS
308 if (ret < 0)
309 {
c43ed2e4 310 zlog_warn("%s: Unable to connect to socket %s [%s]",
c01acf98 311 __func__, ZEBRA_PTM_SOCK_NAME, safe_strerror(errno));
244c1cdc
DS
312 close (sock);
313 return -1;
314 }
c8ed14dd 315 ptm_cb.ptm_sock = sock;
244c1cdc
DS
316 return sock;
317}
318
319static void
320zebra_ptm_install_commands (void)
321{
322 install_element (CONFIG_NODE, &zebra_ptm_enable_cmd);
323 install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd);
324}
325
c43ed2e4 326/* BFD session goes down, send message to the protocols. */
c8ed14dd 327static void
68fe91d6 328if_bfd_session_update (struct interface *ifp, struct prefix *dp,
d553294e 329 struct prefix *sp, int status, vrf_id_t vrf_id)
c01acf98 330{
c43ed2e4
DS
331 if (IS_ZEBRA_DEBUG_EVENT)
332 {
333 char buf[2][INET6_ADDRSTRLEN];
334
335 if (ifp)
336 {
68fe91d6 337 zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s"
338 " %s event",
339 inet_ntop (dp->family, &dp->u.prefix, buf[0],
340 INET6_ADDRSTRLEN), dp->prefixlen, ifp->name,
341 bfd_get_status_str(status));
c43ed2e4
DS
342 }
343 else
344 {
68fe91d6 345 zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d "
d553294e 346 "with src %s/%d and vrf %d %s event",
c43ed2e4
DS
347 inet_ntop (dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN),
348 dp->prefixlen,
349 inet_ntop (sp->family, &sp->u.prefix, buf[1], INET6_ADDRSTRLEN),
d553294e 350 sp->prefixlen, vrf_id, bfd_get_status_str(status));
c43ed2e4 351 }
c01acf98 352 }
c01acf98 353
d553294e 354 zebra_interface_bfd_update (ifp, dp, sp, status, vrf_id);
c01acf98
DS
355}
356
c43ed2e4 357static int
b255a4b1 358zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp)
244c1cdc 359{
c43ed2e4
DS
360 char bfdst_str[32];
361 char dest_str[64];
362 char src_str[64];
d553294e 363 char vrf_str[64];
244c1cdc 364 struct prefix dest_prefix;
c43ed2e4 365 struct prefix src_prefix;
244c1cdc 366
c43ed2e4 367 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
c01acf98 368
c43ed2e4 369 if (bfdst_str[0] == '\0') {
c43ed2e4 370 return -1;
c01acf98
DS
371 }
372
c43ed2e4 373 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
c01acf98 374
c43ed2e4
DS
375 if (dest_str[0] == '\0') {
376 zlog_debug("%s: Key %s not found in PTM msg", __func__,
c01acf98 377 ZEBRA_PTM_BFDDEST_STR);
c43ed2e4 378 return -1;
c01acf98 379 }
244c1cdc 380
c43ed2e4 381 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
c01acf98 382
c43ed2e4
DS
383 if (src_str[0] == '\0') {
384 zlog_debug("%s: Key %s not found in PTM msg", __func__,
385 ZEBRA_PTM_BFDSRC_STR);
386 return -1;
c01acf98
DS
387 }
388
d553294e 389 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str);
390
391 if (vrf_str[0] == '\0') {
392 zlog_debug("%s: Key %s not found in PTM msg", __func__,
393 ZEBRA_PTM_BFDVRF_STR);
394 return -1;
395 }
396
c8ed14dd 397 if (IS_ZEBRA_DEBUG_EVENT)
d553294e 398 zlog_debug("%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]",
b255a4b1 399 __func__, ifp ? ifp->name : "N/A", bfdst_str,
d553294e 400 vrf_str, dest_str, src_str);
c43ed2e4 401
68fe91d6 402 if (str2prefix(dest_str, &dest_prefix) == 0) {
403 zlog_err("%s: Peer addr %s not found", __func__,
404 dest_str);
405 return -1;
406 }
c01acf98 407
68fe91d6 408 memset(&src_prefix, 0, sizeof(struct prefix));
409 if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
410 if (str2prefix(src_str, &src_prefix) == 0) {
411 zlog_err("%s: Local addr %s not found", __func__,
412 src_str);
413 return -1;
c43ed2e4 414 }
68fe91d6 415 }
c43ed2e4 416
68fe91d6 417 if (!strcmp (bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
d553294e 418 if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_DOWN,
419 vrf_name_to_id(vrf_str));
68fe91d6 420 } else {
d553294e 421 if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_UP,
422 vrf_name_to_id(vrf_str));
c01acf98 423 }
c43ed2e4
DS
424
425 return 0;
c01acf98
DS
426}
427
c43ed2e4 428static int
b255a4b1 429zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, struct interface *ifp,
430 char *cbl_str)
c01acf98 431{
950bd436 432 int send_linkup = 0;
433
b255a4b1 434 if (IS_ZEBRA_DEBUG_EVENT)
435 zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
436 ifp->name, cbl_str);
437
950bd436 438 if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR) &&
439 (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) {
440
441 if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)
442 send_linkup = 1;
443 ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
444 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp) && send_linkup)
b255a4b1 445 if_up (ifp);
950bd436 446 } else if (!strcmp (cbl_str, ZEBRA_PTM_FAIL_STR) &&
447 (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) {
448 ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN;
b255a4b1 449 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp))
450 if_down (ifp);
451 }
452
453 return 0;
454}
950bd436 455
b255a4b1 456/*
457 * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle
458 * all the command responses and notifications received from PTM.
459 *
460 * Command responses: Upon establishing connection with PTM, Zebra requests
461 * status of all interfaces using 'get-status' command if global ptm-enable
462 * knob is enabled. As a response to the get-status command PTM sends status
463 * of all the interfaces as command responses. All other type of command
464 * responses with cmd_status key word are dropped. The sole purpose of
465 * registering this function as callback for the command responses is to
466 * handle the responses to get-status command.
467 *
468 * Notifications: Cable status and BFD session status changes are sent as
469 * notifications by PTM. So, this function is also the callback function for
470 * processing all the notifications from the PTM.
471 *
472 */
473static int
474zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
475{
476 struct interface *ifp = NULL;
c43ed2e4 477 char port_str[128];
b255a4b1 478 char cbl_str[32];
479 char cmd_status_str[32];
c8ed14dd 480
b255a4b1 481 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR, cmd_status_str);
c8ed14dd
DS
482
483 /* Drop command response messages */
b255a4b1 484 if (cmd_status_str[0] != '\0') {
c8ed14dd
DS
485 return 0;
486 }
c01acf98 487
c43ed2e4 488 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
c01acf98 489
c43ed2e4 490 if (port_str[0] == '\0') {
b255a4b1 491 zlog_debug("%s: Key %s not found in PTM msg", __func__,
c01acf98 492 ZEBRA_PTM_PORT_STR);
b255a4b1 493 return -1;
c01acf98
DS
494 }
495
b255a4b1 496 if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
f8962871 497 ifp = if_lookup_by_name_all_vrf(port_str);
c01acf98 498
b255a4b1 499 if (!ifp) {
500 zlog_err("%s: %s not found in interface list", __func__, port_str);
501 return -1;
502 }
c01acf98
DS
503 }
504
b255a4b1 505 ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str);
244c1cdc 506
b255a4b1 507 if (cbl_str[0] == '\0') {
508 return zebra_ptm_handle_bfd_msg(arg, in_ctxt, ifp);
509 } else {
510 if (ifp) {
511 return zebra_ptm_handle_cbl_msg(arg, in_ctxt, ifp, cbl_str);
512 } else {
513 return -1;
514 }
244c1cdc 515 }
c01acf98
DS
516}
517
c01acf98
DS
518int
519zebra_ptm_sock_read (struct thread *thread)
520{
521 int sock, done = 0;
c43ed2e4 522 int rc;
c01acf98 523
c43ed2e4 524 errno = 0;
c01acf98
DS
525 sock = THREAD_FD (thread);
526
527 if (sock == -1)
528 return -1;
529
530 /* PTM communicates in CSV format */
531 while(!done) {
c8ed14dd 532 rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data, ZEBRA_PTM_MAX_SOCKBUF,
c43ed2e4
DS
533 NULL);
534 if (rc <= 0)
535 break;
c01acf98
DS
536 }
537
c43ed2e4
DS
538 if (rc <= 0) {
539 if (((rc == 0) && !errno) || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
540 zlog_warn ("%s routing socket error: %s(%d) bytes %d", __func__,
541 safe_strerror (errno), errno, rc);
c01acf98 542
c8ed14dd
DS
543 close (ptm_cb.ptm_sock);
544 ptm_cb.ptm_sock = -1;
950bd436 545 zebra_ptm_reset_status(0);
c8ed14dd
DS
546 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
547 NULL, ptm_cb.reconnect_time);
c01acf98 548 return (-1);
0a56c844 549 }
c01acf98
DS
550 }
551
c8ed14dd
DS
552 ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read,
553 NULL, ptm_cb.ptm_sock);
c43ed2e4
DS
554
555 return 0;
556}
557
558/* BFD peer/dst register/update */
559int
560zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length,
d651649e 561 int command, struct zebra_vrf *zvrf)
c43ed2e4 562{
c43ed2e4
DS
563 struct stream *s;
564 struct prefix src_p;
565 struct prefix dst_p;
566 u_char multi_hop;
567 u_char multi_hop_cnt;
568 u_char detect_mul;
569 unsigned int min_rx_timer;
570 unsigned int min_tx_timer;
571 char if_name[INTERFACE_NAMSIZ];
572 u_char len;
573 void *out_ctxt;
574 char buf[INET6_ADDRSTRLEN];
575 char tmp_buf[64];
576 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
055c4dfc 577 unsigned int pid;
c43ed2e4
DS
578
579 if (command == ZEBRA_BFD_DEST_UPDATE)
580 client->bfd_peer_upd8_cnt++;
581 else
582 client->bfd_peer_add_cnt++;
583
c8ed14dd
DS
584 if (IS_ZEBRA_DEBUG_EVENT)
585 zlog_debug("bfd_dst_register msg from client %s: length=%d",
586 zebra_route_string(client->proto), length);
c43ed2e4 587
c8ed14dd 588 if (ptm_cb.ptm_sock == -1)
c43ed2e4 589 {
c8ed14dd
DS
590 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
591 NULL, ptm_cb.reconnect_time);
c43ed2e4
DS
592 return -1;
593 }
594
595 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
596 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_START_CMD);
c8ed14dd 597 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
055c4dfc 598 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
c43ed2e4
DS
599 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
600 tmp_buf);
c43ed2e4
DS
601
602 s = client->ibuf;
603
055c4dfc 604 pid = stream_getl(s);
605 sprintf(tmp_buf, "%d", pid);
606 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf);
607
c43ed2e4
DS
608 dst_p.family = stream_getw(s);
609
610 if (dst_p.family == AF_INET)
611 dst_p.prefixlen = IPV4_MAX_BYTELEN;
612 else
613 dst_p.prefixlen = IPV6_MAX_BYTELEN;
614
615 stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
616 if (dst_p.family == AF_INET)
617 {
618 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
619 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
620 }
621#ifdef HAVE_IPV6
622 else
623 {
624 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
625 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
626 }
627#endif /* HAVE_IPV6 */
628
629 min_rx_timer = stream_getl(s);
630 sprintf(tmp_buf, "%d", min_rx_timer);
631 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
632 tmp_buf);
633 min_tx_timer = stream_getl(s);
634 sprintf(tmp_buf, "%d", min_tx_timer);
635 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
636 tmp_buf);
637 detect_mul = stream_getc(s);
638 sprintf(tmp_buf, "%d", detect_mul);
639 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
640 tmp_buf);
641
642 multi_hop = stream_getc(s);
643 if (multi_hop)
644 {
645 sprintf(tmp_buf, "%d", 1);
646 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
647 tmp_buf);
648 src_p.family = stream_getw(s);
649
650 if (src_p.family == AF_INET)
651 src_p.prefixlen = IPV4_MAX_BYTELEN;
652 else
653 src_p.prefixlen = IPV6_MAX_BYTELEN;
654
655 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
656 if (src_p.family == AF_INET)
657 {
658 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
659 ptm_lib_append_msg(ptm_hdl, out_ctxt,
660 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
661 }
662#ifdef HAVE_IPV6
663 else
664 {
665 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
666 ptm_lib_append_msg(ptm_hdl, out_ctxt,
667 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
668 }
669#endif /* HAVE_IPV6 */
670
671 multi_hop_cnt = stream_getc(s);
672 sprintf(tmp_buf, "%d", multi_hop_cnt);
673 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD,
674 tmp_buf);
d553294e 675
d651649e
DS
676 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD,
677 zvrf->name);
c43ed2e4
DS
678 }
679 else
680 {
681#ifdef HAVE_IPV6
682 if (dst_p.family == AF_INET6)
683 {
684 src_p.family = stream_getw(s);
685
686 if (src_p.family == AF_INET)
687 src_p.prefixlen = IPV4_MAX_BYTELEN;
688 else
689 src_p.prefixlen = IPV6_MAX_BYTELEN;
690
691 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
692 if (src_p.family == AF_INET)
693 {
694 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
695 ptm_lib_append_msg(ptm_hdl, out_ctxt,
696 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
697 }
698 else
699 {
700 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
701 ptm_lib_append_msg(ptm_hdl, out_ctxt,
702 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
703 }
704 }
705#endif /* HAVE_IPV6 */
706 len = stream_getc(s);
707 stream_get(if_name, s, len);
708 if_name[len] = '\0';
709
710 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
711 if_name);
712 }
713
68fe91d6 714 sprintf(tmp_buf, "%d", 1);
715 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,
716 tmp_buf);
717
c8ed14dd
DS
718 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
719
720 if (IS_ZEBRA_DEBUG_SEND)
721 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
722 ptm_cb.out_data);
723 zebra_ptm_send_message(ptm_cb.out_data, data_len);
c43ed2e4
DS
724 return 0;
725}
726
727/* BFD peer/dst deregister */
728int
d553294e 729zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length,
d651649e 730 struct zebra_vrf *zvrf)
c43ed2e4 731{
c43ed2e4
DS
732 struct stream *s;
733 struct prefix src_p;
734 struct prefix dst_p;
735 u_char multi_hop;
736 char if_name[INTERFACE_NAMSIZ];
737 u_char len;
738 char buf[INET6_ADDRSTRLEN];
739 char tmp_buf[64];
740 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
741 void *out_ctxt;
055c4dfc 742 unsigned int pid;
c43ed2e4
DS
743
744 client->bfd_peer_del_cnt++;
745
c8ed14dd
DS
746 if (IS_ZEBRA_DEBUG_EVENT)
747 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
748 zebra_route_string(client->proto), length);
c43ed2e4 749
c8ed14dd 750 if (ptm_cb.ptm_sock == -1)
c43ed2e4 751 {
c8ed14dd
DS
752 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
753 NULL, ptm_cb.reconnect_time);
c43ed2e4
DS
754 return -1;
755 }
756
757 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
758
759 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_STOP_CMD);
c8ed14dd 760 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
c43ed2e4 761
055c4dfc 762 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
c43ed2e4
DS
763 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
764 tmp_buf);
765
c43ed2e4
DS
766 s = client->ibuf;
767
055c4dfc 768 pid = stream_getl(s);
769 sprintf(tmp_buf, "%d", pid);
770 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf);
771
c43ed2e4
DS
772 dst_p.family = stream_getw(s);
773
774 if (dst_p.family == AF_INET)
775 dst_p.prefixlen = IPV4_MAX_BYTELEN;
776 else
777 dst_p.prefixlen = IPV6_MAX_BYTELEN;
778
779 stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
780 if (dst_p.family == AF_INET)
781 {
782 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
783 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
784 }
785#ifdef HAVE_IPV6
786 else
787 {
788 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
789 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
790 }
791#endif /* HAVE_IPV6 */
792
793 multi_hop = stream_getc(s);
794 if (multi_hop)
795 {
796 sprintf(tmp_buf, "%d", 1);
797 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
798 tmp_buf);
799
800 src_p.family = stream_getw(s);
801
802 if (src_p.family == AF_INET)
803 src_p.prefixlen = IPV4_MAX_BYTELEN;
804 else
805 src_p.prefixlen = IPV6_MAX_BYTELEN;
806
807 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
808 if (src_p.family == AF_INET)
809 {
810 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
811 ptm_lib_append_msg(ptm_hdl, out_ctxt,
812 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
813 }
814#ifdef HAVE_IPV6
815 else
816 {
817 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
818 ptm_lib_append_msg(ptm_hdl, out_ctxt,
819 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
820 }
821#endif /* HAVE_IPV6 */
d651649e
DS
822 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD,
823 zvrf->name);
c43ed2e4
DS
824 }
825 else
826 {
827#ifdef HAVE_IPV6
828 if (dst_p.family == AF_INET6)
829 {
830 src_p.family = stream_getw(s);
831
832 if (src_p.family == AF_INET)
833 src_p.prefixlen = IPV4_MAX_BYTELEN;
834 else
835 src_p.prefixlen = IPV6_MAX_BYTELEN;
836
837 stream_get(&src_p.u.prefix, s, src_p.prefixlen);
838 if (src_p.family == AF_INET)
839 {
840 inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
841 ptm_lib_append_msg(ptm_hdl, out_ctxt,
842 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
843 }
844 else
845 {
846 inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
847 ptm_lib_append_msg(ptm_hdl, out_ctxt,
848 ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
849 }
850 }
851#endif /* HAVE_IPV6 */
852
853 len = stream_getc(s);
854 stream_get(if_name, s, len);
855 if_name[len] = '\0';
856
857 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
858 if_name);
859 }
c01acf98 860
c8ed14dd
DS
861 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
862 if (IS_ZEBRA_DEBUG_SEND)
863 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
864 ptm_cb.out_data);
865
866 zebra_ptm_send_message(ptm_cb.out_data, data_len);
c01acf98
DS
867 return 0;
868}
c8ed14dd 869
055c4dfc 870/* BFD client register */
871int
872zebra_ptm_bfd_client_register (struct zserv *client, int sock, u_short length)
873{
874 struct stream *s;
875 unsigned int pid;
876 void *out_ctxt;
877 char tmp_buf[64];
878 int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
879
880 client->bfd_client_reg_cnt++;
881
882 if (IS_ZEBRA_DEBUG_EVENT)
883 zlog_debug("bfd_client_register msg from client %s: length=%d",
884 zebra_route_string(client->proto), length);
885
886 if (ptm_cb.ptm_sock == -1)
887 {
888 ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
889 NULL, ptm_cb.reconnect_time);
890 return -1;
891 }
892
893 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
894
895 sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD);
896 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
897
898 sprintf(tmp_buf, "%s", zebra_route_string(client->proto));
899 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
900 tmp_buf);
901
902 s = client->ibuf;
903
904 pid = stream_getl(s);
905 sprintf(tmp_buf, "%d", pid);
906 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
907 tmp_buf);
908
909 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
910
911 if (IS_ZEBRA_DEBUG_SEND)
912 zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
913 ptm_cb.out_data);
914 zebra_ptm_send_message(ptm_cb.out_data, data_len);
915 return 0;
916}
917
c8ed14dd
DS
918int
919zebra_ptm_get_enable_state(void)
920{
921 return ptm_cb.ptm_enable;
922}
950bd436 923
924/*
925 * zebra_ptm_get_status_str - Convert status to a display string.
926 */
927static const char *
928zebra_ptm_get_status_str(int status)
929{
930 switch (status)
931 {
932 case ZEBRA_PTM_STATUS_DOWN:
933 return "fail";
934 case ZEBRA_PTM_STATUS_UP:
935 return "pass";
936 case ZEBRA_PTM_STATUS_UNKNOWN:
937 default:
938 return "n/a";
939 }
940}
941
942void
943zebra_ptm_show_status(struct vty *vty, struct interface *ifp)
944{
945 vty_out (vty, " PTM status: ");
946 if (ifp->ptm_enable) {
947 vty_out (vty, "%s%s", zebra_ptm_get_status_str (ifp->ptm_status),
948 VTY_NEWLINE);
949 } else {
950 vty_out (vty, "disabled%s", VTY_NEWLINE);
951 }
952}
953
954void
955zebra_ptm_send_status_req(void)
956{
957 void *out_ctxt;
958 int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
959
960 if (ptm_cb.ptm_enable)
961 {
962 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
963 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
964 ZEBRA_PTM_GET_STATUS_CMD);
965 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
966
967 zebra_ptm_send_message(ptm_cb.out_data, len);
968 }
969}
970
971void
972zebra_ptm_reset_status(int ptm_disable)
973{
974 struct listnode *i;
975 struct interface *ifp;
976 int send_linkup;
b2d7c082 977 vrf_iter_t iter;
950bd436 978
b2d7c082
DS
979 for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
980 for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), i, ifp))
981 {
982 send_linkup = 0;
983 if (ifp->ptm_enable)
984 {
985 if (!if_is_operative(ifp))
986 send_linkup = 1;
987
988 if (ptm_disable)
989 ifp->ptm_enable = 0;
990 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
991
992 if (if_is_operative (ifp) && send_linkup)
993 {
994 if (IS_ZEBRA_DEBUG_EVENT)
995 zlog_debug ("%s: Bringing up interface %s", __func__,
996 ifp->name);
997 if_up (ifp);
998 }
999 }
1000 }
950bd436 1001}