mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-07 19:30:37 +01:00
initrd: merge branch 'th/initrd-parse-ip-method'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/939
This commit is contained in:
commit
db41f2afad
5 changed files with 236 additions and 38 deletions
|
|
@ -2336,13 +2336,83 @@ nm_strv_has_duplicate(const char *const *strv, gssize len, gboolean is_sorted)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_strv_is_same_unordered(const char *const *strv1,
|
||||
gssize len1,
|
||||
const char *const *strv2,
|
||||
gssize len2)
|
||||
{
|
||||
gs_free const char **ss1_free = NULL;
|
||||
gs_free const char **ss2_free = NULL;
|
||||
gsize l2;
|
||||
gsize l;
|
||||
gsize i;
|
||||
|
||||
if (len1 < 0)
|
||||
l = NM_PTRARRAY_LEN(strv1);
|
||||
else
|
||||
l = (gsize) len1;
|
||||
|
||||
if (len2 < 0)
|
||||
l2 = NM_PTRARRAY_LEN(strv2);
|
||||
else
|
||||
l2 = (gsize) len2;
|
||||
|
||||
if (l != l2)
|
||||
return FALSE;
|
||||
|
||||
if (l == 0) {
|
||||
/* An empty array. We treat (NULL, -1), (NULL, 0) and ([...], 0)
|
||||
* all the same. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (l > 1) {
|
||||
strv1 = nm_memdup_maybe_a(300, strv1, sizeof(char *) * l, &ss1_free);
|
||||
strv2 = nm_memdup_maybe_a(300, strv2, sizeof(char *) * l2, &ss2_free);
|
||||
_nm_utils_strv_sort((const char **) strv1, l);
|
||||
_nm_utils_strv_sort((const char **) strv2, l);
|
||||
}
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
if (!nm_streq0(strv1[i], strv2[i]))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char **
|
||||
_nm_utils_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated)
|
||||
{
|
||||
gsize i;
|
||||
gsize j;
|
||||
|
||||
if (!strv || !*strv)
|
||||
return strv;
|
||||
|
||||
if (!skip_empty && !skip_repeated)
|
||||
return strv;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; strv[i]; i++) {
|
||||
if ((skip_empty && !*strv[i])
|
||||
|| (skip_repeated && nm_utils_strv_find_first((char **) strv, j, strv[i]) >= 0))
|
||||
continue;
|
||||
strv[j++] = strv[i];
|
||||
}
|
||||
strv[j] = NULL;
|
||||
return strv;
|
||||
}
|
||||
|
||||
char **
|
||||
_nm_utils_strv_cleanup(char ** strv,
|
||||
gboolean strip_whitespace,
|
||||
gboolean skip_empty,
|
||||
gboolean skip_repeated)
|
||||
{
|
||||
guint i, j;
|
||||
gsize i;
|
||||
gsize j;
|
||||
|
||||
if (!strv || !*strv)
|
||||
return strv;
|
||||
|
|
|
|||
|
|
@ -741,11 +741,19 @@ gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle);
|
|||
|
||||
gboolean nm_strv_has_duplicate(const char *const *list, gssize len, gboolean is_sorted);
|
||||
|
||||
const char **
|
||||
_nm_utils_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated);
|
||||
|
||||
char **_nm_utils_strv_cleanup(char ** strv,
|
||||
gboolean strip_whitespace,
|
||||
gboolean skip_empty,
|
||||
gboolean skip_repeated);
|
||||
|
||||
gboolean nm_strv_is_same_unordered(const char *const *strv1,
|
||||
gssize len1,
|
||||
const char *const *strv2,
|
||||
gssize len2);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline gpointer
|
||||
|
|
|
|||
|
|
@ -316,22 +316,28 @@ nm_mult_clamped_u(unsigned a, unsigned b)
|
|||
/* macro to return strlen() of a compile time string. */
|
||||
#define NM_STRLEN(str) (sizeof("" str "") - 1u)
|
||||
|
||||
static inline size_t
|
||||
_nm_ptrarray_len_impl(const void *const *array)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if (array) {
|
||||
while (array[n])
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* returns the length of a NULL terminated array of pointers,
|
||||
* like g_strv_length() does. The difference is:
|
||||
* - it operates on arrays of pointers (of any kind, requiring no cast).
|
||||
* - it accepts NULL to return zero. */
|
||||
#define NM_PTRARRAY_LEN(array) \
|
||||
({ \
|
||||
typeof(*(array)) *const _array = (array); \
|
||||
size_t _n = 0; \
|
||||
\
|
||||
if (_array) { \
|
||||
_nm_unused const void *_type_check_is_pointer = _array[0]; \
|
||||
\
|
||||
while (_array[_n]) \
|
||||
_n++; \
|
||||
} \
|
||||
_n; \
|
||||
#define NM_PTRARRAY_LEN(array) \
|
||||
({ \
|
||||
typeof(*(array)) *const _array = (array); \
|
||||
_nm_unused const void * _type_check_is_pointer = 0 ? _array[0] : NULL; \
|
||||
\
|
||||
_nm_ptrarray_len_impl((const void *const *) _array); \
|
||||
})
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -394,6 +394,120 @@ reader_read_all_connections_from_fw(Reader *reader, const char *sysfs_dir)
|
|||
reader_add_connection(reader, "ofw", dt_connection);
|
||||
}
|
||||
|
||||
#define _strv_is_same_unordered(strv, ...) \
|
||||
nm_strv_is_same_unordered(NM_CAST_STRV_CC(strv), -1, NM_MAKE_STRV(__VA_ARGS__), -1)
|
||||
|
||||
static void
|
||||
_strv_remove(const char **strv, const char *needle)
|
||||
{
|
||||
gssize idx;
|
||||
gsize len;
|
||||
gsize i;
|
||||
|
||||
idx = nm_utils_strv_find_first((char **) strv, -1, needle);
|
||||
if (idx < 0)
|
||||
return;
|
||||
|
||||
/* Remove element at idx, by shifting the remaining ones
|
||||
* (including the terminating NULL). */
|
||||
len = NM_PTRARRAY_LEN(strv);
|
||||
for (i = idx; i < len; i++)
|
||||
strv[i] = strv[i + 1];
|
||||
}
|
||||
|
||||
static const char *
|
||||
_parse_ip_method(const char *kind)
|
||||
{
|
||||
const char *const KINDS[] = {
|
||||
"none",
|
||||
"dhcp",
|
||||
"dhcp6",
|
||||
"link6",
|
||||
"auto",
|
||||
"ibft",
|
||||
};
|
||||
gs_free char * kind_to_free = NULL;
|
||||
gs_free const char **strv = NULL;
|
||||
gsize i;
|
||||
|
||||
kind = nm_strstrip_avoid_copy_a(300, kind, &kind_to_free);
|
||||
|
||||
if (nm_str_is_empty(kind)) {
|
||||
/* Dracut defaults empty/missing to "dhcp". We treat them differently, as it
|
||||
* depends on whether we have IP addresses too.
|
||||
* https://github.com/dracutdevs/dracut/blob/3cc9f1c10c67dcdb5254e0eb69f19e9ab22abf20/modules.d/35network-legacy/parse-ip-opts.sh#L62 */
|
||||
return "auto";
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(KINDS); i++) {
|
||||
if (nm_streq(kind, KINDS[i]))
|
||||
return KINDS[i];
|
||||
}
|
||||
|
||||
/* the following are (currently) treated as aliases. */
|
||||
if (nm_streq(kind, "fw"))
|
||||
return "ibft";
|
||||
if (nm_streq(kind, "single-dhcp"))
|
||||
return "dhcp";
|
||||
if (nm_streq(kind, "off"))
|
||||
return "none";
|
||||
if (nm_streq(kind, "auto6"))
|
||||
return "dhcp6";
|
||||
if (NM_IN_STRSET(kind, "on", "any"))
|
||||
return "auto";
|
||||
|
||||
if (!strchr(kind, ','))
|
||||
return NULL;
|
||||
|
||||
/* dracut also supports combinations, separated by comma. We don't
|
||||
* support arbitrary combinations, but accept specific subsets. */
|
||||
strv = nm_utils_strsplit_set_full(kind, ",", NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
|
||||
if (!strv)
|
||||
return NULL;
|
||||
|
||||
/* first normalize the strv array by replacing all entries by their
|
||||
* normalized kind. */
|
||||
for (i = 0; strv[i]; i++) {
|
||||
strv[i] = _parse_ip_method(strv[i]);
|
||||
if (!strv[i]) {
|
||||
/* Unknown key. Not recognized. */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort list and remove duplicates. */
|
||||
nm_utils_strv_sort(strv, -1);
|
||||
_nm_utils_strv_cleanup_const(strv, TRUE, TRUE);
|
||||
|
||||
if (nm_utils_strv_find_first((char **) strv, -1, "auto") >= 0) {
|
||||
/* if "auto" is present, then "dhcp4", "dhcp6", and "local6" is implied. */
|
||||
_strv_remove(strv, "dhcp4");
|
||||
_strv_remove(strv, "dhcp6");
|
||||
_strv_remove(strv, "local6");
|
||||
} else if (nm_utils_strv_find_first((char **) strv, -1, "dhcp6") >= 0) {
|
||||
/* if "dhcp6" is present, then "local6" is implied. */
|
||||
_strv_remove(strv, "local6");
|
||||
}
|
||||
|
||||
if (strv[0] && !strv[1]) {
|
||||
/* there is only one value left. It's good. */
|
||||
return strv[0];
|
||||
}
|
||||
|
||||
/* only certain combinations are allowed... those are listed
|
||||
* and mapped to a canonical value.
|
||||
*
|
||||
* For the moment, these map all to "auto". This might be revisited
|
||||
* in the future to add new kinds like "dhcp+local6". */
|
||||
if (_strv_is_same_unordered(strv, "dhcp", "dhcp6"))
|
||||
return "auto";
|
||||
if (_strv_is_same_unordered(strv, "dhcp", "local6"))
|
||||
return "auto";
|
||||
|
||||
/* undetected. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
||||
{
|
||||
|
|
@ -403,7 +517,8 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
gs_unref_hashtable GHashTable *ibft = NULL;
|
||||
const char * tmp;
|
||||
const char * tmp2;
|
||||
const char * kind = NULL;
|
||||
const char * tmp3;
|
||||
const char * kind;
|
||||
const char * client_ip = NULL;
|
||||
const char * peer = NULL;
|
||||
const char * gateway_ip = NULL;
|
||||
|
|
@ -432,24 +547,17 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
tmp = get_word(&argument, ':');
|
||||
if (!*argument) {
|
||||
/* ip={dhcp|on|any|dhcp6|auto6|link6|ibft} */
|
||||
kind = tmp;
|
||||
kind = _parse_ip_method(tmp);
|
||||
if (!kind) {
|
||||
/* invalid method. We treat it as "auto". */
|
||||
kind = "auto";
|
||||
}
|
||||
} else {
|
||||
tmp2 = get_word(&argument, ':');
|
||||
if (NM_IN_STRSET(tmp2,
|
||||
"none",
|
||||
"off",
|
||||
"dhcp",
|
||||
"single-dhcp",
|
||||
"on"
|
||||
"any",
|
||||
"dhcp6",
|
||||
"auto",
|
||||
"auto6",
|
||||
"link6",
|
||||
"ibft")) {
|
||||
if (!nm_str_is_empty(tmp2) && (tmp3 = _parse_ip_method(tmp2))) {
|
||||
/* <ifname>:{none|off|dhcp|on|any|dhcp6|auto|auto6|link6|ibft} */
|
||||
iface_spec = tmp;
|
||||
kind = tmp2;
|
||||
kind = tmp3;
|
||||
} else {
|
||||
/* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<kind> */
|
||||
client_ip = tmp;
|
||||
|
|
@ -466,7 +574,12 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
netmask = get_word(&argument, ':');
|
||||
client_hostname = get_word(&argument, ':');
|
||||
iface_spec = get_word(&argument, ':');
|
||||
kind = get_word(&argument, ':');
|
||||
tmp2 = get_word(&argument, ':');
|
||||
kind = _parse_ip_method(tmp2);
|
||||
if (!kind) {
|
||||
/* invalid method. We treat that as "auto". */
|
||||
kind = "auto";
|
||||
}
|
||||
}
|
||||
|
||||
if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE))
|
||||
|
|
@ -495,7 +608,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
}
|
||||
}
|
||||
|
||||
if (iface_spec == NULL && NM_IN_STRSET(kind, "fw", "ibft")) {
|
||||
if (iface_spec == NULL && nm_streq(kind, "ibft")) {
|
||||
reader_read_all_connections_from_fw(reader, sysfs_dir);
|
||||
return;
|
||||
}
|
||||
|
|
@ -592,7 +705,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
}
|
||||
|
||||
/* Dynamic IP configuration configured explicitly. */
|
||||
if (NM_IN_STRSET(kind, "none", "off")) {
|
||||
if (nm_streq(kind, "none")) {
|
||||
if (nm_setting_ip_config_get_num_addresses(s_ip6) == 0) {
|
||||
g_object_set(s_ip6,
|
||||
NM_SETTING_IP_CONFIG_METHOD,
|
||||
|
|
@ -605,7 +718,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
|
||||
NULL);
|
||||
}
|
||||
} else if (NM_IN_STRSET(kind, "dhcp", "single-dhcp")) {
|
||||
} else if (nm_streq(kind, "dhcp")) {
|
||||
g_object_set(s_ip4,
|
||||
NM_SETTING_IP_CONFIG_METHOD,
|
||||
NM_SETTING_IP4_CONFIG_METHOD_AUTO,
|
||||
|
|
@ -618,7 +731,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
|
||||
NULL);
|
||||
}
|
||||
} else if (NM_IN_STRSET(kind, "auto6", "dhcp6")) {
|
||||
} else if (nm_streq(kind, "dhcp6")) {
|
||||
g_object_set(s_ip6,
|
||||
NM_SETTING_IP_CONFIG_METHOD,
|
||||
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
|
||||
|
|
@ -631,7 +744,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
|
||||
NULL);
|
||||
}
|
||||
} else if (nm_streq0(kind, "link6")) {
|
||||
} else if (nm_streq(kind, "link6")) {
|
||||
g_object_set(s_ip6,
|
||||
NM_SETTING_IP_CONFIG_METHOD,
|
||||
NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
|
||||
|
|
@ -644,7 +757,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
|
||||
NULL);
|
||||
}
|
||||
} else if (nm_streq0(kind, "ibft")) {
|
||||
} else if (nm_streq(kind, "ibft")) {
|
||||
NMSettingWired *s_wired;
|
||||
const char * mac = NULL;
|
||||
const char * ifname;
|
||||
|
|
@ -684,6 +797,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
nm_assert(nm_streq(kind, "auto"));
|
||||
clear_ip4_required_timeout = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ static void
|
|||
test_dhcp_with_hostname(void)
|
||||
{
|
||||
gs_unref_hashtable GHashTable *connections = NULL;
|
||||
const char *const * ARGV = NM_MAKE_STRV("ip=::::host1::dhcp");
|
||||
const char *const * ARGV = NM_MAKE_STRV("ip=::::host1::dhcp,dhcp6");
|
||||
NMConnection * connection;
|
||||
NMSettingConnection * s_con;
|
||||
NMSettingWired * s_wired;
|
||||
|
|
@ -181,7 +181,7 @@ test_dhcp_with_hostname(void)
|
|||
static void
|
||||
test_dhcp_with_mtu(void)
|
||||
{
|
||||
const char *const *ARGV0 = NM_MAKE_STRV("ip=:dhcp:1499");
|
||||
const char *const *ARGV0 = NM_MAKE_STRV("ip=:dhcp6,dhcp:1499");
|
||||
const char *const *ARGV1 = NM_MAKE_STRV("ip=::::::dhcp:1499");
|
||||
const char *const *ARGV[] = {ARGV0, ARGV1};
|
||||
guint i;
|
||||
|
|
@ -290,7 +290,7 @@ test_dhcp_timeout(void)
|
|||
static void
|
||||
test_if_auto_with_mtu(void)
|
||||
{
|
||||
const char *const *ARGV = NM_MAKE_STRV("ip=eth0:auto:1666");
|
||||
const char *const *ARGV = NM_MAKE_STRV("ip=eth0:dhcp,dhcp6:1666");
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMSettingConnection * s_con;
|
||||
NMSettingWired * s_wired;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue