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