]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_attr_evpn.c
Merge branch 'master' into docuser
[mirror_frr.git] / bgpd / bgp_attr_evpn.c
1 /* Ethernet-VPN Attribute handling file
2 * Copyright (C) 2016 6WIND
3 *
4 * This file is part of FRRouting.
5 *
6 * FRRouting is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRRouting is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "command.h"
24 #include "filter.h"
25 #include "prefix.h"
26 #include "log.h"
27 #include "memory.h"
28 #include "stream.h"
29
30 #include "bgpd/bgpd.h"
31 #include "bgpd/bgp_attr.h"
32 #include "bgpd/bgp_route.h"
33 #include "bgpd/bgp_attr_evpn.h"
34 #include "bgpd/bgp_ecommunity.h"
35 #include "bgpd/bgp_evpn.h"
36 #include "bgpd/bgp_evpn_private.h"
37
38 void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
39 {
40 struct ecommunity_val routermac_ecom;
41
42 memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
43 routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
44 routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
45 memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
46 if (!attr->ecommunity)
47 attr->ecommunity = ecommunity_new();
48 ecommunity_add_val(attr->ecommunity, &routermac_ecom);
49 ecommunity_str(attr->ecommunity);
50 }
51
52 /* converts to an esi
53 * returns 1 on success, 0 otherwise
54 * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
55 * if id is null, check only is done
56 */
57 int str2esi(const char *str, struct eth_segment_id *id)
58 {
59 unsigned int a[ESI_LEN];
60 int i;
61
62 if (!str)
63 return 0;
64 if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
65 a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
66 != ESI_LEN) {
67 /* error in incoming str length */
68 return 0;
69 }
70 /* valid mac address */
71 if (!id)
72 return 1;
73 for (i = 0; i < ESI_LEN; ++i)
74 id->val[i] = a[i] & 0xff;
75 return 1;
76 }
77
78 char *esi2str(struct eth_segment_id *id)
79 {
80 char *ptr;
81 u_char *val;
82
83 if (!id)
84 return NULL;
85
86 val = id->val;
87 ptr = (char *)XMALLOC(MTYPE_TMP,
88 (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
89
90 snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
91 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", val[0],
92 val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8],
93 val[9]);
94
95 return ptr;
96 }
97
98 char *ecom_mac2str(char *ecom_mac)
99 {
100 char *en;
101
102 en = ecom_mac;
103 en += 2;
104
105 return prefix_mac2str((struct ethaddr *)en, NULL, 0);
106 }
107
108 /* Fetch router-mac from extended community */
109 void bgp_attr_rmac(struct attr *attr,
110 struct ethaddr *rmac)
111 {
112 int i = 0;
113 struct ecommunity *ecom;
114
115 ecom = attr->ecommunity;
116 if (!ecom || !ecom->size)
117 return;
118
119 /* If there is a router mac extended community, set RMAC in attr */
120 for (i = 0; i < ecom->size; i++) {
121 u_char *pnt = NULL;
122 u_char type = 0;
123 u_char sub_type = 0;
124
125 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
126 type = *pnt++;
127 sub_type = *pnt++;
128
129 if (!(type == ECOMMUNITY_ENCODE_EVPN &&
130 sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
131 continue;
132
133 memcpy(rmac, pnt, ETH_ALEN);
134 }
135 }
136
137 /*
138 * return true if attr contains default gw extended community
139 */
140 uint8_t bgp_attr_default_gw(struct attr *attr)
141 {
142 struct ecommunity *ecom;
143 int i;
144
145 ecom = attr->ecommunity;
146 if (!ecom || !ecom->size)
147 return 0;
148
149 /* If there is a default gw extendd community return true otherwise
150 * return 0 */
151 for (i = 0; i < ecom->size; i++) {
152 u_char *pnt;
153 u_char type, sub_type;
154
155 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
156 type = *pnt++;
157 sub_type = *pnt++;
158
159 if ((type == ECOMMUNITY_ENCODE_OPAQUE
160 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
161 return 1;
162 }
163
164 return 0;
165 }
166
167 /*
168 * Fetch and return the sequence number from MAC Mobility extended
169 * community, if present, else 0.
170 */
171 u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, u_char *sticky)
172 {
173 struct ecommunity *ecom;
174 int i;
175 u_char flags = 0;
176
177 ecom = attr->ecommunity;
178 if (!ecom || !ecom->size)
179 return 0;
180
181 /* If there is a MAC Mobility extended community, return its
182 * sequence number.
183 * TODO: RFC is silent on handling of multiple MAC mobility extended
184 * communities for the same route. We will bail out upon the first
185 * one.
186 */
187 for (i = 0; i < ecom->size; i++) {
188 u_char *pnt;
189 u_char type, sub_type;
190 u_int32_t seq_num;
191
192 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
193 type = *pnt++;
194 sub_type = *pnt++;
195 if (!(type == ECOMMUNITY_ENCODE_EVPN
196 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
197 continue;
198 flags = *pnt++;
199
200 if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
201 *sticky = 1;
202 else
203 *sticky = 0;
204
205 pnt++;
206 pnt = ptr_get_be32(pnt, &seq_num);
207 (void)pnt; /* consume value */
208 return seq_num;
209 }
210
211 return 0;
212 }
213
214 /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
215 extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
216 struct prefix *dst)
217 {
218 struct evpn_addr *p_evpn_p;
219 struct prefix p2;
220 struct prefix *src = &p2;
221
222 if (!dst || dst->family == 0)
223 return -1;
224 /* store initial prefix in src */
225 prefix_copy(src, dst);
226 memset(dst, 0, sizeof(struct prefix));
227 p_evpn_p = &(dst->u.prefix_evpn);
228 dst->family = AF_EVPN;
229 p_evpn_p->route_type = evpn_type;
230 if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
231 p_evpn_p->eth_tag = eth_tag;
232 p_evpn_p->ip_prefix_length = p2.prefixlen;
233 if (src->family == AF_INET) {
234 SET_IPADDR_V4(&p_evpn_p->ip);
235 memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4,
236 sizeof(struct in_addr));
237 dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4;
238 } else {
239 SET_IPADDR_V6(&p_evpn_p->ip);
240 memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6,
241 sizeof(struct in6_addr));
242 dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV6;
243 }
244 } else
245 return -1;
246 return 0;
247 }