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