From b8b16dc9ce1360e10348cecde19bdb61a84dd6a7 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Wed, 12 Jul 2017 19:18:35 +0200 Subject: [PATCH] Add OSPF API and FRR Hacking documents With the help of the WayBackMachine, add old documentation about the OSPF API and basic Zebra hacking Signed-off-by: Olivier Dugeon --- doc/FRR-hacking.md | 1441 +++++++++++++++++++++++++++++++++ doc/OSPF-API.md | 263 ++++++ doc/ospf_api_architecture.png | Bin 0 -> 20580 bytes doc/ospf_api_msghdr.png | Bin 0 -> 6604 bytes doc/ospf_api_msgs1.png | Bin 0 -> 36814 bytes doc/ospf_api_msgs2.png | Bin 0 -> 35544 bytes 6 files changed, 1704 insertions(+) create mode 100644 doc/FRR-hacking.md create mode 100644 doc/OSPF-API.md create mode 100644 doc/ospf_api_architecture.png create mode 100644 doc/ospf_api_msghdr.png create mode 100644 doc/ospf_api_msgs1.png create mode 100644 doc/ospf_api_msgs2.png diff --git a/doc/FRR-hacking.md b/doc/FRR-hacking.md new file mode 100644 index 000000000..0a054af7b --- /dev/null +++ b/doc/FRR-hacking.md @@ -0,0 +1,1441 @@ +# ZEBRA for Dummies + +a.k.a. Learn ZEBRA in 2 hours +a.k.a. Zebra Hacking How-To + +author: yon uriarte + +(C) Feb. 2001 + +[TOC] + +## Disclaimers + +This documentation is an attempt to recreate original documentation for the development in FR Routing based on original work done for Zebra by the author (with lots of help of the WayBackMachine). + +## Introduction + +The author makes the following assumptions about the reader: +* a certain C know-how +* some motivation +* knows what zebra is and does +* has read at least 2 pages about the general architecture of zebra +* can read a 3 liner unified diff without getting confused +* knows the socket(2) syscall and companions + +This is not a 100% documentation. When in doubt, do a "less ../lib/*.[ch]" + +This document is based on zebra 0.91 + +## Overview + +For the sake of this how-to, let assume you want to write a zebra daemon for a new protocol, ZAP (ZAP's Another Protocol). + +You have downloaded a copy of zebra. I'll assume _/frr_ contains the unpacked files. There are some subdirectories, like _/frr/ospfd_, containing the different protocol implementations. There is a subdirectory containing the library _/frr/lib_, the main zebra daemon is in _/frr/zebra_. + +Quite a good part of your program will be ZAP specific, but some functionality will be needed from the zebra framework. That is, you want to link the libzebra.a library to use certain common functions and you want to connect to a running zebra daemon to have information about the system (interfaces and routes). + +The library includes functions and structures for: + * connecting to the zebra daemon (zclient.h) + * vty management (access method (telnet), terminal mangling and cli control) + command registration + * access lists (commands and functionality) (filter.h) + * prefix lists (commands and functionality) (plist.h) + * route maps + * keychains + * satanism (becoming a daemon) + * logging + * linked lists, vectors and hashes + * memory management, including cli + * cooperative multithreading (using select(2)) + * FSF's getopt() & regexs + * MD5 + * interface structs and functions, including zebra protocol functions (if.h) + * socket mangling (sockunion.h and sockopt.h) + * ip v4&6 route tables (if_rmap.h) ? + +and some internally used functions, like serialization support routines for the zebra protocol and whatnot. + +## Main + +Now, just create a subdirectory, _/frr/zapd_, to store zapd's files. I'll start with main(), as usual, so let's call this file zapd_main.c, here it goes. It is based on ospfd. + +```C +/* + * ZAPd main + * zapd_main.c (c) 2001 you + */ + +/* just some includes, as usual */ + +#include + +#include "log.h" +#include "version.h" +#include +#include "command.h" +#include "thread.h" +#include + +/* you might want to put the following #defines on a zapd.h file */ + +/* + * this will be the name of the config file in the zebra + * config directory (could be /usr/local/etc/) + */ +#define ZAPD_DEFAULT_CONFIG "zapd.conf" + +/* telnet to this port to login to the zapd vty */ +#define ZAPD_VTY_PORT 26666 + +/* name of the unix socket to communicate with the vtysh */ +#define ZAPD_VTYSH_PATH "/tmp/.zapd" + +/* Global Variables */ +char config_current[] = LDPD_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR LDPD_DEFAULT_CONFIG; +/* zebra does #define SYSCONFDIR */ + +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "help", no_argument, NULL, 'h'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* will contain (mangled) argv[0] */ +char* progname; + +/* needed by the thread implementation */ +struct thread_master *master; + +/* some signal initialization, to avoid getting + * the floor pulled under you, this is defined after + * main(), if you are curious + */ +void signal_init(void); + +/* These 2 are defined somewhere else, say in libzapd.a */ +#ifdef REALLY_DUMMY +void zap_init(void) {return;}; +void zap_terminate(void) {return;}; +#else +void zap_init(void); +void zap_terminate(void); +#endif + +/* Help information display. */ +static void +usage (int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages ZAP.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* Main function */ +int main(int argc, char** argv, char** envp) { + char *p; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + struct thread thread; + + umask(0027); + + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_ZAP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + +/* initialize the log subsystem, you will have to include + * ZLOG_ZAP in the zlog_proto_t enum type definition in + * lib/log.h + */ + +/* this while just reads the options */ + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "dlf:hP:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + print_version (); + exit (0); + break; + case 'h': + usage (0); + break; + default: + usage (1); + break; + } + } + +/* one to control them all, ... */ +/* this the main thread controlling structure, + * nothing to remember. + */ + master = thread_make_master (); + + +/* before you start the engine, put your safety belt on */ + signal_init (); + + +/* Library inits */ +/* First, initializes the command sub-system, if arg, add some commands + * which are mostly only useful for humans on the vty */ + cmd_init (1); + +/* these are all from libzebra */ + vty_init (); + memory_init (); + access_list_init (); + prefix_list_init (); + +/* + * ZAP inits + */ +/* this is implemented somewhere, e.g. on libzap.a + * here, you could start some threads (the thread subsystem + * is not running yet), register some commands, ... + */ + zap_init(); + +/* This is needed by the command subsystem to finish initialization. */ + sort_node(); + +/* Read the config file, your commands should be defined before this */ +vty_read_config (config_file, config_current, config_default); + +/* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + +/* Create VTY socket: start the TCP and unix socket listeners */ + vty_serv_sock (vty_port ? vty_port : LDPD_VTY_PORT, LDPD_VTYSH_PATH); + +/* Print banner. */ + zlog (NULL, LOG_INFO, "ZAP (%s) starts", ZEBRA_VERSION); + +/* this is the main event loop */ +/* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + +/* never reached */ + return 0; +} +``` + +The various signal handlers could call various functions depending on what you would manage: terminate, log rotate ... + +```C +/* SIGHUP handler */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + zap_terminate (); +/* this is your clean-up function */ + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +#define RETSIGTYPE void +/* Signal wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} +``` + +In complement, you will need a sample zapd.conf, looking more like this: + +``` +!---------------------------------------------------------------- +! +! ZAPd sample configuratin file +! +! zapd.conf +! +hostname zapd +password zebra +! +!log file zapd.log +! +log stdout +! +!---------------------------------------------------------------- +``` + +Which you will have to put in zebra''s config dir, specified with *--prefix=DIR* when running *./configure* to build the library. If you are just experimenting, you might want to define +it as *$HOME/etc* or somesuch and run zebra as non-root, just-in-case. This way, depending on platform, zapd will receive interface and route information but won't be able to change anything. + +Now compile it (there is no libzapd.a, yet) + +``` + gcc -o zapd -I. -I.. -I../lib zapd_main.c ../lib/libzebra.a libzapd.a +``` +and run it +``` + ./zapd & +``` +and connect to it: +``` + telnet localhost 26666 +``` + +## Zebra Threads + +They are of the easily-and-somewhat-portably-implemented cooperatively-multitasking kind, using select(2). + +There are 3 possibilities for a thread to be scheduled: + 1. timer expiration, + 1. I/O event (read or write, not both at once) + 1. as an event (to decouple threads) + +The main data structure is struct thread, consider it opaque. The functions for setting up a thread are: + +```C +typedef int (*cb)(struct thread* ); +/* cb == callback */ + +struct thread * +thread_add_read (struct thread_master *m, + cb func, void *arg, int fd); +struct thread * +thread_add_write (struct thread_master *m, + cb func, void *arg, int fd); + +struct thread * +thread_add_timer (struct thread_master *m, + cb func, void *arg, long timer); + +struct thread * +thread_add_event (struct thread_master *m, + cb func, void *arg, int val); +``` + +All callback functions can read a single parameter, _void* arg_, which is accessed through a simple _THREAD_ARG(struct thread*)_ macro. + +The add_read and add_write functions expect a file descriptor, a read thread example follows: + +```C +extern struct thread_master* master; +extern int my_read_fd; +extern struct zap_fd_data* per_fd_data; + +struct thread* tp; + +/* This is the handler function */ +int thread_read_handler(struct thread* th) { + int which_fd; + struct zap_fd_data* my_fd_data; + u_int8_t c; + + which_fd = THREAD_FD(th); + my_fd_data = THREAD_ARG(th); + + read(which_fd,&c,1); + +/* do something useful with the data */ + zap_input(my_arg,which_fd,c); + +/* reschedule the read thread */ +tp = thread_add_read(master, &thread_read_handler, my_fd_data, which_fd); + return 0; +} + +/* Intall it for the first time */ +tp = thread_add_read(master, &thread_read_handler, per_fd_data, my_read_fd); +``` + +Function thread_add_timer expects a "seconds" argument as its last parameter instead of a fd and the thread_add_event function allows for an int val parameter, which you can read in the thread handler with the *THREAD_VAL* macro. + +Event threads have priority over timer threads. + +All threads are one-time events. If you want some sort of recurring timer or reading/writing more than once you must reschedule your handler inside your handler. + +Using _"void thread_cancel (struct thread \*thread);"_ you can remove any thread from the scheduler's list, and citing _thread.c_: + +```C +/* Delete all events which has argument value arg. */ +void thread_cancel_event (struct thread_master *m, void *arg); +``` + +## Talking to Zebra + +You will want your protocol daemon to communicate with the main zebra daemon. It will tell you about interfaces and routes, allowing you to know which interfaces exist and their configuration and which routes are installed and by whom (ospf,bgp,static,...). + +The _zclient.h_ library declares the API, interesting are the main structure for talking to the main daemon: + +```C +/* Structure for the zebra client. */ +struct zclient +{ +... + + /* Flag of communication to zebra is enabled or not. Default is on. + This flag is disabled by `no router zebra' statement. */ + int enable; +... + /* Pointer to the callback functions. */ + int (*interface_add) (int, struct zclient *, zebra_size_t); + int (*interface_delete) (int, struct zclient *, zebra_size_t); + int (*interface_up) (int, struct zclient *, zebra_size_t); + int (*interface_down) (int, struct zclient *, zebra_size_t); + int (*interface_address_add) (int, struct zclient *, zebra_size_t); + int (*interface_address_delete) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t); +}; +``` + +and the many function prototypes, which will be described as they are used. + +So, for a starter, let's create a new file, _zap_zebra.c_ + +```C +/*---------------------------------------- + * zap_zebra.c + */ + +/* might as well be defined here and exported over zap_zebra.h + * as it could be needed somewhere else + */ +extern struct zclient* zclient; + + +void zap_zebra_init(void) { + int i; + + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_ZAP); +/* create such a struct, and initialize it, + * thus making it ready to connect when the threads are started + * ZEBRA_ROUTE_ZAP is the type of routes you are not interested in. + * It is defined in zebra.h and you will have to extend it, e.g. : + + #define ZEBRA_ROUTE_BGP 8 + #define ZEBRA_ROUTE_ZAP 9 + #define ZEBRA_ROUTE_MAX 10 +``` + +And edit _/frr/zebra/rib.c_ too, in at least two places as well as functions *command_exit* and *command_end* in _/frr/lib/command.c_ file. + +**FIXME** is this true: ROUTE_MAX seems to have some magic semantics, it seems to be some sort of default route placeholder even though the defaults fields exist. + +```C +/* set the routes we want to get from zebra, in this case: + * tell me all routes but my own + */ + for(i=0; i++ < ZEBRA_ROUTE_MAX;) + if( i != ZEBRA_ROUTE_ZAP) + zclient_redistribute_set (zclient, i); + +/* fill in the callbacks */ + zclient->interface_add = zap_interface_add; + zclient->interface_delete = zap_interface_delete; + zclient->interface_up = zap_interface_state_up; + zclient->interface_down = zap_interface_state_down; + zclient->interface_address_add = zap_interface_address_add; + zclient->interface_address_delete = zap_interface_address_delete; + zclient->ipv4_route_add = zap_zebra_route_manage; + zclient->ipv4_route_delete = zap_zebra_route_manage; + + /* Install zebra node. **FIXME** is this needed?*/ + install_node (&zebra_node, zebra_config_write); +} +``` + +Now, your functions (declared and defined elsewhere) will be called whenever such an event happens. You might want to define some dummy functions, which just print the arguments. + +Now you might want to get information about the interfaces on the system, just add the following functions to the start of _zap_zebra.c_ and you will get a list of all interfaces active on the machine. + +```C +/* Inteface addition message from zebra. */ +int +zap_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + +/* now, is your duty to extract the interface information from + * the serialized zebra protocol stream, this was just an event + * indication. This will add the interface to the library's global + * interface list, so you can search for it later on. + */ + ifp = zebra_interface_add_read (zclient->ibuf); + zlog_info ("Zebra: interface add %s index %d flags %d metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + return 0; +} + +int +zap_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + +/* again, it is your job to pluck the interface information off the stream + */ + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + if (if_is_up (ifp)) + zlog_warn ("Zebra: got delete of %s, but interface is still up", + ifp->name); + + zlog_info ("Zebra: interface delete %s index %d flags %d metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if_delete(ifp); + return 0; +} +``` + +Taking a look at _if.h_ you will see the following functions: + +```C +int if_is_up (struct interface *); +int if_is_loopback (struct interface *); +int if_is_broadcast (struct interface *); +int if_is_pointopoint (struct interface *); +int if_is_multicast (struct interface *); +``` + +which are just flag testers, as used in the above example. Now for the up and down callbacks: + +```C +int +zap_interface_state_up (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct interface if_tmp; + u_int32_t old_cost; + + +/* searches for the interface by that name (the name specified + * in the stream) in the existing interface list. + */ + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + assert(if_is_up(ifp)); /* maybe untrue **FIXME** */ + zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name); + return 0; +} + +int +zap_interface_state_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read (zclient->ibuf); + if (ifp == NULL) + return 0; + zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name); + return 0; +} +``` + +There are two interface add event triggers: + 1. a real interface is announced via the zebra protocol + 1. the user types "interface foo" on the command line + +For the second case, the only information about the interface is its name, and for the first one the whole struct interface might be relevant. This structure is also defined in _if.h_ : + +```C +/* Interface structure */ +struct interface +{ + /* Interface name. */ + char name[INTERFACE_NAMSIZ + 1]; +/* INTERFACE_NAMSIZ is a #define, usually 20 (bytes) */ +... + /* Hardware address. */ +#ifdef HAVE_SOCKADDR_DL + struct sockaddr_dl sdl; +#else + unsigned short hw_type; + u_char hw_addr[INTERFACE_HWADDR_MAX]; + int hw_addr_len; +#endif /* HAVE_SOCKADDR_DL */ +/* hw dependant hw address + * INTERFACE_HWADDR_MAX is #defined to 20 + */ +... + /* Connected address list. */ + list connected; +/* This are the addresses on the interface, with masks */ + + /* Daemon specific interface data pointer. */ + void *info; +/* This is for your convenience */ +...}; +``` + +A struct connected looks like this: + +```C +/* Connected address structure. */ +struct connected +{ + /* Attached interface. */ + struct interface *ifp; + + /* Flags for configuration. */ + u_char conf; +#define ZEBRA_IFC_REAL (1 << 0) +#define ZEBRA_IFC_CONFIGURED (1 << 1) + + /* Flags for connected address. */ + u_char flags; +#define ZEBRA_IFA_SECONDARY (1 << 0) + + /* Address of connected network. */ + struct prefix *address; + struct prefix *destination; + +...}; +``` + +thus you have access to the IP addresses of the interface. Now you are ready for the next callbacks: + +```C +int +zap_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + +/* read the address from the zebra protocol stream */ + c = zebra_interface_address_add_read (zclient->ibuf); + if (c == NULL) + return 0; + p = c->address; + if (p->family == AF_INET) + zlog_info (" new connected IPv4 address %s/%d on interface %s", + inet_ntoa (p->u.prefix4), p->prefixlen, c->ifp->name); + else if(p->family == AF_INET6) + zlog_info (" new connected IPv6 address on interface %s", c->ifp->name); + return 0; +} + +int +zap_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + + c = zebra_interface_address_delete_read (zclient->ibuf); + if (c == NULL) + return 0; +/* you might want to print something over here */ + + connected_free (c); +/* what you must do, is free the connected struct, which was implicitely + * created in the zebra_interface_address_delete_read call + */ + return 0; +} +``` + +And now, the only callbacks left to fill in, are the route callbacks. + +**FIXME** I am not so sure about this part. + +Apparently, there is no function in the library to do the deserialization of the zebra protocol stream, so you have to do it by hand: + +```C +void zclient_read_zapi_ipv4( struct zclient* zclient, + struct zapi_ipv4 *zapi, struct prefix_ipv4* p, + unsigned long* ifindex, struct in_addr* nexthop) +{ + struct stream *s; + + + s = zclient->ibuf; + +/* read the header */ + zapi->type = stream_getc (s); + zapi->flags = stream_getc (s); + zapi->message = stream_getc (s); + +/* and the prefix */ + memset (p, 0, sizeof (struct prefix_ipv4)); + p->family = AF_INET; + p->prefixlen = stream_getc (s); + stream_get (&p->prefix, s, PSIZE (p->prefixlen)); + + if (CHECK_FLAG (zapi->message, ZAPI_MESSAGE_NEXTHOP)) + { + zapi->nexthop_num = stream_getc (s); + nexthop->s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (zapi->message, ZAPI_MESSAGE_IFINDEX)) + { + zapi->ifindex_num = stream_getc (s); + *ifindex = stream_getl (s); + } + if (CHECK_FLAG (zapi->message, ZAPI_MESSAGE_DISTANCE)) + zapi->distance = stream_getc (s); + if (CHECK_FLAG (zapi->message, ZAPI_MESSAGE_METRIC)) + zapi->metric = stream_getl (s); + +} +``` + +and then just call it from the unified routed add/del manager: + +```C +int zap_zebra_route_manage (int command, struct zclient *zclient, + zebra_size_t length) { + + struct prefix_ipv4 p; + struct zapi_ipv4 zapi; + unsigned long ifindex; + struct in_addr nexthop; + + zclient_read_zapi_ipv4( zclient, &zapi, &p,&ifindex,&nexthop); + + if (command == ZEBRA_IPV4_ROUTE_ADD) { + zlog_info (" new IPv4 route %s/%d on interface ifindex %d", + inet_atop (p->u.prefix4), p->prefixlen, ifindex); + + } else { /* ZEBRA_IPV4_ROUTE_DELETE */ + + } + return 0; +} +``` + +And to end this chapter, let us take a look at the API for setting and deleting routes: + +```C +/* Zebra API message flag. */ +#define ZAPI_MESSAGE_NEXTHOP 0x01 +#define ZAPI_MESSAGE_IFINDEX 0x02 +#define ZAPI_MESSAGE_DISTANCE 0x04 +#define ZAPI_MESSAGE_METRIC 0x08 + +/* Zebra IPv4 route message API. */ +struct zapi_ipv4 +{ + u_char type; + u_char flags; + u_char message; + u_char nexthop_num; + struct in_addr **nexthop; + u_char ifindex_num; + unsigned int *ifindex; + u_char distance; + u_int32_t metric; +}; + +int +zapi_ipv4_add (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + +int +zapi_ipv4_delete (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + + Usage example: + +struct zapi_ipv4 zr; + +zr.type = ZEBRA_ROUTE_ZAP; +zr.flags = 0; +SET_FLAG (zr->message, ZAPI_MESSAGE_NEXTHOP); +SET_FLAG (zr->message, ZAPI_MESSAGE_METRIC); +zr.nexthop_num = 1; +zr.nexthop = &some_nexthop; +zr.metric = 111; +zapi_ipv4_add(&zc, &the_prefix, &zr); +``` + +This will set a route of type ZAP to the destination prefix the_prefix with nexthop some_nexthop and metric 111. Interface routes are supported. + +**FIXME** is this right? can a daemon set an interface route without a nexthop? The code suggests only ZAPI_MESSAGE_NEXTHOP is checked and then nexthops and ifindices are sent. + +You can combine a number of nexthop/ifindex to install an equal weight load balancing route, if the underlying OS supports it. + +## Defining Commands + +You know the cisco interface, which changes the available commands depending on the configuration mode you are. These configuration modes are called nodes in the implementation. All defines and functions are in _lib/command.h_ file. The available nodes are defined in the _enum node_type_, which looks like this: + +```C +/* There are some command levels which called from command node. */ +enum node_type +{ + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ +... + ENABLE_NODE, /* Enable node. */ + CONFIG_NODE, /* Config node. Default mode of config file. */ +... + INTERFACE_NODE, /* Interface mode node. */ +... + RIP_NODE, /* RIP protocol mode node. */ +... + ACCESS_NODE, /* Access list node. */ + PREFIX_NODE, /* Prefix list node. */ +... + VTY_NODE /* Vty node. */ +}; +``` + +As you will want a router-zap node, you will have to extend the enum to include ZAP_NODE. ZAP has some per interface configuration options, but the interface node for the per-interface configuration mode is not installed per default. The following code installs both the interface and the zap node. + +```C +#include +#include +#include "command.h" + +int zap_interface_config_write (struct vty *vty); +int zap_router_config_write (struct vty *vty); +/* I'll come to this later + */ + +/* zapd's interface node. */ +struct cmd_node zap_interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 /* vtysh ? yes */ +}; + +/* zapd's router node. */ +struct cmd_node zap_router_node = +{ + ZAP_NODE, + "%s(config-router)# ", + 1 /* vtysh ? yes */ +}; + +void zap_cmd_init(void) { + if_init(); + +/* Install interface nodes. */ + install_node (&zap_interface_node, zap_interface_config_write); + install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); /* from if.h */ + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + +/* Install router nodes. */ + install_node (&zap_router_node, zap_router_config_write); +/* add the default commands, like exit(!) */ + install_default(ZAP_NODE); +} +``` + +This code just made possible to define commands for the router zap configuration mode. There is, of course, no way to reach the node, at the moment. So you will have to define +a command to change into ZAP configuration mode. So, let's start: + +```C +extern zap_instance_t zap_global; + +DEFUN (router_zap, + router_zap_cmd, + "router zap", + "Enable a routing process\n" + "Enter ZAP configuration mode\n") +{ + vty->node = ZAP_NODE; + vty->index = zap_global; + return CMD_SUCCESS; +} +``` + +and later on: + +```C + install_element (CONFIG_NODE, &router_zap_cmd); +``` + +The _**DEFUN**_ macro defines a command, first parameter is function name, second parameter is a name for a struct, 3rd is the whole command (some control parameters are allowed), and the fourth parameter is a help string, containing as many _\n_ separated help lines as arguments has the command. + +With *install_element* you register the command at the main configuration node (after *conf XXX*). + +Suppose you are using a german keyboard, which switches the y and z keys, so you want to add a command *"router yap"*, which does the same as router_zap (calls the same function). Then, just add the following lines. + +```C +ALIAS (router_zap, + router_yap_cmd, + "router yap", + "Enable a routing process\n" + "Enter ZAP configuration mode\n") +``` + +Just make sure the first parameter is the same as the one in the *DEFUN* macro and the second isn't. To register this command, we reference the struct again: + +```C + install_element (CONFIG_NODE, &router_yap_cmd); +``` + +Now, whenever the user types *"router zap"* or *"router yap"*, the same function is called. The function, called *router_zap* in this example, has the signature: + +```C + f(struct cmd_element *self, struct vty *vty, int argc, char **argv) +``` + +So, whenever your commands are called, you have a struct vty to print information to, a reference to the command struct and the usual argc/argv combo (which, for this example will be 0,GARBAGE). + +Getting back to our example, the router_zap function modifies the struct vty, setting the node to ZAP_NODE, so only commands defined in that node are available, and setting the index to point to zap_global. + +The index allows you to have a per node private void\*. This could be useful when expanding router zap to run with multiple instances, allowing a single lookup of the relevant information on the *"router yap XX"* command, so you won't have to find the relevant data struct on every call to a *ZAP\_NODE* command. A quick _zap_instance_t zi= (zap_instance_t) vty->index;_ will be enough (assuming zap_instance_t is some kind of pointer). + +A quick look at command.[ch] suggest a special meaning for certain formats in the command line in DEFUN. This helps the parsing routines, so you don't have to start playing with all those horrible str* functions. A (**FIXME** partial?) list follows: + +```C +"A.B.C.D" IPV4 +"A.B.C.D/M" IPV4_PREFIX +"X:X::X:X" IPV6 +"X:X::X:X/M" IPV6_PREFIX +``` + +Words starting with a capital letter are variables, those are put in argv. For example: + +```C +DEFUN (..., + "router zap AS", + STR_ROUTER + STR_ZAP + "Autonomous System number for this routing process\n") +``` +will give you the user input in arg[0]. + +For some variables only range of values make sense. This is represented with the "<" symbol, the above example would now be: _"router zap <1-65535>"_. + +Optional arguments are between square brackets. For ZAP the default AS number is 1, so instead of defining and registering two commands ("router zap" and "router zap AS") you could just define it as: + +```C +DEFUN(..., "router zap [AS]", ...) { + unsigned long int as = argc == 0 ? 1 : strtoul(argv[0]); + if ( (as == 0) || (as & ! 0xFFFF) ) { + vty_out(vty, "Invalid AS number %d%s", as, VTY_NEWLINE); + return CMD_WARNING; + } +/* switch to ROUTER_ZAP node */ +} +``` + +**FIXME** nesting of meta characters: can I define "router zap[<1-65535>]" ? + +For inputs requiring a variable word number you use "." to signal a vararg input. ZAP requires a passphrase for authentication, so you could add a "zap passphrase .PASSPHRASE" command to the inferface node. + +**FIXME** argc == 1 or argc == number of words? + +## Using access lists + +Access list functions are defined in _filter.h_. Once you have initialised the subsystem with _access_list_init()_ function, the user has the following commands available: + +``` + access-list WORD (deny|permit) (A.B.C.D/M|any) + access-list WORD (deny|permit) A.B.C.D/M (exact-match|) + no access-list WORD (deny|permit) (A.B.C.D/M|any) + no access-list WORD (deny|permit) A.B.C.D/M (exact-match|) + no access-list WORD + access-list WORD remark .LINE + no access-list WORD remark + no access-list WORD remark .LINE +``` + +If ipv6 support is configured another set of commands for ipv6 access lists is created. + +You have the following functions available (from filter.h): + +```C +void access_list_reset (void); +void access_list_add_hook (void (*func)(struct access_list *)); +void access_list_delete_hook (void (*func)(struct access_list *)); +struct access_list *access_list_lookup (int, char *); +enum filter_type access_list_apply (struct access_list *, void *); +``` + * **access_list_reset** just removes all access-lists. + * **access_list_[add|delete]_hook** citing filter.c: + * "Hook function which is executed when new access_list is added." + * "Hook function which is executed when access_list is deleted." + * **access_list_lookup**: first parameter is AF_INET or AF_INET6, second is the name of the list, e.g. "101". + * **access_list_apply** citing filter.c: + * "Apply access list to object (which should be struct prefix *)" + * enum filter_type is {FILTER_DENY, FILTER_PERMIT, FILTER_DYNAMIC} + * non-existant or empty lists return DENY. + +## Using prefix lists + +Prefix list functions are defined in *plist.h*. Just a quick glance over *plist.h* shows the following interesting information: + +```C +enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT }; +enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER}; + +/* Prototypes. */ +void prefix_list_reset (void); +void prefix_list_add_hook (void (*func) (void)); +void prefix_list_delete_hook (void (*func) (void)); +struct prefix_list *prefix_list_lookup (int family, char *); +enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); +``` + +The prototypes look like the access-list API ones, read it there. The structure prefix has the following layout: + +```C +/* IPv4 and IPv6 unified prefix structure. */ +struct prefix +{ + u_char family; + u_char safi; + u_char prefixlen; + u_char padding; + union + { + u_char prefix; + struct in_addr prefix4; +#ifdef HAVE_IPV6 + struct in6_addr prefix6; +#endif /* HAVE_IPV6 */ + struct + { + struct in_addr id; + struct in_addr adv_router; + } lp; + u_char val[8]; + } u; +}; +``` + +For *access_list_apply* and *prefix_list_apply*, you only need to fill in the _prefixlen_ and _u_, though it might be useful to fill in the _family_ and _safi_ fields, depending on compilation time configuration. + +**FIXME** I'm not so sure about this last paragraph, are afi and safi needed? + +## Routing tables + +**FIXME** This chapter need to be reviewed + +You might want to store the routes you get from zebra on a radix tree, for fast retrieval. The library offers such a service, just include _table.h_. + +A little peek at the .h file shows two structures: *route_table* and *route_node*: + +```C +struct route_table { struct route_node *top; }; + +struct route_node { + /* Actual prefix of this radix. */ + struct prefix p; + + /* Tree link. */ +/* radix tree, 1 bit per depth, max 32 lookups for IPv4 + */ + + /* Lock of this radix */ + unsigned int lock; + + /* Each node of route. */ + void *info; +/* info is yours to use */ + + /* Aggregation. */ + void *aggregate; +/* doesn't seem to be used much + **FIXME** What is this for? can it be used by the daemon? table.c doesn't touch it at all + or any file in /frr/zebra/ for that matter. */ +}; +``` + +A mix of usage example and function list follows: + +```C +/* zap_rib_example.c */ + +#include "table.h" + +struct route_table table1; +struct route_node entry; +struct prefix dst; +struct zap_per_route_t route_info; +/* [...] */ + +/* create a new table */ +table1 = route_table_init(); + +/* Quoting: "Add node to routing table." + * more detailed: if dst matches an entry exactly, return that entry, + * otherwise create it; + * The reference counter is set to 1 (**FIXME** sure? ) +*/ +entry = route_node_get (table1, dst); + +/* store our per route info, if none exists yet*/ +if (entry->info != NULL ) + entry->info = route_info; + +/* decrements reference counter and frees the node if it is 0 */ +void route_unlock_node (struct route_node *node); + +/* (node->info == NULL && node->lock == 0) must hold for calling this */ +void route_node_delete (struct route_node *node); + +/* Quoting: + * Get fist node and lock it. This function is useful when one wants + * to lookup all the nodes in the routing table. + */ +struct route_node *route_top (struct route_table *); + +/* Quoting: + * Unlock current node and lock next node then return it. + */ +struct route_node *route_next (struct route_node *); + +/* Quoting: + * Unlock current node and lock next node until limit. + */ +struct route_node *route_next_until (struct route_node *, struct route_node *); + +/* Quoting: + * Add node to routing table. */ +struct route_node *route_node_get (struct route_table *, struct prefix *); + +/* exact match or NULL */ +struct route_node *route_node_lookup (struct route_table *, struct prefix *); + +/* increments the reference counter */ +entry = route_lock_node (entry); + +/* walks down the radix tree and returns the longest matching route */ +struct route_node *route_node_match (struct route_table *, struct prefix *); + +/* creates a struct prefix from in_addr and calls route_node_match */ +struct route_node *route_node_match_ipv4 (struct route_table *, + struct in_addr *); + +/* Free the table and its contents */ +route_table_finish(table1); +``` + +## Hash tables + +**FIXME** Need to be rewrite to be conform to the new set of hash_XXX() functions. + +You know the drill. BUGLET: + 1. hash_push:hash.c count++ but not -- + 1. hash_clean:hash.c missing count=0 + +The hash.h suggests it could be possible to have hash with different table sizes. But hash.c, specifically hash_clean, works with a fixed size of HASHTABSIZE. + +```C +/* for Hash tables */ +#define HASHTABSIZE 2048 + +typedef struct HashBacket +{ + void *data; + struct HashBacket *next; +} HashBacket; + +struct Hash +{ + /* Hash backet. */ + HashBacket **index; + + /* Hash size. */ + int size; + + /* Key make function. */ + unsigned int (*hash_key)(); +/* in fact, unsigned int (*hash_key)(void* ) + */ + + /* Data compare function. */ + int (*hash_cmp)(); +/* in fact, unsigned int (*hash_cmp)(void*, void* ) + * returns 1 if equal. (not !0, but == 1) + */ + + /* Backet alloc. */ + unsigned long count; +}; + + For each void* p,q with hash_key(p) == hash_key(q), + hash_cmp(p,q) != 1 must hold. + +/* hash instance ctor & dtor */ +struct Hash *hash_new (int size); +void hash_free (struct Hash *hash); +/* remember to set the 2 functions in the Hash struct, e.g. +unsigned int my_hash_key_gen(zap_some_data* e) +{ return e %HASHTABSIZE; /* simplest hash function */ } +int my_hash_cmp(zap_some_data* p, zap_some_data* q) +{ return p->whatever == q->whatever ? 1 : 0; } + +h = hash_new(HASHTABSIZE); +h->hash_key = my_hash_key_gen; +h->hash_cmp = my_hash_cmp; + */ + +/* returns the first hash bucket of the hash bucket linked list + * for key int (0 <= key < HASHTABSIZE) +*/ +HashBacket *hash_head (struct Hash *, int); +/* usage example: + HashBacket* t; int i; +for( i=0; i < HASHTABSIZE; i++) + for (t=hash_head(my_hash,i); t != NULL, t = t->next) + do_something(t->data); +*/ + +/* insert the data in the hash */ +HashBacket *hash_push (struct Hash *, void *); + +/* returns the bucket data portion or NULL + * and removes the hash entry */ +void *hash_pull (struct Hash *, void *); + +/* returns the bucket data portion or NULL */ +void *hash_search (struct Hash *, void *); + +/* Deletes all entries from the hash (but not the hash itself) + * calls func on each node's data (if func != NULL) +void hash_clean (struct Hash *hash, void (* func) (void *)); +``` + +## Network portability and utility library + +I assume you are already familiar with the usual socket framework (sockopt.h, sockunion.h, network.h). A short description of the available API follows. + +First sockopt.h: + +I can say it better than the code: + +> Set up a multicast socket options for IPv4 +> This is here so that people only have to do their OS multicast mess +> in one place rather than all through zebra, ospfd, and ripd + +```C +sockopt.h, sockunion.h, network.h +int +setsockopt_multicast_ipv4(int sock, + int optname, + struct in_addr if_addr, + unsigned int mcast_addr, + unsigned int ifindex); +``` + +optname is one of IP_MULTICAST_IF, IP_ADD_MEMBERSHIP or IP_DROP_MEMBERSHIP. + +And the IPv6 sockopts, which I won't describe here. And then sockunion.h, which defines a socket interface, which should be portable. + +Starting with 2 simple types: + +```C +union sockunion +{ + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ +}; + +enum connect_result { + connect_error, connect_success, connect_in_progress +}; +``` + +some macros, e.g.: + +```C +#define sock2ip(X) (((struct sockaddr_in *)(X))->sin_addr.s_addr) +#define sock2ip6(X) (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr) +#define sockunion_family(X) (X)->sa.sa_family +``` + +and many functions: + +```C +/* Prototypes. */ + +/* sockunion is already allocated, parse str into it, 0 if no prob */ +int str2sockunion (char *, union sockunion *); + +/* print the sockunion param1 in buffer param2 of size param3 */ +const char *sockunion2str (union sockunion *, char *, size_t); + +/* 1,0,-1 for param1 >,==,< param2*/ +int sockunion_cmp (union sockunion *, union sockunion *); + +/* Quote: "If same family and same prefix return 1." */ +int sockunion_same (union sockunion *, union sockunion *); + +/* returns pointer to newly allocated buffer with the sockunion +printed into in. remember to free the buffer **FIXME** man strdup */ +char *sockunion_su2str (union sockunion *su); + +/* create a sockunion from a str, allocates it. + returns NULL if not possible. */ +union sockunion *sockunion_str2su (char *str); + +/* **FIXME** seems to be a zombie prototype in sockunion.h */ +struct in_addr sockunion_get_in_addr (union sockunion *su); + +/* accepts on sock, returns new client in sockunion */ +int sockunion_accept (int sock, union sockunion *); + +/* makes stream socket of the family specified in sockunion. + If no family is specified, it is ipv6 unless ipv6 is not + compiled in, in that case, it is ipv4 */ +int sockunion_stream_socket (union sockunion *); + +/* bind to addr param4, port param3 (port in host byte order) + returns the socket or <0 + if param4 is NULL, use INADDR_ANY (or ipv6 equivalent) , + param2 must not be NULL and will hold the address the socket was bound + to */ +int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); + +/* 0 if no problems */ +int sockopt_reuseaddr (int); +int sockopt_reuseport (int); +int sockopt_ttl (int family, int sock, int ttl); + +/* returns STREAM socket of sockunion type specified in su, + or error (<0)*/ +int sockunion_socket (union sockunion *su); + +const char *inet_sutop (union sockunion *su, char *str); + +/* returns pointer to *static* buffer where su is printed */ +char *sockunion_log (union sockunion *su); + +/* fd is socket number, su is the target, port is in network byte order, + last param is ifindex for ipv6 linklocal addresses */ +enum connect_result + sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int); + +/* Quoting: + "After TCP connection is established. Get local address and port." + or NULL */ +union sockunion *sockunion_getsockname (int); + +/* Quoting +"After TCP connection is established. Get remote address and port. " + or NULL */ +union sockunion *sockunion_getpeername (int); + +/* print addrptr in len length strptr buffer, + return NULL or strptr */ +const char *inet_ntop (int family, const void *addrptr, char *strptr, size_t len); + +/* put strptr in addrptr (which is a struct in_addr*), + return 1 if ok */ +int inet_pton (int family, const char *strptr, void *addrptr); + +/* put cp in inaddr (network byteorder) + return 1 if ok , 0 if problem */ +int inet_aton (const char *cp, struct in_addr *inaddr); +``` + +And last network.h + +```C +int readn (int, char *, int); +int writen (int, char *, int); +``` + +This is for the known case, where write(2) and read(2) return the number of bytes written/read, which need not be the number of bytes requested, and which doesn't necessarily imply an error. + + * readn returns 0 if all data was read, otherwise, if an error ocurred, the return value of read(2) is returned (<0). If the connection was closed, the number of bytes sent is returned. + * writen returns 0 if all data was sent, the error return value (<0) otherwise. diff --git a/doc/OSPF-API.md b/doc/OSPF-API.md new file mode 100644 index 000000000..5774300c0 --- /dev/null +++ b/doc/OSPF-API.md @@ -0,0 +1,263 @@ +# OSPF API Documentation + +[TOC] + +## Disclaimer + +The OSPF daemon contains an API for application access to the LSA database. This API was created by Ralph Keller, originally as patch for Zebra. Unfortunately, the page containing documentation of the API is no longer online. This page is an attempt to recreate documentation for the API (with lots of help of the WayBackMachine) + +## 1.  Introduction + +This page describes an API that allows external applications to access the link-state database (LSDB) of the OSPF daemon. The implementation is based on the OSPF code from FRRouting (forked from Quagga and formerly Zebra) routing protocol suite and is subject to the GNU General Public License. The OSPF API provides you with the following functionality: + +* Retrieval of the full or partial link-state database of the OSPF daemon. This allows applications to obtain an exact copy of the LSDB including router LSAs, network LSAs and so on. Whenever a new LSA arrives at the OSPF daemon, the API module immediately informs the application by sending a message. This way, the application is always synchronized with the LSDB of the OSPF daemon. +* Origination of own opaque LSAs (of type 9, 10, or 11) which are then distributed transparently to other routers within the flooding scope and received by other applications through the OSPF API. + +Opaque LSAs, which are described in RFC 2370 , allow you to distribute application-specific information within a network using the OSPF protocol. The information contained in opaque LSAs is transparent for the routing process but it can be processed by other modules such as traffic engineering (e.g., MPLS-TE). + +## 2.  Architecture + +The following picture depicts the architecture of the Quagga/Zebra protocol suite. The OSPF daemon is extended with opaque LSA capabilities and an API for external applications. The OSPF core module executes the OSPF protocol by discovering neighbors and exchanging neighbor state. The opaque module, implemented by Masahiko Endo, provides functions to exchange opaque LSAs between routers. Opaque LSAs can be generated by several modules such as the MPLS-TE module or the API server module. These modules then invoke the opaque module to flood their data to neighbors within the flooding scope. + +The client, which is an application potentially running on a different node than the OSPF daemon, links against the OSPF API client library. This client library establishes a socket connection with the API server module of the OSPF daemon and uses this connection to retrieve LSAs and originate opaque LSAs. + +![image](ospf_api_architecture.png) + +The OSPF API server module works like any other internal opaque module (such as the MPLS-TE module), but listens to connections from external applications that want to communicate with the OSPF daemon. The API server module can handle multiple clients concurrently. + +One of the main objectives of the implementation is to make as little changes to the existing Zebra code as possible. + +## 3.  Installation & Configuration + +Download FRRouting and unpack + +Configure your frr version (note that --enable-opaque-lsa also enables the ospfapi server and ospfclient). + +``` +% update-autotools +% sh ./configure --enable-opaque-lsa +% make + +``` + +This should also compile the client library and sample application in ospfclient. + +Make sure that you have enabled opaque LSAs in your configuration. Add the ospf opaque-lsa statement to your ospfd.conf: + +``` +! -*- ospf -*- +! +! OSPFd sample configuration file +! +! +hostname xxxxx +password xxxxx + +router ospf + router-id 10.0.0.1 + network 10.0.0.1/24 area 1 + neighbor 10.0.0.2 + network 10.0.1.2/24 area 1 + neighbor 10.0.1.1 + ospf opaque-lsa <============ add this statement! + +``` + +## 4. Usage + +In the following we describe how you can use the sample application to originate opaque LSAs. The sample application first registers with the OSPF daemon the opaque type it wants to inject and then waits until the OSPF daemon is ready to accept opaque LSAs of that type. Then the client application originates an opaque LSA, waits 10 seconds and then updates the opaque LSA with new opaque data. After another 20 seconds, the client application deletes the opaque LSA from the LSDB. If the clients terminates unexpectedly, the OSPF API module will remove all the opaque LSAs that the application registered. Since the opaque LSAs are flooded to other routers, we will see the opaque LSAs in all routers according to the flooding scope of the opaque LSA. + +We have a very simple demo setup, just two routers connected with an ATM point-to-point link. Start the modified OSPF daemons on two adjacent routers. First run on msr2: + +``` + > msr2:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf +``` + +And on the neighboring router msr3: + + +``` + > msr3:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf +``` + +Now the two routers form adjacency and start exchanging their databases. Looking at the OSPF daemon of msr2 (or msr3), you see this: + +``` + ospfd> show ip ospf database + + OSPF Router with ID (10.0.0.1) + + Router Link States (Area 0.0.0.1) + + Link ID ADV Router Age Seq# CkSum Link count + 10.0.0.1 10.0.0.1 55 0x80000003 0xc62f 2 + 10.0.0.2 10.0.0.2 55 0x80000003 0xe3e4 3 + + Net Link States (Area 0.0.0.1) + + Link ID ADV Router Age Seq# CkSum + 10.0.0.2 10.0.0.2 60 0x80000001 0x5fcb + +``` + +Now we start the sample main application that originates an opaque LSA. + + +``` + > cd ospfapi/apiclient + > ./main msr2 10 250 20 0.0.0.0 0.0.0.1 + +``` + +This originates an opaque LSA of type 10 (area local), with opaque type 250 (experimental), opaque id of 20 (chosen arbitrarily), interface address 0.0.0.0 (which is used only for opaque LSAs type 9), and area 0.0.0.1 + +Again looking at the OSPF database you see: + +``` + ospfd> show ip ospf database + + OSPF Router with ID (10.0.0.1) + + Router Link States (Area 0.0.0.1) + + Link ID ADV Router Age Seq# CkSum Link count + 10.0.0.1 10.0.0.1 437 0x80000003 0xc62f 2 + 10.0.0.2 10.0.0.2 437 0x80000003 0xe3e4 3 + + Net Link States (Area 0.0.0.1) + + Link ID ADV Router Age Seq# CkSum + 10.0.0.2 10.0.0.2 442 0x80000001 0x5fcb + + Area-Local Opaque-LSA (Area 0.0.0.1) + + Opaque-Type/Id ADV Router Age Seq# CkSum + 250.0.0.20 10.0.0.1 0 0x80000001 0x58a6 <=== opaque LSA + +``` + +You can take a closer look at this opaque LSA: + +``` + ospfd> show ip ospf database opaque-area + + OSPF Router with ID (10.0.0.1) + + + Area-Local Opaque-LSA (Area 0.0.0.1) + + LS age: 4 + Options: 66 + LS Type: Area-Local Opaque-LSA + Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID) + Advertising Router: 10.0.0.1 + LS Seq Number: 80000001 + Checksum: 0x58a6 + Length: 24 + Opaque-Type 250 (Private/Experimental) + Opaque-ID 0x14 + Opaque-Info: 4 octets of data + Added using OSPF API: 4 octets of opaque data + Opaque data: 1 0 0 0 <==== counter is 1 + +``` + +Note that the main application updates the opaque LSA after 10 seconds, then it looks as follows: + +``` + ospfd> show ip ospf database opaque-area + + OSPF Router with ID (10.0.0.1) + + + Area-Local Opaque-LSA (Area 0.0.0.1) + + LS age: 1 + Options: 66 + LS Type: Area-Local Opaque-LSA + Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID) + Advertising Router: 10.0.0.1 + LS Seq Number: 80000002 + Checksum: 0x59a3 + Length: 24 + Opaque-Type 250 (Private/Experimental) + Opaque-ID 0x14 + Opaque-Info: 4 octets of data + Added using OSPF API: 4 octets of opaque data + Opaque data: 2 0 0 0 <==== counter is now 2 + +``` + +Note that the payload of the opaque LSA has changed as you can see above. + +Then, again after another 20 seconds, the opaque LSA is flushed from the LSDB. + +#### Important note: + +In order to originate an opaque LSA, there must be at least one active opaque-capable neighbor. Thus, you cannot originate opaque LSAs of no neighbors are present. If you try to originate even so no neighbor is ready, you will receive a not ready error message. The reason for this restriction is that it might be possible that some routers have an identical opaque LSA from a previous origination in their LSDB that unfortunately could not be flushed due to a crash, and now if the router comes up again and starts originating a new opaque LSA, the new opaque LSA is considered older since it has a lower sequence number and is ignored by other routers (that consider the stalled opaque LSA as more recent). However, if the originating router first synchronizes the database before originating opaque LSAs, it will detect the older opaque LSA and can flush it first. + + +## 5.  Protocol and Message Formats + +If you are developing your own client application and you don't want to make use of the client library (due to the GNU license restriction or whatever reason), you can implement your own client-side message handling. The OSPF API uses two connections between the client and the OSPF API server: One connection is used for a synchronous request /reply protocol and another connection is used for asynchronous notifications (e.g., LSA update, neighbor status change). + +Each message begins with the following header: + +![image](ospf_api_msghdr.png) + +The message type field can take one of the following values: + +Messages to OSPF deamon | Value +----------------------- | ----- +MSG_REGISTER_OPAQUETYPE | 1 +MSG_UNREGISTER_OPAQUETYPE | 2 +MSG_REGISTER_EVENT | 3 +MSG_SYNC_LSDB | 4 +MSG_ORIGINATE_REQUEST | 5 +MSG_DELETE_REQUEST | 6 + +Messages from OSPF deamon | Value +------------------------- | ----- +MSG_REPLY | 10 +MSG_READY_NOTIFY | 11 +MSG_LSA_UPDATE_NOTIFY | 12 +MSG_LSA_DELETE_NOTIFY | 13 +MSG_NEW_IF | 14 +MSG_DEL_IF | 15 +MSG_ISM_CHANGE | 16 +MSG_NSM_CHANGE | 17 + +The synchronous requests and replies have the following message formats: + +![image](ospf_api_msgs1.png) + +The origin field allows to select according to the following types of origins: + +Origin | Value +------ | ----- +NON_SELF_ORIGINATED | 0 +SELF_ORIGINATED | 1 +ANY_ORIGIN | 2 + +The reply message has on of the following error codes: + +Error code | Value +---------- | ----- +API_OK | 0 +API_NOSUCHINTERFACE | -1 +API_NOSUCHAREA | -2 +API_NOSUCHLSA | -3 +API_ILLEGALSATYPE | -4 +API_ILLEGALOPAQUETYPE | -5 +API_OPAQUETYPEINUSE | -6 +API_NOMEMORY | -7 +API_ERROR | -99 +API_UNDEF | -100 + +The asynchronous notifications have the following message formats: + +![image](ospf_api_msgs2.png) + +## 6.  Original Acknowledgments from Ralph Keller + +I would like to thank Masahiko Endo, the author of the opaque LSA extension module, for his great support. His wonderful ASCII graphs explaining the internal workings of this code, and his invaluable input proved to be crucial in designing a useful API for accessing the link state database of the OSPF daemon. Once, he even decided to take the plane from Tokyo to Zurich so that we could actually meet and have face-to-face discussions, which was a lot of fun. Clearly, without Masahiko no API would ever be completed. I also would like to thank Daniel Bauer who wrote an opaque LSA implementation too and was willing to test the OSPF API code in one of his projects. diff --git a/doc/ospf_api_architecture.png b/doc/ospf_api_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..bd10a3865bb6d28e3b7c88eb7da15ddb457dede7 GIT binary patch literal 20580 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

K*^ z02N{(2{kqHPO$dtAIMYNv%_gH3-B?CuqHIXLDbCbf-Decp-qELYLSG#Zw6J(CRqZv zV36!*aD4dL5pe@wW9lx?C0nKnjv#$!#5x{i3DK&BDZ25+6|R;7FW=k8)k=XO+Q+4+ zq;&4K;VWICyG8;fUl%vot3bSqBZRF(eOtMDeJYLDS63fDdIW-L?KI%FiHVWDvvb+s zA}@;N6%}Vcs@!1%<#PVCK3_osZ_MFK)NMIn)lPN&tz7pn=K<(1U78#e#0r9xOp=L{WB5b9zA(OllasT? z{ifSxP*=~^1+hF5`$#IgBszkxuOUyT)Qwq46NN(A7NaV!jOMoU?ULb1~KxEeEcGS^(GeN=d0kM znp#@qudNSiOcytU%*@zqsIxVyx)*)kX&}27%w_-VB)p#fpLY-XoYquHkoS~1}E O44|!{uU?C=i})`Jc)8sG literal 0 HcmV?d00001 diff --git a/doc/ospf_api_msgs1.png b/doc/ospf_api_msgs1.png new file mode 100644 index 0000000000000000000000000000000000000000..a23cc619cd7489eaca5710fcf40cec08c5fe3fee GIT binary patch literal 36814 zcmdp;cTiL9`{tvFAYDY7bPy1!5_*$JuOht*(tGbkk=~2+CLkasAYHnOh)4+#A=1GJ z0YZ`9VISUizO%pG**|t>cV=gnk-^|eJUQoi?s8q9J26i+6p0CF2_O&%v9glfGYI5* zDERimzYc!0jvaFaKW@1x8G1q>Bww$-ucbdExd(wTL6qfWb^P+yXU&yZ?JxK)Y@=GU zBJhR(6koSrk=7xeCj0yyznhLbo5;L7*(SXv;+EB0)(0QDUtIp)m~OcNPO@#KB#syS{FLx|g%AQ6ab`64y0$=Y?{0W^SCIc` zsi-+)=-Kw=Y3Suvv8sEbQ)ee!0bQ(m&9QYwS;OQTW7`~RyA=mwqQQ6@CZ|P5P5sw6=w!8=uFtw*vcZZc zwwN$tY2Mo*mUeq|*I5z+g~fY>iVoFUzplMS|t<;ra2`4Js;#UY`a z$-YkdNV$T-wosW&wKDYfe9%e7_uclKi43R3mTr1RY9$30jJW~iCFw$8Nlj#ABs8x3 z@_dV^=PP>K2=231jq~a;6Pc*Ex+H^ZUNgep+1c63>W>$ypz0~-pKZTHrMHz1P}&V6 z|C+`nrEs#;$zMli$Szc)Ol>WS_(csm?x#=1-tlX^SZ;GUnrje^^#uV0T^|o0AGVFR z`xKE~Ss69{OGnq4a6IjwujK(Fcv)rTgqEWie^pPa;g%U(4_DUD)kSfBFxn0g-NK(-j;#I%+fT!omcx4}^L4s~?=`Bj)cHB5|kI^}gRYQ1k zMFj3HhOn;6ULxwu`=?_Qy)K+_k9qU`nuR{SPyeWoPE&(31j3v9MA3AVt76Eegs)-J zNs>VX!OO#wkeE1D$eI#O^UlA3FJ0w0Xl}y?IijQ)Q*6MMZbutw@hF?9&z-JswT)Lf zl}#DiY}oK9?KbR&?1HF9hP5e*QPPiT;8B8q;(6#B&2aQbH_^O-C8D0UB0n&@BvDUv zb-U;J@W1^2%`#A5Yu5Q&bn^pCMWwiqkoEE>_Zdx@b2)7fIx2z)8yg#krkwe$a(jGc z-psg+nXSV+u(J>uDH!7iBY4i11$$ai%L+H*LBV0=sTK;(r}+Bw=<|^PIgN6|Oe{%X z9dBlyMoa!iSZr~Sh=lR{k6pu7S5K6X*z#iEt`ZtL&`e4k6AXVB&m-a!h^C+okpZM60c7 zZ0RcLD)$3?93A7x$YbR2nRCkOxbG1}*sZ9uk=JwAR##{B4;D-Xbn*^(a8gW7O&J*& zFopl|Xl>95O6&hKGm}?l4{i%TQ3JgJYTu)^qpPc{vGJ?>%x(FcoE(;LCue8-97_Bf zY|6!?jzVH$_AS$^xfuvd)wly!x<~u$aZmwSDgrY!VqA+_JxxPkR7;;(bzj!QCCfwR zsvKD;PpjAx+-Dk@{yeJ~Hkz#|b9QyPSyqP6Y$p3_Zf4zMsMf5imr=^YgU+l~sQcWw#xbUQiUhKWyOt}W~w+3wBG%+P)C+gnMQbqU>HyDQb+ z(IE+iS_!iva||D4vxUDyuHun0j4*AuiLO)#H`1zCy_AxYIu5${l%ki)b}Q`hw3Gd# z9)1dWfjeODe4KTm4gaxJkHARmzu1-3bp7MgZpxe4r0Z{K`31W_mUC_)|4i50(^D|5 zf8^B=*qo#ck}DmA=NF?+!m9~podMR)vE@+pz~h}IaANSj_SsDXZX4&nEg6`bw8S?r zJG$l&y8%r(U{$@Zid|}fX_V)4t8xs+-+Zl+F?6<_G|OGYtsI`*dOm+P`us1dDA{oG zemMS}JB>?0BiId$zgRwd_{=JnFuZ43k}Vy38LUk6@w%Ic_ zJbxAzp4S;b%@6kXJ6n{Xc#hVMJa@RrW7IS?Nr{N~iO{>pU1vK3!>J=PD}gSZag+H@ z8JKUhdja-OD^L!O^&J@lV38Pw?8gdMan(E7W_ht#l+Dj=p;r<;>g-z1Jjh`#4b_G> zIR=c3zYJ*yyR^Kv@TkzK8s(&lv#Ande&<5XFfjk~EegASlPgX4W1iM=ht)O)f{1GOQOqvAsGpy+bAtcjeEY7OTuSx!5q?QYNn!9oHur#|qhl(Y ze90&VQHVFck?z!F#68eFjt-V)9H>8OKhGC=DzDW%uoQFtVAdy!m0wKk3PFsh>Uc|+Kdr= zqM+tdoTAP7*mVCW=v*C^RwVe%jKLBCAcTc(HV zop>`Hjoo_q0-GLNr|oJ;OnuH^Fwv|!3>(yY8==v34v{0 zC6&vMm}J((;heR++#h%|#X^3FuTKv1yK;AHwC6M*c5PYsiVpYJw;1|-*=aZWZnH(d zhrxkle*P?&sGtZU^$1818$S72S-)mxpj7jm6a;8Ay759pKwx`kNj0Ey(uv_?vAlRb zxI$&Kg;w47ei3yp2bmXO?khhsHepRs0twtWJg!o&N^x+n6ek9*8WCOm9((fOB!={1 zDhf+aOG_@FBCR8w8|**g(WkAg-6&NEijTr--Gk0fDOmLM1_LcE2&a$c3zgW$Cdh(c zjE2k{l_;tdJ!i)qck2eY$?X$MVt;lwR@=k|9Tau%8Xg#R zt#$q~SF%#nZBe~HRq5pH&|JoRwdVtx9KOA96lqRFuSJeJ2;X9c+cY?>uCHK@!`QO* z@3W?ONnY&AhDy7MHx!G;y>j}yNGFb7nRe~wNmprTXefR5fSRZ)fH z-?QVlDAm&dMe!Wy^|Z8BtNIUZQ~A6I+1f)=L}594yU8Sx?3oDB#L^=S$!*vH)Hxo# zPNXdoA5u_0j*Kx_KSZN{UlwAe2~@On^`D6^NW&+M(G8^r7n_Lr)S7 zQAlb2$yZCQk}mU|xklzPr@VxCydoB+jsA+dRZAXKqaT`KTMkAIt^@7unH z?@@hjh4S8!kk7Ov`$d@enU=C<=Lwa@Xnyf{x!zbp96gN_6LOIYbQ z&pScyR|4(x-IG`aPYRX-KjHQN!Os*tX(s;YD3sf3i?}`?^a8tD!5Mq8JQU5utymJ6 zv;5~{#j*d1?(61Dyo2tX7VA{iQoB>R!oFR8I^phoP_B+!d6b)MHcczak2+@0DwbP| ztnEjod|&%=U3M>m6tfUAkIv1>DSjx;PJT<4j6o(O=-W7B?TthQ0#h69v(sD<{6AD>7dB1wZbm{r>xxr+pT^>zt`_yStFxcwoscXk*Yy zkHWM6T_0xmC`e+dUQ|*oY0Du;RPwB(%s;4Wn(nZ@PQdfP=n?tx`O%ScA~>pwkZ?ay zTIgkiDE6Yutk(C%izlgUuzgl{+b&wIe_%9lE`lMX?U7L^NRl2oIS*)Zc45Z5JD64E41O}e+Hb|1)LMeC>3NO)%ZK+PFfnS@(C}kcRlwk(o#|P(91MsX_#gjo|v!c+Q41R z7xXx~3*vS@Nl#)lKdUu<`D00siVB=F*ykD*+P{Y_I)d zSGe9o13l?5$G2ux4^ZcV8`Y|xZ!2`2d1#_+<=qu^Ju7sk>OF?F^l`6G=jN`;fwN6Z ziEc&V=9}!zt~<$V`REAcD>=EkjO~ACP+$p7XA590eHtwjU}c*nTZ`Is^TTDPPok=y zq}T1`(*OI}v~xv5QnJIdlJAR~eN0c!Nz;WIGUlrQ8t8b9B#`BZP2^=uj}nLDF6%` z7obH8FmUy*y=s5mFZG`*_jS0^K?YpTRw=D^bhpd-w%gIlpRvy+OSW>*=6pkT#5><5 zpq7&Wu{&WE0eiKqxut~qydYZRd@Bowk&^dEBh&h7fNW|RZc#BO3j)PcSn-TgjqrL= z)%|zR`jxEW(ceUC;P?6Sl}6An=rY@_3hjB*xs=8VYT_gdRZGionQ3AS?x+!lJ>y(= zm;x{MzViF-3p$RSAY;d~YR)k{XgmM4g|(AtGM3n4Hsv}4?m|RV&thK^Bl78#Lz7uo z(CXnS2Rpm4uyBy{{I6eG^_RAxAUYYhxGe1+2T3y$L==y{Z-tMXpB{pqODcU}Nu`v0 z_WS!$JDn=s-8s0Pqo-%urln5Rcs0!g*8B3}L`V;$R_+0UFn$RM?0x`oPck>*Z;(G{ z+Pve)itUX+ZH2<#yLa#5!-vosBs4|o-G;^OmwbA5J{iN1TSLPn0iE7G$vlOtYhS`P zCU{`q3(A&K`wQ3h2fryeSzBu&%MN9bR&39b-^Ca>Nf(la_rxVJnpZ+3PyQC^ljU*W zGc#idKKeVi@YefGLtbmop=qlDkprK=X7ZJUbn^?OO#b?N6a*rLU`h4&-M}15W5a9& z#-4DE*QOg{V$JB7!>*j#ify0XaDmdMvSkz6WlhrnVFui2&>PgEswyi7mVT_a`~kg? za_Y(#O=wnUz<#WYU@`&|bx7qc0fW-s56`0M3fOme{+uaYr3ua~-$J*tu~8~BLJzUm zTJ6I1^z^i`%*pLp%*xF@{T;^#RR_XBJ$Ij_0JeucO}Sdf`_&4$eDj>y3C`?;B;mtx z$EG%mAm?K>dvww4B9o`*<#sPsdk)ZnC=7);682hW;R>voYBza@Y#p$xb^8aY=Nxxo zMPY1r>kW+-zN~R!JtpZBb1cYU3Qw2=f-G&8)k{;2%^3CqKt(;v|LER5uf3<{?1DV_ z11aCh6&A0X7&6wv;dR`Orp^7BUHKBNwm{N>`l6@bC51#qm9RN3Eyfwvw10mr?QCw= zbjf@S1r>k=wPzG#RFB2%&jbF(^U0|ob^QJ%55>OTC{jk1R5{<)a$G@F>z~6zml8a~ zjNt9x5q;=U?@pjXhyXFDt;T!@9`5pHG>Y_+OSwJACkkzM|JMxU?fgzQSP~i;rR@+< z6Pm$u26mfi6Pl$q`0lp%d~P#|OX#0p2z*r;9_Qzm}Ja4cHbeLjHSCBr^Llx z;rh#m81%Q(vSi=Q52~P{%}t?+-1d`Pzp!-O4>+e-dV4xW$kN>h0!My|D`1$FzZOXuGYEKRp=T<^DfM21fW zs~&9`t9zJ-TwTXv;}lA=)s{Qm>3K(#n37f5FL}tA!VR!tuHw?#-&Q-2s6$hzcy9kp zt9aq69e-A0ABgML&O=5;^GI)_)pEX}-gHT6bJ^7D!0A!?>urWMkfRUMv@|r#;Rb!Y zQh^8Y)`o)BU4GkNB<~MAavm+M8&WIbjGf$B-#zv+6~VJL)Z9NfAcqZV{g}w90m_J8 z)!Ky-rpd_J&+j9g`Q)*e=s1vB2A1j-untXAKmkBBJ`Aw3`nuuMz6u{96$3erJ# zQe8I3p4wK~-)yGZTuf_Oe;;bjzl2L(tEo$(CsE|4yvN9h^3J!OR4IK12ik1LAVn(M zsCKVqiUqa!8)b^#x;gh6*F2&OtkL6Ay1loAE#@BCTFfO*VB-hs%rl_6AMx`OXrfxO7g%>7kVL zd{WzmzVb=WE(R*B`PH(UkbU?5tCT%I3>CtKF}VTS3|ks08^JR>lPs{T6MgjP8CN>2DA~VRhbyATLLJGKt|CguYdAGo{U}?FlY*9x z4w^(nLefl3#~RL01Xj5neQAM(s5I#YUEI&KDqTrYjfRng(Nw`Jrr< z0&5SK9BQH2N^C1c#R&-salC{<)T?s86-`l9@8n zdAY;8&d7NX`h>-Nd2=QG{UWY&CSDJQM-eiYCP3cIJHk4+x*}X!LU;N(s7%R3(<0=) zptr#x3pdDuuK`zO<9~8hKqU)-%troevHXAY;9y&x3R1%_uSFr>y7KH(_SxAkqA+Nu zUq179km;%I*`G8`(5CQ(9uLIv;^#rY#WZ_L;V=7P(&_4=byB55q2g<9;(TpPn9}B! zL-W>|9u7@j@aX;CZ`>aKVoozJ*{dtMs0KPd^p&-wdaay8b!??4>b2PxxN#ltOUG=A z{_fArT;0X-g9F|+d^gLLLtF@CMOe-p0(t53WbZ!@ULLA)kONI5c_>zrZzqU3x2d4g z;N~UfS%nFgJifh9?p~!88_NzT6hQ+4i$1PD)x4I8SIh_bbb6P~e(fSyK0`{nFbxg# zHJ6(UVQkKs12#XJOk8*}S;NnspjLHd#<2{AuI)OpN9QbvOP$(7f63|6u|_77!Jbd| zUkV@~kiI6ifxRdx^)%!vkZV`=0^2t4hX4I?ojKfHJXA*d;*Vx1ftm(6EbFQ>`{PeV z&CBx>tf$0Y^lr8cc)7lgwfXDUPI~gYq+!vHmoQYF=S#<1R~^+?;LK5(-uO86@A@OY z`dzhALgcaMEI;oDHaA_SlP`DmwBDGix34_Q`;=Ij=suHJ39fJ3T9&5NH}_S!VhQ<^ z4+fd4DN8V6V=an7*02|_y@)CxI$fgU_&~`BF0s{t*LiW=h_jS%ZoWmpT+2N?tcU6H z@XzMolL3MGbc&&7sY@XRntkYP#Uz&oCnmbG@&Kpiiz4RT&l2YKy!yV3*LiObie7)Y z>m7xDR5})zmYwF$Ti*P8)bL4Jt6JG^YBSzekbgfT&G6l|F1Py|4n`ghv1F-vIXQQG z?PY<_HgN+P_LhPGgc%-uiAt`WGwQw=$yy462`eCKeRJP?(`urH(Y-5Q*VQOooFf+R zp4T*9SIh}Lr|wfH{PK$D4`?Hd$c%=T@q%pIV!E`J1;--t@R=Kmvs6o0Dh#z|#-S;g zAz!9^rL0VfdPC3N7<<{bs&d&|-Py-?ol|a#UN7b|QT7$p$jV~665W0y%MWkj-BlGT zF6InqnmU}c9n!<@4`ga}n`dQx2e~1r3rJPjT6%wurPSl#)j+-ar%{t*4d1W4@=VA> z_oBPv;nid?y9JJL(7R;!$ZX$1R$402a%bbeI>*wkebrKMJ#Z z9QgY6s-H=%o_%CMlS&^icvt#l%e%)R1(&?EO}tC^Zp3ewXll6Hd_L!QbxF{1gu`%^ zxvUzzHj4gts%D?4*JNXv{c40?JlHISZ{GZ35ipMWw>rN(K0llr)q+I}2&5$T-C~B0 z1xbl0iu7%Gwl8@FXd>~M_qr}A@j>Yxo;;~m225QZun#xwr-Gz4@0iFBq(tXi3{s+& z^lO1Uq11==GUc$euWS;&OTo4Z0(awNGh)LsNvQ% zID(Z+q?x}?AfMn2CRT24u2TmFdiQ(~Bw`N#_VfKbqRqri_HTT=LHn&VZEc_mg!)~a ztwox_qCr7sG-qI}2{d}2gG`CCttYvr>eEPX&kYXP_io(lQS#~Xcyw=d?swbp;lv-!Gan=he@^&niW4=X;3J zCjoggq@aal@YwsRx$g{flh4i9#QY$BiYF=qJb88C60Q14W~%5;Oq}@7Np_WEK_g)s z>Ji<_71oD&sFdnWV$Q0#xaHzwE16<#nHD3PdrrLRMnPwOdy7wu5=i*? z=B+1dZ{DN~Ii1Go`(buhroips&1;K1?)LVE7kVeYzCOc6CJ=pyg6Ze|(f^?=J@_4Q z+`uvb6+R4<3~Y0mEfxBGSZLQLaz1pAV<2(ee9S?3NIsEZvRYKqDe)S^?Hjq?tbg6Mn=NP zxlKvU(cY@7^!ZOvIQ4iE{P#+bgaUX-q4WgjAweBGCqh!XBJq=HKjjo}FlVYMoQ1UQ ztIMXY6FtHCYsb$CUiv}6JkV{#FTP8NpJ1N?9YyNs7^7cz?$4Wc+dl-Pf+U0@p5`RD zA(T$#6%i4jV(k-6?9yKuiMU5NN>%gW?^tSA!;6~7UQy^gZby0oxn4az;kaIpI#F_b zgPtA}c0urh>8M&D*7RZSz?i3Yf-3#adQ#0g0 z*4N6RAMjY-b?%2Jk3M}rk7lOdA|Fcb^sSX3#T}vV_B%b;kk7nUQwfTrvI$ha?-s}k z7cs++g*a~ChWY4t2R&ano|s5yFb%4?I6v4pc4~H93^gKCkWU$&WjXDc=#oM7wv9hq z_3b_$ItjfzT;;9h{BhL-t{(ag`oVou76>kVyGe+;c8-FZa3AcR#VBaVW=^`ys%U7ogq*Bun9qj-H9Ia2 z2%hF%MI`rkIwmDG0x4JcJ7*efy&8jN`9W3uyh7)@4RZTqcB*&l;OcNg@kbC$wY_^l z)Yv1ml-B|=)tjOFeN+VRY1WkjgPqNW2RS@)W3*&h zhjMYf2b*cGkuv$%s>Tiy!)y4UkQ#3haPdXr!FC)q^DljRH2dpUV&$06n~foL@tMwX zrwPXF)s7ft+%ynmluO{y5`ZOm_B`jqMOK;oeaW zcXtb#t|lSr7IQJDi;GKrh8d+P$}l6L*YdL%C=!ruS&>YK4fvYsS!~i zmByyr{_J$glpzX^4jtS-FUn=Nu>pU0+bFg~1Ox?lmNKJ=qdn`n6W%lz6o4!BwSEg$ zIK6QrWuDeg)rEb31uvn9@N zen)>|^vM7V1e{)Jez)f;({SVSCr=iamWH+O${#23bsc$gLdo$zN)~`tnrN)i!bTtY z!_hIlsj0UwDPh*sGlCMF7rpnm9TcCr`JAM|N%-D;A@yT?Ln9;F*)4dC9Lvtd(e;8W zwn4hkw|zE@i43;#K#O9iO{j-ITP+eTng~);CR@Lgdy|bdJ8L+8*eCZq?t!)%8Na`e zHw~!u$imky2s$MZwvT8|aQfV7R27-}+#AJAb;m0z9=y0bb>gJR$gJ^H0BmRe)_{kf03{f=y~P{e>e`)dNVm` zm|<<-U0civJkdor10+-(=~qx#P*5}O5T5KL-2U++bzCo0efrn05vcmSt3I%e_XG0D zQdLTU1}fFw)Fh7&u1`3bI?^BmXa~@&`{cI_GxYWJ2CbGMC;x>zSvlIExKU(Qi#!9G zYK2bmG2ZoSj-CNr=`7(R96P7ybbX_JF};?fc8wpp|0LI7TTK#|56+HvGx^Mc#5X)< zWZhuc@F%A%qGz$US6*;(Ad?Tf-*!CFU#~VVu0;WW6zM_~)Y;m4X@$fCvhqlxXWgFG zbkI>B*_E3w#eLsdpr9?Zu*Ri~f?#>#c8gfz`qs`*2Vq zv`7FCHI^M7WP6xNKDgx37^1x8LMcQ|6bWN?d|H^5^|lpQ@fp^K2M38EcTP`EzAS$5 z4UH`9Lo$*2JP7FgqC6pbr&`Qi!78al5JsZ6n;r5Ltymw$k zJ%5jbmSq#szkE>*_rt?sMV56dho`rg!nrL5A%MTK!qcw;)A#X;!)1P;mv+l zVOBLxRN@@IYth$#LHT`|oBgBK#rT#Z$(jHD+W4nWFPq9U$bNgY0-Xx3f3V57b!bKs zRieWM5JFU~`9OUK*b4*^Qx5%bJyq2HQ%)=5Iq5>g?q-d1z7d>qpnk#?vIomS0J{zt zhxp9>R;d=$C&9nVfkf5uhnpbc%ibPzNQMmmms9ih_BLs{7{uhQ1P6_;y{{;V2`~Bs zngX^p^gp8-(=Yx(H3T!Z0w$d@zR5>gaHYrk&rEGON*%RypYu=?jon-Wvb-9*V^faz z9v_^do_pFS69I6I6}-QGl1Yp*2jH%>;He`I4h{kW0`Qp|=kioa!Ih5cfqn*HPLom7 z-211TqKAhXG7%9GxJLbDe7XZFCsFS0v)lt21J(_{CRAh~5EECtEq+mPaaw{1N-8S* z7VOurUzeB5CSMtGQhe*{vv17G%Hr?4FO)lkLq)4z4xD`C(0TrMJCP4G0ryT%;X9Ii z%BeJMz)=M}MW?F-P~fDXQ0Nt{#~345O*|ULG{Wo9@FIP9QYg--YP_txyih98XD?w& z#c_P%XV74^UjYJalV3wNg1$`^p2%tJZ`F%sXi!;Vxj)%<<;7xk8O7inRK7C5u6WwdM_hw+p$i(E0wIQ-m zjlE~LV}7fJU1IppEU-Gd=QVfBeG!=5<;j?snBLxAz=>rUf<14*O_|gumROQGGO51R znbOoafvz)f3JRK8S1Q~0bL>2Lyyrh;Nf_p~bP^ou(qz+hvW8BoGdj9^;8~?>V0ymz zcNMB{>g>9O(ZfdH9zcDX=Sn}R4e=f=eVKOLJKf?+YMk8aEI^=+oLKR(XJvJc87gH1 zy1GpU+~WDe&HD{gdhbQ~C*3pR^(abBcmpL1hM7$(E5S`Su#43D8q%}@!aX1^4^P`0Y0%r2}_=of&N7| zKb&j#^t8HuTuk%(%y$5(C$F|J^x`;8Q~K)fB~qrBPq=+_GuCm}swIewGJi6i2Dceh zA4Pt2k|4T1qxQ?g+fW7imy=WDpG#4Z;Nh&CK2afz(d}chKVbEZQgBeH#JkjeGHp|Yp5sR#@_o&8qwEgw3=QSNbDQ(e--2SrYIh zK)8}*&;+pzvkP*&f>2W5E&!u?>krzv2LLZi2F!!=5Sf8`;DyqWsHR#eXw%|?48L=H z1~+cmobPtM+3F|Biw~17#Q00oCXD47!zVy`UVT7IE3fs2?E%PhgN!mEPBtOGg26v6 zFSE}Q+xz(V_?t740r(GS&f&>`nEuyt%}xSttmcW$t*{RtKXT&3z+3G$=yjlHLH)M|%qZn5v zS{L22%nJIgfOP`AuX`_g7WqvXO^{IK)B>4M4Q=prg%W1v)JdJdg{gCd$X2`UYupm2y#&CZ1i)*<=Jaf=dS-{axvxO;9j4 zkgC8rtdYUhq9E@1u(_jJbtF$1X^}Wr{{dLU(C!P)ZfGQBY z&kS_IuZxTC=Nb1;`$TL0ZpMGaNpLp_=sxTlG^As=sP*mcxOk7fQ}=63ce;d@w_A>- zh_3O{t6@@&ja*SbWH@!s2r{*(lz;zW6?l7q1+cIv(&4htQ8?9JEfJ?9$sB0v=umS^ z&Ocpl24`6+I}A`#k{}exlj-*egWKX}Rapj#q&v-vsZfcv)y zcz7X)nF(XwQnU#Sq2gF&q_!95vraQtC@m<(o3o4>ihD9N-*D_}3FkI72N8sQGNMhq zA^Tphs?}suG&qeRNfG5OI5XkUWcBD6og~B14P|9z{WBZ8&|r%&$dI}y*!7|V?xAD* zSIn+%m2Sfh$nlX;QJRfoxbzZI04+c7N*l8AHZ3=&6(4sH5^u&v&n@Y2m15g4e&-Hu zFA{EC2fD|eZF`S}Z5C)c3pOyvqtBC@NvYWSAL8%X0!j%cZ7vcYTTBMKDRX&-Z52Dc zpz50DaAL_ot|AyE-!e~Zx&Z<5khy?pK?+1Kk@+CcgP<9g!-2!KCF)`GDVxHhpt%&wDX|(2?Bh* zwPBfcTpuveaBNg}K!N3b^8?tknM^1C{6sIDA+7^6{6wZGfVBor-(83#RMXI-kk5F> z=pC$y1mNgtRODcT4PEJMT`afp!!p3nn(~qcbe4Qxs3|MG6QfsBr_GDfJknH{<*)9k zxY=puwLJ&+pL)iULdod#^h5lxNtg1<%IS?^n+CWZcCjbQi=wiabIGHX=YBfKKTJh@ z-Df*;v!N72ldE21x=G@37%%bHTaJn$BYV2S= zn0JSm@@5WI8)W1c7PjbB;Jo_O8F)w{d6(!WpfAyE#Ab z%r=H!M8uXll6zpuLk!Fn$ZAdW=IiO}TN_Sz2Rk^#MoMDu-B(T>SSp^Zyb=*id8zVW zia&a^gJ`N@=infXQ;4)sQ&TfYYSg9aG^-W*cH{NuX1?2C%)vP`>u^nSJbN*4%W>$> zN`7RL-(b(?*mCqxJn6%OZ9zQIr_8ytb2DeVCv9Q}N9|9Z%`J*@49wX~-WqT$zin0m!dSX*w{$R75f_$3Q|H65(B%E&Xj`+iYy;1tC;wdK?40K*#;=@%w4$vgT^nZV@9SMp(5Vz|eoY?Ro z40}%BFIP@7DuNmDE&w8e-RauxDz@v7seqR6AxyGy9_@L9(*{ z-DaT%0MB>2GKf&Bgt52AB1E-J)x5l$4paH){b2A^pfuYLd-tqh{P#}h=!A25$YZit z*FQ)B^ZU&k=~u~yZR_^PoZcXF8L_pLd$ocXPvNS5KR;e-RF$m8Vo=!lL8>nA&`{>MoN1WzGPE7xKx61rnCG{O?)6Z+O zj*7@e08oQ30QGHcZu*2C<^Xz+n3$Np;YR@df#~&*w?L@F=4jje!p4X0Ex0E#W|i%d zV+SPYY!B!dec}$6Z|M`7TK-<4x8}@w?(2)H4gi_V4tfIgl^%Y82-@?qscCd|fDKk( z!&}W6E9Nhfq6Dfs4Gj$sIuS83|1pLo(xnE3^uu(OV6*l~k+nZfs5BK9JFdlE` zvZy`JVy7!5-8g;N)_p_ouW z9Zaa*k6P^+O9j(BU?uBKOmAMqwE*&?5eoUa(eA5_#SXXo0=FL`GF8n<@Z^cJF}yIU zhcaK3TcC$OKVdwI{*tLzRO=Rk)bz#CN-FRoA&|r+xmOz>zS<@wD*kb!f$=eaU3BX> z#NvVu3SvU7jwGpSVw`vxB*k=c9r7t+QFPO$hU?W8XF;`^3Z?R;`6dZ^L$7;Rhd*v% zzB;HBbWe9;Zh+qFO}I5_jSkm+d>9+KShulAuDZBqi{n*mx$s*kSG_HXnfaXwZ?5WN zAi0C}bR~FphJ^TTt**9uWA%QAPrDT0Dwtk_eCj>ja18~~DWCmxNMs%mk{cTvV9lkI zO#Z~;T6gt#=_+?u&+qm==KoUQ@}j~paw z>}hA?Wp#D2o46A<_{=((!bS5nuzGu5qYtmR|3|YgKTFOvk7bnE6ZP!v?TKF1mUj~r zRx5vEh##tdS)J_)KE+<{cdwfs7vMvpQpjUs9=|1gs9sR`k3J-%Ucz@LCY(*#i&jnu$1${R6T2SzGsF_sL=P|BQ9U zxz{{(d?k2vgqBXi!%E_qRDW4plc!p&_Gq1X6?oJ3QMMe57B{7Yae=OGI-7lPaQ;nD zNr>_DGbxkLjz30ugT|Mx^mCR=qMV4z7&HMbTHl?}=^MJGkHzbTE-o5sYF;*h1*I1pSE$Ix01EkI zK%e3>gK6DDgkz4+;FKpAzRWB~t`-$BPu-Xez5+{LR@wUdXIoEd$7}kC(h>Dk*VJUF z+^3D17R?_f)%tY!cot|1yjcTFT$FJfZQ&D!y1Mtnp}Fc>6w^ipN&Er=vQh3$#Kn5L zx+w3YKF{LRJd%HwGCyFXJKo|Nz?OnOYsFUw@59I!HD*K`@(vlTQPb z(WxD7$~aTUxNkw`qMiSGb^>Vp1`ehbUb+erJVFtVLGy2!P@(sAq3=-T>qXg!eTlegisdIDfRx z0lFs<4aOm6T3?KTr;Uw`wa(2FfTI#qHQ2cD&R_p>5JtwxRZT*ZbSUoUE4{lDGh4&` z6Az`yo@U=l)=TA`G zaSE3*g|&zc_A3s;3_e8@X*Pz~^)xlCWT?3V)D`~UtDiE~z;sqklbH6^aKIZdnYnpN zDe%4YSwNF`Ap)snqV?wT=y%*_gbZWTx)=^b4;-fdq*Kp0ZAq^LxF7VlZ+JRZ(CY$Q z1i-#k4boz?36{4dxAkRcKabF5wy_Lt}3?fgMnC1Q)k4NBcUErr|JbTbkCyV{qP^^T1JOB!*8;Dp- zkAR#qlSDa#Oh@I6Ro#9ixs;_th568Q=9KsMA}2c}AI1V=0S_FaaEtlX=0Wi_6CUba zA~#&_?f~n^ISn(_-5sBbpP22D5mo${pi>^^cgaKKFq>x;txg9&t-&nixumNwADE6} z$a2!70E9AVHnr#R7udn-UmyT{7ocp)O=|AlWVX^ofkx!Q+owChS08x*W<0E|yTerP zAbAbids0+OCp^SpO6Pxd&q=gJh>{StT^&8{!-=B?|Jb(Y{=uD|@lc2Xh}$ODe*gWD zZy_non7_!nbM~s=NjNvn8fWnXcGmj$>RW5^2X;`3wL`zni#7dvw$VvB#_D8ASLd9Y zFIhoqF!8x+_3M)nEeU3ua(AfP+ieOR!Kz49=q=a8MsA-h4ai7_x(r`;$af=jpIG7o z&Pn#y>{*ZrFqhLgKjSnoE>B|R7i#KkRrahwIm{0Y=ak#X*SS!Gv0Jd*eRa|=Y)x+x zLZ*P}?KVjq&mc} z^GN{QfEhbqQQn{(o}p_C@gPOIh&Qs~crn`00Xg=+rq}=d2NP{!$aYW6@UP1wMk-SR z2osW&(ah`ig4Kr}rmJLKbd~ui*Mi&xn61 z&i{ZDK#jJMy$bsO56BD7TxxH`lEUx#!EDS9T1^8Og=Q;f67IEEq}H86Jm7OyhHTPo#ttZ) z`G&3=&)Z_%cNKbvf^-F`(n66U8Z3Yy zXaa;PLg>9nM@6IwC`xaNB0?xa2na|~L_k2Al+cmhdkgJ9@%?t+Z+E}hzs&rzGyBXl zqa!4_?>kpH&!b(b6TnidXG+G_$8~i2MF!Dn=XEr`R+=wHp8MCO{`Nid47d~a$lB~y zukwMmvg9iO4PU!CKc}B;5fc`|8$I~s(k_e{xH^HU- zPFLtav~c1?TnE_MPga|-0L%seB+K=`I+ipT{i^9vSy{j-U@EK%%*3sJ2x~D+IVJeZ zvx5;1x&kn1mF6}SWLqT&HAtQ&*R5WMNRt)io=|v7e;a}YAAT>JTTu{y1H|&nzKIoZ ziM2fQB0SB?!lrg%hoFT9@&G8;Uk@Yi$7yF4mX-=M6y(kTUGn(K(DU*k$0jiCrR0Ly zWBjFbG}Z3?mYMTU>!KvZBp|jzDiP#K$@e1^k0LmJdQVq0G&DTB?*qOs$wFTn_V&jp4&C0~?=7or zK^Dk6Y*rdMw^CEdya_zTZ*r~U(xEd#?aw;712Ga6FU|z!QexjctNVC`z2~h$-L)h6 zFA|BLzR5kWk$L`2my`YscBl$ZCrtmvNSjOC(nB6~jJiObv5<>m>MC7;s~Gc1Pmy1x zAGr55|3uCCC_TNNrIewOY3J{zkt~-k?@PW{sl)x!#7SQymQjWN$o;{YueM-(%r@&e z_X?eZA&_R5m&Gqn0)ZC74?|At?VTY{MV1oX44eMtJ%An>I?A7i$cP$2DI1z2g z^Fl2h24`FDq2}gh4%hVc@uoyO%)uA<*S{@8CXy)EKw_INRbWo`S$ zuHT&0jKYO9^^)0>#{|>cY|y)Y_7UZCu5zf+lSlTJXV1`=_jG?g6XK&Joe}NWon>-I zkPR`=n?GJkb%a7l1so0D8(?|tuoqFyXom~54f#m2&B{t>7%TkUdQX6HzTct6x0dB6 zNCg$xBiGm8D9+`!ty1=oNH2MBX)z!rtp-21q-%4fg@pXGdlijNY#Qgf!3$28lW6qD z?XTq%4d>n+`l@)v_c1mQazr563f5K6lwy)?6tC~=?Xn@$#ThTforU!$PjNV1j)HZJ zx56Ly$jORC_ws><(S8pR9u7h24g%3wef{=g^P|djX5wSco;EfOGiw5&1r-&3+v|3| z%OF{~`u3BwulLoMvAoJXIhGU9+=DH#xOd~W>Z|(iD?7`}&Rxt;cxnxeOPp(_T<0%$ zHrgVK2W;H?OfGF!(<-^5BZI#fLC8=J1`iPCJ%RquP9ycN_>P+(9<5A%S}k{<>jCz+ z^lSn7F>%T@VZsx6;il->@cB7r;P$fBFfOC#%28$n@Se3b&Uej$nJTGV67X^PW)4q> zsOsT6Xkz=6rSETGLHZ+IHx1Z~eU?z_t6iSm7Z_f3fWJex!(!SGb zQM{qx*#a(sfr@m_Zd3$V#SMe~c{M6C$|Ln9yZBn zw=X__YnsXdjmCFmaULJ^S!n_Z59{E2{-3L>g=zdZGy-aJHzUHs^98@xm}<=knBWUn zIye#n%iUQ)kTN^4V(tL(A;?6jcy*Am!H(LKA<*DVAngF)U|HNyt}FB>f(M@GALHOU zTO<9eGI}peO;GPyk&BThZkkEHiF}rA>ClZ?sdu{ODVX(bMi~!-xd3-i> z3b?PkJ<0Po7;2nL8bz?oR7as_6%*q+{tXP!dq3V*=W}(!)Mh?%-^&ZjppuiGt2CJV zs?>MeT|C~b7W8^#v~8SZFJzg?`)s}-)~%)AR#y*Bt5Z}!j@p6mpQ5q%C}J^Wa~2Zk zYDpSeuVKoLy0wg0N}g@Pt;DHZ3^f&xFMO+MSo|a92R*)H+B<2SE2u?7neM5{C7E}u zh0b;P-G-XpdD^Ly1{%G<9zNT1uEyAtEh))iRQklev#ENopC8dRx zEubJt4EIolpFelcs6toc^Ma64!4wwQbiRHdk#`i=ukN3vol0paPFCk+vw8SHhAkQ%ZZUv(WKk^ldiam?fJIzI}C?bwGGjRm3wY^ zHi!5EDias?L<~zMCmlZpT|r#Qb9HxLwDFkd^c~(cB=5NF(<+(d3O*XJ{yhU?8_&Nl znK`hLUB3n>CW7VU6o8y2lJ5c7eAN2lzx#tKC%2xt9Ba2hbZ=-u4*#((%AuXBWQr=M zv4z1%vd?yI!mIbPx5PgyA|{x}J&!#aIqNLrWq9-vHN_OQqfx%bkaC&tAeubZ8`?JS zO4Ab+EW~C}q#GgsC%6~ZrI}bZZE*zK!SC+z^3a#uX&ES05&QD#3JNTJ9Y2oIEBNnp z|6I{zFvnwWYuqL#+%8I&W;xN+_^GSLK;&GcP2eK3H!Zi(7nn&?0;X+svQ(866~Q{39kdgnxQP@91N@ zGodx?sCUl!H&NgNKNq=OeZNSc=u38|_13-V&5oNIx9M9oMU54;UTanQyZG)h{9+vX zcC{BiV~T@qHK-a(`>AP|GtE7tdI0O`XYH5b#zT-yZZPW>aNzv3w6pc|+mqgz-9EGB zV*z{hw~9ieJ4qy2+_|Exj;6J>{e=a8X~PP2)Lwl((P!^LGG|o=0-nmR6FqZG5e*sI z$;rv8neW#GYzhTG=k2W*mu9Jo#1^UccDrslTjD;%HAu~@>9De1&cPU>BaMS9V^lFI z3(QCCLaIkHU#l*7sv=U^--}ks@-TK(oRdqFy0T`3}Rq0D@uiB+)qvV2N8 z9=uhms~+SiegTsYsV1h4qi(r`1FQ@%dKUV8RcqchRW$EypKWg9wcN% z2gjsoag(RU)H>aKw2i&wY13NmR9X`%Z3~$ZY^MS2PLeP*Y>J#8RI*ePW8qCB_20UL z4ZrT}{)t9i750v^eg_3(E7;cXLqSCf#aBz zJhXtfL#dR$(Axt@W03BML@f*oiQ0T+-L~Y*cgL0=R#(sB-YOD2>!#$jwxzxlGOTSC zMg!9V$|I`~!KKi!Z zem^_QP^`~dQozQh$!k|F@4UN zCtZ^`y<4Y}HU5$CO%c3l?BRdY_z?jy<<0(f;tXOhq`$6kA&V>MolU|m*oRpT_!SdL zxXYo`LQ)=L=-%78|EbCO@9Es=c9a7}-tf;*+q_6IneOi@$FsXzo_jRu#Gd^(%FVIZ zMUH*TB3&;-+DDpLm**W7>s;$vnMs zJ3RcH^J`egd^|Q+_r9mPZ`Dfk-ExU??YR*`_SxFrfcFd9hxa>}B#LbzPqFx#nAlYQ zpQlyozj%D@wXL6;!n}JsXnQ_h(uIwF>~1D|2Ls~Q`GemUNRNsix!z~L-f5fP_+A@T zh~b}4u^bxima7VAS|>}Nw5y(T(5@Vc^(%wR$sRCiL1d4 z&3KKAo2*nx?sz6-V^!YeKe3V>M99rD_FZZEV;|~(#zW*4hEPA?74WsC@r1Ww<5=6$ zXAFe{!OHtQ554CGQJ-Ora=J(G%jd~;uMkTtLmt%=1AbSu$)I(dtUdD86!Q`8Qm*5B zjvm6P7B)?6#h*%lDl+XFWz(7%&$j4ChZdQ8SXs5$D~*1hJ+j8JS;(J|YY^XHwt9Zz zZl;fT$%a{(BKP{mKxU@GwBOk9a(3qunk-~hCM=sK9CxXyQM`tgA|(cZnGCvX`&n7l zP0cbt^;2eXmRnI%3u5?;&NMUn;*rL`zqB~KQX3go!luu@ww3*)id=jxzdOM4wV@%{ z_oh7hIA{py{4sMP=D}`nje-5xK=~b^AEn=m1sLb}SqpYx0V(Qw(U86tvrve2emivX z7)OPVEHUv~!szeUnDE8}i}SJ;>4H7RSp4PqXUm}lmES?5VI~{zKpteGoz9` z&g#H<1qDN8yF_-5f0p`j5woDDN|zk$ov@{3YvHA*H#D1?30=6bnntI~IWa}O`|?XjK}|??kV<4N@Tqem+2kz!l-nsQ zWx_BqRglLMb6+*}m8+q40|NFOb$bWK9qF{n+PTu2oJsKY#B2oj_IJ1-OjuUs56?E+ z=3DwkXA8S6bPD&}re{iOnwxXwRz|@#SDM9CpqDfFS#5u4NJ(vA?!E6?ab*V@-R9hhqWmWq~8hnfEL#GPDJ(Ql~LQtPYy#N29}z-&Vhd2jT&z@1att zm3DTw_c;7aa^$#|k5LRXx$GHJVH+1+(be^Hr6!>L;r`)r&j({$xySGS7rSke zIBA`H{zF9t&qkC%E{0$=E)!HcQtr9(b#`{?*U)F0tZJ^>wPO?j0L3+&lw-@my;@V@ zcx51TAtR%S&4Tf%R^_0X_^yoN-rEVpq82RKrMvIiFX9L&*E_H61%Hl{$^P;_b*29C zrXm|7n;v4Z?V|F1#Fz9$Ogo2)2vZYAkUrlAuT<`n>3g^(PIkWI$FmA?EFo^KZ<^X{ z%FROx5}M&nj8hcaORYKB-Yx&9?VgNvgK7htqr1QJqS|TH3HIHqaygyWxQO;=l~$#S zlpmUHFQmb!-Q|>;E7*P0Z$Gw$P5CI#*e1FrgIO=MBV=xOteEi)TDuPDHY%C-z3f5w=K%nDD!R9uR$ov75Wap!sv9cF3>2O zZtMs#QMIRez(C$TDJ<;O1T(L7U0gtQI)NGk9sH0Z!_*&WAn3nC7tCqNNVpf4^ z$j1)bfiJ#^{Z0&_HGXUyUAg}HN0n`sf0>I%HPk3}!|t#bd(QI%f}`I8^l)=-=Z3zN z%3XTlwcaRqsbwbgONK_-?uvbYwnWtm)?%S3%@!@tw@t7PW6+?+d}^gH%$;}|#;KJxq7i@W8R>QadS zan49};Z>%fDy>{@Q68FZwRp?De%|JYcf^-Bndh$vtd-sc@Ik zZy{)pBFX79aCD(VD#=X^FY3ptYa9uvsWE8B?d^?#|x$OCvm7Si!ecdJ8JAa!@|)Z#5%>0_-l97|gmG#pDgws1Q2HlY6_P ztE*Lc{!OYTTR$;&4hNRn?~@n@Xb3SQuPw30dt+o_TcY0f(5 z0yCA6ZwEHVJMZe_=sbm~$<5|mgbXvZxf$jJg9u?!8wc8{oQ{n$KY;I=MDug_)m|Q- zL66%N#Y2y$_bVm(_mpcyU%}@BQ&?^;`vB?^#LRsALi@nn8lMU(b*86XljgH}1Fo=B z>D|T~3z~unj>!_0{1+NLzQa$xeiVFk_ba>P`>~G(LgTOM?+76)OV1h^^a;fhZ?N7H z(J|CAZD@cwict>MRR8q$dd~F+*0znVV?TGMr{RAMJR@nLXHJ>DztUlBt5tzEeb9zr z(3#@$W@6oIBiX|G`&_4}1!Y@t*5$c%4DqMN3x(Q{;4hCKX%bpP-EXk{%^s?!bouH=+(!?q;cnx+#AAyrulncmFFPhFmHKgqclGwt^pQJzm@g5T>IgcMs-UZ zPG9T8j~^dY@@IaE&ERNjOl>8ZZ2s67F0mG{rN&Lp&bqEWb-)P3EuIm9R^kyoEKKPc zni3Be>|+{cPdV^2tsJA!kEWtWtDfKek*yY^K&4apv(c&Z@O-(LOA?b#<I|^yTD;_+WPqsm}|B>RvjYey59BzN!R45@v>J%dknf4h|Fbex{3LL#Pp7 z?$DWCdr_^WgGQplLN{ejqd*dSWVTI_>ce^U=mywc?aZDUCY*CF3AX$`w`X^0b7XV#$I66` zX9W~v)i2>1qO~thuau~?{_fIg#I5x=+(>9LgKz%St5@C*-TgLxZc@`Lx4QBYW$jyr zyR+`WSoYtZcfAKP36qKFq=acXwi)X^C!ZZ+meJT2ASu>4FnLu`&`h}a_WxWF3OLhQ zuyKq6z@*eTlZ?#$BXK`_&X#*iOH>_ww0cyAan?B#c^g&92@MOs86jG`Uf}p_nrN@H z$g4A3)A;a-X2JBR>JjCUsJ@L1CLtUgII9fHu?BijZ3WN-by7DOmXmjP zc9d@z3o(S2BpL9}7Gh~4Yxk>Z$xEiJ&8f6g;;ciaf5Fu9+`~yaI+Vw>n^W{Ck9irs zln_Y1`K6~@Mx*^Sjng$cSfW@KeS-hO7*-oJ&N9pgKw2Tt3GP_oUB=roa1Mdks56(> z@E>I|MN(Sg%bP|Ui-%=iLg#)ln%kdzH&2jaacQ_zwCbX>ce&x=fZ@$XCh8RXBg~9F z|6RQCKkudgV+iH{+bia@^8^tSy_od2?tytXVT7X94)LhM^Lr782o`~*sf>JorqP?%11b=%FV5J9;%E4 z9NKp>l^)RoFOTA#dh^d!Mir+Lg9i^DfPR@ha(`N<5?D@e37Oc2leDzkJ{70W^-iqx zSNiWS+JT9}KgrZwuY$!T3G$kKdLKy$`tSR#J{qi*y_HZ#R~dl#A(J*Cdn$ykHH=wQ zcY6~Kb!o!6IQ&X)p8}x-&ewN$5xF`QpPW3`@m49#nh16?c!rM-pOj@AF!|I)M0`FT zadQxxGrr^@#6;~q<6Z`g3xV|ehT*$blb5ruatj0H-lJT=S18{CwRWWK7F5O$)}1+= zITavhHT|4+MH>G?>m>zC(W0IA{cDJX9P70=enYu{pgY&a=yzDpcqj$&*gu5&KJNVC zDy|5>A1^_ATYPX<%<;)s-dDG{m%Ylt#f;0N1uInmsIagwh=q3eCyl?; zS}Nx$IF*@l^YTu=n|v^PdxuWtWpKCu z-OS$=D)2}>sAy8<5iNfLC9flh4c9eeA(a~ub6Q5xbWuVdk zv97B?sA+L8O?lT{pO}@+~E?LQEl+&dzPNNWvIAU0?;HRY9W*CQ@#!p`ps^ zH?F^{^!NY37?*;o1vloccv4cpK1ZZ zHOAcTuwD!r4KW)iv%fr`V(MV=M_Z&C3Tq?&s(w+v*+^7aST^}ref=#v#yMoBRA?HU zyx?JPAK@0zJGZVYROFxv4_%7^SaW(qIO)mFjYzVcp2>zoa{BCxyJi&L?^qK{D=NVF zDq>vGsCaswWpI^LOgHCq`0n{kKeJv7L7tjjC1qfqzw8CJ^($oT;Q`c?>4e>n#Fp_GX= z-!AsZjC%re!nYS3{I?TfD!ytfP2hQ12MT-eJk&a|M^3;_eRJBnmqj4l zy%=3+WFGGM@XZf=S9~dI;Ru)kZuT|Fjxy zUZS1ZIBRsiKvxJ(h=Hg{2<7lwooof~_Pf@P9oBFv(!1b^t?1}z-*@wL$V50i3RMZ* zxaNLQ`_!WR!ji`-HAoOTA9W({q9HY8I@VjBJ*e8r<7kB5-Vy*#IETm2yJmKQY6k8b z4*o$VhX3`W&z2_8IMS8qs%vN_%Kj2K4uR11W@INHpF!cv4gOEKhEG1W| zL+VDBKK-%??_?U4ff$*l$sgJW<^C5}8Mb2k{$&q&teTG2YtWhJ(bE6(q-sUJdBrdt zs$k}zq^aRC2rq!MMEFBHcOV!*=8GgZMDb>JSd*<8!c_1bs;CZYHwz03aCy1Os6{bE z*1oK8R2QVCCev#Nosg|Sil=p2leKvCO>;zgtNB*#}g6Pr4t3m(q*!9ga1mLdEsC!*}tF#^$TKLla9 z0PUTDNbLYqSPi6jG;86Q3rPUS;a$Hn%^BcGSbswfalcptiWWRm_Byp5-#jKLl}S*tWQkFKmWy2k;m0aT`aN; z_Ut|4`h|Y~#oqX=E1$*2q$#FimZ1?-+LstWu#6MHfdqn>VyllFKf!koTfnbh5f#j( z{r31Q>%kRj&9W5-w!*AC{Bi0Zu5iBLr>b?rc0pt$oYjMpl#|QyW$gB5aF;5@DzrjNofJJlm;lt&*b$k|(*E1Wd!qCJ-UDp56m<~##=BysZ>YVHE z3W_?jyDC>bR`G>n?*{#PMUTTjw%X2zJC>J^F}sv#WJm~vLLUK%ru*_ceMa(xC|yYBIGk4+&i%r`)(P=yU{;O5@JcUV(qc7V+}*Km!6nsZ6e* ztsESj5r7(2_Svd0M_dAxh=7t`(V-Jg-_>716}{N{KhGH6&lTL{Y^&VAY*_kPNu_e< zDvEjQNXTTYF}ZPEE!BTu#;a-@kI%ZcL8mLjEV7!)C}R$OVztdke@TuJQvJkleaqrQD7qlV?S`nx>{eEHaR)jW;aqR*+<-&)vSd&`T{^#rgy>+UV~d}*f0UTeuhqsfzc7of$e1H7#J#aLLs z)(HgjVXu_o?3vlw$-!qh+_;X;8uKHd%Wx4c-sRUcEc~qM7pb%}`f>du(npk?OS+2> zaramO=Du;sJo~a zcDEfsm&~Mq@7mJ?@>Ph}( ztd`ydv506k8`X6?*NSsZBrwl>f_|n=!thwlj|6w!`Zxv?bhcizE*7TI|%+v;sqLn`;T1_ zo}=?Bkkd0+*5jX5Ggq5OoRc#17OsUJebgSX8c4u@E{M{+K-4h2?%!Jc7a!#-ReOta zy+)_IkSi8lNcC;po^Qp-4c(7n$l2CmRW4!(p?lf+1h^I*kdWdV*)klcI3~o`|B^nC zbL(Fn?WZe)NRk2>ghkg!{!?0}&IRrEHq>Dy28L)^(3Bt>%!}}=Eo(oX?>?a;-p&}P&S`0Yi53d%YM$9QCJdd=9)4ii*M&=axAFsQ@Ll-=*MKoZ8q z;p@HT-PCJqv-M@YD6RoOAe(c`i^I#A3?Ez`M;^B`mN^|t%7%k8n{ADR7#f+>_?gsd zM+Q&QCdx+S^cWcL+g+MGc|`XFq4k%SboKp`JG!?nKnrv1cOUC)HuhmG#HNB z0>p%-zz+0oW;vzJ?x{p7K0u`I8V}l_a|A=9CyI-Uj?JwDIGKJg;Vi3* zhkPCyJ@{!|wGHM*98--A4-YvqEcgQx6QEbTu?@pZAn?*{oZ0?o=y1NMblk6_icIfC zS5y36Xl-O&sS=Ze1Ivu+3%*RCcAGx^K(xy3GKCN!7e=G`3MkWnrY?O^2f#o zeRrkw=hwaVmuK~y%*TKaWT7fi5%b?y)b9{I9?vXFMY2u5S3m{GeESFfLysgT5BARW zQW{4i!*eV*6})kccbU9Q&7JaJH}Ain8B%!pFC7LnIUH@rcKHL@{*=9>j~w*xOeuK7 z;aF=6tcYDkKX{{dpWJC2OIVY$AX*Pfbe|jE|MGLso~t+XTQ0>3SvJFJ3Z$7QL0b&G z454Xzrk?m#T|ox9%a=_ru`F!`^Sdlc?XknU);jgtF=(UYNs%ZbNfx9YVWeziipD-8 zum65UMVBuyg(3`0)JM4!Uh%daeP8hc0y-OUq&4dGtG(*ZCD^75`q7#fs>8zU^J0TT zOAO@LyWF|B=awm}f~o=VZ+9k{opqKIO;lG99eqMFFa~SA#F+C3gNoe=B_;nIkL`Y^ z1#dqMybP_*%?uLfB7O08{k)wCK)r9O-=0*AgeZR$r0I8auETj& zMLsR|U6BtcHysbSs@e!oO&1TR{0`d)TG~Onr&d~K&4t~V*QHs&c6v+JoK)Vl_xPNf z)#T+%(4G?5>48LxWD1{z0|ZP&5t_Pnui~r@P?SY$Pti)-?=027`YKxSY59v1Tahdq zIh@j?;&VY8KI+vsTi+r0-0I0a3&0W;&1b+sQNF%dSla7T6 zx0&Ld^MO^hEdfHVFWxa+O6xzoQmKw_G!d`IIH940U(~*x3;~gqI zFI{f9aQlH~fn4C}Kuu<^l(!q*CvG!uTFGzS6G&B8R7P<02KV{`ZQvswuX!P)j)R7S zZ|55|bspn+MKNU*E@CC9+V&xLg0Uf}5c|8&eHmv`LD~z#GEXA4(wL3Q*myq=I9BQ5~pXiKqTP~1Vj>!`EG^UGx`{(EhF#u&y9`$3hE=7o8of5FGSyxwYLqRxruIBMYiJrMEG`h3A2i zxfU~Ks^wh58;g%?n3C>&F{XD5Bm;W4cAp1WP^2si=ge~zO((n>p>+kM3zfX;ND_Hca zQmb>tjANjN*~bz0va@Pz-K}k(2Y)F3&k9wBAjt6*i{bERMz zx_Xs-H8S7mJ1m562c!R(nq?gN@Ou^+*`P4Z z@goPK#hw>qKwdp)Xc!JWiZttLbfT`@_odYYuMZs*WlY8VMKJ2{+4R{>Z<~8{~TGcy)B`+Du7$FFH*xL?jR;D1iu?ZHm{IyWcf-6BeFhY`S} z?0?DAynF-CX`50%wRdPJ?$R{XFD3`h7ZJ5xR7dwm&A5_r&1n|v8pz)y(*5Ri2*W3j z)h2m;(z(9thx`^pe01X>>joxeaO2d2^m|!&>)#U+1yKmcESNRppH-ZMQ#lxGFa+7e zddmi5ymeR1hYH2L9x1_Q3!^VG8{ho}${K+?Oigcafcn$30-@?X5 zhZyoPH!GSbHD{N8&s1WYuwTG;}-Vtoc;MrYE|qz^s(DRxazWKYx#&8Fkx4ZJ>cz{qf zfNxm9z+XvikiNM0=L#9$^IVBd6_-fz_-e4JtB<3@heSNay8FU!`ms%|*$8e4T}=*u9>=h`!uie78o-Tu<_?AB|9q8?P@`UNg7KuL`{=d)vPr;_^c z0=@=H3j>!6S68jN1O%Hm(yk*~4j=qtsh4G>f!{o+ytW4}yS6wZKEF`(22)4g3}T`q z+JCz^8G{F$8bNN}-)XL!Z=7%x0m5woBBjRm7WRoWCss?j5vhfGx5SNKt4XBNG!}ut z;eT8({$J2Bi>>Nmrhqq02|Ut-Nrg~6OT<9?lH|%*#dlm&5Ai7S811biG8YcyzG=vl_Rd-)vI?VLk* zFppii-`agJ2GShM04hA04h_Cj5XP#t}gIf#Q936}kf;K#7PL16b+?hL>a@3^P&sVC*qH&AEQ9)Xx{M?c^b^ z(>T8HEC@7v%~`6b#AsEq#Eyt&U%J*zb zpnzAF^fHr*;iezJJ)k_#om;7tsvi3F4QB791swJ|0Yu=OJGZl!Jlx;RD?bJVGYfEZ z77b7=0;wAYA(~4ci3#hNQkNT*)&zqKX;62BqXSi+UeGO5hvu$;hp?$ud; zB=(?{0gELmB~~k=Y|8HYBoQvTu!R|6%1783hT0z&iB^%cm0X9Sq9?YG-XBCmy5G!o zq)SpoM%VAIjB-Vd1AS}`KFff=ZsEt=5~c8h0<}c#ITzzcnuh?2u$_`fe2C4th6FK@ z_vym828H134j@#CXw_nBmUiXxZPWKXHs>zb9Aqly!0DKFP70$evtx6lijPL28SbfW z(h?L!v^YOv{#z-wnJlcHeme$u{Q(>gcgY>lobJAQCFHeMMq6S)zF;dBd)X54d%ZJe zy{FL$7*rbvX|t_ooRhT@98OHezUfL~n0N35BTGd8rPMFlVniP*sj($H8 z$>9$w6FXSp4|J;?)<{S*54JROb#?JoNL2-OvvWSwsg}j{m!*_6QG_UvTr#rkkUc1$srQB21wCf_~9BTro+SuH~2MwHQ5L#Fc=9AuT>ufTsI% z`m|PR9_+2iy?7uL0$mewuwLZXQtohHpiBF8Ad1e5s|V-W1XE2H&?&eu^QozJ7~Jsh zFEqgKkn_<`c@vg1Hx&>?Lw5>&`hk?#{8dPBpHW_s032vA>TLDy11$)md!%r4LhzBM z{F0;2Q=&?Teg6D=nfXs{o6)=Z=o~0Km3+3eS=IXRSBKQ&|JLNZz(RueyZ0~6dJrR# z;`6!;r}X{>D`npT3f0qh7U9SX`sxxf%VPh{2PYIi(aGO9H1zIDv&8=zF?^|u(dR{u zYI=To|6lsj-8ItX*$Q}17Me$vUbjsF0g9OHA=;GZQY4)KLHxn02YSSR8*~2u#RVHq zyB!^3+uoW;EiNwhHVkVg5(w=Op$pH3ZMXqK`nvpgyADX@yWD4_FHfK-nM|il%#i`62n}V_{9cQvhWqmUtJ#==Qf( z^<4|CbhjgDgZcr;2Y=_NV34h06*W;kr!a5G(~O`m`}ytLn`(L^-N}y3LkPCfQ}nl@ z-t&k0Wx`qA=guYf?YgY{btAs0Us&M^tg68@j)64tpwD0QFv3p*o@MLl`F-vJfN=U3 zqp?jN;zxolg;R}rOdUXA4NirFI+l%{mVWFNxOEioikxo6rE53hLh2fw@&A=RRv4{^kVenaQboWta!!GBHF{p`J*YikA0f z%VLnjfU-LW~P(T1B08ww8ND_p&uuD#`x61?MA*?Cd8VHvNJ2Zy198xh|D z42&=dA$ zRDsZ}&OyilYM14ak$%QT^S7qGq%X9P?+x_dJDq$rZS| zG?HxvoF%w?KngB-_$V5S#8MxjK)uhJt`4Fl*=R8UNuHZyI^S0UF_AR8`%Fg zXR-e5=2~8eWzLovD7M;s$Vpt1&oj?~fX+PABg&3)$#7iYtlir?i`%;y zu8NKkal+7OKoKkm#{r}9z!1hY(a5pgxGqY6TUdy$HJcZ93+U*6CB_ylX~@k-@J=FpW5T6tm{Q~y?6@t02Hk4!r8e6 z-N?1IC1m1bzC#E{(`|zda8Ng=Dn(v@M-vpV#^`cz0JrkP`2yR{_9uE0va%3>>Qd6T zGSO^@OdKoEUHKXaI?aFP&Sc&|g)OYVX`I_ynqhvLYsa!b`hLIK9!-gmvDP_T{TjNJ#M7*%YInqBJ{HMe3S&h3;wX;gd|_*@jB@j1{QnJ~qQP3)nVDUzH_G zxf)Q=*lF1ieW`C<=l*L+1Zmt_P&GK^Ohs;h*cjwbyu4{AkC$Ro*q@m5FRxzP~Fy^ z0VpWpVk5LoO})h=sX*njU1FBKUzNHKLg8TuO-iUG|q=$mD%i+i)O1}gmrafD%{G2(br<6=NSjrw&F2F!dvVR;9%vTynatdSuf zLH(x>BUs?LcZSk7n?&+gSql`ofVvt5y4AafX($mEgLOK_`6Zu=8O=4KqVC>}cP2GD z`QiwE{NAAayZctp)6d%`%x=}jCC7vU50vfo|@1WF8&KEopb zDovr%+UA$n|mYfdfmyS=7C(2x+;MSIU$FlVxXbW7e&b(^A^yvOGIjDpE>Y zttFwK(7Pd-*sm^l=w0s67l||wII8+#Iw)HwV}XI^ebU}?fE`%KvFq3nrE@xQCAMQ* zJR4^jYkb7dEN!u|H{-*@lQC+&Y9|6=qvA`$%kN{+`+|wPkwLT}{E`wNC+I$Ieb<;H zF(9y?Mv?gGk`xjt9NKmLx~^4*=MO~2{I%W+#Nx%e*9|b5@Y*G&NWcYPBwVARq(8a1 z1BmhA(n}yAB?%B}qCA&C3i|Q2D$l!j@VHn{6bOU(0{k9jrbr#tbV1w-{C#D9Ah?cZ z6{`g*p3Umv#`%^kKjk_QpQGt?t<*GAz1$*sDPMYF#y0B&wEmfuRVH~(d- zTreU4ztyA~NWgAWQq~3qfk7*i=t~j+;QS+h#o)VFr8EqXz_8zyr}T;K(Os#(+W!A2 zHc~7m)Aerk2*r{V1Zr%N3}N}m7k*m-maF4)y*(q(0U+zJO^}V))iF*e3JqSaH}i06 z&GF8XL{yO;uLh=oM>ugzysYDCFl6t@v4hGJI+IGU*MOE-an!k_e880(N_`?4YV?wd zU#f}GynpfA_3S{sTX4t}57-23zquJt#$T1Q8<)vxmywi^I1rCUYg^TgwZ(WJe$16Y zh^wD9JU?~8fg}{WrpfpG0I>Z&E_wtZW7D!8XaqBaTr7mq2lUUG+w_4!8D@=|g7tb? z4!;{Zn)>K&IQ(hXIg_E|iFmXD>O~{6u4WeCa+s8jplb3(+7Qbj7U>_*eA6m4w@CQn zRxs&l<#tkMp*_T7rCgHya+SG3b!>a}*Z{6QukC}cNp)gkZ!gUFZHwX0H#QcE*X4cA zA`bZ8tIeAkA7D8nJup2GK$yoqcDT+>9I-#3Gq|2 zv!kzW*@+^bQ6q*s7?AbN4=>BF9 zuy<8w-ed5iuIr^tj^e;QEolBr2pM*F6{=oWIXJ?w;-I2EKJ2*pGg|P#CtJ0D_{NQA WKGi!K-+XT literal 0 HcmV?d00001 diff --git a/doc/ospf_api_msgs2.png b/doc/ospf_api_msgs2.png new file mode 100644 index 0000000000000000000000000000000000000000..8997ac4010c83bda5949a01089d02cdb4fdbdd1c GIT binary patch literal 35544 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%0D($Q#+0il3jdIhb8sGCasvhdZXL8vZi=Moj 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

sgat5R{w#wU>q-Fu^O!d=J#GtVCpB1 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 U_u%p<4*XJ(Rh210JbLy&0M=04+5i9m literal 0 HcmV?d00001 -- 2.39.5