platform: add nmp_utils_bridge_normalized_vlans_equal()
Add a function to compare two arrays of NMPlatformBridgeVlan. It will be used in the next commit to compare the VLANs from platform to the ones we want to set. To compare in a performant way, the vlans need to be normalized (no duplicated VLANS, ranges into their minimal expression...). Add the function nmp_utils_bridge_vlan_normalize. Co-authored-by: Íñigo Huguet <ihuguet@redhat.com>
This commit is contained in:

committed by
Íñigo Huguet

parent
7ae4660a77
commit
1c43fe5235
@@ -2275,6 +2275,89 @@ nmp_utils_lifetime_get(guint32 timestamp,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
bridge_vlan_compare(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
const NMPlatformBridgeVlan *vlan_a = a;
|
||||
const NMPlatformBridgeVlan *vlan_b = b;
|
||||
|
||||
return (int) vlan_a->vid_start - (int) vlan_b->vid_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* nmp_utils_bridge_vlan_normalize:
|
||||
* @vlans: the array of VLAN ranges
|
||||
* @num_vlans: the number of VLAN ranges in the array. On return, it contains
|
||||
* the new number.
|
||||
*
|
||||
* Sort the VLAN ranges and merge those that are contiguous or overlapping. It
|
||||
* must not contain invalid data such as 2 overlapping ranges with different
|
||||
* flags.
|
||||
*/
|
||||
void
|
||||
nmp_utils_bridge_vlan_normalize(NMPlatformBridgeVlan *vlans, guint *num_vlans)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (*num_vlans <= 1)
|
||||
return;
|
||||
|
||||
g_qsort_with_data(vlans, *num_vlans, sizeof(NMPlatformBridgeVlan), bridge_vlan_compare, NULL);
|
||||
|
||||
/* Merge VLAN ranges that are contiguous or overlap */
|
||||
i = 0;
|
||||
while (i < *num_vlans - 1) {
|
||||
guint j = i + 1;
|
||||
gboolean can_merge = vlans[j].vid_start <= vlans[i].vid_end + 1
|
||||
&& vlans[j].pvid == vlans[i].pvid
|
||||
&& vlans[j].untagged == vlans[i].untagged;
|
||||
|
||||
if (can_merge) {
|
||||
vlans[i].vid_end = NM_MAX(vlans[i].vid_end, vlans[j].vid_end);
|
||||
for (; j < *num_vlans - 1; j++)
|
||||
vlans[j] = vlans[j + 1];
|
||||
*num_vlans -= 1;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nmp_utils_bridge_normalized_vlans_equal:
|
||||
* @vlans_a: the first array of bridge VLANs
|
||||
* @num_vlans_a: the number of elements of first array
|
||||
* @vlans_b: the second array of bridge VLANs
|
||||
* @num_vlans_b: the number of elements of second array
|
||||
*
|
||||
* Given two arrays of bridge VLAN ranges, compare if they are equal,
|
||||
* i.e. if they represent the same set of VLANs with the same attributes.
|
||||
* The input arrays must be normalized (sorted and without overlapping or
|
||||
* duplicated ranges). Normalize with nmp_utils_bridge_vlan_normalize().
|
||||
*/
|
||||
gboolean
|
||||
nmp_utils_bridge_normalized_vlans_equal(const NMPlatformBridgeVlan *vlans_a,
|
||||
guint num_vlans_a,
|
||||
const NMPlatformBridgeVlan *vlans_b,
|
||||
guint num_vlans_b)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (num_vlans_a != num_vlans_b)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < num_vlans_a; i++) {
|
||||
if (vlans_a[i].vid_start != vlans_b[i].vid_start || vlans_a[i].vid_end != vlans_b[i].vid_end
|
||||
|| vlans_a[i].pvid != vlans_b[i].pvid || vlans_a[i].untagged != vlans_b[i].untagged) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
_trunk_first_line(char *str)
|
||||
{
|
||||
|
@@ -99,4 +99,11 @@ guint32 nmp_utils_lifetime_get(guint32 timestamp,
|
||||
int nmp_utils_modprobe(GError **error, gboolean suppress_error_logging, const char *arg1, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void nmp_utils_bridge_vlan_normalize(NMPlatformBridgeVlan *vlans, guint *num_vlans);
|
||||
|
||||
gboolean nmp_utils_bridge_normalized_vlans_equal(const NMPlatformBridgeVlan *vlans_a,
|
||||
guint num_vlans_a,
|
||||
const NMPlatformBridgeVlan *vlans_b,
|
||||
guint num_vlans_b);
|
||||
|
||||
#endif /* __NM_PLATFORM_UTILS_H__ */
|
||||
|
@@ -741,13 +741,6 @@ typedef struct {
|
||||
gint8 trust;
|
||||
} NMPlatformVF;
|
||||
|
||||
typedef struct {
|
||||
guint16 vid_start;
|
||||
guint16 vid_end;
|
||||
bool untagged : 1;
|
||||
bool pvid : 1;
|
||||
} NMPlatformBridgeVlan;
|
||||
|
||||
typedef struct {
|
||||
guint16 vlan_default_pvid_val;
|
||||
bool vlan_filtering_val : 1;
|
||||
|
@@ -38,6 +38,15 @@ typedef enum {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
guint16 vid_start;
|
||||
guint16 vid_end;
|
||||
bool untagged : 1;
|
||||
bool pvid : 1;
|
||||
} NMPlatformBridgeVlan;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
/* We don't want to include <linux/ethtool.h> in header files,
|
||||
* thus create a ABI compatible version of struct ethtool_drvinfo.*/
|
||||
|
@@ -190,6 +190,239 @@ test_nmp_link_mode_all_advertised_modes_bits(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_nmp_utils_bridge_vlans_normalize(void)
|
||||
{
|
||||
NMPlatformBridgeVlan vlans[10];
|
||||
NMPlatformBridgeVlan expect[10];
|
||||
guint vlans_len;
|
||||
|
||||
/* Single one is unmodified */
|
||||
vlans[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
expect[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans_len = 1;
|
||||
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
|
||||
g_assert(vlans_len == 1);
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
|
||||
|
||||
/* Not merged if flags are different */
|
||||
vlans[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 11,
|
||||
.vid_end = 11,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
vlans[2] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 20,
|
||||
.vid_end = 25,
|
||||
};
|
||||
vlans[3] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 26,
|
||||
.vid_end = 30,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[4] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 40,
|
||||
.vid_end = 40,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[5] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 40,
|
||||
.vid_end = 40,
|
||||
.untagged = TRUE,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
expect[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
expect[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 11,
|
||||
.vid_end = 11,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
expect[2] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 20,
|
||||
.vid_end = 25,
|
||||
};
|
||||
expect[3] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 26,
|
||||
.vid_end = 30,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
expect[4] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 40,
|
||||
.vid_end = 40,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
expect[5] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 40,
|
||||
.vid_end = 40,
|
||||
.untagged = TRUE,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
vlans_len = 6;
|
||||
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
|
||||
g_assert(vlans_len == 6);
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
|
||||
|
||||
/* Overlapping and contiguous ranges are merged */
|
||||
vlans[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 11,
|
||||
.vid_end = 20,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[2] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 19,
|
||||
.vid_end = 30,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
expect[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 30,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans_len = 3;
|
||||
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
|
||||
g_assert(vlans_len == 1);
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
|
||||
|
||||
vlans[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 20,
|
||||
.vid_end = 20,
|
||||
};
|
||||
vlans[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 4,
|
||||
.vid_end = 4,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
vlans[2] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 33,
|
||||
.vid_end = 33,
|
||||
};
|
||||
vlans[3] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 100,
|
||||
.vid_end = 100,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans[4] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 34,
|
||||
.vid_end = 40,
|
||||
};
|
||||
vlans[5] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 21,
|
||||
.vid_end = 32,
|
||||
};
|
||||
expect[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 4,
|
||||
.vid_end = 4,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
expect[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 20,
|
||||
.vid_end = 40,
|
||||
};
|
||||
expect[2] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 100,
|
||||
.vid_end = 100,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
vlans_len = 6;
|
||||
nmp_utils_bridge_vlan_normalize(vlans, &vlans_len);
|
||||
g_assert(vlans_len == 3);
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(vlans, vlans_len, expect, vlans_len));
|
||||
}
|
||||
|
||||
static void
|
||||
test_nmp_utils_bridge_normalized_vlans_equal(void)
|
||||
{
|
||||
NMPlatformBridgeVlan a[10];
|
||||
NMPlatformBridgeVlan b[10];
|
||||
|
||||
/* Both empty */
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(NULL, 0, NULL, 0));
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 0, b, 0));
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 0, NULL, 0));
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(NULL, 0, b, 0));
|
||||
|
||||
/* One empty, other not */
|
||||
a[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, NULL, 0));
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(NULL, 0, a, 1));
|
||||
|
||||
/* Equal range + VLAN */
|
||||
a[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
a[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 11,
|
||||
.vid_end = 11,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
b[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 10,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
b[1] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 11,
|
||||
.vid_end = 11,
|
||||
.pvid = TRUE,
|
||||
};
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(a, 2, b, 2));
|
||||
g_assert(nmp_utils_bridge_normalized_vlans_equal(b, 2, a, 2));
|
||||
|
||||
/* Different flag */
|
||||
b[1].pvid = FALSE;
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 2, b, 2));
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 2, a, 2));
|
||||
|
||||
/* Different ranges */
|
||||
a[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 30,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
b[0] = (NMPlatformBridgeVlan){
|
||||
.vid_start = 1,
|
||||
.vid_end = 29,
|
||||
.untagged = TRUE,
|
||||
};
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, b, 1));
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 1, a, 1));
|
||||
|
||||
b[0].vid_start = 2;
|
||||
b[0].vid_end = 30;
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(a, 1, b, 1));
|
||||
g_assert(!nmp_utils_bridge_normalized_vlans_equal(b, 1, a, 1));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_nmpclass_consistency(void)
|
||||
{
|
||||
@@ -252,6 +485,10 @@ main(int argc, char **argv)
|
||||
g_test_add_func("/nm-platform/test_nmp_link_mode_all_advertised_modes_bits",
|
||||
test_nmp_link_mode_all_advertised_modes_bits);
|
||||
g_test_add_func("/nm-platform/test_nmpclass_consistency", test_nmpclass_consistency);
|
||||
g_test_add_func("/nm-platform/test_nmp_utils_bridge_vlans_normalize",
|
||||
test_nmp_utils_bridge_vlans_normalize);
|
||||
g_test_add_func("/nm-platform/nmp-utils-bridge-vlans-equal",
|
||||
test_nmp_utils_bridge_normalized_vlans_equal);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
Reference in New Issue
Block a user