Coverage Report

Created: 2025-08-26 06:20

/src/frr/bgpd/bgp_attr_evpn.c
Line
Count
Source (jump to first uncovered line)
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
107
{
88
107
  uint32_t i = 0;
89
107
  struct ecommunity *ecom;
90
91
107
  ecom = bgp_attr_get_ecommunity(attr);
92
107
  if (!ecom || !ecom->size)
93
0
    return false;
94
95
  /* If there is a router mac extended community, set RMAC in attr */
96
10.4k
  for (i = 0; i < ecom->size; i++) {
97
10.3k
    uint8_t *pnt = NULL;
98
10.3k
    uint8_t type = 0;
99
10.3k
    uint8_t sub_type = 0;
100
101
10.3k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
102
10.3k
    type = *pnt++;
103
10.3k
    sub_type = *pnt++;
104
105
10.3k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
106
10.3k
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
107
10.3k
      continue;
108
109
4
    memcpy(rmac, pnt, ETH_ALEN);
110
4
    return true;
111
10.3k
  }
112
103
  return false;
113
107
}
114
115
/*
116
 * return true if attr contains default gw extended community
117
 */
118
uint8_t bgp_attr_default_gw(struct attr *attr)
119
107
{
120
107
  struct ecommunity *ecom;
121
107
  uint32_t i;
122
123
107
  ecom = bgp_attr_get_ecommunity(attr);
124
107
  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.7k
  for (i = 0; i < ecom->size; i++) {
130
10.6k
    uint8_t *pnt;
131
10.6k
    uint8_t type, sub_type;
132
133
10.6k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
134
10.6k
    type = *pnt++;
135
10.6k
    sub_type = *pnt++;
136
137
10.6k
    if ((type == ECOMMUNITY_ENCODE_OPAQUE
138
10.6k
         && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
139
1
      return 1;
140
10.6k
  }
141
142
106
  return 0;
143
107
}
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
107
{
151
107
  struct ecommunity *ecom;
152
107
  uint32_t i;
153
107
  uint16_t df_pref = 0;
154
155
107
  *alg = EVPN_MH_DF_ALG_SERVICE_CARVING;
156
107
  ecom = bgp_attr_get_ecommunity(attr);
157
107
  if (!ecom || !ecom->size)
158
0
    return 0;
159
160
7.82k
  for (i = 0; i < ecom->size; i++) {
161
7.75k
    uint8_t *pnt;
162
7.75k
    uint8_t type, sub_type;
163
164
7.75k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
165
7.75k
    type = *pnt++;
166
7.75k
    sub_type = *pnt++;
167
7.75k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
168
7.75k
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION))
169
7.72k
      continue;
170
171
31
    *alg = (*pnt++) & ECOMMUNITY_EVPN_SUBTYPE_DF_ALG_BITS;
172
173
31
    pnt += 3;
174
31
    pnt = ptr_get_be16(pnt, &df_pref);
175
31
    (void)pnt; /* consume value */
176
31
    break;
177
7.75k
  }
178
179
107
  return df_pref;
180
107
}
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
107
{
188
107
  struct ecommunity *ecom;
189
107
  uint32_t i;
190
107
  uint8_t flags = 0;
191
192
107
  ecom = bgp_attr_get_ecommunity(attr);
193
107
  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.58k
  for (i = 0; i < ecom->size; i++) {
203
8.50k
    const uint8_t *pnt;
204
8.50k
    uint8_t type, sub_type;
205
8.50k
    uint32_t seq_num;
206
207
8.50k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
208
8.50k
    type = *pnt++;
209
8.50k
    sub_type = *pnt++;
210
8.50k
    if (!(type == ECOMMUNITY_ENCODE_EVPN
211
8.50k
          && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
212
8.48k
      continue;
213
25
    flags = *pnt++;
214
215
25
    if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
216
3
      *sticky = 1;
217
22
    else
218
22
      *sticky = 0;
219
220
25
    pnt++;
221
25
    pnt = ptr_get_be32(pnt, &seq_num);
222
25
    (void)pnt; /* consume value */
223
25
    return seq_num;
224
8.50k
  }
225
226
82
  return 0;
227
107
}
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
107
{
235
107
  struct ecommunity *ecom;
236
107
  uint32_t i;
237
107
  uint8_t val;
238
239
107
  ecom = bgp_attr_get_ecommunity(attr);
240
107
  if (!ecom || !ecom->size)
241
0
    return;
242
243
  /* If there is a evpn na extendd community set router_flag */
244
9.19k
  for (i = 0; i < ecom->size; i++) {
245
9.10k
    uint8_t *pnt;
246
9.10k
    uint8_t type, sub_type;
247
248
9.10k
    pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
249
9.10k
    type = *pnt++;
250
9.10k
    sub_type = *pnt++;
251
252
9.10k
    if (type == ECOMMUNITY_ENCODE_EVPN &&
253
9.10k
        sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
254
17
      val = *pnt++;
255
256
17
      if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
257
2
        *router_flag = 1;
258
259
17
      if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
260
10
        *proxy = true;
261
262
17
      break;
263
17
    }
264
9.10k
  }
265
107
}
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
}