1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* This file is part of Quagga.
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.
13 /* The following includes are needed in all OSPF API client
17 #include "prefix.h" /* needed by ospf_asbr.h */
20 #include "lib/printfrr.h"
22 /* work around gcc bug 69981, disable MTYPEs in libospf */
23 #define _QUAGGA_OSPF_MEMORY_H
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"
33 * set cap_num_* and uid/gid to nothing to use NULL privs
34 * as ospfapiclient links in libospf.a which uses privs.
36 struct zebra_privs_t ospfd_privs
= {.user
= NULL
,
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). */
45 #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */
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
54 struct thread_master
*master
;
56 /* Global variables */
57 struct ospf_apiclient
*oclient
;
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 */
67 /* ---------------------------------------------------------
68 * Threads for asynchronous messages and LSA update/delete
69 * ---------------------------------------------------------
72 static void lsa_delete(struct thread
*t
)
74 struct ospf_apiclient
*oclient
;
75 struct in_addr area_id
;
78 oclient
= THREAD_ARG(t
);
80 rc
= inet_aton(args
[6], &area_id
);
82 printf("Address Specified: %s is invalid\n", args
[6]);
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
);
95 static void lsa_inject(struct thread
*t
)
97 struct ospf_apiclient
*cl
;
98 struct in_addr ifaddr
;
99 struct in_addr area_id
;
106 static uint32_t counter
= 1; /* Incremented each time invoked */
111 rc
= inet_aton(args
[5], &ifaddr
);
113 printf("Ifaddr specified %s is invalid\n", args
[5]);
117 rc
= inet_aton(args
[6], &area_id
);
119 printf("Area ID specified %s is invalid\n", args
[6]);
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);
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
,
133 printf("done, return code is %d\n", rc
);
139 /* This thread handles asynchronous messages coming in from the OSPF
141 static void lsa_read(struct thread
*thread
)
143 struct ospf_apiclient
*oclient
;
147 printf("lsa_read called\n");
149 oclient
= THREAD_ARG(thread
);
150 fd
= THREAD_FD(thread
);
152 /* Handle asynchronous message */
153 ret
= ospf_apiclient_handle_async(oclient
);
155 printf("Connection closed, exiting...");
159 /* Reschedule read thread */
160 thread_add_read(master
, lsa_read
, oclient
, fd
, NULL
);
163 /* ---------------------------------------------------------
164 * Callback functions for asynchronous events
165 * ---------------------------------------------------------
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
)
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
);
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,
182 if (lsa->type == OSPF_ROUTER_LSA) {
183 struct router_lsa *rl = (struct router_lsa) lsa;
185 uint16_t links = rl->links;
190 ospf_lsa_header_dump(lsa
);
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
)
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
);
202 ospf_lsa_header_dump(lsa
);
205 static void ready_callback(uint8_t lsa_type
, uint8_t opaque_type
,
208 printfrr("ready_callback: lsa_type: %d opaque_type: %d addr=%pI4\n",
209 lsa_type
, opaque_type
, &addr
);
211 /* Schedule opaque LSA originate in 5 secs */
212 thread_add_timer(master
, lsa_inject
, oclient
, 5, NULL
);
214 /* Schedule opaque LSA update with new value */
215 thread_add_timer(master
, lsa_inject
, oclient
, 10, NULL
);
217 /* Schedule delete */
218 thread_add_timer(master
, lsa_delete
, oclient
, 30, NULL
);
221 static void new_if_callback(struct in_addr ifaddr
, struct in_addr area_id
)
223 printfrr("new_if_callback: ifaddr: %pI4 ", &ifaddr
);
224 printfrr("area_id: %pI4\n", &area_id
);
227 static void del_if_callback(struct in_addr ifaddr
)
229 printfrr("new_if_callback: ifaddr: %pI4\n ", &ifaddr
);
232 static void ism_change_callback(struct in_addr ifaddr
, struct in_addr area_id
,
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
));
241 static void nsm_change_callback(struct in_addr ifaddr
, struct in_addr nbraddr
,
242 struct in_addr router_id
, uint8_t state
)
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
));
252 /* ---------------------------------------------------------
254 * ---------------------------------------------------------
257 static int usage(void)
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");
270 int main(int argc
, char *argv
[])
272 struct thread thread
;
276 /* ospfclient should be started with the following arguments:
278 * (1) host (2) lsa_type (3) opaque_type (4) opaque_id (5) if_addr
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
294 zprivs_preinit(&ospfd_privs
);
295 zprivs_init(&ospfd_privs
);
296 master
= thread_master_create(NULL
);
298 /* Open connection to OSPF daemon */
299 oclient
= ospf_apiclient_connect(args
[1], ASYNCPORT
);
301 printf("Connecting to OSPF daemon on %s failed!\n", args
[1]);
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
);
311 /* Register LSA type and opaque type. */
312 ospf_apiclient_register_opaque_type(oclient
, atoi(args
[2]),
315 /* Synchronize database with OSPF daemon. */
316 ospf_apiclient_sync_lsdb(oclient
);
318 /* Schedule thread that handles asynchronous messages */
319 thread_add_read(master
, lsa_read
, oclient
, oclient
->fd_async
, NULL
);
321 /* Now connection is established, run loop */
323 thread_fetch(master
, &thread
);
324 thread_call(&thread
);