]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
46f4a4d2 | 2 | /* This file is part of Quagga. |
46f4a4d2 PJ |
3 | */ |
4 | ||
d62a17ae | 5 | /* |
f894c3ad | 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. | |
2d33f157 | 11 | */ |
12 | ||
13 | /* The following includes are needed in all OSPF API client | |
f894c3ad | 14 | applications. */ |
2d33f157 | 15 | |
16 | #include <zebra.h> | |
f894c3ad | 17 | #include "prefix.h" /* needed by ospf_asbr.h */ |
edd7c245 | 18 | #include "privs.h" |
3fc1eca9 | 19 | #include "log.h" |
d0b0a2c5 | 20 | #include "lib/printfrr.h" |
edd7c245 | 21 | |
5c088023 DL |
22 | /* work around gcc bug 69981, disable MTYPEs in libospf */ |
23 | #define _QUAGGA_OSPF_MEMORY_H | |
24 | ||
2d33f157 | 25 | #include "ospfd/ospfd.h" |
26 | #include "ospfd/ospf_asbr.h" | |
27 | #include "ospfd/ospf_lsa.h" | |
28 | #include "ospfd/ospf_opaque.h" | |
2d33f157 | 29 | #include "ospfd/ospf_api.h" |
30 | #include "ospf_apiclient.h" | |
31 | ||
d62a17ae | 32 | /* privileges struct. |
edd7c245 | 33 | * set cap_num_* and uid/gid to nothing to use NULL privs |
34 | * as ospfapiclient links in libospf.a which uses privs. | |
35 | */ | |
d62a17ae | 36 | struct zebra_privs_t ospfd_privs = {.user = NULL, |
37 | .group = NULL, | |
38 | .cap_num_p = 0, | |
39 | .cap_num_i = 0}; | |
edd7c245 | 40 | |
f894c3ad | 41 | /* The following includes are specific to this application. For |
55c72803 | 42 | example it uses threads from libfrr, however your application is |
f894c3ad | 43 | free to use any thread library (like pthreads). */ |
2d33f157 | 44 | |
f894c3ad | 45 | #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */ |
2d33f157 | 46 | #include "thread.h" |
47 | #include "log.h" | |
48 | ||
f894c3ad | 49 | /* Local portnumber for async channel. Note that OSPF API library will also |
50 | allocate a sync channel at ASYNCPORT+1. */ | |
2d33f157 | 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 | ||
f894c3ad | 60 | /* Our opaque LSAs have the following format. */ |
d62a17ae | 61 | struct my_opaque_lsa { |
62 | struct lsa_header hdr; /* include common LSA header */ | |
d7c0a89a | 63 | uint8_t data[4]; /* our own data format then follows here */ |
2d33f157 | 64 | }; |
65 | ||
66 | ||
67 | /* --------------------------------------------------------- | |
d62a17ae | 68 | * Threads for asynchronous messages and LSA update/delete |
2d33f157 | 69 | * --------------------------------------------------------- |
70 | */ | |
71 | ||
cc9f21da | 72 | static void lsa_delete(struct thread *t) |
2d33f157 | 73 | { |
d62a17ae | 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]); | |
cc9f21da | 83 | return; |
d62a17ae | 84 | } |
85 | ||
86 | printf("Deleting LSA... "); | |
87 | rc = ospf_apiclient_lsa_delete(oclient, area_id, | |
2f30cb25 LB |
88 | atoi(args[2]), /* lsa type */ |
89 | atoi(args[3]), /* opaque type */ | |
90 | atoi(args[4]), /* opaque ID */ | |
91 | 0); /* send data in withdrawals */ | |
d62a17ae | 92 | printf("done, return code is = %d\n", rc); |
2d33f157 | 93 | } |
94 | ||
cc9f21da | 95 | static void lsa_inject(struct thread *t) |
2d33f157 | 96 | { |
d62a17ae | 97 | struct ospf_apiclient *cl; |
98 | struct in_addr ifaddr; | |
99 | struct in_addr area_id; | |
d7c0a89a QY |
100 | uint8_t lsa_type; |
101 | uint8_t opaque_type; | |
102 | uint32_t opaque_id; | |
d62a17ae | 103 | void *opaquedata; |
104 | int opaquelen; | |
105 | ||
d7c0a89a | 106 | static uint32_t counter = 1; /* Incremented each time invoked */ |
d62a17ae | 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]); | |
cc9f21da | 114 | return; |
d62a17ae | 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]); | |
cc9f21da | 120 | return; |
d62a17ae | 121 | } |
122 | lsa_type = atoi(args[2]); | |
123 | opaque_type = atoi(args[3]); | |
124 | opaque_id = atoi(args[4]); | |
125 | opaquedata = &counter; | |
d7c0a89a | 126 | opaquelen = sizeof(uint32_t); |
d62a17ae | 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++; | |
30a2231a | 136 | } |
2d33f157 | 137 | |
138 | ||
139 | /* This thread handles asynchronous messages coming in from the OSPF | |
140 | API server */ | |
cc9f21da | 141 | static void lsa_read(struct thread *thread) |
2d33f157 | 142 | { |
d62a17ae | 143 | struct ospf_apiclient *oclient; |
144 | int fd; | |
145 | int ret; | |
2d33f157 | 146 | |
d62a17ae | 147 | printf("lsa_read called\n"); |
2d33f157 | 148 | |
d62a17ae | 149 | oclient = THREAD_ARG(thread); |
150 | fd = THREAD_FD(thread); | |
2d33f157 | 151 | |
d62a17ae | 152 | /* Handle asynchronous message */ |
153 | ret = ospf_apiclient_handle_async(oclient); | |
154 | if (ret < 0) { | |
155 | printf("Connection closed, exiting..."); | |
156 | exit(0); | |
157 | } | |
2d33f157 | 158 | |
d62a17ae | 159 | /* Reschedule read thread */ |
160 | thread_add_read(master, lsa_read, oclient, fd, NULL); | |
2d33f157 | 161 | } |
162 | ||
2d33f157 | 163 | /* --------------------------------------------------------- |
d62a17ae | 164 | * Callback functions for asynchronous events |
2d33f157 | 165 | * --------------------------------------------------------- |
166 | */ | |
167 | ||
d62a17ae | 168 | static void lsa_update_callback(struct in_addr ifaddr, struct in_addr area_id, |
d7c0a89a | 169 | uint8_t is_self_originated, |
d62a17ae | 170 | struct lsa_header *lsa) |
2d33f157 | 171 | { |
d62a17ae | 172 | printf("lsa_update_callback: "); |
d0b0a2c5 MS |
173 | printfrr("ifaddr: %pI4 ", &ifaddr); |
174 | printfrr("area: %pI4\n", &area_id); | |
d62a17ae | 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 | ... | |
d7c0a89a | 185 | uint16_t links = rl->links; |
d62a17ae | 186 | ... |
187 | } | |
188 | */ | |
189 | ||
190 | ospf_lsa_header_dump(lsa); | |
2d33f157 | 191 | } |
192 | ||
d62a17ae | 193 | static void lsa_delete_callback(struct in_addr ifaddr, struct in_addr area_id, |
d7c0a89a | 194 | uint8_t is_self_originated, |
d62a17ae | 195 | struct lsa_header *lsa) |
2d33f157 | 196 | { |
d62a17ae | 197 | printf("lsa_delete_callback: "); |
d0b0a2c5 MS |
198 | printf("ifaddr: %pI4 ", &ifaddr); |
199 | printf("area: %pI4\n", &area_id); | |
d62a17ae | 200 | printf("is_self_origin: %u\n", is_self_originated); |
2d33f157 | 201 | |
d62a17ae | 202 | ospf_lsa_header_dump(lsa); |
2d33f157 | 203 | } |
204 | ||
d7c0a89a | 205 | static void ready_callback(uint8_t lsa_type, uint8_t opaque_type, |
d62a17ae | 206 | struct in_addr addr) |
2d33f157 | 207 | { |
d0b0a2c5 MS |
208 | printfrr("ready_callback: lsa_type: %d opaque_type: %d addr=%pI4\n", |
209 | lsa_type, opaque_type, &addr); | |
2d33f157 | 210 | |
d62a17ae | 211 | /* Schedule opaque LSA originate in 5 secs */ |
212 | thread_add_timer(master, lsa_inject, oclient, 5, NULL); | |
2d33f157 | 213 | |
d62a17ae | 214 | /* Schedule opaque LSA update with new value */ |
215 | thread_add_timer(master, lsa_inject, oclient, 10, NULL); | |
2d33f157 | 216 | |
d62a17ae | 217 | /* Schedule delete */ |
218 | thread_add_timer(master, lsa_delete, oclient, 30, NULL); | |
2d33f157 | 219 | } |
220 | ||
d62a17ae | 221 | static void new_if_callback(struct in_addr ifaddr, struct in_addr area_id) |
2d33f157 | 222 | { |
d0b0a2c5 MS |
223 | printfrr("new_if_callback: ifaddr: %pI4 ", &ifaddr); |
224 | printfrr("area_id: %pI4\n", &area_id); | |
2d33f157 | 225 | } |
226 | ||
d62a17ae | 227 | static void del_if_callback(struct in_addr ifaddr) |
2d33f157 | 228 | { |
d0b0a2c5 | 229 | printfrr("new_if_callback: ifaddr: %pI4\n ", &ifaddr); |
2d33f157 | 230 | } |
231 | ||
d62a17ae | 232 | static void ism_change_callback(struct in_addr ifaddr, struct in_addr area_id, |
d7c0a89a | 233 | uint8_t state) |
2d33f157 | 234 | { |
d0b0a2c5 MS |
235 | printfrr("ism_change: ifaddr: %pI4 ", &ifaddr); |
236 | printfrr("area_id: %pI4\n", &area_id); | |
d62a17ae | 237 | printf("state: %d [%s]\n", state, |
238 | lookup_msg(ospf_ism_state_msg, state, NULL)); | |
2d33f157 | 239 | } |
240 | ||
d62a17ae | 241 | static void nsm_change_callback(struct in_addr ifaddr, struct in_addr nbraddr, |
d7c0a89a | 242 | struct in_addr router_id, uint8_t state) |
2d33f157 | 243 | { |
d0b0a2c5 MS |
244 | printfrr("nsm_change: ifaddr: %pI4 ", &ifaddr); |
245 | printfrr("nbraddr: %pI4\n", &nbraddr); | |
246 | printfrr("router_id: %pI4\n", &router_id); | |
d62a17ae | 247 | printf("state: %d [%s]\n", state, |
248 | lookup_msg(ospf_nsm_state_msg, state, NULL)); | |
2d33f157 | 249 | } |
250 | ||
251 | ||
252 | /* --------------------------------------------------------- | |
d62a17ae | 253 | * Main program |
2d33f157 | 254 | * --------------------------------------------------------- |
255 | */ | |
256 | ||
35dece84 | 257 | static int usage(void) |
f894c3ad | 258 | { |
d62a17ae | 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); | |
f894c3ad | 268 | } |
269 | ||
d62a17ae | 270 | int main(int argc, char *argv[]) |
2d33f157 | 271 | { |
d62a17ae | 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 */ | |
37a1f2fb | 294 | zprivs_preinit(&ospfd_privs); |
d62a17ae | 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; | |
2d33f157 | 329 | } |