]>
Commit | Line | Data |
---|---|---|
eb5d44eb | 1 | /* |
d62a17ae | 2 | * IS-IS Rout(e)ing protocol - isis_zebra.c |
eb5d44eb | 3 | * |
4 | * Copyright (C) 2001,2002 Sampo Saaristo | |
d62a17ae | 5 | * Tampere University of Technology |
eb5d44eb | 6 | * Institute of Communications Engineering |
f3ccedaa | 7 | * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org> |
eb5d44eb | 8 | * |
d62a17ae | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public Licenseas published by the Free | |
11 | * Software Foundation; either version 2 of the License, or (at your option) | |
eb5d44eb | 12 | * any later version. |
13 | * | |
d62a17ae | 14 | * This program is distributed in the hope that it will be useful,but WITHOUT |
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
eb5d44eb | 17 | * more details. |
896014f4 DL |
18 | * |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; see the file COPYING; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
eb5d44eb | 22 | */ |
23 | ||
24 | #include <zebra.h> | |
eb5d44eb | 25 | |
26 | #include "thread.h" | |
27 | #include "command.h" | |
28 | #include "memory.h" | |
29 | #include "log.h" | |
30 | #include "if.h" | |
31 | #include "network.h" | |
32 | #include "prefix.h" | |
33 | #include "zclient.h" | |
34 | #include "stream.h" | |
35 | #include "linklist.h" | |
f3ccedaa | 36 | #include "nexthop.h" |
7076bb2f | 37 | #include "vrf.h" |
8879bd22 | 38 | #include "libfrr.h" |
eb5d44eb | 39 | |
40 | #include "isisd/isis_constants.h" | |
41 | #include "isisd/isis_common.h" | |
3f045a08 JB |
42 | #include "isisd/isis_flags.h" |
43 | #include "isisd/isis_misc.h" | |
44 | #include "isisd/isis_circuit.h" | |
c89c05dd | 45 | #include "isisd/isisd.h" |
eb5d44eb | 46 | #include "isisd/isis_circuit.h" |
47 | #include "isisd/isis_csm.h" | |
3f045a08 | 48 | #include "isisd/isis_lsp.h" |
eb5d44eb | 49 | #include "isisd/isis_route.h" |
50 | #include "isisd/isis_zebra.h" | |
f8c06e2c | 51 | #include "isisd/isis_te.h" |
eb5d44eb | 52 | |
53 | struct zclient *zclient = NULL; | |
54 | ||
18a6dce6 | 55 | /* Router-id update message from zebra. */ |
121f9dee | 56 | static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) |
18a6dce6 | 57 | { |
d62a17ae | 58 | struct isis_area *area; |
59 | struct listnode *node; | |
60 | struct prefix router_id; | |
61 | ||
d62a17ae | 62 | zebra_router_id_update_read(zclient->ibuf, &router_id); |
63 | if (isis->router_id == router_id.u.prefix4.s_addr) | |
64 | return 0; | |
65 | ||
66 | isis->router_id = router_id.u.prefix4.s_addr; | |
67 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) | |
68 | if (listcount(area->area_addrs) > 0) | |
69 | lsp_regenerate_schedule(area, area->is_type, 0); | |
70 | ||
71 | return 0; | |
18a6dce6 | 72 | } |
eb5d44eb | 73 | |
121f9dee | 74 | static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 75 | { |
d62a17ae | 76 | struct interface *ifp; |
eb5d44eb | 77 | |
d62a17ae | 78 | ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); |
f390d2c7 | 79 | |
d62a17ae | 80 | if (if_is_operative(ifp)) |
81 | isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), | |
82 | ifp); | |
f390d2c7 | 83 | |
d62a17ae | 84 | return 0; |
eb5d44eb | 85 | } |
86 | ||
121f9dee | 87 | static int isis_zebra_if_del(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 88 | { |
d62a17ae | 89 | struct interface *ifp; |
90 | struct stream *s; | |
eb5d44eb | 91 | |
d62a17ae | 92 | s = zclient->ibuf; |
93 | ifp = zebra_interface_state_read(s, vrf_id); | |
f390d2c7 | 94 | |
d62a17ae | 95 | if (!ifp) |
96 | return 0; | |
eb5d44eb | 97 | |
d62a17ae | 98 | if (if_is_operative(ifp)) |
99 | zlog_warn("Zebra: got delete of %s, but interface is still up", | |
100 | ifp->name); | |
eb5d44eb | 101 | |
d62a17ae | 102 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp); |
d2fc8896 | 103 | |
d62a17ae | 104 | /* Cannot call if_delete because we should retain the pseudo interface |
105 | in case there is configuration info attached to it. */ | |
106 | if_delete_retain(ifp); | |
f390d2c7 | 107 | |
ff880b78 | 108 | if_set_index(ifp, IFINDEX_INTERNAL); |
d2fc8896 | 109 | |
d62a17ae | 110 | return 0; |
eb5d44eb | 111 | } |
112 | ||
121f9dee | 113 | static int isis_zebra_if_state_up(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 114 | { |
d62a17ae | 115 | struct interface *ifp; |
f390d2c7 | 116 | |
d62a17ae | 117 | ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); |
f390d2c7 | 118 | |
d62a17ae | 119 | if (ifp == NULL) |
120 | return 0; | |
f390d2c7 | 121 | |
d62a17ae | 122 | isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); |
f390d2c7 | 123 | |
d62a17ae | 124 | return 0; |
eb5d44eb | 125 | } |
126 | ||
121f9dee | 127 | static int isis_zebra_if_state_down(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 128 | { |
d62a17ae | 129 | struct interface *ifp; |
130 | struct isis_circuit *circuit; | |
f390d2c7 | 131 | |
d62a17ae | 132 | ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); |
f390d2c7 | 133 | |
d62a17ae | 134 | if (ifp == NULL) |
135 | return 0; | |
f390d2c7 | 136 | |
d62a17ae | 137 | circuit = isis_csm_state_change(IF_DOWN_FROM_Z, |
138 | circuit_scan_by_ifp(ifp), ifp); | |
139 | if (circuit) | |
140 | SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); | |
f390d2c7 | 141 | |
d62a17ae | 142 | return 0; |
eb5d44eb | 143 | } |
144 | ||
121f9dee | 145 | static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 146 | { |
d62a17ae | 147 | struct connected *c; |
148 | struct prefix *p; | |
149 | char buf[PREFIX2STR_BUFFER]; | |
eb5d44eb | 150 | |
d62a17ae | 151 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, |
152 | zclient->ibuf, vrf_id); | |
f390d2c7 | 153 | |
d62a17ae | 154 | if (c == NULL) |
155 | return 0; | |
f390d2c7 | 156 | |
d62a17ae | 157 | p = c->address; |
f390d2c7 | 158 | |
d62a17ae | 159 | prefix2str(p, buf, sizeof(buf)); |
eb5d44eb | 160 | #ifdef EXTREME_DEBUG |
d62a17ae | 161 | if (p->family == AF_INET) |
162 | zlog_debug("connected IP address %s", buf); | |
163 | if (p->family == AF_INET6) | |
164 | zlog_debug("connected IPv6 address %s", buf); | |
eb5d44eb | 165 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 166 | if (if_is_operative(c->ifp)) |
167 | isis_circuit_add_addr(circuit_scan_by_ifp(c->ifp), c); | |
eb5d44eb | 168 | |
d62a17ae | 169 | return 0; |
eb5d44eb | 170 | } |
171 | ||
121f9dee | 172 | static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 173 | { |
d62a17ae | 174 | struct connected *c; |
175 | struct interface *ifp; | |
1cd80845 | 176 | #ifdef EXTREME_DEBUG |
d62a17ae | 177 | struct prefix *p; |
178 | char buf[PREFIX2STR_BUFFER]; | |
1cd80845 | 179 | #endif /* EXTREME_DEBUG */ |
eb5d44eb | 180 | |
d62a17ae | 181 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, |
182 | zclient->ibuf, vrf_id); | |
f390d2c7 | 183 | |
d62a17ae | 184 | if (c == NULL) |
185 | return 0; | |
f390d2c7 | 186 | |
d62a17ae | 187 | ifp = c->ifp; |
f390d2c7 | 188 | |
f891f443 | 189 | #ifdef EXTREME_DEBUG |
d62a17ae | 190 | p = c->address; |
191 | prefix2str(p, buf, sizeof(buf)); | |
f891f443 | 192 | |
d62a17ae | 193 | if (p->family == AF_INET) |
194 | zlog_debug("disconnected IP address %s", buf); | |
195 | if (p->family == AF_INET6) | |
196 | zlog_debug("disconnected IPv6 address %s", buf); | |
f891f443 | 197 | #endif /* EXTREME_DEBUG */ |
f390d2c7 | 198 | |
d62a17ae | 199 | if (if_is_operative(ifp)) |
200 | isis_circuit_del_addr(circuit_scan_by_ifp(ifp), c); | |
201 | connected_free(c); | |
f390d2c7 | 202 | |
d62a17ae | 203 | return 0; |
eb5d44eb | 204 | } |
205 | ||
121f9dee | 206 | static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS) |
f8c06e2c | 207 | { |
d62a17ae | 208 | struct interface *ifp; |
f8c06e2c | 209 | |
edc12762 | 210 | ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id); |
f8c06e2c | 211 | |
d62a17ae | 212 | if (ifp == NULL) |
213 | return 0; | |
f8c06e2c | 214 | |
d62a17ae | 215 | /* Update TE TLV */ |
216 | isis_mpls_te_update(ifp); | |
f8c06e2c | 217 | |
d62a17ae | 218 | return 0; |
f8c06e2c OD |
219 | } |
220 | ||
f80dd32b | 221 | static void isis_zebra_route_add_route(struct prefix *prefix, |
321c1bbb | 222 | struct prefix_ipv6 *src_p, |
f80dd32b | 223 | struct isis_route_info *route_info) |
eb5d44eb | 224 | { |
c0721de4 RW |
225 | struct zapi_route api; |
226 | struct zapi_nexthop *api_nh; | |
d62a17ae | 227 | struct isis_nexthop *nexthop; |
f80dd32b | 228 | struct isis_nexthop6 *nexthop6; |
d62a17ae | 229 | struct listnode *node; |
c0721de4 | 230 | int count = 0; |
d62a17ae | 231 | |
232 | if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) | |
233 | return; | |
234 | ||
c0721de4 RW |
235 | memset(&api, 0, sizeof(api)); |
236 | api.vrf_id = VRF_DEFAULT; | |
7c0cbd0e | 237 | api.type = PROTO_TYPE; |
c0721de4 RW |
238 | api.safi = SAFI_UNICAST; |
239 | api.prefix = *prefix; | |
321c1bbb CF |
240 | if (src_p && src_p->prefixlen) { |
241 | api.src_prefix = *src_p; | |
242 | SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); | |
243 | } | |
c0721de4 RW |
244 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); |
245 | SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); | |
246 | api.metric = route_info->cost; | |
2097cd8a | 247 | #if 0 |
c0721de4 RW |
248 | SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); |
249 | api.distance = route_info->depth; | |
2097cd8a | 250 | #endif |
f390d2c7 | 251 | |
f80dd32b RW |
252 | /* Nexthops */ |
253 | switch (prefix->family) { | |
254 | case AF_INET: | |
255 | for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, | |
256 | nexthop)) { | |
a74e593b RW |
257 | if (count >= MULTIPATH_NUM) |
258 | break; | |
f80dd32b | 259 | api_nh = &api.nexthops[count]; |
fe85601c DS |
260 | if (fabricd) |
261 | api_nh->onlink = true; | |
4a7371e9 | 262 | api_nh->vrf_id = VRF_DEFAULT; |
f80dd32b RW |
263 | /* FIXME: can it be ? */ |
264 | if (nexthop->ip.s_addr != INADDR_ANY) { | |
265 | api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; | |
266 | api_nh->gate.ipv4 = nexthop->ip; | |
267 | } else { | |
268 | api_nh->type = NEXTHOP_TYPE_IFINDEX; | |
269 | } | |
270 | api_nh->ifindex = nexthop->ifindex; | |
271 | count++; | |
d62a17ae | 272 | } |
f80dd32b RW |
273 | break; |
274 | case AF_INET6: | |
275 | for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, | |
276 | nexthop6)) { | |
a74e593b RW |
277 | if (count >= MULTIPATH_NUM) |
278 | break; | |
f80dd32b RW |
279 | if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6) |
280 | && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) { | |
281 | continue; | |
282 | } | |
283 | ||
284 | api_nh = &api.nexthops[count]; | |
fe85601c DS |
285 | if (fabricd) |
286 | api_nh->onlink = true; | |
4a7371e9 | 287 | api_nh->vrf_id = VRF_DEFAULT; |
f80dd32b RW |
288 | api_nh->gate.ipv6 = nexthop6->ip6; |
289 | api_nh->ifindex = nexthop6->ifindex; | |
290 | api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; | |
291 | count++; | |
d62a17ae | 292 | } |
f80dd32b | 293 | break; |
d62a17ae | 294 | } |
c0721de4 RW |
295 | if (!count) |
296 | return; | |
f390d2c7 | 297 | |
c0721de4 | 298 | api.nexthop_num = count; |
f390d2c7 | 299 | |
c0721de4 RW |
300 | zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
301 | SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); | |
302 | UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); | |
eb5d44eb | 303 | } |
304 | ||
f80dd32b | 305 | static void isis_zebra_route_del_route(struct prefix *prefix, |
321c1bbb | 306 | struct prefix_ipv6 *src_p, |
f80dd32b | 307 | struct isis_route_info *route_info) |
eb5d44eb | 308 | { |
c0721de4 | 309 | struct zapi_route api; |
d62a17ae | 310 | |
311 | if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) | |
312 | return; | |
313 | ||
c0721de4 | 314 | memset(&api, 0, sizeof(api)); |
d62a17ae | 315 | api.vrf_id = VRF_DEFAULT; |
7c0cbd0e | 316 | api.type = PROTO_TYPE; |
d62a17ae | 317 | api.safi = SAFI_UNICAST; |
c0721de4 | 318 | api.prefix = *prefix; |
321c1bbb CF |
319 | if (src_p && src_p->prefixlen) { |
320 | api.src_prefix = *src_p; | |
321 | SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); | |
322 | } | |
f390d2c7 | 323 | |
c0721de4 RW |
324 | zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
325 | UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); | |
eb5d44eb | 326 | } |
327 | ||
d62a17ae | 328 | void isis_zebra_route_update(struct prefix *prefix, |
321c1bbb | 329 | struct prefix_ipv6 *src_p, |
d62a17ae | 330 | struct isis_route_info *route_info) |
eb5d44eb | 331 | { |
d62a17ae | 332 | if (zclient->sock < 0) |
333 | return; | |
334 | ||
f80dd32b | 335 | if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) |
321c1bbb | 336 | isis_zebra_route_add_route(prefix, src_p, route_info); |
f80dd32b | 337 | else |
321c1bbb | 338 | isis_zebra_route_del_route(prefix, src_p, route_info); |
eb5d44eb | 339 | } |
340 | ||
121f9dee | 341 | static int isis_zebra_read(ZAPI_CALLBACK_ARGS) |
eb5d44eb | 342 | { |
74489921 | 343 | struct zapi_route api; |
d62a17ae | 344 | |
74489921 RW |
345 | if (zapi_route_decode(zclient->ibuf, &api) < 0) |
346 | return -1; | |
d62a17ae | 347 | |
9fb2b879 DS |
348 | if (api.prefix.family == AF_INET6 |
349 | && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) | |
350 | return 0; | |
351 | ||
d62a17ae | 352 | /* |
353 | * Avoid advertising a false default reachability. (A default | |
354 | * route installed by IS-IS gets redistributed from zebra back | |
355 | * into IS-IS causing us to start advertising default reachabity | |
356 | * without this check) | |
357 | */ | |
d43d2df5 CF |
358 | if (api.prefix.prefixlen == 0 |
359 | && api.src_prefix.prefixlen == 0 | |
7c0cbd0e | 360 | && api.type == PROTO_TYPE) { |
121f9dee | 361 | cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL; |
d43d2df5 | 362 | } |
d62a17ae | 363 | |
121f9dee | 364 | if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) |
d43d2df5 CF |
365 | isis_redist_add(api.type, &api.prefix, &api.src_prefix, |
366 | api.distance, api.metric); | |
d62a17ae | 367 | else |
d43d2df5 | 368 | isis_redist_delete(api.type, &api.prefix, &api.src_prefix); |
d62a17ae | 369 | |
370 | return 0; | |
eb5d44eb | 371 | } |
eb5d44eb | 372 | |
d62a17ae | 373 | int isis_distribute_list_update(int routetype) |
eb5d44eb | 374 | { |
d62a17ae | 375 | return 0; |
eb5d44eb | 376 | } |
377 | ||
d62a17ae | 378 | void isis_zebra_redistribute_set(afi_t afi, int type) |
eb5d44eb | 379 | { |
d62a17ae | 380 | if (type == DEFAULT_ROUTE) |
381 | zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, | |
49db7a7b | 382 | zclient, afi, VRF_DEFAULT); |
d62a17ae | 383 | else |
384 | zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type, | |
385 | 0, VRF_DEFAULT); | |
f3ccedaa CF |
386 | } |
387 | ||
d62a17ae | 388 | void isis_zebra_redistribute_unset(afi_t afi, int type) |
f3ccedaa | 389 | { |
d62a17ae | 390 | if (type == DEFAULT_ROUTE) |
391 | zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, | |
49db7a7b | 392 | zclient, afi, VRF_DEFAULT); |
d62a17ae | 393 | else |
394 | zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, | |
395 | type, 0, VRF_DEFAULT); | |
eb5d44eb | 396 | } |
397 | ||
d62a17ae | 398 | static void isis_zebra_connected(struct zclient *zclient) |
7076bb2f | 399 | { |
d62a17ae | 400 | zclient_send_reg_requests(zclient, VRF_DEFAULT); |
7076bb2f FL |
401 | } |
402 | ||
d62a17ae | 403 | void isis_zebra_init(struct thread_master *master) |
eb5d44eb | 404 | { |
26f63a1e | 405 | zclient = zclient_new(master, &zclient_options_default); |
7c0cbd0e | 406 | zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs); |
d62a17ae | 407 | zclient->zebra_connected = isis_zebra_connected; |
408 | zclient->router_id_update = isis_router_id_update_zebra; | |
409 | zclient->interface_add = isis_zebra_if_add; | |
410 | zclient->interface_delete = isis_zebra_if_del; | |
411 | zclient->interface_up = isis_zebra_if_state_up; | |
412 | zclient->interface_down = isis_zebra_if_state_down; | |
413 | zclient->interface_address_add = isis_zebra_if_address_add; | |
414 | zclient->interface_address_delete = isis_zebra_if_address_del; | |
415 | zclient->interface_link_params = isis_zebra_link_params; | |
74489921 RW |
416 | zclient->redistribute_route_add = isis_zebra_read; |
417 | zclient->redistribute_route_del = isis_zebra_read; | |
d62a17ae | 418 | |
419 | return; | |
eb5d44eb | 420 | } |
8d429559 | 421 | |
d62a17ae | 422 | void isis_zebra_stop(void) |
8d429559 | 423 | { |
d62a17ae | 424 | zclient_stop(zclient); |
425 | zclient_free(zclient); | |
8879bd22 | 426 | frr_fini(); |
8d429559 | 427 | } |