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