]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7f57883e DS |
2 | /* |
3 | * Zebra connect library for EIGRP. | |
4 | * Copyright (C) 2013-2014 | |
5 | * Authors: | |
6 | * Donnie Savage | |
7 | * Jan Janovic | |
8 | * Matej Perina | |
9 | * Peter Orsag | |
10 | * Peter Paluch | |
7f57883e DS |
11 | */ |
12 | ||
13 | #include <zebra.h> | |
14 | ||
24a58196 | 15 | #include "frrevent.h" |
7f57883e DS |
16 | #include "command.h" |
17 | #include "network.h" | |
18 | #include "prefix.h" | |
19 | #include "routemap.h" | |
20 | #include "table.h" | |
21 | #include "stream.h" | |
22 | #include "memory.h" | |
23 | #include "zclient.h" | |
24 | #include "filter.h" | |
25 | #include "plist.h" | |
26 | #include "log.h" | |
27 | #include "nexthop.h" | |
28 | ||
e9f1847e | 29 | #include "eigrpd/eigrp_types.h" |
7f57883e DS |
30 | #include "eigrpd/eigrp_structs.h" |
31 | #include "eigrpd/eigrpd.h" | |
32 | #include "eigrpd/eigrp_interface.h" | |
33 | #include "eigrpd/eigrp_neighbor.h" | |
34 | #include "eigrpd/eigrp_packet.h" | |
35 | #include "eigrpd/eigrp_zebra.h" | |
36 | #include "eigrpd/eigrp_vty.h" | |
37 | #include "eigrpd/eigrp_dump.h" | |
38 | #include "eigrpd/eigrp_network.h" | |
39 | #include "eigrpd/eigrp_topology.h" | |
40 | #include "eigrpd/eigrp_fsm.h" | |
e9f1847e | 41 | #include "eigrpd/eigrp_metric.h" |
7f57883e | 42 | |
121f9dee QY |
43 | static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS); |
44 | static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS); | |
d62a17ae | 45 | |
121f9dee | 46 | static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS); |
7f57883e DS |
47 | |
48 | /* Zebra structure to hold current status. */ | |
49 | struct zclient *zclient = NULL; | |
50 | ||
51 | /* For registering threads. */ | |
cd9d0537 | 52 | extern struct event_loop *master; |
7f57883e DS |
53 | struct in_addr router_id_zebra; |
54 | ||
55 | /* Router-id update message from zebra. */ | |
121f9dee | 56 | static int eigrp_router_id_update_zebra(ZAPI_CALLBACK_ARGS) |
7f57883e | 57 | { |
d62a17ae | 58 | struct eigrp *eigrp; |
59 | struct prefix router_id; | |
60 | zebra_router_id_update_read(zclient->ibuf, &router_id); | |
7f57883e | 61 | |
d62a17ae | 62 | router_id_zebra = router_id.u.prefix4; |
7f57883e | 63 | |
e9449961 | 64 | eigrp = eigrp_lookup(vrf_id); |
7f57883e | 65 | |
d62a17ae | 66 | if (eigrp != NULL) |
67 | eigrp_router_id_update(eigrp); | |
7f57883e | 68 | |
d62a17ae | 69 | return 0; |
7f57883e DS |
70 | } |
71 | ||
121f9dee | 72 | static int eigrp_zebra_route_notify_owner(ZAPI_CALLBACK_ARGS) |
ca890872 DS |
73 | { |
74 | struct prefix p; | |
75 | enum zapi_route_notify_owner note; | |
28610f7e | 76 | uint32_t table; |
ca890872 | 77 | |
77b38a4a S |
78 | if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, ¬e, NULL, |
79 | NULL)) | |
ca890872 DS |
80 | return -1; |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
d62a17ae | 85 | static void eigrp_zebra_connected(struct zclient *zclient) |
08ff1a68 | 86 | { |
d62a17ae | 87 | zclient_send_reg_requests(zclient, VRF_DEFAULT); |
08ff1a68 | 88 | } |
7f57883e | 89 | |
a243d1db DL |
90 | static zclient_handler *const eigrp_handlers[] = { |
91 | [ZEBRA_ROUTER_ID_UPDATE] = eigrp_router_id_update_zebra, | |
92 | [ZEBRA_INTERFACE_ADDRESS_ADD] = eigrp_interface_address_add, | |
93 | [ZEBRA_INTERFACE_ADDRESS_DELETE] = eigrp_interface_address_delete, | |
94 | [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = eigrp_zebra_read_route, | |
95 | [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = eigrp_zebra_read_route, | |
96 | [ZEBRA_ROUTE_NOTIFY_OWNER] = eigrp_zebra_route_notify_owner, | |
97 | }; | |
98 | ||
d62a17ae | 99 | void eigrp_zebra_init(void) |
7f57883e | 100 | { |
996c9314 | 101 | struct zclient_options opt = {.receive_notify = false}; |
ca890872 | 102 | |
a243d1db DL |
103 | zclient = zclient_new(master, &opt, eigrp_handlers, |
104 | array_size(eigrp_handlers)); | |
d62a17ae | 105 | |
342213ea | 106 | zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); |
d62a17ae | 107 | zclient->zebra_connected = eigrp_zebra_connected; |
7f57883e DS |
108 | } |
109 | ||
110 | ||
111 | /* Zebra route add and delete treatment. */ | |
121f9dee | 112 | static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS) |
7f57883e | 113 | { |
74489921 | 114 | struct zapi_route api; |
d62a17ae | 115 | struct eigrp *eigrp; |
116 | ||
74489921 RW |
117 | if (zapi_route_decode(zclient->ibuf, &api) < 0) |
118 | return -1; | |
d62a17ae | 119 | |
74489921 | 120 | if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr))) |
d62a17ae | 121 | return 0; |
122 | ||
e9449961 | 123 | eigrp = eigrp_lookup(vrf_id); |
d62a17ae | 124 | if (eigrp == NULL) |
125 | return 0; | |
126 | ||
121f9dee | 127 | if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { |
d62a17ae | 128 | |
121f9dee | 129 | } else /* if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */ |
d62a17ae | 130 | { |
131 | } | |
132 | ||
133 | return 0; | |
7f57883e DS |
134 | } |
135 | ||
121f9dee | 136 | static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS) |
7f57883e | 137 | { |
d62a17ae | 138 | struct connected *c; |
7f57883e | 139 | |
121f9dee | 140 | c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
7f57883e | 141 | |
d62a17ae | 142 | if (c == NULL) |
143 | return 0; | |
7f57883e | 144 | |
2dbe669b DA |
145 | if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) |
146 | zlog_debug("Zebra: interface %s address add %pFX", c->ifp->name, | |
147 | c->address); | |
7f57883e | 148 | |
d62a17ae | 149 | eigrp_if_update(c->ifp); |
7f57883e | 150 | |
d62a17ae | 151 | return 0; |
7f57883e DS |
152 | } |
153 | ||
121f9dee | 154 | static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS) |
7f57883e | 155 | { |
d62a17ae | 156 | struct connected *c; |
157 | struct interface *ifp; | |
158 | struct eigrp_interface *ei; | |
7f57883e | 159 | |
121f9dee | 160 | c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
7f57883e | 161 | |
d62a17ae | 162 | if (c == NULL) |
163 | return 0; | |
7f57883e | 164 | |
2dbe669b DA |
165 | if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) |
166 | zlog_debug("Zebra: interface %s address delete %pFX", | |
167 | c->ifp->name, c->address); | |
7f57883e | 168 | |
d62a17ae | 169 | ifp = c->ifp; |
b748db67 DS |
170 | ei = ifp->info; |
171 | if (!ei) | |
d62a17ae | 172 | return 0; |
7f57883e | 173 | |
d62a17ae | 174 | /* Call interface hook functions to clean up */ |
84b5e534 DS |
175 | if (prefix_cmp(&ei->address, c->address) == 0) |
176 | eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); | |
7f57883e | 177 | |
721c0857 | 178 | connected_free(&c); |
7f57883e | 179 | |
d62a17ae | 180 | return 0; |
7f57883e DS |
181 | } |
182 | ||
0e64ed02 DS |
183 | void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p, |
184 | struct list *successors, uint32_t distance) | |
7f57883e | 185 | { |
8fb753e3 RW |
186 | struct zapi_route api; |
187 | struct zapi_nexthop *api_nh; | |
dc4accdd | 188 | struct eigrp_route_descriptor *te; |
d62a17ae | 189 | struct listnode *node; |
8fb753e3 | 190 | int count = 0; |
d62a17ae | 191 | |
d00061ea RW |
192 | if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) |
193 | return; | |
194 | ||
8fb753e3 | 195 | memset(&api, 0, sizeof(api)); |
0e64ed02 | 196 | api.vrf_id = eigrp->vrf_id; |
8fb753e3 RW |
197 | api.type = ZEBRA_ROUTE_EIGRP; |
198 | api.safi = SAFI_UNICAST; | |
0f9bc496 | 199 | api.metric = distance; |
8fb753e3 | 200 | memcpy(&api.prefix, p, sizeof(*p)); |
d00061ea | 201 | |
8fb753e3 | 202 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); |
0f9bc496 | 203 | SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); |
d00061ea RW |
204 | |
205 | /* Nexthop, ifindex, distance and metric information. */ | |
206 | for (ALL_LIST_ELEMENTS_RO(successors, node, te)) { | |
a74e593b RW |
207 | if (count >= MULTIPATH_NUM) |
208 | break; | |
8fb753e3 | 209 | api_nh = &api.nexthops[count]; |
0e64ed02 | 210 | api_nh->vrf_id = eigrp->vrf_id; |
d00061ea | 211 | if (te->adv_router->src.s_addr) { |
8fb753e3 RW |
212 | api_nh->gate.ipv4 = te->adv_router->src; |
213 | api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; | |
d00061ea | 214 | } else |
8fb753e3 RW |
215 | api_nh->type = NEXTHOP_TYPE_IFINDEX; |
216 | api_nh->ifindex = te->ei->ifp->ifindex; | |
217 | ||
218 | count++; | |
d00061ea | 219 | } |
a74e593b | 220 | api.nexthop_num = count; |
d62a17ae | 221 | |
d00061ea | 222 | if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { |
4f278784 | 223 | zlog_debug("Zebra: Route add %pFX", p); |
d00061ea | 224 | } |
d62a17ae | 225 | |
8fb753e3 | 226 | zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
7f57883e DS |
227 | } |
228 | ||
0e64ed02 | 229 | void eigrp_zebra_route_delete(struct eigrp *eigrp, struct prefix *p) |
7f57883e | 230 | { |
8fb753e3 | 231 | struct zapi_route api; |
d62a17ae | 232 | |
d00061ea RW |
233 | if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) |
234 | return; | |
235 | ||
8fb753e3 | 236 | memset(&api, 0, sizeof(api)); |
0e64ed02 | 237 | api.vrf_id = eigrp->vrf_id; |
d00061ea | 238 | api.type = ZEBRA_ROUTE_EIGRP; |
d00061ea | 239 | api.safi = SAFI_UNICAST; |
8fb753e3 RW |
240 | memcpy(&api.prefix, p, sizeof(*p)); |
241 | zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); | |
d00061ea | 242 | |
2dbe669b DA |
243 | if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) |
244 | zlog_debug("Zebra: Route del %pFX", p); | |
d62a17ae | 245 | |
246 | return; | |
7f57883e DS |
247 | } |
248 | ||
0e64ed02 | 249 | static int eigrp_is_type_redistributed(int type, vrf_id_t vrf_id) |
7f57883e | 250 | { |
d62a17ae | 251 | return ((DEFAULT_ROUTE_TYPE(type)) |
49db7a7b | 252 | ? vrf_bitmap_check(zclient->default_information[AFI_IP], |
0e64ed02 | 253 | vrf_id) |
d62a17ae | 254 | : vrf_bitmap_check(zclient->redist[AFI_IP][type], |
0e64ed02 | 255 | vrf_id)); |
7f57883e DS |
256 | } |
257 | ||
d62a17ae | 258 | int eigrp_redistribute_set(struct eigrp *eigrp, int type, |
259 | struct eigrp_metrics metric) | |
7f57883e DS |
260 | { |
261 | ||
0e64ed02 | 262 | if (eigrp_is_type_redistributed(type, eigrp->vrf_id)) { |
d62a17ae | 263 | if (eigrp_metrics_is_same(metric, eigrp->dmetric[type])) { |
264 | eigrp->dmetric[type] = metric; | |
265 | } | |
7f57883e | 266 | |
d62a17ae | 267 | eigrp_external_routes_refresh(eigrp, type); |
7f57883e | 268 | |
d62a17ae | 269 | // if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) |
270 | // zlog_debug ("Redistribute[%s]: Refresh Type[%d], | |
271 | // Metric[%d]", | |
272 | // eigrp_redist_string(type), | |
273 | // metric_type (eigrp, type), metric_value | |
274 | // (eigrp, type)); | |
275 | return CMD_SUCCESS; | |
276 | } | |
7f57883e | 277 | |
d62a17ae | 278 | eigrp->dmetric[type] = metric; |
7f57883e | 279 | |
d62a17ae | 280 | zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, 0, |
daa64bdf | 281 | eigrp->vrf_id); |
7f57883e | 282 | |
d62a17ae | 283 | ++eigrp->redistribute; |
7f57883e | 284 | |
d62a17ae | 285 | return CMD_SUCCESS; |
7f57883e DS |
286 | } |
287 | ||
d62a17ae | 288 | int eigrp_redistribute_unset(struct eigrp *eigrp, int type) |
7f57883e DS |
289 | { |
290 | ||
0e64ed02 | 291 | if (eigrp_is_type_redistributed(type, eigrp->vrf_id)) { |
d62a17ae | 292 | memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics)); |
293 | zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, | |
daa64bdf | 294 | type, 0, eigrp->vrf_id); |
d62a17ae | 295 | --eigrp->redistribute; |
296 | } | |
7f57883e | 297 | |
d62a17ae | 298 | return CMD_SUCCESS; |
7f57883e | 299 | } |