1 /*
2  * Copyright (C) 2018  NetDEF, Inc.
3  *                     Renato Westphal
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; see the file COPYING; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <zebra.h>
21 
22 #include "if.h"
23 #include "vrf.h"
24 #include "log.h"
25 #include "prefix.h"
26 #include "table.h"
27 #include "command.h"
28 #include "routemap.h"
29 #include "northbound.h"
30 #include "libfrr.h"
31 
32 #include "ripd/ripd.h"
33 #include "ripd/rip_nb.h"
34 #include "ripd/rip_debug.h"
35 #include "ripd/rip_interface.h"
36 
37 /*
38  * XPath: /frr-ripd:ripd/instance
39  */
ripd_instance_get_next(struct nb_cb_get_next_args * args)40 const void *ripd_instance_get_next(struct nb_cb_get_next_args *args)
41 {
42 	struct rip *rip = (struct rip *)args->list_entry;
43 
44 	if (args->list_entry == NULL)
45 		rip = RB_MIN(rip_instance_head, &rip_instances);
46 	else
47 		rip = RB_NEXT(rip_instance_head, rip);
48 
49 	return rip;
50 }
51 
ripd_instance_get_keys(struct nb_cb_get_keys_args * args)52 int ripd_instance_get_keys(struct nb_cb_get_keys_args *args)
53 {
54 	const struct rip *rip = args->list_entry;
55 
56 	args->keys->num = 1;
57 	strlcpy(args->keys->key[0], rip->vrf_name, sizeof(args->keys->key[0]));
58 
59 	return NB_OK;
60 }
61 
ripd_instance_lookup_entry(struct nb_cb_lookup_entry_args * args)62 const void *ripd_instance_lookup_entry(struct nb_cb_lookup_entry_args *args)
63 {
64 	const char *vrf_name = args->keys->key[0];
65 
66 	return rip_lookup_by_vrf_name(vrf_name);
67 }
68 
69 /*
70  * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor
71  */
ripd_instance_state_neighbors_neighbor_get_next(struct nb_cb_get_next_args * args)72 const void *ripd_instance_state_neighbors_neighbor_get_next(
73 	struct nb_cb_get_next_args *args)
74 {
75 	const struct rip *rip = args->parent_list_entry;
76 	struct listnode *node;
77 
78 	if (args->list_entry == NULL)
79 		node = listhead(rip->peer_list);
80 	else
81 		node = listnextnode((struct listnode *)args->list_entry);
82 
83 	return node;
84 }
85 
ripd_instance_state_neighbors_neighbor_get_keys(struct nb_cb_get_keys_args * args)86 int ripd_instance_state_neighbors_neighbor_get_keys(
87 	struct nb_cb_get_keys_args *args)
88 {
89 	const struct listnode *node = args->list_entry;
90 	const struct rip_peer *peer = listgetdata(node);
91 
92 	args->keys->num = 1;
93 	(void)inet_ntop(AF_INET, &peer->addr, args->keys->key[0],
94 			sizeof(args->keys->key[0]));
95 
96 	return NB_OK;
97 }
98 
ripd_instance_state_neighbors_neighbor_lookup_entry(struct nb_cb_lookup_entry_args * args)99 const void *ripd_instance_state_neighbors_neighbor_lookup_entry(
100 	struct nb_cb_lookup_entry_args *args)
101 {
102 	const struct rip *rip = args->parent_list_entry;
103 	struct in_addr address;
104 	struct rip_peer *peer;
105 	struct listnode *node;
106 
107 	yang_str2ipv4(args->keys->key[0], &address);
108 
109 	for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, peer)) {
110 		if (IPV4_ADDR_SAME(&peer->addr, &address))
111 			return node;
112 	}
113 
114 	return NULL;
115 }
116 
117 /*
118  * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/address
119  */
ripd_instance_state_neighbors_neighbor_address_get_elem(struct nb_cb_get_elem_args * args)120 struct yang_data *ripd_instance_state_neighbors_neighbor_address_get_elem(
121 	struct nb_cb_get_elem_args *args)
122 {
123 	const struct listnode *node = args->list_entry;
124 	const struct rip_peer *peer = listgetdata(node);
125 
126 	return yang_data_new_ipv4(args->xpath, &peer->addr);
127 }
128 
129 /*
130  * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/last-update
131  */
ripd_instance_state_neighbors_neighbor_last_update_get_elem(struct nb_cb_get_elem_args * args)132 struct yang_data *ripd_instance_state_neighbors_neighbor_last_update_get_elem(
133 	struct nb_cb_get_elem_args *args)
134 {
135 	/* TODO: yang:date-and-time is tricky */
136 	return NULL;
137 }
138 
139 /*
140  * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd
141  */
142 struct yang_data *
ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(struct nb_cb_get_elem_args * args)143 ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
144 	struct nb_cb_get_elem_args *args)
145 {
146 	const struct listnode *node = args->list_entry;
147 	const struct rip_peer *peer = listgetdata(node);
148 
149 	return yang_data_new_uint32(args->xpath, peer->recv_badpackets);
150 }
151 
152 /*
153  * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd
154  */
155 struct yang_data *
ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(struct nb_cb_get_elem_args * args)156 ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
157 	struct nb_cb_get_elem_args *args)
158 {
159 	const struct listnode *node = args->list_entry;
160 	const struct rip_peer *peer = listgetdata(node);
161 
162 	return yang_data_new_uint32(args->xpath, peer->recv_badroutes);
163 }
164 
165 /*
166  * XPath: /frr-ripd:ripd/instance/state/routes/route
167  */
168 const void *
ripd_instance_state_routes_route_get_next(struct nb_cb_get_next_args * args)169 ripd_instance_state_routes_route_get_next(struct nb_cb_get_next_args *args)
170 {
171 	const struct rip *rip = args->parent_list_entry;
172 	struct route_node *rn;
173 
174 	if (args->list_entry == NULL)
175 		rn = route_top(rip->table);
176 	else
177 		rn = route_next((struct route_node *)args->list_entry);
178 	/* Optimization: skip empty route nodes. */
179 	while (rn && rn->info == NULL)
180 		rn = route_next(rn);
181 
182 	return rn;
183 }
184 
ripd_instance_state_routes_route_get_keys(struct nb_cb_get_keys_args * args)185 int ripd_instance_state_routes_route_get_keys(struct nb_cb_get_keys_args *args)
186 {
187 	const struct route_node *rn = args->list_entry;
188 
189 	args->keys->num = 1;
190 	(void)prefix2str(&rn->p, args->keys->key[0],
191 			 sizeof(args->keys->key[0]));
192 
193 	return NB_OK;
194 }
195 
ripd_instance_state_routes_route_lookup_entry(struct nb_cb_lookup_entry_args * args)196 const void *ripd_instance_state_routes_route_lookup_entry(
197 	struct nb_cb_lookup_entry_args *args)
198 {
199 	const struct rip *rip = args->parent_list_entry;
200 	struct prefix prefix;
201 	struct route_node *rn;
202 
203 	yang_str2ipv4p(args->keys->key[0], &prefix);
204 
205 	rn = route_node_lookup(rip->table, &prefix);
206 	if (!rn || !rn->info)
207 		return NULL;
208 
209 	route_unlock_node(rn);
210 
211 	return rn;
212 }
213 
214 /*
215  * XPath: /frr-ripd:ripd/instance/state/routes/route/prefix
216  */
ripd_instance_state_routes_route_prefix_get_elem(struct nb_cb_get_elem_args * args)217 struct yang_data *ripd_instance_state_routes_route_prefix_get_elem(
218 	struct nb_cb_get_elem_args *args)
219 {
220 	const struct route_node *rn = args->list_entry;
221 	const struct rip_info *rinfo = listnode_head(rn->info);
222 
223 	return yang_data_new_ipv4p(args->xpath, &rinfo->rp->p);
224 }
225 
226 /*
227  * XPath: /frr-ripd:ripd/instance/state/routes/route/next-hop
228  */
ripd_instance_state_routes_route_next_hop_get_elem(struct nb_cb_get_elem_args * args)229 struct yang_data *ripd_instance_state_routes_route_next_hop_get_elem(
230 	struct nb_cb_get_elem_args *args)
231 {
232 	const struct route_node *rn = args->list_entry;
233 	const struct rip_info *rinfo = listnode_head(rn->info);
234 
235 	switch (rinfo->nh.type) {
236 	case NEXTHOP_TYPE_IPV4:
237 	case NEXTHOP_TYPE_IPV4_IFINDEX:
238 		return yang_data_new_ipv4(args->xpath, &rinfo->nh.gate.ipv4);
239 	default:
240 		return NULL;
241 	}
242 }
243 
244 /*
245  * XPath: /frr-ripd:ripd/instance/state/routes/route/interface
246  */
ripd_instance_state_routes_route_interface_get_elem(struct nb_cb_get_elem_args * args)247 struct yang_data *ripd_instance_state_routes_route_interface_get_elem(
248 	struct nb_cb_get_elem_args *args)
249 {
250 	const struct route_node *rn = args->list_entry;
251 	const struct rip_info *rinfo = listnode_head(rn->info);
252 	const struct rip *rip = rip_info_get_instance(rinfo);
253 
254 	switch (rinfo->nh.type) {
255 	case NEXTHOP_TYPE_IFINDEX:
256 	case NEXTHOP_TYPE_IPV4_IFINDEX:
257 		return yang_data_new_string(
258 			args->xpath,
259 			ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id));
260 	default:
261 		return NULL;
262 	}
263 }
264 
265 /*
266  * XPath: /frr-ripd:ripd/instance/state/routes/route/metric
267  */
ripd_instance_state_routes_route_metric_get_elem(struct nb_cb_get_elem_args * args)268 struct yang_data *ripd_instance_state_routes_route_metric_get_elem(
269 	struct nb_cb_get_elem_args *args)
270 {
271 	const struct route_node *rn = args->list_entry;
272 	const struct rip_info *rinfo = listnode_head(rn->info);
273 
274 	return yang_data_new_uint8(args->xpath, rinfo->metric);
275 }
276