]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
f80ec39e RW |
2 | /* |
3 | * Copyright (C) 2018 NetDEF, Inc. | |
4 | * Renato Westphal | |
f80ec39e RW |
5 | */ |
6 | ||
7 | #include <zebra.h> | |
8 | ||
9 | #include "if.h" | |
10 | #include "vrf.h" | |
11 | #include "log.h" | |
12 | #include "prefix.h" | |
13 | #include "table.h" | |
14 | #include "command.h" | |
15 | #include "routemap.h" | |
16 | #include "northbound.h" | |
17 | #include "libfrr.h" | |
18 | ||
19 | #include "ripd/ripd.h" | |
20 | #include "ripd/rip_nb.h" | |
21 | #include "ripd/rip_debug.h" | |
22 | #include "ripd/rip_interface.h" | |
23 | ||
24 | /* | |
25 | * XPath: /frr-ripd:ripd/instance | |
26 | */ | |
60ee8be1 | 27 | const void *ripd_instance_get_next(struct nb_cb_get_next_args *args) |
f80ec39e | 28 | { |
60ee8be1 | 29 | struct rip *rip = (struct rip *)args->list_entry; |
f80ec39e | 30 | |
60ee8be1 | 31 | if (args->list_entry == NULL) |
f80ec39e RW |
32 | rip = RB_MIN(rip_instance_head, &rip_instances); |
33 | else | |
34 | rip = RB_NEXT(rip_instance_head, rip); | |
35 | ||
36 | return rip; | |
37 | } | |
38 | ||
60ee8be1 | 39 | int ripd_instance_get_keys(struct nb_cb_get_keys_args *args) |
f80ec39e | 40 | { |
60ee8be1 | 41 | const struct rip *rip = args->list_entry; |
f80ec39e | 42 | |
60ee8be1 RW |
43 | args->keys->num = 1; |
44 | strlcpy(args->keys->key[0], rip->vrf_name, sizeof(args->keys->key[0])); | |
f80ec39e RW |
45 | |
46 | return NB_OK; | |
47 | } | |
48 | ||
60ee8be1 | 49 | const void *ripd_instance_lookup_entry(struct nb_cb_lookup_entry_args *args) |
f80ec39e | 50 | { |
60ee8be1 | 51 | const char *vrf_name = args->keys->key[0]; |
f80ec39e RW |
52 | |
53 | return rip_lookup_by_vrf_name(vrf_name); | |
54 | } | |
55 | ||
56 | /* | |
57 | * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor | |
58 | */ | |
60ee8be1 RW |
59 | const void *ripd_instance_state_neighbors_neighbor_get_next( |
60 | struct nb_cb_get_next_args *args) | |
f80ec39e | 61 | { |
60ee8be1 | 62 | const struct rip *rip = args->parent_list_entry; |
f80ec39e RW |
63 | struct listnode *node; |
64 | ||
60ee8be1 | 65 | if (args->list_entry == NULL) |
f80ec39e RW |
66 | node = listhead(rip->peer_list); |
67 | else | |
60ee8be1 | 68 | node = listnextnode((struct listnode *)args->list_entry); |
f80ec39e RW |
69 | |
70 | return node; | |
71 | } | |
72 | ||
60ee8be1 RW |
73 | int ripd_instance_state_neighbors_neighbor_get_keys( |
74 | struct nb_cb_get_keys_args *args) | |
f80ec39e | 75 | { |
60ee8be1 | 76 | const struct listnode *node = args->list_entry; |
f80ec39e RW |
77 | const struct rip_peer *peer = listgetdata(node); |
78 | ||
60ee8be1 RW |
79 | args->keys->num = 1; |
80 | (void)inet_ntop(AF_INET, &peer->addr, args->keys->key[0], | |
81 | sizeof(args->keys->key[0])); | |
f80ec39e RW |
82 | |
83 | return NB_OK; | |
84 | } | |
85 | ||
86 | const void *ripd_instance_state_neighbors_neighbor_lookup_entry( | |
60ee8be1 | 87 | struct nb_cb_lookup_entry_args *args) |
f80ec39e | 88 | { |
60ee8be1 | 89 | const struct rip *rip = args->parent_list_entry; |
f80ec39e RW |
90 | struct in_addr address; |
91 | struct rip_peer *peer; | |
92 | struct listnode *node; | |
93 | ||
60ee8be1 | 94 | yang_str2ipv4(args->keys->key[0], &address); |
f80ec39e RW |
95 | |
96 | for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, peer)) { | |
97 | if (IPV4_ADDR_SAME(&peer->addr, &address)) | |
98 | return node; | |
99 | } | |
100 | ||
101 | return NULL; | |
102 | } | |
103 | ||
104 | /* | |
105 | * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/address | |
106 | */ | |
60ee8be1 RW |
107 | struct yang_data *ripd_instance_state_neighbors_neighbor_address_get_elem( |
108 | struct nb_cb_get_elem_args *args) | |
f80ec39e | 109 | { |
60ee8be1 | 110 | const struct listnode *node = args->list_entry; |
f80ec39e RW |
111 | const struct rip_peer *peer = listgetdata(node); |
112 | ||
60ee8be1 | 113 | return yang_data_new_ipv4(args->xpath, &peer->addr); |
f80ec39e RW |
114 | } |
115 | ||
116 | /* | |
117 | * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/last-update | |
118 | */ | |
119 | struct yang_data *ripd_instance_state_neighbors_neighbor_last_update_get_elem( | |
60ee8be1 | 120 | struct nb_cb_get_elem_args *args) |
f80ec39e RW |
121 | { |
122 | /* TODO: yang:date-and-time is tricky */ | |
123 | return NULL; | |
124 | } | |
125 | ||
126 | /* | |
127 | * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd | |
128 | */ | |
129 | struct yang_data * | |
130 | ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem( | |
60ee8be1 | 131 | struct nb_cb_get_elem_args *args) |
f80ec39e | 132 | { |
60ee8be1 | 133 | const struct listnode *node = args->list_entry; |
f80ec39e RW |
134 | const struct rip_peer *peer = listgetdata(node); |
135 | ||
60ee8be1 | 136 | return yang_data_new_uint32(args->xpath, peer->recv_badpackets); |
f80ec39e RW |
137 | } |
138 | ||
139 | /* | |
140 | * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd | |
141 | */ | |
142 | struct yang_data * | |
143 | ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem( | |
60ee8be1 | 144 | struct nb_cb_get_elem_args *args) |
f80ec39e | 145 | { |
60ee8be1 | 146 | const struct listnode *node = args->list_entry; |
f80ec39e RW |
147 | const struct rip_peer *peer = listgetdata(node); |
148 | ||
60ee8be1 | 149 | return yang_data_new_uint32(args->xpath, peer->recv_badroutes); |
f80ec39e RW |
150 | } |
151 | ||
152 | /* | |
153 | * XPath: /frr-ripd:ripd/instance/state/routes/route | |
154 | */ | |
155 | const void * | |
60ee8be1 | 156 | ripd_instance_state_routes_route_get_next(struct nb_cb_get_next_args *args) |
f80ec39e | 157 | { |
60ee8be1 | 158 | const struct rip *rip = args->parent_list_entry; |
f80ec39e RW |
159 | struct route_node *rn; |
160 | ||
60ee8be1 | 161 | if (args->list_entry == NULL) |
f80ec39e RW |
162 | rn = route_top(rip->table); |
163 | else | |
60ee8be1 | 164 | rn = route_next((struct route_node *)args->list_entry); |
78769ea2 | 165 | /* Optimization: skip empty route nodes. */ |
f80ec39e RW |
166 | while (rn && rn->info == NULL) |
167 | rn = route_next(rn); | |
168 | ||
169 | return rn; | |
170 | } | |
171 | ||
60ee8be1 | 172 | int ripd_instance_state_routes_route_get_keys(struct nb_cb_get_keys_args *args) |
f80ec39e | 173 | { |
60ee8be1 | 174 | const struct route_node *rn = args->list_entry; |
f80ec39e | 175 | |
60ee8be1 RW |
176 | args->keys->num = 1; |
177 | (void)prefix2str(&rn->p, args->keys->key[0], | |
178 | sizeof(args->keys->key[0])); | |
f80ec39e RW |
179 | |
180 | return NB_OK; | |
181 | } | |
182 | ||
60ee8be1 RW |
183 | const void *ripd_instance_state_routes_route_lookup_entry( |
184 | struct nb_cb_lookup_entry_args *args) | |
f80ec39e | 185 | { |
60ee8be1 | 186 | const struct rip *rip = args->parent_list_entry; |
f80ec39e RW |
187 | struct prefix prefix; |
188 | struct route_node *rn; | |
189 | ||
60ee8be1 | 190 | yang_str2ipv4p(args->keys->key[0], &prefix); |
f80ec39e RW |
191 | |
192 | rn = route_node_lookup(rip->table, &prefix); | |
193 | if (!rn || !rn->info) | |
194 | return NULL; | |
195 | ||
196 | route_unlock_node(rn); | |
197 | ||
198 | return rn; | |
199 | } | |
200 | ||
201 | /* | |
202 | * XPath: /frr-ripd:ripd/instance/state/routes/route/prefix | |
203 | */ | |
60ee8be1 RW |
204 | struct yang_data *ripd_instance_state_routes_route_prefix_get_elem( |
205 | struct nb_cb_get_elem_args *args) | |
f80ec39e | 206 | { |
60ee8be1 | 207 | const struct route_node *rn = args->list_entry; |
f80ec39e RW |
208 | const struct rip_info *rinfo = listnode_head(rn->info); |
209 | ||
7fd2ffb9 | 210 | assert(rinfo); |
60ee8be1 | 211 | return yang_data_new_ipv4p(args->xpath, &rinfo->rp->p); |
f80ec39e RW |
212 | } |
213 | ||
0b7f0e35 CH |
214 | /* |
215 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop | |
216 | */ | |
217 | const void *ripd_instance_state_routes_route_nexthops_nexthop_get_next( | |
218 | struct nb_cb_get_next_args *args) | |
219 | { | |
7fd2ffb9 CH |
220 | const struct route_node *rn = args->parent_list_entry; |
221 | const struct listnode *node = args->list_entry; | |
222 | ||
223 | assert(rn); | |
224 | if (node) | |
225 | return listnextnode(node); | |
226 | assert(rn->info); | |
227 | return listhead((struct list *)rn->info); | |
228 | } | |
229 | ||
230 | static inline const struct rip_info *get_rip_info(const void *info) | |
231 | { | |
232 | return (const struct rip_info *)listgetdata( | |
233 | (const struct listnode *)info); | |
0b7f0e35 CH |
234 | } |
235 | ||
236 | /* | |
237 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/nh-type | |
238 | */ | |
239 | struct yang_data * | |
240 | ripd_instance_state_routes_route_nexthops_nexthop_nh_type_get_elem( | |
241 | struct nb_cb_get_elem_args *args) | |
242 | { | |
7fd2ffb9 CH |
243 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
244 | ||
245 | assert(rinfo); | |
246 | return yang_data_new_enum(args->xpath, rinfo->nh.type); | |
0b7f0e35 CH |
247 | } |
248 | ||
249 | /* | |
250 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/protocol | |
251 | */ | |
252 | struct yang_data * | |
253 | ripd_instance_state_routes_route_nexthops_nexthop_protocol_get_elem( | |
254 | struct nb_cb_get_elem_args *args) | |
255 | { | |
7fd2ffb9 CH |
256 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
257 | ||
258 | assert(rinfo); | |
259 | return yang_data_new_enum(args->xpath, rinfo->type); | |
0b7f0e35 CH |
260 | } |
261 | ||
262 | /* | |
263 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/rip-type | |
264 | */ | |
265 | struct yang_data * | |
266 | ripd_instance_state_routes_route_nexthops_nexthop_rip_type_get_elem( | |
267 | struct nb_cb_get_elem_args *args) | |
268 | { | |
7fd2ffb9 CH |
269 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
270 | ||
271 | assert(rinfo); | |
272 | return yang_data_new_enum(args->xpath, rinfo->sub_type); | |
0b7f0e35 CH |
273 | } |
274 | ||
275 | /* | |
276 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/gateway | |
277 | */ | |
278 | struct yang_data * | |
279 | ripd_instance_state_routes_route_nexthops_nexthop_gateway_get_elem( | |
280 | struct nb_cb_get_elem_args *args) | |
281 | { | |
7fd2ffb9 CH |
282 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
283 | ||
284 | if (rinfo->nh.type != NEXTHOP_TYPE_IPV4 && | |
285 | rinfo->nh.type != NEXTHOP_TYPE_IPV4_IFINDEX) | |
286 | return NULL; | |
287 | ||
288 | return yang_data_new_ipv4(args->xpath, &rinfo->nh.gate.ipv4); | |
0b7f0e35 CH |
289 | } |
290 | ||
291 | /* | |
292 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/interface | |
293 | */ | |
294 | struct yang_data * | |
295 | ripd_instance_state_routes_route_nexthops_nexthop_interface_get_elem( | |
296 | struct nb_cb_get_elem_args *args) | |
297 | { | |
7fd2ffb9 CH |
298 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
299 | const struct rip *rip = rip_info_get_instance(rinfo); | |
300 | ||
301 | if (rinfo->nh.type != NEXTHOP_TYPE_IFINDEX && | |
302 | rinfo->nh.type != NEXTHOP_TYPE_IPV4_IFINDEX) | |
303 | return NULL; | |
304 | ||
305 | return yang_data_new_string( | |
306 | args->xpath, | |
307 | ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id)); | |
0b7f0e35 CH |
308 | } |
309 | ||
310 | /* | |
311 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/from | |
312 | */ | |
313 | struct yang_data * | |
314 | ripd_instance_state_routes_route_nexthops_nexthop_from_get_elem( | |
315 | struct nb_cb_get_elem_args *args) | |
316 | { | |
7fd2ffb9 CH |
317 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
318 | ||
319 | if (rinfo->type != ZEBRA_ROUTE_RIP || rinfo->sub_type != RIP_ROUTE_RTE) | |
320 | return NULL; | |
321 | ||
322 | return yang_data_new_ipv4(args->xpath, &rinfo->from); | |
0b7f0e35 CH |
323 | } |
324 | ||
325 | /* | |
326 | * XPath: /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/tag | |
327 | */ | |
328 | struct yang_data * | |
329 | ripd_instance_state_routes_route_nexthops_nexthop_tag_get_elem( | |
330 | struct nb_cb_get_elem_args *args) | |
331 | { | |
7fd2ffb9 CH |
332 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
333 | ||
334 | return yang_data_new_uint32(args->xpath, rinfo->tag); | |
0b7f0e35 CH |
335 | } |
336 | ||
337 | /* | |
338 | * XPath: | |
339 | * /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/external-metric | |
340 | */ | |
341 | struct yang_data * | |
342 | ripd_instance_state_routes_route_nexthops_nexthop_external_metric_get_elem( | |
343 | struct nb_cb_get_elem_args *args) | |
344 | { | |
7fd2ffb9 CH |
345 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
346 | ||
347 | if ((rinfo->type == ZEBRA_ROUTE_RIP && | |
348 | rinfo->sub_type == RIP_ROUTE_RTE) || | |
349 | rinfo->metric == RIP_METRIC_INFINITY || rinfo->external_metric == 0) | |
350 | return NULL; | |
351 | return yang_data_new_uint32(args->xpath, rinfo->external_metric); | |
0b7f0e35 CH |
352 | } |
353 | ||
354 | /* | |
355 | * XPath: | |
356 | * /frr-ripd:ripd/instance/state/routes/route/nexthops/nexthop/expire-time | |
357 | */ | |
358 | struct yang_data * | |
359 | ripd_instance_state_routes_route_nexthops_nexthop_expire_time_get_elem( | |
360 | struct nb_cb_get_elem_args *args) | |
361 | { | |
7fd2ffb9 CH |
362 | const struct rip_info *rinfo = get_rip_info(args->list_entry); |
363 | struct event *event; | |
364 | ||
365 | if ((event = rinfo->t_timeout) == NULL) | |
366 | event = rinfo->t_garbage_collect; | |
367 | if (!event) | |
368 | return NULL; | |
369 | ||
370 | return yang_data_new_uint32(args->xpath, | |
371 | event_timer_remain_second(event)); | |
0b7f0e35 CH |
372 | } |
373 | ||
f80ec39e RW |
374 | /* |
375 | * XPath: /frr-ripd:ripd/instance/state/routes/route/next-hop | |
376 | */ | |
60ee8be1 RW |
377 | struct yang_data *ripd_instance_state_routes_route_next_hop_get_elem( |
378 | struct nb_cb_get_elem_args *args) | |
f80ec39e | 379 | { |
60ee8be1 | 380 | const struct route_node *rn = args->list_entry; |
f80ec39e RW |
381 | const struct rip_info *rinfo = listnode_head(rn->info); |
382 | ||
383 | switch (rinfo->nh.type) { | |
384 | case NEXTHOP_TYPE_IPV4: | |
385 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
60ee8be1 | 386 | return yang_data_new_ipv4(args->xpath, &rinfo->nh.gate.ipv4); |
ec378ba0 DS |
387 | case NEXTHOP_TYPE_IFINDEX: |
388 | case NEXTHOP_TYPE_IPV6: | |
389 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
390 | case NEXTHOP_TYPE_BLACKHOLE: | |
f80ec39e RW |
391 | return NULL; |
392 | } | |
ec378ba0 DS |
393 | |
394 | assert(!"Reached end of function where we do not expect to reach"); | |
f80ec39e RW |
395 | } |
396 | ||
397 | /* | |
398 | * XPath: /frr-ripd:ripd/instance/state/routes/route/interface | |
399 | */ | |
60ee8be1 RW |
400 | struct yang_data *ripd_instance_state_routes_route_interface_get_elem( |
401 | struct nb_cb_get_elem_args *args) | |
f80ec39e | 402 | { |
60ee8be1 | 403 | const struct route_node *rn = args->list_entry; |
f80ec39e RW |
404 | const struct rip_info *rinfo = listnode_head(rn->info); |
405 | const struct rip *rip = rip_info_get_instance(rinfo); | |
406 | ||
407 | switch (rinfo->nh.type) { | |
408 | case NEXTHOP_TYPE_IFINDEX: | |
409 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
410 | return yang_data_new_string( | |
60ee8be1 | 411 | args->xpath, |
f80ec39e | 412 | ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id)); |
ec378ba0 DS |
413 | case NEXTHOP_TYPE_IPV4: |
414 | case NEXTHOP_TYPE_IPV6: | |
415 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
416 | case NEXTHOP_TYPE_BLACKHOLE: | |
f80ec39e RW |
417 | return NULL; |
418 | } | |
ec378ba0 DS |
419 | |
420 | assert(!"Reached end of function where we do not expect to reach"); | |
f80ec39e RW |
421 | } |
422 | ||
423 | /* | |
424 | * XPath: /frr-ripd:ripd/instance/state/routes/route/metric | |
425 | */ | |
60ee8be1 RW |
426 | struct yang_data *ripd_instance_state_routes_route_metric_get_elem( |
427 | struct nb_cb_get_elem_args *args) | |
f80ec39e | 428 | { |
60ee8be1 | 429 | const struct route_node *rn = args->list_entry; |
f80ec39e RW |
430 | const struct rip_info *rinfo = listnode_head(rn->info); |
431 | ||
60ee8be1 | 432 | return yang_data_new_uint8(args->xpath, rinfo->metric); |
f80ec39e | 433 | } |