platform: support reading bridge VLANs
Add a function to read the list of bridge VLANs on an interface.
This commit is contained in:

committed by
Íñigo Huguet

parent
c5d1e35f99
commit
7ae4660a77
@@ -9576,6 +9576,138 @@ nla_put_failure:
|
|||||||
g_return_val_if_reached(FALSE);
|
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
|
static gboolean
|
||||||
link_set_bridge_info(NMPlatform *platform,
|
link_set_bridge_info(NMPlatform *platform,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
@@ -11915,6 +12047,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_params_async = link_set_sriov_params_async;
|
||||||
platform_class->link_set_sriov_vfs = link_set_sriov_vfs;
|
platform_class->link_set_sriov_vfs = link_set_sriov_vfs;
|
||||||
platform_class->link_set_bridge_vlans = link_set_bridge_vlans;
|
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_set_bridge_info = link_set_bridge_info;
|
||||||
|
|
||||||
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
||||||
|
@@ -2099,6 +2099,40 @@ nm_platform_link_set_bridge_vlans(NMPlatform *self,
|
|||||||
return klass->link_set_bridge_vlans(self, ifindex, on_controller, vlans, num_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
|
gboolean
|
||||||
nm_platform_link_set_bridge_info(NMPlatform *self,
|
nm_platform_link_set_bridge_info(NMPlatform *self,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
|
@@ -1190,6 +1190,10 @@ typedef struct {
|
|||||||
gboolean on_controller,
|
gboolean on_controller,
|
||||||
const NMPlatformBridgeVlan *vlans,
|
const NMPlatformBridgeVlan *vlans,
|
||||||
guint num_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,
|
gboolean (*link_set_bridge_info)(NMPlatform *self,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
const NMPlatformLinkSetBridgeInfoData *bridge_info);
|
const NMPlatformLinkSetBridgeInfoData *bridge_info);
|
||||||
@@ -2055,6 +2059,10 @@ gboolean nm_platform_link_set_bridge_vlans(NMPlatform *self,
|
|||||||
gboolean on_controller,
|
gboolean on_controller,
|
||||||
const NMPlatformBridgeVlan *vlans,
|
const NMPlatformBridgeVlan *vlans,
|
||||||
guint num_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,
|
gboolean nm_platform_link_set_bridge_info(NMPlatform *self,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
const NMPlatformLinkSetBridgeInfoData *bridge_info);
|
const NMPlatformLinkSetBridgeInfoData *bridge_info);
|
||||||
|
Reference in New Issue
Block a user