]>
Commit | Line | Data |
---|---|---|
d62a17ae | 1 | /* |
65efcfce LB |
2 | * |
3 | * Copyright 2009-2016, LabN Consulting, L.L.C. | |
4 | * | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
896014f4 DL |
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 | |
65efcfce LB |
19 | */ |
20 | ||
21 | /* | |
22 | * File: vnc_zebra.c | |
23 | * Purpose: Handle exchange of routes between VNC and Zebra | |
24 | */ | |
25 | ||
f8b6f499 LB |
26 | #include "lib/zebra.h" |
27 | #include "lib/prefix.h" | |
fe08ba7e | 28 | #include "lib/agg_table.h" |
f8b6f499 LB |
29 | #include "lib/log.h" |
30 | #include "lib/command.h" | |
31 | #include "lib/zclient.h" | |
32 | #include "lib/stream.h" | |
74ffbfe6 | 33 | #include "lib/ringbuf.h" |
f8b6f499 | 34 | #include "lib/memory.h" |
02705213 | 35 | #include "lib/lib_errors.h" |
65efcfce | 36 | |
f8b6f499 LB |
37 | #include "bgpd/bgpd.h" |
38 | #include "bgpd/bgp_ecommunity.h" | |
39 | #include "bgpd/bgp_route.h" | |
40 | #include "bgpd/bgp_debug.h" | |
41 | #include "bgpd/bgp_advertise.h" | |
65efcfce | 42 | |
f8b6f499 LB |
43 | #include "bgpd/rfapi/bgp_rfapi_cfg.h" |
44 | #include "bgpd/rfapi/rfapi.h" | |
45 | #include "bgpd/rfapi/rfapi_import.h" | |
46 | #include "bgpd/rfapi/rfapi_private.h" | |
47 | #include "bgpd/rfapi/vnc_zebra.h" | |
48 | #include "bgpd/rfapi/rfapi_vty.h" | |
49 | #include "bgpd/rfapi/rfapi_backend.h" | |
a3b55c25 | 50 | #include "bgpd/rfapi/vnc_debug.h" |
65efcfce | 51 | |
d62a17ae | 52 | static struct rfapi_descriptor vncHD1VR; /* Single-VR export dummy nve descr */ |
65efcfce LB |
53 | static struct zclient *zclient_vnc = NULL; |
54 | ||
55 | /*********************************************************************** | |
56 | * REDISTRIBUTE: Zebra sends updates/withdraws to BGPD | |
57 | ***********************************************************************/ | |
58 | ||
59 | /* | |
60 | * Routes coming from zebra get added to VNC here | |
61 | */ | |
d7c0a89a | 62 | static void vnc_redistribute_add(struct prefix *p, uint32_t metric, |
74489921 | 63 | uint8_t type) |
65efcfce | 64 | { |
d62a17ae | 65 | struct bgp *bgp = bgp_get_default(); |
66 | struct prefix_rd prd; | |
67 | struct rfapi_ip_addr vnaddr; | |
68 | afi_t afi; | |
69 | uint32_t local_pref = | |
70 | rfp_cost_to_localpref(metric > 255 ? 255 : metric); | |
71 | ||
72 | if (!bgp) | |
73 | return; | |
74 | ||
75 | if (!bgp->rfapi_cfg) { | |
76 | vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping", | |
77 | __func__); | |
78 | return; | |
79 | } | |
80 | ||
81 | afi = family2afi(p->family); | |
82 | if (!afi) { | |
83 | vnc_zlog_debug_verbose("%s: unknown prefix address family %d", | |
84 | __func__, p->family); | |
85 | return; | |
86 | } | |
87 | ||
88 | if (!bgp->rfapi_cfg->redist[afi][type]) { | |
89 | vnc_zlog_debug_verbose( | |
90 | "%s: bgp->rfapi_cfg->redist[afi=%d][type=%d] is 0, skipping", | |
91 | __func__, afi, type); | |
92 | return; | |
93 | } | |
94 | if (!bgp->rfapi_cfg->rfg_redist) { | |
95 | vnc_zlog_debug_verbose("%s: no redist nve group, skipping", | |
96 | __func__); | |
97 | return; | |
98 | } | |
99 | ||
100 | /* | |
101 | * Assume nve group's configured VN address prefix is a host | |
102 | * route which also happens to give the NVE VN address to use | |
103 | * for redistributing into VNC. | |
104 | */ | |
105 | vnaddr.addr_family = bgp->rfapi_cfg->rfg_redist->vn_prefix.family; | |
106 | switch (bgp->rfapi_cfg->rfg_redist->vn_prefix.family) { | |
107 | case AF_INET: | |
108 | if (bgp->rfapi_cfg->rfg_redist->vn_prefix.prefixlen != 32) { | |
109 | vnc_zlog_debug_verbose( | |
110 | "%s: redist nve group VN prefix len (%d) != 32, skipping", | |
111 | __func__, | |
112 | bgp->rfapi_cfg->rfg_redist->vn_prefix | |
113 | .prefixlen); | |
114 | return; | |
115 | } | |
116 | vnaddr.addr.v4 = | |
117 | bgp->rfapi_cfg->rfg_redist->vn_prefix.u.prefix4; | |
118 | break; | |
119 | case AF_INET6: | |
120 | if (bgp->rfapi_cfg->rfg_redist->vn_prefix.prefixlen != 128) { | |
121 | vnc_zlog_debug_verbose( | |
122 | "%s: redist nve group VN prefix len (%d) != 128, skipping", | |
123 | __func__, | |
124 | bgp->rfapi_cfg->rfg_redist->vn_prefix | |
125 | .prefixlen); | |
126 | return; | |
127 | } | |
128 | vnaddr.addr.v6 = | |
129 | bgp->rfapi_cfg->rfg_redist->vn_prefix.u.prefix6; | |
130 | break; | |
131 | default: | |
132 | vnc_zlog_debug_verbose( | |
133 | "%s: no redist nve group VN host prefix configured, skipping", | |
134 | __func__); | |
135 | return; | |
136 | } | |
137 | ||
138 | /* | |
139 | * Assume nve group's configured UN address prefix is a host | |
140 | * route which also happens to give the NVE UN address to use | |
141 | * for redistributing into VNC. | |
142 | */ | |
143 | ||
144 | /* | |
145 | * Set UN address in dummy nve descriptor so add_vnc_route | |
146 | * can use it in VNC tunnel SubTLV | |
147 | */ | |
148 | { | |
149 | struct rfapi_ip_prefix pfx_un; | |
150 | ||
151 | rfapiQprefix2Rprefix(&bgp->rfapi_cfg->rfg_redist->un_prefix, | |
152 | &pfx_un); | |
153 | ||
154 | switch (pfx_un.prefix.addr_family) { | |
155 | case AF_INET: | |
156 | if (pfx_un.length != 32) { | |
157 | vnc_zlog_debug_verbose( | |
158 | "%s: redist nve group UN prefix len (%d) != 32, skipping", | |
159 | __func__, pfx_un.length); | |
160 | return; | |
161 | } | |
162 | break; | |
163 | case AF_INET6: | |
164 | if (pfx_un.length != 128) { | |
165 | vnc_zlog_debug_verbose( | |
166 | "%s: redist nve group UN prefix len (%d) != 128, skipping", | |
167 | __func__, pfx_un.length); | |
168 | return; | |
169 | } | |
170 | break; | |
171 | default: | |
172 | vnc_zlog_debug_verbose( | |
173 | "%s: no redist nve group UN host prefix configured, skipping", | |
174 | __func__); | |
175 | return; | |
176 | } | |
177 | ||
178 | vncHD1VR.un_addr = pfx_un.prefix; | |
179 | ||
180 | if (!vncHD1VR.peer) { | |
181 | /* | |
182 | * Same setup as in rfapi_open() | |
183 | */ | |
184 | vncHD1VR.peer = peer_new(bgp); | |
185 | vncHD1VR.peer->status = | |
186 | Established; /* keep bgp core happy */ | |
187 | bgp_sync_delete(vncHD1VR.peer); /* don't need these */ | |
424ab01d | 188 | |
becedef6 QY |
189 | /* |
190 | * since this peer is not on the I/O thread, this lock | |
191 | * is not strictly necessary, but serves as a reminder | |
192 | * to those who may meddle... | |
193 | */ | |
424ab01d QY |
194 | pthread_mutex_lock(&vncHD1VR.peer->io_mtx); |
195 | { | |
196 | // we don't need any I/O related facilities | |
197 | if (vncHD1VR.peer->ibuf) | |
198 | stream_fifo_free(vncHD1VR.peer->ibuf); | |
199 | if (vncHD1VR.peer->obuf) | |
200 | stream_fifo_free(vncHD1VR.peer->obuf); | |
201 | ||
202 | if (vncHD1VR.peer->ibuf_work) | |
74ffbfe6 | 203 | ringbuf_del(vncHD1VR.peer->ibuf_work); |
424ab01d QY |
204 | if (vncHD1VR.peer->obuf_work) |
205 | stream_free(vncHD1VR.peer->obuf_work); | |
206 | ||
d62a17ae | 207 | vncHD1VR.peer->ibuf = NULL; |
d62a17ae | 208 | vncHD1VR.peer->obuf = NULL; |
424ab01d QY |
209 | vncHD1VR.peer->obuf_work = NULL; |
210 | vncHD1VR.peer->ibuf_work = NULL; | |
d62a17ae | 211 | } |
424ab01d QY |
212 | pthread_mutex_unlock(&vncHD1VR.peer->io_mtx); |
213 | ||
d62a17ae | 214 | /* base code assumes have valid host pointer */ |
215 | vncHD1VR.peer->host = | |
216 | XSTRDUP(MTYPE_BGP_PEER_HOST, ".zebra."); | |
217 | ||
218 | /* Mark peer as belonging to HD */ | |
219 | SET_FLAG(vncHD1VR.peer->flags, PEER_FLAG_IS_RFAPI_HD); | |
220 | } | |
221 | } | |
222 | ||
223 | memset(&prd, 0, sizeof(prd)); | |
224 | prd = bgp->rfapi_cfg->rfg_redist->rd; | |
225 | prd.family = AF_UNSPEC; | |
226 | prd.prefixlen = 64; | |
227 | ||
228 | add_vnc_route(&vncHD1VR, /* cookie + UN addr */ | |
229 | bgp, SAFI_MPLS_VPN, p, &prd, &vnaddr, &local_pref, | |
230 | &(bgp->rfapi_cfg->redist_lifetime), | |
231 | NULL, /* RFP options */ | |
232 | NULL, /* struct rfapi_un_option */ | |
233 | NULL, /* struct rfapi_vn_option */ | |
234 | bgp->rfapi_cfg->rfg_redist->rt_export_list, NULL, | |
235 | NULL, /* label: default */ | |
236 | type, BGP_ROUTE_REDISTRIBUTE, 0); /* flags */ | |
65efcfce LB |
237 | } |
238 | ||
239 | /* | |
240 | * Route deletions from zebra propagate to VNC here | |
241 | */ | |
d62a17ae | 242 | static void vnc_redistribute_delete(struct prefix *p, uint8_t type) |
65efcfce | 243 | { |
d62a17ae | 244 | struct bgp *bgp = bgp_get_default(); |
245 | struct prefix_rd prd; | |
246 | afi_t afi; | |
247 | ||
248 | if (!bgp) | |
249 | return; | |
250 | ||
251 | if (!bgp->rfapi_cfg) { | |
252 | vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping", | |
253 | __func__); | |
254 | return; | |
255 | } | |
256 | afi = family2afi(p->family); | |
257 | if (!afi) { | |
258 | vnc_zlog_debug_verbose("%s: unknown prefix address family %d", | |
259 | __func__, p->family); | |
260 | return; | |
261 | } | |
262 | if (!bgp->rfapi_cfg->redist[afi][type]) { | |
263 | vnc_zlog_debug_verbose( | |
264 | "%s: bgp->rfapi_cfg->redist[afi=%d][type=%d] is 0, skipping", | |
265 | __func__, afi, type); | |
266 | return; | |
267 | } | |
268 | if (!bgp->rfapi_cfg->rfg_redist) { | |
269 | vnc_zlog_debug_verbose("%s: no redist nve group, skipping", | |
270 | __func__); | |
271 | return; | |
272 | } | |
273 | ||
274 | memset(&prd, 0, sizeof(prd)); | |
275 | prd = bgp->rfapi_cfg->rfg_redist->rd; | |
276 | prd.family = AF_UNSPEC; | |
277 | prd.prefixlen = 64; | |
278 | ||
279 | del_vnc_route(&vncHD1VR, /* use dummy ptr as cookie */ | |
280 | vncHD1VR.peer, bgp, SAFI_MPLS_VPN, p, &prd, type, | |
281 | BGP_ROUTE_REDISTRIBUTE, NULL, 0); | |
65efcfce LB |
282 | } |
283 | ||
284 | /* | |
285 | * Flush all redistributed routes of type <type> | |
286 | */ | |
d62a17ae | 287 | static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type) |
65efcfce | 288 | { |
d62a17ae | 289 | struct prefix_rd prd; |
290 | struct bgp_table *table; | |
291 | struct bgp_node *prn; | |
292 | struct bgp_node *rn; | |
293 | ||
294 | vnc_zlog_debug_verbose("%s: entry", __func__); | |
295 | ||
296 | if (!bgp) | |
297 | return; | |
298 | if (!bgp->rfapi_cfg) { | |
299 | vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping", | |
300 | __func__); | |
301 | return; | |
302 | } | |
303 | ||
304 | /* | |
305 | * Loop over all the RDs | |
306 | */ | |
307 | for (prn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); prn; | |
308 | prn = bgp_route_next(prn)) { | |
309 | memset(&prd, 0, sizeof(prd)); | |
310 | prd.family = AF_UNSPEC; | |
311 | prd.prefixlen = 64; | |
312 | memcpy(prd.val, prn->p.u.val, 8); | |
313 | ||
314 | /* This is the per-RD table of prefixes */ | |
67009e22 | 315 | table = bgp_node_get_bgp_table_info(prn); |
2eab1324 RW |
316 | if (!table) |
317 | continue; | |
d62a17ae | 318 | |
319 | for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { | |
320 | ||
4b7e6066 | 321 | struct bgp_path_info *ri; |
d62a17ae | 322 | |
6f94b685 DS |
323 | for (ri = bgp_node_get_bgp_path_info(rn); ri; |
324 | ri = ri->next) { | |
d62a17ae | 325 | if (ri->type |
326 | == type) { /* has matching redist type */ | |
327 | break; | |
328 | } | |
329 | } | |
330 | if (ri) { | |
331 | del_vnc_route( | |
332 | &vncHD1VR, /* use dummy ptr as cookie */ | |
333 | vncHD1VR.peer, bgp, SAFI_MPLS_VPN, | |
334 | &(rn->p), &prd, type, | |
335 | BGP_ROUTE_REDISTRIBUTE, NULL, 0); | |
336 | } | |
337 | } | |
338 | } | |
339 | vnc_zlog_debug_verbose("%s: return", __func__); | |
65efcfce LB |
340 | } |
341 | ||
342 | /* | |
343 | * Zebra route add and delete treatment. | |
344 | * | |
345 | * Assumes 1 nexthop | |
346 | */ | |
74489921 RW |
347 | static int vnc_zebra_read_route(int command, struct zclient *zclient, |
348 | zebra_size_t length, vrf_id_t vrf_id) | |
65efcfce | 349 | { |
74489921 RW |
350 | struct zapi_route api; |
351 | int add; | |
d62a17ae | 352 | |
74489921 RW |
353 | if (zapi_route_decode(zclient->ibuf, &api) < 0) |
354 | return -1; | |
65efcfce | 355 | |
74489921 RW |
356 | /* we completely ignore srcdest routes for now. */ |
357 | if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) | |
d62a17ae | 358 | return 0; |
359 | ||
74489921 RW |
360 | add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD); |
361 | if (add) | |
362 | vnc_redistribute_add(&api.prefix, api.metric, api.type); | |
d62a17ae | 363 | else |
74489921 | 364 | vnc_redistribute_delete(&api.prefix, api.type); |
d62a17ae | 365 | |
74489921 RW |
366 | if (BGP_DEBUG(zebra, ZEBRA)) { |
367 | char buf[PREFIX_STRLEN]; | |
d62a17ae | 368 | |
74489921 RW |
369 | prefix2str(&api.prefix, buf, sizeof(buf)); |
370 | vnc_zlog_debug_verbose( | |
371 | "%s: Zebra rcvd: route delete %s %s metric %u", | |
372 | __func__, zebra_route_string(api.type), buf, | |
373 | api.metric); | |
d62a17ae | 374 | } |
375 | ||
376 | return 0; | |
65efcfce LB |
377 | } |
378 | ||
379 | /*********************************************************************** | |
380 | * vnc_bgp_zebra_*: VNC sends updates/withdraws to Zebra | |
381 | ***********************************************************************/ | |
382 | ||
383 | /* | |
384 | * low-level message builder | |
385 | */ | |
a74e593b RW |
386 | static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count, |
387 | void *nhp_ary, int add) /* 1 = add, 0 = del */ | |
65efcfce | 388 | { |
2ad4f093 RW |
389 | struct zapi_route api; |
390 | struct zapi_nexthop *api_nh; | |
391 | int i; | |
b40c5062 LB |
392 | struct in_addr **nhp_ary4 = nhp_ary; |
393 | struct in6_addr **nhp_ary6 = nhp_ary; | |
2ad4f093 | 394 | |
d62a17ae | 395 | if (!nhp_count) { |
396 | vnc_zlog_debug_verbose("%s: empty nexthop list, skipping", | |
397 | __func__); | |
398 | return; | |
399 | } | |
400 | ||
2ad4f093 RW |
401 | memset(&api, 0, sizeof(api)); |
402 | api.vrf_id = VRF_DEFAULT; | |
403 | api.type = ZEBRA_ROUTE_VNC; | |
404 | api.safi = SAFI_UNICAST; | |
405 | api.prefix = *p; | |
406 | ||
407 | /* Nexthops */ | |
408 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
a74e593b RW |
409 | api.nexthop_num = MIN(nhp_count, multipath_num); |
410 | for (i = 0; i < api.nexthop_num; i++) { | |
2ad4f093 RW |
411 | |
412 | api_nh = &api.nexthops[i]; | |
4a7371e9 | 413 | api_nh->vrf_id = VRF_DEFAULT; |
2ad4f093 RW |
414 | switch (p->family) { |
415 | case AF_INET: | |
b40c5062 | 416 | memcpy(&api_nh->gate.ipv4, nhp_ary4[i], |
9913029c RW |
417 | sizeof(api_nh->gate.ipv4)); |
418 | api_nh->type = NEXTHOP_TYPE_IPV4; | |
2ad4f093 RW |
419 | break; |
420 | case AF_INET6: | |
b40c5062 | 421 | memcpy(&api_nh->gate.ipv6, nhp_ary6[i], |
9913029c RW |
422 | sizeof(api_nh->gate.ipv6)); |
423 | api_nh->type = NEXTHOP_TYPE_IPV6; | |
2ad4f093 | 424 | break; |
9913029c | 425 | } |
2ad4f093 | 426 | } |
9913029c | 427 | |
2ad4f093 RW |
428 | if (BGP_DEBUG(zebra, ZEBRA)) { |
429 | char buf[PREFIX_STRLEN]; | |
d62a17ae | 430 | |
2ad4f093 | 431 | prefix2str(&api.prefix, buf, sizeof(buf)); |
d62a17ae | 432 | vnc_zlog_debug_verbose( |
2ad4f093 RW |
433 | "%s: Zebra send: route %s %s, nhp_count=%d", __func__, |
434 | (add ? "add" : "del"), buf, nhp_count); | |
d62a17ae | 435 | } |
2ad4f093 RW |
436 | |
437 | zclient_route_send((add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE), | |
438 | zclient_vnc, &api); | |
65efcfce LB |
439 | } |
440 | ||
441 | ||
442 | static void | |
d7c0a89a | 443 | nve_list_to_nh_array(uint8_t family, struct list *nve_list, |
a74e593b | 444 | unsigned int *nh_count_ret, |
d62a17ae | 445 | void **nh_ary_ret, /* returned address array */ |
446 | void **nhp_ary_ret) /* returned pointer array */ | |
65efcfce | 447 | { |
d62a17ae | 448 | int nve_count = listcount(nve_list); |
65efcfce | 449 | |
d62a17ae | 450 | *nh_count_ret = 0; |
451 | *nh_ary_ret = NULL; | |
452 | *nhp_ary_ret = NULL; | |
65efcfce | 453 | |
d62a17ae | 454 | if (!nve_count) { |
455 | vnc_zlog_debug_verbose("%s: empty nve_list, skipping", | |
456 | __func__); | |
457 | return; | |
458 | } | |
65efcfce | 459 | |
d62a17ae | 460 | if (family == AF_INET) { |
461 | struct listnode *ln; | |
462 | struct in_addr *iap; | |
463 | struct in_addr **v; | |
65efcfce | 464 | |
d62a17ae | 465 | /* |
466 | * Array of nexthop addresses | |
467 | */ | |
468 | *nh_ary_ret = | |
469 | XCALLOC(MTYPE_TMP, nve_count * sizeof(struct in_addr)); | |
65efcfce | 470 | |
d62a17ae | 471 | /* |
472 | * Array of pointers to nexthop addresses | |
473 | */ | |
474 | *nhp_ary_ret = XCALLOC(MTYPE_TMP, | |
475 | nve_count * sizeof(struct in_addr *)); | |
476 | iap = *nh_ary_ret; | |
477 | v = *nhp_ary_ret; | |
65efcfce | 478 | |
d62a17ae | 479 | for (ln = listhead(nve_list); ln; ln = listnextnode(ln)) { |
65efcfce | 480 | |
d62a17ae | 481 | struct rfapi_descriptor *irfd; |
482 | struct prefix nhp; | |
65efcfce | 483 | |
d62a17ae | 484 | irfd = listgetdata(ln); |
65efcfce | 485 | |
d62a17ae | 486 | if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp)) |
487 | continue; | |
65efcfce | 488 | |
d62a17ae | 489 | *iap = nhp.u.prefix4; |
490 | *v = iap; | |
491 | vnc_zlog_debug_verbose( | |
492 | "%s: ipadr: (%p)<-0x%x, ptr: (%p)<-%p", | |
493 | __func__, iap, nhp.u.prefix4.s_addr, v, iap); | |
65efcfce | 494 | |
d62a17ae | 495 | ++iap; |
496 | ++v; | |
497 | ++*nh_count_ret; | |
498 | } | |
65efcfce | 499 | |
d62a17ae | 500 | } else if (family == AF_INET6) { |
65efcfce | 501 | |
d62a17ae | 502 | struct listnode *ln; |
65efcfce | 503 | |
d62a17ae | 504 | *nh_ary_ret = |
505 | XCALLOC(MTYPE_TMP, nve_count * sizeof(struct in6_addr)); | |
65efcfce | 506 | |
d62a17ae | 507 | *nhp_ary_ret = XCALLOC(MTYPE_TMP, |
508 | nve_count * sizeof(struct in6_addr *)); | |
65efcfce | 509 | |
d62a17ae | 510 | for (ln = listhead(nve_list); ln; ln = listnextnode(ln)) { |
65efcfce | 511 | |
d62a17ae | 512 | struct rfapi_descriptor *irfd; |
513 | struct in6_addr *iap = *nh_ary_ret; | |
514 | struct in6_addr **v = *nhp_ary_ret; | |
515 | struct prefix nhp; | |
65efcfce | 516 | |
d62a17ae | 517 | irfd = listgetdata(ln); |
65efcfce | 518 | |
d62a17ae | 519 | if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp)) |
520 | continue; | |
65efcfce | 521 | |
d62a17ae | 522 | *iap = nhp.u.prefix6; |
523 | *v = iap; | |
65efcfce | 524 | |
d62a17ae | 525 | ++iap; |
526 | ++v; | |
527 | ++*nh_count_ret; | |
528 | } | |
529 | } | |
65efcfce LB |
530 | } |
531 | ||
d62a17ae | 532 | static void import_table_to_nve_list_zebra(struct bgp *bgp, |
533 | struct rfapi_import_table *it, | |
534 | struct list **nves, uint8_t family) | |
65efcfce | 535 | { |
d62a17ae | 536 | struct listnode *node; |
537 | struct rfapi_rfg_name *rfgn; | |
538 | ||
539 | /* | |
540 | * Loop over the list of NVE-Groups configured for | |
541 | * exporting to direct-bgp. | |
542 | * | |
543 | * Build a list of NVEs that use this import table | |
544 | */ | |
545 | *nves = NULL; | |
546 | for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, | |
547 | rfgn)) { | |
548 | ||
549 | /* | |
550 | * If this NVE-Group's import table matches the current one | |
551 | */ | |
552 | if (rfgn->rfg && rfgn->rfg->nves | |
553 | && rfgn->rfg->rfapi_import_table == it) { | |
554 | ||
555 | nve_group_to_nve_list(rfgn->rfg, nves, family); | |
556 | } | |
557 | } | |
65efcfce LB |
558 | } |
559 | ||
d62a17ae | 560 | static void vnc_zebra_add_del_prefix(struct bgp *bgp, |
561 | struct rfapi_import_table *import_table, | |
fe08ba7e | 562 | struct agg_node *rn, |
d62a17ae | 563 | int add) /* !0 = add, 0 = del */ |
65efcfce | 564 | { |
d62a17ae | 565 | struct list *nves; |
566 | ||
a74e593b | 567 | unsigned int nexthop_count = 0; |
d62a17ae | 568 | void *nh_ary = NULL; |
569 | void *nhp_ary = NULL; | |
570 | ||
571 | vnc_zlog_debug_verbose("%s: entry, add=%d", __func__, add); | |
572 | ||
573 | if (zclient_vnc->sock < 0) | |
574 | return; | |
575 | ||
576 | if (rn->p.family != AF_INET && rn->p.family != AF_INET6) { | |
450971aa | 577 | flog_err(EC_LIB_DEVELOPMENT, |
1c50c1c0 | 578 | "%s: invalid route node addr family", __func__); |
d62a17ae | 579 | return; |
580 | } | |
581 | ||
9f2337c9 RW |
582 | if (!vrf_bitmap_check(zclient_vnc->redist[family2afi(rn->p.family)] |
583 | [ZEBRA_ROUTE_VNC], | |
584 | VRF_DEFAULT)) | |
d62a17ae | 585 | return; |
586 | ||
587 | if (!bgp->rfapi_cfg) { | |
588 | vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping", | |
589 | __func__); | |
590 | return; | |
591 | } | |
592 | if (!listcount(bgp->rfapi_cfg->rfg_export_zebra_l)) { | |
593 | vnc_zlog_debug_verbose( | |
594 | "%s: no zebra export nve group, skipping", __func__); | |
595 | return; | |
596 | } | |
597 | ||
598 | import_table_to_nve_list_zebra(bgp, import_table, &nves, rn->p.family); | |
599 | ||
600 | if (nves) { | |
601 | nve_list_to_nh_array(rn->p.family, nves, &nexthop_count, | |
602 | &nh_ary, &nhp_ary); | |
603 | ||
6a154c88 | 604 | list_delete(&nves); |
d62a17ae | 605 | |
606 | if (nexthop_count) | |
607 | vnc_zebra_route_msg(&rn->p, nexthop_count, nhp_ary, | |
608 | add); | |
609 | } | |
610 | ||
0a22ddfb QY |
611 | XFREE(MTYPE_TMP, nhp_ary); |
612 | XFREE(MTYPE_TMP, nh_ary); | |
65efcfce LB |
613 | } |
614 | ||
d62a17ae | 615 | void vnc_zebra_add_prefix(struct bgp *bgp, |
616 | struct rfapi_import_table *import_table, | |
fe08ba7e | 617 | struct agg_node *rn) |
65efcfce | 618 | { |
d62a17ae | 619 | vnc_zebra_add_del_prefix(bgp, import_table, rn, 1); |
65efcfce LB |
620 | } |
621 | ||
d62a17ae | 622 | void vnc_zebra_del_prefix(struct bgp *bgp, |
623 | struct rfapi_import_table *import_table, | |
fe08ba7e | 624 | struct agg_node *rn) |
65efcfce | 625 | { |
d62a17ae | 626 | vnc_zebra_add_del_prefix(bgp, import_table, rn, 0); |
65efcfce LB |
627 | } |
628 | ||
629 | ||
d62a17ae | 630 | static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd, |
631 | int add) /* 0 = del, !0 = add */ | |
65efcfce | 632 | { |
d62a17ae | 633 | struct listnode *node; |
634 | struct rfapi_rfg_name *rfgn; | |
635 | struct rfapi_nve_group_cfg *rfg = rfd->rfg; | |
636 | afi_t afi = family2afi(rfd->vn_addr.addr_family); | |
637 | struct prefix nhp; | |
638 | // struct prefix *nhpp; | |
639 | void *pAddr; | |
640 | ||
641 | vnc_zlog_debug_verbose("%s: entry, add=%d", __func__, add); | |
642 | ||
643 | if (zclient_vnc->sock < 0) | |
644 | return; | |
645 | ||
9f2337c9 RW |
646 | if (!vrf_bitmap_check(zclient_vnc->redist[afi][ZEBRA_ROUTE_VNC], |
647 | VRF_DEFAULT)) | |
d62a17ae | 648 | return; |
649 | ||
650 | if (afi != AFI_IP && afi != AFI_IP6) { | |
450971aa | 651 | flog_err(EC_LIB_DEVELOPMENT, "%s: invalid vn addr family", |
1c50c1c0 | 652 | __func__); |
d62a17ae | 653 | return; |
654 | } | |
655 | ||
656 | if (!bgp) | |
657 | return; | |
658 | if (!bgp->rfapi_cfg) { | |
659 | vnc_zlog_debug_verbose("%s: bgp->rfapi_cfg is NULL, skipping", | |
660 | __func__); | |
661 | return; | |
662 | } | |
663 | ||
664 | if (rfapiRaddr2Qprefix(&rfd->vn_addr, &nhp)) { | |
665 | vnc_zlog_debug_verbose("%s: can't convert vn address, skipping", | |
666 | __func__); | |
667 | return; | |
668 | } | |
669 | ||
670 | pAddr = &nhp.u.prefix4; | |
671 | ||
672 | /* | |
673 | * Loop over the list of NVE-Groups configured for | |
674 | * exporting to zebra and see if this new NVE's | |
675 | * group is among them. | |
676 | */ | |
677 | for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, | |
678 | rfgn)) { | |
679 | ||
680 | /* | |
681 | * Yes, this NVE's group is configured for export to zebra | |
682 | */ | |
683 | if (rfgn->rfg == rfg) { | |
684 | ||
fe08ba7e DS |
685 | struct agg_table *rt = NULL; |
686 | struct agg_node *rn; | |
d62a17ae | 687 | struct rfapi_import_table *import_table; |
688 | import_table = rfg->rfapi_import_table; | |
689 | ||
690 | vnc_zlog_debug_verbose( | |
691 | "%s: this nve's group is in zebra export list", | |
692 | __func__); | |
693 | ||
694 | rt = import_table->imported_vpn[afi]; | |
695 | ||
696 | /* | |
697 | * Walk the NVE-Group's VNC Import table | |
698 | */ | |
fe08ba7e DS |
699 | for (rn = agg_route_top(rt); rn; |
700 | rn = agg_route_next(rn)) { | |
d62a17ae | 701 | |
702 | if (rn->info) { | |
703 | ||
704 | vnc_zlog_debug_verbose( | |
705 | "%s: sending %s", __func__, | |
706 | (add ? "add" : "del")); | |
707 | vnc_zebra_route_msg(&rn->p, 1, &pAddr, | |
708 | add); | |
709 | } | |
710 | } | |
711 | } | |
712 | } | |
65efcfce LB |
713 | } |
714 | ||
d62a17ae | 715 | void vnc_zebra_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) |
65efcfce | 716 | { |
d62a17ae | 717 | vnc_zebra_add_del_nve(bgp, rfd, 1); |
65efcfce LB |
718 | } |
719 | ||
d62a17ae | 720 | void vnc_zebra_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) |
65efcfce | 721 | { |
d62a17ae | 722 | vnc_zebra_add_del_nve(bgp, rfd, 0); |
65efcfce LB |
723 | } |
724 | ||
d62a17ae | 725 | static void vnc_zebra_add_del_group_afi(struct bgp *bgp, |
726 | struct rfapi_nve_group_cfg *rfg, | |
727 | afi_t afi, int add) | |
65efcfce | 728 | { |
fe08ba7e DS |
729 | struct agg_table *rt = NULL; |
730 | struct agg_node *rn; | |
d62a17ae | 731 | struct rfapi_import_table *import_table; |
732 | uint8_t family = afi2family(afi); | |
733 | ||
734 | struct list *nves = NULL; | |
a74e593b | 735 | unsigned int nexthop_count = 0; |
d62a17ae | 736 | void *nh_ary = NULL; |
737 | void *nhp_ary = NULL; | |
738 | ||
739 | vnc_zlog_debug_verbose("%s: entry", __func__); | |
740 | import_table = rfg->rfapi_import_table; | |
741 | if (!import_table) { | |
742 | vnc_zlog_debug_verbose( | |
743 | "%s: import table not defined, returning", __func__); | |
744 | return; | |
745 | } | |
746 | ||
747 | if (afi == AFI_IP || afi == AFI_IP6) { | |
748 | rt = import_table->imported_vpn[afi]; | |
749 | } else { | |
450971aa | 750 | flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi); |
d62a17ae | 751 | return; |
752 | } | |
753 | ||
754 | if (!family) { | |
450971aa | 755 | flog_err(EC_LIB_DEVELOPMENT, "%s: computed bad family: %d", |
1c50c1c0 | 756 | __func__, family); |
d62a17ae | 757 | return; |
758 | } | |
759 | ||
760 | if (!rfg->nves) { | |
761 | /* avoid segfault below if list doesn't exist */ | |
762 | vnc_zlog_debug_verbose("%s: no NVEs in this group", __func__); | |
763 | return; | |
764 | } | |
765 | ||
766 | nve_group_to_nve_list(rfg, &nves, family); | |
767 | if (nves) { | |
768 | vnc_zlog_debug_verbose("%s: have nves", __func__); | |
769 | nve_list_to_nh_array(family, nves, &nexthop_count, &nh_ary, | |
770 | &nhp_ary); | |
771 | ||
772 | vnc_zlog_debug_verbose("%s: family: %d, nve count: %d", | |
773 | __func__, family, nexthop_count); | |
774 | ||
6a154c88 | 775 | list_delete(&nves); |
d62a17ae | 776 | |
777 | if (nexthop_count) { | |
778 | /* | |
779 | * Walk the NVE-Group's VNC Import table | |
780 | */ | |
fe08ba7e DS |
781 | for (rn = agg_route_top(rt); rn; |
782 | rn = agg_route_next(rn)) { | |
d62a17ae | 783 | if (rn->info) { |
784 | vnc_zebra_route_msg(&rn->p, | |
785 | nexthop_count, | |
786 | nhp_ary, add); | |
787 | } | |
788 | } | |
789 | } | |
0a22ddfb QY |
790 | XFREE(MTYPE_TMP, nhp_ary); |
791 | XFREE(MTYPE_TMP, nh_ary); | |
d62a17ae | 792 | } |
65efcfce LB |
793 | } |
794 | ||
d62a17ae | 795 | void vnc_zebra_add_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg) |
65efcfce | 796 | { |
d62a17ae | 797 | vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP, 1); |
798 | vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP6, 1); | |
65efcfce LB |
799 | } |
800 | ||
d62a17ae | 801 | void vnc_zebra_del_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg) |
65efcfce | 802 | { |
d62a17ae | 803 | vnc_zlog_debug_verbose("%s: entry", __func__); |
804 | vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP, 0); | |
805 | vnc_zebra_add_del_group_afi(bgp, rfg, AFI_IP6, 0); | |
65efcfce LB |
806 | } |
807 | ||
d62a17ae | 808 | void vnc_zebra_reexport_group_afi(struct bgp *bgp, |
809 | struct rfapi_nve_group_cfg *rfg, afi_t afi) | |
65efcfce | 810 | { |
d62a17ae | 811 | struct listnode *node; |
812 | struct rfapi_rfg_name *rfgn; | |
813 | ||
814 | for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, | |
815 | rfgn)) { | |
816 | ||
817 | if (rfgn->rfg == rfg) { | |
818 | vnc_zebra_add_del_group_afi(bgp, rfg, afi, 0); | |
819 | vnc_zebra_add_del_group_afi(bgp, rfg, afi, 1); | |
820 | break; | |
821 | } | |
822 | } | |
65efcfce LB |
823 | } |
824 | ||
825 | ||
826 | /*********************************************************************** | |
827 | * CONTROL INTERFACE | |
828 | ***********************************************************************/ | |
829 | ||
830 | ||
831 | /* Other routes redistribution into BGP. */ | |
d62a17ae | 832 | int vnc_redistribute_set(struct bgp *bgp, afi_t afi, int type) |
65efcfce | 833 | { |
d62a17ae | 834 | if (!bgp->rfapi_cfg) { |
835 | return CMD_WARNING_CONFIG_FAILED; | |
836 | } | |
65efcfce | 837 | |
d62a17ae | 838 | /* Set flag to BGP instance. */ |
839 | bgp->rfapi_cfg->redist[afi][type] = 1; | |
65efcfce | 840 | |
d62a17ae | 841 | // bgp->redist[afi][type] = 1; |
65efcfce | 842 | |
d62a17ae | 843 | /* Return if already redistribute flag is set. */ |
9f2337c9 | 844 | if (vrf_bitmap_check(zclient_vnc->redist[afi][type], VRF_DEFAULT)) |
d62a17ae | 845 | return CMD_WARNING_CONFIG_FAILED; |
65efcfce | 846 | |
d62a17ae | 847 | vrf_bitmap_set(zclient_vnc->redist[afi][type], VRF_DEFAULT); |
65efcfce | 848 | |
9f2337c9 | 849 | // vrf_bitmap_set(zclient_vnc->redist[afi][type], VRF_DEFAULT); |
65efcfce | 850 | |
d62a17ae | 851 | /* Return if zebra connection is not established. */ |
852 | if (zclient_vnc->sock < 0) | |
853 | return CMD_WARNING_CONFIG_FAILED; | |
65efcfce | 854 | |
d62a17ae | 855 | if (BGP_DEBUG(zebra, ZEBRA)) |
856 | vnc_zlog_debug_verbose("Zebra send: redistribute add %s", | |
857 | zebra_route_string(type)); | |
65efcfce | 858 | |
d62a17ae | 859 | /* Send distribute add message to zebra. */ |
860 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient_vnc, afi, type, | |
861 | 0, VRF_DEFAULT); | |
65efcfce | 862 | |
d62a17ae | 863 | return CMD_SUCCESS; |
65efcfce LB |
864 | } |
865 | ||
866 | /* Unset redistribution. */ | |
d62a17ae | 867 | int vnc_redistribute_unset(struct bgp *bgp, afi_t afi, int type) |
65efcfce | 868 | { |
d62a17ae | 869 | vnc_zlog_debug_verbose("%s: type=%d entry", __func__, type); |
870 | ||
871 | if (!bgp->rfapi_cfg) { | |
872 | vnc_zlog_debug_verbose("%s: return (no rfapi_cfg)", __func__); | |
873 | return CMD_WARNING_CONFIG_FAILED; | |
874 | } | |
875 | ||
876 | /* Unset flag from BGP instance. */ | |
877 | bgp->rfapi_cfg->redist[afi][type] = 0; | |
878 | ||
879 | /* Return if zebra connection is disabled. */ | |
9f2337c9 | 880 | if (!vrf_bitmap_check(zclient_vnc->redist[afi][type], VRF_DEFAULT)) |
d62a17ae | 881 | return CMD_WARNING_CONFIG_FAILED; |
9f2337c9 | 882 | vrf_bitmap_unset(zclient_vnc->redist[afi][type], VRF_DEFAULT); |
d62a17ae | 883 | |
884 | if (bgp->rfapi_cfg->redist[AFI_IP][type] == 0 | |
885 | && bgp->rfapi_cfg->redist[AFI_IP6][type] == 0 | |
886 | && zclient_vnc->sock >= 0) { | |
887 | /* Send distribute delete message to zebra. */ | |
888 | if (BGP_DEBUG(zebra, ZEBRA)) | |
889 | vnc_zlog_debug_verbose( | |
890 | "Zebra send: redistribute delete %s", | |
891 | zebra_route_string(type)); | |
892 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient_vnc, | |
893 | afi, type, 0, VRF_DEFAULT); | |
894 | } | |
895 | ||
896 | /* Withdraw redistributed routes from current BGP's routing table. */ | |
897 | vnc_redistribute_withdraw(bgp, afi, type); | |
898 | ||
899 | vnc_zlog_debug_verbose("%s: return", __func__); | |
900 | ||
901 | return CMD_SUCCESS; | |
65efcfce LB |
902 | } |
903 | ||
342213ea | 904 | extern struct zebra_privs_t bgpd_privs; |
65efcfce LB |
905 | |
906 | /* | |
907 | * Modeled after bgp_zebra.c'bgp_zebra_init() | |
908 | * Charriere asks, "Is it possible to carry two?" | |
909 | */ | |
d62a17ae | 910 | void vnc_zebra_init(struct thread_master *master) |
65efcfce | 911 | { |
d62a17ae | 912 | /* Set default values. */ |
26f63a1e | 913 | zclient_vnc = zclient_new(master, &zclient_options_default); |
342213ea | 914 | zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs); |
d62a17ae | 915 | |
74489921 RW |
916 | zclient_vnc->redistribute_route_add = vnc_zebra_read_route; |
917 | zclient_vnc->redistribute_route_del = vnc_zebra_read_route; | |
65efcfce LB |
918 | } |
919 | ||
d62a17ae | 920 | void vnc_zebra_destroy(void) |
65efcfce | 921 | { |
d62a17ae | 922 | if (zclient_vnc == NULL) |
923 | return; | |
924 | zclient_stop(zclient_vnc); | |
925 | zclient_free(zclient_vnc); | |
926 | zclient_vnc = NULL; | |
65efcfce | 927 | } |