]>
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 | |
c89c05dd | 40 | #include "isisd/dict.h" |
eb5d44eb | 41 | #include "isisd/isis_constants.h" |
42 | #include "isisd/isis_common.h" | |
3f045a08 JB |
43 | #include "isisd/isis_flags.h" |
44 | #include "isisd/isis_misc.h" | |
45 | #include "isisd/isis_circuit.h" | |
c89c05dd | 46 | #include "isisd/isisd.h" |
eb5d44eb | 47 | #include "isisd/isis_circuit.h" |
48 | #include "isisd/isis_csm.h" | |
3f045a08 | 49 | #include "isisd/isis_lsp.h" |
eb5d44eb | 50 | #include "isisd/isis_route.h" |
51 | #include "isisd/isis_zebra.h" | |
f8c06e2c | 52 | #include "isisd/isis_te.h" |
eb5d44eb | 53 | |
54 | struct zclient *zclient = NULL; | |
55 | ||
18a6dce6 | 56 | /* Router-id update message from zebra. */ |
d62a17ae | 57 | static int isis_router_id_update_zebra(int command, struct zclient *zclient, |
58 | zebra_size_t length, vrf_id_t vrf_id) | |
18a6dce6 | 59 | { |
d62a17ae | 60 | struct isis_area *area; |
61 | struct listnode *node; | |
62 | struct prefix router_id; | |
63 | ||
64 | /* | |
65 | * If ISIS TE is enable, TE Router ID is set through specific command. | |
66 | * See mpls_te_router_addr() command in isis_te.c | |
67 | */ | |
68 | if (IS_MPLS_TE(isisMplsTE)) | |
69 | return 0; | |
70 | ||
71 | zebra_router_id_update_read(zclient->ibuf, &router_id); | |
72 | if (isis->router_id == router_id.u.prefix4.s_addr) | |
73 | return 0; | |
74 | ||
75 | isis->router_id = router_id.u.prefix4.s_addr; | |
76 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) | |
77 | if (listcount(area->area_addrs) > 0) | |
78 | lsp_regenerate_schedule(area, area->is_type, 0); | |
79 | ||
80 | return 0; | |
18a6dce6 | 81 | } |
eb5d44eb | 82 | |
d62a17ae | 83 | static int isis_zebra_if_add(int command, struct zclient *zclient, |
84 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 85 | { |
d62a17ae | 86 | struct interface *ifp; |
eb5d44eb | 87 | |
d62a17ae | 88 | ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); |
f390d2c7 | 89 | |
d62a17ae | 90 | if (isis->debugs & DEBUG_ZEBRA) |
91 | zlog_debug( | |
92 | "Zebra I/F add: %s index %d flags %ld metric %d mtu %d", | |
93 | ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, | |
94 | ifp->mtu); | |
f390d2c7 | 95 | |
d62a17ae | 96 | if (if_is_operative(ifp)) |
97 | isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), | |
98 | ifp); | |
f390d2c7 | 99 | |
d62a17ae | 100 | return 0; |
eb5d44eb | 101 | } |
102 | ||
d62a17ae | 103 | static int isis_zebra_if_del(int command, struct zclient *zclient, |
104 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 105 | { |
d62a17ae | 106 | struct interface *ifp; |
107 | struct stream *s; | |
eb5d44eb | 108 | |
d62a17ae | 109 | s = zclient->ibuf; |
110 | ifp = zebra_interface_state_read(s, vrf_id); | |
f390d2c7 | 111 | |
d62a17ae | 112 | if (!ifp) |
113 | return 0; | |
eb5d44eb | 114 | |
d62a17ae | 115 | if (if_is_operative(ifp)) |
116 | zlog_warn("Zebra: got delete of %s, but interface is still up", | |
117 | ifp->name); | |
eb5d44eb | 118 | |
d62a17ae | 119 | if (isis->debugs & DEBUG_ZEBRA) |
120 | zlog_debug( | |
121 | "Zebra I/F delete: %s index %d flags %ld metric %d mtu %d", | |
122 | ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, | |
123 | ifp->mtu); | |
eb5d44eb | 124 | |
d62a17ae | 125 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp); |
d2fc8896 | 126 | |
d62a17ae | 127 | /* Cannot call if_delete because we should retain the pseudo interface |
128 | in case there is configuration info attached to it. */ | |
129 | if_delete_retain(ifp); | |
f390d2c7 | 130 | |
d62a17ae | 131 | ifp->ifindex = IFINDEX_DELETED; |
d2fc8896 | 132 | |
d62a17ae | 133 | return 0; |
eb5d44eb | 134 | } |
135 | ||
d62a17ae | 136 | static int isis_zebra_if_state_up(int command, struct zclient *zclient, |
137 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 138 | { |
d62a17ae | 139 | struct interface *ifp; |
f390d2c7 | 140 | |
d62a17ae | 141 | ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); |
f390d2c7 | 142 | |
d62a17ae | 143 | if (ifp == NULL) |
144 | return 0; | |
f390d2c7 | 145 | |
d62a17ae | 146 | isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp); |
f390d2c7 | 147 | |
d62a17ae | 148 | return 0; |
eb5d44eb | 149 | } |
150 | ||
d62a17ae | 151 | static int isis_zebra_if_state_down(int command, struct zclient *zclient, |
152 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 153 | { |
d62a17ae | 154 | struct interface *ifp; |
155 | struct isis_circuit *circuit; | |
f390d2c7 | 156 | |
d62a17ae | 157 | ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); |
f390d2c7 | 158 | |
d62a17ae | 159 | if (ifp == NULL) |
160 | return 0; | |
f390d2c7 | 161 | |
d62a17ae | 162 | circuit = isis_csm_state_change(IF_DOWN_FROM_Z, |
163 | circuit_scan_by_ifp(ifp), ifp); | |
164 | if (circuit) | |
165 | SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); | |
f390d2c7 | 166 | |
d62a17ae | 167 | return 0; |
eb5d44eb | 168 | } |
169 | ||
d62a17ae | 170 | static int isis_zebra_if_address_add(int command, struct zclient *zclient, |
171 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 172 | { |
d62a17ae | 173 | struct connected *c; |
174 | struct prefix *p; | |
175 | char buf[PREFIX2STR_BUFFER]; | |
eb5d44eb | 176 | |
d62a17ae | 177 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, |
178 | zclient->ibuf, vrf_id); | |
f390d2c7 | 179 | |
d62a17ae | 180 | if (c == NULL) |
181 | return 0; | |
f390d2c7 | 182 | |
d62a17ae | 183 | p = c->address; |
f390d2c7 | 184 | |
d62a17ae | 185 | prefix2str(p, buf, sizeof(buf)); |
eb5d44eb | 186 | #ifdef EXTREME_DEBUG |
d62a17ae | 187 | if (p->family == AF_INET) |
188 | zlog_debug("connected IP address %s", buf); | |
189 | if (p->family == AF_INET6) | |
190 | zlog_debug("connected IPv6 address %s", buf); | |
eb5d44eb | 191 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 192 | if (if_is_operative(c->ifp)) |
193 | isis_circuit_add_addr(circuit_scan_by_ifp(c->ifp), c); | |
eb5d44eb | 194 | |
d62a17ae | 195 | return 0; |
eb5d44eb | 196 | } |
197 | ||
d62a17ae | 198 | static int isis_zebra_if_address_del(int command, struct zclient *client, |
199 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 200 | { |
d62a17ae | 201 | struct connected *c; |
202 | struct interface *ifp; | |
1cd80845 | 203 | #ifdef EXTREME_DEBUG |
d62a17ae | 204 | struct prefix *p; |
205 | char buf[PREFIX2STR_BUFFER]; | |
1cd80845 | 206 | #endif /* EXTREME_DEBUG */ |
eb5d44eb | 207 | |
d62a17ae | 208 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, |
209 | zclient->ibuf, vrf_id); | |
f390d2c7 | 210 | |
d62a17ae | 211 | if (c == NULL) |
212 | return 0; | |
f390d2c7 | 213 | |
d62a17ae | 214 | ifp = c->ifp; |
f390d2c7 | 215 | |
f891f443 | 216 | #ifdef EXTREME_DEBUG |
d62a17ae | 217 | p = c->address; |
218 | prefix2str(p, buf, sizeof(buf)); | |
f891f443 | 219 | |
d62a17ae | 220 | if (p->family == AF_INET) |
221 | zlog_debug("disconnected IP address %s", buf); | |
222 | if (p->family == AF_INET6) | |
223 | zlog_debug("disconnected IPv6 address %s", buf); | |
f891f443 | 224 | #endif /* EXTREME_DEBUG */ |
f390d2c7 | 225 | |
d62a17ae | 226 | if (if_is_operative(ifp)) |
227 | isis_circuit_del_addr(circuit_scan_by_ifp(ifp), c); | |
228 | connected_free(c); | |
f390d2c7 | 229 | |
d62a17ae | 230 | return 0; |
eb5d44eb | 231 | } |
232 | ||
d62a17ae | 233 | static int isis_zebra_link_params(int command, struct zclient *zclient, |
234 | zebra_size_t length) | |
f8c06e2c | 235 | { |
d62a17ae | 236 | struct interface *ifp; |
f8c06e2c | 237 | |
d62a17ae | 238 | ifp = zebra_interface_link_params_read(zclient->ibuf); |
f8c06e2c | 239 | |
d62a17ae | 240 | if (ifp == NULL) |
241 | return 0; | |
f8c06e2c | 242 | |
d62a17ae | 243 | /* Update TE TLV */ |
244 | isis_mpls_te_update(ifp); | |
f8c06e2c | 245 | |
d62a17ae | 246 | return 0; |
f8c06e2c OD |
247 | } |
248 | ||
f80dd32b RW |
249 | static void isis_zebra_route_add_route(struct prefix *prefix, |
250 | struct isis_route_info *route_info) | |
eb5d44eb | 251 | { |
c0721de4 RW |
252 | struct zapi_route api; |
253 | struct zapi_nexthop *api_nh; | |
d62a17ae | 254 | struct isis_nexthop *nexthop; |
f80dd32b | 255 | struct isis_nexthop6 *nexthop6; |
d62a17ae | 256 | struct listnode *node; |
c0721de4 | 257 | int count = 0; |
d62a17ae | 258 | |
259 | if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) | |
260 | return; | |
261 | ||
c0721de4 RW |
262 | memset(&api, 0, sizeof(api)); |
263 | api.vrf_id = VRF_DEFAULT; | |
264 | api.type = ZEBRA_ROUTE_ISIS; | |
265 | api.safi = SAFI_UNICAST; | |
266 | api.prefix = *prefix; | |
267 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
268 | SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); | |
269 | api.metric = route_info->cost; | |
2097cd8a | 270 | #if 0 |
c0721de4 RW |
271 | SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); |
272 | api.distance = route_info->depth; | |
2097cd8a | 273 | #endif |
f390d2c7 | 274 | |
f80dd32b RW |
275 | /* Nexthops */ |
276 | switch (prefix->family) { | |
277 | case AF_INET: | |
278 | for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, | |
279 | nexthop)) { | |
280 | api_nh = &api.nexthops[count]; | |
281 | /* FIXME: can it be ? */ | |
282 | if (nexthop->ip.s_addr != INADDR_ANY) { | |
283 | api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; | |
284 | api_nh->gate.ipv4 = nexthop->ip; | |
285 | } else { | |
286 | api_nh->type = NEXTHOP_TYPE_IFINDEX; | |
287 | } | |
288 | api_nh->ifindex = nexthop->ifindex; | |
289 | count++; | |
d62a17ae | 290 | } |
f80dd32b RW |
291 | break; |
292 | case AF_INET6: | |
293 | for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, | |
294 | nexthop6)) { | |
295 | if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6) | |
296 | && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) { | |
297 | continue; | |
298 | } | |
299 | ||
300 | api_nh = &api.nexthops[count]; | |
301 | api_nh->gate.ipv6 = nexthop6->ip6; | |
302 | api_nh->ifindex = nexthop6->ifindex; | |
303 | api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; | |
304 | count++; | |
d62a17ae | 305 | } |
f80dd32b | 306 | break; |
d62a17ae | 307 | } |
c0721de4 RW |
308 | if (!count) |
309 | return; | |
f390d2c7 | 310 | |
c0721de4 | 311 | api.nexthop_num = count; |
f390d2c7 | 312 | |
c0721de4 RW |
313 | zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
314 | SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); | |
315 | UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); | |
eb5d44eb | 316 | } |
317 | ||
f80dd32b RW |
318 | static void isis_zebra_route_del_route(struct prefix *prefix, |
319 | struct isis_route_info *route_info) | |
eb5d44eb | 320 | { |
c0721de4 | 321 | struct zapi_route api; |
d62a17ae | 322 | |
323 | if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) | |
324 | return; | |
325 | ||
c0721de4 | 326 | memset(&api, 0, sizeof(api)); |
d62a17ae | 327 | api.vrf_id = VRF_DEFAULT; |
328 | api.type = ZEBRA_ROUTE_ISIS; | |
d62a17ae | 329 | api.safi = SAFI_UNICAST; |
c0721de4 | 330 | api.prefix = *prefix; |
f390d2c7 | 331 | |
c0721de4 RW |
332 | zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
333 | UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); | |
eb5d44eb | 334 | } |
335 | ||
d62a17ae | 336 | void isis_zebra_route_update(struct prefix *prefix, |
337 | struct isis_route_info *route_info) | |
eb5d44eb | 338 | { |
d62a17ae | 339 | if (zclient->sock < 0) |
340 | return; | |
341 | ||
f80dd32b RW |
342 | if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) |
343 | isis_zebra_route_add_route(prefix, route_info); | |
344 | else | |
345 | isis_zebra_route_del_route(prefix, route_info); | |
eb5d44eb | 346 | } |
347 | ||
74489921 RW |
348 | static int isis_zebra_read(int command, struct zclient *zclient, |
349 | zebra_size_t length, vrf_id_t vrf_id) | |
eb5d44eb | 350 | { |
74489921 | 351 | struct zapi_route api; |
d62a17ae | 352 | |
74489921 RW |
353 | if (zapi_route_decode(zclient->ibuf, &api) < 0) |
354 | return -1; | |
d62a17ae | 355 | |
74489921 RW |
356 | /* we completely ignore srcdest routes for now. */ |
357 | if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) | |
d62a17ae | 358 | return 0; |
359 | ||
d62a17ae | 360 | /* |
361 | * Avoid advertising a false default reachability. (A default | |
362 | * route installed by IS-IS gets redistributed from zebra back | |
363 | * into IS-IS causing us to start advertising default reachabity | |
364 | * without this check) | |
365 | */ | |
74489921 RW |
366 | if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) |
367 | command = ZEBRA_REDISTRIBUTE_ROUTE_DEL; | |
d62a17ae | 368 | |
74489921 RW |
369 | if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) |
370 | isis_redist_add(api.type, &api.prefix, api.distance, | |
371 | api.metric); | |
d62a17ae | 372 | else |
74489921 | 373 | isis_redist_delete(api.type, &api.prefix); |
d62a17ae | 374 | |
375 | return 0; | |
eb5d44eb | 376 | } |
eb5d44eb | 377 | |
d62a17ae | 378 | int isis_distribute_list_update(int routetype) |
eb5d44eb | 379 | { |
d62a17ae | 380 | return 0; |
eb5d44eb | 381 | } |
382 | ||
d62a17ae | 383 | void isis_zebra_redistribute_set(afi_t afi, int type) |
eb5d44eb | 384 | { |
d62a17ae | 385 | if (type == DEFAULT_ROUTE) |
386 | zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, | |
387 | zclient, VRF_DEFAULT); | |
388 | else | |
389 | zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type, | |
390 | 0, VRF_DEFAULT); | |
f3ccedaa CF |
391 | } |
392 | ||
d62a17ae | 393 | void isis_zebra_redistribute_unset(afi_t afi, int type) |
f3ccedaa | 394 | { |
d62a17ae | 395 | if (type == DEFAULT_ROUTE) |
396 | zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, | |
397 | zclient, VRF_DEFAULT); | |
398 | else | |
399 | zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, | |
400 | type, 0, VRF_DEFAULT); | |
eb5d44eb | 401 | } |
402 | ||
d62a17ae | 403 | static void isis_zebra_connected(struct zclient *zclient) |
7076bb2f | 404 | { |
d62a17ae | 405 | zclient_send_reg_requests(zclient, VRF_DEFAULT); |
7076bb2f FL |
406 | } |
407 | ||
d62a17ae | 408 | void isis_zebra_init(struct thread_master *master) |
eb5d44eb | 409 | { |
d62a17ae | 410 | zclient = zclient_new(master); |
411 | zclient_init(zclient, ZEBRA_ROUTE_ISIS, 0); | |
412 | zclient->zebra_connected = isis_zebra_connected; | |
413 | zclient->router_id_update = isis_router_id_update_zebra; | |
414 | zclient->interface_add = isis_zebra_if_add; | |
415 | zclient->interface_delete = isis_zebra_if_del; | |
416 | zclient->interface_up = isis_zebra_if_state_up; | |
417 | zclient->interface_down = isis_zebra_if_state_down; | |
418 | zclient->interface_address_add = isis_zebra_if_address_add; | |
419 | zclient->interface_address_delete = isis_zebra_if_address_del; | |
420 | zclient->interface_link_params = isis_zebra_link_params; | |
74489921 RW |
421 | zclient->redistribute_route_add = isis_zebra_read; |
422 | zclient->redistribute_route_del = isis_zebra_read; | |
d62a17ae | 423 | |
424 | return; | |
eb5d44eb | 425 | } |
8d429559 | 426 | |
d62a17ae | 427 | void isis_zebra_stop(void) |
8d429559 | 428 | { |
d62a17ae | 429 | zclient_stop(zclient); |
430 | zclient_free(zclient); | |
8879bd22 | 431 | frr_fini(); |
8d429559 | 432 | } |