diff options
-rw-r--r-- | src/vlib/unix/plugin.c | 110 | ||||
-rw-r--r-- | src/vlib/unix/plugin.h | 27 |
2 files changed, 128 insertions, 9 deletions
diff --git a/src/vlib/unix/plugin.c b/src/vlib/unix/plugin.c index 0837ecdb13e..a714c7c29ce 100644 --- a/src/vlib/unix/plugin.c +++ b/src/vlib/unix/plugin.c @@ -81,22 +81,120 @@ extract (u8 * sp, u8 * ep) return rv; } +/* + * If a plugin .so contains a ".vlib_plugin_r2" section, + * this function converts the vlib_plugin_r2_t to + * a vlib_plugin_registration_t. + */ + +static clib_error_t * +r2_to_reg (elf_main_t * em, vlib_plugin_r2_t * r2, + vlib_plugin_registration_t * reg) +{ + clib_error_t *error; + elf_section_t *section; + uword data_segment_offset; + u8 *data; + + /* It turns out that the strings land in the ".data" section */ + error = elf_get_section_by_name (em, ".data", §ion); + if (error) + return error; + data = elf_get_section_contents (em, section->index, 1); + + /* + * Offsets in the ".vlib_plugin_r2" section + * need to have the data section base subtracted from them. + * The offset is in the first 8 bytes of the ".data" section + */ + + data_segment_offset = *((uword *) data); + + /* Relocate pointers, subtract data_segment_offset */ +#define _(a) r2->a.data_segment_offset -= data_segment_offset; + foreach_r2_string_field; +#undef _ + + if (r2->version.length >= ARRAY_LEN (reg->version) - 1) + return clib_error_return (0, "Version string too long"); + + if (r2->version_required.length >= ARRAY_LEN (reg->version_required) - 1) + return clib_error_return (0, "Version-required string too long"); + + if (r2->overrides.length >= ARRAY_LEN (reg->overrides) - 1) + return clib_error_return (0, "Override string too long"); + + /* Compatibility with C-initializer */ + memcpy ((void *) reg->version, data + r2->version.data_segment_offset, + r2->version.length); + memcpy ((void *) reg->version_required, + data + r2->version_required.data_segment_offset, + r2->version_required.length); + memcpy ((void *) reg->overrides, data + r2->overrides.data_segment_offset, + r2->overrides.length); + + if (r2->early_init.length > 0) + { + u8 *ei = 0; + vec_validate (ei, r2->early_init.length + 1); + memcpy (ei, data + r2->early_init.data_segment_offset, + r2->early_init.length); + reg->early_init = (void *) ei; + } + + if (r2->description.length > 0) + { + u8 *desc = 0; + vec_validate (desc, r2->description.length + 1); + memcpy (desc, data + r2->description.data_segment_offset, + r2->description.length); + reg->description = (void *) desc; + } + vec_free (data); + return 0; +} + + static int load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init) { void *handle; + int reread_reg = 1; clib_error_t *error; elf_main_t em = { 0 }; elf_section_t *section; u8 *data; char *version_required; vlib_plugin_registration_t *reg; + vlib_plugin_r2_t *r2; plugin_config_t *pc = 0; uword *p; if (elf_read_file (&em, (char *) pi->filename)) return -1; + /* New / improved (well, not really) registration structure? */ + error = elf_get_section_by_name (&em, ".vlib_plugin_r2", §ion); + if (error == 0) + { + data = elf_get_section_contents (&em, section->index, 1); + r2 = (vlib_plugin_r2_t *) data; + reg = clib_mem_alloc (sizeof (*reg)); + memset (reg, 0, sizeof (*reg)); + + reg->default_disabled = r2->default_disabled != 0; + error = r2_to_reg (&em, r2, reg); + if (error) + { + PLUGIN_LOG_ERR ("Bad r2 registration: %s\n", (char *) pi->name); + return -1; + } + if (pm->plugins_default_disable) + reg->default_disabled = 1; + reread_reg = 0; + goto process_reg; + } + error = elf_get_section_by_name (&em, ".vlib_plugin_registration", §ion); if (error) @@ -118,6 +216,7 @@ load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init) if (pm->plugins_default_disable) reg->default_disabled = 1; +process_reg: p = hash_get_mem (pm->config_index_by_name, pi->name); if (p) { @@ -216,15 +315,8 @@ load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init) pi->handle = handle; - reg = dlsym (pi->handle, "vlib_plugin_registration"); - - if (reg == 0) - { - /* This should never happen unless somebody changes registration macro */ - PLUGIN_LOG_ERR ("Missing plugin registration in plugin '%s'", pi->name); - dlclose (pi->handle); - goto error; - } + if (reread_reg) + reg = dlsym (pi->handle, "vlib_plugin_registration"); pi->reg = reg; pi->version = str_array_to_vec ((char *) ®->version, diff --git a/src/vlib/unix/plugin.h b/src/vlib/unix/plugin.h index c9a33ccd96a..4beae43d504 100644 --- a/src/vlib/unix/plugin.h +++ b/src/vlib/unix/plugin.h @@ -67,6 +67,33 @@ typedef CLIB_PACKED(struct { }) vlib_plugin_registration_t; /* *INDENT-ON* */ +/* + * Plugins may also use this registration format, which is + * easy enough to emit from e.g. a golang compiler. + */ +typedef struct +{ + uword data_segment_offset; + uword length; +} vlib_r2_string_t; + +typedef struct +{ + int default_disabled; + vlib_r2_string_t version; + vlib_r2_string_t version_required; + vlib_r2_string_t overrides; + vlib_r2_string_t early_init; + vlib_r2_string_t description; +} vlib_plugin_r2_t; + +#define foreach_r2_string_field \ +_(version) \ +_(version_required) \ +_(overrides) \ +_(early_init) \ +_(description) + typedef struct { u8 *name; |