]>
Commit | Line | Data |
---|---|---|
fb018d25 DS |
1 | /* BGP Nexthop tracking |
2 | * Copyright (C) 2013 Cumulus Networks, Inc. | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | * 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | #include "command.h" | |
25 | #include "thread.h" | |
26 | #include "prefix.h" | |
27 | #include "zclient.h" | |
28 | #include "stream.h" | |
29 | #include "network.h" | |
30 | #include "log.h" | |
31 | #include "memory.h" | |
32 | #include "nexthop.h" | |
7076bb2f | 33 | #include "vrf.h" |
fb018d25 DS |
34 | |
35 | #include "bgpd/bgpd.h" | |
36 | #include "bgpd/bgp_table.h" | |
37 | #include "bgpd/bgp_route.h" | |
38 | #include "bgpd/bgp_attr.h" | |
39 | #include "bgpd/bgp_nexthop.h" | |
40 | #include "bgpd/bgp_debug.h" | |
41 | #include "bgpd/bgp_nht.h" | |
ffd0c037 | 42 | #include "bgpd/bgp_fsm.h" |
fb018d25 DS |
43 | |
44 | extern struct zclient *zclient; | |
45 | extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; | |
078430f6 | 46 | extern struct bgp_table *bgp_import_check_table[AFI_MAX]; |
fb018d25 | 47 | |
078430f6 DS |
48 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, |
49 | int is_bgp_static_route); | |
50 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, | |
51 | int is_bgp_static_route); | |
fb018d25 DS |
52 | static void evaluate_paths(struct bgp_nexthop_cache *bnc); |
53 | static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p); | |
54 | static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, | |
55 | int keep); | |
56 | ||
57 | int | |
fc9a856f | 58 | bgp_find_nexthop (struct bgp_info *path, int connected) |
fb018d25 DS |
59 | { |
60 | struct bgp_nexthop_cache *bnc = path->nexthop; | |
61 | ||
62 | if (!bnc) | |
63 | return 0; | |
64 | ||
fc9a856f DS |
65 | if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) |
66 | return 0; | |
fb018d25 DS |
67 | |
68 | return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); | |
69 | } | |
70 | ||
71 | void | |
72 | bgp_unlink_nexthop (struct bgp_info *path) | |
73 | { | |
74 | struct bgp_nexthop_cache *bnc = path->nexthop; | |
75 | ||
76 | if (!bnc) | |
77 | return; | |
78 | ||
79 | path_nh_map(path, NULL, 0); | |
80 | ||
fc9a856f | 81 | if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) |
fb018d25 DS |
82 | { |
83 | if (BGP_DEBUG(nht, NHT)) | |
84 | { | |
85 | char buf[INET6_ADDRSTRLEN]; | |
86 | zlog_debug("bgp_unlink_nexthop: freeing bnc %s", | |
87 | bnc_str(bnc, buf, INET6_ADDRSTRLEN)); | |
88 | } | |
078430f6 | 89 | unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); |
fb018d25 DS |
90 | bnc->node->info = NULL; |
91 | bgp_unlock_node(bnc->node); | |
92 | bnc_free(bnc); | |
93 | } | |
94 | } | |
95 | ||
96 | int | |
75aead62 DS |
97 | bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri, |
98 | struct peer *peer, int connected) | |
fb018d25 DS |
99 | { |
100 | struct bgp_node *rn; | |
101 | struct bgp_nexthop_cache *bnc; | |
102 | struct prefix p; | |
078430f6 | 103 | int is_bgp_static_route = 0; |
fb018d25 | 104 | |
fc9a856f DS |
105 | if (ri) |
106 | { | |
8a92a8a0 DS |
107 | is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) && |
108 | (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0; | |
109 | ||
110 | /* Since Extended Next-hop Encoding (RFC5549) support, we want to derive | |
111 | address-family from the next-hop. */ | |
112 | if (!is_bgp_static_route) | |
113 | afi = BGP_ATTR_NEXTHOP_AFI_IP6(ri->attr) ? AFI_IP6 : AFI_IP; | |
114 | ||
65740e1b | 115 | /* This will return TRUE if the global IPv6 NH is a link local addr */ |
fc9a856f DS |
116 | if (make_prefix(afi, ri, &p) < 0) |
117 | return 1; | |
118 | } | |
119 | else if (peer) | |
120 | { | |
121 | if (afi == AFI_IP) | |
122 | { | |
123 | p.family = AF_INET; | |
124 | p.prefixlen = IPV4_MAX_BITLEN; | |
125 | p.u.prefix4 = peer->su.sin.sin_addr; | |
126 | } | |
127 | else if (afi == AFI_IP6) | |
128 | { | |
129 | p.family = AF_INET6; | |
130 | p.prefixlen = IPV6_MAX_BITLEN; | |
131 | p.u.prefix6 = peer->su.sin6.sin6_addr; | |
65740e1b DS |
132 | |
133 | /* Don't register link local NH */ | |
134 | if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) | |
135 | return 1; | |
136 | } | |
137 | else | |
138 | { | |
139 | if (BGP_DEBUG(nht, NHT)) | |
140 | { | |
141 | zlog_debug("%s: Attempting to register with unknown AFI %d (not %d or %d)", | |
142 | __FUNCTION__, afi, AFI_IP, AFI_IP6); | |
143 | } | |
144 | return 0; | |
fc9a856f DS |
145 | } |
146 | } | |
65740e1b DS |
147 | else |
148 | return 0; | |
fc9a856f | 149 | |
078430f6 DS |
150 | if (is_bgp_static_route) |
151 | rn = bgp_node_get (bgp_import_check_table[afi], &p); | |
152 | else | |
153 | rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p); | |
fb018d25 DS |
154 | |
155 | if (!rn->info) | |
156 | { | |
157 | bnc = bnc_new(); | |
158 | rn->info = bnc; | |
159 | bnc->node = rn; | |
75aead62 | 160 | bnc->bgp = bgp; |
fb018d25 | 161 | bgp_lock_node(rn); |
9a233a02 DS |
162 | if (BGP_DEBUG(nht, NHT)) |
163 | { | |
164 | char buf[INET6_ADDRSTRLEN]; | |
165 | ||
078430f6 | 166 | zlog_debug("Allocated bnc %s peer %p", |
9a233a02 DS |
167 | bnc_str(bnc, buf, INET6_ADDRSTRLEN), peer); |
168 | } | |
fb018d25 | 169 | } |
fc9a856f | 170 | |
fb018d25 DS |
171 | bnc = rn->info; |
172 | bgp_unlock_node (rn); | |
fb018d25 | 173 | |
078430f6 DS |
174 | if (is_bgp_static_route) |
175 | { | |
176 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); | |
177 | ||
178 | /* If we're toggling the type, re-register */ | |
5623e905 | 179 | if ((bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) && |
078430f6 DS |
180 | !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) |
181 | { | |
182 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
183 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
184 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
185 | } | |
5623e905 | 186 | else if ((!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) && |
078430f6 DS |
187 | CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) |
188 | { | |
189 | UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
190 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
191 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
192 | } | |
193 | } | |
194 | else if (connected && ! CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) | |
195 | { | |
196 | SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
197 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
198 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
199 | } | |
200 | else if (!connected && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) | |
201 | { | |
202 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
203 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
204 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
205 | } | |
206 | ||
fc9a856f | 207 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) |
078430f6 | 208 | register_zebra_rnh(bnc, is_bgp_static_route); |
fb018d25 | 209 | |
22a29185 | 210 | if (ri && ri->nexthop != bnc) |
fc9a856f | 211 | { |
22a29185 DS |
212 | /* Unlink from existing nexthop cache, if any. This will also free |
213 | * the nexthop cache entry, if appropriate. | |
214 | */ | |
215 | bgp_unlink_nexthop (ri); | |
216 | ||
217 | /* Link to new nexthop cache. */ | |
fc9a856f | 218 | path_nh_map(ri, bnc, 1); |
fb018d25 | 219 | |
fc9a856f DS |
220 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) |
221 | (bgp_info_extra_get(ri))->igpmetric = bnc->metric; | |
222 | else if (ri->extra) | |
223 | ri->extra->igpmetric = 0; | |
224 | } | |
225 | else if (peer) | |
226 | bnc->nht_info = (void *)peer; | |
fb018d25 DS |
227 | |
228 | return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); | |
229 | } | |
230 | ||
9a233a02 DS |
231 | void |
232 | bgp_delete_connected_nexthop (afi_t afi, struct peer *peer) | |
233 | { | |
234 | struct bgp_node *rn; | |
235 | struct bgp_nexthop_cache *bnc; | |
236 | struct prefix p; | |
237 | ||
65740e1b DS |
238 | if (!peer) |
239 | return; | |
240 | ||
9a233a02 DS |
241 | if (afi == AFI_IP) |
242 | { | |
243 | p.family = AF_INET; | |
244 | p.prefixlen = IPV4_MAX_BITLEN; | |
245 | p.u.prefix4 = peer->su.sin.sin_addr; | |
246 | } | |
247 | else if (afi == AFI_IP6) | |
248 | { | |
249 | p.family = AF_INET6; | |
250 | p.prefixlen = IPV6_MAX_BITLEN; | |
251 | p.u.prefix6 = peer->su.sin6.sin6_addr; | |
65740e1b DS |
252 | |
253 | /* We don't register link local address for NHT */ | |
254 | if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) | |
255 | return; | |
9a233a02 | 256 | } |
65740e1b DS |
257 | else |
258 | return; | |
9a233a02 DS |
259 | |
260 | rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); | |
261 | if (!rn || !rn->info) | |
262 | { | |
263 | if (BGP_DEBUG(nht, NHT)) | |
264 | zlog_debug("Cannot find connected NHT node for peer %s", peer->host); | |
265 | if (rn) | |
266 | bgp_unlock_node (rn); | |
267 | return; | |
268 | } | |
269 | ||
270 | bnc = rn->info; | |
271 | bgp_unlock_node(rn); | |
272 | ||
273 | if (bnc->nht_info != peer) | |
274 | { | |
275 | if (BGP_DEBUG(nht, NHT)) | |
276 | zlog_debug("Connected NHT %p node for peer %s points to %p", | |
277 | bnc, peer->host, bnc->nht_info); | |
278 | return; | |
279 | } | |
280 | ||
281 | bnc->nht_info = NULL; | |
282 | ||
283 | if (LIST_EMPTY(&(bnc->paths))) | |
284 | { | |
285 | if (BGP_DEBUG(nht, NHT)) | |
286 | zlog_debug("Freeing connected NHT node %p for peer %s", | |
287 | bnc, peer->host); | |
078430f6 | 288 | unregister_zebra_rnh(bnc, 0); |
9a233a02 DS |
289 | bnc->node->info = NULL; |
290 | bgp_unlock_node(bnc->node); | |
291 | bnc_free(bnc); | |
292 | } | |
293 | } | |
294 | ||
fb018d25 | 295 | void |
7076bb2f | 296 | bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) |
fb018d25 DS |
297 | { |
298 | struct stream *s; | |
ffd0c037 | 299 | struct bgp_node *rn = NULL; |
fb018d25 DS |
300 | struct bgp_nexthop_cache *bnc; |
301 | struct nexthop *nexthop; | |
302 | struct nexthop *oldnh; | |
303 | struct nexthop *nhlist_head = NULL; | |
304 | struct nexthop *nhlist_tail = NULL; | |
305 | uint32_t metric; | |
306 | u_char nexthop_num; | |
307 | struct prefix p; | |
308 | int i; | |
309 | ||
310 | s = zclient->ibuf; | |
311 | ||
312 | memset(&p, 0, sizeof(struct prefix)); | |
313 | p.family = stream_getw(s); | |
314 | p.prefixlen = stream_getc(s); | |
315 | switch (p.family) | |
316 | { | |
317 | case AF_INET: | |
318 | p.u.prefix4.s_addr = stream_get_ipv4 (s); | |
319 | break; | |
320 | case AF_INET6: | |
321 | stream_get(&p.u.prefix6, s, 16); | |
322 | break; | |
323 | default: | |
324 | break; | |
325 | } | |
326 | ||
078430f6 DS |
327 | if (command == ZEBRA_NEXTHOP_UPDATE) |
328 | rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); | |
329 | else if (command == ZEBRA_IMPORT_CHECK_UPDATE) | |
330 | rn = bgp_node_lookup(bgp_import_check_table[family2afi(p.family)], &p); | |
331 | ||
fb018d25 DS |
332 | if (!rn || !rn->info) |
333 | { | |
334 | if (BGP_DEBUG(nht, NHT)) | |
335 | { | |
336 | char buf[INET6_ADDRSTRLEN]; | |
337 | prefix2str(&p, buf, INET6_ADDRSTRLEN); | |
338 | zlog_debug("parse nexthop update(%s): rn not found", buf); | |
339 | } | |
7898cb4f DS |
340 | if (rn) |
341 | bgp_unlock_node (rn); | |
fb018d25 DS |
342 | return; |
343 | } | |
344 | ||
345 | bnc = rn->info; | |
7898cb4f | 346 | bgp_unlock_node (rn); |
fb018d25 DS |
347 | bnc->last_update = bgp_clock(); |
348 | bnc->change_flags = 0; | |
349 | metric = stream_getl (s); | |
350 | nexthop_num = stream_getc (s); | |
351 | ||
352 | /* debug print the input */ | |
353 | if (BGP_DEBUG(nht, NHT)) | |
354 | { | |
355 | char buf[INET6_ADDRSTRLEN]; | |
356 | prefix2str(&p, buf, INET6_ADDRSTRLEN); | |
357 | zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf, | |
358 | metric, nexthop_num); | |
359 | } | |
360 | ||
361 | if (metric != bnc->metric) | |
362 | bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; | |
363 | ||
364 | if(nexthop_num != bnc->nexthop_num) | |
365 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; | |
366 | ||
367 | if (nexthop_num) | |
368 | { | |
9ff31ad5 DS |
369 | /* notify bgp fsm if nbr ip goes from invalid->valid */ |
370 | if (!bnc->nexthop_num) | |
371 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
372 | ||
fb018d25 DS |
373 | bnc->flags |= BGP_NEXTHOP_VALID; |
374 | bnc->metric = metric; | |
375 | bnc->nexthop_num = nexthop_num; | |
376 | ||
377 | for (i = 0; i < nexthop_num; i++) | |
378 | { | |
379 | nexthop = nexthop_new(); | |
380 | nexthop->type = stream_getc (s); | |
381 | switch (nexthop->type) | |
382 | { | |
383 | case ZEBRA_NEXTHOP_IPV4: | |
384 | nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); | |
385 | break; | |
386 | case ZEBRA_NEXTHOP_IFINDEX: | |
387 | case ZEBRA_NEXTHOP_IFNAME: | |
388 | nexthop->ifindex = stream_getl (s); | |
389 | break; | |
390 | case ZEBRA_NEXTHOP_IPV4_IFINDEX: | |
391 | case ZEBRA_NEXTHOP_IPV4_IFNAME: | |
392 | nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); | |
393 | nexthop->ifindex = stream_getl (s); | |
394 | break; | |
395 | #ifdef HAVE_IPV6 | |
396 | case ZEBRA_NEXTHOP_IPV6: | |
397 | stream_get (&nexthop->gate.ipv6, s, 16); | |
398 | break; | |
399 | case ZEBRA_NEXTHOP_IPV6_IFINDEX: | |
400 | case ZEBRA_NEXTHOP_IPV6_IFNAME: | |
401 | stream_get (&nexthop->gate.ipv6, s, 16); | |
402 | nexthop->ifindex = stream_getl (s); | |
403 | break; | |
404 | #endif | |
405 | default: | |
406 | /* do nothing */ | |
407 | break; | |
408 | } | |
409 | ||
410 | if (nhlist_tail) | |
411 | { | |
412 | nhlist_tail->next = nexthop; | |
413 | nhlist_tail = nexthop; | |
414 | } | |
415 | else | |
416 | { | |
417 | nhlist_tail = nexthop; | |
418 | nhlist_head = nexthop; | |
419 | } | |
420 | ||
421 | /* No need to evaluate the nexthop if we have already determined | |
422 | * that there has been a change. | |
423 | */ | |
424 | if (bnc->change_flags & BGP_NEXTHOP_CHANGED) | |
425 | continue; | |
426 | ||
427 | for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) | |
428 | if (nexthop_same_no_recurse(oldnh, nexthop)) | |
429 | break; | |
430 | ||
431 | if (!oldnh) | |
9ff31ad5 | 432 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; |
fb018d25 DS |
433 | } |
434 | bnc_nexthop_free(bnc); | |
435 | bnc->nexthop = nhlist_head; | |
436 | } | |
437 | else | |
438 | { | |
439 | bnc->flags &= ~BGP_NEXTHOP_VALID; | |
9ff31ad5 DS |
440 | bnc->nexthop_num = nexthop_num; |
441 | ||
442 | /* notify bgp fsm if nbr ip goes from valid->invalid */ | |
fc9a856f | 443 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); |
9ff31ad5 | 444 | |
fb018d25 DS |
445 | bnc_nexthop_free(bnc); |
446 | bnc->nexthop = NULL; | |
447 | } | |
448 | ||
449 | evaluate_paths(bnc); | |
450 | } | |
451 | ||
452 | /** | |
453 | * make_prefix - make a prefix structure from the path (essentially | |
454 | * path's node. | |
455 | */ | |
456 | static int | |
457 | make_prefix (int afi, struct bgp_info *ri, struct prefix *p) | |
458 | { | |
078430f6 DS |
459 | |
460 | int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) && | |
461 | (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0; | |
462 | ||
fb018d25 DS |
463 | memset (p, 0, sizeof (struct prefix)); |
464 | switch (afi) | |
465 | { | |
466 | case AFI_IP: | |
467 | p->family = AF_INET; | |
078430f6 DS |
468 | if (is_bgp_static) |
469 | { | |
470 | p->u.prefix4 = ri->net->p.u.prefix4; | |
471 | p->prefixlen = ri->net->p.prefixlen; | |
472 | } | |
473 | else | |
474 | { | |
475 | p->u.prefix4 = ri->attr->nexthop; | |
476 | p->prefixlen = IPV4_MAX_BITLEN; | |
477 | } | |
fb018d25 DS |
478 | break; |
479 | #ifdef HAVE_IPV6 | |
480 | case AFI_IP6: | |
65740e1b | 481 | /* We don't register link local NH */ |
801a9bcc | 482 | if (ri->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL |
fb018d25 DS |
483 | || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global)) |
484 | return -1; | |
485 | ||
486 | p->family = AF_INET6; | |
078430f6 DS |
487 | |
488 | if (is_bgp_static) | |
489 | { | |
490 | p->u.prefix6 = ri->net->p.u.prefix6; | |
491 | p->prefixlen = ri->net->p.prefixlen; | |
492 | } | |
493 | else | |
494 | { | |
495 | p->u.prefix6 = ri->attr->extra->mp_nexthop_global; | |
496 | p->prefixlen = IPV6_MAX_BITLEN; | |
497 | } | |
fb018d25 DS |
498 | break; |
499 | #endif | |
500 | default: | |
65740e1b DS |
501 | if (BGP_DEBUG(nht, NHT)) |
502 | { | |
503 | zlog_debug("%s: Attempting to make prefix with unknown AFI %d (not %d or %d)", | |
504 | __FUNCTION__, afi, AFI_IP, AFI_IP6); | |
505 | } | |
fb018d25 DS |
506 | break; |
507 | } | |
508 | return 0; | |
509 | } | |
510 | ||
511 | /** | |
078430f6 | 512 | * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister |
fb018d25 DS |
513 | * command to Zebra. |
514 | * ARGUMENTS: | |
515 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
078430f6 | 516 | * int command -- command to send to zebra |
fb018d25 DS |
517 | * RETURNS: |
518 | * void. | |
519 | */ | |
520 | static void | |
078430f6 | 521 | sendmsg_zebra_rnh (struct bgp_nexthop_cache *bnc, int command) |
fb018d25 DS |
522 | { |
523 | struct stream *s; | |
524 | struct prefix *p; | |
525 | int ret; | |
526 | ||
527 | /* Check socket. */ | |
528 | if (!zclient || zclient->sock < 0) | |
fc9a856f | 529 | { |
7076bb2f FL |
530 | /* Pending: hiding this error now, because bgp_nht_register_all() is implemented. |
531 | which tries it after zclient_connect() | |
532 | zlog_debug("%s: Can't send NH register, Zebra client not established", | |
fc9a856f | 533 | __FUNCTION__); |
7076bb2f | 534 | */ |
fc9a856f DS |
535 | return; |
536 | } | |
fb018d25 DS |
537 | |
538 | p = &(bnc->node->p); | |
539 | s = zclient->obuf; | |
540 | stream_reset (s); | |
7076bb2f | 541 | zclient_create_header (s, command, VRF_DEFAULT); |
078430f6 DS |
542 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) || |
543 | CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) | |
fc9a856f DS |
544 | stream_putc(s, 1); |
545 | else | |
546 | stream_putc(s, 0); | |
547 | ||
fb018d25 DS |
548 | stream_putw(s, PREFIX_FAMILY(p)); |
549 | stream_putc(s, p->prefixlen); | |
550 | switch (PREFIX_FAMILY(p)) | |
551 | { | |
552 | case AF_INET: | |
553 | stream_put_in_addr (s, &p->u.prefix4); | |
554 | break; | |
555 | #ifdef HAVE_IPV6 | |
556 | case AF_INET6: | |
557 | stream_put(s, &(p->u.prefix6), 16); | |
558 | break; | |
559 | #endif | |
560 | default: | |
561 | break; | |
562 | } | |
563 | stream_putw_at (s, 0, stream_get_endp (s)); | |
564 | ||
565 | ret = zclient_send_message(zclient); | |
566 | /* TBD: handle the failure */ | |
567 | if (ret < 0) | |
568 | zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); | |
fc9a856f | 569 | |
078430f6 DS |
570 | if ((command == ZEBRA_NEXTHOP_REGISTER) || |
571 | (command == ZEBRA_IMPORT_ROUTE_REGISTER)) | |
fc9a856f | 572 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
078430f6 DS |
573 | else if ((command == ZEBRA_NEXTHOP_UNREGISTER) || |
574 | (command == ZEBRA_IMPORT_ROUTE_UNREGISTER)) | |
fc9a856f | 575 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
fb018d25 DS |
576 | return; |
577 | } | |
578 | ||
579 | /** | |
078430f6 DS |
580 | * register_zebra_rnh - register a NH/route with Zebra for notification |
581 | * when the route or the route to the nexthop changes. | |
fb018d25 | 582 | * ARGUMENTS: |
078430f6 | 583 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
584 | * RETURNS: |
585 | * void. | |
586 | */ | |
587 | static void | |
078430f6 | 588 | register_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route) |
fb018d25 DS |
589 | { |
590 | /* Check if we have already registered */ | |
591 | if (bnc->flags & BGP_NEXTHOP_REGISTERED) | |
592 | return; | |
078430f6 DS |
593 | if (is_bgp_import_route) |
594 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER); | |
595 | else | |
596 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); | |
fb018d25 DS |
597 | } |
598 | ||
599 | /** | |
078430f6 | 600 | * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra. |
fb018d25 | 601 | * ARGUMENTS: |
078430f6 | 602 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
603 | * RETURNS: |
604 | * void. | |
605 | */ | |
606 | static void | |
078430f6 | 607 | unregister_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route) |
fb018d25 DS |
608 | { |
609 | /* Check if we have already registered */ | |
610 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
611 | return; | |
612 | ||
078430f6 DS |
613 | if (is_bgp_import_route) |
614 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER); | |
615 | else | |
616 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); | |
fb018d25 DS |
617 | } |
618 | ||
619 | /** | |
620 | * evaluate_paths - Evaluate the paths/nets associated with a nexthop. | |
621 | * ARGUMENTS: | |
622 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
623 | * RETURNS: | |
624 | * void. | |
625 | */ | |
626 | static void | |
627 | evaluate_paths (struct bgp_nexthop_cache *bnc) | |
628 | { | |
629 | struct bgp_node *rn; | |
630 | struct bgp_info *path; | |
75aead62 | 631 | struct bgp *bgp = bnc->bgp; |
fb018d25 | 632 | int afi; |
fc9a856f | 633 | struct peer *peer = (struct peer *)bnc->nht_info; |
fb018d25 DS |
634 | |
635 | LIST_FOREACH(path, &(bnc->paths), nh_thread) | |
636 | { | |
637 | if (!(path->type == ZEBRA_ROUTE_BGP && | |
ffd0c037 DS |
638 | ((path->sub_type == BGP_ROUTE_NORMAL) || |
639 | (path->sub_type == BGP_ROUTE_STATIC)))) | |
fb018d25 DS |
640 | continue; |
641 | ||
642 | rn = path->net; | |
643 | afi = family2afi(rn->p.family); | |
644 | ||
645 | /* Path becomes valid/invalid depending on whether the nexthop | |
646 | * reachable/unreachable. | |
647 | */ | |
648 | if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) != | |
649 | (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0)) | |
650 | { | |
651 | if (CHECK_FLAG (path->flags, BGP_INFO_VALID)) | |
652 | { | |
653 | bgp_aggregate_decrement (bgp, &rn->p, path, | |
654 | afi, SAFI_UNICAST); | |
655 | bgp_info_unset_flag (rn, path, BGP_INFO_VALID); | |
656 | } | |
657 | else | |
658 | { | |
659 | bgp_info_set_flag (rn, path, BGP_INFO_VALID); | |
660 | bgp_aggregate_increment (bgp, &rn->p, path, | |
661 | afi, SAFI_UNICAST); | |
662 | } | |
663 | } | |
664 | ||
665 | /* Copy the metric to the path. Will be used for bestpath computation */ | |
666 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) | |
667 | (bgp_info_extra_get(path))->igpmetric = bnc->metric; | |
668 | else if (path->extra) | |
669 | path->extra->igpmetric = 0; | |
670 | ||
671 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) || | |
672 | CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED)) | |
673 | SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); | |
674 | ||
675 | bgp_process(bgp, rn, afi, SAFI_UNICAST); | |
676 | } | |
fc9a856f DS |
677 | |
678 | if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) | |
679 | { | |
680 | if (BGP_DEBUG(nht, NHT)) | |
681 | zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); | |
682 | bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); | |
683 | SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
684 | } | |
685 | ||
fb018d25 DS |
686 | RESET_FLAG(bnc->change_flags); |
687 | } | |
688 | ||
7076bb2f FL |
689 | void |
690 | bgp_nht_register_all (void) | |
691 | { | |
692 | struct bgp_node *rn; | |
693 | struct bgp_nexthop_cache *bnc; | |
694 | ||
695 | for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) | |
696 | if ((bnc = rn->info) != NULL && | |
697 | !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
698 | { | |
699 | register_zebra_rnh(bnc, 0); | |
700 | } | |
701 | for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) | |
702 | if ((bnc = rn->info) != NULL && | |
703 | !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
704 | { | |
705 | register_zebra_rnh(bnc, 0); | |
706 | } | |
707 | ||
708 | for (rn = bgp_table_top (bgp_import_check_table[AFI_IP]); rn; rn = bgp_route_next (rn)) | |
709 | if ((bnc = rn->info) != NULL && | |
710 | !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
711 | { | |
712 | register_zebra_rnh(bnc, 1); | |
713 | } | |
714 | for (rn = bgp_table_top (bgp_import_check_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) | |
715 | if ((bnc = rn->info) != NULL && | |
716 | !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
717 | { | |
718 | register_zebra_rnh(bnc, 1); | |
719 | } | |
720 | ||
721 | } | |
722 | ||
fb018d25 DS |
723 | /** |
724 | * path_nh_map - make or break path-to-nexthop association. | |
725 | * ARGUMENTS: | |
726 | * path - pointer to the path structure | |
727 | * bnc - pointer to the nexthop structure | |
728 | * make - if set, make the association. if unset, just break the existing | |
729 | * association. | |
730 | */ | |
731 | static void | |
732 | path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make) | |
733 | { | |
734 | if (path->nexthop) | |
735 | { | |
736 | LIST_REMOVE(path, nh_thread); | |
737 | path->nexthop->path_count--; | |
738 | path->nexthop = NULL; | |
739 | } | |
740 | if (make) | |
741 | { | |
742 | LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); | |
743 | path->nexthop = bnc; | |
744 | path->nexthop->path_count++; | |
745 | } | |
746 | } |