Coverage Report

Created: 2025-07-14 06:48

/src/frr/zebra/zebra_mpls_vty.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Zebra MPLS VTY functions
3
 * Copyright (C) 2002 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
8
#include "memory.h"
9
#include "if.h"
10
#include "prefix.h"
11
#include "command.h"
12
#include "table.h"
13
#include "rib.h"
14
#include "nexthop.h"
15
#include "vrf.h"
16
#include "mpls.h"
17
#include "lib/json.h"
18
19
#include "zebra/zserv.h"
20
#include "zebra/zebra_vrf.h"
21
#include "zebra/zebra_mpls.h"
22
#include "zebra/zebra_rnh.h"
23
#include "zebra/redistribute.h"
24
#include "zebra/zebra_routemap.h"
25
26
static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd,
27
          const char *inlabel_str, const char *gate_str,
28
          const char *outlabel_str,
29
          const char *flag_str)
30
0
{
31
0
  struct zebra_vrf *zvrf;
32
0
  int ret;
33
0
  enum nexthop_types_t gtype;
34
0
  union g_addr gate;
35
0
  mpls_label_t label;
36
0
  mpls_label_t in_label, out_label;
37
38
0
  if (!mpls_enabled) {
39
0
    vty_out(vty,
40
0
      "%% MPLS not turned on in kernel, ignoring command\n");
41
0
    return CMD_WARNING_CONFIG_FAILED;
42
0
  }
43
44
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
45
0
  if (!zvrf) {
46
0
    vty_out(vty, "%% Default VRF does not exist\n");
47
0
    return CMD_WARNING_CONFIG_FAILED;
48
0
  }
49
50
0
  if (!inlabel_str) {
51
0
    vty_out(vty, "%% No Label Information\n");
52
0
    return CMD_WARNING_CONFIG_FAILED;
53
0
  }
54
55
0
  out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */
56
0
  label = atoi(inlabel_str);
57
0
  if (!IS_MPLS_UNRESERVED_LABEL(label)) {
58
0
    vty_out(vty, "%% Invalid label\n");
59
0
    return CMD_WARNING_CONFIG_FAILED;
60
0
  }
61
62
0
  if (add_cmd) {
63
0
    if (!gate_str) {
64
0
      vty_out(vty, "%% No Nexthop Information\n");
65
0
      return CMD_WARNING_CONFIG_FAILED;
66
0
    }
67
0
    if (!outlabel_str) {
68
0
      vty_out(vty, "%% No Outgoing label Information\n");
69
0
      return CMD_WARNING_CONFIG_FAILED;
70
0
    }
71
0
  }
72
73
0
  in_label = label;
74
0
  gtype = NEXTHOP_TYPE_BLACKHOLE; /* as initialization */
75
76
0
  if (gate_str) {
77
    /* Gateway is a IPv4 or IPv6 nexthop. */
78
0
    ret = inet_pton(AF_INET6, gate_str, &gate.ipv6);
79
0
    if (ret == 1)
80
0
      gtype = NEXTHOP_TYPE_IPV6;
81
0
    else {
82
0
      ret = inet_pton(AF_INET, gate_str, &gate.ipv4);
83
0
      if (ret == 1)
84
0
        gtype = NEXTHOP_TYPE_IPV4;
85
0
      else {
86
0
        vty_out(vty, "%% Invalid nexthop\n");
87
0
        return CMD_WARNING_CONFIG_FAILED;
88
0
      }
89
0
    }
90
0
  }
91
92
0
  if (outlabel_str) {
93
0
    if (outlabel_str[0] == 'i')
94
0
      out_label = MPLS_LABEL_IMPLICIT_NULL;
95
0
    else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV4)
96
0
      out_label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
97
0
    else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV6)
98
0
      out_label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
99
0
    else
100
0
      out_label = atoi(outlabel_str);
101
0
  }
102
103
0
  if (add_cmd) {
104
#if defined(HAVE_CUMULUS)
105
    /* Check that label value is consistent. */
106
    if (!zebra_mpls_lsp_label_consistent(zvrf, in_label, out_label,
107
                 gtype, &gate, 0)) {
108
      vty_out(vty, "%% Label value not consistent\n");
109
      return CMD_WARNING_CONFIG_FAILED;
110
    }
111
#endif /* HAVE_CUMULUS */
112
113
0
    ret = zebra_mpls_static_lsp_add(zvrf, in_label, out_label,
114
0
            gtype, &gate, 0);
115
0
  } else
116
0
    ret = zebra_mpls_static_lsp_del(zvrf, in_label, gtype, &gate,
117
0
            0);
118
119
0
  if (ret != 0) {
120
0
    vty_out(vty, "%% LSP cannot be %s\n",
121
0
      add_cmd ? "added" : "deleted");
122
0
    return CMD_WARNING_CONFIG_FAILED;
123
0
  }
124
125
0
  return CMD_SUCCESS;
126
0
}
127
128
DEFUN (mpls_transit_lsp,
129
       mpls_transit_lsp_cmd,
130
       "mpls lsp (16-1048575) <A.B.C.D|X:X::X:X> <(16-1048575)|explicit-null|implicit-null>",
131
       MPLS_STR
132
       "Establish label switched path\n"
133
       "Incoming MPLS label\n"
134
       "IPv4 gateway address\n"
135
       "IPv6 gateway address\n"
136
       "Outgoing MPLS label\n"
137
       "Use Explicit-Null label\n"
138
       "Use Implicit-Null label\n")
139
0
{
140
0
  return zebra_mpls_transit_lsp(vty, 1, argv[2]->arg, argv[3]->arg,
141
0
              argv[4]->arg, NULL);
142
0
}
143
144
DEFUN (no_mpls_transit_lsp,
145
       no_mpls_transit_lsp_cmd,
146
       "no mpls lsp (16-1048575) <A.B.C.D|X:X::X:X>",
147
       NO_STR
148
       MPLS_STR
149
       "Establish label switched path\n"
150
       "Incoming MPLS label\n"
151
       "IPv4 gateway address\n"
152
       "IPv6 gateway address\n")
153
0
{
154
0
  return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, argv[4]->arg, NULL,
155
0
              NULL);
156
0
}
157
158
ALIAS(no_mpls_transit_lsp, no_mpls_transit_lsp_out_label_cmd,
159
      "no mpls lsp (16-1048575) <A.B.C.D|X:X::X:X> <(16-1048575)|explicit-null|implicit-null>",
160
      NO_STR MPLS_STR
161
      "Establish label switched path\n"
162
      "Incoming MPLS label\n"
163
      "IPv4 gateway address\n"
164
      "IPv6 gateway address\n"
165
      "Outgoing MPLS label\n"
166
      "Use Explicit-Null label\n"
167
      "Use Implicit-Null label\n")
168
169
DEFUN (no_mpls_transit_lsp_all,
170
       no_mpls_transit_lsp_all_cmd,
171
       "no mpls lsp (16-1048575)",
172
       NO_STR
173
       MPLS_STR
174
       "Establish label switched path\n"
175
       "Incoming MPLS label\n")
176
0
{
177
0
  return zebra_mpls_transit_lsp(vty, 0, argv[3]->arg, NULL, NULL, NULL);
178
0
}
179
180
static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix,
181
         const char *label_str)
182
0
{
183
0
  struct zebra_vrf *zvrf;
184
0
  struct prefix p;
185
0
  uint32_t label;
186
0
  int ret;
187
188
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
189
0
  if (!zvrf) {
190
0
    vty_out(vty, "%% Default VRF does not exist\n");
191
0
    return CMD_WARNING_CONFIG_FAILED;
192
0
  }
193
194
0
  memset(&p, 0, sizeof(p));
195
0
  ret = str2prefix(prefix, &p);
196
0
  if (ret <= 0) {
197
0
    vty_out(vty, "%% Malformed address\n");
198
0
    return CMD_WARNING_CONFIG_FAILED;
199
0
  }
200
201
0
  if (add_cmd) {
202
0
    if (!label_str) {
203
0
      vty_out(vty, "%% No label binding specified\n");
204
0
      return CMD_WARNING_CONFIG_FAILED;
205
0
    }
206
207
0
    if (!strcmp(label_str, "implicit-null"))
208
0
      label = MPLS_LABEL_IMPLICIT_NULL;
209
0
    else if (!strcmp(label_str, "explicit-null")) {
210
0
      if (p.family == AF_INET)
211
0
        label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
212
0
      else
213
0
        label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
214
0
    } else {
215
0
      label = atoi(label_str);
216
0
      if (!IS_MPLS_UNRESERVED_LABEL(label)) {
217
0
        vty_out(vty, "%% Invalid label\n");
218
0
        return CMD_WARNING_CONFIG_FAILED;
219
0
      }
220
0
      if (zebra_mpls_label_already_bound(zvrf, label)) {
221
0
        vty_out(vty,
222
0
          "%% Label already bound to a FEC\n");
223
0
        return CMD_WARNING_CONFIG_FAILED;
224
0
      }
225
0
    }
226
227
0
    ret = zebra_mpls_static_fec_add(zvrf, &p, label);
228
0
  } else
229
0
    ret = zebra_mpls_static_fec_del(zvrf, &p);
230
231
0
  if (ret) {
232
0
    vty_out(vty, "%% FEC to label binding cannot be %s\n",
233
0
      add_cmd ? "added" : "deleted");
234
0
    return CMD_WARNING_CONFIG_FAILED;
235
0
  }
236
237
0
  return CMD_SUCCESS;
238
0
}
239
240
DEFUN (mpls_label_bind,
241
       mpls_label_bind_cmd,
242
       "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>",
243
       MPLS_STR
244
       "Label configuration\n"
245
       "Establish FEC to label binding\n"
246
       "IPv4 prefix\n"
247
       "IPv6 prefix\n"
248
       "MPLS Label to bind\n"
249
       "Use Implicit-Null Label\n"
250
       "Use Explicit-Null Label\n")
251
0
{
252
0
  return zebra_mpls_bind(vty, 1, argv[3]->arg, argv[4]->arg);
253
0
}
254
255
DEFUN (no_mpls_label_bind,
256
       no_mpls_label_bind_cmd,
257
       "no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]",
258
       NO_STR
259
       MPLS_STR
260
       "Label configuration\n"
261
       "Establish FEC to label binding\n"
262
       "IPv4 prefix\n"
263
       "IPv6 prefix\n"
264
       "MPLS Label to bind\n"
265
       "Use Implicit-Null Label\n")
266
0
{
267
0
  return zebra_mpls_bind(vty, 0, argv[4]->arg, NULL);
268
0
}
269
270
/* MPLS LSP configuration write function. */
271
static int zebra_mpls_config(struct vty *vty)
272
0
{
273
0
  int write = 0;
274
0
  struct zebra_vrf *zvrf;
275
276
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
277
0
  if (!zvrf)
278
0
    return 0;
279
280
0
  write += zebra_mpls_write_lsp_config(vty, zvrf);
281
0
  write += zebra_mpls_write_fec_config(vty, zvrf);
282
0
  write += zebra_mpls_write_label_block_config(vty, zvrf);
283
0
  return write;
284
0
}
285
286
DEFUN (show_mpls_fec,
287
       show_mpls_fec_cmd,
288
       "show mpls fec [<A.B.C.D/M|X:X::X:X/M>]",
289
       SHOW_STR
290
       MPLS_STR
291
       "MPLS FEC table\n"
292
       "FEC to display information about\n"
293
       "FEC to display information about\n")
294
0
{
295
0
  struct zebra_vrf *zvrf;
296
0
  struct prefix p;
297
0
  int ret;
298
299
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
300
0
  if (!zvrf)
301
0
    return 0;
302
303
0
  if (argc == 3)
304
0
    zebra_mpls_print_fec_table(vty, zvrf);
305
0
  else {
306
0
    memset(&p, 0, sizeof(struct prefix));
307
0
    ret = str2prefix(argv[3]->arg, &p);
308
0
    if (ret <= 0) {
309
0
      vty_out(vty, "%% Malformed address\n");
310
0
      return CMD_WARNING;
311
0
    }
312
0
    zebra_mpls_print_fec(vty, zvrf, &p);
313
0
  }
314
315
0
  return CMD_SUCCESS;
316
0
}
317
318
DEFUN (show_mpls_table,
319
       show_mpls_table_cmd,
320
       "show mpls table [json]",
321
       SHOW_STR
322
       MPLS_STR
323
       "MPLS table\n"
324
       JSON_STR)
325
0
{
326
0
  struct zebra_vrf *zvrf;
327
0
  bool uj = use_json(argc, argv);
328
329
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
330
0
  zebra_mpls_print_lsp_table(vty, zvrf, uj);
331
0
  return CMD_SUCCESS;
332
0
}
333
334
DEFUN (show_mpls_table_lsp,
335
       show_mpls_table_lsp_cmd,
336
       "show mpls table (16-1048575) [json]",
337
       SHOW_STR
338
       MPLS_STR
339
       "MPLS table\n"
340
       "LSP to display information about\n"
341
       JSON_STR)
342
0
{
343
0
  uint32_t label;
344
0
  struct zebra_vrf *zvrf;
345
0
  bool uj = use_json(argc, argv);
346
347
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
348
0
  label = atoi(argv[3]->arg);
349
0
  zebra_mpls_print_lsp(vty, zvrf, label, uj);
350
0
  return CMD_SUCCESS;
351
0
}
352
353
DEFUN (show_mpls_status,
354
       show_mpls_status_cmd,
355
       "show mpls status",
356
       SHOW_STR
357
       "MPLS information\n"
358
       "MPLS status\n")
359
0
{
360
0
  vty_out(vty, "MPLS support enabled: %s\n",
361
0
    (mpls_enabled) ? "yes"
362
0
             : "no (mpls kernel extensions not detected)");
363
0
  return CMD_SUCCESS;
364
0
}
365
366
static int zebra_mpls_global_block(struct vty *vty, int add_cmd,
367
           const char *start_label_str,
368
           const char *end_label_str)
369
0
{
370
0
  int ret;
371
0
  uint32_t start_label;
372
0
  uint32_t end_label;
373
0
  struct zebra_vrf *zvrf;
374
375
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
376
0
  if (!zvrf) {
377
0
    vty_out(vty, "%% Default VRF does not exist\n");
378
0
    return CMD_WARNING_CONFIG_FAILED;
379
0
  }
380
381
0
  if (add_cmd) {
382
0
    if (!start_label_str || !end_label_str) {
383
0
      vty_out(vty, "%% Labels not specified\n");
384
0
      return CMD_WARNING_CONFIG_FAILED;
385
0
    }
386
387
0
    start_label = atoi(start_label_str);
388
0
    end_label = atoi(end_label_str);
389
0
    if (!IS_MPLS_UNRESERVED_LABEL(start_label)
390
0
        || !IS_MPLS_UNRESERVED_LABEL(end_label)) {
391
0
      vty_out(vty, "%% Invalid label\n");
392
0
      return CMD_WARNING_CONFIG_FAILED;
393
0
    }
394
0
    if (end_label < start_label) {
395
0
      vty_out(vty, "%% End label is less than Start label\n");
396
0
      return CMD_WARNING_CONFIG_FAILED;
397
0
    }
398
399
0
    ret = zebra_mpls_label_block_add(zvrf, start_label, end_label);
400
0
  } else
401
0
    ret = zebra_mpls_label_block_del(zvrf);
402
403
0
  if (ret) {
404
0
    vty_out(vty, "%% Global label block could not be %s\n",
405
0
      add_cmd ? "added" : "deleted");
406
0
    return CMD_WARNING_CONFIG_FAILED;
407
0
  }
408
409
0
  return CMD_SUCCESS;
410
0
}
411
412
DEFUN (mpls_label_global_block,
413
       mpls_label_global_block_cmd,
414
       "mpls label global-block (16-1048575) (16-1048575)",
415
       MPLS_STR
416
       "Label configuration\n"
417
       "Configure global label block\n"
418
       "Start label\n"
419
       "End label\n")
420
0
{
421
0
  return zebra_mpls_global_block(vty, 1, argv[3]->arg, argv[4]->arg);
422
0
}
423
424
DEFUN (no_mpls_label_global_block,
425
       no_mpls_label_global_block_cmd,
426
       "no mpls label global-block [(16-1048575) (16-1048575)]",
427
       NO_STR
428
       MPLS_STR
429
       "Label configuration\n"
430
       "Configure global label block\n"
431
       "Start label\n"
432
       "End label\n")
433
0
{
434
0
  return zebra_mpls_global_block(vty, 0, NULL, NULL);
435
0
}
436
437
static int zebra_mpls_config(struct vty *vty);
438
/* MPLS node for MPLS LSP. */
439
static struct cmd_node mpls_node = {
440
  .name = "mpls",
441
  .node = MPLS_NODE,
442
  .prompt = "",
443
  .config_write = zebra_mpls_config,
444
};
445
446
/* MPLS VTY.  */
447
void zebra_mpls_vty_init(void)
448
0
{
449
0
  install_element(VIEW_NODE, &show_mpls_status_cmd);
450
451
0
  install_node(&mpls_node);
452
453
0
  install_element(CONFIG_NODE, &mpls_transit_lsp_cmd);
454
0
  install_element(CONFIG_NODE, &no_mpls_transit_lsp_cmd);
455
0
  install_element(CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
456
0
  install_element(CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
457
458
0
  install_element(CONFIG_NODE, &mpls_label_bind_cmd);
459
0
  install_element(CONFIG_NODE, &no_mpls_label_bind_cmd);
460
461
0
  install_element(CONFIG_NODE, &mpls_label_global_block_cmd);
462
0
  install_element(CONFIG_NODE, &no_mpls_label_global_block_cmd);
463
464
0
  install_element(VIEW_NODE, &show_mpls_table_cmd);
465
0
  install_element(VIEW_NODE, &show_mpls_table_lsp_cmd);
466
0
  install_element(VIEW_NODE, &show_mpls_fec_cmd);
467
0
}