Coverage Report

Created: 2025-08-28 06:29

/src/frr/lib/if.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Interface functions.
4
 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5
 */
6
7
#include <zebra.h>
8
9
#include "linklist.h"
10
#include "vector.h"
11
#include "lib_errors.h"
12
#include "vty.h"
13
#include "command.h"
14
#include "vrf.h"
15
#include "if.h"
16
#include "sockunion.h"
17
#include "prefix.h"
18
#include "memory.h"
19
#include "table.h"
20
#include "buffer.h"
21
#include "log.h"
22
#include "northbound_cli.h"
23
#include "admin_group.h"
24
#include "lib/if_clippy.c"
25
26
DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
27
DEFINE_MTYPE_STATIC(LIB, IFDESC, "Intf Desc");
28
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
29
DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
30
DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
31
DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
32
33
static void if_set_name(struct interface *ifp, const char *name);
34
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
35
                vrf_id_t vrf_id);
36
static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex);
37
static int if_cmp_func(const struct interface *, const struct interface *);
38
static int if_cmp_index_func(const struct interface *ifp1,
39
           const struct interface *ifp2);
40
RB_GENERATE(if_name_head, interface, name_entry, if_cmp_func);
41
RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func);
42
43
DEFINE_QOBJ_TYPE(interface);
44
45
DEFINE_HOOK(if_add, (struct interface * ifp), (ifp));
46
DEFINE_KOOH(if_del, (struct interface * ifp), (ifp));
47
48
static struct interface_master{
49
  int (*create_hook)(struct interface *ifp);
50
  int (*up_hook)(struct interface *ifp);
51
  int (*down_hook)(struct interface *ifp);
52
  int (*destroy_hook)(struct interface *ifp);
53
} ifp_master = { 0, };
54
55
/* Compare interface names, returning an integer greater than, equal to, or
56
 * less than 0, (following the strcmp convention), according to the
57
 * relationship between ifp1 and ifp2.  Interface names consist of an
58
 * alphabetic prefix and a numeric suffix.  The primary sort key is
59
 * lexicographic by name, and then numeric by number.  No number sorts
60
 * before all numbers.  Examples: de0 < de1, de100 < fxp0 < xl0, devpty <
61
 * devpty0, de0 < del0
62
 */
63
int if_cmp_name_func(const char *p1, const char *p2)
64
5
{
65
5
  unsigned int l1, l2;
66
5
  long int x1, x2;
67
5
  int res;
68
69
5
  while (*p1 && *p2) {
70
2
    char *tmp1, *tmp2;
71
72
    /* look up to any number */
73
2
    l1 = strcspn(p1, "0123456789");
74
2
    l2 = strcspn(p2, "0123456789");
75
76
    /* name lengths are different -> compare names */
77
2
    if (l1 != l2)
78
2
      return (strcmp(p1, p2));
79
80
    /* Note that this relies on all numbers being less than all
81
     * letters, so
82
     * that de0 < del0.
83
     */
84
0
    res = strncmp(p1, p2, l1);
85
86
    /* names are different -> compare them */
87
0
    if (res)
88
0
      return res;
89
90
    /* with identical name part, go to numeric part */
91
0
    p1 += l1;
92
0
    p2 += l1;
93
94
0
    if (!*p1 && !*p2)
95
0
      return 0;
96
0
    if (!*p1)
97
0
      return -1;
98
0
    if (!*p2)
99
0
      return 1;
100
101
0
    x1 = strtol(p1, (char **)&tmp1, 10);
102
0
    x2 = strtol(p2, (char **)&tmp2, 10);
103
104
    /* let's compare numbers now */
105
0
    if (x1 < x2)
106
0
      return -1;
107
0
    if (x1 > x2)
108
0
      return 1;
109
110
    /* Compare string if numbers are equal (distinguish foo-1 from foo-001) */
111
0
    l1 = strspn(p1, "0123456789");
112
0
    l2 = strspn(p2, "0123456789");
113
0
    if (l1 != l2)
114
0
      return (strcmp(p1, p2));
115
116
    /* Continue to parse the rest of the string */
117
0
    p1 = (const char *)tmp1;
118
0
    p2 = (const char *)tmp2;
119
120
    /* numbers were equal, lets do it again..
121
    (it happens with name like "eth123.456:789") */
122
0
  }
123
3
  if (*p1)
124
0
    return 1;
125
3
  if (*p2)
126
3
    return -1;
127
0
  return 0;
128
3
}
129
130
static int if_cmp_func(const struct interface *ifp1,
131
           const struct interface *ifp2)
132
2
{
133
2
  return if_cmp_name_func(ifp1->name, ifp2->name);
134
2
}
135
136
static int if_cmp_index_func(const struct interface *ifp1,
137
           const struct interface *ifp2)
138
0
{
139
0
  if (ifp1->ifindex == ifp2->ifindex)
140
0
    return 0;
141
0
  else if (ifp1->ifindex > ifp2->ifindex)
142
0
    return 1;
143
0
  else
144
0
    return -1;
145
0
}
146
147
static void ifp_connected_free(void *arg)
148
0
{
149
0
  struct connected *c = arg;
150
151
0
  connected_free(&c);
152
0
}
153
154
/* Create new interface structure. */
155
static struct interface *if_new(struct vrf *vrf)
156
3
{
157
3
  struct interface *ifp;
158
159
3
  assert(vrf);
160
161
3
  ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
162
163
3
  ifp->ifindex = IFINDEX_INTERNAL;
164
3
  ifp->name[0] = '\0';
165
166
3
  ifp->vrf = vrf;
167
168
3
  ifp->connected = list_new();
169
3
  ifp->connected->del = ifp_connected_free;
170
171
3
  ifp->nbr_connected = list_new();
172
3
  ifp->nbr_connected->del = (void (*)(void *))nbr_connected_free;
173
174
  /* Enable Link-detection by default */
175
3
  SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
176
177
3
  QOBJ_REG(ifp, interface);
178
3
  return ifp;
179
3
}
180
181
void if_new_via_zapi(struct interface *ifp)
182
0
{
183
0
  if (ifp_master.create_hook)
184
0
    (*ifp_master.create_hook)(ifp);
185
0
}
186
187
void if_destroy_via_zapi(struct interface *ifp)
188
0
{
189
0
  if (ifp_master.destroy_hook)
190
0
    (*ifp_master.destroy_hook)(ifp);
191
192
0
  ifp->oldifindex = ifp->ifindex;
193
0
  if_set_index(ifp, IFINDEX_INTERNAL);
194
195
0
  if (!ifp->configured)
196
0
    if_delete(&ifp);
197
0
}
198
199
void if_up_via_zapi(struct interface *ifp)
200
0
{
201
0
  if (ifp_master.up_hook)
202
0
    (*ifp_master.up_hook)(ifp);
203
0
}
204
205
void if_down_via_zapi(struct interface *ifp)
206
0
{
207
0
  if (ifp_master.down_hook)
208
0
    (*ifp_master.down_hook)(ifp);
209
0
}
210
211
#ifndef FUZZING
212
static
213
#endif
214
struct interface *if_create_name(const char *name, struct vrf *vrf)
215
3
{
216
3
  struct interface *ifp;
217
218
3
  ifp = if_new(vrf);
219
220
3
  if_set_name(ifp, name);
221
222
3
  hook_call(if_add, ifp);
223
3
  return ifp;
224
3
}
225
226
/* Create new interface structure. */
227
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
228
0
{
229
0
  struct vrf *old_vrf, *vrf;
230
231
  /* remove interface from old master vrf list */
232
0
  old_vrf = ifp->vrf;
233
234
0
  if (ifp->name[0] != '\0')
235
0
    IFNAME_RB_REMOVE(old_vrf, ifp);
236
237
0
  if (ifp->ifindex != IFINDEX_INTERNAL)
238
0
    IFINDEX_RB_REMOVE(old_vrf, ifp);
239
240
0
  vrf = vrf_get(vrf_id, NULL);
241
0
  ifp->vrf = vrf;
242
243
0
  if (ifp->name[0] != '\0')
244
0
    IFNAME_RB_INSERT(vrf, ifp);
245
246
0
  if (ifp->ifindex != IFINDEX_INTERNAL)
247
0
    IFINDEX_RB_INSERT(vrf, ifp);
248
0
}
249
250
251
/* Delete interface structure. */
252
void if_delete_retain(struct interface *ifp)
253
0
{
254
0
  hook_call(if_del, ifp);
255
0
  QOBJ_UNREG(ifp);
256
257
  /* Free connected address list */
258
0
  list_delete_all_node(ifp->connected);
259
260
  /* Free connected nbr address list */
261
0
  list_delete_all_node(ifp->nbr_connected);
262
0
}
263
264
/* Delete and free interface structure. */
265
void if_delete(struct interface **ifp)
266
0
{
267
0
  struct interface *ptr = *ifp;
268
0
  struct vrf *vrf = ptr->vrf;
269
270
0
  IFNAME_RB_REMOVE(vrf, ptr);
271
0
  if (ptr->ifindex != IFINDEX_INTERNAL)
272
0
    IFINDEX_RB_REMOVE(vrf, ptr);
273
274
0
  if_delete_retain(ptr);
275
276
0
  list_delete(&ptr->connected);
277
0
  list_delete(&ptr->nbr_connected);
278
279
0
  if_link_params_free(ptr);
280
281
0
  XFREE(MTYPE_IFDESC, ptr->desc);
282
283
0
  XFREE(MTYPE_IF, ptr);
284
0
  *ifp = NULL;
285
0
}
286
287
/* Used only internally to check within VRF only */
288
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
289
                vrf_id_t vrf_id)
290
1
{
291
1
  struct vrf *vrf;
292
1
  struct interface if_tmp;
293
294
1
  vrf = vrf_lookup_by_id(vrf_id);
295
1
  if (!vrf)
296
0
    return NULL;
297
298
1
  if_tmp.ifindex = ifindex;
299
1
  return RB_FIND(if_index_head, &vrf->ifaces_by_index, &if_tmp);
300
1
}
301
302
/* Interface existence check by index. */
303
struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
304
0
{
305
0
  switch (vrf_get_backend()) {
306
0
  case VRF_BACKEND_UNKNOWN:
307
0
  case VRF_BACKEND_NETNS:
308
0
    return(if_lookup_by_ifindex(ifindex, vrf_id));
309
0
  case VRF_BACKEND_VRF_LITE:
310
0
    return(if_lookup_by_index_all_vrf(ifindex));
311
0
  }
312
0
  return NULL;
313
0
}
314
315
/* Interface existence check by index. */
316
struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex,
317
                vrf_id_t vrf_id)
318
0
{
319
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
320
0
  struct interface *tmp_ifp;
321
0
  bool found = false;
322
323
0
  if (!vrf)
324
0
    return NULL;
325
326
0
  if (ifindex == 0) {
327
0
    tmp_ifp = RB_MIN(if_index_head, &vrf->ifaces_by_index);
328
    /* skip the vrf interface */
329
0
    if (tmp_ifp && if_is_vrf(tmp_ifp))
330
0
      ifindex = tmp_ifp->ifindex;
331
0
    else
332
0
      return tmp_ifp;
333
0
  }
334
335
0
  RB_FOREACH (tmp_ifp, if_index_head, &vrf->ifaces_by_index) {
336
0
    if (found) {
337
      /* skip the vrf interface */
338
0
      if (tmp_ifp && if_is_vrf(tmp_ifp))
339
0
        continue;
340
0
      else
341
0
        return tmp_ifp;
342
0
    }
343
0
    if (tmp_ifp->ifindex == ifindex)
344
0
      found = true;
345
0
  }
346
0
  return NULL;
347
0
}
348
349
const char *ifindex2ifname(ifindex_t ifindex, vrf_id_t vrf_id)
350
0
{
351
0
  struct interface *ifp;
352
353
0
  return ((ifp = if_lookup_by_index(ifindex, vrf_id)) != NULL)
354
0
           ? ifp->name
355
0
           : "unknown";
356
0
}
357
358
ifindex_t ifname2ifindex(const char *name, vrf_id_t vrf_id)
359
0
{
360
0
  struct interface *ifp;
361
362
0
  return ((ifp = if_lookup_by_name(name, vrf_id)) != NULL)
363
0
           ? ifp->ifindex
364
0
           : IFINDEX_INTERNAL;
365
0
}
366
367
/* Interface existence check by interface name. */
368
struct interface *if_lookup_by_name(const char *name, vrf_id_t vrf_id)
369
0
{
370
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
371
0
  struct interface if_tmp;
372
373
0
  if (!vrf || !name
374
0
      || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ)
375
0
    return NULL;
376
377
0
  strlcpy(if_tmp.name, name, sizeof(if_tmp.name));
378
0
  return RB_FIND(if_name_head, &vrf->ifaces_by_name, &if_tmp);
379
0
}
380
381
struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf)
382
3
{
383
3
  struct interface if_tmp;
384
385
3
  if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ)
386
0
    return NULL;
387
388
3
  strlcpy(if_tmp.name, name, sizeof(if_tmp.name));
389
3
  return RB_FIND(if_name_head, &vrf->ifaces_by_name, &if_tmp);
390
3
}
391
392
static struct interface *if_lookup_by_name_all_vrf(const char *name)
393
2
{
394
2
  struct vrf *vrf;
395
2
  struct interface *ifp;
396
397
2
  if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ)
398
0
    return NULL;
399
400
2
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
401
2
    ifp = if_lookup_by_name_vrf(name, vrf);
402
2
    if (ifp)
403
0
      return ifp;
404
2
  }
405
406
2
  return NULL;
407
2
}
408
409
static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
410
0
{
411
0
  struct vrf *vrf;
412
0
  struct interface *ifp;
413
414
0
  if (ifindex == IFINDEX_INTERNAL)
415
0
    return NULL;
416
417
0
  RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
418
0
    ifp = if_lookup_by_ifindex(ifindex, vrf->vrf_id);
419
0
    if (ifp)
420
0
      return ifp;
421
0
  }
422
423
0
  return NULL;
424
0
}
425
426
/* Lookup interface by IP address.
427
 *
428
 * supersedes if_lookup_exact_address(), which didn't care about up/down
429
 * state.  but all users we have either only care if the address is local
430
 * (=> use if_address_is_local() please), or care about UP interfaces before
431
 * anything else
432
 *
433
 * to accept only UP interfaces, check if_is_up() on the returned ifp.
434
 */
435
struct interface *if_lookup_address_local(const void *src, int family,
436
            vrf_id_t vrf_id)
437
1.22k
{
438
1.22k
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
439
1.22k
  struct listnode *cnode;
440
1.22k
  struct interface *ifp, *best_down = NULL;
441
1.22k
  struct prefix *p;
442
1.22k
  struct connected *c;
443
444
1.22k
  if (family != AF_INET && family != AF_INET6)
445
0
    return NULL;
446
447
2.45k
  FOR_ALL_INTERFACES (vrf, ifp) {
448
2.45k
    for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
449
1.22k
      p = c->address;
450
451
1.22k
      if (!p || p->family != family)
452
0
        continue;
453
454
1.22k
      if (family == AF_INET) {
455
1.22k
        if (!IPV4_ADDR_SAME(&p->u.prefix4,
456
1.22k
                (struct in_addr *)src))
457
53
          continue;
458
1.22k
      } else if (family == AF_INET6) {
459
0
        if (!IPV6_ADDR_SAME(&p->u.prefix6,
460
0
                (struct in6_addr *)src))
461
0
          continue;
462
0
      }
463
464
1.17k
      if (if_is_up(ifp))
465
0
        return ifp;
466
1.17k
      if (!best_down)
467
1.17k
        best_down = ifp;
468
1.17k
    }
469
2.45k
  }
470
1.22k
  return best_down;
471
1.22k
}
472
473
/* Lookup interface by IP address. */
474
struct connected *if_lookup_address(const void *matchaddr, int family,
475
            vrf_id_t vrf_id)
476
0
{
477
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
478
0
  struct prefix addr;
479
0
  int bestlen = 0;
480
0
  struct listnode *cnode;
481
0
  struct interface *ifp;
482
0
  struct connected *c;
483
0
  struct connected *match;
484
485
0
  if (family == AF_INET) {
486
0
    addr.family = AF_INET;
487
0
    addr.u.prefix4 = *((struct in_addr *)matchaddr);
488
0
    addr.prefixlen = IPV4_MAX_BITLEN;
489
0
  } else if (family == AF_INET6) {
490
0
    addr.family = AF_INET6;
491
0
    addr.u.prefix6 = *((struct in6_addr *)matchaddr);
492
0
    addr.prefixlen = IPV6_MAX_BITLEN;
493
0
  } else
494
0
    assert(!"Attempted lookup of family not supported");
495
496
0
  match = NULL;
497
498
0
  FOR_ALL_INTERFACES (vrf, ifp) {
499
0
    for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
500
0
      if (c->address && (c->address->family == AF_INET)
501
0
          && prefix_match(CONNECTED_PREFIX(c), &addr)
502
0
          && (c->address->prefixlen > bestlen)) {
503
0
        bestlen = c->address->prefixlen;
504
0
        match = c;
505
0
      }
506
0
    }
507
0
  }
508
0
  return match;
509
0
}
510
511
/* Lookup interface by prefix */
512
struct interface *if_lookup_prefix(const struct prefix *prefix, vrf_id_t vrf_id)
513
0
{
514
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
515
0
  struct listnode *cnode;
516
0
  struct interface *ifp;
517
0
  struct connected *c;
518
519
0
  FOR_ALL_INTERFACES (vrf, ifp) {
520
0
    for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
521
0
      if (prefix_cmp(c->address, prefix) == 0) {
522
0
        return ifp;
523
0
      }
524
0
    }
525
0
  }
526
0
  return NULL;
527
0
}
528
529
size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
530
         struct interface ***result, vrf_id_t vrf_id)
531
0
{
532
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
533
534
0
  struct list *rs = list_new();
535
0
  struct interface *ifp;
536
537
0
  FOR_ALL_INTERFACES (vrf, ifp) {
538
0
    if (ifp->hw_addr_len == (int)addrsz
539
0
        && !memcmp(hw_addr, ifp->hw_addr, addrsz))
540
0
      listnode_add(rs, ifp);
541
0
  }
542
543
0
  if (rs->count) {
544
0
    *result = XCALLOC(MTYPE_TMP,
545
0
          sizeof(struct interface *) * rs->count);
546
0
    list_to_array(rs, (void **)*result, rs->count);
547
0
  }
548
549
0
  int count = rs->count;
550
551
0
  list_delete(&rs);
552
553
0
  return count;
554
0
}
555
556
/* Get the VRF loopback interface, i.e. the loopback on the default VRF
557
 * or the VRF interface.
558
 */
559
struct interface *if_get_vrf_loopback(vrf_id_t vrf_id)
560
0
{
561
0
  struct interface *ifp = NULL;
562
0
  struct vrf *vrf = vrf_lookup_by_id(vrf_id);
563
564
0
  FOR_ALL_INTERFACES (vrf, ifp)
565
0
    if (if_is_loopback(ifp))
566
0
      return ifp;
567
568
0
  return NULL;
569
0
}
570
571
/* Get interface by name if given name interface doesn't exist create
572
   one. */
573
struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id,
574
         const char *vrf_name)
575
3
{
576
3
  struct interface *ifp = NULL;
577
3
  struct vrf *vrf;
578
579
3
  switch (vrf_get_backend()) {
580
1
  case VRF_BACKEND_UNKNOWN:
581
1
  case VRF_BACKEND_NETNS:
582
1
    vrf = vrf_get(vrf_id, vrf_name);
583
1
    assert(vrf);
584
585
1
    ifp = if_lookup_by_name_vrf(name, vrf);
586
1
    if (ifp) {
587
      /* If it came from the kernel or by way of zclient,
588
       * believe it and update the ifp accordingly.
589
       */
590
0
      if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
591
0
        if_update_to_new_vrf(ifp, vrf_id);
592
593
0
      return ifp;
594
0
    }
595
596
1
    break;
597
2
  case VRF_BACKEND_VRF_LITE:
598
2
    ifp = if_lookup_by_name_all_vrf(name);
599
2
    if (ifp) {
600
      /* If it came from the kernel or by way of zclient,
601
       * believe it and update the ifp accordingly.
602
       */
603
0
      if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
604
0
        if_update_to_new_vrf(ifp, vrf_id);
605
606
0
      return ifp;
607
0
    }
608
609
2
    vrf = vrf_get(vrf_id, vrf_name);
610
2
    assert(vrf);
611
612
2
    break;
613
2
  default:
614
0
    return NULL;
615
3
  }
616
617
3
  return if_create_name(name, vrf);
618
3
}
619
620
int if_set_index(struct interface *ifp, ifindex_t ifindex)
621
1
{
622
1
  if (ifp->ifindex == ifindex)
623
0
    return 0;
624
625
  /*
626
   * If there is already an interface with this ifindex, we will collide
627
   * on insertion, so don't even try.
628
   */
629
1
  if (if_lookup_by_ifindex(ifindex, ifp->vrf->vrf_id))
630
0
    return -1;
631
632
1
  if (ifp->ifindex != IFINDEX_INTERNAL)
633
0
    IFINDEX_RB_REMOVE(ifp->vrf, ifp);
634
635
1
  ifp->ifindex = ifindex;
636
637
1
  if (ifp->ifindex != IFINDEX_INTERNAL) {
638
    /*
639
     * This should never happen, since we checked if there was
640
     * already an interface with the desired ifindex at the top of
641
     * the function. Nevertheless.
642
     */
643
1
    if (IFINDEX_RB_INSERT(ifp->vrf, ifp))
644
0
      return -1;
645
1
  }
646
647
1
  return 0;
648
1
}
649
650
static void if_set_name(struct interface *ifp, const char *name)
651
3
{
652
3
  if (if_cmp_name_func(ifp->name, name) == 0)
653
0
    return;
654
655
3
  if (ifp->name[0] != '\0')
656
0
    IFNAME_RB_REMOVE(ifp->vrf, ifp);
657
658
3
  strlcpy(ifp->name, name, sizeof(ifp->name));
659
660
3
  if (ifp->name[0] != '\0')
661
3
    IFNAME_RB_INSERT(ifp->vrf, ifp);
662
3
}
663
664
/* Does interface up ? */
665
int if_is_up(const struct interface *ifp)
666
4.47k
{
667
4.47k
  return ifp->flags & IFF_UP;
668
4.47k
}
669
670
/* Is interface running? */
671
int if_is_running(const struct interface *ifp)
672
0
{
673
0
  return ifp->flags & IFF_RUNNING;
674
0
}
675
676
/* Is the interface operative, eg. either UP & RUNNING
677
   or UP & !ZEBRA_INTERFACE_LINK_DETECTION and
678
   if ptm checking is enabled, then ptm check has passed */
679
int if_is_operative(const struct interface *ifp)
680
1
{
681
1
  return ((ifp->flags & IFF_UP)
682
1
    && (((ifp->flags & IFF_RUNNING)
683
0
         && (ifp->ptm_status || !ifp->ptm_enable))
684
0
        || !CHECK_FLAG(ifp->status,
685
0
           ZEBRA_INTERFACE_LINKDETECTION)));
686
1
}
687
688
/* Is the interface operative, eg. either UP & RUNNING
689
   or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */
690
int if_is_no_ptm_operative(const struct interface *ifp)
691
0
{
692
0
  return ((ifp->flags & IFF_UP)
693
0
    && ((ifp->flags & IFF_RUNNING)
694
0
        || !CHECK_FLAG(ifp->status,
695
0
           ZEBRA_INTERFACE_LINKDETECTION)));
696
0
}
697
698
/* Is this loopback interface ? */
699
int if_is_loopback_exact(const struct interface *ifp)
700
6.57k
{
701
  /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M
702
   * but Y on platform N?
703
   */
704
6.57k
  return (ifp->flags & (IFF_LOOPBACK | IFF_NOXMIT | IFF_VIRTUAL));
705
6.57k
}
706
707
/* Check interface is VRF */
708
int if_is_vrf(const struct interface *ifp)
709
6.57k
{
710
6.57k
  return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
711
6.57k
}
712
713
/* Should this interface be treated as a loopback? */
714
bool if_is_loopback(const struct interface *ifp)
715
6.57k
{
716
6.57k
  if (if_is_loopback_exact(ifp) || if_is_vrf(ifp))
717
0
    return true;
718
719
6.57k
  return false;
720
6.57k
}
721
722
/* Does this interface support broadcast ? */
723
int if_is_broadcast(const struct interface *ifp)
724
0
{
725
0
  return ifp->flags & IFF_BROADCAST;
726
0
}
727
728
/* Does this interface support pointopoint ? */
729
int if_is_pointopoint(const struct interface *ifp)
730
0
{
731
0
  return ifp->flags & IFF_POINTOPOINT;
732
0
}
733
734
/* Does this interface support multicast ? */
735
int if_is_multicast(const struct interface *ifp)
736
0
{
737
0
  return ifp->flags & IFF_MULTICAST;
738
0
}
739
740
/* Printout flag information into log */
741
const char *if_flag_dump(unsigned long flag)
742
0
{
743
0
  int separator = 0;
744
0
  static char logbuf[BUFSIZ];
745
746
0
#define IFF_OUT_LOG(X, STR)                                                    \
747
0
  if (flag & (X)) {                                                      \
748
0
    if (separator)                                                 \
749
0
      strlcat(logbuf, ",", sizeof(logbuf));                  \
750
0
    else                                                           \
751
0
      separator = 1;                                         \
752
0
    strlcat(logbuf, STR, sizeof(logbuf));                          \
753
0
  }
754
755
0
  strlcpy(logbuf, "<", BUFSIZ);
756
0
  IFF_OUT_LOG(IFF_UP, "UP");
757
0
  IFF_OUT_LOG(IFF_BROADCAST, "BROADCAST");
758
0
  IFF_OUT_LOG(IFF_DEBUG, "DEBUG");
759
0
  IFF_OUT_LOG(IFF_LOOPBACK, "LOOPBACK");
760
0
  IFF_OUT_LOG(IFF_POINTOPOINT, "POINTOPOINT");
761
0
  IFF_OUT_LOG(IFF_NOTRAILERS, "NOTRAILERS");
762
0
  IFF_OUT_LOG(IFF_RUNNING, "RUNNING");
763
0
  IFF_OUT_LOG(IFF_NOARP, "NOARP");
764
0
  IFF_OUT_LOG(IFF_PROMISC, "PROMISC");
765
0
  IFF_OUT_LOG(IFF_ALLMULTI, "ALLMULTI");
766
0
  IFF_OUT_LOG(IFF_OACTIVE, "OACTIVE");
767
0
  IFF_OUT_LOG(IFF_SIMPLEX, "SIMPLEX");
768
0
  IFF_OUT_LOG(IFF_LINK0, "LINK0");
769
0
  IFF_OUT_LOG(IFF_LINK1, "LINK1");
770
0
  IFF_OUT_LOG(IFF_LINK2, "LINK2");
771
0
  IFF_OUT_LOG(IFF_MULTICAST, "MULTICAST");
772
0
  IFF_OUT_LOG(IFF_NOXMIT, "NOXMIT");
773
0
  IFF_OUT_LOG(IFF_NORTEXCH, "NORTEXCH");
774
0
  IFF_OUT_LOG(IFF_VIRTUAL, "VIRTUAL");
775
0
  IFF_OUT_LOG(IFF_IPV4, "IPv4");
776
0
  IFF_OUT_LOG(IFF_IPV6, "IPv6");
777
778
0
  strlcat(logbuf, ">", sizeof(logbuf));
779
780
0
  return logbuf;
781
0
#undef IFF_OUT_LOG
782
0
}
783
784
/* For debugging */
785
static void if_dump(const struct interface *ifp)
786
0
{
787
0
  struct listnode *node;
788
0
  struct connected *c __attribute__((unused));
789
790
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c))
791
0
    zlog_info(
792
0
      "Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s",
793
0
      ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
794
0
      ifp->ifindex, ifp->metric, ifp->mtu, ifp->mtu6,
795
0
      if_flag_dump(ifp->flags));
796
0
}
797
798
/* Interface printing for all interface. */
799
void if_dump_all(void)
800
0
{
801
0
  struct vrf *vrf;
802
0
  void *ifp;
803
804
0
  RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
805
0
    FOR_ALL_INTERFACES (vrf, ifp)
806
0
      if_dump(ifp);
807
0
}
808
809
/* Allocate connected structure. */
810
struct connected *connected_new(void)
811
2
{
812
2
  return XCALLOC(MTYPE_CONNECTED, sizeof(struct connected));
813
2
}
814
815
/* Allocate nbr connected structure. */
816
struct nbr_connected *nbr_connected_new(void)
817
0
{
818
0
  return XCALLOC(MTYPE_NBR_CONNECTED, sizeof(struct nbr_connected));
819
0
}
820
821
/* Free connected structure. */
822
void connected_free(struct connected **connected)
823
0
{
824
0
  struct connected *ptr = *connected;
825
826
0
  prefix_free(&ptr->address);
827
0
  prefix_free(&ptr->destination);
828
829
0
  XFREE(MTYPE_CONNECTED_LABEL, ptr->label);
830
831
0
  XFREE(MTYPE_CONNECTED, ptr);
832
0
  *connected = NULL;
833
0
}
834
835
/* Free nbr connected structure. */
836
void nbr_connected_free(struct nbr_connected *connected)
837
0
{
838
0
  if (connected->address)
839
0
    prefix_free(&connected->address);
840
841
0
  XFREE(MTYPE_NBR_CONNECTED, connected);
842
0
}
843
844
/* If same interface nbr address already exists... */
845
struct nbr_connected *nbr_connected_check(struct interface *ifp,
846
            struct prefix *p)
847
0
{
848
0
  struct nbr_connected *ifc;
849
0
  struct listnode *node;
850
851
0
  for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node, ifc))
852
0
    if (prefix_same(ifc->address, p))
853
0
      return ifc;
854
855
0
  return NULL;
856
0
}
857
858
/* Print if_addr structure. */
859
static void __attribute__((unused))
860
connected_log(struct connected *connected, char *str)
861
0
{
862
0
  struct prefix *p;
863
0
  struct interface *ifp;
864
0
  char logbuf[BUFSIZ];
865
0
  char buf[BUFSIZ];
866
0
867
0
  ifp = connected->ifp;
868
0
  p = connected->address;
869
0
870
0
  snprintf(logbuf, sizeof(logbuf), "%s interface %s vrf %s(%u) %s %pFX ",
871
0
     str, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
872
0
     prefix_family_str(p), p);
873
0
874
0
  p = connected->destination;
875
0
  if (p) {
876
0
    strlcat(logbuf, inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
877
0
      BUFSIZ);
878
0
  }
879
0
  zlog_info("%s", logbuf);
880
0
}
881
882
/* Print if_addr structure. */
883
static void __attribute__((unused))
884
nbr_connected_log(struct nbr_connected *connected, char *str)
885
0
{
886
0
  struct prefix *p;
887
0
  struct interface *ifp;
888
0
  char logbuf[BUFSIZ];
889
0
890
0
  ifp = connected->ifp;
891
0
  p = connected->address;
892
0
893
0
  snprintf(logbuf, sizeof(logbuf), "%s interface %s %s %pFX ", str,
894
0
     ifp->name, prefix_family_str(p), p);
895
0
896
0
  zlog_info("%s", logbuf);
897
0
}
898
899
/* If two connected address has same prefix return 1. */
900
static int connected_same_prefix(const struct prefix *p1,
901
         const struct prefix *p2)
902
0
{
903
0
  if (p1->family == p2->family) {
904
0
    if (p1->family == AF_INET
905
0
        && IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
906
0
      return 1;
907
0
    if (p1->family == AF_INET6
908
0
        && IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6))
909
0
      return 1;
910
0
  }
911
0
  return 0;
912
0
}
913
914
/* count the number of connected addresses that are in the given family */
915
unsigned int connected_count_by_family(struct interface *ifp, int family)
916
0
{
917
0
  struct listnode *cnode;
918
0
  struct connected *connected;
919
0
  unsigned int cnt = 0;
920
921
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected))
922
0
    if (connected->address->family == family)
923
0
      cnt++;
924
925
0
  return cnt;
926
0
}
927
928
struct connected *connected_lookup_prefix_exact(struct interface *ifp,
929
            const struct prefix *p)
930
0
{
931
0
  struct listnode *node;
932
0
  struct listnode *next;
933
0
  struct connected *ifc;
934
935
0
  for (node = listhead(ifp->connected); node; node = next) {
936
0
    ifc = listgetdata(node);
937
0
    next = node->next;
938
939
0
    if (connected_same_prefix(ifc->address, p))
940
0
      return ifc;
941
0
  }
942
0
  return NULL;
943
0
}
944
945
struct connected *connected_delete_by_prefix(struct interface *ifp,
946
               struct prefix *p)
947
0
{
948
0
  struct listnode *node;
949
0
  struct listnode *next;
950
0
  struct connected *ifc;
951
952
  /* In case of same prefix come, replace it with new one. */
953
0
  for (node = listhead(ifp->connected); node; node = next) {
954
0
    ifc = listgetdata(node);
955
0
    next = node->next;
956
957
0
    if (connected_same_prefix(ifc->address, p)) {
958
0
      listnode_delete(ifp->connected, ifc);
959
0
      return ifc;
960
0
    }
961
0
  }
962
0
  return NULL;
963
0
}
964
965
/* Find the address on our side that will be used when packets
966
   are sent to dst. */
967
struct connected *connected_lookup_prefix(struct interface *ifp,
968
            const struct prefix *addr)
969
0
{
970
0
  struct listnode *cnode;
971
0
  struct connected *c;
972
0
  struct connected *match;
973
974
0
  match = NULL;
975
976
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
977
0
    if (c->address && (c->address->family == addr->family)
978
0
        && prefix_match(CONNECTED_PREFIX(c), addr)
979
0
        && (!match
980
0
      || (c->address->prefixlen > match->address->prefixlen)))
981
0
      match = c;
982
0
  }
983
0
  return match;
984
0
}
985
986
struct connected *connected_add_by_prefix(struct interface *ifp,
987
            struct prefix *p,
988
            struct prefix *destination)
989
2
{
990
2
  struct connected *ifc;
991
992
  /* Allocate new connected address. */
993
2
  ifc = connected_new();
994
2
  ifc->ifp = ifp;
995
996
  /* Fetch interface address */
997
2
  ifc->address = prefix_new();
998
2
  memcpy(ifc->address, p, sizeof(struct prefix));
999
1000
  /* Fetch dest address */
1001
2
  if (destination) {
1002
0
    ifc->destination = prefix_new();
1003
0
    memcpy(ifc->destination, destination, sizeof(struct prefix));
1004
0
  }
1005
1006
  /* Add connected address to the interface. */
1007
2
  listnode_add(ifp->connected, ifc);
1008
2
  return ifc;
1009
2
}
1010
1011
struct connected *connected_get_linklocal(struct interface *ifp)
1012
0
{
1013
0
  struct listnode *n;
1014
0
  struct connected *c = NULL;
1015
1016
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) {
1017
0
    if (c->address->family == AF_INET6
1018
0
        && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
1019
0
      break;
1020
0
  }
1021
0
  return c;
1022
0
}
1023
1024
void if_terminate(struct vrf *vrf)
1025
0
{
1026
0
  struct interface *ifp;
1027
1028
0
  while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
1029
0
    ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);
1030
1031
0
    if (ifp->node) {
1032
0
      ifp->node->info = NULL;
1033
0
      route_unlock_node(ifp->node);
1034
0
      ifp->node = NULL;
1035
0
    }
1036
0
    if_delete(&ifp);
1037
0
  }
1038
0
}
1039
1040
const char *if_link_type_str(enum zebra_link_type llt)
1041
0
{
1042
0
  switch (llt) {
1043
0
#define llts(T,S) case (T): return (S)
1044
0
    llts(ZEBRA_LLT_UNKNOWN, "Unknown");
1045
0
    llts(ZEBRA_LLT_ETHER, "Ethernet");
1046
0
    llts(ZEBRA_LLT_EETHER, "Experimental Ethernet");
1047
0
    llts(ZEBRA_LLT_AX25, "AX.25 Level 2");
1048
0
    llts(ZEBRA_LLT_PRONET, "PROnet token ring");
1049
0
    llts(ZEBRA_LLT_IEEE802, "IEEE 802.2 Ethernet/TR/TB");
1050
0
    llts(ZEBRA_LLT_ARCNET, "ARCnet");
1051
0
    llts(ZEBRA_LLT_APPLETLK, "AppleTalk");
1052
0
    llts(ZEBRA_LLT_DLCI, "Frame Relay DLCI");
1053
0
    llts(ZEBRA_LLT_ATM, "ATM");
1054
0
    llts(ZEBRA_LLT_METRICOM, "Metricom STRIP");
1055
0
    llts(ZEBRA_LLT_IEEE1394, "IEEE 1394 IPv4");
1056
0
    llts(ZEBRA_LLT_EUI64, "EUI-64");
1057
0
    llts(ZEBRA_LLT_INFINIBAND, "InfiniBand");
1058
0
    llts(ZEBRA_LLT_SLIP, "SLIP");
1059
0
    llts(ZEBRA_LLT_CSLIP, "Compressed SLIP");
1060
0
    llts(ZEBRA_LLT_SLIP6, "SLIPv6");
1061
0
    llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6");
1062
0
    llts(ZEBRA_LLT_RSRVD, "Reserved");
1063
0
    llts(ZEBRA_LLT_ADAPT, "Adapt");
1064
0
    llts(ZEBRA_LLT_ROSE, "ROSE packet radio");
1065
0
    llts(ZEBRA_LLT_X25, "CCITT X.25");
1066
0
    llts(ZEBRA_LLT_PPP, "PPP");
1067
0
    llts(ZEBRA_LLT_CHDLC, "Cisco HDLC");
1068
0
    llts(ZEBRA_LLT_RAWHDLC, "Raw HDLC");
1069
0
    llts(ZEBRA_LLT_LAPB, "LAPB");
1070
0
    llts(ZEBRA_LLT_IPIP, "IPIP Tunnel");
1071
0
    llts(ZEBRA_LLT_IPIP6, "IPIP6 Tunnel");
1072
0
    llts(ZEBRA_LLT_FRAD, "FRAD");
1073
0
    llts(ZEBRA_LLT_SKIP, "SKIP vif");
1074
0
    llts(ZEBRA_LLT_LOOPBACK, "Loopback");
1075
0
    llts(ZEBRA_LLT_LOCALTLK, "Localtalk");
1076
0
    llts(ZEBRA_LLT_FDDI, "FDDI");
1077
0
    llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT");
1078
0
    llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel");
1079
0
    llts(ZEBRA_LLT_IPGRE, "GRE over IP");
1080
0
    llts(ZEBRA_LLT_IP6GRE, "GRE over IPv6");
1081
0
    llts(ZEBRA_LLT_PIMREG, "PIMSM registration");
1082
0
    llts(ZEBRA_LLT_HIPPI, "HiPPI");
1083
0
    llts(ZEBRA_LLT_ECONET, "Acorn Econet");
1084
0
    llts(ZEBRA_LLT_IRDA, "IrDA");
1085
0
    llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP");
1086
0
    llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop");
1087
0
    llts(ZEBRA_LLT_FCPL, "Fibre-Channel Public Loop");
1088
0
    llts(ZEBRA_LLT_FCFABRIC, "Fibre-Channel Fabric");
1089
0
    llts(ZEBRA_LLT_IEEE802_TR, "IEEE 802.2 Token Ring");
1090
0
    llts(ZEBRA_LLT_IEEE80211, "IEEE 802.11");
1091
0
    llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap");
1092
0
    llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4");
1093
0
    llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy");
1094
0
#undef llts
1095
0
  }
1096
0
  return NULL;
1097
0
}
1098
1099
bool if_link_params_cmp(struct if_link_params *iflp1,
1100
      struct if_link_params *iflp2)
1101
0
{
1102
0
  struct if_link_params iflp1_copy, iflp2_copy;
1103
1104
  /* Extended admin-groups in if_link_params contain pointers.
1105
   * They cannot be compared with memcpy.
1106
   * Make copies of if_link_params without ext. admin-groups
1107
   * and compare separately the ext. admin-groups.
1108
   */
1109
0
  memcpy(&iflp1_copy, iflp1, sizeof(struct if_link_params));
1110
0
  memset(&iflp1_copy.ext_admin_grp, 0, sizeof(struct admin_group));
1111
1112
0
  memcpy(&iflp2_copy, iflp2, sizeof(struct if_link_params));
1113
0
  memset(&iflp2_copy.ext_admin_grp, 0, sizeof(struct admin_group));
1114
1115
0
  if (memcmp(&iflp1_copy, &iflp2_copy, sizeof(struct if_link_params)))
1116
0
    return false;
1117
1118
0
  if (!admin_group_cmp(&iflp1->ext_admin_grp, &iflp2->ext_admin_grp))
1119
0
    return false;
1120
1121
0
  return true;
1122
0
}
1123
1124
void if_link_params_copy(struct if_link_params *dst, struct if_link_params *src)
1125
0
{
1126
0
  struct admin_group dst_ag;
1127
1128
  /* backup the admin_group structure that contains a pointer */
1129
0
  memcpy(&dst_ag, &dst->ext_admin_grp, sizeof(struct admin_group));
1130
  /* copy the if_link_params structure */
1131
0
  memcpy(dst, src, sizeof(struct if_link_params));
1132
  /* restore the admin_group structure */
1133
0
  memcpy(&dst->ext_admin_grp, &dst_ag, sizeof(struct admin_group));
1134
  /* copy src->ext_admin_grp data to dst->ext_admin_grp data memory */
1135
0
  admin_group_copy(&dst->ext_admin_grp, &src->ext_admin_grp);
1136
0
}
1137
1138
struct if_link_params *if_link_params_get(struct interface *ifp)
1139
0
{
1140
0
  return ifp->link_params;
1141
0
}
1142
1143
struct if_link_params *if_link_params_enable(struct interface *ifp)
1144
0
{
1145
0
  struct if_link_params *iflp;
1146
0
  int i;
1147
1148
0
  iflp = if_link_params_init(ifp);
1149
1150
  /* Compute default bandwidth based on interface */
1151
0
  iflp->default_bw =
1152
0
    ((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH)
1153
0
     * TE_MEGA_BIT / TE_BYTE);
1154
1155
  /* Set Max, Reservable and Unreserved Bandwidth */
1156
0
  iflp->max_bw = iflp->default_bw;
1157
0
  iflp->max_rsv_bw = iflp->default_bw;
1158
0
  for (i = 0; i < MAX_CLASS_TYPE; i++)
1159
0
    iflp->unrsv_bw[i] = iflp->default_bw;
1160
1161
  /* Update Link parameters status */
1162
0
  iflp->lp_status = LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW;
1163
1164
  /* Set TE metric equal to standard metric only if it is set */
1165
0
  if (ifp->metric != 0) {
1166
0
    iflp->te_metric = ifp->metric;
1167
0
    iflp->lp_status |= LP_TE_METRIC;
1168
0
  }
1169
1170
  /* Finally attach newly created Link Parameters */
1171
0
  ifp->link_params = iflp;
1172
1173
0
  return iflp;
1174
0
}
1175
1176
struct if_link_params *if_link_params_init(struct interface *ifp)
1177
0
{
1178
0
  struct if_link_params *iflp = if_link_params_get(ifp);
1179
1180
0
  if (iflp)
1181
0
    return iflp;
1182
1183
0
  iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params));
1184
1185
0
  admin_group_init(&iflp->ext_admin_grp);
1186
1187
0
  ifp->link_params = iflp;
1188
1189
0
  return iflp;
1190
0
}
1191
1192
void if_link_params_free(struct interface *ifp)
1193
0
{
1194
0
  if (!ifp->link_params)
1195
0
    return;
1196
1197
0
  admin_group_term(&ifp->link_params->ext_admin_grp);
1198
0
  XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
1199
0
}
1200
1201
/* ----------- CLI commands ----------- */
1202
1203
/* Guess the VRF of an interface. */
1204
static int vrfname_by_ifname(const char *ifname, const char **vrfname)
1205
0
{
1206
0
  struct vrf *vrf;
1207
0
  struct interface *ifp;
1208
0
  int count = 0;
1209
1210
0
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1211
0
    FOR_ALL_INTERFACES (vrf, ifp) {
1212
0
      if (strmatch(ifp->name, ifname)) {
1213
0
        *vrfname = vrf->name;
1214
0
        count++;
1215
0
      }
1216
0
    }
1217
0
  }
1218
1219
0
  return count;
1220
0
}
1221
1222
/*
1223
 * XPath: /frr-interface:lib/interface
1224
 */
1225
DEFPY_YANG_NOSH (interface,
1226
       interface_cmd,
1227
       "interface IFNAME [vrf NAME$vrf_name]",
1228
       "Select an interface to configure\n"
1229
       "Interface's name\n"
1230
       VRF_CMD_HELP_STR)
1231
0
{
1232
0
  char xpath_list[XPATH_MAXLEN];
1233
0
  struct interface *ifp;
1234
0
  struct vrf *vrf;
1235
0
  int ret, count;
1236
1237
0
  if (vrf_is_backend_netns()) {
1238
    /*
1239
     * For backward compatibility, if the VRF name is not specified
1240
     * and there is exactly one interface with this name in the
1241
     * system, use its VRF. Otherwise fallback to the default VRF.
1242
     */
1243
0
    if (!vrf_name) {
1244
0
      count = vrfname_by_ifname(ifname, &vrf_name);
1245
0
      if (count != 1)
1246
0
        vrf_name = VRF_DEFAULT_NAME;
1247
0
    }
1248
1249
0
    snprintf(xpath_list, XPATH_MAXLEN,
1250
0
       "/frr-interface:lib/interface[name='%s:%s']", vrf_name,
1251
0
       ifname);
1252
0
  } else {
1253
0
    snprintf(xpath_list, XPATH_MAXLEN,
1254
0
       "/frr-interface:lib/interface[name='%s']", ifname);
1255
0
  }
1256
1257
0
  nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
1258
0
  ret = nb_cli_apply_changes_clear_pending(vty, "%s", xpath_list);
1259
0
  if (ret == CMD_SUCCESS) {
1260
0
    VTY_PUSH_XPATH(INTERFACE_NODE, xpath_list);
1261
1262
    /*
1263
     * For backward compatibility with old commands we still need
1264
     * to use the qobj infrastructure. This can be removed once
1265
     * all interface-level commands are converted to the new
1266
     * northbound model.
1267
     */
1268
0
    if (vrf_is_backend_netns()) {
1269
0
      vrf = vrf_lookup_by_name(vrf_name);
1270
0
      if (vrf)
1271
0
        ifp = if_lookup_by_name_vrf(ifname, vrf);
1272
0
      else
1273
0
        ifp = NULL;
1274
0
    } else {
1275
0
      ifp = if_lookup_by_name_all_vrf(ifname);
1276
0
    }
1277
0
    if (ifp)
1278
0
      VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
1279
0
  }
1280
1281
0
  return ret;
1282
0
}
1283
1284
DEFPY_YANG (no_interface,
1285
       no_interface_cmd,
1286
       "no interface IFNAME [vrf NAME$vrf_name]",
1287
       NO_STR
1288
       "Delete a pseudo interface's configuration\n"
1289
       "Interface's name\n"
1290
       VRF_CMD_HELP_STR)
1291
0
{
1292
0
  char xpath_list[XPATH_MAXLEN];
1293
0
  int count;
1294
1295
0
  if (vrf_is_backend_netns()) {
1296
    /*
1297
     * For backward compatibility, if the VRF name is not specified
1298
     * and there is exactly one interface with this name in the
1299
     * system, use its VRF. Otherwise fallback to the default VRF.
1300
     */
1301
0
    if (!vrf_name) {
1302
0
      count = vrfname_by_ifname(ifname, &vrf_name);
1303
0
      if (count != 1)
1304
0
        vrf_name = VRF_DEFAULT_NAME;
1305
0
    }
1306
1307
0
    snprintf(xpath_list, XPATH_MAXLEN,
1308
0
       "/frr-interface:lib/interface[name='%s:%s']", vrf_name,
1309
0
       ifname);
1310
0
  } else {
1311
0
    snprintf(xpath_list, XPATH_MAXLEN,
1312
0
       "/frr-interface:lib/interface[name='%s']", ifname);
1313
0
  }
1314
1315
0
  nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
1316
1317
0
  return nb_cli_apply_changes(vty, "%s", xpath_list);
1318
0
}
1319
1320
static void netns_ifname_split(const char *xpath, char *ifname, char *vrfname)
1321
0
{
1322
0
  char *delim;
1323
0
  int len;
1324
1325
0
  assert(vrf_is_backend_netns());
1326
1327
0
  delim = strchr(xpath, ':');
1328
0
  assert(delim);
1329
1330
0
  len = delim - xpath;
1331
0
  memcpy(vrfname, xpath, len);
1332
0
  vrfname[len] = 0;
1333
1334
0
  strlcpy(ifname, delim + 1, XPATH_MAXLEN);
1335
0
}
1336
1337
static void cli_show_interface(struct vty *vty, const struct lyd_node *dnode,
1338
             bool show_defaults)
1339
0
{
1340
0
  vty_out(vty, "!\n");
1341
1342
0
  if (vrf_is_backend_netns()) {
1343
0
    char ifname[XPATH_MAXLEN];
1344
0
    char vrfname[XPATH_MAXLEN];
1345
1346
0
    netns_ifname_split(yang_dnode_get_string(dnode, "./name"),
1347
0
           ifname, vrfname);
1348
1349
0
    vty_out(vty, "interface %s", ifname);
1350
0
    if (!strmatch(vrfname, VRF_DEFAULT_NAME))
1351
0
      vty_out(vty, " vrf %s", vrfname);
1352
0
  } else {
1353
0
    const char *ifname = yang_dnode_get_string(dnode, "./name");
1354
1355
0
    vty_out(vty, "interface %s", ifname);
1356
0
  }
1357
1358
0
  vty_out(vty, "\n");
1359
0
}
1360
1361
static void cli_show_interface_end(struct vty *vty,
1362
           const struct lyd_node *dnode)
1363
0
{
1364
0
  vty_out(vty, "exit\n");
1365
0
}
1366
1367
void if_vty_config_start(struct vty *vty, struct interface *ifp)
1368
0
{
1369
0
  vty_frame(vty, "!\n");
1370
0
  vty_frame(vty, "interface %s", ifp->name);
1371
1372
0
  if (vrf_is_backend_netns() && strcmp(ifp->vrf->name, VRF_DEFAULT_NAME))
1373
0
    vty_frame(vty, " vrf %s", ifp->vrf->name);
1374
1375
0
  vty_frame(vty, "\n");
1376
0
}
1377
1378
void if_vty_config_end(struct vty *vty)
1379
0
{
1380
0
  vty_endframe(vty, "exit\n!\n");
1381
0
}
1382
1383
/*
1384
 * XPath: /frr-interface:lib/interface/description
1385
 */
1386
DEFPY_YANG (interface_desc,
1387
       interface_desc_cmd,
1388
       "description LINE...",
1389
       "Interface specific description\n"
1390
       "Characters describing this interface\n")
1391
0
{
1392
0
  char *desc;
1393
0
  int ret;
1394
1395
0
  desc = argv_concat(argv, argc, 1);
1396
0
  nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
1397
0
  ret = nb_cli_apply_changes(vty, NULL);
1398
0
  XFREE(MTYPE_TMP, desc);
1399
1400
0
  return ret;
1401
0
}
1402
1403
DEFPY_YANG  (no_interface_desc,
1404
  no_interface_desc_cmd,
1405
  "no description",
1406
  NO_STR
1407
  "Interface specific description\n")
1408
0
{
1409
0
  nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
1410
1411
0
  return nb_cli_apply_changes(vty, NULL);
1412
0
}
1413
1414
static void cli_show_interface_desc(struct vty *vty,
1415
            const struct lyd_node *dnode,
1416
            bool show_defaults)
1417
0
{
1418
0
  vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
1419
0
}
1420
1421
/* Interface autocomplete. */
1422
static void if_autocomplete(vector comps, struct cmd_token *token)
1423
0
{
1424
0
  struct interface *ifp;
1425
0
  struct vrf *vrf;
1426
1427
0
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1428
0
    FOR_ALL_INTERFACES (vrf, ifp) {
1429
0
      vector_set(comps, XSTRDUP(MTYPE_COMPLETION, ifp->name));
1430
0
    }
1431
0
  }
1432
0
}
1433
1434
static const struct cmd_variable_handler if_var_handlers[] = {
1435
  {/* "interface NAME" */
1436
   .varname = "interface",
1437
   .completions = if_autocomplete},
1438
  {.tokenname = "IFNAME", .completions = if_autocomplete},
1439
  {.tokenname = "INTERFACE", .completions = if_autocomplete},
1440
  {.completions = NULL}};
1441
1442
static struct cmd_node interface_node = {
1443
  .name = "interface",
1444
  .node = INTERFACE_NODE,
1445
  .parent_node = CONFIG_NODE,
1446
  .prompt = "%s(config-if)# ",
1447
};
1448
1449
static int if_config_write_single(const struct lyd_node *dnode, void *arg)
1450
0
{
1451
0
  nb_cli_show_dnode_cmds(arg, dnode, false);
1452
1453
0
  return YANG_ITER_CONTINUE;
1454
0
}
1455
1456
static int if_nb_config_write(struct vty *vty)
1457
0
{
1458
0
  yang_dnode_iterate(if_config_write_single, vty, running_config->dnode,
1459
0
         "/frr-interface:lib/interface");
1460
0
  return 1;
1461
0
}
1462
1463
void if_cmd_init(int (*config_write)(struct vty *))
1464
1
{
1465
1
  cmd_variable_handler_register(if_var_handlers);
1466
1467
1
  interface_node.config_write = config_write;
1468
1
  install_node(&interface_node);
1469
1470
1
  install_element(CONFIG_NODE, &interface_cmd);
1471
1
  install_element(CONFIG_NODE, &no_interface_cmd);
1472
1473
1
  install_default(INTERFACE_NODE);
1474
1
  install_element(INTERFACE_NODE, &interface_desc_cmd);
1475
1
  install_element(INTERFACE_NODE, &no_interface_desc_cmd);
1476
1
}
1477
1478
void if_cmd_init_default(void)
1479
0
{
1480
0
  if_cmd_init(if_nb_config_write);
1481
0
}
1482
1483
void if_zapi_callbacks(int (*create)(struct interface *ifp),
1484
           int (*up)(struct interface *ifp),
1485
           int (*down)(struct interface *ifp),
1486
           int (*destroy)(struct interface *ifp))
1487
2
{
1488
2
  ifp_master.create_hook = create;
1489
2
  ifp_master.up_hook = up;
1490
2
  ifp_master.down_hook = down;
1491
2
  ifp_master.destroy_hook = destroy;
1492
2
}
1493
1494
/* ------- Northbound callbacks ------- */
1495
1496
/*
1497
 * XPath: /frr-interface:lib/interface
1498
 */
1499
static int lib_interface_create(struct nb_cb_create_args *args)
1500
0
{
1501
0
  const char *ifname;
1502
0
  struct interface *ifp;
1503
1504
0
  ifname = yang_dnode_get_string(args->dnode, "./name");
1505
1506
0
  switch (args->event) {
1507
0
  case NB_EV_VALIDATE:
1508
0
    if (vrf_is_backend_netns()) {
1509
0
      char ifname_ns[XPATH_MAXLEN];
1510
0
      char vrfname_ns[XPATH_MAXLEN];
1511
1512
0
      netns_ifname_split(ifname, ifname_ns, vrfname_ns);
1513
1514
0
      if (strlen(ifname_ns) > 16) {
1515
0
        snprintf(
1516
0
          args->errmsg, args->errmsg_len,
1517
0
          "Maximum interface name length is 16 characters");
1518
0
        return NB_ERR_VALIDATION;
1519
0
      }
1520
0
      if (strlen(vrfname_ns) > 36) {
1521
0
        snprintf(
1522
0
          args->errmsg, args->errmsg_len,
1523
0
          "Maximum VRF name length is 36 characters");
1524
0
        return NB_ERR_VALIDATION;
1525
0
      }
1526
0
    } else {
1527
0
      if (strlen(ifname) > 16) {
1528
0
        snprintf(
1529
0
          args->errmsg, args->errmsg_len,
1530
0
          "Maximum interface name length is 16 characters");
1531
0
        return NB_ERR_VALIDATION;
1532
0
      }
1533
0
    }
1534
0
    break;
1535
0
  case NB_EV_PREPARE:
1536
0
  case NB_EV_ABORT:
1537
0
    break;
1538
0
  case NB_EV_APPLY:
1539
0
    if (vrf_is_backend_netns()) {
1540
0
      char ifname_ns[XPATH_MAXLEN];
1541
0
      char vrfname_ns[XPATH_MAXLEN];
1542
1543
0
      netns_ifname_split(ifname, ifname_ns, vrfname_ns);
1544
1545
0
      ifp = if_get_by_name(ifname_ns, VRF_UNKNOWN,
1546
0
               vrfname_ns);
1547
0
    } else {
1548
0
      ifp = if_get_by_name(ifname, VRF_UNKNOWN,
1549
0
               VRF_DEFAULT_NAME);
1550
0
    }
1551
1552
0
    ifp->configured = true;
1553
0
    nb_running_set_entry(args->dnode, ifp);
1554
0
    break;
1555
0
  }
1556
1557
0
  return NB_OK;
1558
0
}
1559
1560
static int lib_interface_destroy(struct nb_cb_destroy_args *args)
1561
0
{
1562
0
  struct interface *ifp;
1563
0
  struct vrf *vrf;
1564
1565
0
  switch (args->event) {
1566
0
  case NB_EV_VALIDATE:
1567
0
    ifp = nb_running_get_entry(args->dnode, NULL, true);
1568
0
    if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
1569
0
      snprintf(args->errmsg, args->errmsg_len,
1570
0
         "only inactive interfaces can be deleted");
1571
0
      return NB_ERR_VALIDATION;
1572
0
    }
1573
0
    break;
1574
0
  case NB_EV_PREPARE:
1575
0
  case NB_EV_ABORT:
1576
0
    break;
1577
0
  case NB_EV_APPLY:
1578
0
    ifp = nb_running_unset_entry(args->dnode);
1579
0
    vrf = ifp->vrf;
1580
1581
0
    ifp->configured = false;
1582
0
    if_delete(&ifp);
1583
1584
0
    if (!vrf_is_enabled(vrf))
1585
0
      vrf_delete(vrf);
1586
0
    break;
1587
0
  }
1588
1589
0
  return NB_OK;
1590
0
}
1591
1592
/*
1593
 * XPath: /frr-interface:lib/interface
1594
 */
1595
static const void *lib_interface_get_next(struct nb_cb_get_next_args *args)
1596
0
{
1597
0
  struct vrf *vrf;
1598
0
  struct interface *pif = (struct interface *)args->list_entry;
1599
1600
0
  if (args->list_entry == NULL) {
1601
0
    vrf = RB_MIN(vrf_name_head, &vrfs_by_name);
1602
0
    assert(vrf);
1603
0
    pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
1604
0
  } else {
1605
0
    vrf = pif->vrf;
1606
0
    pif = RB_NEXT(if_name_head, pif);
1607
    /* if no more interfaces, switch to next vrf */
1608
0
    while (pif == NULL) {
1609
0
      vrf = RB_NEXT(vrf_name_head, vrf);
1610
0
      if (!vrf)
1611
0
        return NULL;
1612
0
      pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
1613
0
    }
1614
0
  }
1615
1616
0
  return pif;
1617
0
}
1618
1619
static int lib_interface_get_keys(struct nb_cb_get_keys_args *args)
1620
0
{
1621
0
  const struct interface *ifp = args->list_entry;
1622
1623
0
  args->keys->num = 1;
1624
1625
0
  if (vrf_is_backend_netns())
1626
0
    snprintf(args->keys->key[0], sizeof(args->keys->key[0]),
1627
0
       "%s:%s", ifp->vrf->name, ifp->name);
1628
0
  else
1629
0
    snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s",
1630
0
       ifp->name);
1631
1632
0
  return NB_OK;
1633
0
}
1634
1635
static const void *
1636
lib_interface_lookup_entry(struct nb_cb_lookup_entry_args *args)
1637
0
{
1638
0
  if (vrf_is_backend_netns()) {
1639
0
    char ifname[XPATH_MAXLEN];
1640
0
    char vrfname[XPATH_MAXLEN];
1641
0
    struct vrf *vrf;
1642
1643
0
    netns_ifname_split(args->keys->key[0], ifname, vrfname);
1644
1645
0
    vrf = vrf_lookup_by_name(vrfname);
1646
1647
0
    return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL;
1648
0
  } else {
1649
0
    return if_lookup_by_name_all_vrf(args->keys->key[0]);
1650
0
  }
1651
0
}
1652
1653
/*
1654
 * XPath: /frr-interface:lib/interface/description
1655
 */
1656
static int lib_interface_description_modify(struct nb_cb_modify_args *args)
1657
0
{
1658
0
  struct interface *ifp;
1659
0
  const char *description;
1660
1661
0
  if (args->event != NB_EV_APPLY)
1662
0
    return NB_OK;
1663
1664
0
  ifp = nb_running_get_entry(args->dnode, NULL, true);
1665
0
  XFREE(MTYPE_IFDESC, ifp->desc);
1666
0
  description = yang_dnode_get_string(args->dnode, NULL);
1667
0
  ifp->desc = XSTRDUP(MTYPE_IFDESC, description);
1668
1669
0
  return NB_OK;
1670
0
}
1671
1672
static int lib_interface_description_destroy(struct nb_cb_destroy_args *args)
1673
0
{
1674
0
  struct interface *ifp;
1675
1676
0
  if (args->event != NB_EV_APPLY)
1677
0
    return NB_OK;
1678
1679
0
  ifp = nb_running_get_entry(args->dnode, NULL, true);
1680
0
  XFREE(MTYPE_IFDESC, ifp->desc);
1681
1682
0
  return NB_OK;
1683
0
}
1684
1685
/*
1686
 * XPath: /frr-interface:lib/interface/vrf
1687
 */
1688
static struct yang_data *
1689
lib_interface_vrf_get_elem(struct nb_cb_get_elem_args *args)
1690
0
{
1691
0
  const struct interface *ifp = args->list_entry;
1692
1693
0
  return yang_data_new_string(args->xpath, ifp->vrf->name);
1694
0
}
1695
1696
/*
1697
 * XPath: /frr-interface:lib/interface/state/if-index
1698
 */
1699
static struct yang_data *
1700
lib_interface_state_if_index_get_elem(struct nb_cb_get_elem_args *args)
1701
0
{
1702
0
  const struct interface *ifp = args->list_entry;
1703
1704
0
  return yang_data_new_int32(args->xpath, ifp->ifindex);
1705
0
}
1706
1707
/*
1708
 * XPath: /frr-interface:lib/interface/state/mtu
1709
 */
1710
static struct yang_data *
1711
lib_interface_state_mtu_get_elem(struct nb_cb_get_elem_args *args)
1712
0
{
1713
0
  const struct interface *ifp = args->list_entry;
1714
1715
0
  return yang_data_new_uint16(args->xpath, ifp->mtu);
1716
0
}
1717
1718
/*
1719
 * XPath: /frr-interface:lib/interface/state/mtu6
1720
 */
1721
static struct yang_data *
1722
lib_interface_state_mtu6_get_elem(struct nb_cb_get_elem_args *args)
1723
0
{
1724
0
  const struct interface *ifp = args->list_entry;
1725
1726
0
  return yang_data_new_uint32(args->xpath, ifp->mtu6);
1727
0
}
1728
1729
/*
1730
 * XPath: /frr-interface:lib/interface/state/speed
1731
 */
1732
static struct yang_data *
1733
lib_interface_state_speed_get_elem(struct nb_cb_get_elem_args *args)
1734
0
{
1735
0
  const struct interface *ifp = args->list_entry;
1736
1737
0
  return yang_data_new_uint32(args->xpath, ifp->speed);
1738
0
}
1739
1740
/*
1741
 * XPath: /frr-interface:lib/interface/state/metric
1742
 */
1743
static struct yang_data *
1744
lib_interface_state_metric_get_elem(struct nb_cb_get_elem_args *args)
1745
0
{
1746
0
  const struct interface *ifp = args->list_entry;
1747
1748
0
  return yang_data_new_uint32(args->xpath, ifp->metric);
1749
0
}
1750
1751
/*
1752
 * XPath: /frr-interface:lib/interface/state/flags
1753
 */
1754
static struct yang_data *
1755
lib_interface_state_flags_get_elem(struct nb_cb_get_elem_args *args)
1756
0
{
1757
  /* TODO: implement me. */
1758
0
  return NULL;
1759
0
}
1760
1761
/*
1762
 * XPath: /frr-interface:lib/interface/state/type
1763
 */
1764
static struct yang_data *
1765
lib_interface_state_type_get_elem(struct nb_cb_get_elem_args *args)
1766
0
{
1767
  /* TODO: implement me. */
1768
0
  return NULL;
1769
0
}
1770
1771
/*
1772
 * XPath: /frr-interface:lib/interface/state/phy-address
1773
 */
1774
static struct yang_data *
1775
lib_interface_state_phy_address_get_elem(struct nb_cb_get_elem_args *args)
1776
0
{
1777
0
  const struct interface *ifp = args->list_entry;
1778
0
  struct ethaddr macaddr;
1779
1780
0
  memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
1781
1782
0
  return yang_data_new_mac(args->xpath, &macaddr);
1783
0
}
1784
1785
/* clang-format off */
1786
const struct frr_yang_module_info frr_interface_info = {
1787
  .name = "frr-interface",
1788
  .nodes = {
1789
    {
1790
      .xpath = "/frr-interface:lib/interface",
1791
      .cbs = {
1792
        .create = lib_interface_create,
1793
        .destroy = lib_interface_destroy,
1794
        .cli_show = cli_show_interface,
1795
        .cli_show_end = cli_show_interface_end,
1796
        .get_next = lib_interface_get_next,
1797
        .get_keys = lib_interface_get_keys,
1798
        .lookup_entry = lib_interface_lookup_entry,
1799
      },
1800
    },
1801
    {
1802
      .xpath = "/frr-interface:lib/interface/description",
1803
      .cbs = {
1804
        .modify = lib_interface_description_modify,
1805
        .destroy = lib_interface_description_destroy,
1806
        .cli_show = cli_show_interface_desc,
1807
      },
1808
    },
1809
    {
1810
      .xpath = "/frr-interface:lib/interface/vrf",
1811
      .cbs = {
1812
        .get_elem = lib_interface_vrf_get_elem,
1813
      }
1814
    },
1815
    {
1816
      .xpath = "/frr-interface:lib/interface/state/if-index",
1817
      .cbs = {
1818
        .get_elem = lib_interface_state_if_index_get_elem,
1819
      }
1820
    },
1821
    {
1822
      .xpath = "/frr-interface:lib/interface/state/mtu",
1823
      .cbs = {
1824
        .get_elem = lib_interface_state_mtu_get_elem,
1825
      }
1826
    },
1827
    {
1828
      .xpath = "/frr-interface:lib/interface/state/mtu6",
1829
      .cbs = {
1830
        .get_elem = lib_interface_state_mtu6_get_elem,
1831
      }
1832
    },
1833
    {
1834
      .xpath = "/frr-interface:lib/interface/state/speed",
1835
      .cbs = {
1836
        .get_elem = lib_interface_state_speed_get_elem,
1837
      }
1838
    },
1839
    {
1840
      .xpath = "/frr-interface:lib/interface/state/metric",
1841
      .cbs = {
1842
        .get_elem = lib_interface_state_metric_get_elem,
1843
      }
1844
    },
1845
    {
1846
      .xpath = "/frr-interface:lib/interface/state/flags",
1847
      .cbs = {
1848
        .get_elem = lib_interface_state_flags_get_elem,
1849
      }
1850
    },
1851
    {
1852
      .xpath = "/frr-interface:lib/interface/state/type",
1853
      .cbs = {
1854
        .get_elem = lib_interface_state_type_get_elem,
1855
      }
1856
    },
1857
    {
1858
      .xpath = "/frr-interface:lib/interface/state/phy-address",
1859
      .cbs = {
1860
        .get_elem = lib_interface_state_phy_address_get_elem,
1861
      }
1862
    },
1863
    {
1864
      .xpath = NULL,
1865
    },
1866
  }
1867
};