|
15 | 15 |
|
16 | 16 | VIR_LOG_INIT("ch.ch_interface"); |
17 | 17 |
|
| 18 | +/* chInterfaceEthernetConnect: |
| 19 | + * @def: the definition of the VM |
| 20 | + * @driver: ch driver data |
| 21 | + * @net: pointer to the VM's interface description |
| 22 | + * @tapfd: array of file descriptor return value for the new device |
| 23 | + * @tapfdsize: number of file descriptors in @tapfd |
| 24 | + * |
| 25 | + * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET |
| 26 | + * (i.e. if the connection is made with a tap device) |
| 27 | + */ |
| 28 | +int |
| 29 | +chInterfaceEthernetConnect(virDomainDefPtr def, |
| 30 | + virCHDriverPtr driver, |
| 31 | + virDomainNetDefPtr net, |
| 32 | + int *tapfd, |
| 33 | + size_t tapfdSize) |
| 34 | +{ |
| 35 | + virMacAddr tapmac; |
| 36 | + int ret = -1; |
| 37 | + unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP; |
| 38 | + bool template_ifname = false; |
| 39 | + virCHDriverConfigPtr cfg = virCHDriverGetConfig(driver); |
| 40 | + const char *tunpath = "/dev/net/tun"; |
| 41 | + const char *auditdev = tunpath; |
| 42 | + |
| 43 | + if (net->backend.tap) { |
| 44 | + tunpath = net->backend.tap; |
| 45 | + if (!driver->privileged) { |
| 46 | + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", |
| 47 | + _("cannot use custom tap device in session mode")); |
| 48 | + goto cleanup; |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + if (virDomainNetIsVirtioModel(net)) |
| 53 | + tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; |
| 54 | + |
| 55 | + if (net->managed_tap == VIR_TRISTATE_BOOL_NO) { |
| 56 | + if (!net->ifname) { |
| 57 | + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", |
| 58 | + _("target dev must be supplied when managed='no'")); |
| 59 | + goto cleanup; |
| 60 | + } |
| 61 | + if (virNetDevExists(net->ifname) != 1) { |
| 62 | + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", |
| 63 | + _("target managed='no' but specified dev doesn't exist")); |
| 64 | + goto cleanup; |
| 65 | + } |
| 66 | + if (virNetDevMacVLanIsMacvtap(net->ifname)) { |
| 67 | + auditdev = net->ifname; |
| 68 | + if (virNetDevMacVLanTapOpen(net->ifname, tapfd, tapfdSize) < 0) |
| 69 | + goto cleanup; |
| 70 | + if (virNetDevMacVLanTapSetup(tapfd, tapfdSize, |
| 71 | + virDomainNetIsVirtioModel(net)) < 0) { |
| 72 | + goto cleanup; |
| 73 | + } |
| 74 | + } else { |
| 75 | + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize, |
| 76 | + tap_create_flags) < 0) |
| 77 | + goto cleanup; |
| 78 | + } |
| 79 | + } else { |
| 80 | + if (!net->ifname || |
| 81 | + STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) || |
| 82 | + strchr(net->ifname, '%')) { |
| 83 | + g_free(net->ifname); |
| 84 | + net->ifname = g_strdup(VIR_NET_GENERATED_TAP_PREFIX "%d"); |
| 85 | + /* avoid exposing vnet%d in getXMLDesc or error outputs */ |
| 86 | + template_ifname = true; |
| 87 | + } |
| 88 | + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize, |
| 89 | + tap_create_flags) < 0) { |
| 90 | + goto cleanup; |
| 91 | + } |
| 92 | + |
| 93 | + /* The tap device's MAC address cannot match the MAC address |
| 94 | + * used by the guest. This results in "received packet on |
| 95 | + * vnetX with own address as source address" error logs from |
| 96 | + * the kernel. |
| 97 | + */ |
| 98 | + virMacAddrSet(&tapmac, &net->mac); |
| 99 | + if (tapmac.addr[0] == 0xFE) |
| 100 | + tapmac.addr[0] = 0xFA; |
| 101 | + else |
| 102 | + tapmac.addr[0] = 0xFE; |
| 103 | + |
| 104 | + if (virNetDevSetMAC(net->ifname, &tapmac) < 0) |
| 105 | + goto cleanup; |
| 106 | + |
| 107 | + if (virNetDevSetOnline(net->ifname, true) < 0) |
| 108 | + goto cleanup; |
| 109 | + } |
| 110 | + |
| 111 | + if (net->script && |
| 112 | + virNetDevRunEthernetScript(net->ifname, net->script) < 0) |
| 113 | + goto cleanup; |
| 114 | + |
| 115 | + if (cfg->macFilter && |
| 116 | + ebtablesAddForwardAllowIn(driver->ebtables, |
| 117 | + net->ifname, |
| 118 | + &net->mac) < 0) |
| 119 | + goto cleanup; |
| 120 | + |
| 121 | + if (net->filter && |
| 122 | + virDomainConfNWFilterInstantiate(def->name, def->uuid, net, false) < 0) { |
| 123 | + goto cleanup; |
| 124 | + } |
| 125 | + |
| 126 | + virDomainAuditNetDevice(def, net, auditdev, true); |
| 127 | + |
| 128 | + ret = 0; |
| 129 | + |
| 130 | + cleanup: |
| 131 | + if (ret < 0) { |
| 132 | + size_t i; |
| 133 | + |
| 134 | + virDomainAuditNetDevice(def, net, auditdev, false); |
| 135 | + for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++) |
| 136 | + VIR_FORCE_CLOSE(tapfd[i]); |
| 137 | + if (template_ifname) |
| 138 | + g_free(net->ifname); |
| 139 | + } |
| 140 | + virObjectUnref(cfg); |
| 141 | + |
| 142 | + return ret; |
| 143 | +} |
| 144 | + |
18 | 145 | /* chInterfaceBridgeConnect: |
19 | 146 | * @def: the definition of the VM |
20 | 147 | * @driver: qemu driver data |
|
0 commit comments