{ "lxc.namespace.share", true, set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
{ "lxc.time.offset.boot", true, set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, },
{ "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, },
- { "lxc.net.flags", true, set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
- { "lxc.net.hwaddr", true, set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
- { "lxc.net.ipv4.address", true, set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
- { "lxc.net.ipv4.gateway", true, set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
- { "lxc.net.ipv6.address", true, set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
- { "lxc.net.ipv6.gateway", true, set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
- { "lxc.net.link", true, set_config_net_link, get_config_net_link, clr_config_net_link, },
- { "lxc.net.l2proxy", true, set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
- { "lxc.net.macvlan.mode", true, set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
- { "lxc.net.ipvlan.mode", true, set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
- { "lxc.net.ipvlan.isolation", true, set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
- { "lxc.net.mtu", true, set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
- { "lxc.net.name", true, set_config_net_name, get_config_net_name, clr_config_net_name, },
- { "lxc.net.script.down", true, set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
- { "lxc.net.script.up", true, set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
- { "lxc.net.type", true, set_config_net_type, get_config_net_type, clr_config_net_type, },
- { "lxc.net.vlan.id", true, set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
- { "lxc.net.veth.mode", true, set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
- { "lxc.net.veth.pair", true, set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
- { "lxc.net.veth.ipv4.route", true, set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
- { "lxc.net.veth.ipv6.route", true, set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
- { "lxc.net.veth.vlan.id", true, set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
- { "lxc.net.veth.vlan.tagged.id", true, set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
{ "lxc.net.", false, set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
{ "lxc.net", true, set_config_net, get_config_net, clr_config_net, },
{ "lxc.no_new_privs", true, set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
{ "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
};
-static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t);
+static struct lxc_config_t config_jump_table_net[] = {
+ /* If a longer key is added please update. */
+ #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2)
+ { "flags", true, set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
+ { "hwaddr", true, set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
+ { "ipv4.address", true, set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
+ { "ipv4.gateway", true, set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
+ { "ipv6.address", true, set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
+ { "ipv6.gateway", true, set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
+ { "link", true, set_config_net_link, get_config_net_link, clr_config_net_link, },
+ { "l2proxy", true, set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
+ { "macvlan.mode", true, set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
+ { "ipvlan.mode", true, set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
+ { "ipvlan.isolation", true, set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
+ { "mtu", true, set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
+ { "name", true, set_config_net_name, get_config_net_name, clr_config_net_name, },
+ { "script.down", true, set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
+ { "script.up", true, set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
+ { "type", true, set_config_net_type, get_config_net_type, clr_config_net_type, },
+ { "vlan.id", true, set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
+ { "veth.mode", true, set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
+ { "veth.pair", true, set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
+ { "veth.ipv4.route", true, set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
+ { "veth.ipv6.route", true, set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
+ { "veth.vlan.id", true, set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
+ { "veth.vlan.tagged.id", true, set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
+};
struct lxc_config_t *lxc_get_config_exact(const char *key)
{
size_t i;
- for (i = 0; i < config_jump_table_size; i++)
+ for (i = 0; i < ARRAY_SIZE(config_jump_table); i++)
if (strequal(config_jump_table[i].name, key))
return &config_jump_table[i];
return NULL;
}
+static inline bool match_config_item(const struct lxc_config_t *entry,
+ const char *key)
+{
+ if (entry->strict)
+ return strequal(entry->name, key);
+ return strnequal(entry->name, key, strlen(entry->name));
+}
struct lxc_config_t *lxc_get_config(const char *key)
{
- size_t i;
-
- for (i = 0; i < config_jump_table_size; i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
struct lxc_config_t *cur = &config_jump_table[i];
- bool match;
- if (cur->strict)
- match = strequal(cur->name, key);
- else
- match = strnequal(config_jump_table[i].name, key,
- strlen(config_jump_table[i].name));
- if (!match)
+ if (!match_config_item(cur, key))
+ continue;
+
+ return cur;
+ }
+
+ return NULL;
+}
+
+static struct lxc_config_t *lxc_get_config_net(const char *key)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(config_jump_table_net); i++) {
+ struct lxc_config_t *cur = &config_jump_table_net[i];
+
+ if (!match_config_item(cur, key))
continue;
return cur;
static struct lxc_config_t *get_network_config_ops(const char *key,
struct lxc_conf *lxc_conf,
ssize_t *idx,
- char **deindexed_key)
+ const char **const subkey)
{
- __do_free char *copy = NULL;
struct lxc_config_t *config = NULL;
int ret;
- unsigned int tmpidx;
- size_t numstrlen;
- char *idx_start, *idx_end;
+ int64_t tmpidx;
+ const char *idx_start, *subkey_start;
+ char buf[NETWORK_SUBKEY_SIZE_MAX];
+
+ if (!idx)
+ return ret_set_errno(NULL, EINVAL);
+
+ if (is_empty_string(key))
+ return ret_set_errno(NULL, EINVAL);
/* check that this is a sensible network key */
if (!strnequal("lxc.net.", key, STRLITERALLEN("lxc.net.")))
return log_error_errno(NULL, EINVAL, "Invalid network configuration key \"%s\"", key);
- copy = strdup(key);
- if (!copy)
- return log_error_errno(NULL, ENOMEM, "Failed to duplicate string \"%s\"", key);
-
/* lxc.net.<n> */
- if (!isdigit(*(key + STRLITERALLEN("lxc.net."))))
+ /* beginning of index string */
+ idx_start = key + STRLITERALLEN("lxc.net.");
+ if (!isdigit(*idx_start))
return log_error_errno(NULL, EINVAL, "Failed to detect digit in string \"%s\"", key + 8);
- /* beginning of index string */
- idx_start = copy + (STRLITERALLEN("lxc.net.") - 1);
- *idx_start = '\0';
-
- /* end of index string */
- idx_end = strchr((copy + STRLITERALLEN("lxc.net.")), '.');
- if (idx_end)
- *idx_end = '\0';
-
- /* parse current index */
- ret = lxc_safe_uint((idx_start + 1), &tmpidx);
- if (ret < 0) {
- *idx = ret;
- return log_error_errno(NULL, -ret, "Failed to parse unsigned integer from string \"%s\"", idx_start + 1);
- }
+ ret = lxc_safe_int64_residual(idx_start, &tmpidx, 10, buf, sizeof(buf));
+ if (ret)
+ return log_error_errno(NULL, -ret, "Failed to parse network index");
- /* This, of course is utterly nonsensical on so many levels, but
- * better safe than sorry.
- * (Checking for INT_MAX here is intentional.)
- */
- if (tmpidx >= INT_MAX)
+ if (tmpidx < 0 || tmpidx >= INT_MAX)
return log_error_errno(NULL, ERANGE, "Number of configured networks would overflow the counter");
- *idx = tmpidx;
+ *idx = (ssize_t)tmpidx;
- numstrlen = strlen((idx_start + 1));
+ if (!subkey)
+ return NULL;
- /* repair configuration key */
- *idx_start = '.';
+ subkey_start = &buf[1];
+ if (is_empty_string(subkey_start))
+ return log_error_errno(NULL, EINVAL, "No network subkey specified");
/* lxc.net.<idx>.<subkey> */
- if (idx_end) {
- *idx_end = '.';
- if (strlen(idx_end + 1) == 0)
- return log_error_errno(NULL, EINVAL, "No subkey in network configuration key \"%s\"", key);
- if (isdigit(*(idx_end + 1)))
- return log_error_errno(NULL, EINVAL, "Key can't contain more than one index");
-
- memmove(copy + STRLITERALLEN("lxc.net."), idx_end + 1, strlen(idx_end + 1));
- copy[strlen(key) - (numstrlen + 1)] = '\0';
-
- config = lxc_get_config(copy);
- if (!config)
- return log_error_errno(NULL, ENOENT, "Unknown network configuration key \"%s\"", key);
- }
-
- if (deindexed_key)
- *deindexed_key = move_ptr(copy);
+ *subkey = subkey_start;
+ config = lxc_get_config_net(*subkey);
+ if (!config)
+ return log_error_errno(NULL, ENOENT, "Unknown network configuration key \"%s\"", key);
return config;
}
static int set_config_net_nic(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
- __do_free char *deindexed_key = NULL;
+ const char *subkey = NULL;
ssize_t idx = -1;
const char *idxstring;
struct lxc_config_t *config;
struct lxc_netdev *netdev;
- idxstring = key + 8;
+ idxstring = key + STRLITERALLEN("lxc.net.");
if (!isdigit(*idxstring))
return ret_errno(EINVAL);
if (lxc_config_value_empty(value))
return clr_config_net_nic(key, lxc_conf, data);
- config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
+ config = get_network_config_ops(key, lxc_conf, &idx, &subkey);
if (!config || idx < 0)
return -errno;
if (!netdev)
return ret_errno(EINVAL);
- return config->set(deindexed_key, value, lxc_conf, netdev);
+ return config->set(subkey, value, lxc_conf, netdev);
}
static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
void *data)
{
- __do_free char *deindexed_key = NULL;
+ const char *subkey = NULL;
ssize_t idx = -1;
int ret;
const char *idxstring;
return 0;
}
- config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
+ config = get_network_config_ops(key, lxc_conf, &idx, &subkey);
if (!config || idx < 0)
return -errno;
if (!netdev)
return ret_errno(EINVAL);
- return config->clr(deindexed_key, lxc_conf, netdev);
+ return config->clr(subkey, lxc_conf, netdev);
}
static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
static int get_config_net_nic(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
- __do_free char *deindexed_key = NULL;
+ const char *subkey = NULL;
ssize_t idx = -1;
const char *idxstring;
struct lxc_config_t *config;
struct lxc_netdev *netdev;
- idxstring = key + 8;
+ idxstring = key + STRLITERALLEN("lxc.net.");
if (!isdigit(*idxstring))
return ret_errno(EINVAL);
- config = get_network_config_ops(key, c, &idx, &deindexed_key);
+ config = get_network_config_ops(key, c, &idx, &subkey);
if (!config || idx < 0)
return -errno;
if (!netdev)
return ret_errno(EINVAL);
- return config->get(deindexed_key, retv, inlen, c, netdev);
+ return config->get(subkey, retv, inlen, c, netdev);
}
static int get_config_net_type(const char *key, char *retv, int inlen,
else
memset(retv, 0, inlen);
- for (i = 0; i < config_jump_table_size; i++) {
+ for (i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
char *s = config_jump_table[i].name;
if (s[strlen(s) - 1] == '.')
int fulllen = 0;
ssize_t idx = -1;
- idxstring = key + 8;
+ idxstring = key + STRLITERALLEN("lxc.net.");
if (!isdigit(*idxstring))
- return -1;
+ return ret_errno(EINVAL);
(void)get_network_config_ops(key, c, &idx, NULL);
if (idx < 0)