diff options
author | Thomas Haller <thaller@redhat.com> | 2015-10-27 16:14:54 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-11-02 13:57:02 +0100 |
commit | a5ea141956eea99f0882061d12d229d36c9ea684 (patch) | |
tree | 1d4d7d759d01a4eef84574aea80f5f0c53c6b397 | |
parent | 17aa8c0fc87e301fe5959bc586b762e8399a372a (diff) | |
download | NetworkManager-a5ea141956eea99f0882061d12d229d36c9ea684.tar.gz |
platform/vlan: add support for ingress/egress-qos-mappings and changing flags
Previously, we could only set the ingress-qos-mappings/egress-qos-mappings.
Now also cache the mappings and expose them from the platform cache.
Also, support changing the vlan flags not only when creating the vlan
interface.
-rw-r--r-- | src/platform/nm-fake-platform.c | 22 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 369 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 127 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 35 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 140 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 5 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 522 |
7 files changed, 1122 insertions, 98 deletions
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 663930ebac..a7c6b000ff 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -685,15 +685,18 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint } static gboolean -vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) +link_vlan_change (NMPlatform *platform, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { - return !!link_get (platform, ifindex); -} - -static gboolean -vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) -{ - return !!link_get (platform, ifindex); + return FALSE; } static gboolean @@ -1445,8 +1448,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->slave_get_option = slave_get_option; platform_class->vlan_add = vlan_add; - platform_class->vlan_set_ingress_map = vlan_set_ingress_map; - platform_class->vlan_set_egress_map = vlan_set_egress_map; + platform_class->link_vlan_change = link_vlan_change; platform_class->infiniband_partition_add = infiniband_partition_add; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 21b565564b..b07afc1d45 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -255,6 +255,25 @@ clear_host_address (int family, const void *network, int plen, void *dst) } } +static int +_vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data) +{ + const NMVlanQosMapping *map_a = a; + const NMVlanQosMapping *map_b = b; + + if (map_a->from != map_b->from) + return map_a->from < map_b->from ? -1 : 1; + return 0; +} + +static int +_vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a), + *((const NMVlanQosMapping **) b), + NULL); +} + /****************************************************************** * NMLinkType functions ******************************************************************/ @@ -929,6 +948,65 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static gboolean +_vlan_qos_mapping_from_nla (struct nlattr *nlattr, + const NMVlanQosMapping **out_map, + guint *out_n_map) +{ + struct nlattr *nla; + int remaining; + gs_unref_ptrarray GPtrArray *array = NULL; + + G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (struct ifla_vlan_qos_mapping)); + G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->to) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->to)); + G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->from) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->from)); + G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (((NMVlanQosMapping *) 0)->from) + sizeof (((NMVlanQosMapping *) 0)->to)); + + nm_assert (out_map && !*out_map); + nm_assert (out_n_map && !*out_n_map); + + if (!nlattr) + return TRUE; + + array = g_ptr_array_new (); + nla_for_each_nested (nla, nlattr, remaining) { + if (nla_len (nla) < sizeof(NMVlanQosMapping)) + return FALSE; + g_ptr_array_add (array, nla_data (nla)); + } + + if (array->len > 0) { + NMVlanQosMapping *list; + guint i, j; + + /* The sorting is necessary, because for egress mapping, kernel + * doesn't sent the items strictly sorted by the from field. */ + g_ptr_array_sort_with_data (array, _vlan_qos_mapping_cmp_from_ptr, NULL); + + list = g_new (NMVlanQosMapping, array->len); + + for (i = 0, j = 0; i < array->len; i++) { + NMVlanQosMapping *map; + + map = array->pdata[i]; + + /* kernel doesn't really send us duplicates. Just be extra cautious + * because we want strong guarantees about the sort order and uniqueness + * of our mapping list (for simpler equality comparison). */ + if ( j > 0 + && list[j - 1].from == map->from) + list[j - 1] = *map; + else + list[j++] = *map; + } + + *out_n_map = j; + *out_map = list; + } + + return TRUE; +} + /* Copied and heavily modified from libnl3's vlan_parse() */ static NMPObject * _parse_lnk_vlan (const char *kind, struct nlattr *info_data) @@ -942,7 +1020,8 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) }; struct nlattr *tb[IFLA_VLAN_MAX+1]; int err; - NMPObject *obj = NULL; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_result; if (!info_data || g_strcmp0 (kind, "vlan")) return NULL; @@ -954,9 +1033,30 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); - obj->lnk_vlan.id = nla_get_u16(tb[IFLA_VLAN_ID]); + obj->lnk_vlan.id = nla_get_u16 (tb[IFLA_VLAN_ID]); - return obj; + if (tb[IFLA_VLAN_FLAGS]) { + struct ifla_vlan_flags flags; + + nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); + + obj->lnk_vlan.flags = flags.flags; + } + + if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_INGRESS_QOS], + &obj->_lnk_vlan.ingress_qos_map, + &obj->_lnk_vlan.n_ingress_qos_map)) + return NULL; + + if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_EGRESS_QOS], + &obj->_lnk_vlan.egress_qos_map, + &obj->_lnk_vlan.n_egress_qos_map)) + return NULL; + + + obj_result = obj; + obj = NULL; + return obj_result; } /*****************************************************************************/ @@ -1676,17 +1776,46 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, int vlan_id, guint32 flags_mask, guint32 flags_set, - const struct ifla_vlan_qos_mapping *ingress_qos, + const NMVlanQosMapping *ingress_qos, int ingress_qos_len, - const struct ifla_vlan_qos_mapping *egress_qos, + const NMVlanQosMapping *egress_qos, int egress_qos_len) { struct nlattr *info; struct nlattr *data; guint i; + gboolean has_any_vlan_properties = FALSE; + +#define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0) nm_assert (msg); + /* We must not create an empty IFLA_LINKINFO section. Otherwise, kernel + * rejects the request as invalid. */ + if ( flags_mask != 0 + || vlan_id >= 0) + has_any_vlan_properties = TRUE; + if ( !has_any_vlan_properties + && ingress_qos && ingress_qos_len > 0) { + for (i = 0; i < ingress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) { + has_any_vlan_properties = TRUE; + break; + } + } + } + if ( !has_any_vlan_properties + && egress_qos && egress_qos_len > 0) { + for (i = 0; i < egress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { + has_any_vlan_properties = TRUE; + break; + } + } + } + if (!has_any_vlan_properties) + return TRUE; + if (!(info = nla_nest_start (msg, IFLA_LINKINFO))) goto nla_put_failure; @@ -1708,27 +1837,39 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, } if (ingress_qos && ingress_qos_len > 0) { - struct nlattr *qos; - - if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS))) - goto nla_put_failure; - - for (i = 0; i < ingress_qos_len; i++) - NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]); + struct nlattr *qos = NULL; + + for (i = 0; i < ingress_qos_len; i++) { + /* Silently ignore invalid mappings. Kernel would truncate + * them and modify the wrong mapping. */ + if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) { + if (!qos) { + if (!(qos = nla_nest_start (msg, IFLA_VLAN_INGRESS_QOS))) + goto nla_put_failure; + } + NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]); + } + } - nla_nest_end(msg, qos); + if (qos) + nla_nest_end (msg, qos); } if (egress_qos && egress_qos_len > 0) { - struct nlattr *qos; - - if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) - goto nla_put_failure; + struct nlattr *qos = NULL; - for (i = 0; i < egress_qos_len; i++) - NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); + for (i = 0; i < egress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { + if (!qos) { + if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + goto nla_put_failure; + } + NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); + } + } - nla_nest_end(msg, qos); + if (qos) + nla_nest_end(msg, qos); } nla_nest_end (msg, data); @@ -3950,54 +4091,155 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static gboolean -vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct ifla_vlan_qos_mapping ingress_qos = { - .from = from, - .to = to, - }; - unsigned flags; - - if (!_lookup_cached_link_data (platform, ifindex, "vlan-ingress", &flags)) - return FALSE; +static void +_vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, + gboolean reset_all, + const NMVlanQosMapping *current_map, + guint current_n_map, + const NMVlanQosMapping *set_map, + guint set_n_map, + NMVlanQosMapping **out_map, + guint *out_n_map) +{ + NMVlanQosMapping *map; + guint i, j, len; + const guint INGRESS_RANGE_LEN = 8; + + nm_assert (out_map && !*out_map); + nm_assert (out_n_map && !*out_n_map); + + if (!reset_all) + current_n_map = 0; + else if (is_ingress_map) + current_n_map = INGRESS_RANGE_LEN; + + len = current_n_map + set_n_map; + + if (len == 0) + return; - _LOGD ("link: change %d: vlan-ingress: set %d -> %d", ifindex, from, to); + map = g_new (NMVlanQosMapping, len); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - 0, - ifindex, - NULL, - flags); - if ( !nlmsg - || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg, - -1, - 0, - 0, - &ingress_qos, - 1, - NULL, - 0)) - return FALSE; + if (current_n_map) { + if (is_ingress_map) { + /* For the ingress-map, there are only 8 entries (0 to 7). + * When the user requests to reset all entires, we don't actually + * need the cached entries, we can just explicitly clear all possible + * ones. + * + * That makes only a real difference in case our cache is out-of-date. + * + * For the egress map we cannot do that, because there are far too + * many. There we can only clear the entries that we know about. */ + for (i = 0; i < INGRESS_RANGE_LEN; i++) { + map[i].from = i; + map[i].to = 0; + } + } else { + for (i = 0; i < current_n_map; i++) { + map[i].from = current_map[i].from; + map[i].to = 0; + } + } + } + if (set_n_map) + memcpy (&map[current_n_map], set_map, sizeof (*set_map) * set_n_map); + + g_qsort_with_data (map, + len, + sizeof (*map), + _vlan_qos_mapping_cmp_from, + NULL); + + for (i = 0, j = 0; i < len; i++) { + if ( ( is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].from)) + || (!is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].to))) + continue; + if ( j > 0 + && map[j - 1].from == map[i].from) + map[j - 1] = map[i]; + else + map[j++] = map[i]; + } - return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; + *out_map = map; + *out_n_map = j; } static gboolean -vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) +link_vlan_change (NMPlatform *platform, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + const NMPObject *obj_cache; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct ifla_vlan_qos_mapping egress_qos = { - .from = from, - .to = to, - }; unsigned flags; + const NMPObjectLnkVlan *lnk; + guint new_n_ingress_map = 0; + guint new_n_egress_map = 0; + gs_free NMVlanQosMapping *new_ingress_map = NULL; + gs_free NMVlanQosMapping *new_egress_map = NULL; + char s_flags[64]; + char s_ingress[256]; + char s_egress[256]; - if (!_lookup_cached_link_data (platform, ifindex, "vlan-egress", &flags)) + obj_cache = nmp_cache_lookup_link (priv->cache, ifindex); + if ( !obj_cache + || !obj_cache->_link.netlink.is_in_netlink) { + _LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan"); return FALSE; + } - _LOGD ("link: change %d: vlan-egress: set %d -> %d", ifindex, from, to); + lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL; + flags = obj_cache->link.flags; + + flags_set &= flags_mask; + + _vlan_change_vlan_qos_mapping_create (TRUE, + ingress_reset_all, + lnk ? lnk->ingress_qos_map : NULL, + lnk ? lnk->n_ingress_qos_map : 0, + ingress_map, + n_ingress_map, + &new_ingress_map, + &new_n_ingress_map); + + _vlan_change_vlan_qos_mapping_create (FALSE, + egress_reset_all, + lnk ? lnk->egress_qos_map : NULL, + lnk ? lnk->n_egress_qos_map : 0, + egress_map, + n_egress_map, + &new_egress_map, + &new_n_egress_map); + + _LOGD ("link: change %d: vlan:%s%s%s", + ifindex, + flags_mask + ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask) + : "", + new_n_ingress_map + ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map", + new_ingress_map, + new_n_ingress_map, + s_ingress, + sizeof (s_ingress)) + : "", + new_n_egress_map + ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map", + new_egress_map, + new_n_egress_map, + s_egress, + sizeof (s_egress)) + : ""); nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, @@ -4007,12 +4249,12 @@ vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) if ( !nlmsg || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg, -1, - 0, - 0, - NULL, - 0, - &egress_qos, - 1)) + flags_mask, + flags_set, + new_ingress_map, + new_n_ingress_map, + new_egress_map, + new_n_egress_map)) return FALSE; return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; @@ -5228,8 +5470,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->slave_get_option = slave_get_option; platform_class->vlan_add = vlan_add; - platform_class->vlan_set_ingress_map = vlan_set_ingress_map; - platform_class->vlan_set_egress_map = vlan_set_egress_map; + platform_class->link_vlan_change = link_vlan_change; platform_class->infiniband_partition_add = infiniband_partition_add; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 55794c1c54..35cfc885ec 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1582,25 +1582,91 @@ nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option) } gboolean -nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to) +nm_platform_link_vlan_change (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE); + nm_assert (klass->link_vlan_change); + + g_return_val_if_fail (!n_ingress_map || ingress_map, FALSE); + g_return_val_if_fail (!n_egress_map || egress_map, FALSE); + + flags_set &= flags_mask; + + if (_LOGD_ENABLED ()) { + char buf[512]; + char *b = buf; + gsize len, i; + + b[0] = '\0'; + len = sizeof (buf); + + if (flags_mask) + nm_utils_strbuf_append (&b, &len, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask); + + if (ingress_reset_all || n_ingress_map) { + nm_utils_strbuf_append_str (&b, &len, " ingress-qos-map"); + nm_platform_vlan_qos_mapping_to_string ("", ingress_map, n_ingress_map, b, len); + i = strlen (b); + b += i; + len -= i; + if (ingress_reset_all) + nm_utils_strbuf_append_str (&b, &len, " (reset-all)"); + } + + if (egress_reset_all || n_egress_map) { + nm_utils_strbuf_append_str (&b, &len, " egress-qos-map"); + nm_platform_vlan_qos_mapping_to_string ("", egress_map, n_egress_map, b, len); + i = strlen (b); + b += i; + len -= i; + if (egress_reset_all) + nm_utils_strbuf_append_str (&b, &len, " (reset-all)"); + } - _LOGD ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to); - return klass->vlan_set_ingress_map (self, ifindex, from, to); + _LOGD ("link: change vlan %d:%s", ifindex, buf); + } + return klass->link_vlan_change (self, + ifindex, + flags_mask, + flags_set, + ingress_reset_all, + ingress_map, + n_ingress_map, + egress_reset_all, + egress_map, + n_egress_map); } gboolean -nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to) +nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to) { - _CHECK_SELF (self, klass, FALSE); + NMVlanQosMapping map = { + .from = from, + .to = to, + }; + + return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, &map, 1, FALSE, NULL, 0); +} - g_return_val_if_fail (klass->vlan_set_egress_map, FALSE); +gboolean +nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to) +{ + NMVlanQosMapping map = { + .from = from, + .to = to, + }; - _LOGD ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to); - return klass->vlan_set_egress_map (self, ifindex, from, to); + return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1); } NMPlatformError @@ -2438,6 +2504,40 @@ nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr networ /******************************************************************/ +const char * +nm_platform_vlan_qos_mapping_to_string (const char *name, + const NMVlanQosMapping *map, + gsize n_map, + char *buf, + gsize len) +{ + gsize i; + char *b; + + nm_utils_to_string_buffer_init (&buf, &len); + + if (!n_map) { + nm_utils_strbuf_append_str (&buf, &len, ""); + return buf; + } + + if (!map) + g_return_val_if_reached (""); + + b = buf; + + if (name) { + nm_utils_strbuf_append_str (&b, &len, name); + nm_utils_strbuf_append_str (&b, &len, " {"); + } else + nm_utils_strbuf_append_c (&b, &len, '{'); + + for (i = 0; i < n_map; i++) + nm_utils_strbuf_append (&b, &len, " %u:%u", map[i].from, map[i].to); + nm_utils_strbuf_append_str (&b, &len, " }"); + return buf; +} + static const char * source_to_string (NMIPConfigSource source) { @@ -2685,10 +2785,16 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g const char * nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) { + char *b; + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) return buf; - g_snprintf (buf, len, "vlan %u", (guint) lnk->id); + b = buf; + + nm_utils_strbuf_append (&b, &len, "vlan %u", lnk->id); + if (lnk->flags) + nm_utils_strbuf_append (&b, &len, " flags 0x%x", lnk->flags); return buf; } @@ -3231,6 +3337,7 @@ nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b { _CMP_SELF (a, b); _CMP_FIELD (a, b, id); + _CMP_FIELD (a, b, flags); return 0; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index fa53792fc9..42c3b79390 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -25,9 +25,11 @@ #include <linux/if.h> #include <linux/if_addr.h> -#include <nm-dbus-interface.h> +#include "nm-dbus-interface.h" #include "nm-default.h" #include "NetworkManagerUtils.h" +#include "nm-setting-vlan.h" +#include "nm-core-types-internal.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -105,7 +107,6 @@ extern const NMIPAddr nm_ip_addr_zero; #define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT } - #define NM_PLATFORM_LINK_OTHER_NETNS (-1) #define __NMPlatformObject_COMMON \ @@ -381,6 +382,7 @@ typedef struct { typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; + NMVlanFlags flags; } NMPlatformLnkVlan; typedef struct { @@ -510,8 +512,16 @@ typedef struct { char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); - gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to); - gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); + gboolean (*link_vlan_change) (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map); gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link); @@ -706,6 +716,17 @@ const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int NMPlatformError nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); +gboolean nm_platform_link_vlan_change (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map); + NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link); gboolean nm_platform_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); @@ -783,6 +804,12 @@ const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *addre const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); +const char *nm_platform_vlan_qos_mapping_to_string (const char *name, + const NMVlanQosMapping *map, + gsize n_map, + char *buf, + gsize len); + int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 0e5222f459..fbdc88771c 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -82,6 +82,40 @@ _id_hash_ip6_addr (const struct in6_addr *addr) return hash; } +static int +_vlan_xgress_qos_mappings_cmp (guint n_map, + const NMVlanQosMapping *map1, + const NMVlanQosMapping *map2) +{ + guint i; + + for (i = 0; i < n_map; i++) { + if (map1[i].from != map2[i].from) + return map1[i].from < map2[i].from ? -1 : 1; + if (map1[i].to != map2[i].to) + return map1[i].to < map2[i].to ? -1 : 1; + } + return 0; +} + +static void +_vlan_xgress_qos_mappings_cpy (guint *dst_n_map, + const NMVlanQosMapping **dst_map, + guint src_n_map, + const NMVlanQosMapping *src_map) +{ + if (src_n_map == 0) { + g_clear_pointer (dst_map, g_free); + *dst_n_map = 0; + } else if ( src_n_map != *dst_n_map + || _vlan_xgress_qos_mappings_cmp (src_n_map, *dst_map, src_map) != 0) { + g_clear_pointer (dst_map, g_free); + *dst_n_map = src_n_map; + if (src_n_map > 0) + *dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map); + } +} + /******************************************************************/ static const char * @@ -212,6 +246,13 @@ _vt_cmd_obj_dispose_link (NMPObject *obj) nmp_object_unref (obj->_link.netlink.lnk); } +static void +_vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj) +{ + g_free ((gpointer) obj->_lnk_vlan.ingress_qos_map); + g_free ((gpointer) obj->_lnk_vlan.egress_qos_map); +} + static NMPObject * _nmp_object_new_from_class (const NMPClass *klass) { @@ -451,6 +492,65 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin } } +static const char * +_vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) +{ + const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); + char buf2[sizeof (_nm_utils_to_string_buffer)]; + char *b; + gsize l; + + klass = NMP_OBJECT_GET_CLASS (obj); + + switch (to_string_mode) { + case NMP_OBJECT_TO_STRING_ID: + g_snprintf (buf, buf_size, "%p", obj); + return buf; + case NMP_OBJECT_TO_STRING_ALL: + + g_snprintf (buf, buf_size, + "[%s,%p,%d,%ccache,%calive,%cvisible; %s]", + klass->obj_type_name, obj, obj->_ref_count, + obj->is_cached ? '+' : '-', + nmp_object_is_alive (obj) ? '+' : '-', + nmp_object_is_visible (obj) ? '+' : '-', + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2))); + return buf; + case NMP_OBJECT_TO_STRING_PUBLIC: + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + + b = buf; + l = strlen (b); + b += l; + buf_size -= l; + + if (obj->_lnk_vlan.n_ingress_qos_map) { + nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map", + obj->_lnk_vlan.ingress_qos_map, + obj->_lnk_vlan.n_ingress_qos_map, + b, + buf_size); + l = strlen (b); + b += l; + buf_size -= l; + } + if (obj->_lnk_vlan.n_egress_qos_map) { + nm_platform_vlan_qos_mapping_to_string (" egress-qos-map", + obj->_lnk_vlan.egress_qos_map, + obj->_lnk_vlan.n_egress_qos_map, + b, + buf_size); + l = strlen (b); + b += l; + buf_size -= l; + } + + return buf; + default: + g_return_val_if_reached ("ERROR"); + } +} + #define _vt_cmd_plobj_to_string_id(type, plat_type, ...) \ static const char * \ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsize buf_len) \ @@ -528,6 +628,28 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2) return 0; } +static int +_vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) +{ + int c; + + c = nm_platform_lnk_vlan_cmp (&obj1->lnk_vlan, &obj2->lnk_vlan); + if (c) + return c; + + if (obj1->_lnk_vlan.n_ingress_qos_map != obj2->_lnk_vlan.n_ingress_qos_map) + return obj1->_lnk_vlan.n_ingress_qos_map < obj2->_lnk_vlan.n_ingress_qos_map ? -1 : 1; + if (obj1->_lnk_vlan.n_egress_qos_map != obj2->_lnk_vlan.n_egress_qos_map) + return obj1->_lnk_vlan.n_egress_qos_map < obj2->_lnk_vlan.n_egress_qos_map ? -1 : 1; + + c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_ingress_qos_map, obj1->_lnk_vlan.ingress_qos_map, obj2->_lnk_vlan.ingress_qos_map); + if (c) + return c; + c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_egress_qos_map, obj1->_lnk_vlan.egress_qos_map, obj2->_lnk_vlan.egress_qos_map); + + return c; +} + gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) { @@ -578,6 +700,20 @@ _vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src) dst->_link = src->_link; } +static void +_vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src) +{ + dst->lnk_vlan = src->lnk_vlan; + _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_ingress_qos_map, + &dst->_lnk_vlan.ingress_qos_map, + src->_lnk_vlan.n_ingress_qos_map, + src->_lnk_vlan.ingress_qos_map); + _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_egress_qos_map, + &dst->_lnk_vlan.egress_qos_map, + src->_lnk_vlan.n_egress_qos_map, + src->_lnk_vlan.egress_qos_map); +} + #define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \ static void \ _vt_cmd_plobj_id_copy_##type (NMPlatformObject *_dst, const NMPlatformObject *_src) \ @@ -1919,6 +2055,10 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_public = sizeof (NMPlatformLnkVlan), .obj_type_name = "vlan", .lnk_link_type = NM_LINK_TYPE_VLAN, + .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_vlan, + .cmd_obj_copy = _vt_cmd_obj_copy_lnk_vlan, + .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_vlan, + .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_vlan, .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vlan_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, }, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index efced61879..e49d358675 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -174,6 +174,11 @@ typedef struct { typedef struct { NMPlatformLnkVlan _public; + + guint n_ingress_qos_map; + guint n_egress_qos_map; + const NMVlanQosMapping *ingress_qos_map; + const NMVlanQosMapping *egress_qos_map; } NMPObjectLnkVlan; typedef struct { diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 645d9f6342..9030f0e4df 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -812,6 +812,85 @@ test_software_detect_add (const char *testpath, /*****************************************************************************/ static void +_assert_xgress_qos_mappings_impl (int ifindex, + gboolean is_ingress_map , + int n_entries, + int n, + ...) +{ + const NMPlatformLink *plink; + const NMPObject *lnk; + guint n_map; + const NMVlanQosMapping *map; + va_list ap; + guint i; + + lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink); + + g_assert (plink); + g_assert_cmpint (plink->ifindex, ==, ifindex); + g_assert (lnk); + g_assert (&lnk->lnk_vlan == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL)); + + if (nmtst_is_debug ()) + nmtstp_run_command_check ("ip -d link show %s", plink->name); + + if (is_ingress_map) { + map = lnk->_lnk_vlan.ingress_qos_map; + n_map = lnk->_lnk_vlan.n_ingress_qos_map; + } else { + map = lnk->_lnk_vlan.egress_qos_map; + n_map = lnk->_lnk_vlan.n_egress_qos_map; + } + + if (n_entries != -1) + g_assert_cmpint (n_map, ==, n_entries); + + for (i = 0; i < n_map; i++) { + if (is_ingress_map) { + g_assert_cmpint (map[i].from, >=, 0); + g_assert_cmpint (map[i].from, <=, 7); + } + if (i > 0) + g_assert_cmpint (map[i - 1].from, <, map[i].from); + } + + va_start (ap, n); + for (; n > 0; n--) { + gboolean found = FALSE; + guint from = va_arg (ap, guint); + guint to = va_arg (ap, guint); + + for (i = 0; i < n_map; i++) { + if (map[i].from == from) { + g_assert (!found); + found = TRUE; + + g_assert (map[i].to == to); + } + } + g_assert (found); + } + va_end (ap); +} +#define _assert_xgress_qos_mappings(ifindex, is_ingress_map, n_entries, ...) \ + _assert_xgress_qos_mappings_impl ((ifindex), (is_ingress_map), (n_entries), \ + (G_STATIC_ASSERT_EXPR ((NM_NARG (__VA_ARGS__) % 2) == 0), NM_NARG (__VA_ARGS__) / 2), \ + __VA_ARGS__) +#define _assert_ingress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, TRUE, n_entries, __VA_ARGS__) +#define _assert_egress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, FALSE, n_entries, __VA_ARGS__) + +static void +_assert_vlan_flags (int ifindex, NMVlanFlags flags) +{ + const NMPlatformLnkVlan *plnk; + + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL); + g_assert (plnk); + g_assert_cmpint (plnk->flags, ==, flags); +} + +static void test_vlan_set_xgress (void) { int ifindex, ifindex_parent; @@ -822,29 +901,452 @@ test_vlan_set_xgress (void) nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1245", DEVICE_NAME, PARENT_NAME); ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex; + /* ingress-qos-map */ + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 4, 5)); + _assert_ingress_qos_mappings (ifindex, 1, + 4, 5); + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 7)); + _assert_ingress_qos_mappings (ifindex, 2, + 3, 7, + 4, 5); + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 8)); + _assert_ingress_qos_mappings (ifindex, 2, + 3, 8, + 4, 5); + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 4)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 4, + 3, 8, + 4, 5); + + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, G_MAXUINT32, + 3, 8, + 4, 5); + + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32 - 1)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, G_MAXUINT32 - 1, + 3, 8, + 4, 5); + + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + /* Set invalid values: */ + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 8, 3)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 9, 4)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + /* egress-qos-map */ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 3)); + _assert_egress_qos_mappings (ifindex, 1, + 7, 3); + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 4)); + _assert_egress_qos_mappings (ifindex, 2, + 7, 3, + 8, 4); + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 4)); + _assert_egress_qos_mappings (ifindex, 3, + 0, 4, + 7, 3, + 8, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 4)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 4, + 7, 3, + 8, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 5)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 5, + 7, 3, + 8, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 9, 5)); + _assert_egress_qos_mappings (ifindex, 5, + 0, 4, + 1, 5, + 7, 3, + 8, 4, + 9, 5); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 5)); + _assert_egress_qos_mappings (ifindex, 5, + 0, 4, + 1, 5, + 7, 3, + 8, 5, + 9, 5); - /* TODO: assert that the values are actually set. Currently only verified - * by manual inspection. */ + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 0)); + _assert_egress_qos_mappings (ifindex, 3, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 4)); + _assert_egress_qos_mappings (ifindex, 4, + 1, 5, + 7, 3, + 9, 5, + 100, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 4)); + _assert_egress_qos_mappings (ifindex, 5, + 1, 5, + 7, 3, + 9, 5, + 100, 4, + G_MAXUINT32, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 8)); + _assert_egress_qos_mappings (ifindex, 5, + 1, 5, + 7, 3, + 9, 5, + 100, 4, + G_MAXUINT32, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 0)); + _assert_egress_qos_mappings (ifindex, 4, + 1, 5, + 7, 3, + 9, 5, + 100, 4); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 0)); + _assert_egress_qos_mappings (ifindex, 3, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 0)); + _assert_egress_qos_mappings (ifindex, 2, + 7, 3, + 9, 5); + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 1, 5); + } - if (nmtst_is_debug ()) - nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME); + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 5 }, + { .from = 7, .to = 1655 }, + { .from = 7, .to = 17655 }, + { .from = 5, .to = 754 }, + { .from = 4, .to = 12 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 4, + 3, 5, + 4, 12, + 7, 17655, + 5, 754); + } - g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 0)); - g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0)); + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 18 }, + { .from = 6, .to = 121 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 5, + 3, 18, + 4, 12, + 6, 121, + 7, 17655, + 5, 754); + } - g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 0)); - g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 0)); + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 0 }, + { .from = 6, .to = 7 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 6, 7); + } - if (nmtst_is_debug ()) - nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME); + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 1, 5); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 5, .to = 1 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 5, 1); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 5, .to = 3 }, + { .from = 1655, .to = 5 }, + { .from = 1655, .to = 7 }, + { .from = G_MAXUINT32, .to = 6 }, + { .from = G_MAXUINT32, .to = 8 }, + { .from = 754, .to = 4 }, + { .from = 3, .to = 2 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 5, + 3, 2, + 5, 3, + 754, 4, + 1655, 7, + G_MAXUINT32, 6); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 754, .to = 3 }, + { .from = 755, .to = 8 }, + { .from = 1655, .to = 0 }, + { .from = 6, .to = 1 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + FALSE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 5, + 3, 2, + 5, 3, + 6, 1, + 754, 3, + G_MAXUINT32, 6); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 6, .to = 0 }, + { .from = 3, .to = 4 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 3, 4); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 1, 5); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 6, .to = 145 }, + { .from = 4, .to = 1 }, + { .from = 6, .to = 12 }, + }; + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 5 }, + { .from = 3232, .to = 7 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP, + NM_VLAN_FLAG_REORDER_HEADERS, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_ingress_qos_mappings (ifindex, 2, + 4, 1, + 6, 12); + _assert_egress_qos_mappings (ifindex, 2, + 1, 5, + 3232, 7); + _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 6, .to = 145 }, + { .from = 4, .to = 1 }, + { .from = 6, .to = 12 }, + }; + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 7 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 3232, .to = 0 }, + { .from = 64, .to = 4 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + NM_VLAN_FLAG_GVRP, + NM_VLAN_FLAG_GVRP, + FALSE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_ingress_qos_mappings (ifindex, 2, + 4, 1, + 6, 12); + _assert_egress_qos_mappings (ifindex, 2, + 1, 7, + 64, 4); + _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP); + } g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex_parent)); |