Coverage Report

Created: 2025-10-23 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/bgp_attr_evpn.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Ethernet-VPN Attribute handling file
3
 * Copyright (C) 2016 6WIND
4
 */
5
6
#include <zebra.h>
7
8
#include "command.h"
9
#include "filter.h"
10
#include "prefix.h"
11
#include "log.h"
12
#include "memory.h"
13
#include "stream.h"
14
#include "vxlan.h"
15
16
#include "bgpd/bgpd.h"
17
#include "bgpd/bgp_attr.h"
18
#include "bgpd/bgp_route.h"
19
#include "bgpd/bgp_attr_evpn.h"
20
#include "bgpd/bgp_ecommunity.h"
21
#include "bgpd/bgp_evpn.h"
22
#include "bgpd/bgp_evpn_private.h"
23
24
bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
25
       const struct bgp_route_evpn *e2)
26
0
{
27
0
  return (e1->type == e2->type &&
28
0
    !memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
29
0
    !ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip)));
30
0
}
31
32
void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
33
0
{
34
0
  struct ecommunity_val routermac_ecom;
35
0
  struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
36
37
0
  memset(&routermac_ecom, 0, sizeof(routermac_ecom));
38
0
  routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
39
0
  routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
40
0
  memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
41
0
  if (!ecomm) {
42
0
    bgp_attr_set_ecommunity(attr, ecommunity_new());
43
0
    ecomm = bgp_attr_get_ecommunity(attr);
44
0
  }
45
0
  ecommunity_add_val(ecomm, &routermac_ecom, false, false);
46
0
  ecommunity_str(ecomm);
47
0
}
48
49
/* converts to an esi
50
 * returns 1 on success, 0 otherwise
51
 * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
52
 * if id is null, check only is done
53
 */
54
bool str2esi(const char *str, esi_t *id)
55
0
{
56
0
  unsigned int a[ESI_BYTES];
57
0
  int i;
58
59
0
  if (!str)
60
0
    return false;
61
0
  if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
62
0
       a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
63
0
      != ESI_BYTES) {
64
    /* error in incoming str length */
65
0
    return false;
66
0
  }
67
  /* valid mac address */
68
0
  if (!id)
69
0
    return true;
70
0
  for (i = 0; i < ESI_BYTES; ++i)
71
0
    id->val[i] = a[i] & 0xff;
72
0
  return true;
73
0
}
74
75
char *ecom_mac2str(char *ecom_mac)
76
0
{
77
0
  char *en;
78
79
0
  en = ecom_mac;
80
0
  en += 2;
81
82
0
  return prefix_mac2str((struct ethaddr *)en, NULL, 0);
83
0
}
84
85
/* Fetch router-mac from extended community */
86
bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
87
99
{
88
99
  uint32_t i = 0;
89
99
  struct ecommunity *ecom;
90
91
99
  ecom = bgp_attr_get_ecommunity(attr);
92
99
  if (!ecom || !ecom->size)
93
0
    return false;
94
95
  /* If there is a router mac extended community, set RMAC in attr */
96
10.5k
  for (i = 0; i < ecom->size; i++) {
97
10.4k
    uint8_t *pnt = NULL;
98
10.4k
    uint8_t type = 0;
99
10.4k
    uint8_t sub_type = 0;
100
101
10.4k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
102
10.4k
    type = *pnt++;
103
10.4k
    sub_type = *pnt++;
104
105
10.4k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
106
662
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
107
10.4k
      continue;
108
109
2
    memcpy(rmac, pnt, ETH_ALEN);
110
2
    return true;
111
10.4k
  }
112
97
  return false;
113
99
}
114
115
/*
116
 * return true if attr contains default gw extended community
117
 */
118
uint8_t bgp_attr_default_gw(struct attr *attr)
119
99
{
120
99
  struct ecommunity *ecom;
121
99
  uint32_t i;
122
123
99
  ecom = bgp_attr_get_ecommunity(attr);
124
99
  if (!ecom || !ecom->size)
125
0
    return 0;
126
127
  /* If there is a default gw extendd community return true otherwise
128
   * return 0 */
129
10.6k
  for (i = 0; i < ecom->size; i++) {
130
10.5k
    uint8_t *pnt;
131
10.5k
    uint8_t type, sub_type;
132
133
10.5k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
134
10.5k
    type = *pnt++;
135
10.5k
    sub_type = *pnt++;
136
137
10.5k
    if ((type == ECOMMUNITY_ENCODE_OPAQUE
138
239
         && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
139
2
      return 1;
140
10.5k
  }
141
142
97
  return 0;
143
99
}
144
145
/*
146
 * Fetch and return the DF preference and algorithm from
147
 * DF election extended community, if present, else 0.
148
 */
149
uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
150
99
{
151
99
  struct ecommunity *ecom;
152
99
  uint32_t i;
153
99
  uint16_t df_pref = 0;
154
155
99
  *alg = EVPN_MH_DF_ALG_SERVICE_CARVING;
156
99
  ecom = bgp_attr_get_ecommunity(attr);
157
99
  if (!ecom || !ecom->size)
158
0
    return 0;
159
160
7.38k
  for (i = 0; i < ecom->size; i++) {
161
7.32k
    uint8_t *pnt;
162
7.32k
    uint8_t type, sub_type;
163
164
7.32k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
165
7.32k
    type = *pnt++;
166
7.32k
    sub_type = *pnt++;
167
7.32k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
168
252
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION))
169
7.28k
      continue;
170
171
38
    *alg = (*pnt++) & ECOMMUNITY_EVPN_SUBTYPE_DF_ALG_BITS;
172
173
38
    pnt += 3;
174
38
    pnt = ptr_get_be16(pnt, &df_pref);
175
38
    (void)pnt; /* consume value */
176
38
    break;
177
7.32k
  }
178
179
99
  return df_pref;
180
99
}
181
182
/*
183
 * Fetch and return the sequence number from MAC Mobility extended
184
 * community, if present, else 0.
185
 */
186
uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
187
99
{
188
99
  struct ecommunity *ecom;
189
99
  uint32_t i;
190
99
  uint8_t flags = 0;
191
192
99
  ecom = bgp_attr_get_ecommunity(attr);
193
99
  if (!ecom || !ecom->size)
194
0
    return 0;
195
196
  /* If there is a MAC Mobility extended community, return its
197
   * sequence number.
198
   * TODO: RFC is silent on handling of multiple MAC mobility extended
199
   * communities for the same route. We will bail out upon the first
200
   * one.
201
   */
202
8.70k
  for (i = 0; i < ecom->size; i++) {
203
8.62k
    const uint8_t *pnt;
204
8.62k
    uint8_t type, sub_type;
205
8.62k
    uint32_t seq_num;
206
207
8.62k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
208
8.62k
    type = *pnt++;
209
8.62k
    sub_type = *pnt++;
210
8.62k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
211
298
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
212
8.60k
      continue;
213
22
    flags = *pnt++;
214
215
22
    if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
216
5
      *sticky = 1;
217
17
    else
218
17
      *sticky = 0;
219
220
22
    pnt++;
221
22
    pnt = ptr_get_be32(pnt, &seq_num);
222
22
    (void)pnt; /* consume value */
223
22
    return seq_num;
224
8.62k
  }
225
226
77
  return 0;
227
99
}
228
229
/*
230
 * return true if attr contains router flag extended community
231
 */
232
void bgp_attr_evpn_na_flag(struct attr *attr,
233
    uint8_t *router_flag, bool *proxy)
234
99
{
235
99
  struct ecommunity *ecom;
236
99
  uint32_t i;
237
99
  uint8_t val;
238
239
99
  ecom = bgp_attr_get_ecommunity(attr);
240
99
  if (!ecom || !ecom->size)
241
0
    return;
242
243
  /* If there is a evpn na extendd community set router_flag */
244
9.61k
  for (i = 0; i < ecom->size; i++) {
245
9.52k
    uint8_t *pnt;
246
9.52k
    uint8_t type, sub_type;
247
248
9.52k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
249
9.52k
    type = *pnt++;
250
9.52k
    sub_type = *pnt++;
251
252
9.52k
    if (type == ECOMMUNITY_ENCODE_EVPN &&
253
512
        sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
254
12
      val = *pnt++;
255
256
12
      if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
257
3
        *router_flag = 1;
258
259
12
      if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
260
2
        *proxy = true;
261
262
12
      break;
263
12
    }
264
9.52k
  }
265
99
}
266
267
/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
268
extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
269
         struct prefix *dst)
270
0
{
271
0
  struct evpn_addr *p_evpn_p;
272
0
  struct prefix p2;
273
0
  struct prefix *src = &p2;
274
275
0
  if (!dst || dst->family == 0)
276
0
    return -1;
277
  /* store initial prefix in src */
278
0
  prefix_copy(src, dst);
279
0
  memset(dst, 0, sizeof(struct prefix));
280
0
  p_evpn_p = &(dst->u.prefix_evpn);
281
0
  dst->family = AF_EVPN;
282
0
  p_evpn_p->route_type = evpn_type;
283
0
  if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
284
0
    p_evpn_p->prefix_addr.eth_tag = eth_tag;
285
0
    p_evpn_p->prefix_addr.ip_prefix_length = p2.prefixlen;
286
0
    if (src->family == AF_INET) {
287
0
      SET_IPADDR_V4(&p_evpn_p->prefix_addr.ip);
288
0
      memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v4,
289
0
             &src->u.prefix4,
290
0
             sizeof(struct in_addr));
291
0
      dst->prefixlen = (uint16_t)PREFIX_LEN_ROUTE_TYPE_5_IPV4;
292
0
    } else {
293
0
      SET_IPADDR_V6(&p_evpn_p->prefix_addr.ip);
294
0
      memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v6,
295
0
             &src->u.prefix6,
296
0
             sizeof(struct in6_addr));
297
0
      dst->prefixlen = (uint16_t)PREFIX_LEN_ROUTE_TYPE_5_IPV6;
298
0
    }
299
0
  } else
300
0
    return -1;
301
0
  return 0;
302
0
}