Coverage Report

Created: 2025-08-26 06:20

/src/frr/bgpd/bgp_rd.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* BGP RD definitions for BGP-based VPNs (IP/EVPN)
3
 * -- brought over from bgpd/bgp_mplsvpn.c
4
 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
5
 */
6
7
#include <zebra.h>
8
#include "command.h"
9
#include "log.h"
10
#include "prefix.h"
11
#include "memory.h"
12
#include "stream.h"
13
#include "filter.h"
14
#include "frrstr.h"
15
16
#include "lib/printfrr.h"
17
18
#include "bgpd/bgpd.h"
19
#include "bgpd/bgp_rd.h"
20
#include "bgpd/bgp_attr.h"
21
22
#ifdef ENABLE_BGP_VNC
23
#include "bgpd/rfapi/rfapi_backend.h"
24
#endif
25
26
uint16_t decode_rd_type(const uint8_t *pnt)
27
176
{
28
176
  uint16_t v;
29
30
176
  v = ((uint16_t)*pnt++ << 8);
31
176
#ifdef ENABLE_BGP_VNC
32
  /*
33
   * VNC L2 stores LHI in lower byte, so omit it
34
   */
35
176
  if (v != RD_TYPE_VNC_ETH)
36
145
    v |= (uint16_t)*pnt;
37
#else /* duplicate code for clarity */
38
  v |= (uint16_t)*pnt;
39
#endif
40
176
  return v;
41
176
}
42
43
void encode_rd_type(uint16_t v, uint8_t *pnt)
44
0
{
45
0
  *((uint16_t *)pnt) = htons(v);
46
0
}
47
48
/* type == RD_TYPE_AS */
49
void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as)
50
15
{
51
15
  rd_as->as = (uint16_t)*pnt++ << 8;
52
15
  rd_as->as |= (uint16_t)*pnt++;
53
15
  ptr_get_be32(pnt, &rd_as->val);
54
15
}
55
56
/* type == RD_TYPE_AS4 */
57
void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as)
58
65
{
59
65
  pnt = ptr_get_be32(pnt, &rd_as->as);
60
65
  rd_as->val = ((uint16_t)*pnt++ << 8);
61
65
  rd_as->val |= (uint16_t)*pnt;
62
65
}
63
64
/* type == RD_TYPE_IP */
65
void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip)
66
6
{
67
6
  memcpy(&rd_ip->ip, pnt, 4);
68
6
  pnt += 4;
69
70
6
  rd_ip->val = ((uint16_t)*pnt++ << 8);
71
6
  rd_ip->val |= (uint16_t)*pnt;
72
6
}
73
74
#ifdef ENABLE_BGP_VNC
75
/* type == RD_TYPE_VNC_ETH */
76
void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth)
77
0
{
78
0
  rd_vnc_eth->type = RD_TYPE_VNC_ETH;
79
0
  rd_vnc_eth->local_nve_id = pnt[1];
80
0
  memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETH_ALEN);
81
0
}
82
#endif
83
84
int str2prefix_rd(const char *str, struct prefix_rd *prd)
85
0
{
86
0
  int ret = 0, type = RD_TYPE_UNDEFINED;
87
0
  char *p, *p2;
88
0
  struct stream *s = NULL;
89
0
  char *half = NULL;
90
0
  struct in_addr addr;
91
0
  as_t as_val;
92
93
0
  prd->family = AF_UNSPEC;
94
0
  prd->prefixlen = 64;
95
96
0
  p = strchr(str, ':');
97
0
  if (!p)
98
0
    goto out;
99
100
  /* a second ':' is accepted */
101
0
  p2 = strchr(p + 1, ':');
102
0
  if (p2) {
103
    /* type is in first part */
104
0
    half = XMALLOC(MTYPE_TMP, (p - str) + 1);
105
0
    memcpy(half, str, (p - str));
106
0
    half[p - str] = '\0';
107
0
    type = atoi(half);
108
0
    if (type != RD_TYPE_AS && type != RD_TYPE_IP &&
109
0
        type != RD_TYPE_AS4)
110
0
      goto out;
111
0
    XFREE(MTYPE_TMP, half);
112
0
    half = XMALLOC(MTYPE_TMP, (p2 - p));
113
0
    memcpy(half, p + 1, (p2 - p - 1));
114
0
    half[p2 - p - 1] = '\0';
115
0
    p = p2 + 1;
116
0
  } else {
117
0
    half = XMALLOC(MTYPE_TMP, (p - str) + 1);
118
0
    memcpy(half, str, (p - str));
119
0
    half[p - str] = '\0';
120
0
  }
121
0
  if (!all_digit(p + 1))
122
0
    goto out;
123
124
0
  s = stream_new(RD_BYTES);
125
126
  /* if it is an AS format or an IP */
127
0
  if (asn_str2asn(half, &as_val)) {
128
0
    if (as_val > UINT16_MAX) {
129
0
      stream_putw(s, RD_TYPE_AS4);
130
0
      stream_putl(s, as_val);
131
0
      stream_putw(s, atol(p + 1));
132
0
      if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS4)
133
0
        goto out;
134
0
    } else {
135
0
      stream_putw(s, RD_TYPE_AS);
136
0
      stream_putw(s, as_val);
137
0
      stream_putl(s, atol(p + 1));
138
0
      if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS)
139
0
        goto out;
140
0
    }
141
0
  } else if (inet_aton(half, &addr)) {
142
0
    stream_putw(s, RD_TYPE_IP);
143
0
    stream_put_in_addr(s, &addr);
144
0
    stream_putw(s, atol(p + 1));
145
0
    if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_IP)
146
0
      goto out;
147
0
  } else
148
0
    goto out;
149
0
  memcpy(prd->val, s->data, 8);
150
0
  ret = 1;
151
152
0
out:
153
0
  if (s)
154
0
    stream_free(s);
155
0
  XFREE(MTYPE_TMP, half);
156
0
  return ret;
157
0
}
158
159
char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size,
160
        enum asnotation_mode asnotation)
161
0
{
162
0
  const uint8_t *pnt;
163
0
  uint16_t type;
164
0
  struct rd_as rd_as;
165
0
  struct rd_ip rd_ip;
166
0
  int len = 0;
167
168
0
  assert(size >= RD_ADDRSTRLEN);
169
170
0
  pnt = prd->val;
171
172
0
  type = decode_rd_type(pnt);
173
174
0
  if (type == RD_TYPE_AS) {
175
0
    decode_rd_as(pnt + 2, &rd_as);
176
0
    len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
177
0
          &rd_as.as);
178
0
    snprintfrr(buf + len, size - len, ":%u", rd_as.val);
179
0
    return buf;
180
0
  } else if (type == RD_TYPE_AS4) {
181
0
    decode_rd_as4(pnt + 2, &rd_as);
182
0
    len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
183
0
          &rd_as.as);
184
0
    snprintfrr(buf + len, size - len, ":%u", rd_as.val);
185
0
    return buf;
186
0
  } else if (type == RD_TYPE_IP) {
187
0
    decode_rd_ip(pnt + 2, &rd_ip);
188
0
    snprintfrr(buf, size, "%pI4:%hu", &rd_ip.ip, rd_ip.val);
189
0
    return buf;
190
0
  }
191
0
#ifdef ENABLE_BGP_VNC
192
0
  else if (type == RD_TYPE_VNC_ETH) {
193
0
    snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x",
194
0
       *(pnt + 1), /* LHI */
195
0
       *(pnt + 2), /* MAC[0] */
196
0
       *(pnt + 3), *(pnt + 4), *(pnt + 5), *(pnt + 6),
197
0
       *(pnt + 7));
198
199
0
    return buf;
200
0
  }
201
0
#endif
202
203
0
  snprintf(buf, size, "Unknown Type: %d", type);
204
0
  return buf;
205
0
}
206
207
void form_auto_rd(struct in_addr router_id,
208
      uint16_t rd_id,
209
      struct prefix_rd *prd)
210
0
{
211
0
  char buf[100];
212
213
0
  prd->family = AF_UNSPEC;
214
0
  prd->prefixlen = 64;
215
0
  snprintfrr(buf, sizeof(buf), "%pI4:%hu", &router_id, rd_id);
216
0
  (void)str2prefix_rd(buf, prd);
217
0
}
218
219
static ssize_t printfrr_prd_asnotation(struct fbuf *buf,
220
               struct printfrr_eargs *ea,
221
               const void *ptr,
222
               enum asnotation_mode asnotation)
223
0
{
224
0
  char rd_buf[RD_ADDRSTRLEN];
225
226
0
  if (!ptr)
227
0
    return bputs(buf, "(null)");
228
229
0
  prefix_rd2str(ptr, rd_buf, sizeof(rd_buf), asnotation);
230
231
0
  return bputs(buf, rd_buf);
232
0
}
233
234
printfrr_ext_autoreg_p("RDP", printfrr_prd);
235
static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
236
          const void *ptr)
237
0
{
238
0
  return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
239
0
}
240
241
printfrr_ext_autoreg_p("RDD", printfrr_prd_dot);
242
static ssize_t printfrr_prd_dot(struct fbuf *buf, struct printfrr_eargs *ea,
243
        const void *ptr)
244
0
{
245
0
  return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOT);
246
0
}
247
248
printfrr_ext_autoreg_p("RDE", printfrr_prd_dotplus);
249
static ssize_t printfrr_prd_dotplus(struct fbuf *buf, struct printfrr_eargs *ea,
250
            const void *ptr)
251
0
{
252
0
  return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
253
0
}