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