]>
Commit | Line | Data |
---|---|---|
7ef5a232 PG |
1 | /* Ethernet-VPN Packet and vty Processing File |
2 | Copyright (C) 2016 6WIND | |
3 | ||
52884837 | 4 | This file is part of FRRouting. |
7ef5a232 | 5 | |
52884837 | 6 | FRRouting is free software; you can redistribute it and/or modify it |
7ef5a232 PG |
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 | ||
52884837 | 11 | FRRouting is distributed in the hope that it will be useful, but |
7ef5a232 PG |
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 | |
52884837 | 17 | along with FRRouting; see the file COPYING. If not, write to the Free |
7ef5a232 PG |
18 | Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
19 | 02111-1307, USA. */ | |
20 | ||
7ef5a232 PG |
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 | ||
ac4d0be5 | 38 | int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, |
39 | struct bgp_nlri *packet, int withdraw) | |
7ef5a232 | 40 | { |
4d0e6ece PG |
41 | u_char *pnt; |
42 | u_char *lim; | |
43 | struct prefix p; | |
44 | struct prefix_rd prd; | |
45 | struct evpn_addr *p_evpn_p; | |
46 | struct bgp_route_evpn evpn; | |
47 | uint8_t route_type, route_length; | |
48 | u_char *pnt_label; | |
49 | u_int32_t addpath_id = 0; | |
50 | ||
51 | /* Check peer status. */ | |
52 | if (peer->status != Established) | |
53 | return 0; | |
54 | ||
55 | /* Make prefix_rd */ | |
56 | prd.family = AF_UNSPEC; | |
57 | prd.prefixlen = 64; | |
58 | ||
59 | p_evpn_p = &p.u.prefix_evpn; | |
60 | pnt = packet->nlri; | |
61 | lim = pnt + packet->length; | |
62 | while (pnt < lim) { | |
63 | /* clear evpn structure */ | |
64 | memset(&evpn, 0, sizeof(evpn)); | |
65 | ||
66 | /* Clear prefix structure. */ | |
67 | memset(&p, 0, sizeof(struct prefix)); | |
68 | memset(&evpn.gw_ip, 0, sizeof(union gw_addr)); | |
69 | memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id)); | |
70 | ||
71 | /* Fetch Route Type */ | |
72 | route_type = *pnt++; | |
73 | route_length = *pnt++; | |
74 | /* simply ignore. goto next route type if any */ | |
75 | if (route_type != EVPN_IP_PREFIX) { | |
76 | if (pnt + route_length > lim) { | |
ac4d0be5 | 77 | zlog_err( |
78 | "not enough bytes for New Route Type left in NLRI?"); | |
4d0e6ece PG |
79 | return -1; |
80 | } | |
81 | pnt += route_length; | |
82 | continue; | |
83 | } | |
84 | ||
85 | /* Fetch RD */ | |
86 | if (pnt + 8 > lim) { | |
87 | zlog_err("not enough bytes for RD left in NLRI?"); | |
88 | return -1; | |
89 | } | |
90 | ||
91 | /* Copy routing distinguisher to rd. */ | |
92 | memcpy(&prd.val, pnt, 8); | |
93 | pnt += 8; | |
94 | ||
95 | /* Fetch ESI */ | |
96 | if (pnt + 10 > lim) { | |
97 | zlog_err("not enough bytes for ESI left in NLRI?"); | |
98 | return -1; | |
99 | } | |
100 | memcpy(&evpn.eth_s_id.val, pnt, 10); | |
101 | pnt += 10; | |
102 | ||
103 | /* Fetch Ethernet Tag */ | |
104 | if (pnt + 4 > lim) { | |
105 | zlog_err("not enough bytes for Eth Tag left in NLRI?"); | |
106 | return -1; | |
107 | } | |
108 | ||
109 | if (route_type == EVPN_IP_PREFIX) { | |
110 | p_evpn_p->route_type = route_type; | |
111 | memcpy(&(p_evpn_p->eth_tag), pnt, 4); | |
112 | p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag); | |
113 | pnt += 4; | |
114 | ||
115 | /* Fetch IP prefix length. */ | |
116 | p_evpn_p->ip_prefix_length = *pnt++; | |
117 | ||
118 | if (p_evpn_p->ip_prefix_length > 128) { | |
119 | zlog_err("invalid prefixlen %d in EVPN NLRI?", | |
120 | p.prefixlen); | |
121 | return -1; | |
122 | } | |
123 | /* determine IPv4 or IPv6 prefix */ | |
ac4d0be5 | 124 | if (route_length - 4 - 10 - 8 - 3 /* label to be read */ |
125 | >= 32) { | |
4d0e6ece | 126 | p_evpn_p->flags = IP_PREFIX_V6; |
daf9ddbb | 127 | memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16); |
4d0e6ece PG |
128 | pnt += 16; |
129 | memcpy(&evpn.gw_ip.ipv6, pnt, 16); | |
130 | pnt += 16; | |
131 | } else { | |
132 | p_evpn_p->flags = IP_PREFIX_V4; | |
133 | memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4); | |
134 | pnt += 4; | |
135 | memcpy(&evpn.gw_ip.ipv4, pnt, 4); | |
136 | pnt += 4; | |
137 | } | |
138 | p.family = AFI_L2VPN; | |
139 | if (p_evpn_p->flags == IP_PREFIX_V4) | |
140 | p.prefixlen = | |
ac4d0be5 | 141 | (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4; |
4d0e6ece PG |
142 | else |
143 | p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; | |
144 | p.family = AF_ETHERNET; | |
145 | } | |
146 | ||
147 | /* Fetch Label */ | |
148 | if (pnt + 3 > lim) { | |
149 | zlog_err("not enough bytes for Label left in NLRI?"); | |
150 | return -1; | |
151 | } | |
152 | pnt_label = pnt; | |
153 | ||
154 | pnt += 3; | |
155 | ||
156 | if (!withdraw) { | |
157 | bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN, | |
158 | SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, | |
159 | &prd, pnt_label, 0, &evpn); | |
160 | } else { | |
161 | bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN, | |
162 | SAFI_EVPN, ZEBRA_ROUTE_BGP, | |
163 | BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn); | |
164 | } | |
7ef5a232 PG |
165 | } |
166 | ||
4d0e6ece PG |
167 | /* Packet length consistency check. */ |
168 | if (pnt != lim) | |
169 | return -1; | |
170 | return 0; | |
7ef5a232 | 171 | } |
b18825eb | 172 | |
ac4d0be5 | 173 | void bgp_packet_mpattr_route_type_5(struct stream *s, struct prefix *p, |
174 | struct prefix_rd *prd, u_char *label, | |
175 | struct attr *attr) | |
b18825eb | 176 | { |
4d0e6ece PG |
177 | int len; |
178 | char temp[16]; | |
179 | struct evpn_addr *p_evpn_p; | |
180 | ||
181 | memset(&temp, 0, 16); | |
182 | if (p->family != AF_ETHERNET) | |
183 | return; | |
184 | p_evpn_p = &(p->u.prefix_evpn); | |
185 | if (p_evpn_p->flags & IP_PREFIX_V4) | |
ac4d0be5 | 186 | len = 8; /* ipv4 */ |
4d0e6ece | 187 | else |
ac4d0be5 | 188 | len = 32; /* ipv6 */ |
4d0e6ece PG |
189 | stream_putc(s, EVPN_IP_PREFIX); |
190 | stream_putc(s, | |
ac4d0be5 | 191 | 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len |
192 | + 3 /* label */); | |
4d0e6ece PG |
193 | stream_put(s, prd->val, 8); |
194 | if (attr && attr->extra) | |
195 | stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10); | |
196 | else | |
197 | stream_put(s, &temp, 10); | |
198 | stream_putl(s, p_evpn_p->eth_tag); | |
199 | stream_putc(s, p_evpn_p->ip_prefix_length); | |
200 | if (p_evpn_p->flags & IP_PREFIX_V4) | |
201 | stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr); | |
202 | else | |
203 | stream_put(s, &p_evpn_p->ip.v6_addr, 16); | |
204 | if (attr && attr->extra) { | |
205 | if (p_evpn_p->flags & IP_PREFIX_V4) | |
ac4d0be5 | 206 | stream_put_ipv4( |
207 | s, attr->extra->evpn_overlay.gw_ip.ipv4.s_addr); | |
4d0e6ece PG |
208 | else |
209 | stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), | |
210 | 16); | |
211 | } else { | |
212 | if (p_evpn_p->flags & IP_PREFIX_V4) | |
213 | stream_put_ipv4(s, 0); | |
214 | else | |
215 | stream_put(s, &temp, 16); | |
216 | } | |
217 | if (label) | |
218 | stream_put(s, label, 3); | |
219 | else | |
220 | stream_put3(s, 0); | |
221 | return; | |
b18825eb | 222 | } |