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