]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_evpn.c
Merge pull request #698 from dslicenc/cm16737-srgb-block
[mirror_frr.git] / bgpd / bgp_evpn.c
1 /* Ethernet-VPN Packet and vty Processing 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/bgp_attr_evpn.h"
31 #include "bgpd/bgpd.h"
32 #include "bgpd/bgp_table.h"
33 #include "bgpd/bgp_route.h"
34 #include "bgpd/bgp_attr.h"
35 #include "bgpd/bgp_mplsvpn.h"
36 #include "bgpd/bgp_evpn.h"
37
38 int
39 bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
40 struct bgp_nlri *packet, int withdraw)
41 {
42 u_char *pnt;
43 u_char *lim;
44 struct prefix p;
45 struct prefix_rd prd;
46 struct evpn_addr *p_evpn_p;
47 struct bgp_route_evpn evpn;
48 uint8_t route_type, route_length;
49 u_char *pnt_label;
50 u_int32_t addpath_id = 0;
51
52 /* Check peer status. */
53 if (peer->status != Established)
54 return 0;
55
56 /* Make prefix_rd */
57 prd.family = AF_UNSPEC;
58 prd.prefixlen = 64;
59
60 p_evpn_p = &p.u.prefix_evpn;
61 pnt = packet->nlri;
62 lim = pnt + packet->length;
63 while (pnt < lim) {
64 /* clear evpn structure */
65 memset(&evpn, 0, sizeof(evpn));
66
67 /* Clear prefix structure. */
68 memset(&p, 0, sizeof(struct prefix));
69 memset(&evpn.gw_ip, 0, sizeof(union gw_addr));
70 memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id));
71
72 /* Fetch Route Type */
73 route_type = *pnt++;
74 route_length = *pnt++;
75 /* simply ignore. goto next route type if any */
76 if (route_type != EVPN_IP_PREFIX) {
77 if (pnt + route_length > lim) {
78 zlog_err
79 ("not enough bytes for New Route Type left in NLRI?");
80 return -1;
81 }
82 pnt += route_length;
83 continue;
84 }
85
86 /* Fetch RD */
87 if (pnt + 8 > lim) {
88 zlog_err("not enough bytes for RD left in NLRI?");
89 return -1;
90 }
91
92 /* Copy routing distinguisher to rd. */
93 memcpy(&prd.val, pnt, 8);
94 pnt += 8;
95
96 /* Fetch ESI */
97 if (pnt + 10 > lim) {
98 zlog_err("not enough bytes for ESI left in NLRI?");
99 return -1;
100 }
101 memcpy(&evpn.eth_s_id.val, pnt, 10);
102 pnt += 10;
103
104 /* Fetch Ethernet Tag */
105 if (pnt + 4 > lim) {
106 zlog_err("not enough bytes for Eth Tag left in NLRI?");
107 return -1;
108 }
109
110 if (route_type == EVPN_IP_PREFIX) {
111 p_evpn_p->route_type = route_type;
112 memcpy(&(p_evpn_p->eth_tag), pnt, 4);
113 p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag);
114 pnt += 4;
115
116 /* Fetch IP prefix length. */
117 p_evpn_p->ip_prefix_length = *pnt++;
118
119 if (p_evpn_p->ip_prefix_length > 128) {
120 zlog_err("invalid prefixlen %d in EVPN NLRI?",
121 p.prefixlen);
122 return -1;
123 }
124 /* determine IPv4 or IPv6 prefix */
125 if (route_length - 4 - 10 - 8 -
126 3 /* label to be read */ >= 32) {
127 p_evpn_p->flags = IP_PREFIX_V6;
128 memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16);
129 pnt += 16;
130 memcpy(&evpn.gw_ip.ipv6, pnt, 16);
131 pnt += 16;
132 } else {
133 p_evpn_p->flags = IP_PREFIX_V4;
134 memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4);
135 pnt += 4;
136 memcpy(&evpn.gw_ip.ipv4, pnt, 4);
137 pnt += 4;
138 }
139 p.family = AFI_L2VPN;
140 if (p_evpn_p->flags == IP_PREFIX_V4)
141 p.prefixlen =
142 (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
143 else
144 p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
145 p.family = AF_ETHERNET;
146 }
147
148 /* Fetch Label */
149 if (pnt + 3 > lim) {
150 zlog_err("not enough bytes for Label left in NLRI?");
151 return -1;
152 }
153 pnt_label = pnt;
154
155 pnt += 3;
156
157 if (!withdraw) {
158 bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN,
159 SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
160 &prd, pnt_label, 0, &evpn);
161 } else {
162 bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN,
163 SAFI_EVPN, ZEBRA_ROUTE_BGP,
164 BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn);
165 }
166 }
167
168 /* Packet length consistency check. */
169 if (pnt != lim)
170 return -1;
171 return 0;
172 }
173
174 void
175 bgp_packet_mpattr_route_type_5(struct stream *s,
176 struct prefix *p, struct prefix_rd *prd,
177 u_char * label, struct attr *attr)
178 {
179 int len;
180 char temp[16];
181 struct evpn_addr *p_evpn_p;
182
183 memset(&temp, 0, 16);
184 if (p->family != AF_ETHERNET)
185 return;
186 p_evpn_p = &(p->u.prefix_evpn);
187 if (p_evpn_p->flags & IP_PREFIX_V4)
188 len = 8; /* ipv4 */
189 else
190 len = 32; /* ipv6 */
191 stream_putc(s, EVPN_IP_PREFIX);
192 stream_putc(s,
193 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len +
194 3 /* label */ );
195 stream_put(s, prd->val, 8);
196 if (attr && attr->extra)
197 stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10);
198 else
199 stream_put(s, &temp, 10);
200 stream_putl(s, p_evpn_p->eth_tag);
201 stream_putc(s, p_evpn_p->ip_prefix_length);
202 if (p_evpn_p->flags & IP_PREFIX_V4)
203 stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr);
204 else
205 stream_put(s, &p_evpn_p->ip.v6_addr, 16);
206 if (attr && attr->extra) {
207 if (p_evpn_p->flags & IP_PREFIX_V4)
208 stream_put_ipv4(s,
209 attr->extra->evpn_overlay.gw_ip.ipv4.
210 s_addr);
211 else
212 stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6),
213 16);
214 } else {
215 if (p_evpn_p->flags & IP_PREFIX_V4)
216 stream_put_ipv4(s, 0);
217 else
218 stream_put(s, &temp, 16);
219 }
220 if (label)
221 stream_put(s, label, 3);
222 else
223 stream_put3(s, 0);
224 return;
225 }