This patch may get 802.1Qbh devices working. I am adding some code to
poll for the status of an 802.1Qbh device and loop for a while until the
status indicates success. This part for sure needs more work and
testing...
I am recycling link_dump from a previous patch.
Changes from V1 to V2:
- Following tree
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/util/macvtap.c | 116
+++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -960,6 +960,95 @@ getPortProfileStatus(struct nlmsghdr *nl
static int
+link_dump(int ifindex, const char *ifname, struct nlattr **tb,
+ char **recvbuf)
+{
+ int rc = 0;
+ char nlmsgbuf[256] = { 0, };
+ struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
+ struct nlmsgerr *err;
+ char rtattbuf[64];
+ struct rtattr *rta;
+ struct ifinfomsg i = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex
+ };
+ int recvbuflen;
+
+ *recvbuf = NULL;
+
+ nlInit(nlm, NLM_F_REQUEST, RTM_GETLINK);
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &i, sizeof(i)))
+ goto buffer_too_small;
+
+ if (ifindex < 0 && ifname != NULL) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME,
+ ifname, strlen(ifname) + 1);
+ if (!rta)
+ goto buffer_too_small;
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (nlComm(nlm, recvbuf, &recvbuflen) < 0)
+ return -1;
+
+ if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)*recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ switch (-err->error) {
+ case 0:
+ break;
+
+ default:
+ virReportSystemError(-err->error,
+ _("error dumping %d interface"),
+ ifindex);
+ rc = -1;
+ }
+ break;
+
+ case GENL_ID_CTRL:
+ case NLMSG_DONE:
+ if (nlmsg_parse(resp, sizeof(struct ifinfomsg),
+ tb, IFLA_MAX, ifla_policy)) {
+ goto malformed_resp;
+ }
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ if (rc != 0)
+ VIR_FREE(*recvbuf);
+
+ return rc;
+
+malformed_resp:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(*recvbuf);
+ return -1;
+
+buffer_too_small:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("internal buffer is too small"));
+ return -1;
+}
+
+
+static int
doPortProfileOpSetLink(bool multicast,
const char *ifname, int ifindex,
const char *profileId,
@@ -1151,6 +1240,10 @@ doPortProfileOpCommon(bool multicast,
uint8_t op)
{
int rc;
+ char *recvbuf = NULL;
+ struct nlattr *tb[IFLA_MAX + 1];
+ int repeats = 5;
+ uint16_t status;
rc = doPortProfileOpSetLink(multicast,
ifname, ifindex,
@@ -1167,6 +1260,30 @@ doPortProfileOpCommon(bool multicast,
return rc;
}
+ if (!multicast) {
+ /* 802.1Qbh -- query for status */
+ while (--repeats) {
+ rc = link_dump(ifindex, ifname, tb, &recvbuf);
+ if (rc)
+ goto err_exit;
+ rc = getPortProfileStatus((struct nlmsghdr *)recvbuf,
&status);
+ if (rc == 0) {
+ if (status == 0)
+ break;
+ if (status != 0) {
+ fprintf(stderr,"Current status: %d\n", status);
+ rc = 1;
+ }
+ }
+ usleep(10000);
+
+ VIR_FREE(recvbuf);
+ }
+ }
+
+err_exit:
+ VIR_FREE(recvbuf);
+
return rc;
}