Imported Upstream version 1.2.5
[archive/platform/upstream/libvirt.git] / src / util / virnetdevmacvlan.c
1 /*
2  * Copyright (C) 2010-2013 Red Hat, Inc.
3  * Copyright (C) 2010-2012 IBM Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library.  If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * Authors:
20  *     Stefan Berger <stefanb@us.ibm.com>
21  *
22  * Notes:
23  * netlink: http://lovezutto.googlepages.com/netlink.pdf
24  *          iproute2 package
25  *
26  */
27
28 #include <config.h>
29
30 #include "virnetdevmacvlan.h"
31 #include "virmacaddr.h"
32 #include "virerror.h"
33 #include "virthread.h"
34 #include "virstring.h"
35
36 #define VIR_FROM_THIS VIR_FROM_NET
37
38 VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
39               "vepa",
40               "private",
41               "bridge",
42               "passthrough")
43
44 #if WITH_MACVTAP
45 # include <stdint.h>
46 # include <stdio.h>
47 # include <errno.h>
48 # include <fcntl.h>
49 # include <sys/socket.h>
50 # include <sys/ioctl.h>
51
52 # include <net/if.h>
53 # include <linux/if_tun.h>
54
55 /* Older kernels lacked this enum value.  */
56 # if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
57 #  define MACVLAN_MODE_PASSTHRU 8
58 # endif
59
60 # include "viralloc.h"
61 # include "virlog.h"
62 # include "viruuid.h"
63 # include "virfile.h"
64 # include "virnetlink.h"
65 # include "virnetdev.h"
66 # include "virpidfile.h"
67
68 VIR_LOG_INIT("util.netdevmacvlan");
69
70 # define MACVTAP_NAME_PREFIX    "macvtap"
71 # define MACVTAP_NAME_PATTERN   "macvtap%d"
72
73 # define MACVLAN_NAME_PREFIX    "macvlan"
74 # define MACVLAN_NAME_PATTERN   "macvlan%d"
75
76 virMutex virNetDevMacVLanCreateMutex = VIR_MUTEX_INITIALIZER;
77
78 /**
79  * virNetDevMacVLanCreate:
80  *
81  * @ifname: The name the interface is supposed to have; optional parameter
82  * @type: The type of device, i.e., "macvtap", "macvlan"
83  * @macaddress: The MAC address of the device
84  * @srcdev: The name of the 'link' device
85  * @macvlan_mode: The macvlan mode to use
86  * @retry: Pointer to integer that will be '1' upon return if an interface
87  *         with the same name already exists and it is worth to try
88  *         again with a different name
89  *
90  * Create a macvtap device with the given properties.
91  *
92  * Returns 0 on success, -1 on fatal error.
93  */
94 int
95 virNetDevMacVLanCreate(const char *ifname,
96                        const char *type,
97                        const virMacAddr *macaddress,
98                        const char *srcdev,
99                        uint32_t macvlan_mode,
100                        int *retry)
101 {
102     int rc = -1;
103     struct nlmsghdr *resp = NULL;
104     struct nlmsgerr *err;
105     struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
106     int ifindex;
107     unsigned int recvbuflen;
108     struct nl_msg *nl_msg;
109     struct nlattr *linkinfo, *info_data;
110
111     if (virNetDevGetIndex(srcdev, &ifindex) < 0)
112         return -1;
113
114     *retry = 0;
115
116     nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
117                                 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
118     if (!nl_msg) {
119         virReportOOMError();
120         return -1;
121     }
122
123     if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
124         goto buffer_too_small;
125
126     if (nla_put_u32(nl_msg, IFLA_LINK, ifindex) < 0)
127         goto buffer_too_small;
128
129     if (nla_put(nl_msg, IFLA_ADDRESS, VIR_MAC_BUFLEN, macaddress) < 0)
130         goto buffer_too_small;
131
132     if (ifname &&
133         nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
134         goto buffer_too_small;
135
136     if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
137         goto buffer_too_small;
138
139     if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
140         goto buffer_too_small;
141
142     if (macvlan_mode > 0) {
143         if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
144             goto buffer_too_small;
145
146         if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(macvlan_mode),
147                     &macvlan_mode) < 0)
148             goto buffer_too_small;
149
150         nla_nest_end(nl_msg, info_data);
151     }
152
153     nla_nest_end(nl_msg, linkinfo);
154
155     if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
156                           NETLINK_ROUTE, 0) < 0) {
157         goto cleanup;
158     }
159
160     if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
161         goto malformed_resp;
162
163     switch (resp->nlmsg_type) {
164     case NLMSG_ERROR:
165         err = (struct nlmsgerr *)NLMSG_DATA(resp);
166         if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
167             goto malformed_resp;
168
169         switch (err->error) {
170
171         case 0:
172             break;
173
174         case -EEXIST:
175             *retry = 1;
176             goto cleanup;
177
178         default:
179             virReportSystemError(-err->error,
180                                  _("error creating %s type of interface attach to %s"),
181                                  type, srcdev);
182             goto cleanup;
183         }
184         break;
185
186     case NLMSG_DONE:
187         break;
188
189     default:
190         goto malformed_resp;
191     }
192
193     rc = 0;
194  cleanup:
195     nlmsg_free(nl_msg);
196     VIR_FREE(resp);
197     return rc;
198
199  malformed_resp:
200     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
201                    _("malformed netlink response message"));
202     goto cleanup;
203
204  buffer_too_small:
205     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
206                    _("allocated netlink buffer is too small"));
207     goto cleanup;
208 }
209
210 /**
211  * virNetDevMacVLanDelete:
212  *
213  * @ifname: Name of the interface
214  *
215  * Tear down an interface with the given name.
216  *
217  * Returns 0 on success, -1 on fatal error.
218  */
219 int virNetDevMacVLanDelete(const char *ifname)
220 {
221     int rc = -1;
222     struct nlmsghdr *resp = NULL;
223     struct nlmsgerr *err;
224     struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
225     unsigned int recvbuflen;
226     struct nl_msg *nl_msg;
227
228     nl_msg = nlmsg_alloc_simple(RTM_DELLINK,
229                                 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
230     if (!nl_msg) {
231         virReportOOMError();
232         return -1;
233     }
234
235     if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
236         goto buffer_too_small;
237
238     if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
239         goto buffer_too_small;
240
241     if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
242                           NETLINK_ROUTE, 0) < 0) {
243         goto cleanup;
244     }
245
246     if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
247         goto malformed_resp;
248
249     switch (resp->nlmsg_type) {
250     case NLMSG_ERROR:
251         err = (struct nlmsgerr *)NLMSG_DATA(resp);
252         if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
253             goto malformed_resp;
254
255         if (err->error) {
256             virReportSystemError(-err->error,
257                                  _("error destroying %s interface"),
258                                  ifname);
259             goto cleanup;
260         }
261         break;
262
263     case NLMSG_DONE:
264         break;
265
266     default:
267         goto malformed_resp;
268     }
269
270     rc = 0;
271  cleanup:
272     nlmsg_free(nl_msg);
273     VIR_FREE(resp);
274     return rc;
275
276  malformed_resp:
277     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
278                    _("malformed netlink response message"));
279     goto cleanup;
280
281  buffer_too_small:
282     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
283                    _("allocated netlink buffer is too small"));
284     goto cleanup;
285 }
286
287
288 /**
289  * virNetDevMacVLanTapOpen:
290  * Open the macvtap's tap device.
291  * @ifname: Name of the macvtap interface
292  * @retries : Number of retries in case udev for example may need to be
293  *            waited for to create the tap chardev
294  * Returns negative value in case of error, the file descriptor otherwise.
295  */
296 static
297 int virNetDevMacVLanTapOpen(const char *ifname,
298                             int retries)
299 {
300     FILE *file;
301     char path[64];
302     int ifindex;
303     char tapname[50];
304     int tapfd;
305
306     if (snprintf(path, sizeof(path),
307                  "/sys/class/net/%s/ifindex", ifname) >= sizeof(path)) {
308         virReportSystemError(errno,
309                              "%s",
310                              _("buffer for ifindex path is too small"));
311         return -1;
312     }
313
314     file = fopen(path, "r");
315
316     if (!file) {
317         virReportSystemError(errno,
318                              _("cannot open macvtap file %s to determine "
319                                "interface index"), path);
320         return -1;
321     }
322
323     if (fscanf(file, "%d", &ifindex) != 1) {
324         virReportSystemError(errno,
325                              "%s", _("cannot determine macvtap's tap device "
326                              "interface index"));
327         VIR_FORCE_FCLOSE(file);
328         return -1;
329     }
330
331     VIR_FORCE_FCLOSE(file);
332
333     if (snprintf(tapname, sizeof(tapname),
334                  "/dev/tap%d", ifindex) >= sizeof(tapname)) {
335         virReportSystemError(errno,
336                              "%s",
337                              _("internal buffer for tap device is too small"));
338         return -1;
339     }
340
341     while (1) {
342         /* may need to wait for udev to be done */
343         tapfd = open(tapname, O_RDWR);
344         if (tapfd < 0 && retries > 0) {
345             retries--;
346             usleep(20000);
347             continue;
348         }
349         break;
350     }
351
352     if (tapfd < 0)
353         virReportSystemError(errno,
354                              _("cannot open macvtap tap device %s"),
355                              tapname);
356
357     return tapfd;
358 }
359
360
361 /**
362  * virNetDevMacVLanTapSetup:
363  * @tapfd: file descriptor of the macvtap tap
364  * @vnet_hdr: 1 to enable IFF_VNET_HDR, 0 to disable it
365  *
366  * Returns 0 on success, -1 in case of fatal error, error code otherwise.
367  *
368  * Turn the IFF_VNET_HDR flag, if requested and available, make sure
369  * it's off in the other cases.
370  * A fatal error is defined as the VNET_HDR flag being set but it cannot
371  * be turned off for some reason. This is reported with -1. Other fatal
372  * error is not being able to read the interface flags. In that case the
373  * macvtap device should not be used.
374  */
375 static int
376 virNetDevMacVLanTapSetup(int tapfd, int vnet_hdr)
377 {
378     unsigned int features;
379     struct ifreq ifreq;
380     short new_flags = 0;
381     int rc_on_fail = 0;
382     const char *errmsg = NULL;
383
384     memset(&ifreq, 0, sizeof(ifreq));
385
386     if (ioctl(tapfd, TUNGETIFF, &ifreq) < 0) {
387         virReportSystemError(errno, "%s",
388                              _("cannot get interface flags on macvtap tap"));
389         return -1;
390     }
391
392     new_flags = ifreq.ifr_flags;
393
394     if ((ifreq.ifr_flags & IFF_VNET_HDR) && !vnet_hdr) {
395         new_flags = ifreq.ifr_flags & ~IFF_VNET_HDR;
396         rc_on_fail = -1;
397         errmsg = _("cannot clean IFF_VNET_HDR flag on macvtap tap");
398     } else if ((ifreq.ifr_flags & IFF_VNET_HDR) == 0 && vnet_hdr) {
399         if (ioctl(tapfd, TUNGETFEATURES, &features) < 0) {
400             virReportSystemError(errno, "%s",
401                    _("cannot get feature flags on macvtap tap"));
402             return -1;
403         }
404         if ((features & IFF_VNET_HDR)) {
405             new_flags = ifreq.ifr_flags | IFF_VNET_HDR;
406             errmsg = _("cannot set IFF_VNET_HDR flag on macvtap tap");
407         }
408     }
409
410     if (new_flags != ifreq.ifr_flags) {
411         ifreq.ifr_flags = new_flags;
412         if (ioctl(tapfd, TUNSETIFF, &ifreq) < 0) {
413             virReportSystemError(errno, "%s", errmsg);
414             return rc_on_fail;
415         }
416     }
417
418     return 0;
419 }
420
421
422 static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = {
423     [VIR_NETDEV_MACVLAN_MODE_VEPA] = MACVLAN_MODE_VEPA,
424     [VIR_NETDEV_MACVLAN_MODE_PRIVATE] = MACVLAN_MODE_PRIVATE,
425     [VIR_NETDEV_MACVLAN_MODE_BRIDGE] = MACVLAN_MODE_BRIDGE,
426     [VIR_NETDEV_MACVLAN_MODE_PASSTHRU] = MACVLAN_MODE_PASSTHRU,
427 };
428
429 /* Struct to hold the state and configuration of a 802.1qbg port */
430 struct virNetlinkCallbackData {
431     char *cr_ifname;
432     virNetDevVPortProfilePtr virtPortProfile;
433     virMacAddr macaddress;
434     char *linkdev;
435     int vf;
436     unsigned char vmuuid[VIR_UUID_BUFLEN];
437     virNetDevVPortProfileOp vmOp;
438     unsigned int linkState;
439 };
440
441 typedef struct virNetlinkCallbackData *virNetlinkCallbackDataPtr;
442
443 # define INSTANCE_STRLEN 36
444
445 static int instance2str(const unsigned char *p, char *dst, size_t size)
446 {
447     if (dst && size > INSTANCE_STRLEN) {
448         snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
449                  "%02x%02x-%02x%02x%02x%02x%02x%02x",
450                  p[0], p[1], p[2], p[3],
451                  p[4], p[5], p[6], p[7],
452                  p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
453         return 0;
454     }
455     return -1;
456 }
457
458 # define LLDPAD_PID_FILE  "/var/run/lldpad.pid"
459 # define VIRIP_PID_FILE   "/var/run/virip.pid"
460
461 /**
462  * virNetDevMacVLanVPortProfileCallback:
463  *
464  * @hdr: The buffer containing the received netlink header + payload
465  * @length: The length of the received netlink message.
466  * @peer: The netling sockaddr containing the peer information
467  * @handled: Contains information if the message has been replied to yet
468  * @opaque: Contains vital information regarding the associated vm an interface
469  *
470  * This function is called when a netlink message is received. The function
471  * reads the message and responds if it is pertinent to the running VMs
472  * network interface.
473  */
474
475 static void
476 virNetDevMacVLanVPortProfileCallback(struct nlmsghdr *hdr,
477                                      unsigned int length,
478                                      struct sockaddr_nl *peer,
479                                      bool *handled,
480                                      void *opaque)
481 {
482    struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = {
483        [IFLA_VF_MAC] = {.minlen = sizeof(struct ifla_vf_mac),
484                         .maxlen = sizeof(struct ifla_vf_mac)},
485        [IFLA_VF_VLAN] = {.minlen = sizeof(struct ifla_vf_vlan),
486                          .maxlen = sizeof(struct ifla_vf_vlan)},
487     };
488
489     struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = {
490         [IFLA_PORT_RESPONSE] = {.type = NLA_U16},
491     };
492
493     struct nlattr *tb[IFLA_MAX + 1], *tb3[IFLA_PORT_MAX + 1],
494         *tb_vfinfo[IFLA_VF_MAX + 1], *tb_vfinfo_list;
495
496     struct ifinfomsg ifinfo;
497     void *data;
498     int rem;
499     char *ifname;
500     bool indicate = false;
501     virNetlinkCallbackDataPtr calld = opaque;
502     pid_t lldpad_pid = 0;
503     pid_t virip_pid = 0;
504     char macaddr[VIR_MAC_STRING_BUFLEN];
505
506     data = nlmsg_data(hdr);
507
508     /* Quickly decide if we want this or not */
509
510     if (virPidFileReadPath(LLDPAD_PID_FILE, &lldpad_pid) < 0)
511         return;
512
513     ignore_value(virPidFileReadPath(VIRIP_PID_FILE, &virip_pid));
514
515     if (hdr->nlmsg_pid != lldpad_pid && hdr->nlmsg_pid != virip_pid)
516         return; /* we only care for lldpad and virip messages */
517     if (hdr->nlmsg_type != RTM_SETLINK)
518         return; /* we only care for RTM_SETLINK */
519     if (*handled)
520         return; /* if it has been handled - dont handle again */
521
522     /* DEBUG start */
523     VIR_INFO("netlink message nl_sockaddr: %p len: %d", peer, length);
524     VIR_DEBUG("nlmsg_type  = 0x%02x", hdr->nlmsg_type);
525     VIR_DEBUG("nlmsg_len   = 0x%04x", hdr->nlmsg_len);
526     VIR_DEBUG("nlmsg_pid   = %d", hdr->nlmsg_pid);
527     VIR_DEBUG("nlmsg_seq   = 0x%08x", hdr->nlmsg_seq);
528     VIR_DEBUG("nlmsg_flags = 0x%04x", hdr->nlmsg_flags);
529
530     VIR_DEBUG("lldpad pid  = %d", lldpad_pid);
531
532     switch (hdr->nlmsg_type) {
533     case RTM_NEWLINK:
534     case RTM_DELLINK:
535     case RTM_SETLINK:
536     case RTM_GETLINK:
537         VIR_DEBUG(" IFINFOMSG\n");
538         VIR_DEBUG("        ifi_family = 0x%02x\n",
539             ((struct ifinfomsg *)data)->ifi_family);
540         VIR_DEBUG("        ifi_type   = 0x%x\n",
541             ((struct ifinfomsg *)data)->ifi_type);
542         VIR_DEBUG("        ifi_index  = %i\n",
543             ((struct ifinfomsg *)data)->ifi_index);
544         VIR_DEBUG("        ifi_flags  = 0x%04x\n",
545             ((struct ifinfomsg *)data)->ifi_flags);
546         VIR_DEBUG("        ifi_change = 0x%04x\n",
547             ((struct ifinfomsg *)data)->ifi_change);
548     }
549     /* DEBUG end */
550
551     /* Parse netlink message assume a setlink with vfports */
552     memcpy(&ifinfo, NLMSG_DATA(hdr), sizeof(ifinfo));
553     VIR_DEBUG("family:%#x type:%#x index:%d flags:%#x change:%#x",
554         ifinfo.ifi_family, ifinfo.ifi_type, ifinfo.ifi_index,
555         ifinfo.ifi_flags, ifinfo.ifi_change);
556     if (nlmsg_parse(hdr, sizeof(ifinfo),
557         (struct nlattr **)&tb, IFLA_MAX, NULL)) {
558         VIR_DEBUG("error parsing request...");
559         return;
560     }
561
562     if (tb[IFLA_VFINFO_LIST]) {
563         VIR_DEBUG("FOUND IFLA_VFINFO_LIST!");
564
565         nla_for_each_nested(tb_vfinfo_list, tb[IFLA_VFINFO_LIST], rem) {
566             if (nla_type(tb_vfinfo_list) != IFLA_VF_INFO) {
567                 VIR_DEBUG("nested parsing of"
568                     "IFLA_VFINFO_LIST failed.");
569                 return;
570             }
571             if (nla_parse_nested(tb_vfinfo, IFLA_VF_MAX,
572                 tb_vfinfo_list, ifla_vf_policy)) {
573                 VIR_DEBUG("nested parsing of "
574                     "IFLA_VF_INFO failed.");
575                 return;
576             }
577         }
578
579         if (tb_vfinfo[IFLA_VF_MAC]) {
580             struct ifla_vf_mac *mac = RTA_DATA(tb_vfinfo[IFLA_VF_MAC]);
581             unsigned char *m = mac->mac;
582
583             VIR_DEBUG("IFLA_VF_MAC = %2x:%2x:%2x:%2x:%2x:%2x",
584                       m[0], m[1], m[2], m[3], m[4], m[5]);
585
586             if (virMacAddrCmpRaw(&calld->macaddress, mac->mac))
587             {
588                 /* Repeat the same check for a broadcast mac */
589                 size_t i;
590
591                 for (i = 0; i < VIR_MAC_BUFLEN; i++) {
592                     if (calld->macaddress.addr[i] != 0xff) {
593                         VIR_DEBUG("MAC address match failed (wasn't broadcast)");
594                         return;
595                     }
596                 }
597             }
598         }
599
600         if (tb_vfinfo[IFLA_VF_VLAN]) {
601             struct ifla_vf_vlan *vlan = RTA_DATA(tb_vfinfo[IFLA_VF_VLAN]);
602
603             VIR_DEBUG("IFLA_VF_VLAN = %d", vlan->vlan);
604         }
605     }
606
607     if (tb[IFLA_IFNAME]) {
608         ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
609         VIR_DEBUG("IFLA_IFNAME = %s\n", ifname);
610     }
611
612     if (tb[IFLA_OPERSTATE]) {
613         rem = *(unsigned short *)RTA_DATA(tb[IFLA_OPERSTATE]);
614         VIR_DEBUG("IFLA_OPERSTATE = %d\n", rem);
615     }
616
617     if (tb[IFLA_VF_PORTS]) {
618         struct nlattr *tb_vf_ports;
619
620         VIR_DEBUG("found IFLA_VF_PORTS\n");
621         nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
622
623             VIR_DEBUG("iterating\n");
624             if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
625                 VIR_DEBUG("not a IFLA_VF_PORT. skipping\n");
626                 continue;
627             }
628             if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
629                 ifla_port_policy)) {
630                 VIR_DEBUG("nested parsing on level 2"
631                           " failed.");
632             }
633             if (tb3[IFLA_PORT_VF]) {
634                 VIR_DEBUG("IFLA_PORT_VF = %d",
635                           *(uint32_t *) (RTA_DATA(tb3[IFLA_PORT_VF])));
636             }
637             if (tb3[IFLA_PORT_PROFILE]) {
638                 VIR_DEBUG("IFLA_PORT_PROFILE = %s",
639                           (char *) RTA_DATA(tb3[IFLA_PORT_PROFILE]));
640             }
641
642             if (tb3[IFLA_PORT_VSI_TYPE]) {
643                 struct ifla_port_vsi *pvsi;
644                 int tid = 0;
645
646                 pvsi = (struct ifla_port_vsi *)
647                     RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
648                 tid = ((pvsi->vsi_type_id[2] << 16) |
649                        (pvsi->vsi_type_id[1] << 8) |
650                        pvsi->vsi_type_id[0]);
651
652                 VIR_DEBUG("mgr_id: %d", pvsi->vsi_mgr_id);
653                 VIR_DEBUG("type_id: %d", tid);
654                 VIR_DEBUG("type_version: %d",
655                           pvsi->vsi_type_version);
656             }
657
658             if (tb3[IFLA_PORT_INSTANCE_UUID]) {
659                 char instance[INSTANCE_STRLEN + 2];
660                 unsigned char *uuid;
661
662                 uuid = (unsigned char *)
663                     RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
664                 instance2str(uuid, instance, sizeof(instance));
665                 VIR_DEBUG("IFLA_PORT_INSTANCE_UUID = %s\n",
666                           instance);
667             }
668
669             if (tb3[IFLA_PORT_REQUEST]) {
670                 uint8_t req = *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]);
671                 VIR_DEBUG("IFLA_PORT_REQUEST = %d", req);
672
673                 if (req == PORT_REQUEST_DISASSOCIATE) {
674                     VIR_DEBUG("Set dissaccociated.");
675                     indicate = true;
676                 }
677             }
678
679             if (tb3[IFLA_PORT_RESPONSE]) {
680                 VIR_DEBUG("IFLA_PORT_RESPONSE = %d\n", *(uint16_t *)
681                     RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
682             }
683         }
684     }
685
686     if (!indicate) {
687         return;
688     }
689
690     VIR_INFO("Re-send 802.1qbg associate request:");
691     VIR_INFO("  if: %s", calld->cr_ifname);
692     VIR_INFO("  lf: %s", calld->linkdev);
693     VIR_INFO(" mac: %s", virMacAddrFormat(&calld->macaddress, macaddr));
694     ignore_value(virNetDevVPortProfileAssociate(calld->cr_ifname,
695                                                 calld->virtPortProfile,
696                                                 &calld->macaddress,
697                                                 calld->linkdev,
698                                                 calld->vf,
699                                                 calld->vmuuid,
700                                                 calld->vmOp, true));
701     *handled = true;
702     return;
703 }
704
705 /**
706  * virNetlinkCallbackDataFree
707  *
708  * @calld: pointer to a virNetlinkCallbackData object to free
709  *
710  * This function frees all the data associated with a virNetlinkCallbackData object
711  * as well as the object itself. If called with NULL, it does nothing.
712  *
713  * Returns nothing.
714  */
715 static void
716 virNetlinkCallbackDataFree(virNetlinkCallbackDataPtr calld)
717 {
718     if (calld) {
719         VIR_FREE(calld->cr_ifname);
720         VIR_FREE(calld->virtPortProfile);
721         VIR_FREE(calld->linkdev);
722     }
723     VIR_FREE(calld);
724 }
725
726 /**
727  * virNetDevMacVLanVPortProfileDestroyCallback:
728  *
729  * @watch: watch whose handle to remove
730  * @macaddr: macaddr whose handle to remove
731  * @opaque: Contains vital information regarding the associated vm
732  *
733  * This function is called when a netlink message handler is terminated.
734  * The function frees locally allocated data referenced in the opaque
735  * data, and the opaque object itself.
736  */
737 static void
738 virNetDevMacVLanVPortProfileDestroyCallback(int watch ATTRIBUTE_UNUSED,
739                                             const virMacAddr *macaddr ATTRIBUTE_UNUSED,
740                                             void *opaque)
741 {
742     virNetlinkCallbackDataFree((virNetlinkCallbackDataPtr)opaque);
743 }
744
745 int
746 virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
747                                              const virMacAddr *macaddress,
748                                              const char *linkdev,
749                                              const unsigned char *vmuuid,
750                                              virNetDevVPortProfilePtr virtPortProfile,
751                                              virNetDevVPortProfileOp vmOp)
752 {
753     virNetlinkCallbackDataPtr calld = NULL;
754
755     if (virtPortProfile && virNetlinkEventServiceIsRunning(NETLINK_ROUTE)) {
756         if (VIR_ALLOC(calld) < 0)
757             goto error;
758         if (VIR_STRDUP(calld->cr_ifname, ifname) < 0)
759             goto error;
760         if (VIR_ALLOC(calld->virtPortProfile) < 0)
761             goto error;
762         memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
763         virMacAddrSet(&calld->macaddress, macaddress);
764         if (VIR_STRDUP(calld->linkdev, linkdev) < 0)
765             goto error;
766         memcpy(calld->vmuuid, vmuuid, sizeof(calld->vmuuid));
767
768         calld->vmOp = vmOp;
769
770         if (virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
771                                      virNetDevMacVLanVPortProfileDestroyCallback,
772                                      calld, macaddress, NETLINK_ROUTE) < 0)
773             goto error;
774     }
775
776     return 0;
777
778  error:
779     virNetlinkCallbackDataFree(calld);
780     return -1;
781 }
782
783
784 /**
785  * virNetDevMacVLanCreateWithVPortProfile:
786  * Create an instance of a macvtap device and open its tap character
787  * device.
788  * @tgifname: Interface name that the macvtap is supposed to have. May
789  *    be NULL if this function is supposed to choose a name
790  * @macaddress: The MAC address for the macvtap device
791  * @linkdev: The interface name of the NIC to connect to the external bridge
792  * @mode: int describing the mode for 'bridge', 'vepa', 'private' or 'passthru'.
793  * @vnet_hdr: 1 to enable IFF_VNET_HDR, 0 to disable it
794  * @vmuuid: The UUID of the VM the macvtap belongs to
795  * @virtPortProfile: pointer to object holding the virtual port profile data
796  * @res_ifname: Pointer to a string pointer where the actual name of the
797  *     interface will be stored into if everything succeeded. It is up
798  *     to the caller to free the string.
799  *
800  * Returns file descriptor of the tap device in case of success with @withTap,
801  * otherwise returns 0; returns -1 on error.
802  */
803 int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
804                                            const virMacAddr *macaddress,
805                                            const char *linkdev,
806                                            virNetDevMacVLanMode mode,
807                                            bool withTap,
808                                            int vnet_hdr,
809                                            const unsigned char *vmuuid,
810                                            virNetDevVPortProfilePtr virtPortProfile,
811                                            char **res_ifname,
812                                            virNetDevVPortProfileOp vmOp,
813                                            char *stateDir,
814                                            virNetDevBandwidthPtr bandwidth)
815 {
816     const char *type = withTap ? "macvtap" : "macvlan";
817     const char *prefix = withTap ? MACVTAP_NAME_PREFIX : MACVLAN_NAME_PREFIX;
818     const char *pattern = withTap ? MACVTAP_NAME_PATTERN : MACVLAN_NAME_PATTERN;
819     int c, rc;
820     char ifname[IFNAMSIZ];
821     int retries, do_retry = 0;
822     uint32_t macvtapMode;
823     const char *cr_ifname = NULL;
824     int ret;
825     int vf = -1;
826
827     macvtapMode = modeMap[mode];
828
829     *res_ifname = NULL;
830
831     VIR_DEBUG("%s: VM OPERATION: %s", __FUNCTION__, virNetDevVPortProfileOpTypeToString(vmOp));
832
833     /** Note: When using PASSTHROUGH mode with MACVTAP devices the link
834      * device's MAC address must be set to the VMs MAC address. In
835      * order to not confuse the first switch or bridge in line this MAC
836      * address must be reset when the VM is shut down.
837      * This is especially important when using SRIOV capable cards that
838      * emulate their switch in firmware.
839      */
840     if (mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) {
841         if (virNetDevReplaceMacAddress(linkdev, macaddress, stateDir) < 0)
842             return -1;
843     }
844
845     if (tgifname) {
846         if ((ret = virNetDevExists(tgifname)) < 0)
847             return -1;
848
849         if (ret) {
850             if (STRPREFIX(tgifname, prefix)) {
851                 goto create_name;
852             }
853             virReportSystemError(EEXIST,
854                                  _("Unable to create macvlan device %s"), tgifname);
855             return -1;
856         }
857         cr_ifname = tgifname;
858         rc = virNetDevMacVLanCreate(tgifname, type, macaddress, linkdev,
859                                     macvtapMode, &do_retry);
860         if (rc < 0)
861             return -1;
862     } else {
863  create_name:
864         retries = 5;
865         virMutexLock(&virNetDevMacVLanCreateMutex);
866         for (c = 0; c < 8192; c++) {
867             snprintf(ifname, sizeof(ifname), pattern, c);
868             if ((ret = virNetDevExists(ifname)) < 0) {
869                 virMutexUnlock(&virNetDevMacVLanCreateMutex);
870                 return -1;
871             }
872             if (!ret) {
873                 rc = virNetDevMacVLanCreate(ifname, type, macaddress, linkdev,
874                                             macvtapMode, &do_retry);
875                 if (rc == 0) {
876                     cr_ifname = ifname;
877                     break;
878                 }
879
880                 if (do_retry && --retries)
881                     continue;
882                 break;
883             }
884         }
885
886         virMutexUnlock(&virNetDevMacVLanCreateMutex);
887         if (!cr_ifname)
888             return -1;
889     }
890
891     if (virNetDevVPortProfileAssociate(cr_ifname,
892                                        virtPortProfile,
893                                        macaddress,
894                                        linkdev,
895                                        vf,
896                                        vmuuid, vmOp, false) < 0) {
897         rc = -1;
898         goto link_del_exit;
899     }
900
901     if (virNetDevSetOnline(cr_ifname, true) < 0) {
902         rc = -1;
903         goto disassociate_exit;
904     }
905
906     if (withTap) {
907         if ((rc = virNetDevMacVLanTapOpen(cr_ifname, 10)) < 0)
908             goto disassociate_exit;
909
910         if (virNetDevMacVLanTapSetup(rc, vnet_hdr) < 0) {
911             VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
912             goto disassociate_exit;
913         }
914         if (VIR_STRDUP(*res_ifname, cr_ifname) < 0) {
915             VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
916             goto disassociate_exit;
917         }
918     } else {
919         if (VIR_STRDUP(*res_ifname, cr_ifname) < 0)
920             goto disassociate_exit;
921         rc = 0;
922     }
923
924     if (virNetDevBandwidthSet(cr_ifname, bandwidth, false) < 0) {
925         virReportError(VIR_ERR_INTERNAL_ERROR,
926                        _("cannot set bandwidth limits on %s"),
927                        cr_ifname);
928         if (withTap)
929             VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
930         else
931             rc = -1;
932         goto disassociate_exit;
933     }
934
935     if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
936         vmOp == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) {
937         /* Only directly register upon a create or restore (restarting
938          * a saved image) - migration and libvirtd restart are handled
939          * elsewhere.
940          */
941         if (virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
942                                                          linkdev, vmuuid,
943                                                          virtPortProfile,
944                                                          vmOp) < 0)
945         goto disassociate_exit;
946     }
947
948     return rc;
949
950  disassociate_exit:
951     ignore_value(virNetDevVPortProfileDisassociate(cr_ifname,
952                                                    virtPortProfile,
953                                                    macaddress,
954                                                    linkdev,
955                                                    vf,
956                                                    vmOp));
957
958  link_del_exit:
959     ignore_value(virNetDevMacVLanDelete(cr_ifname));
960
961     return rc;
962 }
963
964
965 /**
966  * virNetDevMacVLanDeleteWithVPortProfile:
967  * @ifname : The name of the macvtap interface
968  * @linkdev: The interface name of the NIC to connect to the external bridge
969  * @virtPortProfile: pointer to object holding the virtual port profile data
970  *
971  * Delete an interface given its name. Disassociate
972  * it with the switch if port profile parameters
973  * were provided.
974  */
975 int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
976                                            const virMacAddr *macaddr,
977                                            const char *linkdev,
978                                            int mode,
979                                            virNetDevVPortProfilePtr virtPortProfile,
980                                            char *stateDir)
981 {
982     int ret = 0;
983     int vf = -1;
984
985     if (mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) {
986         ignore_value(virNetDevRestoreMacAddress(linkdev, stateDir));
987     }
988
989     if (ifname) {
990         if (virNetDevVPortProfileDisassociate(ifname,
991                                               virtPortProfile,
992                                               macaddr,
993                                               linkdev,
994                                               vf,
995                                               VIR_NETDEV_VPORT_PROFILE_OP_DESTROY) < 0)
996             ret = -1;
997         if (virNetDevMacVLanDelete(ifname) < 0)
998             ret = -1;
999     }
1000
1001     virNetlinkEventRemoveClient(0, macaddr, NETLINK_ROUTE);
1002
1003     return ret;
1004 }
1005
1006 /**
1007  * virNetDevMacVLanRestartWithVPortProfile:
1008  * Register a port profile callback handler for a VM that
1009  * is already running
1010  * .
1011  * @cr_ifname: Interface name that the macvtap has.
1012  * @macaddress: The MAC address for the macvtap device
1013  * @linkdev: The interface name of the NIC to connect to the external bridge
1014  * @vmuuid: The UUID of the VM the macvtap belongs to
1015  * @virtPortProfile: pointer to object holding the virtual port profile data
1016  * @vmOp: Operation to use during setup of the association
1017  *
1018  * Returns 0; returns -1 on error.
1019  */
1020 int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
1021                                            const virMacAddr *macaddress,
1022                                            const char *linkdev,
1023                                            const unsigned char *vmuuid,
1024                                            virNetDevVPortProfilePtr virtPortProfile,
1025                                            virNetDevVPortProfileOp vmOp)
1026 {
1027     int rc = 0;
1028
1029     rc = virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
1030                                                       linkdev, vmuuid,
1031                                                       virtPortProfile, vmOp);
1032     if (rc < 0)
1033         goto error;
1034
1035     ignore_value(virNetDevVPortProfileAssociate(cr_ifname,
1036                                                 virtPortProfile,
1037                                                 macaddress,
1038                                                 linkdev,
1039                                                 -1,
1040                                                 vmuuid,
1041                                                 vmOp, true));
1042
1043  error:
1044     return rc;
1045
1046 }
1047
1048 #else /* ! WITH_MACVTAP */
1049 int virNetDevMacVLanCreate(const char *ifname ATTRIBUTE_UNUSED,
1050                            const char *type ATTRIBUTE_UNUSED,
1051                            const virMacAddr *macaddress ATTRIBUTE_UNUSED,
1052                            const char *srcdev ATTRIBUTE_UNUSED,
1053                            uint32_t macvlan_mode ATTRIBUTE_UNUSED,
1054                            int *retry ATTRIBUTE_UNUSED)
1055 {
1056     virReportSystemError(ENOSYS, "%s",
1057                          _("Cannot create macvlan devices on this platform"));
1058     return -1;
1059 }
1060
1061 int virNetDevMacVLanDelete(const char *ifname ATTRIBUTE_UNUSED)
1062 {
1063     virReportSystemError(ENOSYS, "%s",
1064                          _("Cannot create macvlan devices on this platform"));
1065     return -1;
1066 }
1067
1068 int virNetDevMacVLanCreateWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
1069                                            const virMacAddr *macaddress ATTRIBUTE_UNUSED,
1070                                            const char *linkdev ATTRIBUTE_UNUSED,
1071                                            virNetDevMacVLanMode mode ATTRIBUTE_UNUSED,
1072                                            bool withTap ATTRIBUTE_UNUSED,
1073                                            int vnet_hdr ATTRIBUTE_UNUSED,
1074                                            const unsigned char *vmuuid ATTRIBUTE_UNUSED,
1075                                            virNetDevVPortProfilePtr virtPortProfile ATTRIBUTE_UNUSED,
1076                                            char **res_ifname ATTRIBUTE_UNUSED,
1077                                            virNetDevVPortProfileOp vmop ATTRIBUTE_UNUSED,
1078                                            char *stateDir ATTRIBUTE_UNUSED,
1079                                            virNetDevBandwidthPtr bandwidth ATTRIBUTE_UNUSED)
1080 {
1081     virReportSystemError(ENOSYS, "%s",
1082                          _("Cannot create macvlan devices on this platform"));
1083     return -1;
1084 }
1085
1086 int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
1087                                            const virMacAddr *macaddress ATTRIBUTE_UNUSED,
1088                                            const char *linkdev ATTRIBUTE_UNUSED,
1089                                            int mode ATTRIBUTE_UNUSED,
1090                                            virNetDevVPortProfilePtr virtPortProfile ATTRIBUTE_UNUSED,
1091                                            char *stateDir ATTRIBUTE_UNUSED)
1092 {
1093     virReportSystemError(ENOSYS, "%s",
1094                          _("Cannot create macvlan devices on this platform"));
1095     return -1;
1096 }
1097
1098 int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname ATTRIBUTE_UNUSED,
1099                                            const virMacAddr *macaddress ATTRIBUTE_UNUSED,
1100                                            const char *linkdev ATTRIBUTE_UNUSED,
1101                                            const unsigned char *vmuuid ATTRIBUTE_UNUSED,
1102                                            virNetDevVPortProfilePtr virtPortProfile ATTRIBUTE_UNUSED,
1103                                            virNetDevVPortProfileOp vmOp ATTRIBUTE_UNUSED)
1104 {
1105     virReportSystemError(ENOSYS, "%s",
1106                          _("Cannot create macvlan devices on this platform"));
1107     return -1;
1108 }
1109
1110 int virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname ATTRIBUTE_UNUSED,
1111                                              const virMacAddr *macaddress ATTRIBUTE_UNUSED,
1112                                              const char *linkdev ATTRIBUTE_UNUSED,
1113                                              const unsigned char *vmuuid ATTRIBUTE_UNUSED,
1114                                              virNetDevVPortProfilePtr virtPortProfile ATTRIBUTE_UNUSED,
1115                                              virNetDevVPortProfileOp vmOp ATTRIBUTE_UNUSED)
1116 {
1117     virReportSystemError(ENOSYS, "%s",
1118                          _("Cannot create macvlan devices on this platform"));
1119     return -1;
1120 }
1121 #endif /* ! WITH_MACVTAP */