diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1c74137534..57a017cd4a 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -277,6 +278,14 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ +/* Appeared in in kernel 4.0 dated April 12, 2015 */ +#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1 << 3) /* VLAN is start of vlan range */ +#define BRIDGE_VLAN_INFO_RANGE_END (1 << 4) /* VLAN is end of vlan range */ +#endif + +/*****************************************************************************/ + typedef enum { INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD, @@ -3858,7 +3867,7 @@ _nl_msg_new_link_full (int nlmsg_type, .ifi_index = ifindex, }; - nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK)); + nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK, RTM_SETLINK)); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); @@ -6781,6 +6790,67 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_set_bridge_vlans (NMPlatform *platform, + int ifindex, + gboolean on_master, + const NMPlatformBridgeVlan *const *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, + 0, + ifindex, + NULL, + AF_BRIDGE, + 0, + 0); + if (!nlmsg) + g_return_val_if_reached (-NME_BUG); + + if (!(list = nla_nest_start (nlmsg, IFLA_AF_SPEC))) + goto nla_put_failure; + + NLA_PUT_U16 (nlmsg, + IFLA_BRIDGE_FLAGS, + on_master ? BRIDGE_FLAGS_MASTER : BRIDGE_FLAGS_SELF); + + if (vlans) { + /* Add VLANs */ + for (i = 0; vlans[i]; i++) { + const NMPlatformBridgeVlan *vlan = vlans[i]; + + vinfo.vid = vlan->vid; + vinfo.flags = 0; + + if (vlan->untagged) + vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; + if (vlan->pvid) + vinfo.flags |= BRIDGE_VLAN_INFO_PVID; + + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + } + } else { + /* Flush existing VLANs */ + vinfo.vid = 1; + vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN; + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + + vinfo.vid = 4094; + vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END; + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + } + + nla_nest_end (nlmsg, list); + + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static char * link_get_physical_port_id (NMPlatform *platform, int ifindex) { @@ -8921,6 +8991,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_set_name = link_set_name; platform_class->link_set_sriov_params = link_set_sriov_params; platform_class->link_set_sriov_vfs = link_set_sriov_vfs; + platform_class->link_set_bridge_vlans = link_set_bridge_vlans; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 8500c2faa4..ffab6ac28c 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1518,6 +1518,28 @@ nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformV return klass->link_set_sriov_vfs (self, ifindex, vfs); } +gboolean +nm_platform_link_set_bridge_vlans (NMPlatform *self, int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans) +{ + guint i; + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + _LOG3D ("link: %s bridge VLANs on %s", + vlans ? "setting" : "clearing", + on_master ? "master" : "self"); + if (vlans) { + for (i = 0; vlans[i]; i++) { + const NMPlatformBridgeVlan *vlan = vlans[i]; + + _LOG3D ("link: bridge VLAN %s", nm_platform_bridge_vlan_to_string (vlan, NULL, 0)); + } + } + + return klass->link_set_bridge_vlans (self, ifindex, on_master, vlans); +} + /** * nm_platform_link_set_up: * @self: platform instance @@ -6506,6 +6528,24 @@ nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len) return buf; } + +const char * +nm_platform_bridge_vlan_to_string (const NMPlatformBridgeVlan *vlan, char *buf, gsize len) +{ + if (!nm_utils_to_string_buffer_init_null (vlan, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "%u" + "%s" + "%s", + vlan->vid, + vlan->pvid ? " PVID" : "", + vlan->untagged ? " untagged" : ""); + + return buf; +} + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 06231a1dc9..2e30f8b9ce 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -670,6 +670,12 @@ typedef struct { gint8 trust; } NMPlatformVF; +typedef struct { + guint16 vid; + bool untagged:1; + bool pvid:1; +} NMPlatformBridgeVlan; + typedef struct { in_addr_t local; in_addr_t remote; @@ -893,6 +899,7 @@ typedef struct { gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name); gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe); gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); + gboolean (*link_set_bridge_vlans) (NMPlatform *self, int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans); char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); @@ -1326,6 +1333,7 @@ int nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name); gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe); 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_master, const NMPlatformBridgeVlan *const *vlans); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); @@ -1585,6 +1593,7 @@ const char *nm_platform_routing_rule_to_string (const NMPlatformRoutingRule *rou const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len); const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len); const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len); +const char *nm_platform_bridge_vlan_to_string (const NMPlatformBridgeVlan *vlan, char *buf, gsize len); const char *nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map,