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