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