Coverage Report

Created: 2026-02-21 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/bgp_flowspec_vty.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* BGP FlowSpec VTY
3
 * Copyright (C) 2018 6WIND
4
 */
5
6
#include <zebra.h>
7
#include "command.h"
8
9
#include "bgpd/bgpd.h"
10
#include "bgpd/bgp_table.h"
11
#include "bgpd/bgp_attr.h"
12
#include "bgpd/bgp_ecommunity.h"
13
#include "bgpd/bgp_vty.h"
14
#include "bgpd/bgp_route.h"
15
#include "bgpd/bgp_aspath.h"
16
#include "bgpd/bgp_flowspec.h"
17
#include "bgpd/bgp_flowspec_util.h"
18
#include "bgpd/bgp_flowspec_private.h"
19
#include "bgpd/bgp_debug.h"
20
#include "bgpd/bgp_pbr.h"
21
22
/* Local Structures and variables declarations
23
 * This code block hosts the struct declared that host the flowspec rules
24
 * as well as some structure used to convert to stringx
25
 */
26
27
static const struct message bgp_flowspec_display_large[] = {
28
  {FLOWSPEC_DEST_PREFIX, "Destination Address"},
29
  {FLOWSPEC_SRC_PREFIX, "Source Address"},
30
  {FLOWSPEC_IP_PROTOCOL, "IP Protocol"},
31
  {FLOWSPEC_PORT, "Port"},
32
  {FLOWSPEC_DEST_PORT, "Destination Port"},
33
  {FLOWSPEC_SRC_PORT, "Source Port"},
34
  {FLOWSPEC_ICMP_TYPE, "ICMP Type"},
35
  {FLOWSPEC_ICMP_CODE, "ICMP Code"},
36
  {FLOWSPEC_TCP_FLAGS, "TCP Flags"},
37
  {FLOWSPEC_PKT_LEN, "Packet Length"},
38
  {FLOWSPEC_DSCP, "DSCP field"},
39
  {FLOWSPEC_FRAGMENT, "Packet Fragment"},
40
  {FLOWSPEC_FLOW_LABEL, "Packet Flow Label"},
41
  {0}
42
};
43
44
static const struct message bgp_flowspec_display_min[] = {
45
  {FLOWSPEC_DEST_PREFIX, "to"},
46
  {FLOWSPEC_SRC_PREFIX, "from"},
47
  {FLOWSPEC_IP_PROTOCOL, "proto"},
48
  {FLOWSPEC_PORT, "port"},
49
  {FLOWSPEC_DEST_PORT, "dstp"},
50
  {FLOWSPEC_SRC_PORT, "srcp"},
51
  {FLOWSPEC_ICMP_TYPE, "type"},
52
  {FLOWSPEC_ICMP_CODE, "code"},
53
  {FLOWSPEC_TCP_FLAGS, "tcp"},
54
  {FLOWSPEC_PKT_LEN, "pktlen"},
55
  {FLOWSPEC_DSCP, "dscp"},
56
  {FLOWSPEC_FRAGMENT, "pktfrag"},
57
  {FLOWSPEC_FLOW_LABEL, "flwlbl"},
58
  {0}
59
};
60
61
0
#define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \
62
0
    int _len_written;         \
63
0
                  \
64
0
    if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\
65
0
      _len_written = snprintf((ptr), (remaining_len), \
66
0
            ", ");      \
67
0
      (remaining_len) -= _len_written;    \
68
0
      (ptr) += _len_written;        \
69
0
    } else if (((format) == NLRI_STRING_FORMAT_MIN)   \
70
0
         && (count)) {       \
71
0
      _len_written = snprintf((ptr), (remaining_len), \
72
0
            " ");     \
73
0
      (remaining_len) -= _len_written;    \
74
0
      (ptr) += _len_written;        \
75
0
    }              \
76
0
    count++;            \
77
0
  } while (0)
78
79
/* Parse FLOWSPEC NLRI
80
 * passed return_string string has assumed length
81
 * BGP_FLOWSPEC_STRING_DISPLAY_MAX
82
 */
83
void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
84
          char *return_string, int format,
85
          json_object *json_path,
86
          afi_t afi)
87
0
{
88
0
  uint32_t offset = 0;
89
0
  int type;
90
0
  int ret = 0, error = 0;
91
0
  char *ptr = return_string;
92
0
  char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
93
0
  int count = 0;
94
0
  char extra[2] = "";
95
0
  char pre_extra[2] = "";
96
0
  const struct message *bgp_flowspec_display;
97
0
  enum bgp_flowspec_util_nlri_t type_util;
98
0
  int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
99
0
  int len_written;
100
101
0
  if (format == NLRI_STRING_FORMAT_LARGE) {
102
0
    snprintf(pre_extra, sizeof(pre_extra), "\t");
103
0
    snprintf(extra, sizeof(extra), "\n");
104
0
    bgp_flowspec_display = bgp_flowspec_display_large;
105
0
  } else
106
0
    bgp_flowspec_display = bgp_flowspec_display_min;
107
  /* if needed. type_util can be set to other values */
108
0
  type_util = BGP_FLOWSPEC_RETURN_STRING;
109
0
  error = 0;
110
0
  while (offset < len-1 && error >= 0) {
111
0
    type = nlri_content[offset];
112
0
    offset++;
113
0
    switch (type) {
114
0
    case FLOWSPEC_DEST_PREFIX:
115
0
    case FLOWSPEC_SRC_PREFIX:
116
0
      ret = bgp_flowspec_ip_address(
117
0
            type_util,
118
0
            nlri_content+offset,
119
0
            len - offset,
120
0
            local_string, &error,
121
0
            afi, NULL);
122
0
      if (ret <= 0)
123
0
        break;
124
0
      if (json_path) {
125
0
        json_object_string_add(json_path,
126
0
             lookup_msg(bgp_flowspec_display, type, ""),
127
0
             local_string);
128
0
        break;
129
0
      }
130
0
      FS_STRING_UPDATE(count, ptr, format, len_string);
131
0
      len_written = snprintf(ptr, len_string, "%s%s %s%s",
132
0
          pre_extra,
133
0
          lookup_msg(bgp_flowspec_display,
134
0
               type, ""),
135
0
          local_string, extra);
136
0
      len_string -= len_written;
137
0
      ptr += len_written;
138
0
      break;
139
0
    case FLOWSPEC_FLOW_LABEL:
140
0
    case FLOWSPEC_IP_PROTOCOL:
141
0
    case FLOWSPEC_PORT:
142
0
    case FLOWSPEC_DEST_PORT:
143
0
    case FLOWSPEC_SRC_PORT:
144
0
    case FLOWSPEC_ICMP_TYPE:
145
0
    case FLOWSPEC_ICMP_CODE:
146
0
      ret = bgp_flowspec_op_decode(type_util,
147
0
                 nlri_content+offset,
148
0
                 len - offset,
149
0
                 local_string, &error);
150
0
      if (ret <= 0)
151
0
        break;
152
0
      if (json_path) {
153
0
        json_object_string_add(json_path,
154
0
             lookup_msg(bgp_flowspec_display, type, ""),
155
0
             local_string);
156
0
        break;
157
0
      }
158
0
      FS_STRING_UPDATE(count, ptr, format, len_string);
159
0
      len_written = snprintf(ptr, len_string, "%s%s %s%s",
160
0
          pre_extra,
161
0
          lookup_msg(bgp_flowspec_display,
162
0
          type, ""),
163
0
             local_string, extra);
164
0
      len_string -= len_written;
165
0
      ptr += len_written;
166
0
      break;
167
0
    case FLOWSPEC_TCP_FLAGS:
168
0
      ret = bgp_flowspec_bitmask_decode(
169
0
                type_util,
170
0
                nlri_content+offset,
171
0
                len - offset,
172
0
                local_string, &error);
173
0
      if (ret <= 0)
174
0
        break;
175
0
      if (json_path) {
176
0
        json_object_string_add(json_path,
177
0
             lookup_msg(bgp_flowspec_display,
178
0
            type, ""),
179
0
             local_string);
180
0
        break;
181
0
      }
182
0
      FS_STRING_UPDATE(count, ptr, format, len_string);
183
0
      len_written = snprintf(ptr, len_string, "%s%s %s%s",
184
0
          pre_extra,
185
0
          lookup_msg(bgp_flowspec_display,
186
0
               type, ""),
187
0
          local_string, extra);
188
0
      len_string -= len_written;
189
0
      ptr += len_written;
190
0
      break;
191
0
    case FLOWSPEC_PKT_LEN:
192
0
    case FLOWSPEC_DSCP:
193
0
      ret = bgp_flowspec_op_decode(
194
0
            type_util,
195
0
            nlri_content + offset,
196
0
            len - offset, local_string,
197
0
            &error);
198
0
      if (ret <= 0)
199
0
        break;
200
0
      if (json_path) {
201
0
        json_object_string_add(json_path,
202
0
            lookup_msg(bgp_flowspec_display, type, ""),
203
0
            local_string);
204
0
        break;
205
0
      }
206
0
      FS_STRING_UPDATE(count, ptr, format, len_string);
207
0
      len_written = snprintf(ptr, len_string, "%s%s %s%s",
208
0
          pre_extra,
209
0
          lookup_msg(bgp_flowspec_display,
210
0
          type, ""),
211
0
             local_string, extra);
212
0
      len_string -= len_written;
213
0
      ptr += len_written;
214
0
      break;
215
0
    case FLOWSPEC_FRAGMENT:
216
0
      ret = bgp_flowspec_bitmask_decode(
217
0
                type_util,
218
0
                nlri_content+offset,
219
0
                len - offset,
220
0
                local_string, &error);
221
0
      if (ret <= 0)
222
0
        break;
223
0
      if (json_path) {
224
0
        json_object_string_add(json_path,
225
0
            lookup_msg(bgp_flowspec_display,
226
0
                 type, ""),
227
0
            local_string);
228
0
        break;
229
0
      }
230
0
      FS_STRING_UPDATE(count, ptr, format, len_string);
231
0
      len_written = snprintf(ptr, len_string, "%s%s %s%s",
232
0
          pre_extra,
233
0
          lookup_msg(bgp_flowspec_display,
234
0
          type, ""),
235
0
          local_string, extra);
236
0
      len_string -= len_written;
237
0
      ptr += len_written;
238
0
      break;
239
0
    default:
240
0
      error = -1;
241
0
      break;
242
0
    }
243
0
    offset += ret;
244
0
  }
245
0
}
246
247
void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
248
          struct bgp_path_info *path, int display,
249
          json_object *json_paths)
250
0
{
251
0
  struct attr *attr;
252
0
  char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
253
0
  char *s1 = NULL, *s2 = NULL;
254
0
  json_object *json_nlri_path = NULL;
255
0
  json_object *json_ecom_path = NULL;
256
0
  json_object *json_time_path = NULL;
257
0
  char timebuf[BGP_UPTIME_LEN];
258
0
  struct ecommunity *ipv6_ecomm = NULL;
259
260
0
  if (p == NULL || p->family != AF_FLOWSPEC)
261
0
    return;
262
0
  if (json_paths) {
263
0
    if (display == NLRI_STRING_FORMAT_JSON)
264
0
      json_nlri_path = json_object_new_object();
265
0
    else
266
0
      json_nlri_path = json_paths;
267
0
  }
268
0
  if (display == NLRI_STRING_FORMAT_LARGE && path)
269
0
    vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
270
0
      path->flags);
271
0
  bgp_fs_nlri_get_string((unsigned char *)
272
0
             p->u.prefix_flowspec.ptr,
273
0
             p->u.prefix_flowspec.prefixlen,
274
0
             return_string,
275
0
             display,
276
0
             json_nlri_path,
277
0
             family2afi(p->u.prefix_flowspec
278
0
            .family));
279
0
  if (display == NLRI_STRING_FORMAT_LARGE)
280
0
    vty_out(vty, "%s", return_string);
281
0
  else if (display == NLRI_STRING_FORMAT_DEBUG)
282
0
    vty_out(vty, "%s", return_string);
283
0
  else if (display == NLRI_STRING_FORMAT_MIN)
284
0
    vty_out(vty, " %-30s", return_string);
285
0
  else if (json_paths && display == NLRI_STRING_FORMAT_JSON)
286
0
    json_object_array_add(json_paths, json_nlri_path);
287
0
  if (!path)
288
0
    return;
289
290
0
  if (path->attr)
291
0
    ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(path->attr);
292
293
0
  if (path->attr && (bgp_attr_get_ecommunity(path->attr) || ipv6_ecomm)) {
294
    /* Print attribute */
295
0
    attr = path->attr;
296
0
    if (bgp_attr_get_ecommunity(attr))
297
0
      s1 = ecommunity_ecom2str(bgp_attr_get_ecommunity(attr),
298
0
             ECOMMUNITY_FORMAT_ROUTE_MAP,
299
0
             0);
300
0
    if (ipv6_ecomm)
301
0
      s2 = ecommunity_ecom2str(
302
0
        ipv6_ecomm, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
303
0
    if (!s1 && !s2)
304
0
      return;
305
0
    if (display == NLRI_STRING_FORMAT_LARGE)
306
0
      vty_out(vty, "\t%s%s%s\n", s1 ? s1 : "",
307
0
        s2 && s1 ? " " : "", s2 ? s2 : "");
308
0
    else if (display == NLRI_STRING_FORMAT_MIN)
309
0
      vty_out(vty, "%s%s", s1 ? s1 : "", s2 ? s2 : "");
310
0
    else if (json_paths) {
311
0
      json_ecom_path = json_object_new_object();
312
0
      if (s1)
313
0
        json_object_string_add(json_ecom_path,
314
0
                   "ecomlist", s1);
315
0
      if (s2)
316
0
        json_object_string_add(json_ecom_path,
317
0
                   "ecom6list", s2);
318
0
      if (display == NLRI_STRING_FORMAT_JSON)
319
0
        json_object_array_add(json_paths,
320
0
                  json_ecom_path);
321
0
    }
322
0
    if (display == NLRI_STRING_FORMAT_LARGE) {
323
0
      char local_buff[INET6_ADDRSTRLEN];
324
325
0
      local_buff[0] = '\0';
326
0
      if (p->u.prefix_flowspec.family == AF_INET
327
0
          && attr->nexthop.s_addr != INADDR_ANY)
328
0
        inet_ntop(AF_INET, &attr->nexthop.s_addr,
329
0
            local_buff, sizeof(local_buff));
330
0
      else if (p->u.prefix_flowspec.family == AF_INET6 &&
331
0
         attr->mp_nexthop_len != 0 &&
332
0
         attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 &&
333
0
         attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4)
334
0
        inet_ntop(AF_INET6, &attr->mp_nexthop_global,
335
0
            local_buff, sizeof(local_buff));
336
0
      if (local_buff[0] != '\0')
337
0
        vty_out(vty, "\tNLRI NH %s\n",
338
0
          local_buff);
339
0
    }
340
0
    XFREE(MTYPE_ECOMMUNITY_STR, s1);
341
0
    XFREE(MTYPE_ECOMMUNITY_STR, s2);
342
0
  }
343
0
  peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
344
0
  if (display == NLRI_STRING_FORMAT_LARGE) {
345
0
    vty_out(vty, "\treceived for %8s\n", timebuf);
346
0
  } else if (json_paths) {
347
0
    json_time_path = json_object_new_object();
348
0
    json_object_string_add(json_time_path,
349
0
               "time", timebuf);
350
0
    if (display == NLRI_STRING_FORMAT_JSON)
351
0
      json_object_array_add(json_paths, json_time_path);
352
0
  }
353
0
  if (display == NLRI_STRING_FORMAT_LARGE) {
354
0
    struct bgp_path_info_extra *extra =
355
0
      bgp_path_info_extra_get(path);
356
0
    bool list_began = false;
357
358
0
    if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) {
359
0
      struct listnode *node;
360
0
      struct bgp_pbr_match_entry *bpme;
361
0
      struct bgp_pbr_match *bpm;
362
0
      struct list *list_bpm;
363
364
0
      list_bpm = list_new();
365
0
      vty_out(vty, "\tinstalled in PBR");
366
0
      for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
367
0
              node, bpme)) {
368
0
        bpm = bpme->backpointer;
369
0
        if (listnode_lookup(list_bpm, bpm))
370
0
          continue;
371
0
        listnode_add(list_bpm, bpm);
372
0
        if (!list_began) {
373
0
          vty_out(vty, " (");
374
0
          list_began = true;
375
0
        } else
376
0
          vty_out(vty, ", ");
377
0
        vty_out(vty, "%s", bpm->ipset_name);
378
0
      }
379
0
      list_delete(&list_bpm);
380
0
    }
381
0
    if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) {
382
0
      struct listnode *node;
383
0
      struct bgp_pbr_rule *bpr;
384
385
0
      if (!list_began)
386
0
        vty_out(vty, "\tinstalled in PBR");
387
0
      for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule,
388
0
              node, bpr)) {
389
0
        if (!bpr->action)
390
0
          continue;
391
0
        if (!list_began) {
392
0
          vty_out(vty, " (");
393
0
          list_began = true;
394
0
        } else
395
0
          vty_out(vty, ", ");
396
0
        vty_out(vty, "-ipv4-rule %d action lookup %u-",
397
0
          bpr->priority,
398
0
          bpr->action->table_id);
399
0
      }
400
0
    }
401
0
    if (list_began)
402
0
      vty_out(vty, ")\n");
403
0
    else
404
0
      vty_out(vty, "\tnot installed in PBR\n");
405
0
  }
406
0
}
407
408
int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
409
          struct bgp_table *table, enum bgp_show_type type,
410
          void *output_arg, bool use_json, int is_last,
411
          unsigned long *output_cum, unsigned long *total_cum)
412
0
{
413
0
  struct bgp_path_info *pi;
414
0
  struct bgp_dest *dest;
415
0
  unsigned long total_count = 0;
416
0
  json_object *json_paths = NULL;
417
0
  int display = NLRI_STRING_FORMAT_LARGE;
418
419
0
  if (type != bgp_show_type_detail)
420
0
    return CMD_SUCCESS;
421
422
0
  for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
423
0
    pi = bgp_dest_get_bgp_path_info(dest);
424
0
    if (pi == NULL)
425
0
      continue;
426
0
    if (use_json) {
427
0
      json_paths = json_object_new_array();
428
0
      display = NLRI_STRING_FORMAT_JSON;
429
0
    }
430
0
    for (; pi; pi = pi->next) {
431
0
      total_count++;
432
0
      route_vty_out_flowspec(vty, bgp_dest_get_prefix(dest),
433
0
                 pi, display, json_paths);
434
0
    }
435
0
    if (use_json) {
436
0
      vty_json(vty, json_paths);
437
0
      json_paths = NULL;
438
0
    }
439
0
  }
440
0
  if (total_count && !use_json)
441
0
    vty_out(vty,
442
0
      "\nDisplayed  %ld flowspec entries\n",
443
0
      total_count);
444
0
  return CMD_SUCCESS;
445
0
}
446
447
DEFUN (debug_bgp_flowspec,
448
       debug_bgp_flowspec_cmd,
449
       "debug bgp flowspec",
450
       DEBUG_STR
451
       BGP_STR
452
       "BGP allow flowspec debugging entries\n")
453
0
{
454
0
  if (vty->node == CONFIG_NODE)
455
0
    DEBUG_ON(flowspec, FLOWSPEC);
456
0
  else {
457
0
    TERM_DEBUG_ON(flowspec, FLOWSPEC);
458
0
    vty_out(vty, "BGP flowspec debugging is on\n");
459
0
  }
460
0
  return CMD_SUCCESS;
461
0
}
462
463
DEFUN (no_debug_bgp_flowspec,
464
       no_debug_bgp_flowspec_cmd,
465
       "no debug bgp flowspec",
466
       NO_STR
467
       DEBUG_STR
468
       BGP_STR
469
       "BGP allow flowspec debugging entries\n")
470
0
{
471
0
  if (vty->node == CONFIG_NODE)
472
0
    DEBUG_OFF(flowspec, FLOWSPEC);
473
0
  else {
474
0
    TERM_DEBUG_OFF(flowspec, FLOWSPEC);
475
0
    vty_out(vty, "BGP flowspec debugging is off\n");
476
0
  }
477
0
  return CMD_SUCCESS;
478
0
}
479
480
int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
481
          afi_t afi, safi_t safi)
482
0
{
483
0
  struct bgp_pbr_interface *pbr_if;
484
0
  bool declare_node = false;
485
0
  struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
486
0
  struct bgp_pbr_interface_head *head;
487
0
  bool bgp_pbr_interface_any;
488
489
0
  if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC)
490
0
    return 0;
491
0
  if (afi == AFI_IP) {
492
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
493
0
    bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4;
494
0
  } else if (afi == AFI_IP6) {
495
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
496
0
    bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv6;
497
0
  } else {
498
0
    return 0;
499
0
  }
500
0
  if (!RB_EMPTY(bgp_pbr_interface_head, head) ||
501
0
       !bgp_pbr_interface_any)
502
0
    declare_node = true;
503
0
  RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
504
0
    vty_out(vty, "  local-install %s\n", pbr_if->name);
505
0
  }
506
0
  return declare_node ? 1 : 0;
507
0
}
508
509
static int bgp_fs_local_install_interface(struct bgp *bgp,
510
            const char *no, const char *ifname,
511
            afi_t afi)
512
0
{
513
0
  struct bgp_pbr_interface *pbr_if;
514
0
  struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
515
0
  struct bgp_pbr_interface_head *head;
516
0
  bool *bgp_pbr_interface_any;
517
518
0
  if (!bgp_pbr_cfg)
519
0
    return CMD_SUCCESS;
520
0
  if (afi == AFI_IP) {
521
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
522
0
    bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4);
523
0
  } else {
524
0
    head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
525
0
    bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv6);
526
0
  }
527
0
  if (no) {
528
0
    if (!ifname) {
529
0
      if (*bgp_pbr_interface_any) {
530
0
        *bgp_pbr_interface_any = false;
531
        /* remove all other interface list */
532
0
        bgp_pbr_reset(bgp, afi);
533
0
      }
534
0
      return CMD_SUCCESS;
535
0
    }
536
0
    pbr_if = bgp_pbr_interface_lookup(ifname, head);
537
0
    if (!pbr_if)
538
0
      return CMD_SUCCESS;
539
0
    RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
540
0
    return CMD_SUCCESS;
541
0
  }
542
0
  if (ifname) {
543
0
    pbr_if = bgp_pbr_interface_lookup(ifname, head);
544
0
    if (pbr_if)
545
0
      return CMD_SUCCESS;
546
0
    pbr_if = XCALLOC(MTYPE_TMP,
547
0
         sizeof(struct bgp_pbr_interface));
548
0
    strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
549
0
    RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
550
0
    *bgp_pbr_interface_any = false;
551
0
  } else {
552
    /* set to default */
553
0
    if (!*bgp_pbr_interface_any) {
554
      /* remove all other interface list
555
       */
556
0
      bgp_pbr_reset(bgp, afi);
557
0
      *bgp_pbr_interface_any = true;
558
0
    }
559
0
  }
560
0
  return CMD_SUCCESS;
561
0
}
562
563
DEFUN (bgp_fs_local_install_ifname,
564
  bgp_fs_local_install_ifname_cmd,
565
  "[no] local-install INTERFACE",
566
  NO_STR
567
  "Apply local policy routing\n"
568
  "Interface name\n")
569
0
{
570
0
  struct bgp *bgp = VTY_GET_CONTEXT(bgp);
571
0
  int idx = 0;
572
0
  const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
573
0
  char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ?
574
0
    argv[idx]->arg : NULL;
575
576
0
  return bgp_fs_local_install_interface(bgp, no, ifname,
577
0
                bgp_node_afi(vty));
578
0
}
579
580
extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib,
581
               struct prefix *match,
582
               int prefix_check, struct vty *vty,
583
               bool use_json,
584
               json_object *json_paths)
585
0
{
586
0
  struct bgp_dest *dest;
587
0
  const struct prefix *prefix;
588
0
  int display = 0;
589
590
0
  for (dest = bgp_table_top(rib); dest; dest = bgp_route_next(dest)) {
591
0
    prefix = bgp_dest_get_prefix(dest);
592
593
0
    if (prefix->family != AF_FLOWSPEC)
594
0
      continue;
595
596
0
    if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) {
597
0
      route_vty_out_flowspec(
598
0
        vty, prefix, bgp_dest_get_bgp_path_info(dest),
599
0
        use_json ? NLRI_STRING_FORMAT_JSON
600
0
           : NLRI_STRING_FORMAT_LARGE,
601
0
        json_paths);
602
0
      display++;
603
0
    }
604
0
  }
605
0
  return display;
606
0
}
607
608
void bgp_flowspec_vty_init(void)
609
0
{
610
0
  install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
611
0
  install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
612
0
  install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
613
0
  install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd);
614
0
  install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
615
0
  install_element(BGP_FLOWSPECV6_NODE, &bgp_fs_local_install_ifname_cmd);
616
0
}