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