]>
Commit | Line | Data |
---|---|---|
bf9735b2 DS |
1 | .. _modules: |
2 | ||
b30de709 QY |
3 | Modules |
4 | ======= | |
d1890d04 | 5 | |
b30de709 QY |
6 | FRR has facilities to load DSOs at startup via ``dlopen()``. These are used to |
7 | implement modules, such as SNMP and FPM. | |
d1890d04 QY |
8 | |
9 | Limitations | |
10 | ----------- | |
11 | ||
12 | - can't load, unload, or reload during runtime. This just needs some | |
13 | work and can probably be done in the future. | |
14 | - doesn't fix any of the "things need to be changed in the code in the | |
15 | library" issues. Most prominently, you can't add a CLI node because | |
16 | CLI nodes are listed in the library... | |
17 | - if your module crashes, the daemon crashes. Should be obvious. | |
18 | - **does not provide a stable API or ABI**. Your module must match a | |
19 | version of FRR and you may have to update it frequently to match | |
20 | changes. | |
21 | - **does not create a license boundary**. Your module will need to link | |
22 | libzebra and include header files from the daemons, meaning it will | |
23 | be GPL-encumbered. | |
24 | ||
25 | Installation | |
26 | ------------ | |
27 | ||
28 | Look for ``moduledir`` in ``configure.ac``, default is normally | |
29 | ``/usr/lib64/frr/modules`` but depends on ``--libdir`` / ``--prefix``. | |
30 | ||
31 | The daemon's name is prepended when looking for a module, e.g. "snmp" | |
32 | tries to find "zebra\_snmp" first when used in zebra. This is just to | |
33 | make it nicer for the user, with the snmp module having the same name | |
34 | everywhere. | |
35 | ||
36 | Modules can be packaged separately from FRR. The SNMP and FPM modules | |
37 | are good candidates for this because they have dependencies (net-snmp / | |
38 | protobuf) that are not FRR dependencies. However, any distro packages | |
39 | should have an "exact-match" dependency onto the FRR package. Using a | |
40 | module from a different FRR version will probably blow up nicely. | |
41 | ||
42 | For snapcraft (and during development), modules can be loaded with full | |
43 | path (e.g. -M ``$SNAP/lib/frr/modules/zebra_snmp.so``). Note that | |
44 | libtool puts output files in the .libs directory, so during development | |
45 | you have to use ``./zebra -M .libs/zebra_snmp.so``. | |
46 | ||
47 | Creating a module | |
48 | ----------------- | |
49 | ||
50 | ... best to look at the existing SNMP or FPM modules. | |
51 | ||
52 | Basic boilerplate: | |
53 | ||
54 | :: | |
55 | ||
56 | #include "hook.h" | |
57 | #include "module.h" | |
2a7d9471 | 58 | #include "libfrr.h" |
24a58196 | 59 | #include "frrevent.h" |
2a7d9471 | 60 | |
cd9d0537 | 61 | static int module_late_init(struct event_loop *master) |
2a7d9471 DS |
62 | { |
63 | /* Do initialization stuff here */ | |
a2bd5d4c | 64 | return 0; |
2a7d9471 | 65 | } |
d1890d04 QY |
66 | |
67 | static int | |
68 | module_init (void) | |
69 | { | |
70 | hook_register(frr_late_init, module_late_init); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | FRR_MODULE_SETUP( | |
75 | .name = "my module", | |
76 | .version = "0.0", | |
77 | .description = "my module", | |
78 | .init = module_init, | |
80413c20 | 79 | ); |
d1890d04 QY |
80 | |
81 | The ``frr_late_init`` hook will be called after the daemon has finished | |
82 | its other startup and is about to enter the main event loop; this is the | |
83 | best place for most initialisation. | |
84 | ||
85 | Compiler & Linker magic | |
86 | ----------------------- | |
87 | ||
88 | There's a ``THIS_MODULE`` (like in the Linux kernel), which uses | |
89 | ``visibility`` attributes to restrict it to the current module. If you | |
90 | get a linker error with ``_frrmod_this_module``, there is some linker | |
91 | SNAFU. This shouldn't be possible, though one way to get it would be to | |
92 | not include libzebra (which provides a fallback definition for the | |
93 | symbol). | |
94 | ||
95 | libzebra and the daemons each have their own ``THIS_MODULE``, as do all | |
96 | loadable modules. In any other libraries (e.g. ``libfrrsnmp``), | |
97 | ``THIS_MODULE`` will use the definition in libzebra; same applies if the | |
98 | main executable doesn't use ``FRR_DAEMON_INFO`` (e.g. all testcases). | |
99 | ||
100 | The deciding factor here is "what dynamic linker unit are you using the | |
101 | symbol from." If you're in a library function and want to know who | |
102 | called you, you can't use ``THIS_MODULE`` (because that'll just tell you | |
103 | you're in the library). Put a macro around your function that adds | |
104 | ``THIS_MODULE`` in the *caller's code calling your function*. | |
105 | ||
106 | The idea is to use this in the future for module unloading. Hooks | |
107 | already remember which module they were installed by, as groundwork for | |
108 | a function that removes all of a module's installed hooks. | |
109 | ||
110 | There's also the ``frr_module`` symbol in modules, pretty much a | |
111 | standard entry point for loadable modules. | |
112 | ||
9e2f406a EDP |
113 | Command line parameters |
114 | ----------------------- | |
115 | ||
4c97fd1a QY |
116 | Command line parameters can be passed directly to a module by appending a |
117 | colon to the module name when loading it, e.g. ``-M mymodule:myparameter``. | |
118 | The text after the colon will be accessible in the module's code through | |
9e2f406a EDP |
119 | ``THIS_MODULE->load_args``. For example, see how the format parameter is |
120 | configured in the ``zfpm_init()`` function inside ``zebra_fpm.c``. | |
121 | ||
d1890d04 QY |
122 | Hooks |
123 | ----- | |
124 | ||
125 | Hooks are just points in the code where you can register your callback | |
126 | to be called. The parameter list is specific to the hook point. Since | |
127 | there is no stable API, the hook code has some extra type safety checks | |
128 | making sure you get a compiler warning when the hook parameter list | |
129 | doesn't match your callback. Don't ignore these warnings. | |
130 | ||
131 | Relation to MTYPE macros | |
132 | ------------------------ | |
133 | ||
134 | The MTYPE macros, while primarily designed to decouple MTYPEs from the | |
135 | library and beautify the code, also work very nicely with loadable | |
136 | modules -- both constructors and destructors are executed when | |
137 | loading/unloading modules. | |
138 | ||
139 | This means there is absolutely no change required to MTYPEs, you can | |
140 | just use them in a module and they will even clean up themselves when we | |
141 | implement module unloading and an unload happens. In fact, it's | |
142 | impossible to create a bug where unloading fails to de-register a MTYPE. |