Coverage Report

Created: 2026-05-25 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_ptm.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Kernel routing table updates using netlink over GNU/Linux system.
3
 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
8
#include <sys/un.h> /* for sockaddr_un */
9
#include <net/if.h>
10
11
#include "bfd.h"
12
#include "buffer.h"
13
#include "command.h"
14
#include "if.h"
15
#include "network.h"
16
#include "ptm_lib.h"
17
#include "rib.h"
18
#include "stream.h"
19
#include "lib/version.h"
20
#include "vrf.h"
21
#include "vty.h"
22
#include "lib_errors.h"
23
24
#include "zebra/debug.h"
25
#include "zebra/interface.h"
26
#include "zebra/zebra_errors.h"
27
#include "zebra/zebra_ptm.h"
28
#include "zebra/zebra_ptm_redistribute.h"
29
#include "zebra/zebra_router.h"
30
#include "zebra_vrf.h"
31
32
/*
33
 * Choose the BFD implementation that we'll use.
34
 *
35
 * There are two implementations:
36
 * - PTM BFD: which uses an external daemon;
37
 * - bfdd: FRR's own BFD daemon;
38
 */
39
#if HAVE_BFDD == 0
40
41
#define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
42
#define ZEBRA_PTM_RECONNECT_TIME_MAX     300
43
44
#define PTM_MSG_LEN     4
45
#define PTM_HEADER_LEN  37
46
47
const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
48
const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
49
const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
50
const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client";
51
const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD[] = "dereg-bfd-client";
52
53
const char ZEBRA_PTM_CMD_STR[] = "cmd";
54
const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status";
55
const char ZEBRA_PTM_PORT_STR[] = "port";
56
const char ZEBRA_PTM_CBL_STR[] = "cbl status";
57
const char ZEBRA_PTM_PASS_STR[] = "pass";
58
const char ZEBRA_PTM_FAIL_STR[] = "fail";
59
const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
60
const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
61
const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
62
const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
63
const char ZEBRA_PTM_BFDSRC_STR[] = "local";
64
const char ZEBRA_PTM_BFDVRF_STR[] = "vrf";
65
const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
66
const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
67
const char ZEBRA_PTM_INVALID_VRF[] = "N/A";
68
69
const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
70
const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
71
const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
72
const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
73
const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
74
const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
75
const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
76
const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
77
const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
78
const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
79
const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
80
const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
81
const char ZEBRA_PTM_BFD_CBIT_FIELD[] = "bfdcbit";
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
void zebra_ptm_sock_read(struct event *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);
95
96
const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
97
98
void zebra_ptm_init(void)
99
{
100
  char buf[64];
101
102
  memset(&ptm_cb, 0, sizeof(ptm_cb));
103
104
  ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
105
  if (!ptm_cb.out_data) {
106
    zlog_debug("%s: Allocation of send data failed", __func__);
107
    return;
108
  }
109
110
  ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
111
  if (!ptm_cb.in_data) {
112
    zlog_debug("%s: Allocation of recv data failed", __func__);
113
    free(ptm_cb.out_data);
114
    return;
115
  }
116
117
  ptm_cb.pid = getpid();
118
  zebra_ptm_install_commands();
119
120
  snprintf(buf, sizeof(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);
124
125
  ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
126
127
  ptm_cb.ptm_sock = -1;
128
129
  hook_register(zserv_client_close, zebra_ptm_bfd_client_deregister);
130
}
131
132
void zebra_ptm_finish(void)
133
{
134
  buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock);
135
136
  free(ptm_hdl);
137
138
  if (ptm_cb.out_data)
139
    free(ptm_cb.out_data);
140
141
  if (ptm_cb.in_data)
142
    free(ptm_cb.in_data);
143
144
  /* Cancel events. */
145
  EVENT_OFF(ptm_cb.t_read);
146
  EVENT_OFF(ptm_cb.t_write);
147
  EVENT_OFF(ptm_cb.t_timer);
148
149
  if (ptm_cb.wb)
150
    buffer_free(ptm_cb.wb);
151
152
  if (ptm_cb.ptm_sock >= 0)
153
    close(ptm_cb.ptm_sock);
154
}
155
156
static void zebra_ptm_flush_messages(struct event *thread)
157
{
158
  ptm_cb.t_write = NULL;
159
160
  if (ptm_cb.ptm_sock == -1)
161
    return;
162
163
  errno = 0;
164
165
  switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock)) {
166
  case BUFFER_ERROR:
167
    flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
168
           safe_strerror(errno));
169
    close(ptm_cb.ptm_sock);
170
    ptm_cb.ptm_sock = -1;
171
    zebra_ptm_reset_status(0);
172
    ptm_cb.t_timer = NULL;
173
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
174
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
175
    return;
176
  case BUFFER_PENDING:
177
    ptm_cb.t_write = NULL;
178
    event_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
179
        ptm_cb.ptm_sock, &ptm_cb.t_write);
180
    break;
181
  case BUFFER_EMPTY:
182
    break;
183
  }
184
}
185
186
static int zebra_ptm_send_message(char *data, int size)
187
{
188
  errno = 0;
189
  switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size)) {
190
  case BUFFER_ERROR:
191
    flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
192
           safe_strerror(errno));
193
    close(ptm_cb.ptm_sock);
194
    ptm_cb.ptm_sock = -1;
195
    zebra_ptm_reset_status(0);
196
    ptm_cb.t_timer = NULL;
197
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
198
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
199
    return -1;
200
  case BUFFER_EMPTY:
201
    EVENT_OFF(ptm_cb.t_write);
202
    break;
203
  case BUFFER_PENDING:
204
    event_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
205
        ptm_cb.ptm_sock, &ptm_cb.t_write);
206
    break;
207
  }
208
209
  return 0;
210
}
211
212
void zebra_ptm_connect(struct event *t)
213
{
214
  int init = 0;
215
216
  if (ptm_cb.ptm_sock == -1) {
217
    zebra_ptm_socket_init();
218
    init = 1;
219
  }
220
221
  if (ptm_cb.ptm_sock != -1) {
222
    if (init) {
223
      ptm_cb.t_read = NULL;
224
      event_add_read(zrouter.master, zebra_ptm_sock_read,
225
               NULL, ptm_cb.ptm_sock, &ptm_cb.t_read);
226
      zebra_bfd_peer_replay_req();
227
    }
228
    zebra_ptm_send_status_req();
229
    ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
230
  } else if (ptm_cb.reconnect_time < ZEBRA_PTM_RECONNECT_TIME_MAX) {
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;
234
235
    ptm_cb.t_timer = NULL;
236
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
237
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
238
  } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) {
239
    ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
240
  }
241
}
242
243
DEFUN (zebra_ptm_enable,
244
       zebra_ptm_enable_cmd,
245
       "ptm-enable",
246
       "Enable neighbor check with specified topology\n")
247
{
248
  struct vrf *vrf;
249
  struct interface *ifp;
250
  struct zebra_if *if_data;
251
252
  ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
253
254
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
255
    FOR_ALL_INTERFACES (vrf, ifp)
256
      if (!ifp->ptm_enable) {
257
        if_data = (struct zebra_if *)ifp->info;
258
        if (if_data
259
            && (if_data->ptm_enable
260
          == ZEBRA_IF_PTM_ENABLE_UNSPEC)) {
261
          ifp->ptm_enable =
262
            ZEBRA_IF_PTM_ENABLE_ON;
263
        }
264
        /* Assign a default unknown status */
265
        ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
266
      }
267
268
  zebra_ptm_connect(NULL);
269
270
  return CMD_SUCCESS;
271
}
272
273
DEFUN (no_zebra_ptm_enable,
274
       no_zebra_ptm_enable_cmd,
275
       "no ptm-enable",
276
       NO_STR
277
       "Enable neighbor check with specified topology\n")
278
{
279
  ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
280
  zebra_ptm_reset_status(1);
281
  return CMD_SUCCESS;
282
}
283
284
DEFUN (zebra_ptm_enable_if,
285
       zebra_ptm_enable_if_cmd,
286
       "ptm-enable",
287
       "Enable neighbor check with specified topology\n")
288
{
289
  VTY_DECLVAR_CONTEXT(interface, ifp);
290
  struct zebra_if *if_data;
291
  int old_ptm_enable;
292
  int send_linkdown = 0;
293
294
  if_data = ifp->info;
295
  if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
296
297
  if (ifp->ifindex == IFINDEX_INTERNAL) {
298
    return CMD_SUCCESS;
299
  }
300
301
  old_ptm_enable = ifp->ptm_enable;
302
  ifp->ptm_enable = ptm_cb.ptm_enable;
303
304
  if (if_is_no_ptm_operative(ifp))
305
    send_linkdown = 1;
306
307
  if (!old_ptm_enable && ptm_cb.ptm_enable) {
308
    if (!if_is_operative(ifp) && send_linkdown) {
309
      if (IS_ZEBRA_DEBUG_EVENT)
310
        zlog_debug("%s: Bringing down interface %s",
311
             __func__, ifp->name);
312
      if_down(ifp);
313
    }
314
  }
315
316
  return CMD_SUCCESS;
317
}
318
319
DEFUN (no_zebra_ptm_enable_if,
320
       no_zebra_ptm_enable_if_cmd,
321
       "no ptm-enable",
322
       NO_STR
323
       "Enable neighbor check with specified topology\n")
324
{
325
  VTY_DECLVAR_CONTEXT(interface, ifp);
326
  int send_linkup = 0;
327
  struct zebra_if *if_data;
328
329
  if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) {
330
    if (!if_is_operative(ifp))
331
      send_linkup = 1;
332
333
    ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
334
    if (if_is_no_ptm_operative(ifp) && send_linkup) {
335
      if (IS_ZEBRA_DEBUG_EVENT)
336
        zlog_debug("%s: Bringing up interface %s",
337
             __func__, ifp->name);
338
      if_up(ifp, true);
339
    }
340
  }
341
342
  if_data = ifp->info;
343
  if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
344
345
  return CMD_SUCCESS;
346
}
347
348
349
void zebra_ptm_write(struct vty *vty)
350
{
351
  if (ptm_cb.ptm_enable)
352
    vty_out(vty, "ptm-enable\n");
353
354
  return;
355
}
356
357
static int zebra_ptm_socket_init(void)
358
{
359
  int ret;
360
  int sock;
361
  struct sockaddr_un addr;
362
363
  ptm_cb.ptm_sock = -1;
364
365
  sock = socket(PF_UNIX, SOCK_STREAM, 0);
366
  if (sock < 0)
367
    return -1;
368
  if (set_nonblocking(sock) < 0) {
369
    if (IS_ZEBRA_DEBUG_EVENT)
370
      zlog_debug("%s: Unable to set socket non blocking[%s]",
371
           __func__, safe_strerror(errno));
372
    close(sock);
373
    return -1;
374
  }
375
376
  /* Make server socket. */
377
  memset(&addr, 0, sizeof(addr));
378
  addr.sun_family = AF_UNIX;
379
  memcpy(&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
380
         sizeof(ZEBRA_PTM_SOCK_NAME));
381
382
  ret = connect(sock, (struct sockaddr *)&addr,
383
          sizeof(addr.sun_family) + sizeof(ZEBRA_PTM_SOCK_NAME)
384
            - 1);
385
  if (ret < 0) {
386
    if (IS_ZEBRA_DEBUG_EVENT)
387
      zlog_debug("%s: Unable to connect to socket %s [%s]",
388
           __func__, ZEBRA_PTM_SOCK_NAME,
389
           safe_strerror(errno));
390
    close(sock);
391
    return -1;
392
  }
393
  ptm_cb.ptm_sock = sock;
394
  return sock;
395
}
396
397
static void zebra_ptm_install_commands(void)
398
{
399
  install_element(CONFIG_NODE, &zebra_ptm_enable_cmd);
400
  install_element(CONFIG_NODE, &no_zebra_ptm_enable_cmd);
401
  install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd);
402
  install_element(INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd);
403
}
404
405
/* BFD session goes down, send message to the protocols. */
406
static void if_bfd_session_update(struct interface *ifp, struct prefix *dp,
407
          struct prefix *sp, int status,
408
          vrf_id_t vrf_id)
409
{
410
  if (IS_ZEBRA_DEBUG_EVENT) {
411
    char buf[2][INET6_ADDRSTRLEN];
412
413
    if (ifp) {
414
      zlog_debug(
415
        "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s %s event",
416
        inet_ntop(dp->family, &dp->u.prefix, buf[0],
417
            INET6_ADDRSTRLEN),
418
        dp->prefixlen, ifp->name,
419
        bfd_get_status_str(status));
420
    } else {
421
      struct vrf *vrf = vrf_lookup_by_id(vrf_id);
422
423
      zlog_debug(
424
        "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d with src %s/%d and vrf %s(%u) %s event",
425
        inet_ntop(dp->family, &dp->u.prefix, buf[0],
426
            INET6_ADDRSTRLEN),
427
        dp->prefixlen,
428
        inet_ntop(sp->family, &sp->u.prefix, buf[1],
429
            INET6_ADDRSTRLEN),
430
        sp->prefixlen, VRF_LOGNAME(vrf), vrf_id,
431
        bfd_get_status_str(status));
432
    }
433
  }
434
435
  zebra_interface_bfd_update(ifp, dp, sp, status, vrf_id);
436
}
437
438
static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
439
            struct interface *ifp)
440
{
441
  char bfdst_str[32];
442
  char dest_str[64];
443
  char src_str[64];
444
  char vrf_str[64];
445
  struct prefix dest_prefix;
446
  struct prefix src_prefix;
447
  vrf_id_t vrf_id;
448
449
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
450
451
  if (bfdst_str[0] == '\0') {
452
    return -1;
453
  }
454
455
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
456
457
  if (dest_str[0] == '\0') {
458
    zlog_debug("%s: Key %s not found in PTM msg", __func__,
459
         ZEBRA_PTM_BFDDEST_STR);
460
    return -1;
461
  }
462
463
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
464
465
  if (src_str[0] == '\0') {
466
    zlog_debug("%s: Key %s not found in PTM msg", __func__,
467
         ZEBRA_PTM_BFDSRC_STR);
468
    return -1;
469
  }
470
471
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str);
472
473
  if (vrf_str[0] == '\0') {
474
    zlog_debug("%s: Key %s not found in PTM msg", __func__,
475
         ZEBRA_PTM_BFDVRF_STR);
476
    return -1;
477
  }
478
479
  if (IS_ZEBRA_DEBUG_EVENT)
480
    zlog_debug(
481
      "%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]",
482
      __func__, ifp ? ifp->name : "N/A", bfdst_str, vrf_str,
483
      dest_str, src_str);
484
485
  if (str2prefix(dest_str, &dest_prefix) == 0) {
486
    flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
487
       "%s: Peer addr %s not found", __func__, dest_str);
488
    return -1;
489
  }
490
491
  memset(&src_prefix, 0, sizeof(src_prefix));
492
  if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
493
    if (str2prefix(src_str, &src_prefix) == 0) {
494
      flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
495
         "%s: Local addr %s not found", __func__,
496
         src_str);
497
      return -1;
498
    }
499
  }
500
501
  if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
502
    vrf_id = ifp->vrf->vrf_id;
503
  } else {
504
    struct vrf *pVrf;
505
506
    pVrf = vrf_lookup_by_name(vrf_str);
507
    if (pVrf)
508
      vrf_id = pVrf->vrf_id;
509
    else
510
      vrf_id = VRF_DEFAULT;
511
  }
512
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);
516
  } else {
517
    if_bfd_session_update(ifp, &dest_prefix, &src_prefix,
518
              BFD_STATUS_UP, vrf_id);
519
  }
520
521
  return 0;
522
}
523
524
static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt,
525
            struct interface *ifp, char *cbl_str)
526
{
527
  int send_linkup = 0;
528
529
  if (IS_ZEBRA_DEBUG_EVENT)
530
    zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
531
         ifp->name, cbl_str);
532
533
  if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR)
534
      && (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) {
535
536
    if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)
537
      send_linkup = 1;
538
    ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
539
    if (ifp->ptm_enable && if_is_no_ptm_operative(ifp)
540
        && send_linkup)
541
      if_up(ifp, true);
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))
546
      if_down(ifp);
547
  }
548
549
  return 0;
550
}
551
552
/*
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.
555
 *
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.
563
 *
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.
567
 *
568
 */
569
static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
570
{
571
  struct interface *ifp = NULL;
572
  char port_str[128];
573
  char cbl_str[32];
574
  char cmd_status_str[32];
575
576
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR,
577
        cmd_status_str);
578
579
  /* Drop command response messages */
580
  if (cmd_status_str[0] != '\0') {
581
    return 0;
582
  }
583
584
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
585
586
  if (port_str[0] == '\0') {
587
    zlog_debug("%s: Key %s not found in PTM msg", __func__,
588
         ZEBRA_PTM_PORT_STR);
589
    return -1;
590
  }
591
592
  if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
593
    struct vrf *vrf;
594
    int count = 0;
595
596
    RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
597
      ifp = if_lookup_by_name_vrf(port_str, vrf);
598
      if (ifp) {
599
        count++;
600
        if (!vrf_is_backend_netns())
601
          break;
602
      }
603
    }
604
605
    if (!ifp) {
606
      flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
607
          "%s: %s not found in interface list",
608
          __func__, port_str);
609
      return -1;
610
    }
611
    if (count > 1) {
612
      flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
613
          "%s: multiple interface with name %s",
614
          __func__, port_str);
615
      return -1;
616
    }
617
  }
618
619
  ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str);
620
621
  if (cbl_str[0] == '\0') {
622
    return zebra_ptm_handle_bfd_msg(arg, in_ctxt, ifp);
623
  } else {
624
    if (ifp) {
625
      return zebra_ptm_handle_cbl_msg(arg, in_ctxt, ifp,
626
              cbl_str);
627
    } else {
628
      return -1;
629
    }
630
  }
631
}
632
633
void zebra_ptm_sock_read(struct event *thread)
634
{
635
  int sock;
636
  int rc;
637
638
  errno = 0;
639
  sock = EVENT_FD(thread);
640
641
  if (sock == -1)
642
    return;
643
644
  /* PTM communicates in CSV format */
645
  do {
646
    rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
647
           ZEBRA_PTM_MAX_SOCKBUF, NULL);
648
  } while (rc > 0);
649
650
  if (((rc == 0) && !errno)
651
      || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
652
    flog_err_sys(EC_LIB_SOCKET,
653
           "%s routing socket error: %s(%d) bytes %d",
654
           __func__, safe_strerror(errno), errno, rc);
655
656
    close(ptm_cb.ptm_sock);
657
    ptm_cb.ptm_sock = -1;
658
    zebra_ptm_reset_status(0);
659
    ptm_cb.t_timer = NULL;
660
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
661
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
662
    return;
663
  }
664
665
  ptm_cb.t_read = NULL;
666
  event_add_read(zrouter.master, zebra_ptm_sock_read, NULL,
667
           ptm_cb.ptm_sock, &ptm_cb.t_read);
668
}
669
670
/* BFD peer/dst register/update */
671
void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
672
{
673
  struct stream *s;
674
  struct prefix src_p;
675
  struct prefix dst_p;
676
  uint8_t multi_hop;
677
  uint8_t multi_hop_cnt;
678
  uint8_t detect_mul;
679
  unsigned int min_rx_timer;
680
  unsigned int min_tx_timer;
681
  char if_name[INTERFACE_NAMSIZ];
682
  uint8_t len;
683
  void *out_ctxt;
684
  char buf[INET6_ADDRSTRLEN];
685
  char tmp_buf[64];
686
  int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
687
  unsigned int pid;
688
  uint8_t cbit_set;
689
690
  if (hdr->command == ZEBRA_BFD_DEST_UPDATE)
691
    client->bfd_peer_upd8_cnt++;
692
  else
693
    client->bfd_peer_add_cnt++;
694
695
  if (IS_ZEBRA_DEBUG_EVENT)
696
    zlog_debug("bfd_dst_register msg from client %s: length=%d",
697
         zebra_route_string(client->proto), hdr->length);
698
699
  if (ptm_cb.ptm_sock == -1) {
700
    ptm_cb.t_timer = NULL;
701
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
702
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
703
    return;
704
  }
705
706
  ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
707
  snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_START_CMD);
708
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
709
  snprintf(tmp_buf, sizeof(tmp_buf), "%s",
710
     zebra_route_string(client->proto));
711
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
712
         tmp_buf);
713
714
  s = msg;
715
716
  STREAM_GETL(s, pid);
717
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
718
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
719
         tmp_buf);
720
721
  STREAM_GETW(s, dst_p.family);
722
723
  if (dst_p.family == AF_INET)
724
    dst_p.prefixlen = IPV4_MAX_BYTELEN;
725
  else
726
    dst_p.prefixlen = IPV6_MAX_BYTELEN;
727
728
  STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
729
  if (dst_p.family == AF_INET) {
730
    inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
731
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
732
           ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
733
  } else {
734
    inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
735
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
736
           ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
737
  }
738
739
  STREAM_GETL(s, min_rx_timer);
740
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_rx_timer);
741
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
742
         tmp_buf);
743
  STREAM_GETL(s, min_tx_timer);
744
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_tx_timer);
745
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
746
         tmp_buf);
747
  STREAM_GETC(s, detect_mul);
748
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", detect_mul);
749
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
750
         tmp_buf);
751
752
  STREAM_GETC(s, multi_hop);
753
  if (multi_hop) {
754
    snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
755
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
756
           ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
757
    STREAM_GETW(s, src_p.family);
758
759
    if (src_p.family == AF_INET)
760
      src_p.prefixlen = IPV4_MAX_BYTELEN;
761
    else
762
      src_p.prefixlen = IPV6_MAX_BYTELEN;
763
764
    STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
765
    if (src_p.family == AF_INET) {
766
      inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
767
      ptm_lib_append_msg(ptm_hdl, out_ctxt,
768
             ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
769
    } else {
770
      inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
771
      ptm_lib_append_msg(ptm_hdl, out_ctxt,
772
             ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
773
    }
774
775
    STREAM_GETC(s, multi_hop_cnt);
776
    snprintf(tmp_buf, sizeof(tmp_buf), "%d", multi_hop_cnt);
777
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
778
           ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD, tmp_buf);
779
780
    if (zvrf_id(zvrf) != VRF_DEFAULT)
781
      ptm_lib_append_msg(ptm_hdl, out_ctxt,
782
             ZEBRA_PTM_BFD_VRF_NAME_FIELD,
783
             zvrf_name(zvrf));
784
  } else {
785
    if (dst_p.family == AF_INET6) {
786
      STREAM_GETW(s, src_p.family);
787
788
      if (src_p.family == AF_INET)
789
        src_p.prefixlen = IPV4_MAX_BYTELEN;
790
      else
791
        src_p.prefixlen = IPV6_MAX_BYTELEN;
792
793
      STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
794
      if (src_p.family == AF_INET) {
795
        inet_ntop(AF_INET, &src_p.u.prefix4, buf,
796
            sizeof(buf));
797
        ptm_lib_append_msg(ptm_hdl, out_ctxt,
798
               ZEBRA_PTM_BFD_SRC_IP_FIELD,
799
               buf);
800
      } else {
801
        inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
802
            sizeof(buf));
803
        ptm_lib_append_msg(ptm_hdl, out_ctxt,
804
               ZEBRA_PTM_BFD_SRC_IP_FIELD,
805
               buf);
806
      }
807
    }
808
    STREAM_GETC(s, len);
809
    STREAM_GET(if_name, s, len);
810
    if_name[len] = '\0';
811
812
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
813
           ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
814
  }
815
  STREAM_GETC(s, cbit_set);
816
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", cbit_set);
817
  ptm_lib_append_msg(ptm_hdl, out_ctxt,
818
         ZEBRA_PTM_BFD_CBIT_FIELD, tmp_buf);
819
820
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
821
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,
822
         tmp_buf);
823
824
  ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
825
826
  if (IS_ZEBRA_DEBUG_SEND)
827
    zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
828
         ptm_cb.out_data);
829
  zebra_ptm_send_message(ptm_cb.out_data, data_len);
830
831
  return;
832
833
stream_failure:
834
  ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
835
}
836
837
/* BFD peer/dst deregister */
838
void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
839
{
840
  struct stream *s;
841
  struct prefix src_p;
842
  struct prefix dst_p;
843
  uint8_t multi_hop;
844
  char if_name[INTERFACE_NAMSIZ];
845
  uint8_t len;
846
  char buf[INET6_ADDRSTRLEN];
847
  char tmp_buf[64];
848
  int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
849
  void *out_ctxt;
850
  unsigned int pid;
851
852
  client->bfd_peer_del_cnt++;
853
854
  if (IS_ZEBRA_DEBUG_EVENT)
855
    zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
856
         zebra_route_string(client->proto), hdr->length);
857
858
  if (ptm_cb.ptm_sock == -1) {
859
    ptm_cb.t_timer = NULL;
860
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
861
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
862
    return;
863
  }
864
865
  ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
866
867
  snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_STOP_CMD);
868
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
869
870
  snprintf(tmp_buf, sizeof(tmp_buf), "%s",
871
     zebra_route_string(client->proto));
872
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
873
         tmp_buf);
874
875
  s = msg;
876
877
  STREAM_GETL(s, pid);
878
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
879
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
880
         tmp_buf);
881
882
  STREAM_GETW(s, dst_p.family);
883
884
  if (dst_p.family == AF_INET)
885
    dst_p.prefixlen = IPV4_MAX_BYTELEN;
886
  else
887
    dst_p.prefixlen = IPV6_MAX_BYTELEN;
888
889
  STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
890
  if (dst_p.family == AF_INET)
891
    inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
892
  else
893
    inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
894
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
895
896
897
  STREAM_GETC(s, multi_hop);
898
  if (multi_hop) {
899
    snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
900
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
901
           ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
902
903
    STREAM_GETW(s, src_p.family);
904
905
    if (src_p.family == AF_INET)
906
      src_p.prefixlen = IPV4_MAX_BYTELEN;
907
    else
908
      src_p.prefixlen = IPV6_MAX_BYTELEN;
909
910
    STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
911
    if (src_p.family == AF_INET)
912
      inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
913
    else
914
      inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
915
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
916
           ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
917
918
    if (zvrf_id(zvrf) != VRF_DEFAULT)
919
      ptm_lib_append_msg(ptm_hdl, out_ctxt,
920
             ZEBRA_PTM_BFD_VRF_NAME_FIELD,
921
             zvrf_name(zvrf));
922
  } else {
923
    if (dst_p.family == AF_INET6) {
924
      STREAM_GETW(s, src_p.family);
925
926
      if (src_p.family == AF_INET)
927
        src_p.prefixlen = IPV4_MAX_BYTELEN;
928
      else
929
        src_p.prefixlen = IPV6_MAX_BYTELEN;
930
931
      STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
932
      if (src_p.family == AF_INET) {
933
        inet_ntop(AF_INET, &src_p.u.prefix4, buf,
934
            sizeof(buf));
935
        ptm_lib_append_msg(ptm_hdl, out_ctxt,
936
               ZEBRA_PTM_BFD_SRC_IP_FIELD,
937
               buf);
938
      } else {
939
        inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
940
            sizeof(buf));
941
        ptm_lib_append_msg(ptm_hdl, out_ctxt,
942
               ZEBRA_PTM_BFD_SRC_IP_FIELD,
943
               buf);
944
      }
945
    }
946
947
    STREAM_GETC(s, len);
948
    STREAM_GET(if_name, s, len);
949
    if_name[len] = '\0';
950
951
    ptm_lib_append_msg(ptm_hdl, out_ctxt,
952
           ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
953
  }
954
955
  ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
956
  if (IS_ZEBRA_DEBUG_SEND)
957
    zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
958
         ptm_cb.out_data);
959
960
  zebra_ptm_send_message(ptm_cb.out_data, data_len);
961
962
  return;
963
964
stream_failure:
965
  ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
966
}
967
968
/* BFD client register */
969
void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
970
{
971
  struct stream *s;
972
  unsigned int pid;
973
  void *out_ctxt = NULL;
974
  char tmp_buf[64];
975
  int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
976
977
  client->bfd_client_reg_cnt++;
978
979
  if (IS_ZEBRA_DEBUG_EVENT)
980
    zlog_debug("bfd_client_register msg from client %s: length=%d",
981
         zebra_route_string(client->proto), hdr->length);
982
983
  s = msg;
984
  STREAM_GETL(s, pid);
985
986
  if (ptm_cb.ptm_sock == -1) {
987
    ptm_cb.t_timer = NULL;
988
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
989
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
990
    return;
991
  }
992
993
  ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
994
995
  snprintf(tmp_buf, sizeof(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
  snprintf(tmp_buf, sizeof(tmp_buf), "%s",
999
     zebra_route_string(client->proto));
1000
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1001
         tmp_buf);
1002
1003
  snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
1004
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
1005
         tmp_buf);
1006
1007
  ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1008
1009
  if (IS_ZEBRA_DEBUG_SEND)
1010
    zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1011
         ptm_cb.out_data);
1012
  zebra_ptm_send_message(ptm_cb.out_data, data_len);
1013
1014
  SET_FLAG(ptm_cb.client_flags[client->proto],
1015
     ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1016
1017
  return;
1018
1019
stream_failure:
1020
  /*
1021
   * IF we ever add more STREAM_GETXXX functions after the out_ctxt
1022
   * is allocated then we need to add this code back in
1023
   *
1024
   * if (out_ctxt)
1025
   *  ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
1026
   */
1027
  return;
1028
}
1029
1030
/* BFD client deregister */
1031
int zebra_ptm_bfd_client_deregister(struct zserv *client)
1032
{
1033
  uint8_t proto = client->proto;
1034
  void *out_ctxt;
1035
  char tmp_buf[64];
1036
  int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1037
1038
  if (!IS_BFD_ENABLED_PROTOCOL(proto))
1039
    return 0;
1040
1041
  if (IS_ZEBRA_DEBUG_EVENT)
1042
    zlog_debug("bfd_client_deregister msg for client %s",
1043
         zebra_route_string(proto));
1044
1045
  if (ptm_cb.ptm_sock == -1) {
1046
    ptm_cb.t_timer = NULL;
1047
    event_add_timer(zrouter.master, zebra_ptm_connect, NULL,
1048
        ptm_cb.reconnect_time, &ptm_cb.t_timer);
1049
    return 0;
1050
  }
1051
1052
  ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
1053
1054
  snprintf(tmp_buf, sizeof(tmp_buf), "%s",
1055
     ZEBRA_PTM_BFD_CLIENT_DEREG_CMD);
1056
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
1057
1058
  snprintf(tmp_buf, sizeof(tmp_buf), "%s", zebra_route_string(proto));
1059
  ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
1060
         tmp_buf);
1061
1062
  ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
1063
1064
  if (IS_ZEBRA_DEBUG_SEND)
1065
    zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
1066
         ptm_cb.out_data);
1067
1068
  zebra_ptm_send_message(ptm_cb.out_data, data_len);
1069
  UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
1070
1071
  return 0;
1072
}
1073
1074
int zebra_ptm_get_enable_state(void)
1075
{
1076
  return ptm_cb.ptm_enable;
1077
}
1078
1079
/*
1080
 * zebra_ptm_get_status_str - Convert status to a display string.
1081
 */
1082
static const char *zebra_ptm_get_status_str(int status)
1083
{
1084
  switch (status) {
1085
  case ZEBRA_PTM_STATUS_DOWN:
1086
    return "fail";
1087
  case ZEBRA_PTM_STATUS_UP:
1088
    return "pass";
1089
  case ZEBRA_PTM_STATUS_UNKNOWN:
1090
  default:
1091
    return "n/a";
1092
  }
1093
}
1094
1095
void zebra_ptm_show_status(struct vty *vty, json_object *json,
1096
         struct interface *ifp)
1097
{
1098
  const char *status;
1099
1100
  if (ifp->ptm_enable)
1101
    status = zebra_ptm_get_status_str(ifp->ptm_status);
1102
  else
1103
    status = "disabled";
1104
1105
  if (json)
1106
    json_object_string_add(json, "ptmStatus", status);
1107
  else
1108
    vty_out(vty, "  PTM status: %s\n", status);
1109
}
1110
1111
void zebra_ptm_send_status_req(void)
1112
{
1113
  void *out_ctxt;
1114
  int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
1115
1116
  if (ptm_cb.ptm_enable) {
1117
    ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL,
1118
         &out_ctxt);
1119
    ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
1120
           ZEBRA_PTM_GET_STATUS_CMD);
1121
    ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
1122
1123
    zebra_ptm_send_message(ptm_cb.out_data, len);
1124
  }
1125
}
1126
1127
void zebra_ptm_reset_status(int ptm_disable)
1128
{
1129
  struct vrf *vrf;
1130
  struct interface *ifp;
1131
  int send_linkup;
1132
1133
  RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
1134
    FOR_ALL_INTERFACES (vrf, ifp) {
1135
      send_linkup = 0;
1136
      if (ifp->ptm_enable) {
1137
        if (!if_is_operative(ifp))
1138
          send_linkup = 1;
1139
1140
        if (ptm_disable)
1141
          ifp->ptm_enable =
1142
            ZEBRA_IF_PTM_ENABLE_OFF;
1143
        ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
1144
1145
        if (if_is_operative(ifp) && send_linkup) {
1146
          if (IS_ZEBRA_DEBUG_EVENT)
1147
            zlog_debug(
1148
              "%s: Bringing up interface %s",
1149
              __func__, ifp->name);
1150
          if_up(ifp, true);
1151
        }
1152
      }
1153
    }
1154
}
1155
1156
void zebra_ptm_if_init(struct zebra_if *zebra_ifp)
1157
{
1158
  zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
1159
}
1160
1161
void zebra_ptm_if_set_ptm_state(struct interface *ifp,
1162
        struct zebra_if *zebra_ifp)
1163
{
1164
  if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
1165
    ifp->ptm_enable = zebra_ifp->ptm_enable;
1166
}
1167
1168
void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
1169
{
1170
  if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
1171
    vty_out(vty, " no ptm-enable\n");
1172
}
1173
1174
#else /* HAVE_BFDD */
1175
1176
/*
1177
 * Data structures.
1178
 */
1179
struct ptm_process {
1180
  struct zserv *pp_zs;
1181
  pid_t pp_pid;
1182
1183
  TAILQ_ENTRY(ptm_process) pp_entry;
1184
};
1185
TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
1186
1187
2
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
1188
2
        "PTM BFD process reg table");
1189
2
1190
2
/*
1191
2
 * Prototypes.
1192
2
 */
1193
2
static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
1194
2
static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
1195
2
static void pp_free(struct ptm_process *pp);
1196
2
static void pp_free_all(void);
1197
2
1198
2
static void zebra_ptm_send_bfdd(struct stream *msg);
1199
2
static void zebra_ptm_send_clients(struct stream *msg);
1200
2
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
1201
2
static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
1202
2
             struct stream *msg, uint32_t command);
1203
2
1204
2
1205
2
/*
1206
2
 * Process PID registration.
1207
2
 */
1208
2
static struct ptm_process *pp_new(pid_t pid, struct zserv *zs)
1209
5
{
1210
5
  struct ptm_process *pp;
1211
1212
#ifdef PTM_DEBUG
1213
  /* Sanity check: more than one client can't have the same PID. */
1214
  TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1215
    if (pp->pp_pid == pid && pp->pp_zs != zs)
1216
      zlog_err("%s:%d pid and client pointer doesn't match",
1217
         __FILE__, __LINE__);
1218
  }
1219
#endif /* PTM_DEBUG */
1220
1221
  /* Lookup for duplicates. */
1222
5
  pp = pp_lookup_byzs(zs);
1223
5
  if (pp != NULL)
1224
2
    return pp;
1225
1226
  /* Allocate and register new process. */
1227
3
  pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
1228
1229
3
  pp->pp_pid = pid;
1230
3
  pp->pp_zs = zs;
1231
3
  TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
1232
1233
3
  return pp;
1234
5
}
1235
1236
static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
1237
5
{
1238
5
  struct ptm_process *pp;
1239
1240
5
  TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
1241
5
    if (pp->pp_zs != zs)
1242
3
      continue;
1243
1244
2
    break;
1245
5
  }
1246
1247
5
  return pp;
1248
5
}
1249
1250
static void pp_free(struct ptm_process *pp)
1251
0
{
1252
0
  if (pp == NULL)
1253
0
    return;
1254
1255
0
  TAILQ_REMOVE(&ppqueue, pp, pp_entry);
1256
0
  XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
1257
0
}
1258
1259
static void pp_free_all(void)
1260
0
{
1261
0
  struct ptm_process *pp;
1262
1263
0
  while (!TAILQ_EMPTY(&ppqueue)) {
1264
0
    pp = TAILQ_FIRST(&ppqueue);
1265
0
    pp_free(pp);
1266
0
  }
1267
0
}
1268
1269
1270
/*
1271
 * Use the FRR's internal daemon implementation.
1272
 */
1273
static void zebra_ptm_send_bfdd(struct stream *msg)
1274
5
{
1275
5
  struct listnode *node;
1276
5
  struct zserv *client;
1277
5
  struct stream *msgc;
1278
1279
  /* Create copy for replication. */
1280
5
  msgc = stream_dup(msg);
1281
1282
  /* Send message to all running BFDd daemons. */
1283
5
  for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
1284
5
    if (client->proto != ZEBRA_ROUTE_BFD)
1285
5
      continue;
1286
1287
0
    zserv_send_message(client, msg);
1288
1289
    /* Allocate more messages. */
1290
0
    msg = stream_dup(msgc);
1291
0
  }
1292
1293
5
  stream_free(msgc);
1294
5
  stream_free(msg);
1295
5
}
1296
1297
static void zebra_ptm_send_clients(struct stream *msg)
1298
0
{
1299
0
  struct listnode *node;
1300
0
  struct zserv *client;
1301
0
  struct stream *msgc;
1302
1303
  /* Create copy for replication. */
1304
0
  msgc = stream_dup(msg);
1305
1306
  /* Send message to all running client daemons. */
1307
0
  for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
1308
0
    if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
1309
0
      continue;
1310
1311
0
    zserv_send_message(client, msg);
1312
1313
    /* Allocate more messages. */
1314
0
    msg = stream_dup(msgc);
1315
0
  }
1316
1317
0
  stream_free(msgc);
1318
0
  stream_free(msg);
1319
0
}
1320
1321
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
1322
0
{
1323
0
  struct stream *msg;
1324
0
  struct ptm_process *pp;
1325
1326
0
  if (!IS_BFD_ENABLED_PROTOCOL(zs->proto))
1327
0
    return 0;
1328
1329
  /* Find daemon pid by zebra connection pointer. */
1330
0
  pp = pp_lookup_byzs(zs);
1331
0
  if (pp == NULL) {
1332
0
    zlog_err("%s:%d failed to find process pid registration",
1333
0
       __FILE__, __LINE__);
1334
0
    return -1;
1335
0
  }
1336
1337
  /* Generate, send message and free() daemon related data. */
1338
0
  msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
1339
0
  if (msg == NULL) {
1340
0
    zlog_debug("%s: not enough memory", __func__);
1341
0
    return 0;
1342
0
  }
1343
1344
  /*
1345
   * The message type will be ZEBRA_BFD_DEST_REPLAY so we can use only
1346
   * one callback at the `bfdd` side, however the real command
1347
   * number will be included right after the zebra header.
1348
   */
1349
0
  zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
1350
0
  stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
1351
1352
  /* Put process PID. */
1353
0
  stream_putl(msg, pp->pp_pid);
1354
1355
  /* Update the data pointers. */
1356
0
  stream_putw_at(msg, 0, stream_get_endp(msg));
1357
1358
0
  zebra_ptm_send_bfdd(msg);
1359
1360
0
  pp_free(pp);
1361
1362
0
  return 0;
1363
0
}
1364
1365
void zebra_ptm_init(void)
1366
0
{
1367
  /* Initialize the ptm process information list. */
1368
0
  TAILQ_INIT(&ppqueue);
1369
1370
  /*
1371
   * Send deregistration messages to BFD daemon when some other
1372
   * daemon closes. This will help avoid sending daemons
1373
   * unnecessary notification messages.
1374
   */
1375
0
  hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1376
0
}
1377
1378
void zebra_ptm_finish(void)
1379
0
{
1380
  /* Remove the client disconnect hook and free all memory. */
1381
0
  hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
1382
0
  pp_free_all();
1383
0
}
1384
1385
1386
/*
1387
 * Message handling.
1388
 */
1389
static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
1390
             struct stream *msg, uint32_t command)
1391
5
{
1392
5
  struct stream *msgc;
1393
5
  char buf[ZEBRA_MAX_PACKET_SIZ];
1394
5
  pid_t ppid;
1395
1396
  /* Create BFD header */
1397
5
  msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1398
5
  zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
1399
5
  stream_putl(msgc, command);
1400
1401
5
  if (STREAM_READABLE(msg) > STREAM_WRITEABLE(msgc)) {
1402
0
    zlog_warn("Cannot fit extended BFD header plus original message contents into ZAPI packet; dropping message");
1403
0
    goto stream_failure;
1404
0
  }
1405
1406
  /* Copy original message, excluding header, into new message */
1407
5
  stream_get_from(buf, msg, stream_get_getp(msg), STREAM_READABLE(msg));
1408
5
  stream_put(msgc, buf, STREAM_READABLE(msg));
1409
1410
  /* Update length field */
1411
5
  stream_putw_at(msgc, 0, STREAM_READABLE(msgc));
1412
1413
5
  zebra_ptm_send_bfdd(msgc);
1414
5
  msgc = NULL;
1415
1416
  /* Registrate process PID for shutdown hook. */
1417
5
  STREAM_GETL(msg, ppid);
1418
5
  pp_new(ppid, zs);
1419
1420
5
  return;
1421
1422
0
stream_failure:
1423
0
  if (msgc)
1424
0
    stream_free(msgc);
1425
0
  zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
1426
0
}
1427
1428
void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
1429
4
{
1430
4
  if (IS_ZEBRA_DEBUG_EVENT)
1431
0
    zlog_debug("bfd_dst_register msg from client %s: length=%d",
1432
4
         zebra_route_string(client->proto), hdr->length);
1433
1434
4
  _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
1435
4
}
1436
1437
void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
1438
0
{
1439
0
  if (IS_ZEBRA_DEBUG_EVENT)
1440
0
    zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
1441
0
         zebra_route_string(client->proto), hdr->length);
1442
1443
0
  _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
1444
0
}
1445
1446
void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
1447
0
{
1448
0
  if (IS_ZEBRA_DEBUG_EVENT)
1449
0
    zlog_debug("bfd_client_register msg from client %s: length=%d",
1450
0
         zebra_route_string(client->proto), hdr->length);
1451
1452
0
  _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
1453
0
}
1454
1455
void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
1456
1
{
1457
1
  struct stream *msgc;
1458
1
  size_t zmsglen, zhdrlen;
1459
1
  uint32_t cmd;
1460
1461
  /*
1462
   * NOTE:
1463
   * Replay messages with HAVE_BFDD are meant to be replayed to
1464
   * the client daemons. These messages are composed and
1465
   * originated from the `bfdd` daemon.
1466
   */
1467
1
  if (IS_ZEBRA_DEBUG_EVENT)
1468
0
    zlog_debug("bfd_dst_update msg from client %s: length=%d",
1469
1
         zebra_route_string(client->proto), hdr->length);
1470
1471
  /*
1472
   * Client messages must be re-routed, otherwise do the `bfdd`
1473
   * special treatment.
1474
   */
1475
1
  if (client->proto != ZEBRA_ROUTE_BFD) {
1476
1
    _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
1477
1
    return;
1478
1
  }
1479
1480
  /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
1481
0
  if (stream_getl2(msg, &cmd) == false) {
1482
0
    zlog_err("%s: expected at least 4 bytes (command)", __func__);
1483
0
    return;
1484
0
  }
1485
1486
  /*
1487
   * Don't modify message in the zebra API. In order to do that we
1488
   * need to allocate a new message stream and copy the message
1489
   * provided by zebra.
1490
   */
1491
0
  msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
1492
0
  if (msgc == NULL) {
1493
0
    zlog_debug("%s: not enough memory", __func__);
1494
0
    return;
1495
0
  }
1496
1497
  /* Calculate our header size plus the message contents. */
1498
0
  if (cmd != ZEBRA_BFD_DEST_REPLAY) {
1499
0
    zhdrlen = ZEBRA_HEADER_SIZE;
1500
0
    zmsglen = msg->endp - msg->getp;
1501
0
    memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
1502
1503
0
    zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1504
1505
0
    msgc->getp = 0;
1506
0
    msgc->endp = zhdrlen + zmsglen;
1507
0
  } else
1508
0
    zclient_create_header(msgc, cmd, zvrf_id(zvrf));
1509
1510
  /* Update the data pointers. */
1511
0
  stream_putw_at(msgc, 0, stream_get_endp(msgc));
1512
1513
0
  zebra_ptm_send_clients(msgc);
1514
0
}
1515
1516
/*
1517
 * Unused functions.
1518
 */
1519
void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
1520
0
{
1521
  /* NOTHING */
1522
0
}
1523
1524
int zebra_ptm_get_enable_state(void)
1525
0
{
1526
0
  return 0;
1527
0
}
1528
1529
void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
1530
         json_object *json __attribute__((__unused__)),
1531
         struct interface *ifp __attribute__((__unused__)))
1532
0
{
1533
  /* NOTHING */
1534
0
}
1535
1536
void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
1537
0
{
1538
  /* NOTHING */
1539
0
}
1540
1541
void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
1542
      struct zebra_if *zifp __attribute__((__unused__)))
1543
0
{
1544
  /* NOTHING */
1545
0
}
1546
void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
1547
        struct zebra_if *zi __attribute__((__unused__)))
1548
0
{
1549
  /* NOTHING */
1550
0
}
1551
1552
#endif /* HAVE_BFDD */