]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
eac6e3f0 RW |
2 | /* |
3 | * Copyright (C) 2016 by Open Source Routing. | |
eac6e3f0 RW |
4 | */ |
5 | ||
6 | #include <zebra.h> | |
7 | ||
8 | #include "prefix.h" | |
9 | #include "stream.h" | |
10 | #include "memory.h" | |
11 | #include "zclient.h" | |
12 | #include "command.h" | |
13 | #include "network.h" | |
14 | #include "linklist.h" | |
ce549947 | 15 | #include "mpls.h" |
eac6e3f0 RW |
16 | |
17 | #include "ldpd.h" | |
18 | #include "ldpe.h" | |
19 | #include "lde.h" | |
e1894ff7 | 20 | #include "ldp_sync.h" |
eac6e3f0 RW |
21 | #include "log.h" |
22 | #include "ldp_debug.h" | |
23 | ||
24 | static void ifp2kif(struct interface *, struct kif *); | |
25 | static void ifc2kaddr(struct interface *, struct connected *, | |
26 | struct kaddr *); | |
bad6b0e7 | 27 | static int ldp_zebra_send_mpls_labels(int, struct kroute *); |
121f9dee | 28 | static int ldp_router_id_update(ZAPI_CALLBACK_ARGS); |
121f9dee QY |
29 | static int ldp_interface_address_add(ZAPI_CALLBACK_ARGS); |
30 | static int ldp_interface_address_delete(ZAPI_CALLBACK_ARGS); | |
31 | static int ldp_zebra_read_route(ZAPI_CALLBACK_ARGS); | |
32 | static int ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS); | |
eac6e3f0 | 33 | static void ldp_zebra_connected(struct zclient *); |
2d1aa1e8 | 34 | static void ldp_zebra_filter_update(struct access_list *access); |
eac6e3f0 | 35 | |
e1894ff7 KS |
36 | static void ldp_zebra_opaque_register(void); |
37 | static void ldp_zebra_opaque_unregister(void); | |
38 | static int ldp_sync_zebra_send_announce(void); | |
39 | static int ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS); | |
e1894ff7 KS |
40 | static void ldp_sync_zebra_init(void); |
41 | ||
eac6e3f0 | 42 | static struct zclient *zclient; |
ce510d2e | 43 | static bool zebra_registered = false; |
eac6e3f0 RW |
44 | |
45 | static void | |
46 | ifp2kif(struct interface *ifp, struct kif *kif) | |
47 | { | |
48 | memset(kif, 0, sizeof(*kif)); | |
49 | strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname)); | |
50 | kif->ifindex = ifp->ifindex; | |
988ded8d | 51 | kif->operative = if_is_operative(ifp); |
26519d8c | 52 | if (ifp->ll_type == ZEBRA_LLT_ETHER) |
9bff8057 | 53 | memcpy(kif->mac, ifp->hw_addr, ETH_ALEN); |
eac6e3f0 RW |
54 | } |
55 | ||
56 | static void | |
57 | ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) | |
58 | { | |
59 | memset(ka, 0, sizeof(*ka)); | |
9cf67225 | 60 | strlcpy(ka->ifname, ifp->name, sizeof(ka->ifname)); |
eac6e3f0 RW |
61 | ka->ifindex = ifp->ifindex; |
62 | ka->af = ifc->address->family; | |
63 | ka->prefixlen = ifc->address->prefixlen; | |
64 | ||
65 | switch (ka->af) { | |
66 | case AF_INET: | |
67 | ka->addr.v4 = ifc->address->u.prefix4; | |
68 | if (ifc->destination) | |
69 | ka->dstbrd.v4 = ifc->destination->u.prefix4; | |
70 | break; | |
71 | case AF_INET6: | |
72 | ka->addr.v6 = ifc->address->u.prefix6; | |
73 | if (ifc->destination) | |
74 | ka->dstbrd.v6 = ifc->destination->u.prefix6; | |
75 | break; | |
76 | default: | |
77 | break; | |
78 | } | |
79 | } | |
80 | ||
87b5f1b7 RW |
81 | void |
82 | pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) | |
83 | { | |
84 | memset(zpw, 0, sizeof(*zpw)); | |
85 | strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname)); | |
86 | zpw->ifindex = pw->ifindex; | |
87 | zpw->type = pw->l2vpn->pw_type; | |
88 | zpw->af = pw->af; | |
89 | zpw->nexthop.ipv6 = pw->addr.v6; | |
90 | zpw->local_label = NO_LABEL; | |
91 | zpw->remote_label = NO_LABEL; | |
92 | if (pw->flags & F_PW_CWORD) | |
93 | zpw->flags = F_PSEUDOWIRE_CWORD; | |
94 | zpw->data.ldp.lsr_id = pw->lsr_id; | |
95 | zpw->data.ldp.pwid = pw->pwid; | |
96 | strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name, | |
97 | sizeof(zpw->data.ldp.vpn_name)); | |
98 | } | |
99 | ||
e1894ff7 KS |
100 | static void |
101 | ldp_zebra_opaque_register(void) | |
102 | { | |
103 | zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST); | |
077d336a RW |
104 | zclient_register_opaque(zclient, LDP_RLFA_REGISTER); |
105 | zclient_register_opaque(zclient, LDP_RLFA_UNREGISTER_ALL); | |
e1894ff7 KS |
106 | } |
107 | ||
108 | static void | |
109 | ldp_zebra_opaque_unregister(void) | |
110 | { | |
111 | zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST); | |
077d336a RW |
112 | zclient_unregister_opaque(zclient, LDP_RLFA_REGISTER); |
113 | zclient_unregister_opaque(zclient, LDP_RLFA_UNREGISTER_ALL); | |
e1894ff7 KS |
114 | } |
115 | ||
116 | int | |
117 | ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *state) | |
118 | { | |
7cfdb485 DS |
119 | if (zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE, |
120 | (const uint8_t *)state, sizeof(*state)) | |
121 | == ZCLIENT_SEND_FAILURE) | |
122 | return -1; | |
123 | else | |
124 | return 0; | |
e1894ff7 KS |
125 | } |
126 | ||
127 | static int | |
128 | ldp_sync_zebra_send_announce(void) | |
129 | { | |
130 | struct ldp_igp_sync_announce announce; | |
131 | announce.proto = ZEBRA_ROUTE_LDP; | |
132 | ||
7cfdb485 DS |
133 | if (zclient_send_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE, |
134 | (const uint8_t *)&announce, sizeof(announce)) | |
135 | == ZCLIENT_SEND_FAILURE) | |
136 | return -1; | |
137 | else | |
138 | return 0; | |
e1894ff7 KS |
139 | } |
140 | ||
077d336a RW |
141 | int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *rlfa_labels) |
142 | { | |
143 | int ret; | |
144 | ||
145 | ret = zclient_send_opaque(zclient, LDP_RLFA_LABELS, | |
146 | (const uint8_t *)rlfa_labels, | |
147 | sizeof(*rlfa_labels)); | |
148 | if (ret == ZCLIENT_SEND_FAILURE) { | |
149 | log_warn("failed to send RLFA labels to IGP"); | |
150 | return -1; | |
151 | } | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
e1894ff7 KS |
156 | static int |
157 | ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS) | |
158 | { | |
159 | struct stream *s; | |
160 | struct zapi_opaque_msg info; | |
161 | struct ldp_igp_sync_if_state_req state_req; | |
077d336a RW |
162 | struct zapi_rlfa_igp igp; |
163 | struct zapi_rlfa_request rlfa; | |
e1894ff7 KS |
164 | |
165 | s = zclient->ibuf; | |
166 | ||
167 | if (zclient_opaque_decode(s, &info) != 0) | |
168 | return -1; | |
169 | ||
170 | switch (info.type) { | |
171 | case LDP_IGP_SYNC_IF_STATE_REQUEST: | |
172 | STREAM_GET(&state_req, s, sizeof(state_req)); | |
173 | main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req, | |
174 | sizeof(state_req)); | |
175 | break; | |
077d336a RW |
176 | case LDP_RLFA_REGISTER: |
177 | STREAM_GET(&rlfa, s, sizeof(rlfa)); | |
178 | main_imsg_compose_both(IMSG_RLFA_REG, &rlfa, sizeof(rlfa)); | |
179 | break; | |
180 | case LDP_RLFA_UNREGISTER_ALL: | |
181 | STREAM_GET(&igp, s, sizeof(igp)); | |
182 | main_imsg_compose_both(IMSG_RLFA_UNREG_ALL, &igp, sizeof(igp)); | |
183 | break; | |
e1894ff7 KS |
184 | default: |
185 | break; | |
186 | } | |
187 | ||
188 | stream_failure: | |
189 | return 0; | |
190 | } | |
191 | ||
e1894ff7 KS |
192 | static void |
193 | ldp_sync_zebra_init(void) | |
194 | { | |
195 | ldp_sync_zebra_send_announce(); | |
e1894ff7 KS |
196 | } |
197 | ||
ce549947 | 198 | static int |
bad6b0e7 | 199 | ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr) |
ce549947 | 200 | { |
bad6b0e7 | 201 | struct zapi_labels zl = {}; |
4945002d | 202 | struct zapi_nexthop *znh; |
ce549947 | 203 | |
8963e0c8 | 204 | if (kr->local_label < MPLS_LABEL_RESERVED_MAX) |
ce549947 RW |
205 | return (0); |
206 | ||
88d88a9c | 207 | debug_zebra_out("prefix %s/%u nexthop %s ifindex %u labels %s/%s (%s)", |
ce549947 | 208 | log_addr(kr->af, &kr->prefix), kr->prefixlen, |
88d88a9c RW |
209 | log_addr(kr->af, &kr->nexthop), kr->ifindex, |
210 | log_label(kr->local_label), log_label(kr->remote_label), | |
ce549947 RW |
211 | (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete"); |
212 | ||
bad6b0e7 | 213 | zl.type = ZEBRA_LSP_LDP; |
b3c49d0e RW |
214 | zl.local_label = kr->local_label; |
215 | ||
216 | /* Set prefix. */ | |
8963e0c8 RW |
217 | if (kr->remote_label != NO_LABEL) { |
218 | SET_FLAG(zl.message, ZAPI_LABELS_FTN); | |
219 | zl.route.prefix.family = kr->af; | |
220 | switch (kr->af) { | |
221 | case AF_INET: | |
222 | zl.route.prefix.u.prefix4 = kr->prefix.v4; | |
223 | break; | |
224 | case AF_INET6: | |
225 | zl.route.prefix.u.prefix6 = kr->prefix.v6; | |
226 | break; | |
227 | default: | |
228 | fatalx("ldp_zebra_send_mpls_labels: unknown af"); | |
229 | } | |
230 | zl.route.prefix.prefixlen = kr->prefixlen; | |
231 | zl.route.type = kr->route_type; | |
232 | zl.route.instance = kr->route_instance; | |
ce549947 | 233 | } |
8963e0c8 | 234 | |
ff5279ba | 235 | /* If allow-broken-lsps is enabled then if an lsp is received with |
236 | * no remote label, instruct the forwarding plane to pop the top-level | |
8963e0c8 RW |
237 | * label and forward packets normally. This is a best-effort attempt |
238 | * to deliver labeled IP packets to their final destination (instead of | |
239 | * dropping them). | |
240 | */ | |
ff5279ba | 241 | if (kr->remote_label == NO_LABEL |
242 | && !(ldpd_conf->flags & F_LDPD_ALLOW_BROKEN_LSP) | |
243 | && cmd == ZEBRA_MPLS_LABELS_ADD) | |
244 | return 0; | |
245 | ||
8963e0c8 RW |
246 | if (kr->remote_label == NO_LABEL) |
247 | kr->remote_label = MPLS_LABEL_IMPLICIT_NULL; | |
b3c49d0e RW |
248 | |
249 | /* Set nexthop. */ | |
ea6b290b RW |
250 | zl.nexthop_num = 1; |
251 | znh = &zl.nexthops[0]; | |
b3c49d0e RW |
252 | switch (kr->af) { |
253 | case AF_INET: | |
4945002d | 254 | znh->gate.ipv4 = kr->nexthop.v4; |
b3c49d0e | 255 | if (kr->ifindex) |
ea6b290b | 256 | znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; |
b3c49d0e | 257 | else |
ea6b290b | 258 | znh->type = NEXTHOP_TYPE_IPV4; |
b3c49d0e RW |
259 | break; |
260 | case AF_INET6: | |
4945002d | 261 | znh->gate.ipv6 = kr->nexthop.v6; |
b3c49d0e | 262 | if (kr->ifindex) |
ea6b290b | 263 | znh->type = NEXTHOP_TYPE_IPV6_IFINDEX; |
b3c49d0e | 264 | else |
ea6b290b | 265 | znh->type = NEXTHOP_TYPE_IPV6; |
b3c49d0e RW |
266 | break; |
267 | default: | |
268 | break; | |
269 | } | |
ea6b290b | 270 | znh->ifindex = kr->ifindex; |
4945002d MS |
271 | znh->label_num = 1; |
272 | znh->labels[0] = kr->remote_label; | |
ce549947 | 273 | |
7cfdb485 DS |
274 | if (zebra_send_mpls_labels(zclient, cmd, &zl) == ZCLIENT_SEND_FAILURE) |
275 | return -1; | |
276 | ||
277 | return 0; | |
ce549947 RW |
278 | } |
279 | ||
eac6e3f0 RW |
280 | int |
281 | kr_change(struct kroute *kr) | |
282 | { | |
bad6b0e7 | 283 | return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr)); |
eac6e3f0 RW |
284 | } |
285 | ||
286 | int | |
287 | kr_delete(struct kroute *kr) | |
288 | { | |
bad6b0e7 | 289 | return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr)); |
eac6e3f0 RW |
290 | } |
291 | ||
292 | int | |
87b5f1b7 | 293 | kmpw_add(struct zapi_pw *zpw) |
eac6e3f0 | 294 | { |
87b5f1b7 RW |
295 | debug_zebra_out("pseudowire %s nexthop %s (add)", |
296 | zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | |
297 | ||
7cfdb485 DS |
298 | return zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw) |
299 | == ZCLIENT_SEND_FAILURE; | |
eac6e3f0 RW |
300 | } |
301 | ||
302 | int | |
87b5f1b7 | 303 | kmpw_del(struct zapi_pw *zpw) |
eac6e3f0 | 304 | { |
87b5f1b7 RW |
305 | debug_zebra_out("pseudowire %s nexthop %s (del)", |
306 | zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | |
307 | ||
7cfdb485 DS |
308 | return zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw) |
309 | == ZCLIENT_SEND_FAILURE; | |
87b5f1b7 RW |
310 | } |
311 | ||
312 | int | |
313 | kmpw_set(struct zapi_pw *zpw) | |
314 | { | |
315 | debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)", | |
316 | zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop), | |
317 | zpw->local_label, zpw->remote_label); | |
318 | ||
7cfdb485 DS |
319 | return zebra_send_pw(zclient, ZEBRA_PW_SET, zpw) |
320 | == ZCLIENT_SEND_FAILURE; | |
87b5f1b7 RW |
321 | } |
322 | ||
323 | int | |
324 | kmpw_unset(struct zapi_pw *zpw) | |
325 | { | |
326 | debug_zebra_out("pseudowire %s nexthop %s (unset)", | |
327 | zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | |
328 | ||
7cfdb485 DS |
329 | return zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw) |
330 | == ZCLIENT_SEND_FAILURE; | |
eac6e3f0 RW |
331 | } |
332 | ||
333 | void | |
334 | kif_redistribute(const char *ifname) | |
335 | { | |
f4e14fdb RW |
336 | struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); |
337 | struct listnode *cnode; | |
eac6e3f0 RW |
338 | struct interface *ifp; |
339 | struct connected *ifc; | |
340 | struct kif kif; | |
341 | struct kaddr ka; | |
342 | ||
451fda4f | 343 | FOR_ALL_INTERFACES (vrf, ifp) { |
eac6e3f0 RW |
344 | if (ifname && strcmp(ifname, ifp->name) != 0) |
345 | continue; | |
346 | ||
347 | ifp2kif(ifp, &kif); | |
52b530fc | 348 | main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); |
eac6e3f0 RW |
349 | |
350 | for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { | |
351 | ifc2kaddr(ifp, ifc, &ka); | |
352 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, | |
353 | sizeof(ka)); | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | static int | |
121f9dee | 359 | ldp_router_id_update(ZAPI_CALLBACK_ARGS) |
eac6e3f0 RW |
360 | { |
361 | struct prefix router_id; | |
362 | ||
363 | zebra_router_id_update_read(zclient->ibuf, &router_id); | |
364 | ||
365 | if (bad_addr_v4(router_id.u.prefix4)) | |
366 | return (0); | |
367 | ||
903a7226 | 368 | debug_zebra_in("router-id update %pI4", &router_id.u.prefix4); |
eac6e3f0 RW |
369 | |
370 | global.rtr_id.s_addr = router_id.u.prefix4.s_addr; | |
371 | main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id, | |
372 | sizeof(global.rtr_id)); | |
373 | ||
374 | return (0); | |
375 | } | |
376 | ||
377 | static int | |
ef7bd2a3 | 378 | ldp_ifp_create(struct interface *ifp) |
eac6e3f0 | 379 | { |
eac6e3f0 RW |
380 | struct kif kif; |
381 | ||
eac6e3f0 RW |
382 | debug_zebra_in("interface add %s index %d mtu %d", ifp->name, |
383 | ifp->ifindex, ifp->mtu); | |
384 | ||
385 | ifp2kif(ifp, &kif); | |
52b530fc | 386 | main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); |
eac6e3f0 | 387 | |
ef7bd2a3 | 388 | return 0; |
eac6e3f0 RW |
389 | } |
390 | ||
391 | static int | |
3c3c3252 | 392 | ldp_ifp_destroy(struct interface *ifp) |
eac6e3f0 | 393 | { |
9cf67225 | 394 | struct kif kif; |
eac6e3f0 | 395 | |
eac6e3f0 RW |
396 | debug_zebra_in("interface delete %s index %d mtu %d", ifp->name, |
397 | ifp->ifindex, ifp->mtu); | |
398 | ||
9cf67225 RW |
399 | ifp2kif(ifp, &kif); |
400 | main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); | |
eac6e3f0 RW |
401 | |
402 | return (0); | |
403 | } | |
404 | ||
405 | static int | |
e1894ff7 | 406 | ldp_interface_status_change(struct interface *ifp) |
eac6e3f0 | 407 | { |
eac6e3f0 RW |
408 | struct listnode *node; |
409 | struct connected *ifc; | |
410 | struct kif kif; | |
411 | struct kaddr ka; | |
eac6e3f0 | 412 | |
eac6e3f0 RW |
413 | debug_zebra_in("interface %s state update", ifp->name); |
414 | ||
415 | ifp2kif(ifp, &kif); | |
52b530fc | 416 | main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); |
eac6e3f0 | 417 | |
988ded8d | 418 | if (if_is_operative(ifp)) { |
eac6e3f0 RW |
419 | for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { |
420 | ifc2kaddr(ifp, ifc, &ka); | |
421 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, | |
422 | sizeof(ka)); | |
423 | } | |
424 | } else { | |
425 | for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { | |
426 | ifc2kaddr(ifp, ifc, &ka); | |
427 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, | |
428 | sizeof(ka)); | |
429 | } | |
430 | } | |
431 | ||
432 | return (0); | |
433 | } | |
ddbf3e60 | 434 | |
b0b69e59 DS |
435 | static int ldp_ifp_up(struct interface *ifp) |
436 | { | |
e1894ff7 | 437 | return ldp_interface_status_change(ifp); |
b0b69e59 | 438 | } |
ddbf3e60 | 439 | |
b0b69e59 DS |
440 | static int ldp_ifp_down(struct interface *ifp) |
441 | { | |
e1894ff7 | 442 | return ldp_interface_status_change(ifp); |
ddbf3e60 | 443 | } |
eac6e3f0 RW |
444 | |
445 | static int | |
121f9dee | 446 | ldp_interface_address_add(ZAPI_CALLBACK_ARGS) |
eac6e3f0 RW |
447 | { |
448 | struct connected *ifc; | |
449 | struct interface *ifp; | |
450 | struct kaddr ka; | |
451 | ||
121f9dee | 452 | ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
eac6e3f0 RW |
453 | if (ifc == NULL) |
454 | return (0); | |
455 | ||
456 | ifp = ifc->ifp; | |
457 | ifc2kaddr(ifp, ifc, &ka); | |
458 | ||
459 | /* Filter invalid addresses. */ | |
460 | if (bad_addr(ka.af, &ka.addr)) | |
461 | return (0); | |
462 | ||
9cf67225 RW |
463 | debug_zebra_in("address add %s/%u interface %s", |
464 | log_addr(ka.af, &ka.addr), ka.prefixlen, ifp->name); | |
eac6e3f0 RW |
465 | |
466 | /* notify ldpe about new address */ | |
467 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka)); | |
468 | ||
469 | return (0); | |
470 | } | |
471 | ||
472 | static int | |
121f9dee | 473 | ldp_interface_address_delete(ZAPI_CALLBACK_ARGS) |
eac6e3f0 RW |
474 | { |
475 | struct connected *ifc; | |
476 | struct interface *ifp; | |
477 | struct kaddr ka; | |
478 | ||
121f9dee | 479 | ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
eac6e3f0 RW |
480 | if (ifc == NULL) |
481 | return (0); | |
482 | ||
483 | ifp = ifc->ifp; | |
484 | ifc2kaddr(ifp, ifc, &ka); | |
721c0857 | 485 | connected_free(&ifc); |
eac6e3f0 RW |
486 | |
487 | /* Filter invalid addresses. */ | |
488 | if (bad_addr(ka.af, &ka.addr)) | |
489 | return (0); | |
490 | ||
9cf67225 RW |
491 | debug_zebra_in("address delete %s/%u interface %s", |
492 | log_addr(ka.af, &ka.addr), ka.prefixlen, ifp->name); | |
eac6e3f0 RW |
493 | |
494 | /* notify ldpe about removed address */ | |
495 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka)); | |
496 | ||
497 | return (0); | |
498 | } | |
499 | ||
500 | static int | |
121f9dee | 501 | ldp_zebra_read_route(ZAPI_CALLBACK_ARGS) |
eac6e3f0 | 502 | { |
74489921 RW |
503 | struct zapi_route api; |
504 | struct zapi_nexthop *api_nh; | |
eac6e3f0 | 505 | struct kroute kr; |
74489921 RW |
506 | int i, add = 0; |
507 | ||
508 | if (zapi_route_decode(zclient->ibuf, &api) < 0) | |
509 | return -1; | |
510 | ||
511 | /* we completely ignore srcdest routes for now. */ | |
512 | if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) | |
513 | return (0); | |
eac6e3f0 RW |
514 | |
515 | memset(&kr, 0, sizeof(kr)); | |
74489921 RW |
516 | kr.af = api.prefix.family; |
517 | switch (kr.af) { | |
518 | case AF_INET: | |
519 | kr.prefix.v4 = api.prefix.u.prefix4; | |
520 | break; | |
521 | case AF_INET6: | |
522 | kr.prefix.v6 = api.prefix.u.prefix6; | |
523 | break; | |
524 | default: | |
525 | break; | |
526 | } | |
527 | kr.prefixlen = api.prefix.prefixlen; | |
e132dea0 RW |
528 | kr.route_type = api.type; |
529 | kr.route_instance = api.instance; | |
eac6e3f0 | 530 | |
74489921 | 531 | switch (api.type) { |
a695cc7b | 532 | case ZEBRA_ROUTE_CONNECT: |
eac6e3f0 | 533 | kr.flags |= F_CONNECTED; |
a695cc7b RW |
534 | break; |
535 | case ZEBRA_ROUTE_BGP: | |
536 | /* LDP should follow the IGP and ignore BGP routes */ | |
537 | return (0); | |
538 | default: | |
539 | break; | |
540 | } | |
541 | ||
eac6e3f0 RW |
542 | if (bad_addr(kr.af, &kr.prefix) || |
543 | (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6))) | |
544 | return (0); | |
545 | ||
121f9dee | 546 | if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) |
1f2ff5b5 RW |
547 | add = 1; |
548 | ||
74489921 | 549 | if (api.nexthop_num == 0) |
1f2ff5b5 RW |
550 | debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete", |
551 | log_addr(kr.af, &kr.prefix), kr.prefixlen, | |
74489921 | 552 | zebra_route_string(api.type)); |
eac6e3f0 RW |
553 | |
554 | /* loop through all the nexthops */ | |
74489921 RW |
555 | for (i = 0; i < api.nexthop_num; i++) { |
556 | api_nh = &api.nexthops[i]; | |
cddef813 RW |
557 | switch (api_nh->type) { |
558 | case NEXTHOP_TYPE_IPV4: | |
559 | if (kr.af != AF_INET) | |
560 | continue; | |
561 | kr.nexthop.v4 = api_nh->gate.ipv4; | |
562 | kr.ifindex = 0; | |
563 | break; | |
564 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
565 | if (kr.af != AF_INET) | |
566 | continue; | |
74489921 | 567 | kr.nexthop.v4 = api_nh->gate.ipv4; |
cddef813 | 568 | kr.ifindex = api_nh->ifindex; |
eac6e3f0 | 569 | break; |
cddef813 RW |
570 | case NEXTHOP_TYPE_IPV6: |
571 | if (kr.af != AF_INET6) | |
572 | continue; | |
74489921 | 573 | kr.nexthop.v6 = api_nh->gate.ipv6; |
cddef813 | 574 | kr.ifindex = 0; |
eac6e3f0 | 575 | break; |
cddef813 RW |
576 | case NEXTHOP_TYPE_IPV6_IFINDEX: |
577 | if (kr.af != AF_INET6) | |
578 | continue; | |
579 | kr.nexthop.v6 = api_nh->gate.ipv6; | |
580 | kr.ifindex = api_nh->ifindex; | |
581 | break; | |
582 | case NEXTHOP_TYPE_IFINDEX: | |
583 | if (!(kr.flags & F_CONNECTED)) | |
584 | continue; | |
eac6e3f0 | 585 | break; |
4a055ac2 | 586 | case NEXTHOP_TYPE_BLACKHOLE: |
cddef813 | 587 | continue; |
eac6e3f0 | 588 | } |
eac6e3f0 | 589 | |
1f2ff5b5 RW |
590 | debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)", |
591 | (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix), | |
592 | kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex, | |
74489921 | 593 | zebra_route_string(api.type)); |
1f2ff5b5 RW |
594 | |
595 | if (add) | |
eac6e3f0 RW |
596 | main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr, |
597 | sizeof(kr)); | |
eac6e3f0 RW |
598 | } |
599 | ||
8cb1fc45 | 600 | main_imsg_compose_lde(IMSG_NETWORK_UPDATE, 0, &kr, sizeof(kr)); |
134970a2 | 601 | |
eac6e3f0 RW |
602 | return (0); |
603 | } | |
604 | ||
87b5f1b7 RW |
605 | /* |
606 | * Receive PW status update from Zebra and send it to LDE process. | |
607 | */ | |
608 | static int | |
121f9dee | 609 | ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS) |
87b5f1b7 RW |
610 | { |
611 | struct zapi_pw_status zpw; | |
612 | ||
121f9dee | 613 | zebra_read_pw_status_update(cmd, zclient, length, vrf_id, &zpw); |
87b5f1b7 | 614 | |
fd563cc7 KS |
615 | debug_zebra_in("pseudowire %s status %s 0x%x", zpw.ifname, |
616 | (zpw.status == PW_FORWARDING) ? "up" : "down", | |
617 | zpw.status); | |
87b5f1b7 RW |
618 | |
619 | main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw)); | |
620 | ||
621 | return (0); | |
622 | } | |
623 | ||
ce510d2e FR |
624 | void ldp_zebra_regdereg_zebra_info(bool want_register) |
625 | { | |
626 | if (zebra_registered == want_register) | |
627 | return; | |
628 | ||
629 | log_debug("%s to receive default VRF information", | |
630 | want_register ? "Register" : "De-register"); | |
631 | ||
632 | if (want_register) { | |
633 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
634 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
635 | ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); | |
636 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, | |
637 | AFI_IP6, ZEBRA_ROUTE_ALL, 0, | |
638 | VRF_DEFAULT); | |
639 | } else { | |
640 | zclient_send_dereg_requests(zclient, VRF_DEFAULT); | |
641 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, | |
642 | AFI_IP, ZEBRA_ROUTE_ALL, 0, | |
643 | VRF_DEFAULT); | |
644 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, | |
645 | AFI_IP6, ZEBRA_ROUTE_ALL, 0, | |
646 | VRF_DEFAULT); | |
647 | } | |
648 | zebra_registered = want_register; | |
649 | } | |
650 | ||
eac6e3f0 RW |
651 | static void |
652 | ldp_zebra_connected(struct zclient *zclient) | |
653 | { | |
ce510d2e FR |
654 | zebra_registered = false; |
655 | ||
656 | /* if MPLS was already enabled and we are re-connecting, register again | |
657 | */ | |
658 | if (vty_conf->flags & F_LDPD_ENABLED) | |
659 | ldp_zebra_regdereg_zebra_info(true); | |
e1894ff7 KS |
660 | |
661 | ldp_zebra_opaque_register(); | |
662 | ||
663 | ldp_sync_zebra_init(); | |
eac6e3f0 RW |
664 | } |
665 | ||
2d1aa1e8 | 666 | static void |
667 | ldp_zebra_filter_update(struct access_list *access) | |
668 | { | |
669 | struct ldp_access laccess; | |
670 | ||
671 | if (access && access->name[0] != '\0') { | |
672 | strlcpy(laccess.name, access->name, sizeof(laccess.name)); | |
3eff8e2f IR |
673 | debug_evt("%s ACL update filter name %s", __func__, |
674 | access->name); | |
2d1aa1e8 | 675 | |
676 | main_imsg_compose_both(IMSG_FILTER_UPDATE, &laccess, | |
677 | sizeof(laccess)); | |
678 | } | |
679 | } | |
680 | ||
342213ea DS |
681 | extern struct zebra_privs_t ldpd_privs; |
682 | ||
a243d1db DL |
683 | static zclient_handler *const ldp_handlers[] = { |
684 | [ZEBRA_ROUTER_ID_UPDATE] = ldp_router_id_update, | |
685 | [ZEBRA_INTERFACE_ADDRESS_ADD] = ldp_interface_address_add, | |
686 | [ZEBRA_INTERFACE_ADDRESS_DELETE] = ldp_interface_address_delete, | |
687 | [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ldp_zebra_read_route, | |
688 | [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ldp_zebra_read_route, | |
689 | [ZEBRA_PW_STATUS_UPDATE] = ldp_zebra_read_pw_status_update, | |
690 | [ZEBRA_OPAQUE_MESSAGE] = ldp_zebra_opaque_msg_handler, | |
691 | }; | |
692 | ||
eac6e3f0 RW |
693 | void |
694 | ldp_zebra_init(struct thread_master *master) | |
695 | { | |
138c5a74 DS |
696 | if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up, |
697 | ldp_ifp_down, ldp_ifp_destroy); | |
698 | ||
eac6e3f0 | 699 | /* Set default values. */ |
a243d1db DL |
700 | zclient = zclient_new(master, &zclient_options_default, ldp_handlers, |
701 | array_size(ldp_handlers)); | |
342213ea | 702 | zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs); |
eac6e3f0 RW |
703 | |
704 | /* set callbacks */ | |
705 | zclient->zebra_connected = ldp_zebra_connected; | |
2d1aa1e8 | 706 | |
707 | /* Access list initialize. */ | |
708 | access_list_add_hook(ldp_zebra_filter_update); | |
709 | access_list_delete_hook(ldp_zebra_filter_update); | |
eac6e3f0 | 710 | } |
64dffe25 RW |
711 | |
712 | void | |
713 | ldp_zebra_destroy(void) | |
714 | { | |
e1894ff7 | 715 | ldp_zebra_opaque_unregister(); |
64dffe25 RW |
716 | zclient_stop(zclient); |
717 | zclient_free(zclient); | |
718 | zclient = NULL; | |
719 | } |