]> git.proxmox.com Git - mirror_frr.git/blame - ospfclient/ospfclient.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / ospfclient / ospfclient.c
CommitLineData
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 36struct 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 */
54struct thread_master *master;
55
56/* Global variables */
57struct ospf_apiclient *oclient;
58char **args;
59
f894c3ad 60/* Our opaque LSAs have the following format. */
d62a17ae 61struct 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 72static 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 95static 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 141static 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 168static 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 193static 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 205static 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 221static 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 227static void del_if_callback(struct in_addr ifaddr)
2d33f157 228{
d0b0a2c5 229 printfrr("new_if_callback: ifaddr: %pI4\n ", &ifaddr);
2d33f157 230}
231
d62a17ae 232static 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 241static 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 257static 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 270int 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}