]> git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospfclient.c
*: Add camelCase JSON keys in addition to PascalCase
[mirror_frr.git] / ospfclient / ospfclient.c
1 /* This file is part of Quagga.
2 *
3 * Quagga is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License as published by the
5 * Free Software Foundation; either version 2, or (at your option) any
6 * later version.
7 *
8 * Quagga is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; see the file COPYING; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 /*
19 * Simple program to demonstrate how OSPF API can be used. This
20 * application retrieves the LSDB from the OSPF daemon and then
21 * originates, updates and finally deletes an application-specific
22 * opaque LSA. You can use this application as a template when writing
23 * your own application.
24 */
25
26 /* The following includes are needed in all OSPF API client
27 applications. */
28
29 #include <zebra.h>
30 #include "prefix.h" /* needed by ospf_asbr.h */
31 #include "privs.h"
32 #include "log.h"
33 #include "lib/printfrr.h"
34
35 /* work around gcc bug 69981, disable MTYPEs in libospf */
36 #define _QUAGGA_OSPF_MEMORY_H
37
38 #include "ospfd/ospfd.h"
39 #include "ospfd/ospf_asbr.h"
40 #include "ospfd/ospf_lsa.h"
41 #include "ospfd/ospf_opaque.h"
42 #include "ospfd/ospf_api.h"
43 #include "ospf_apiclient.h"
44
45 /* privileges struct.
46 * set cap_num_* and uid/gid to nothing to use NULL privs
47 * as ospfapiclient links in libospf.a which uses privs.
48 */
49 struct zebra_privs_t ospfd_privs = {.user = NULL,
50 .group = NULL,
51 .cap_num_p = 0,
52 .cap_num_i = 0};
53
54 /* The following includes are specific to this application. For
55 example it uses threads from libfrr, however your application is
56 free to use any thread library (like pthreads). */
57
58 #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */
59 #include "thread.h"
60 #include "log.h"
61
62 /* Local portnumber for async channel. Note that OSPF API library will also
63 allocate a sync channel at ASYNCPORT+1. */
64 #define ASYNCPORT 4000
65
66 /* Master thread */
67 struct thread_master *master;
68
69 /* Global variables */
70 struct ospf_apiclient *oclient;
71 char **args;
72
73 /* Our opaque LSAs have the following format. */
74 struct my_opaque_lsa {
75 struct lsa_header hdr; /* include common LSA header */
76 uint8_t data[4]; /* our own data format then follows here */
77 };
78
79
80 /* ---------------------------------------------------------
81 * Threads for asynchronous messages and LSA update/delete
82 * ---------------------------------------------------------
83 */
84
85 static int lsa_delete(struct thread *t)
86 {
87 struct ospf_apiclient *oclient;
88 struct in_addr area_id;
89 int rc;
90
91 oclient = THREAD_ARG(t);
92
93 rc = inet_aton(args[6], &area_id);
94 if (rc <= 0) {
95 printf("Address Specified: %s is invalid\n", args[6]);
96 return rc;
97 }
98
99 printf("Deleting LSA... ");
100 rc = ospf_apiclient_lsa_delete(oclient, area_id,
101 atoi(args[2]), /* lsa type */
102 atoi(args[3]), /* opaque type */
103 atoi(args[4])); /* opaque ID */
104 printf("done, return code is = %d\n", rc);
105 return rc;
106 }
107
108 static int lsa_inject(struct thread *t)
109 {
110 struct ospf_apiclient *cl;
111 struct in_addr ifaddr;
112 struct in_addr area_id;
113 uint8_t lsa_type;
114 uint8_t opaque_type;
115 uint32_t opaque_id;
116 void *opaquedata;
117 int opaquelen;
118
119 static uint32_t counter = 1; /* Incremented each time invoked */
120 int rc;
121
122 cl = THREAD_ARG(t);
123
124 rc = inet_aton(args[5], &ifaddr);
125 if (rc <= 0) {
126 printf("Ifaddr specified %s is invalid\n", args[5]);
127 return rc;
128 }
129
130 rc = inet_aton(args[6], &area_id);
131 if (rc <= 0) {
132 printf("Area ID specified %s is invalid\n", args[6]);
133 return rc;
134 }
135 lsa_type = atoi(args[2]);
136 opaque_type = atoi(args[3]);
137 opaque_id = atoi(args[4]);
138 opaquedata = &counter;
139 opaquelen = sizeof(uint32_t);
140
141 printf("Originating/updating LSA with counter=%d... ", counter);
142 rc = ospf_apiclient_lsa_originate(cl, ifaddr, area_id, lsa_type,
143 opaque_type, opaque_id, opaquedata,
144 opaquelen);
145
146 printf("done, return code is %d\n", rc);
147
148 counter++;
149
150 return 0;
151 }
152
153
154 /* This thread handles asynchronous messages coming in from the OSPF
155 API server */
156 static int lsa_read(struct thread *thread)
157 {
158 struct ospf_apiclient *oclient;
159 int fd;
160 int ret;
161
162 printf("lsa_read called\n");
163
164 oclient = THREAD_ARG(thread);
165 fd = THREAD_FD(thread);
166
167 /* Handle asynchronous message */
168 ret = ospf_apiclient_handle_async(oclient);
169 if (ret < 0) {
170 printf("Connection closed, exiting...");
171 exit(0);
172 }
173
174 /* Reschedule read thread */
175 thread_add_read(master, lsa_read, oclient, fd, NULL);
176
177 return 0;
178 }
179
180 /* ---------------------------------------------------------
181 * Callback functions for asynchronous events
182 * ---------------------------------------------------------
183 */
184
185 static void lsa_update_callback(struct in_addr ifaddr, struct in_addr area_id,
186 uint8_t is_self_originated,
187 struct lsa_header *lsa)
188 {
189 printf("lsa_update_callback: ");
190 printfrr("ifaddr: %pI4 ", &ifaddr);
191 printfrr("area: %pI4\n", &area_id);
192 printf("is_self_origin: %u\n", is_self_originated);
193
194 /* It is important to note that lsa_header does indeed include the
195 header and the LSA payload. To access the payload, first check
196 the LSA type and then typecast lsa into the corresponding type,
197 e.g.:
198
199 if (lsa->type == OSPF_ROUTER_LSA) {
200 struct router_lsa *rl = (struct router_lsa) lsa;
201 ...
202 uint16_t links = rl->links;
203 ...
204 }
205 */
206
207 ospf_lsa_header_dump(lsa);
208 }
209
210 static void lsa_delete_callback(struct in_addr ifaddr, struct in_addr area_id,
211 uint8_t is_self_originated,
212 struct lsa_header *lsa)
213 {
214 printf("lsa_delete_callback: ");
215 printf("ifaddr: %pI4 ", &ifaddr);
216 printf("area: %pI4\n", &area_id);
217 printf("is_self_origin: %u\n", is_self_originated);
218
219 ospf_lsa_header_dump(lsa);
220 }
221
222 static void ready_callback(uint8_t lsa_type, uint8_t opaque_type,
223 struct in_addr addr)
224 {
225 printfrr("ready_callback: lsa_type: %d opaque_type: %d addr=%pI4\n",
226 lsa_type, opaque_type, &addr);
227
228 /* Schedule opaque LSA originate in 5 secs */
229 thread_add_timer(master, lsa_inject, oclient, 5, NULL);
230
231 /* Schedule opaque LSA update with new value */
232 thread_add_timer(master, lsa_inject, oclient, 10, NULL);
233
234 /* Schedule delete */
235 thread_add_timer(master, lsa_delete, oclient, 30, NULL);
236 }
237
238 static void new_if_callback(struct in_addr ifaddr, struct in_addr area_id)
239 {
240 printfrr("new_if_callback: ifaddr: %pI4 ", &ifaddr);
241 printfrr("area_id: %pI4\n", &area_id);
242 }
243
244 static void del_if_callback(struct in_addr ifaddr)
245 {
246 printfrr("new_if_callback: ifaddr: %pI4\n ", &ifaddr);
247 }
248
249 static void ism_change_callback(struct in_addr ifaddr, struct in_addr area_id,
250 uint8_t state)
251 {
252 printfrr("ism_change: ifaddr: %pI4 ", &ifaddr);
253 printfrr("area_id: %pI4\n", &area_id);
254 printf("state: %d [%s]\n", state,
255 lookup_msg(ospf_ism_state_msg, state, NULL));
256 }
257
258 static void nsm_change_callback(struct in_addr ifaddr, struct in_addr nbraddr,
259 struct in_addr router_id, uint8_t state)
260 {
261 printfrr("nsm_change: ifaddr: %pI4 ", &ifaddr);
262 printfrr("nbraddr: %pI4\n", &nbraddr);
263 printfrr("router_id: %pI4\n", &router_id);
264 printf("state: %d [%s]\n", state,
265 lookup_msg(ospf_nsm_state_msg, state, NULL));
266 }
267
268
269 /* ---------------------------------------------------------
270 * Main program
271 * ---------------------------------------------------------
272 */
273
274 static int usage(void)
275 {
276 printf("Usage: ospfclient <ospfd> <lsatype> <opaquetype> <opaqueid> <ifaddr> <areaid>\n");
277 printf("where ospfd : router where API-enabled OSPF daemon is running\n");
278 printf(" lsatype : either 9, 10, or 11 depending on flooding scope\n");
279 printf(" opaquetype: 0-255 (e.g., experimental applications use > 128)\n");
280 printf(" opaqueid : arbitrary application instance (24 bits)\n");
281 printf(" ifaddr : interface IP address (for type 9) otherwise ignored\n");
282 printf(" areaid : area in IP address format (for type 10) otherwise ignored\n");
283
284 exit(1);
285 }
286
287 int main(int argc, char *argv[])
288 {
289 struct thread thread;
290
291 args = argv;
292
293 /* ospfclient should be started with the following arguments:
294 *
295 * (1) host (2) lsa_type (3) opaque_type (4) opaque_id (5) if_addr
296 * (6) area_id
297 *
298 * host: name or IP of host where ospfd is running
299 * lsa_type: 9, 10, or 11
300 * opaque_type: 0-255 (e.g., experimental applications use > 128)
301 * opaque_id: arbitrary application instance (24 bits)
302 * if_addr: interface IP address (for type 9) otherwise ignored
303 * area_id: area in IP address format (for type 10) otherwise ignored
304 */
305
306 if (argc != 7) {
307 usage();
308 }
309
310 /* Initialization */
311 zprivs_preinit(&ospfd_privs);
312 zprivs_init(&ospfd_privs);
313 master = thread_master_create(NULL);
314
315 /* Open connection to OSPF daemon */
316 oclient = ospf_apiclient_connect(args[1], ASYNCPORT);
317 if (!oclient) {
318 printf("Connecting to OSPF daemon on %s failed!\n", args[1]);
319 exit(1);
320 }
321
322 /* Register callback functions. */
323 ospf_apiclient_register_callback(
324 oclient, ready_callback, new_if_callback, del_if_callback,
325 ism_change_callback, nsm_change_callback, lsa_update_callback,
326 lsa_delete_callback);
327
328 /* Register LSA type and opaque type. */
329 ospf_apiclient_register_opaque_type(oclient, atoi(args[2]),
330 atoi(args[3]));
331
332 /* Synchronize database with OSPF daemon. */
333 ospf_apiclient_sync_lsdb(oclient);
334
335 /* Schedule thread that handles asynchronous messages */
336 thread_add_read(master, lsa_read, oclient, oclient->fd_async, NULL);
337
338 /* Now connection is established, run loop */
339 while (1) {
340 thread_fetch(master, &thread);
341 thread_call(&thread);
342 }
343
344 /* Never reached */
345 return 0;
346 }