summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vlib/unix/plugin.c110
-rw-r--r--src/vlib/unix/plugin.h27
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", &section);
+ 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", &section);
+ 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",
&section);
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 *) &reg->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;