]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
718e3744 | 2 | /* |
508e53e2 | 3 | * Copyright (C) 2003 Yasuhiro Ohara |
718e3744 | 4 | */ |
5 | ||
508e53e2 | 6 | #include <zebra.h> |
7 | ||
8 | #include "log.h" | |
9 | #include "vty.h" | |
10 | #include "command.h" | |
11 | #include "prefix.h" | |
12 | #include "stream.h" | |
13 | #include "zclient.h" | |
14 | #include "memory.h" | |
5b5d66c4 | 15 | #include "route_opaque.h" |
2376c3f2 | 16 | #include "lib/bfd.h" |
4ba03be5 | 17 | #include "lib_errors.h" |
718e3744 | 18 | |
508e53e2 | 19 | #include "ospf6_proto.h" |
20 | #include "ospf6_top.h" | |
718e3744 | 21 | #include "ospf6_interface.h" |
508e53e2 | 22 | #include "ospf6_route.h" |
23 | #include "ospf6_lsa.h" | |
049207c3 | 24 | #include "ospf6_lsdb.h" |
718e3744 | 25 | #include "ospf6_asbr.h" |
6735622c | 26 | #include "ospf6_nssa.h" |
508e53e2 | 27 | #include "ospf6_zebra.h" |
049207c3 | 28 | #include "ospf6d.h" |
beadc736 | 29 | #include "ospf6_area.h" |
71165098 | 30 | #include "ospf6_gr.h" |
9ebb75c5 | 31 | #include "lib/json.h" |
718e3744 | 32 | |
bf8d3d6a | 33 | DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance"); |
baff583e | 34 | |
508e53e2 | 35 | unsigned char conf_debug_ospf6_zebra = 0; |
718e3744 | 36 | |
37 | /* information about zebra. */ | |
38 | struct zclient *zclient = NULL; | |
39 | ||
beadc736 | 40 | void ospf6_zebra_vrf_register(struct ospf6 *ospf6) |
41 | { | |
42 | if (!zclient || zclient->sock < 0 || !ospf6) | |
43 | return; | |
44 | ||
45 | if (ospf6->vrf_id != VRF_UNKNOWN) { | |
46 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) { | |
47 | zlog_debug("%s: Register VRF %s id %u", __func__, | |
48 | ospf6_vrf_id_to_name(ospf6->vrf_id), | |
49 | ospf6->vrf_id); | |
50 | } | |
51 | zclient_send_reg_requests(zclient, ospf6->vrf_id); | |
52 | } | |
53 | } | |
54 | ||
55 | void ospf6_zebra_vrf_deregister(struct ospf6 *ospf6) | |
56 | { | |
57 | if (!zclient || zclient->sock < 0 || !ospf6) | |
58 | return; | |
59 | ||
60 | if (ospf6->vrf_id != VRF_DEFAULT && ospf6->vrf_id != VRF_UNKNOWN) { | |
61 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) { | |
62 | zlog_debug("%s: De-Register VRF %s id %u to Zebra.", | |
63 | __func__, | |
64 | ospf6_vrf_id_to_name(ospf6->vrf_id), | |
65 | ospf6->vrf_id); | |
66 | } | |
67 | /* Deregister for router-id, interfaces, | |
68 | * redistributed routes. */ | |
69 | zclient_send_dereg_requests(zclient, ospf6->vrf_id); | |
70 | } | |
71 | } | |
72 | ||
18a6dce6 | 73 | /* Router-id update message from zebra. */ |
121f9dee | 74 | static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS) |
18a6dce6 | 75 | { |
d62a17ae | 76 | struct prefix router_id; |
beadc736 | 77 | struct ospf6 *o; |
18a6dce6 | 78 | |
d62a17ae | 79 | zebra_router_id_update_read(zclient->ibuf, &router_id); |
18a6dce6 | 80 | |
3c5122c5 IR |
81 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) |
82 | zlog_debug("Zebra router-id update %pI4 vrf %s id %u", | |
83 | &router_id.u.prefix4, ospf6_vrf_id_to_name(vrf_id), | |
84 | vrf_id); | |
85 | ||
beadc736 | 86 | o = ospf6_lookup_by_vrf_id(vrf_id); |
d62a17ae | 87 | if (o == NULL) |
88 | return 0; | |
c1ba9e8a | 89 | |
3c5122c5 | 90 | o->router_id_zebra = router_id.u.prefix4.s_addr; |
d6927cf3 | 91 | |
436a55a1 | 92 | ospf6_router_id_update(o, false); |
18a6dce6 | 93 | |
d62a17ae | 94 | return 0; |
18a6dce6 | 95 | } |
96 | ||
718e3744 | 97 | /* redistribute function */ |
c5d28568 | 98 | void ospf6_zebra_redistribute(int type, vrf_id_t vrf_id) |
718e3744 | 99 | { |
c5d28568 | 100 | if (vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)) |
d62a17ae | 101 | return; |
c5d28568 | 102 | vrf_bitmap_set(zclient->redist[AFI_IP6][type], vrf_id); |
7076bb2f | 103 | |
d62a17ae | 104 | if (zclient->sock > 0) |
105 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, | |
c5d28568 | 106 | AFI_IP6, type, 0, vrf_id); |
718e3744 | 107 | } |
108 | ||
c5d28568 | 109 | void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id) |
718e3744 | 110 | { |
c5d28568 | 111 | if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)) |
d62a17ae | 112 | return; |
c5d28568 | 113 | vrf_bitmap_unset(zclient->redist[AFI_IP6][type], vrf_id); |
d62a17ae | 114 | if (zclient->sock > 0) |
115 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, | |
c5d28568 | 116 | AFI_IP6, type, 0, vrf_id); |
718e3744 | 117 | } |
118 | ||
6735622c RW |
119 | void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg) |
120 | { | |
121 | struct prefix prefix = {}; | |
122 | int command; | |
123 | ||
124 | if (zclient->sock < 0) { | |
125 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
126 | zlog_debug(" Not connected to Zebra"); | |
127 | return; | |
128 | } | |
129 | ||
130 | prefix.family = AF_INET6; | |
131 | prefix.prefixlen = 0; | |
132 | ||
133 | if (unreg) | |
ad5c8f67 | 134 | command = ZEBRA_NEXTHOP_UNREGISTER; |
6735622c | 135 | else |
ad5c8f67 | 136 | command = ZEBRA_NEXTHOP_REGISTER; |
6735622c RW |
137 | |
138 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
139 | zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__, | |
140 | zserv_command_string(command), &prefix, | |
141 | ospf6->vrf_id); | |
142 | ||
eb3c9d97 DL |
143 | if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, false, |
144 | true, ospf6->vrf_id) | |
6735622c RW |
145 | == ZCLIENT_SEND_FAILURE) |
146 | flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed", | |
147 | __func__); | |
148 | } | |
149 | ||
150 | static int ospf6_zebra_import_check_update(ZAPI_CALLBACK_ARGS) | |
151 | { | |
152 | struct ospf6 *ospf6; | |
153 | struct zapi_route nhr; | |
06e4e901 | 154 | struct prefix matched; |
6735622c RW |
155 | |
156 | ospf6 = ospf6_lookup_by_vrf_id(vrf_id); | |
157 | if (ospf6 == NULL || !IS_OSPF6_ASBR(ospf6)) | |
158 | return 0; | |
159 | ||
06e4e901 | 160 | if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { |
6735622c RW |
161 | zlog_err("%s[%u]: Failure to decode route", __func__, |
162 | ospf6->vrf_id); | |
163 | return -1; | |
164 | } | |
165 | ||
06e4e901 DS |
166 | if (matched.family != AF_INET6 || matched.prefixlen != 0 || |
167 | nhr.type == ZEBRA_ROUTE_OSPF6) | |
6735622c RW |
168 | return 0; |
169 | ||
170 | ospf6->nssa_default_import_check.status = !!nhr.nexthop_num; | |
171 | ospf6_abr_nssa_type_7_defaults(ospf6); | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
121f9dee | 176 | static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS) |
718e3744 | 177 | { |
d62a17ae | 178 | struct connected *c; |
d62a17ae | 179 | |
180 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, | |
181 | zclient->ibuf, vrf_id); | |
182 | if (c == NULL) | |
183 | return 0; | |
184 | ||
185 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) | |
299ce4b3 | 186 | zlog_debug("Zebra Interface address add: %s %5s %pFX", |
d62a17ae | 187 | c->ifp->name, prefix_family_str(c->address), |
299ce4b3 | 188 | c->address); |
d62a17ae | 189 | |
190 | if (c->address->family == AF_INET6) { | |
191 | ospf6_interface_state_update(c->ifp); | |
192 | ospf6_interface_connected_route_update(c->ifp); | |
193 | } | |
194 | return 0; | |
718e3744 | 195 | } |
196 | ||
121f9dee | 197 | static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS) |
718e3744 | 198 | { |
d62a17ae | 199 | struct connected *c; |
d62a17ae | 200 | |
201 | c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, | |
202 | zclient->ibuf, vrf_id); | |
203 | if (c == NULL) | |
204 | return 0; | |
205 | ||
206 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) | |
299ce4b3 | 207 | zlog_debug("Zebra Interface address delete: %s %5s %pFX", |
d62a17ae | 208 | c->ifp->name, prefix_family_str(c->address), |
299ce4b3 | 209 | c->address); |
d62a17ae | 210 | |
211 | if (c->address->family == AF_INET6) { | |
212 | ospf6_interface_connected_route_update(c->ifp); | |
213 | ospf6_interface_state_update(c->ifp); | |
214 | } | |
718e3744 | 215 | |
721c0857 | 216 | connected_free(&c); |
718e3744 | 217 | |
d62a17ae | 218 | return 0; |
219 | } | |
718e3744 | 220 | |
71165098 RW |
221 | static int ospf6_zebra_gr_update(struct ospf6 *ospf6, int command, |
222 | uint32_t stale_time) | |
223 | { | |
224 | struct zapi_cap api; | |
225 | ||
226 | if (!zclient || zclient->sock < 0 || !ospf6) | |
227 | return 1; | |
228 | ||
6006b807 | 229 | memset(&api, 0, sizeof(api)); |
71165098 RW |
230 | api.cap = command; |
231 | api.stale_removal_time = stale_time; | |
232 | api.vrf_id = ospf6->vrf_id; | |
233 | ||
234 | (void)zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, | |
235 | &api); | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | int ospf6_zebra_gr_enable(struct ospf6 *ospf6, uint32_t stale_time) | |
241 | { | |
242 | return ospf6_zebra_gr_update(ospf6, ZEBRA_CLIENT_GR_CAPABILITIES, | |
243 | stale_time); | |
244 | } | |
245 | ||
246 | int ospf6_zebra_gr_disable(struct ospf6 *ospf6) | |
247 | { | |
248 | return ospf6_zebra_gr_update(ospf6, ZEBRA_CLIENT_GR_DISABLE, 0); | |
249 | } | |
250 | ||
121f9dee | 251 | static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) |
d62a17ae | 252 | { |
74489921 | 253 | struct zapi_route api; |
d62a17ae | 254 | unsigned long ifindex; |
6861a5e4 | 255 | const struct in6_addr *nexthop = &in6addr_any; |
beadc736 | 256 | struct ospf6 *ospf6; |
b19502d3 | 257 | struct prefix_ipv6 p; |
beadc736 | 258 | |
259 | ospf6 = ospf6_lookup_by_vrf_id(vrf_id); | |
d62a17ae | 260 | |
261 | if (ospf6 == NULL) | |
262 | return 0; | |
263 | ||
74489921 RW |
264 | if (zapi_route_decode(zclient->ibuf, &api) < 0) |
265 | return -1; | |
d62a17ae | 266 | |
74489921 RW |
267 | /* we completely ignore srcdest routes for now. */ |
268 | if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) | |
d62a17ae | 269 | return 0; |
270 | ||
9fb2b879 DS |
271 | if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) |
272 | return 0; | |
273 | ||
74489921 | 274 | ifindex = api.nexthops[0].ifindex; |
6861a5e4 RW |
275 | if (api.nexthops[0].type == NEXTHOP_TYPE_IPV6 |
276 | || api.nexthops[0].type == NEXTHOP_TYPE_IPV6_IFINDEX) | |
277 | nexthop = &api.nexthops[0].gate.ipv6; | |
d62a17ae | 278 | |
2dbe669b | 279 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) |
d62a17ae | 280 | zlog_debug( |
2dbe669b | 281 | "Zebra Receive route %s: %s %pFX nexthop %pI6 ifindex %ld tag %" ROUTE_TAG_PRI, |
121f9dee QY |
282 | (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD ? "add" |
283 | : "delete"), | |
2dbe669b | 284 | zebra_route_string(api.type), &api.prefix, nexthop, |
d62a17ae | 285 | ifindex, api.tag); |
718e3744 | 286 | |
b19502d3 | 287 | memcpy(&p, &api.prefix, sizeof(p)); |
1fe59b44 | 288 | if (is_default_prefix6(&p)) |
b19502d3 YR |
289 | api.type = DEFAULT_ROUTE; |
290 | ||
121f9dee | 291 | if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) |
74489921 | 292 | ospf6_asbr_redistribute_add(api.type, ifindex, &api.prefix, |
beadc736 | 293 | api.nexthop_num, nexthop, api.tag, |
294 | ospf6); | |
d62a17ae | 295 | else |
beadc736 | 296 | ospf6_asbr_redistribute_remove(api.type, ifindex, &api.prefix, |
297 | ospf6); | |
718e3744 | 298 | |
d62a17ae | 299 | return 0; |
718e3744 | 300 | } |
301 | ||
9ebb75c5 | 302 | DEFUN(show_zebra, |
303 | show_ospf6_zebra_cmd, | |
304 | "show ipv6 ospf6 zebra [json]", | |
305 | SHOW_STR | |
306 | IPV6_STR | |
307 | OSPF6_STR | |
308 | ZEBRA_STR | |
309 | JSON_STR) | |
718e3744 | 310 | { |
d62a17ae | 311 | int i; |
9ebb75c5 | 312 | bool uj = use_json(argc, argv); |
313 | json_object *json; | |
314 | json_object *json_zebra; | |
315 | json_object *json_array; | |
316 | ||
d62a17ae | 317 | if (zclient == NULL) { |
318 | vty_out(vty, "Not connected to zebra\n"); | |
319 | return CMD_SUCCESS; | |
320 | } | |
321 | ||
9ebb75c5 | 322 | if (uj) { |
323 | json = json_object_new_object(); | |
324 | json_zebra = json_object_new_object(); | |
325 | json_array = json_object_new_array(); | |
326 | ||
327 | json_object_int_add(json_zebra, "fail", zclient->fail); | |
328 | json_object_int_add( | |
329 | json_zebra, "redistributeDefault", | |
330 | vrf_bitmap_check(zclient->default_information[AFI_IP6], | |
331 | VRF_DEFAULT)); | |
332 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
333 | if (vrf_bitmap_check(zclient->redist[AFI_IP6][i], | |
334 | VRF_DEFAULT)) | |
335 | json_object_array_add( | |
336 | json_array, | |
337 | json_object_new_string( | |
338 | zebra_route_string(i))); | |
339 | } | |
340 | json_object_object_add(json_zebra, "redistribute", json_array); | |
341 | json_object_object_add(json, "zebraInformation", json_zebra); | |
342 | ||
8b3f1d41 | 343 | vty_json(vty, json); |
9ebb75c5 | 344 | } else { |
bbf5104c | 345 | vty_out(vty, "Zebra Information\n"); |
9ebb75c5 | 346 | vty_out(vty, " fail: %d\n", zclient->fail); |
347 | vty_out(vty, " redistribute default: %d\n", | |
348 | vrf_bitmap_check(zclient->default_information[AFI_IP6], | |
349 | VRF_DEFAULT)); | |
350 | vty_out(vty, " redistribute:"); | |
351 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
352 | if (vrf_bitmap_check(zclient->redist[AFI_IP6][i], | |
353 | VRF_DEFAULT)) | |
354 | vty_out(vty, " %s", zebra_route_string(i)); | |
355 | } | |
356 | vty_out(vty, "\n"); | |
d62a17ae | 357 | } |
d62a17ae | 358 | return CMD_SUCCESS; |
718e3744 | 359 | } |
360 | ||
5b5d66c4 RW |
361 | static void ospf6_zebra_append_opaque_attr(struct ospf6_route *request, |
362 | struct zapi_route *api) | |
363 | { | |
364 | struct ospf_zebra_opaque ospf_opaque = {}; | |
365 | ||
366 | /* OSPF path type */ | |
367 | snprintf(ospf_opaque.path_type, sizeof(ospf_opaque.path_type), "%s", | |
368 | OSPF6_PATH_TYPE_NAME(request->path.type)); | |
369 | ||
370 | switch (request->path.type) { | |
371 | case OSPF6_PATH_TYPE_INTRA: | |
372 | case OSPF6_PATH_TYPE_INTER: | |
373 | /* OSPF area ID */ | |
374 | (void)inet_ntop(AF_INET, &request->path.area_id, | |
375 | ospf_opaque.area_id, | |
376 | sizeof(ospf_opaque.area_id)); | |
377 | break; | |
378 | case OSPF6_PATH_TYPE_EXTERNAL1: | |
379 | case OSPF6_PATH_TYPE_EXTERNAL2: | |
380 | /* OSPF route tag */ | |
381 | snprintf(ospf_opaque.tag, sizeof(ospf_opaque.tag), "%u", | |
382 | request->path.tag); | |
383 | break; | |
384 | default: | |
385 | break; | |
386 | } | |
387 | ||
388 | SET_FLAG(api->message, ZAPI_MESSAGE_OPAQUE); | |
389 | api->opaque.length = sizeof(struct ospf_zebra_opaque); | |
390 | memcpy(api->opaque.data, &ospf_opaque, api->opaque.length); | |
391 | } | |
392 | ||
718e3744 | 393 | #define ADD 0 |
508e53e2 | 394 | #define REM 1 |
beadc736 | 395 | static void ospf6_zebra_route_update(int type, struct ospf6_route *request, |
396 | struct ospf6 *ospf6) | |
718e3744 | 397 | { |
5afa1c6b | 398 | struct zapi_route api; |
d62a17ae | 399 | int nhcount; |
d62a17ae | 400 | int ret = 0; |
5afa1c6b | 401 | struct prefix *dest; |
d62a17ae | 402 | |
2dbe669b | 403 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) |
f85b7619 | 404 | zlog_debug("Zebra Send %s route: %pFX", |
2dbe669b | 405 | (type == REM ? "remove" : "add"), &request->prefix); |
d62a17ae | 406 | |
407 | if (zclient->sock < 0) { | |
408 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
409 | zlog_debug(" Not connected to Zebra"); | |
410 | return; | |
411 | } | |
412 | ||
413 | if (request->path.origin.adv_router == ospf6->router_id | |
414 | && (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 | |
415 | || request->path.type == OSPF6_PATH_TYPE_EXTERNAL2)) { | |
416 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
417 | zlog_debug(" Ignore self-originated external route"); | |
418 | return; | |
419 | } | |
420 | ||
421 | /* If removing is the best path and if there's another path, | |
0f9e2c91 MS |
422 | * treat this request as add the secondary path - if there are |
423 | * nexthops. | |
424 | */ | |
425 | if (type == REM && ospf6_route_is_best(request) && request->next && | |
426 | ospf6_route_is_same(request, request->next) && | |
427 | ospf6_route_num_nexthops(request->next) > 0) { | |
d62a17ae | 428 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) |
429 | zlog_debug( | |
84b7a388 | 430 | " Best-path removal resulted Secondary addition"); |
d62a17ae | 431 | type = ADD; |
432 | request = request->next; | |
433 | } | |
434 | ||
435 | /* Only the best path will be sent to zebra. */ | |
436 | if (!ospf6_route_is_best(request)) { | |
437 | /* this is not preferred best route, ignore */ | |
438 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
439 | zlog_debug(" Ignore non-best route"); | |
440 | return; | |
441 | } | |
442 | ||
443 | nhcount = ospf6_route_num_nexthops(request); | |
444 | if (nhcount == 0) { | |
0f9e2c91 MS |
445 | if (type == ADD) { |
446 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
447 | zlog_debug(" No nexthop, ignore"); | |
448 | return; | |
449 | } else if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
450 | zlog_debug(" No nexthop, rem ok"); | |
d62a17ae | 451 | } |
452 | ||
5afa1c6b | 453 | dest = &request->prefix; |
d62a17ae | 454 | |
5afa1c6b | 455 | memset(&api, 0, sizeof(api)); |
c5d28568 | 456 | api.vrf_id = ospf6->vrf_id; |
d62a17ae | 457 | api.type = ZEBRA_ROUTE_OSPF6; |
d62a17ae | 458 | api.safi = SAFI_UNICAST; |
5afa1c6b | 459 | api.prefix = *dest; |
1958143e MR |
460 | |
461 | if (nhcount > ospf6->max_multipath) { | |
462 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
463 | zlog_debug( | |
464 | " Nexthop count is greater than configured maximum-path, hence ignore the extra nexthops"); | |
465 | } | |
0f9e2c91 | 466 | |
1958143e | 467 | api.nexthop_num = MIN(nhcount, ospf6->max_multipath); |
0f9e2c91 MS |
468 | if (api.nexthop_num > 0) { |
469 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
470 | ospf6_route_zebra_copy_nexthops(request, api.nexthops, | |
471 | api.nexthop_num, api.vrf_id); | |
472 | } | |
1958143e | 473 | |
d62a17ae | 474 | SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); |
475 | api.metric = (request->path.metric_type == 2 ? request->path.u.cost_e2 | |
476 | : request->path.cost); | |
477 | if (request->path.tag) { | |
478 | SET_FLAG(api.message, ZAPI_MESSAGE_TAG); | |
479 | api.tag = request->path.tag; | |
480 | } | |
481 | ||
d62a17ae | 482 | SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); |
beadc736 | 483 | api.distance = ospf6_distance_apply((struct prefix_ipv6 *)dest, request, |
484 | ospf6); | |
d62a17ae | 485 | |
5b5d66c4 RW |
486 | if (type == ADD |
487 | && CHECK_FLAG(ospf6->config_flags, OSPF6_SEND_EXTRA_DATA_TO_ZEBRA)) | |
488 | ospf6_zebra_append_opaque_attr(request, &api); | |
489 | ||
d62a17ae | 490 | if (type == REM) |
5afa1c6b | 491 | ret = zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
d62a17ae | 492 | else |
5afa1c6b | 493 | ret = zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
d62a17ae | 494 | |
8a3f8f2e | 495 | if (ret == ZCLIENT_SEND_FAILURE) |
450971aa | 496 | flog_err(EC_LIB_ZAPI_SOCKET, |
1c50c1c0 QY |
497 | "zclient_route_send() %s failed: %s", |
498 | (type == REM ? "delete" : "add"), | |
499 | safe_strerror(errno)); | |
d62a17ae | 500 | |
d62a17ae | 501 | return; |
718e3744 | 502 | } |
503 | ||
beadc736 | 504 | void ospf6_zebra_route_update_add(struct ospf6_route *request, |
505 | struct ospf6 *ospf6) | |
718e3744 | 506 | { |
71165098 RW |
507 | if (ospf6->gr_info.restart_in_progress |
508 | || ospf6->gr_info.prepare_in_progress) { | |
509 | if (IS_DEBUG_OSPF6_GR) | |
510 | zlog_debug( | |
511 | "Zebra: Graceful Restart in progress -- not installing %pFX", | |
512 | &request->prefix); | |
513 | return; | |
514 | } | |
515 | ||
beadc736 | 516 | ospf6_zebra_route_update(ADD, request, ospf6); |
718e3744 | 517 | } |
518 | ||
beadc736 | 519 | void ospf6_zebra_route_update_remove(struct ospf6_route *request, |
520 | struct ospf6 *ospf6) | |
718e3744 | 521 | { |
71165098 RW |
522 | if (ospf6->gr_info.restart_in_progress |
523 | || ospf6->gr_info.prepare_in_progress) { | |
524 | if (IS_DEBUG_OSPF6_GR) | |
525 | zlog_debug( | |
526 | "Zebra: Graceful Restart in progress -- not uninstalling %pFX", | |
527 | &request->prefix); | |
528 | return; | |
529 | } | |
530 | ||
beadc736 | 531 | ospf6_zebra_route_update(REM, request, ospf6); |
718e3744 | 532 | } |
533 | ||
beadc736 | 534 | void ospf6_zebra_add_discard(struct ospf6_route *request, struct ospf6 *ospf6) |
c3c0ac83 | 535 | { |
5afa1c6b | 536 | struct zapi_route api; |
5afa1c6b | 537 | struct prefix *dest = &request->prefix; |
d62a17ae | 538 | |
71165098 RW |
539 | if (ospf6->gr_info.restart_in_progress |
540 | || ospf6->gr_info.prepare_in_progress) { | |
541 | if (IS_DEBUG_OSPF6_GR) | |
542 | zlog_debug( | |
543 | "Zebra: Graceful Restart in progress -- not installing %pFX", | |
544 | &request->prefix); | |
545 | return; | |
546 | } | |
547 | ||
d00061ea | 548 | if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { |
5afa1c6b | 549 | memset(&api, 0, sizeof(api)); |
c5d28568 | 550 | api.vrf_id = ospf6->vrf_id; |
d00061ea | 551 | api.type = ZEBRA_ROUTE_OSPF6; |
d00061ea | 552 | api.safi = SAFI_UNICAST; |
5afa1c6b | 553 | api.prefix = *dest; |
09a484dd | 554 | zapi_route_set_blackhole(&api, BLACKHOLE_NULL); |
d00061ea | 555 | |
5afa1c6b | 556 | zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
d00061ea RW |
557 | |
558 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
299ce4b3 | 559 | zlog_debug("Zebra: Route add discard %pFX", dest); |
d00061ea RW |
560 | |
561 | SET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED); | |
562 | } else { | |
d00061ea RW |
563 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) |
564 | zlog_debug( | |
299ce4b3 DS |
565 | "Zebra: Blackhole route present already %pFX", |
566 | dest); | |
c3c0ac83 | 567 | } |
c3c0ac83 DS |
568 | } |
569 | ||
beadc736 | 570 | void ospf6_zebra_delete_discard(struct ospf6_route *request, |
571 | struct ospf6 *ospf6) | |
c3c0ac83 | 572 | { |
5afa1c6b | 573 | struct zapi_route api; |
5afa1c6b | 574 | struct prefix *dest = &request->prefix; |
d62a17ae | 575 | |
71165098 RW |
576 | if (ospf6->gr_info.restart_in_progress |
577 | || ospf6->gr_info.prepare_in_progress) { | |
578 | if (IS_DEBUG_OSPF6_GR) | |
579 | zlog_debug( | |
580 | "Zebra: Graceful Restart in progress -- not uninstalling %pFX", | |
581 | &request->prefix); | |
582 | return; | |
583 | } | |
584 | ||
d00061ea | 585 | if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { |
5afa1c6b | 586 | memset(&api, 0, sizeof(api)); |
c5d28568 | 587 | api.vrf_id = ospf6->vrf_id; |
d00061ea | 588 | api.type = ZEBRA_ROUTE_OSPF6; |
d00061ea | 589 | api.safi = SAFI_UNICAST; |
5afa1c6b | 590 | api.prefix = *dest; |
09a484dd | 591 | zapi_route_set_blackhole(&api, BLACKHOLE_NULL); |
d00061ea | 592 | |
5afa1c6b | 593 | zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
d00061ea RW |
594 | |
595 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
299ce4b3 | 596 | zlog_debug("Zebra: Route delete discard %pFX", dest); |
d00061ea RW |
597 | |
598 | UNSET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED); | |
599 | } else { | |
d00061ea RW |
600 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) |
601 | zlog_debug( | |
299ce4b3 DS |
602 | "Zebra: Blackhole route already deleted %pFX", |
603 | dest); | |
c3c0ac83 | 604 | } |
c3c0ac83 DS |
605 | } |
606 | ||
d62a17ae | 607 | static struct ospf6_distance *ospf6_distance_new(void) |
baff583e | 608 | { |
d62a17ae | 609 | return XCALLOC(MTYPE_OSPF6_DISTANCE, sizeof(struct ospf6_distance)); |
baff583e MZ |
610 | } |
611 | ||
d62a17ae | 612 | static void ospf6_distance_free(struct ospf6_distance *odistance) |
baff583e | 613 | { |
d62a17ae | 614 | XFREE(MTYPE_OSPF6_DISTANCE, odistance); |
baff583e MZ |
615 | } |
616 | ||
d62a17ae | 617 | int ospf6_distance_set(struct vty *vty, struct ospf6 *o, |
618 | const char *distance_str, const char *ip_str, | |
619 | const char *access_list_str) | |
baff583e | 620 | { |
d62a17ae | 621 | int ret; |
622 | struct prefix_ipv6 p; | |
d7c0a89a | 623 | uint8_t distance; |
d62a17ae | 624 | struct route_node *rn; |
625 | struct ospf6_distance *odistance; | |
626 | ||
627 | ret = str2prefix_ipv6(ip_str, &p); | |
628 | if (ret == 0) { | |
629 | vty_out(vty, "Malformed prefix\n"); | |
630 | return CMD_WARNING_CONFIG_FAILED; | |
631 | } | |
632 | ||
633 | distance = atoi(distance_str); | |
634 | ||
635 | /* Get OSPF6 distance node. */ | |
636 | rn = route_node_get(o->distance_table, (struct prefix *)&p); | |
637 | if (rn->info) { | |
638 | odistance = rn->info; | |
639 | route_unlock_node(rn); | |
640 | } else { | |
641 | odistance = ospf6_distance_new(); | |
642 | rn->info = odistance; | |
643 | } | |
644 | ||
645 | /* Set distance value. */ | |
646 | odistance->distance = distance; | |
647 | ||
648 | /* Reset access-list configuration. */ | |
649 | if (odistance->access_list) { | |
650 | free(odistance->access_list); | |
651 | odistance->access_list = NULL; | |
652 | } | |
653 | if (access_list_str) | |
654 | odistance->access_list = strdup(access_list_str); | |
655 | ||
656 | return CMD_SUCCESS; | |
baff583e MZ |
657 | } |
658 | ||
d62a17ae | 659 | int ospf6_distance_unset(struct vty *vty, struct ospf6 *o, |
660 | const char *distance_str, const char *ip_str, | |
661 | const char *access_list_str) | |
baff583e | 662 | { |
d62a17ae | 663 | int ret; |
664 | struct prefix_ipv6 p; | |
665 | struct route_node *rn; | |
666 | struct ospf6_distance *odistance; | |
667 | ||
668 | ret = str2prefix_ipv6(ip_str, &p); | |
669 | if (ret == 0) { | |
670 | vty_out(vty, "Malformed prefix\n"); | |
671 | return CMD_WARNING_CONFIG_FAILED; | |
672 | } | |
673 | ||
674 | rn = route_node_lookup(o->distance_table, (struct prefix *)&p); | |
675 | if (!rn) { | |
676 | vty_out(vty, "Cant't find specified prefix\n"); | |
677 | return CMD_WARNING_CONFIG_FAILED; | |
678 | } | |
679 | ||
680 | odistance = rn->info; | |
681 | ||
682 | if (odistance->access_list) | |
683 | free(odistance->access_list); | |
684 | ospf6_distance_free(odistance); | |
685 | ||
686 | rn->info = NULL; | |
687 | route_unlock_node(rn); | |
688 | route_unlock_node(rn); | |
689 | ||
690 | return CMD_SUCCESS; | |
baff583e MZ |
691 | } |
692 | ||
d62a17ae | 693 | void ospf6_distance_reset(struct ospf6 *o) |
baff583e | 694 | { |
d62a17ae | 695 | struct route_node *rn; |
696 | struct ospf6_distance *odistance; | |
697 | ||
698 | for (rn = route_top(o->distance_table); rn; rn = route_next(rn)) | |
699 | if ((odistance = rn->info) != NULL) { | |
700 | if (odistance->access_list) | |
701 | free(odistance->access_list); | |
702 | ospf6_distance_free(odistance); | |
703 | rn->info = NULL; | |
704 | route_unlock_node(rn); | |
705 | } | |
baff583e MZ |
706 | } |
707 | ||
beadc736 | 708 | uint8_t ospf6_distance_apply(struct prefix_ipv6 *p, struct ospf6_route * or, |
709 | struct ospf6 *ospf6) | |
baff583e | 710 | { |
d62a17ae | 711 | struct ospf6 *o; |
baff583e | 712 | |
d62a17ae | 713 | o = ospf6; |
714 | if (o == NULL) | |
715 | return 0; | |
baff583e | 716 | |
d62a17ae | 717 | if (o->distance_intra) |
718 | if (or->path.type == OSPF6_PATH_TYPE_INTRA) | |
719 | return o->distance_intra; | |
baff583e | 720 | |
d62a17ae | 721 | if (o->distance_inter) |
722 | if (or->path.type == OSPF6_PATH_TYPE_INTER) | |
723 | return o->distance_inter; | |
baff583e | 724 | |
d62a17ae | 725 | if (o->distance_external) |
726 | if (or->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || | |
727 | or->path.type == OSPF6_PATH_TYPE_EXTERNAL2) | |
728 | return o->distance_external; | |
baff583e | 729 | |
d62a17ae | 730 | if (o->distance_all) |
731 | return o->distance_all; | |
baff583e | 732 | |
d62a17ae | 733 | return 0; |
baff583e MZ |
734 | } |
735 | ||
d62a17ae | 736 | static void ospf6_zebra_connected(struct zclient *zclient) |
7076bb2f | 737 | { |
d62a17ae | 738 | /* Send the client registration */ |
0945d5ed | 739 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); |
2376c3f2 | 740 | |
d62a17ae | 741 | zclient_send_reg_requests(zclient, VRF_DEFAULT); |
7076bb2f FL |
742 | } |
743 | ||
a243d1db DL |
744 | static zclient_handler *const ospf6_handlers[] = { |
745 | [ZEBRA_ROUTER_ID_UPDATE] = ospf6_router_id_update_zebra, | |
746 | [ZEBRA_INTERFACE_ADDRESS_ADD] = ospf6_zebra_if_address_update_add, | |
747 | [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf6_zebra_if_address_update_delete, | |
748 | [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf6_zebra_read_route, | |
749 | [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf6_zebra_read_route, | |
750 | [ZEBRA_NEXTHOP_UPDATE] = ospf6_zebra_import_check_update, | |
751 | }; | |
752 | ||
cd9d0537 | 753 | void ospf6_zebra_init(struct event_loop *master) |
718e3744 | 754 | { |
d62a17ae | 755 | /* Allocate zebra structure. */ |
a243d1db DL |
756 | zclient = zclient_new(master, &zclient_options_default, ospf6_handlers, |
757 | array_size(ospf6_handlers)); | |
342213ea | 758 | zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs); |
d62a17ae | 759 | zclient->zebra_connected = ospf6_zebra_connected; |
d62a17ae | 760 | |
d62a17ae | 761 | /* Install command element for zebra node. */ |
762 | install_element(VIEW_NODE, &show_ospf6_zebra_cmd); | |
718e3744 | 763 | } |
764 | ||
508e53e2 | 765 | /* Debug */ |
6b0655a2 | 766 | |
508e53e2 | 767 | DEFUN (debug_ospf6_zebra_sendrecv, |
768 | debug_ospf6_zebra_sendrecv_cmd, | |
1d68dbfe | 769 | "debug ospf6 zebra [<send|recv>]", |
508e53e2 | 770 | DEBUG_STR |
771 | OSPF6_STR | |
772 | "Debug connection between zebra\n" | |
773 | "Debug Sending zebra\n" | |
774 | "Debug Receiving zebra\n" | |
775 | ) | |
776 | { | |
d62a17ae | 777 | int idx_send_recv = 3; |
778 | unsigned char level = 0; | |
779 | ||
780 | if (argc == 4) { | |
781 | if (strmatch(argv[idx_send_recv]->text, "send")) | |
782 | level = OSPF6_DEBUG_ZEBRA_SEND; | |
783 | else if (strmatch(argv[idx_send_recv]->text, "recv")) | |
784 | level = OSPF6_DEBUG_ZEBRA_RECV; | |
785 | } else | |
786 | level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; | |
787 | ||
788 | OSPF6_DEBUG_ZEBRA_ON(level); | |
789 | return CMD_SUCCESS; | |
508e53e2 | 790 | } |
791 | ||
508e53e2 | 792 | DEFUN (no_debug_ospf6_zebra_sendrecv, |
793 | no_debug_ospf6_zebra_sendrecv_cmd, | |
1d68dbfe | 794 | "no debug ospf6 zebra [<send|recv>]", |
508e53e2 | 795 | NO_STR |
796 | DEBUG_STR | |
797 | OSPF6_STR | |
798 | "Debug connection between zebra\n" | |
799 | "Debug Sending zebra\n" | |
800 | "Debug Receiving zebra\n" | |
801 | ) | |
802 | { | |
d62a17ae | 803 | int idx_send_recv = 4; |
804 | unsigned char level = 0; | |
805 | ||
806 | if (argc == 5) { | |
807 | if (strmatch(argv[idx_send_recv]->text, "send")) | |
808 | level = OSPF6_DEBUG_ZEBRA_SEND; | |
809 | else if (strmatch(argv[idx_send_recv]->text, "recv")) | |
810 | level = OSPF6_DEBUG_ZEBRA_RECV; | |
811 | } else | |
812 | level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; | |
813 | ||
814 | OSPF6_DEBUG_ZEBRA_OFF(level); | |
815 | return CMD_SUCCESS; | |
508e53e2 | 816 | } |
817 | ||
508e53e2 | 818 | |
d62a17ae | 819 | int config_write_ospf6_debug_zebra(struct vty *vty) |
508e53e2 | 820 | { |
d62a17ae | 821 | if (IS_OSPF6_DEBUG_ZEBRA(SEND) && IS_OSPF6_DEBUG_ZEBRA(RECV)) |
822 | vty_out(vty, "debug ospf6 zebra\n"); | |
823 | else { | |
824 | if (IS_OSPF6_DEBUG_ZEBRA(SEND)) | |
825 | vty_out(vty, "debug ospf6 zebra send\n"); | |
826 | if (IS_OSPF6_DEBUG_ZEBRA(RECV)) | |
827 | vty_out(vty, "debug ospf6 zebra recv\n"); | |
828 | } | |
829 | return 0; | |
508e53e2 | 830 | } |
831 | ||
d62a17ae | 832 | void install_element_ospf6_debug_zebra(void) |
718e3744 | 833 | { |
d62a17ae | 834 | install_element(ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd); |
835 | install_element(ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); | |
836 | install_element(CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd); | |
837 | install_element(CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); | |
718e3744 | 838 | } |