diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 172 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.c | 83 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.h | 7 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 49 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.h | 33 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-base.h | 9 | ||||
| -rw-r--r-- | src/libnm-platform/tests/test-nm-platform.c | 237 |
7 files changed, 559 insertions, 31 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index dd4be614..53f678fc 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -187,6 +187,9 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +/* Added in kernel 5.19, dated July 31, 2022 */ +#define IFLA_BOND_SLAVE_PRIO 9 + #define IFLA_BOND_ACTIVE_PORT IFLA_BOND_ACTIVE_SLAVE #define IFLA_BOND_PORT_PRIO IFLA_BOND_SLAVE_PRIO #define IFLA_BOND_ALL_PORTS_ACTIVE IFLA_BOND_ALL_SLAVES_ACTIVE @@ -353,7 +356,8 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ -#define RESYNC_RETRIES 50 +#define RESYNC_RETRIES 50 +#define RESYNC_BACKOFF_SECONDS 1 /*****************************************************************************/ @@ -9402,17 +9406,20 @@ nla_put_failure: } static gboolean -link_set_bridge_vlans(NMPlatform *platform, - int ifindex, - gboolean on_controller, - const NMPlatformBridgeVlan *const *vlans) +link_set_bridge_vlans(NMPlatform *platform, + int ifindex, + gboolean on_controller, + const NMPlatformBridgeVlan *vlans, + guint num_vlans) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *list; struct bridge_vlan_info vinfo = {}; guint i; - nlmsg = _nl_msg_new_link_full(vlans ? RTM_SETLINK : RTM_DELLINK, + nm_assert(num_vlans == 0 || vlans); + + nlmsg = _nl_msg_new_link_full(num_vlans > 0 ? RTM_SETLINK : RTM_DELLINK, 0, ifindex, NULL, @@ -9430,10 +9437,10 @@ link_set_bridge_vlans(NMPlatform *platform, IFLA_BRIDGE_FLAGS, on_controller ? BRIDGE_FLAGS_CONTROLLER : BRIDGE_FLAGS_SELF); - if (vlans) { + if (num_vlans > 0) { /* Add VLANs */ - for (i = 0; vlans[i]; i++) { - const NMPlatformBridgeVlan *vlan = vlans[i]; + for (i = 0; i < num_vlans; i++) { + const NMPlatformBridgeVlan *vlan = &vlans[i]; gboolean is_range = vlan->vid_start != vlan->vid_end; vinfo.vid = vlan->vid_start; @@ -9470,6 +9477,138 @@ nla_put_failure: g_return_val_if_reached(FALSE); } +typedef struct { + int ifindex; + GArray *vlans; +} BridgeVlanData; + +static int +get_bridge_vlans_cb(const struct nl_msg *msg, void *arg) +{ + static const struct nla_policy policy[] = { + [IFLA_AF_SPEC] = {.type = NLA_NESTED}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + gboolean is_range = FALSE; + BridgeVlanData *data = arg; + struct ifinfomsg *ifinfo; + struct nlattr *attr; + int rem; + + if (nlmsg_parse_arr(nlmsg_hdr(msg), sizeof(struct ifinfomsg), tb, policy) < 0) + return NL_SKIP; + + ifinfo = NLMSG_DATA(nlmsg_hdr(msg)); + if (ifinfo->ifi_index != data->ifindex) + return NL_SKIP; + + if (!tb[IFLA_AF_SPEC]) + return NL_SKIP; + + nla_for_each_nested (attr, tb[IFLA_AF_SPEC], rem) { + struct bridge_vlan_info vlan_info; + NMPlatformBridgeVlan vlan = {}; + + if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO) + continue; + + if (!data->vlans) + data->vlans = g_array_new(0, FALSE, sizeof(NMPlatformBridgeVlan)); + + vlan_info = *nla_data_as(struct bridge_vlan_info, attr); + + if (is_range) { + nm_g_array_index(data->vlans, NMPlatformBridgeVlan, data->vlans->len - 1).vid_end = + vlan_info.vid; + is_range = FALSE; + continue; + } else { + vlan.vid_start = vlan_info.vid; + vlan.vid_end = vlan_info.vid; + vlan.untagged = vlan_info.flags & BRIDGE_VLAN_INFO_UNTAGGED; + vlan.pvid = vlan_info.flags & BRIDGE_VLAN_INFO_PVID; + + if (vlan_info.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + is_range = TRUE; + } + + g_array_append_val(data->vlans, vlan); + } + + return NL_OK; +} + +static gboolean +link_get_bridge_vlans(NMPlatform *platform, + int ifindex, + NMPlatformBridgeVlan **out_vlans, + guint *out_num_vlans) +{ + gboolean ret = FALSE; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nl_sock *sk = NULL; + BridgeVlanData data; + int nle; + + nlmsg = _nl_msg_new_link_full(RTM_GETLINK, NLM_F_DUMP, 0, NULL, AF_BRIDGE, 0, 0, 0); + if (!nlmsg) + g_return_val_if_reached(FALSE); + + nle = nl_socket_new(&sk, NETLINK_ROUTE, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, 0, 0); + if (nle < 0) { + _LOGD("get-bridge-vlan: error opening socket: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + NLA_PUT_U32(nlmsg, IFLA_EXT_MASK, RTEXT_FILTER_BRVLAN_COMPRESSED); + + nle = nl_send_auto(sk, nlmsg); + if (nle < 0) { + _LOGD("get-bridge-vlans: failed sending request: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + data = ((BridgeVlanData){ + .ifindex = ifindex, + }); + + do { + nle = nl_recvmsgs(sk, + &((const struct nl_cb){ + .valid_cb = get_bridge_vlans_cb, + .valid_arg = &data, + })); + } while (nle == -EAGAIN); + + if (nle < 0) { + _LOGD("get-bridge-vlan: recv failed: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + if (data.vlans) { + NM_SET_OUT(out_vlans, &nm_g_array_index(data.vlans, NMPlatformBridgeVlan, 0)); + NM_SET_OUT(out_num_vlans, data.vlans->len); + } else { + NM_SET_OUT(out_vlans, NULL); + NM_SET_OUT(out_num_vlans, 0); + } + + if (data.vlans) + g_array_free(data.vlans, !out_vlans); + + ret = TRUE; +err: + if (sk) + nl_socket_free(sk); + return ret; + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + static gboolean link_set_bridge_info(NMPlatform *platform, int ifindex, @@ -10965,6 +11104,20 @@ event_handler_read_netlink(NMPlatform *platform, } _reason; })); + + if (nle == -ENOBUFS) { + /* Netlink notifications are coming faster than what + * we can process them. Backoff a bit so we give some + * time for this burst to finish, and we don't + * contribute to starve the system contending for the + * kernel's RTNL lock. + */ + _LOGI("netlink[%s]: backoff for %d seconds before the resync.", + nmp_netlink_protocol_info(netlink_protocol)->name, + RESYNC_BACKOFF_SECONDS); + sleep(RESYNC_BACKOFF_SECONDS); + } + _netlink_recv_handle(platform, netlink_protocol, FALSE); delayed_action_wait_for_nl_response_complete_all( platform, @@ -11809,6 +11962,7 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->link_set_sriov_params_async = link_set_sriov_params_async; platform_class->link_set_sriov_vfs = link_set_sriov_vfs; platform_class->link_set_bridge_vlans = link_set_bridge_vlans; + platform_class->link_get_bridge_vlans = link_get_bridge_vlans; platform_class->link_set_bridge_info = link_set_bridge_info; platform_class->link_get_physical_port_id = link_get_physical_port_id; diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index 6f3ad05c..3f70f5fe 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -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) { diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h index 18fc6155..96ac22ef 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -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__ */ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index f82de7f9..af04f29f 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -2070,10 +2070,11 @@ nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF } gboolean -nm_platform_link_set_bridge_vlans(NMPlatform *self, - int ifindex, - gboolean on_controller, - const NMPlatformBridgeVlan *const *vlans) +nm_platform_link_set_bridge_vlans(NMPlatform *self, + int ifindex, + gboolean on_controller, + const NMPlatformBridgeVlan *vlans, + guint num_vlans) { guint i; _CHECK_SELF(self, klass, FALSE); @@ -2085,9 +2086,9 @@ nm_platform_link_set_bridge_vlans(NMPlatform *self, vlans ? "setting" : "clearing", on_controller ? "controller" : "self"); if (vlans) { - for (i = 0; vlans[i]; i++) { + for (i = 0; i < num_vlans; i++) { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - const NMPlatformBridgeVlan *vlan = vlans[i]; + const NMPlatformBridgeVlan *vlan = &vlans[i]; _LOG3D("link: bridge VLAN %s", nm_platform_bridge_vlan_to_string(vlan, sbuf, sizeof(sbuf))); @@ -2095,7 +2096,41 @@ nm_platform_link_set_bridge_vlans(NMPlatform *self, } } - return klass->link_set_bridge_vlans(self, ifindex, on_controller, vlans); + return klass->link_set_bridge_vlans(self, ifindex, on_controller, vlans, num_vlans); +} + +gboolean +nm_platform_link_get_bridge_vlans(NMPlatform *self, + int ifindex, + NMPlatformBridgeVlan **out_vlans, + guint *out_num_vlans) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + gboolean ret; + guint i; + + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + g_return_val_if_fail(out_vlans, FALSE); + g_return_val_if_fail(out_num_vlans, FALSE); + + _LOG3D("link: getting bridge VLANs"); + + ret = klass->link_get_bridge_vlans(self, ifindex, out_vlans, out_num_vlans); + + if (_LOGD_ENABLED()) { + if (!ret) { + _LOG3D("link: failure while getting bridge vlans"); + } else { + for (i = 0; i < *out_num_vlans; i++) { + _LOG3D("link: bridge VLAN %s", + nm_platform_bridge_vlan_to_string(&(*out_vlans)[i], sbuf, sizeof(sbuf))); + } + } + } + + return ret; } gboolean diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index b05b1297..e33be813 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -742,13 +742,6 @@ typedef struct { } 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; bool vlan_default_pvid_has : 1; @@ -1185,10 +1178,15 @@ typedef struct { gpointer callback_data, GCancellable *cancellable); gboolean (*link_set_sriov_vfs)(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); - gboolean (*link_set_bridge_vlans)(NMPlatform *self, - int ifindex, - gboolean on_controller, - const NMPlatformBridgeVlan *const *vlans); + gboolean (*link_set_bridge_vlans)(NMPlatform *self, + int ifindex, + gboolean on_controller, + const NMPlatformBridgeVlan *vlans, + guint num_vlans); + gboolean (*link_get_bridge_vlans)(NMPlatform *self, + int ifindex, + NMPlatformBridgeVlan **out_vlans, + guint *out_num_vlans); gboolean (*link_set_bridge_info)(NMPlatform *self, int ifindex, const NMPlatformLinkSetBridgeInfoData *bridge_info); @@ -2049,10 +2047,15 @@ void nm_platform_link_set_sriov_params_async(NMPlatform *self, gboolean nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); -gboolean nm_platform_link_set_bridge_vlans(NMPlatform *self, - int ifindex, - gboolean on_controller, - const NMPlatformBridgeVlan *const *vlans); +gboolean nm_platform_link_set_bridge_vlans(NMPlatform *self, + int ifindex, + gboolean on_controller, + const NMPlatformBridgeVlan *vlans, + guint num_vlans); +gboolean nm_platform_link_get_bridge_vlans(NMPlatform *self, + int ifindex, + NMPlatformBridgeVlan **out_vlans, + guint *out_num_vlans); gboolean nm_platform_link_set_bridge_info(NMPlatform *self, int ifindex, const NMPlatformLinkSetBridgeInfoData *bridge_info); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 70b5d1bc..c7d487e2 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -39,6 +39,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.*/ guint32 _private_cmd; diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 5fc8a5dd..37707875 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -191,6 +191,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) { NMPObjectType obj_type; @@ -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(); } |