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