Coverage Report

Created: 2025-08-28 06:29

/src/frr/lib/routemap_northbound.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Route map northbound implementation.
4
 *
5
 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
6
 *                    Rafael Zalamena
7
 */
8
9
#include <zebra.h>
10
11
#include "lib/command.h"
12
#include "lib/log.h"
13
#include "lib/northbound.h"
14
#include "lib/routemap.h"
15
16
/*
17
 * Auxiliary functions to avoid code duplication:
18
 *
19
 * lib_route_map_entry_set_destroy: unset `set` commands.
20
 * lib_route_map_entry_match_destroy: unset `match` commands.
21
 */
22
int lib_route_map_entry_match_destroy(struct nb_cb_destroy_args *args)
23
0
{
24
0
  struct routemap_hook_context *rhc;
25
0
  int rv;
26
27
0
  if (args->event != NB_EV_APPLY)
28
0
    return NB_OK;
29
30
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
31
0
  if (rhc->rhc_mhook == NULL)
32
0
    return NB_OK;
33
34
0
  rv = rhc->rhc_mhook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
35
0
          rhc->rhc_event,
36
0
          args->errmsg, args->errmsg_len);
37
0
  if (rv != CMD_SUCCESS)
38
0
    return NB_ERR_INCONSISTENCY;
39
40
0
  return NB_OK;
41
0
}
42
43
int lib_route_map_entry_set_destroy(struct nb_cb_destroy_args *args)
44
0
{
45
0
  struct routemap_hook_context *rhc;
46
0
  int rv;
47
48
0
  if (args->event != NB_EV_APPLY)
49
0
    return NB_OK;
50
51
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
52
0
  if (rhc->rhc_shook == NULL)
53
0
    return NB_OK;
54
55
0
  rv = rhc->rhc_shook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
56
0
          args->errmsg, args->errmsg_len);
57
0
  if (rv != CMD_SUCCESS)
58
0
    return NB_ERR_INCONSISTENCY;
59
60
0
  return NB_OK;
61
0
}
62
63
/*
64
 * Auxiliary hook context list manipulation functions.
65
 */
66
struct routemap_hook_context *
67
routemap_hook_context_insert(struct route_map_index *rmi)
68
0
{
69
0
  struct routemap_hook_context *rhc;
70
71
0
  rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc));
72
0
  rhc->rhc_rmi = rmi;
73
0
  TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry);
74
75
0
  return rhc;
76
0
}
77
78
void routemap_hook_context_free(struct routemap_hook_context *rhc)
79
0
{
80
0
  struct route_map_index *rmi = rhc->rhc_rmi;
81
82
0
  TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry);
83
0
  XFREE(MTYPE_TMP, rhc);
84
0
}
85
86
/*
87
 * XPath: /frr-route-map:lib/route-map
88
 */
89
static int lib_route_map_create(struct nb_cb_create_args *args)
90
0
{
91
0
  struct route_map *rm;
92
0
  const char *rm_name;
93
94
0
  switch (args->event) {
95
0
  case NB_EV_VALIDATE:
96
0
  case NB_EV_PREPARE:
97
0
  case NB_EV_ABORT:
98
    /* NOTHING */
99
0
    break;
100
0
  case NB_EV_APPLY:
101
0
    rm_name = yang_dnode_get_string(args->dnode, "./name");
102
0
    rm = route_map_get(rm_name);
103
0
    nb_running_set_entry(args->dnode, rm);
104
0
    break;
105
0
  }
106
107
0
  return NB_OK;
108
0
}
109
110
static int lib_route_map_destroy(struct nb_cb_destroy_args *args)
111
0
{
112
0
  struct route_map *rm;
113
114
0
  switch (args->event) {
115
0
  case NB_EV_VALIDATE:
116
0
  case NB_EV_PREPARE:
117
0
  case NB_EV_ABORT:
118
    /* NOTHING */
119
0
    break;
120
0
  case NB_EV_APPLY:
121
0
    rm = nb_running_unset_entry(args->dnode);
122
0
    route_map_delete(rm);
123
0
    break;
124
0
  }
125
126
0
  return NB_OK;
127
0
}
128
129
/*
130
 * XPath: /frr-route-map:lib/route-map/optimization-disabled
131
 */
132
static int
133
lib_route_map_optimization_disabled_modify(struct nb_cb_modify_args *args)
134
0
{
135
0
  struct route_map *rm;
136
0
  bool disabled = yang_dnode_get_bool(args->dnode, NULL);
137
138
0
  switch (args->event) {
139
0
  case NB_EV_VALIDATE:
140
0
  case NB_EV_PREPARE:
141
0
  case NB_EV_ABORT:
142
    /* NOTHING */
143
0
    break;
144
0
  case NB_EV_APPLY:
145
0
    rm = nb_running_get_entry(args->dnode, NULL, true);
146
0
    rm->optimization_disabled = disabled;
147
0
    break;
148
0
  }
149
150
0
  return NB_OK;
151
0
}
152
153
/*
154
 * XPath: /frr-route-map:lib/route-map/entry
155
 */
156
static int lib_route_map_entry_create(struct nb_cb_create_args *args)
157
0
{
158
0
  struct route_map_index *rmi;
159
0
  struct route_map *rm;
160
0
  uint16_t sequence;
161
0
  int action;
162
163
0
  switch (args->event) {
164
0
  case NB_EV_VALIDATE:
165
0
  case NB_EV_PREPARE:
166
0
  case NB_EV_ABORT:
167
    /* NOTHING */
168
0
    break;
169
0
  case NB_EV_APPLY:
170
0
    sequence = yang_dnode_get_uint16(args->dnode, "./sequence");
171
0
    action = yang_dnode_get_enum(args->dnode, "./action") == 0
172
0
         ? RMAP_PERMIT
173
0
         : RMAP_DENY;
174
0
    rm = nb_running_get_entry(args->dnode, NULL, true);
175
0
    rmi = route_map_index_get(rm, action, sequence);
176
0
    nb_running_set_entry(args->dnode, rmi);
177
0
    break;
178
0
  }
179
180
0
  return NB_OK;
181
0
}
182
183
static int lib_route_map_entry_destroy(struct nb_cb_destroy_args *args)
184
0
{
185
0
  struct route_map_index *rmi;
186
187
0
  switch (args->event) {
188
0
  case NB_EV_VALIDATE:
189
0
  case NB_EV_PREPARE:
190
0
  case NB_EV_ABORT:
191
    /* NOTHING */
192
0
    break;
193
0
  case NB_EV_APPLY:
194
0
    rmi = nb_running_unset_entry(args->dnode);
195
0
    route_map_index_delete(rmi, 1);
196
0
    break;
197
0
  }
198
199
0
  return NB_OK;
200
0
}
201
202
/*
203
 * XPath: /frr-route-map:lib/route-map/entry/description
204
 */
205
static int
206
lib_route_map_entry_description_modify(struct nb_cb_modify_args *args)
207
0
{
208
0
  struct route_map_index *rmi;
209
0
  const char *description;
210
211
0
  switch (args->event) {
212
0
  case NB_EV_VALIDATE:
213
    /* NOTHING */
214
0
    break;
215
0
  case NB_EV_PREPARE:
216
0
    description = yang_dnode_get_string(args->dnode, NULL);
217
0
    args->resource->ptr = XSTRDUP(MTYPE_TMP, description);
218
0
    if (args->resource->ptr == NULL)
219
0
      return NB_ERR_RESOURCE;
220
0
    break;
221
0
  case NB_EV_ABORT:
222
0
    XFREE(MTYPE_TMP, args->resource->ptr);
223
0
    break;
224
0
  case NB_EV_APPLY:
225
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
226
0
    XFREE(MTYPE_TMP, rmi->description);
227
0
    rmi->description = args->resource->ptr;
228
0
    break;
229
0
  }
230
231
0
  return NB_OK;
232
0
}
233
234
static int
235
lib_route_map_entry_description_destroy(struct nb_cb_destroy_args *args)
236
0
{
237
0
  struct route_map_index *rmi;
238
239
0
  switch (args->event) {
240
0
  case NB_EV_VALIDATE:
241
0
  case NB_EV_PREPARE:
242
0
  case NB_EV_ABORT:
243
    /* NOTHING */
244
0
    break;
245
0
  case NB_EV_APPLY:
246
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
247
0
    XFREE(MTYPE_TMP, rmi->description);
248
0
    break;
249
0
  }
250
251
0
  return NB_OK;
252
0
}
253
254
/*
255
 * XPath: /frr-route-map:lib/route-map/entry/action
256
 */
257
static int lib_route_map_entry_action_modify(struct nb_cb_modify_args *args)
258
0
{
259
0
  struct route_map_index *rmi;
260
0
  struct route_map *map;
261
262
0
  switch (args->event) {
263
0
  case NB_EV_VALIDATE:
264
0
  case NB_EV_PREPARE:
265
0
  case NB_EV_ABORT:
266
    /* NOTHING */
267
0
    break;
268
0
  case NB_EV_APPLY:
269
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
270
0
    rmi->type = yang_dnode_get_enum(args->dnode, NULL);
271
0
    map = rmi->map;
272
273
    /* Execute event hook. */
274
0
    if (route_map_master.event_hook) {
275
0
      (*route_map_master.event_hook)(map->name);
276
0
      route_map_notify_dependencies(map->name,
277
0
                  RMAP_EVENT_CALL_ADDED);
278
0
    }
279
280
0
    break;
281
0
  }
282
283
0
  return NB_OK;
284
0
}
285
286
/*
287
 * XPath: /frr-route-map:lib/route-map/entry/call
288
 */
289
static int lib_route_map_entry_call_modify(struct nb_cb_modify_args *args)
290
0
{
291
0
  struct route_map_index *rmi;
292
0
  const char *rm_name, *rmn_name;
293
294
0
  switch (args->event) {
295
0
  case NB_EV_VALIDATE:
296
0
    rm_name = yang_dnode_get_string(args->dnode, "../../name");
297
0
    rmn_name = yang_dnode_get_string(args->dnode, NULL);
298
    /* Don't allow to jump to the same route map instance. */
299
0
    if (strcmp(rm_name, rmn_name) == 0)
300
0
      return NB_ERR_VALIDATION;
301
302
    /* TODO: detect circular route map sequences. */
303
0
    break;
304
0
  case NB_EV_PREPARE:
305
0
    rmn_name = yang_dnode_get_string(args->dnode, NULL);
306
0
    args->resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name);
307
0
    break;
308
0
  case NB_EV_ABORT:
309
0
    XFREE(MTYPE_ROUTE_MAP_NAME, args->resource->ptr);
310
0
    break;
311
0
  case NB_EV_APPLY:
312
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
313
0
    if (rmi->nextrm) {
314
0
      route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
315
0
              rmi->nextrm, rmi->map->name);
316
0
      XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
317
0
    }
318
0
    rmi->nextrm = args->resource->ptr;
319
0
    route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm,
320
0
            rmi->map->name);
321
0
    break;
322
0
  }
323
324
0
  return NB_OK;
325
0
}
326
327
static int lib_route_map_entry_call_destroy(struct nb_cb_destroy_args *args)
328
0
{
329
0
  struct route_map_index *rmi;
330
331
0
  switch (args->event) {
332
0
  case NB_EV_VALIDATE:
333
0
  case NB_EV_PREPARE:
334
0
  case NB_EV_ABORT:
335
    /* NOTHING */
336
0
    break;
337
0
  case NB_EV_APPLY:
338
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
339
0
    route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm,
340
0
            rmi->map->name);
341
0
    XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
342
0
    rmi->nextrm = NULL;
343
0
    break;
344
0
  }
345
346
0
  return NB_OK;
347
0
}
348
349
/*
350
 * XPath: /frr-route-map:lib/route-map/entry/exit-policy
351
 */
352
static int
353
lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args)
354
0
{
355
0
  struct route_map_index *rmi;
356
0
  struct route_map *map;
357
0
  int rm_action;
358
0
  int policy;
359
360
0
  switch (args->event) {
361
0
  case NB_EV_VALIDATE:
362
0
    policy = yang_dnode_get_enum(args->dnode, NULL);
363
0
    switch (policy) {
364
0
    case 0: /* permit-or-deny */
365
0
      break;
366
0
    case 1: /* next */
367
      /* FALLTHROUGH */
368
0
    case 2: /* goto */
369
0
      rm_action =
370
0
        yang_dnode_get_enum(args->dnode, "../action");
371
0
      if (rm_action == 1 /* deny */) {
372
        /*
373
         * On deny it is not possible to 'goto'
374
         * anywhere.
375
         */
376
0
        return NB_ERR_VALIDATION;
377
0
      }
378
0
      break;
379
0
    }
380
0
    break;
381
0
  case NB_EV_PREPARE:
382
0
  case NB_EV_ABORT:
383
0
    break;
384
0
  case NB_EV_APPLY:
385
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
386
0
    map = rmi->map;
387
0
    policy = yang_dnode_get_enum(args->dnode, NULL);
388
389
0
    switch (policy) {
390
0
    case 0: /* permit-or-deny */
391
0
      rmi->exitpolicy = RMAP_EXIT;
392
0
      break;
393
0
    case 1: /* next */
394
0
      rmi->exitpolicy = RMAP_NEXT;
395
0
      break;
396
0
    case 2: /* goto */
397
0
      rmi->exitpolicy = RMAP_GOTO;
398
0
      break;
399
0
    }
400
401
    /* Execute event hook. */
402
0
    if (route_map_master.event_hook) {
403
0
      (*route_map_master.event_hook)(map->name);
404
0
      route_map_notify_dependencies(map->name,
405
0
                  RMAP_EVENT_CALL_ADDED);
406
0
    }
407
408
0
    break;
409
0
  }
410
411
0
  return NB_OK;
412
0
}
413
414
/*
415
 * XPath: /frr-route-map:lib/route-map/entry/goto-value
416
 */
417
static int lib_route_map_entry_goto_value_modify(struct nb_cb_modify_args *args)
418
0
{
419
0
  struct route_map_index *rmi;
420
0
  uint16_t rmi_index;
421
0
  uint16_t rmi_next;
422
423
0
  switch (args->event) {
424
0
  case NB_EV_VALIDATE:
425
0
    rmi_index = yang_dnode_get_uint16(args->dnode, "../sequence");
426
0
    rmi_next = yang_dnode_get_uint16(args->dnode, NULL);
427
0
    if (rmi_next <= rmi_index) {
428
      /* Can't jump backwards on a route map. */
429
0
      return NB_ERR_VALIDATION;
430
0
    }
431
0
    break;
432
0
  case NB_EV_PREPARE:
433
0
  case NB_EV_ABORT:
434
    /* NOTHING */
435
0
    break;
436
0
  case NB_EV_APPLY:
437
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
438
0
    rmi->nextpref = yang_dnode_get_uint16(args->dnode, NULL);
439
0
    break;
440
0
  }
441
442
0
  return NB_OK;
443
0
}
444
445
static int
446
lib_route_map_entry_goto_value_destroy(struct nb_cb_destroy_args *args)
447
0
{
448
0
  struct route_map_index *rmi;
449
450
0
  switch (args->event) {
451
0
  case NB_EV_VALIDATE:
452
0
  case NB_EV_PREPARE:
453
0
  case NB_EV_ABORT:
454
    /* NOTHING */
455
0
    break;
456
0
  case NB_EV_APPLY:
457
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
458
0
    rmi->nextpref = 0;
459
0
    break;
460
0
  }
461
462
0
  return NB_OK;
463
0
}
464
465
/*
466
 * XPath: /frr-route-map:lib/route-map/entry/match-condition
467
 */
468
static int
469
lib_route_map_entry_match_condition_create(struct nb_cb_create_args *args)
470
0
{
471
0
  struct routemap_hook_context *rhc;
472
0
  struct route_map_index *rmi;
473
474
0
  switch (args->event) {
475
0
  case NB_EV_VALIDATE:
476
0
  case NB_EV_PREPARE:
477
0
  case NB_EV_ABORT:
478
    /* NOTHING */
479
0
    break;
480
0
  case NB_EV_APPLY:
481
0
    rmi = nb_running_get_entry(args->dnode, NULL, true);
482
0
    rhc = routemap_hook_context_insert(rmi);
483
0
    nb_running_set_entry(args->dnode, rhc);
484
0
    break;
485
0
  }
486
487
0
  return NB_OK;
488
0
}
489
490
static int
491
lib_route_map_entry_match_condition_destroy(struct nb_cb_destroy_args *args)
492
0
{
493
0
  struct routemap_hook_context *rhc;
494
0
  int rv;
495
496
0
  if (args->event != NB_EV_APPLY)
497
0
    return NB_OK;
498
499
0
  rv = lib_route_map_entry_match_destroy(args);
500
0
  rhc = nb_running_unset_entry(args->dnode);
501
0
  routemap_hook_context_free(rhc);
502
503
0
  return rv;
504
0
}
505
506
/*
507
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface
508
 */
509
static int lib_route_map_entry_match_condition_interface_modify(
510
  struct nb_cb_modify_args *args)
511
0
{
512
0
  struct routemap_hook_context *rhc;
513
0
  const char *ifname;
514
0
  int rv;
515
516
0
  if (args->event != NB_EV_APPLY)
517
0
    return NB_OK;
518
519
  /* Check for hook function. */
520
0
  if (rmap_match_set_hook.match_interface == NULL)
521
0
    return NB_OK;
522
523
  /* Add configuration. */
524
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
525
0
  ifname = yang_dnode_get_string(args->dnode, NULL);
526
527
  /* Set destroy information. */
528
0
  rhc->rhc_mhook = rmap_match_set_hook.no_match_interface;
529
0
  rhc->rhc_rule = "interface";
530
0
  rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
531
532
0
  rv = rmap_match_set_hook.match_interface(rhc->rhc_rmi,
533
0
             "interface", ifname,
534
0
             RMAP_EVENT_MATCH_ADDED,
535
0
             args->errmsg, args->errmsg_len);
536
0
  if (rv != CMD_SUCCESS) {
537
0
    rhc->rhc_mhook = NULL;
538
0
    return NB_ERR_INCONSISTENCY;
539
0
  }
540
541
0
  return NB_OK;
542
0
}
543
544
static int lib_route_map_entry_match_condition_interface_destroy(
545
  struct nb_cb_destroy_args *args)
546
0
{
547
0
  return lib_route_map_entry_match_destroy(args);
548
0
}
549
550
/*
551
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
552
 */
553
static int lib_route_map_entry_match_condition_list_name_modify(
554
  struct nb_cb_modify_args *args)
555
0
{
556
0
  struct routemap_hook_context *rhc;
557
0
  const char *acl;
558
0
  const char *condition;
559
0
  int rv;
560
561
0
  if (args->event != NB_EV_APPLY)
562
0
    return NB_OK;
563
564
  /* Check for hook installation, otherwise we can just stop. */
565
0
  acl = yang_dnode_get_string(args->dnode, NULL);
566
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
567
0
  condition = yang_dnode_get_string(args->dnode, "../../condition");
568
569
0
  if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) {
570
0
    if (rmap_match_set_hook.match_ip_address == NULL)
571
0
      return NB_OK;
572
0
    rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
573
0
    rhc->rhc_rule = "ip address";
574
0
    rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
575
0
    rv = rmap_match_set_hook.match_ip_address(
576
0
      rhc->rhc_rmi, "ip address", acl,
577
0
      RMAP_EVENT_FILTER_ADDED,
578
0
      args->errmsg, args->errmsg_len);
579
0
  } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
580
0
    if (rmap_match_set_hook.match_ip_address_prefix_list == NULL)
581
0
      return NB_OK;
582
0
    rhc->rhc_mhook =
583
0
      rmap_match_set_hook.no_match_ip_address_prefix_list;
584
0
    rhc->rhc_rule = "ip address prefix-list";
585
0
    rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
586
0
    rv = rmap_match_set_hook.match_ip_address_prefix_list(
587
0
      rhc->rhc_rmi, "ip address prefix-list", acl,
588
0
      RMAP_EVENT_PLIST_ADDED,
589
0
      args->errmsg, args->errmsg_len);
590
0
  } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
591
0
    if (rmap_match_set_hook.match_ip_next_hop == NULL)
592
0
      return NB_OK;
593
0
    rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
594
0
    rhc->rhc_rule = "ip next-hop";
595
0
    rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
596
0
    rv = rmap_match_set_hook.match_ip_next_hop(
597
0
      rhc->rhc_rmi, "ip next-hop", acl,
598
0
      RMAP_EVENT_FILTER_ADDED,
599
0
      args->errmsg, args->errmsg_len);
600
0
  } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) {
601
0
    if (rmap_match_set_hook.match_ipv6_next_hop == NULL)
602
0
      return NB_OK;
603
0
    rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop;
604
0
    rhc->rhc_rule = "ipv6 next-hop";
605
0
    rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
606
0
    rv = rmap_match_set_hook.match_ipv6_next_hop(
607
0
      rhc->rhc_rmi, "ipv6 next-hop", acl,
608
0
      RMAP_EVENT_FILTER_ADDED, args->errmsg,
609
0
      args->errmsg_len);
610
0
  } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
611
0
    if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
612
0
      return NB_OK;
613
0
    rhc->rhc_mhook =
614
0
      rmap_match_set_hook.no_match_ip_next_hop_prefix_list;
615
0
    rhc->rhc_rule = "ip next-hop prefix-list";
616
0
    rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
617
0
    rv = rmap_match_set_hook.match_ip_next_hop_prefix_list(
618
0
      rhc->rhc_rmi, "ip next-hop prefix-list", acl,
619
0
      RMAP_EVENT_PLIST_ADDED,
620
0
      args->errmsg, args->errmsg_len);
621
0
  } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) {
622
0
    if (rmap_match_set_hook.match_ipv6_next_hop_prefix_list == NULL)
623
0
      return NB_OK;
624
0
    rhc->rhc_mhook =
625
0
      rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list;
626
0
    rhc->rhc_rule = "ipv6 next-hop prefix-list";
627
0
    rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
628
0
    rv = rmap_match_set_hook.match_ipv6_next_hop_prefix_list(
629
0
      rhc->rhc_rmi, "ipv6 next-hop prefix-list", acl,
630
0
      RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len);
631
0
  } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
632
0
    if (rmap_match_set_hook.match_ipv6_address == NULL)
633
0
      return NB_OK;
634
0
    rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address;
635
0
    rhc->rhc_rule = "ipv6 address";
636
0
    rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
637
0
    rv = rmap_match_set_hook.match_ipv6_address(
638
0
      rhc->rhc_rmi, "ipv6 address", acl,
639
0
      RMAP_EVENT_FILTER_ADDED,
640
0
      args->errmsg, args->errmsg_len);
641
0
  } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) {
642
0
    if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL)
643
0
      return NB_OK;
644
0
    rhc->rhc_mhook =
645
0
      rmap_match_set_hook.no_match_ipv6_address_prefix_list;
646
0
    rhc->rhc_rule = "ipv6 address prefix-list";
647
0
    rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
648
0
    rv = rmap_match_set_hook.match_ipv6_address_prefix_list(
649
0
      rhc->rhc_rmi, "ipv6 address prefix-list", acl,
650
0
      RMAP_EVENT_PLIST_ADDED,
651
0
      args->errmsg, args->errmsg_len);
652
0
  } else
653
0
    rv = CMD_ERR_NO_MATCH;
654
655
0
  if (rv != CMD_SUCCESS) {
656
0
    rhc->rhc_mhook = NULL;
657
0
    return NB_ERR_INCONSISTENCY;
658
0
  }
659
660
0
  return NB_OK;
661
0
}
662
663
static int lib_route_map_entry_match_condition_list_name_destroy(
664
  struct nb_cb_destroy_args *args)
665
0
{
666
0
  return lib_route_map_entry_match_destroy(args);
667
0
}
668
669
/*
670
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type
671
 */
672
static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
673
  struct nb_cb_modify_args *args)
674
0
{
675
0
  struct routemap_hook_context *rhc;
676
0
  const char *type;
677
0
  int rv;
678
679
0
  if (args->event != NB_EV_APPLY)
680
0
    return NB_OK;
681
682
  /* Check for hook function. */
683
0
  if (rmap_match_set_hook.match_ip_next_hop_type == NULL)
684
0
    return NB_OK;
685
686
  /* Add configuration. */
687
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
688
0
  type = yang_dnode_get_string(args->dnode, NULL);
689
690
  /* Set destroy information. */
691
0
  rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type;
692
0
  rhc->rhc_rule = "ip next-hop type";
693
0
  rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
694
695
0
  rv = rmap_match_set_hook.match_ip_next_hop_type(
696
0
    rhc->rhc_rmi, "ip next-hop type", type,
697
0
    RMAP_EVENT_MATCH_ADDED,
698
0
    args->errmsg, args->errmsg_len);
699
0
  if (rv != CMD_SUCCESS) {
700
0
    rhc->rhc_mhook = NULL;
701
0
    return NB_ERR_INCONSISTENCY;
702
0
  }
703
704
0
  return NB_OK;
705
0
}
706
707
static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy(
708
  struct nb_cb_destroy_args *args)
709
0
{
710
0
  return lib_route_map_entry_match_destroy(args);
711
0
}
712
713
/*
714
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type
715
 */
716
static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
717
  struct nb_cb_modify_args *args)
718
0
{
719
0
  struct routemap_hook_context *rhc;
720
0
  const char *type;
721
0
  int rv;
722
723
0
  if (args->event != NB_EV_APPLY)
724
0
    return NB_OK;
725
726
  /* Check for hook function. */
727
0
  if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL)
728
0
    return NB_OK;
729
730
  /* Add configuration. */
731
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
732
0
  type = yang_dnode_get_string(args->dnode, NULL);
733
734
  /* Set destroy information. */
735
0
  rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type;
736
0
  rhc->rhc_rule = "ipv6 next-hop type";
737
0
  rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
738
739
0
  rv = rmap_match_set_hook.match_ipv6_next_hop_type(
740
0
    rhc->rhc_rmi, "ipv6 next-hop type", type,
741
0
    RMAP_EVENT_MATCH_ADDED,
742
0
    args->errmsg, args->errmsg_len);
743
0
  if (rv != CMD_SUCCESS) {
744
0
    rhc->rhc_mhook = NULL;
745
0
    return NB_ERR_INCONSISTENCY;
746
0
  }
747
748
0
  return NB_OK;
749
0
}
750
751
static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy(
752
  struct nb_cb_destroy_args *args)
753
0
{
754
0
  return lib_route_map_entry_match_destroy(args);
755
0
}
756
757
/*
758
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric
759
 */
760
static int lib_route_map_entry_match_condition_metric_modify(
761
  struct nb_cb_modify_args *args)
762
0
{
763
0
  struct routemap_hook_context *rhc;
764
0
  const char *type;
765
0
  int rv;
766
767
0
  if (args->event != NB_EV_APPLY)
768
0
    return NB_OK;
769
770
  /* Check for hook function. */
771
0
  if (rmap_match_set_hook.match_metric == NULL)
772
0
    return NB_OK;
773
774
  /* Add configuration. */
775
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
776
0
  type = yang_dnode_get_string(args->dnode, NULL);
777
778
  /* Set destroy information. */
779
0
  rhc->rhc_mhook = rmap_match_set_hook.no_match_metric;
780
0
  rhc->rhc_rule = "metric";
781
0
  rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
782
783
0
  rv = rmap_match_set_hook.match_metric(rhc->rhc_rmi, "metric",
784
0
                type, RMAP_EVENT_MATCH_ADDED,
785
0
                args->errmsg, args->errmsg_len);
786
0
  if (rv != CMD_SUCCESS) {
787
0
    rhc->rhc_mhook = NULL;
788
0
    return NB_ERR_INCONSISTENCY;
789
0
  }
790
791
0
  return NB_OK;
792
0
}
793
794
static int lib_route_map_entry_match_condition_metric_destroy(
795
  struct nb_cb_destroy_args *args)
796
0
{
797
0
  return lib_route_map_entry_match_destroy(args);
798
0
}
799
800
/*
801
 * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag
802
 */
803
static int
804
lib_route_map_entry_match_condition_tag_modify(struct nb_cb_modify_args *args)
805
0
{
806
0
  struct routemap_hook_context *rhc;
807
0
  const char *tag;
808
0
  int rv;
809
810
0
  if (args->event != NB_EV_APPLY)
811
0
    return NB_OK;
812
813
  /* Check for hook function. */
814
0
  if (rmap_match_set_hook.match_tag == NULL)
815
0
    return NB_OK;
816
817
  /* Add configuration. */
818
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
819
0
  tag = yang_dnode_get_string(args->dnode, NULL);
820
821
  /* Set destroy information. */
822
0
  rhc->rhc_mhook = rmap_match_set_hook.no_match_tag;
823
0
  rhc->rhc_rule = "tag";
824
0
  rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
825
826
0
  rv = rmap_match_set_hook.match_tag(rhc->rhc_rmi, "tag", tag,
827
0
             RMAP_EVENT_MATCH_ADDED,
828
0
             args->errmsg, args->errmsg_len);
829
0
  if (rv != CMD_SUCCESS) {
830
0
    rhc->rhc_mhook = NULL;
831
0
    return NB_ERR_INCONSISTENCY;
832
0
  }
833
834
0
  return NB_OK;
835
0
}
836
837
static int
838
lib_route_map_entry_match_condition_tag_destroy(struct nb_cb_destroy_args *args)
839
0
{
840
0
  return lib_route_map_entry_match_destroy(args);
841
0
}
842
843
/*
844
 * XPath: /frr-route-map:lib/route-map/entry/set-action
845
 */
846
static int lib_route_map_entry_set_action_create(struct nb_cb_create_args *args)
847
0
{
848
0
  return lib_route_map_entry_match_condition_create(args);
849
0
}
850
851
static int
852
lib_route_map_entry_set_action_destroy(struct nb_cb_destroy_args *args)
853
0
{
854
0
  struct routemap_hook_context *rhc;
855
0
  int rv;
856
857
0
  if (args->event != NB_EV_APPLY)
858
0
    return NB_OK;
859
860
0
  rv = lib_route_map_entry_set_destroy(args);
861
0
  rhc = nb_running_unset_entry(args->dnode);
862
0
  routemap_hook_context_free(rhc);
863
864
0
  return rv;
865
0
}
866
867
/*
868
 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address
869
 */
870
static int lib_route_map_entry_set_action_ipv4_address_modify(
871
  struct nb_cb_modify_args *args)
872
0
{
873
0
  struct routemap_hook_context *rhc;
874
0
  const char *address;
875
0
  struct in_addr ia;
876
0
  int rv;
877
878
0
  switch (args->event) {
879
0
  case NB_EV_VALIDATE:
880
    /*
881
     * NOTE: validate if 'action' is 'ipv4-next-hop',
882
     * currently it is not necessary because this is the
883
     * only implemented action.
884
     */
885
0
    yang_dnode_get_ipv4(&ia, args->dnode, NULL);
886
0
    if (ia.s_addr == INADDR_ANY || !ipv4_unicast_valid(&ia))
887
0
      return NB_ERR_VALIDATION;
888
    /* FALLTHROUGH */
889
0
  case NB_EV_PREPARE:
890
0
  case NB_EV_ABORT:
891
0
    return NB_OK;
892
0
  case NB_EV_APPLY:
893
0
    break;
894
0
  }
895
896
  /* Check for hook function. */
897
0
  if (rmap_match_set_hook.set_ip_nexthop == NULL)
898
0
    return NB_OK;
899
900
  /* Add configuration. */
901
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
902
0
  address = yang_dnode_get_string(args->dnode, NULL);
903
904
  /* Set destroy information. */
905
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop;
906
0
  rhc->rhc_rule = "ip next-hop";
907
908
0
  rv = rmap_match_set_hook.set_ip_nexthop(rhc->rhc_rmi, "ip next-hop",
909
0
            address,
910
0
            args->errmsg, args->errmsg_len);
911
0
  if (rv != CMD_SUCCESS) {
912
0
    rhc->rhc_shook = NULL;
913
0
    return NB_ERR_INCONSISTENCY;
914
0
  }
915
916
0
  return NB_OK;
917
0
}
918
919
static int lib_route_map_entry_set_action_ipv4_address_destroy(
920
  struct nb_cb_destroy_args *args)
921
0
{
922
0
  return lib_route_map_entry_set_destroy(args);
923
0
}
924
925
/*
926
 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address
927
 */
928
static int lib_route_map_entry_set_action_ipv6_address_modify(
929
  struct nb_cb_modify_args *args)
930
0
{
931
0
  struct routemap_hook_context *rhc;
932
0
  const char *address;
933
0
  struct in6_addr i6a;
934
0
  int rv;
935
936
0
  switch (args->event) {
937
0
  case NB_EV_VALIDATE:
938
    /*
939
     * NOTE: validate if 'action' is 'ipv6-next-hop',
940
     * currently it is not necessary because this is the
941
     * only implemented action. Other actions might have
942
     * different validations.
943
     */
944
0
    yang_dnode_get_ipv6(&i6a, args->dnode, NULL);
945
0
    if (!IN6_IS_ADDR_LINKLOCAL(&i6a))
946
0
      return NB_ERR_VALIDATION;
947
    /* FALLTHROUGH */
948
0
  case NB_EV_PREPARE:
949
0
  case NB_EV_ABORT:
950
0
    return NB_OK;
951
0
  case NB_EV_APPLY:
952
0
    break;
953
0
  }
954
955
  /* Check for hook function. */
956
0
  if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL)
957
0
    return NB_OK;
958
959
  /* Add configuration. */
960
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
961
0
  address = yang_dnode_get_string(args->dnode, NULL);
962
963
  /* Set destroy information. */
964
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local;
965
0
  rhc->rhc_rule = "ipv6 next-hop local";
966
967
0
  rv = rmap_match_set_hook.set_ipv6_nexthop_local(
968
0
    rhc->rhc_rmi, "ipv6 next-hop local", address,
969
0
    args->errmsg, args->errmsg_len);
970
0
  if (rv != CMD_SUCCESS) {
971
0
    rhc->rhc_shook = NULL;
972
0
    return NB_ERR_INCONSISTENCY;
973
0
  }
974
975
0
  return NB_OK;
976
0
}
977
978
static int lib_route_map_entry_set_action_ipv6_address_destroy(
979
  struct nb_cb_destroy_args *args)
980
0
{
981
0
  return lib_route_map_entry_set_destroy(args);
982
0
}
983
984
/*
985
 * XPath: /frr-route-map:lib/route-map/entry/set-action/value
986
 */
987
static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
988
           union nb_resource *resource, const char *value,
989
           char *errmsg, size_t errmsg_len)
990
0
{
991
0
  struct routemap_hook_context *rhc;
992
0
  int rv;
993
994
  /*
995
   * NOTE: validate if 'action' is 'metric', currently it is not
996
   * necessary because this is the only implemented action. Other
997
   * actions might have different validations.
998
   */
999
0
  if (event != NB_EV_APPLY)
1000
0
    return NB_OK;
1001
1002
  /* Check for hook function. */
1003
0
  if (rmap_match_set_hook.set_metric == NULL)
1004
0
    return NB_OK;
1005
1006
  /* Add configuration. */
1007
0
  rhc = nb_running_get_entry(dnode, NULL, true);
1008
1009
  /* Set destroy information. */
1010
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_metric;
1011
0
  rhc->rhc_rule = "metric";
1012
1013
0
  rv = rmap_match_set_hook.set_metric(rhc->rhc_rmi, "metric",
1014
0
              value,
1015
0
              errmsg, errmsg_len
1016
0
              );
1017
0
  if (rv != CMD_SUCCESS) {
1018
0
    rhc->rhc_shook = NULL;
1019
0
    return NB_ERR_INCONSISTENCY;
1020
0
  }
1021
1022
0
  return NB_OK;
1023
0
}
1024
1025
static int
1026
lib_route_map_entry_set_action_value_modify(struct nb_cb_modify_args *args)
1027
0
{
1028
0
  const char *metric = yang_dnode_get_string(args->dnode, NULL);
1029
1030
0
  return set_action_modify(args->event, args->dnode, args->resource,
1031
0
         metric, args->errmsg, args->errmsg_len);
1032
0
}
1033
1034
static int
1035
lib_route_map_entry_set_action_value_destroy(struct nb_cb_destroy_args *args)
1036
0
{
1037
0
  return lib_route_map_entry_set_destroy(args);
1038
0
}
1039
1040
/*
1041
 * XPath: /frr-route-map:lib/route-map/entry/set-action/min-metric
1042
 */
1043
static int set_action_min_metric_modify(enum nb_event event,
1044
          const struct lyd_node *dnode,
1045
          union nb_resource *resource,
1046
          const char *value, char *errmsg,
1047
          size_t errmsg_len)
1048
0
{
1049
0
  struct routemap_hook_context *rhc;
1050
0
  int rv;
1051
1052
0
  if (event != NB_EV_APPLY)
1053
0
    return NB_OK;
1054
1055
  /* Check for hook function. */
1056
0
  if (rmap_match_set_hook.set_min_metric == NULL)
1057
0
    return NB_OK;
1058
1059
  /* Add configuration. */
1060
0
  rhc = nb_running_get_entry(dnode, NULL, true);
1061
1062
  /* Set destroy information. */
1063
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_min_metric;
1064
0
  rhc->rhc_rule = "min-metric";
1065
1066
0
  rv = rmap_match_set_hook.set_min_metric(rhc->rhc_rmi, "min-metric",
1067
0
            value, errmsg, errmsg_len);
1068
0
  if (rv != CMD_SUCCESS) {
1069
0
    rhc->rhc_shook = NULL;
1070
0
    return NB_ERR_INCONSISTENCY;
1071
0
  }
1072
1073
0
  return NB_OK;
1074
0
}
1075
1076
static int
1077
lib_route_map_entry_set_action_min_metric_modify(struct nb_cb_modify_args *args)
1078
0
{
1079
0
  const char *min_metric = yang_dnode_get_string(args->dnode, NULL);
1080
1081
0
  return set_action_min_metric_modify(args->event, args->dnode,
1082
0
              args->resource, min_metric,
1083
0
              args->errmsg, args->errmsg_len);
1084
0
}
1085
1086
static int lib_route_map_entry_set_action_min_metric_destroy(
1087
  struct nb_cb_destroy_args *args)
1088
0
{
1089
0
  return lib_route_map_entry_set_destroy(args);
1090
0
}
1091
1092
/*
1093
 * XPath: /frr-route-map:lib/route-map/entry/set-action/max-metric
1094
 */
1095
static int set_action_max_metric_modify(enum nb_event event,
1096
          const struct lyd_node *dnode,
1097
          union nb_resource *resource,
1098
          const char *value, char *errmsg,
1099
          size_t errmsg_len)
1100
0
{
1101
0
  struct routemap_hook_context *rhc;
1102
0
  int rv;
1103
1104
0
  if (event != NB_EV_APPLY)
1105
0
    return NB_OK;
1106
1107
  /* Check for hook function. */
1108
0
  if (rmap_match_set_hook.set_max_metric == NULL)
1109
0
    return NB_OK;
1110
1111
  /* Add configuration. */
1112
0
  rhc = nb_running_get_entry(dnode, NULL, true);
1113
1114
  /* Set destroy information. */
1115
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_max_metric;
1116
0
  rhc->rhc_rule = "max-metric";
1117
1118
0
  rv = rmap_match_set_hook.set_max_metric(rhc->rhc_rmi, "max-metric",
1119
0
            value, errmsg, errmsg_len);
1120
0
  if (rv != CMD_SUCCESS) {
1121
0
    rhc->rhc_shook = NULL;
1122
0
    return NB_ERR_INCONSISTENCY;
1123
0
  }
1124
1125
0
  return NB_OK;
1126
0
}
1127
1128
static int
1129
lib_route_map_entry_set_action_max_metric_modify(struct nb_cb_modify_args *args)
1130
0
{
1131
0
  const char *max_metric = yang_dnode_get_string(args->dnode, NULL);
1132
1133
0
  return set_action_max_metric_modify(args->event, args->dnode,
1134
0
              args->resource, max_metric,
1135
0
              args->errmsg, args->errmsg_len);
1136
0
}
1137
1138
static int lib_route_map_entry_set_action_max_metric_destroy(
1139
  struct nb_cb_destroy_args *args)
1140
0
{
1141
0
  return lib_route_map_entry_set_destroy(args);
1142
0
}
1143
1144
/*
1145
 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric
1146
 */
1147
static int
1148
lib_route_map_entry_set_action_add_metric_modify(struct nb_cb_modify_args *args)
1149
0
{
1150
0
  char metric_str[16];
1151
1152
0
  if (args->event == NB_EV_VALIDATE
1153
0
      && yang_dnode_get_uint32(args->dnode, NULL) == 0) {
1154
0
    snprintf(args->errmsg, args->errmsg_len,
1155
0
       "Can't add zero to metric");
1156
0
    return NB_ERR_VALIDATION;
1157
0
  }
1158
1159
0
  snprintf(metric_str, sizeof(metric_str), "+%s",
1160
0
     yang_dnode_get_string(args->dnode, NULL));
1161
0
  return set_action_modify(args->event, args->dnode, args->resource,
1162
0
         metric_str,
1163
0
         args->errmsg, args->errmsg_len);
1164
0
}
1165
1166
static int lib_route_map_entry_set_action_add_metric_destroy(
1167
  struct nb_cb_destroy_args *args)
1168
0
{
1169
0
  return lib_route_map_entry_set_action_value_destroy(args);
1170
0
}
1171
1172
/*
1173
 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric
1174
 */
1175
static int lib_route_map_entry_set_action_subtract_metric_modify(
1176
  struct nb_cb_modify_args *args)
1177
0
{
1178
0
  char metric_str[16];
1179
1180
0
  if (args->event == NB_EV_VALIDATE
1181
0
      && yang_dnode_get_uint32(args->dnode, NULL) == 0) {
1182
0
    snprintf(args->errmsg, args->errmsg_len,
1183
0
       "Can't subtract zero from metric");
1184
0
    return NB_ERR_VALIDATION;
1185
0
  }
1186
1187
0
  snprintf(metric_str, sizeof(metric_str), "-%s",
1188
0
     yang_dnode_get_string(args->dnode, NULL));
1189
0
  return set_action_modify(args->event, args->dnode, args->resource,
1190
0
         metric_str,
1191
0
         args->errmsg, args->errmsg_len);
1192
0
}
1193
1194
static int lib_route_map_entry_set_action_subtract_metric_destroy(
1195
  struct nb_cb_destroy_args *args)
1196
0
{
1197
0
  return lib_route_map_entry_set_action_value_destroy(args);
1198
0
}
1199
1200
/*
1201
 * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time
1202
 */
1203
static int lib_route_map_entry_set_action_use_round_trip_time_modify(
1204
  struct nb_cb_modify_args *args)
1205
0
{
1206
0
  return set_action_modify(args->event, args->dnode, args->resource,
1207
0
         "rtt",
1208
0
         args->errmsg, args->errmsg_len);
1209
0
}
1210
1211
static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
1212
  struct nb_cb_destroy_args *args)
1213
0
{
1214
0
  return lib_route_map_entry_set_action_value_destroy(args);
1215
0
}
1216
1217
/*
1218
 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time
1219
 */
1220
static int lib_route_map_entry_set_action_add_round_trip_time_modify(
1221
  struct nb_cb_modify_args *args)
1222
0
{
1223
0
  return set_action_modify(args->event, args->dnode, args->resource,
1224
0
         "+rtt",
1225
0
         args->errmsg, args->errmsg_len);
1226
0
}
1227
1228
static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
1229
  struct nb_cb_destroy_args *args)
1230
0
{
1231
0
  return lib_route_map_entry_set_action_value_destroy(args);
1232
0
}
1233
1234
/*
1235
 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time
1236
 */
1237
static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
1238
  struct nb_cb_modify_args *args)
1239
0
{
1240
0
  return set_action_modify(args->event, args->dnode, args->resource,
1241
0
         "-rtt", args->errmsg, args->errmsg_len);
1242
0
}
1243
1244
static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
1245
  struct nb_cb_destroy_args *args)
1246
0
{
1247
0
  return lib_route_map_entry_set_action_value_destroy(args);
1248
0
}
1249
1250
/*
1251
 * XPath: /frr-route-map:lib/route-map/entry/set-action/tag
1252
 */
1253
static int
1254
lib_route_map_entry_set_action_tag_modify(struct nb_cb_modify_args *args)
1255
0
{
1256
0
  struct routemap_hook_context *rhc;
1257
0
  const char *tag;
1258
0
  int rv;
1259
1260
  /*
1261
   * NOTE: validate if 'action' is 'tag', currently it is not
1262
   * necessary because this is the only implemented action. Other
1263
   * actions might have different validations.
1264
   */
1265
0
  if (args->event != NB_EV_APPLY)
1266
0
    return NB_OK;
1267
1268
  /* Check for hook function. */
1269
0
  if (rmap_match_set_hook.set_tag == NULL)
1270
0
    return NB_OK;
1271
1272
  /* Add configuration. */
1273
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
1274
0
  tag = yang_dnode_get_string(args->dnode, NULL);
1275
1276
  /* Set destroy information. */
1277
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
1278
0
  rhc->rhc_rule = "tag";
1279
1280
0
  rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "tag", tag,
1281
0
           args->errmsg, args->errmsg_len);
1282
0
  if (rv != CMD_SUCCESS) {
1283
0
    rhc->rhc_shook = NULL;
1284
0
    return NB_ERR_INCONSISTENCY;
1285
0
  }
1286
1287
0
  return NB_OK;
1288
0
}
1289
1290
static int
1291
lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args *args)
1292
0
{
1293
0
  return lib_route_map_entry_set_destroy(args);
1294
0
}
1295
1296
/*
1297
 * XPath: /frr-route-map:lib/route-map/entry/set-action/policy
1298
 */
1299
static int
1300
lib_route_map_entry_set_action_policy_modify(struct nb_cb_modify_args *args)
1301
0
{
1302
0
  struct routemap_hook_context *rhc;
1303
0
  const char *policy;
1304
0
  int rv;
1305
1306
  /*
1307
   * NOTE: validate if 'action' is 'tag', currently it is not
1308
   * necessary because this is the only implemented action. Other
1309
   * actions might have different validations.
1310
   */
1311
0
  if (args->event != NB_EV_APPLY)
1312
0
    return NB_OK;
1313
1314
  /* Check for hook function. */
1315
0
  if (rmap_match_set_hook.set_srte_color == NULL)
1316
0
    return NB_OK;
1317
1318
  /* Add configuration. */
1319
0
  rhc = nb_running_get_entry(args->dnode, NULL, true);
1320
0
  policy = yang_dnode_get_string(args->dnode, NULL);
1321
1322
  /* Set destroy information. */
1323
0
  rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
1324
0
  rhc->rhc_rule = "sr-te color";
1325
1326
0
  rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "sr-te color", policy,
1327
0
      args->errmsg, args->errmsg_len);
1328
0
  if (rv != CMD_SUCCESS) {
1329
0
    rhc->rhc_shook = NULL;
1330
0
    return NB_ERR_INCONSISTENCY;
1331
0
  }
1332
1333
0
  return NB_OK;
1334
0
}
1335
1336
static int
1337
lib_route_map_entry_set_action_policy_destroy(struct nb_cb_destroy_args *args)
1338
0
{
1339
0
  return lib_route_map_entry_set_destroy(args);
1340
0
}
1341
1342
/* clang-format off */
1343
const struct frr_yang_module_info frr_route_map_info = {
1344
  .name = "frr-route-map",
1345
  .nodes = {
1346
    {
1347
      .xpath = "/frr-route-map:lib/route-map",
1348
      .cbs = {
1349
        .create = lib_route_map_create,
1350
        .destroy = lib_route_map_destroy,
1351
      }
1352
    },
1353
    {
1354
      .xpath = "/frr-route-map:lib/route-map/optimization-disabled",
1355
      .cbs = {
1356
        .modify = lib_route_map_optimization_disabled_modify,
1357
        .cli_show = route_map_optimization_disabled_show,
1358
      }
1359
    },
1360
    {
1361
      .xpath = "/frr-route-map:lib/route-map/entry",
1362
      .cbs = {
1363
        .create = lib_route_map_entry_create,
1364
        .destroy = lib_route_map_entry_destroy,
1365
        .cli_cmp = route_map_instance_cmp,
1366
        .cli_show = route_map_instance_show,
1367
        .cli_show_end = route_map_instance_show_end,
1368
      }
1369
    },
1370
    {
1371
      .xpath = "/frr-route-map:lib/route-map/entry/description",
1372
      .cbs = {
1373
        .modify = lib_route_map_entry_description_modify,
1374
        .destroy = lib_route_map_entry_description_destroy,
1375
        .cli_show = route_map_description_show,
1376
      }
1377
    },
1378
    {
1379
      .xpath = "/frr-route-map:lib/route-map/entry/action",
1380
      .cbs = {
1381
        .modify = lib_route_map_entry_action_modify,
1382
      }
1383
    },
1384
    {
1385
      .xpath = "/frr-route-map:lib/route-map/entry/call",
1386
      .cbs = {
1387
        .modify = lib_route_map_entry_call_modify,
1388
        .destroy = lib_route_map_entry_call_destroy,
1389
        .cli_show = route_map_call_show,
1390
      }
1391
    },
1392
    {
1393
      .xpath = "/frr-route-map:lib/route-map/entry/exit-policy",
1394
      .cbs = {
1395
        .modify = lib_route_map_entry_exit_policy_modify,
1396
        .cli_show = route_map_exit_policy_show,
1397
      }
1398
    },
1399
    {
1400
      .xpath = "/frr-route-map:lib/route-map/entry/goto-value",
1401
      .cbs = {
1402
        .modify = lib_route_map_entry_goto_value_modify,
1403
        .destroy = lib_route_map_entry_goto_value_destroy,
1404
      }
1405
    },
1406
    {
1407
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition",
1408
      .cbs = {
1409
        .create = lib_route_map_entry_match_condition_create,
1410
        .destroy = lib_route_map_entry_match_condition_destroy,
1411
        .cli_show = route_map_condition_show,
1412
      }
1413
    },
1414
    {
1415
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/interface",
1416
      .cbs = {
1417
        .modify = lib_route_map_entry_match_condition_interface_modify,
1418
        .destroy = lib_route_map_entry_match_condition_interface_destroy,
1419
      }
1420
    },
1421
    {
1422
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/list-name",
1423
      .cbs = {
1424
        .modify = lib_route_map_entry_match_condition_list_name_modify,
1425
        .destroy = lib_route_map_entry_match_condition_list_name_destroy,
1426
      }
1427
    },
1428
    {
1429
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv4-next-hop-type",
1430
      .cbs = {
1431
        .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify,
1432
        .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy,
1433
      }
1434
    },
1435
    {
1436
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv6-next-hop-type",
1437
      .cbs = {
1438
        .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify,
1439
        .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy,
1440
      }
1441
    },
1442
    {
1443
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/metric",
1444
      .cbs = {
1445
        .modify = lib_route_map_entry_match_condition_metric_modify,
1446
        .destroy = lib_route_map_entry_match_condition_metric_destroy,
1447
      }
1448
    },
1449
    {
1450
      .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/tag",
1451
      .cbs = {
1452
        .modify = lib_route_map_entry_match_condition_tag_modify,
1453
        .destroy = lib_route_map_entry_match_condition_tag_destroy,
1454
      }
1455
    },
1456
    {
1457
      .xpath = "/frr-route-map:lib/route-map/entry/set-action",
1458
      .cbs = {
1459
        .create = lib_route_map_entry_set_action_create,
1460
        .destroy = lib_route_map_entry_set_action_destroy,
1461
        .cli_show = route_map_action_show,
1462
      }
1463
    },
1464
    {
1465
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv4-address",
1466
      .cbs = {
1467
        .modify = lib_route_map_entry_set_action_ipv4_address_modify,
1468
        .destroy = lib_route_map_entry_set_action_ipv4_address_destroy,
1469
      }
1470
    },
1471
    {
1472
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv6-address",
1473
      .cbs = {
1474
        .modify = lib_route_map_entry_set_action_ipv6_address_modify,
1475
        .destroy = lib_route_map_entry_set_action_ipv6_address_destroy,
1476
      }
1477
    },
1478
    {
1479
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/value",
1480
      .cbs = {
1481
        .modify = lib_route_map_entry_set_action_value_modify,
1482
        .destroy = lib_route_map_entry_set_action_value_destroy,
1483
      }
1484
    },
1485
    {
1486
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/min-metric",
1487
      .cbs = {
1488
        .modify = lib_route_map_entry_set_action_min_metric_modify,
1489
        .destroy = lib_route_map_entry_set_action_min_metric_destroy,
1490
      }
1491
    },
1492
    {
1493
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/max-metric",
1494
      .cbs = {
1495
        .modify = lib_route_map_entry_set_action_max_metric_modify,
1496
        .destroy = lib_route_map_entry_set_action_max_metric_destroy,
1497
      }
1498
    },
1499
    {
1500
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric",
1501
      .cbs = {
1502
        .modify = lib_route_map_entry_set_action_add_metric_modify,
1503
        .destroy = lib_route_map_entry_set_action_add_metric_destroy,
1504
      }
1505
    },
1506
    {
1507
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-metric",
1508
      .cbs = {
1509
        .modify = lib_route_map_entry_set_action_subtract_metric_modify,
1510
        .destroy = lib_route_map_entry_set_action_subtract_metric_destroy,
1511
      }
1512
    },
1513
    {
1514
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-round-trip-time",
1515
      .cbs = {
1516
        .modify = lib_route_map_entry_set_action_use_round_trip_time_modify,
1517
        .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy,
1518
      }
1519
    },
1520
    {
1521
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time",
1522
      .cbs = {
1523
        .modify = lib_route_map_entry_set_action_add_round_trip_time_modify,
1524
        .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy,
1525
      }
1526
    },
1527
    {
1528
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-round-trip-time",
1529
      .cbs = {
1530
        .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify,
1531
        .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy,
1532
      }
1533
    },
1534
    {
1535
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/tag",
1536
      .cbs = {
1537
        .modify = lib_route_map_entry_set_action_tag_modify,
1538
        .destroy = lib_route_map_entry_set_action_tag_destroy,
1539
      }
1540
    },
1541
    {
1542
      .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy",
1543
      .cbs = {
1544
        .modify = lib_route_map_entry_set_action_policy_modify,
1545
        .destroy = lib_route_map_entry_set_action_policy_destroy,
1546
      }
1547
    },
1548
1549
    {
1550
      .xpath = NULL,
1551
    },
1552
  }
1553
};