return NULL;
}
+static void qemudRandomMAC(struct qemud_vm_net_def *net) {
+ net->mac[0] = 0x52;
+ net->mac[1] = 0x54;
+ net->mac[2] = 0x00;
+ net->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ net->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ net->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+}
+
/* Parse the XML definition for a network interface */
static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *server,
xmlChar *macaddr = NULL;
xmlChar *type = NULL;
xmlChar *network = NULL;
- xmlChar *tapifname = NULL;
+ xmlChar *bridge = NULL;
+ xmlChar *ifname = NULL;
+ xmlChar *script = NULL;
+ xmlChar *address = NULL;
+ xmlChar *port = NULL;
if (!net) {
qemudReportError(server, VIR_ERR_NO_MEMORY, "net");
if (type != NULL) {
if (xmlStrEqual(type, BAD_CAST "user"))
net->type = QEMUD_NET_USER;
- else if (xmlStrEqual(type, BAD_CAST "tap"))
- net->type = QEMUD_NET_TAP;
+ else if (xmlStrEqual(type, BAD_CAST "ethernet"))
+ net->type = QEMUD_NET_ETHERNET;
else if (xmlStrEqual(type, BAD_CAST "server"))
net->type = QEMUD_NET_SERVER;
else if (xmlStrEqual(type, BAD_CAST "client"))
net->type = QEMUD_NET_MCAST;
else if (xmlStrEqual(type, BAD_CAST "network"))
net->type = QEMUD_NET_NETWORK;
- /*
- else if (xmlStrEqual(type, BAD_CAST "vde"))
- typ = QEMUD_NET_VDE;
- */
+ else if (xmlStrEqual(type, BAD_CAST "bridge"))
+ net->type = QEMUD_NET_BRIDGE;
else
net->type = QEMUD_NET_USER;
xmlFree(type);
(net->type == QEMUD_NET_NETWORK) &&
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
network = xmlGetProp(cur, BAD_CAST "network");
- } else if ((tapifname == NULL) &&
- (net->type == QEMUD_NET_NETWORK) &&
- xmlStrEqual(cur->name, BAD_CAST "tap")) {
- tapifname = xmlGetProp(cur, BAD_CAST "ifname");
+ } else if ((network == NULL) &&
+ (net->type == QEMUD_NET_BRIDGE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ bridge = xmlGetProp(cur, BAD_CAST "dev");
+ } else if ((network == NULL) &&
+ ((net->type == QEMUD_NET_SERVER) ||
+ (net->type == QEMUD_NET_CLIENT) ||
+ (net->type == QEMUD_NET_MCAST)) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ address = xmlGetProp(cur, BAD_CAST "address");
+ port = xmlGetProp(cur, BAD_CAST "port");
+ } else if ((ifname == NULL) &&
+ ((net->type == QEMUD_NET_NETWORK) ||
+ (net->type == QEMUD_NET_ETHERNET) ||
+ (net->type == QEMUD_NET_BRIDGE)) &&
+ xmlStrEqual(cur->name, BAD_CAST "target")) {
+ ifname = xmlGetProp(cur, BAD_CAST "dev");
+ } else if ((script == NULL) &&
+ (net->type == QEMUD_NET_ETHERNET) &&
+ xmlStrEqual(cur->name, BAD_CAST "script")) {
+ script = xmlGetProp(cur, BAD_CAST "path");
}
}
cur = cur->next;
}
- net->vlan = 0;
-
if (macaddr) {
unsigned int mac[6];
sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
net->mac[5] = mac[5];
xmlFree(macaddr);
+ macaddr = NULL;
+ } else {
+ qemudRandomMAC(net);
}
if (net->type == QEMUD_NET_NETWORK) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"No <source> 'network' attribute specified with <interface type='network'/>");
goto error;
- } else if ((len = xmlStrlen(network)) >= QEMUD_MAX_NAME_LEN) {
+ } else if ((len = xmlStrlen(network)) >= (QEMUD_MAX_NAME_LEN-1)) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Network name '%s' too long", network);
goto error;
net->dst.network.name[len] = '\0';
}
- if (network)
+ if (network) {
xmlFree(network);
+ network = NULL;
+ }
+
+ if (ifname != NULL) {
+ if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "TAP interface name '%s' is too long", ifname);
+ goto error;
+ } else {
+ strncpy(net->dst.network.ifname, (char *)ifname, len);
+ net->dst.network.ifname[len] = '\0';
+ }
+ xmlFree(ifname);
+ ifname = NULL;
+ }
+ } else if (net->type == QEMUD_NET_ETHERNET) {
+ int len;
- if (tapifname != NULL) {
- if ((len == xmlStrlen(tapifname)) >= BR_IFNAME_MAXLEN) {
+ if (script != NULL) {
+ if ((len = xmlStrlen(script)) >= (PATH_MAX-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "TAP script path '%s' is too long", script);
+ goto error;
+ } else {
+ strncpy(net->dst.ethernet.script, (char *)script, len);
+ net->dst.ethernet.script[len] = '\0';
+ }
+ xmlFree(script);
+ script = NULL;
+ }
+ if (ifname != NULL) {
+ if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
- "TAP interface name '%s' is too long", tapifname);
+ "TAP interface name '%s' is too long", ifname);
goto error;
} else {
- strncpy(net->dst.network.tapifname, (char *)tapifname, len);
- net->dst.network.tapifname[len] = '\0';
+ strncpy(net->dst.ethernet.ifname, (char *)ifname, len);
+ net->dst.ethernet.ifname[len] = '\0';
}
- xmlFree(tapifname);
+ xmlFree(ifname);
+ }
+ } else if (net->type == QEMUD_NET_BRIDGE) {
+ int len;
+
+ if (bridge == NULL) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "No <source> 'dev' attribute specified with <interface type='bridge'/>");
+ goto error;
+ } else if ((len = xmlStrlen(bridge)) >= (BR_IFNAME_MAXLEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "TAP bridge path '%s' is too long", bridge);
+ goto error;
+ } else {
+ strncpy(net->dst.bridge.brname, (char *)bridge, len);
+ net->dst.bridge.brname[len] = '\0';
}
+
+ xmlFree(bridge);
+ bridge = NULL;
+
+ if (ifname != NULL) {
+ if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "TAP interface name '%s' is too long", ifname);
+ goto error;
+ } else {
+ strncpy(net->dst.bridge.ifname, (char *)ifname, len);
+ net->dst.bridge.ifname[len] = '\0';
+ }
+ xmlFree(ifname);
+ }
+ } else if (net->type == QEMUD_NET_CLIENT ||
+ net->type == QEMUD_NET_SERVER ||
+ net->type == QEMUD_NET_MCAST) {
+ int len;
+ char *ret;
+
+ if (port == NULL) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "No <source> 'port' attribute specified with socket interface");
+ goto error;
+ }
+ if (!(net->dst.socket.port = strtol((char*)port, &ret, 10)) &&
+ ret == (char*)port) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "Cannot parse <source> 'port' attribute with socket interface");
+ goto error;
+ }
+ xmlFree(port);
+ port = NULL;
+
+ if (address == NULL) {
+ if (net->type == QEMUD_NET_CLIENT ||
+ net->type == QEMUD_NET_MCAST) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "No <source> 'address' attribute specified with socket interface");
+ goto error;
+ }
+ } else if ((len = xmlStrlen(address)) >= (BR_INET_ADDR_MAXLEN)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "IP address '%s' is too long", address);
+ goto error;
+ }
+ if (address == NULL) {
+ net->dst.socket.address[0] = '\0';
+ } else {
+ strncpy(net->dst.socket.address, (char*)address,len);
+ net->dst.socket.address[len] = '\0';
+ }
+ xmlFree(address);
}
return net;
error:
if (network)
xmlFree(network);
- if (tapifname)
- xmlFree(tapifname);
+ if (address)
+ xmlFree(address);
+ if (port)
+ xmlFree(port);
+ if (ifname)
+ xmlFree(ifname);
+ if (script)
+ xmlFree(script);
+ if (bridge)
+ xmlFree(bridge);
free(net);
return NULL;
}
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+ struct qemud_vm_disk_def *prev = NULL;
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
struct qemud_vm_disk_def *disk;
if (!(disk = qemudParseDiskXML(server, obj->nodesetval->nodeTab[i]))) {
goto error;
}
def->ndisks++;
- disk->next = def->disks;
- def->disks = disk;
+ disk->next = NULL;
+ if (i == 0) {
+ def->disks = disk;
+ } else {
+ prev->next = disk;
+ }
+ prev = disk;
}
}
xmlXPathFreeObject(obj);
obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+ struct qemud_vm_net_def *prev = NULL;
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
struct qemud_vm_net_def *net;
if (!(net = qemudParseInterfaceXML(server, obj->nodesetval->nodeTab[i]))) {
goto error;
}
def->nnets++;
- net->next = def->nets;
- def->nets = net;
+ net->next = NULL;
+ if (i == 0) {
+ def->nets = net;
+ } else {
+ prev->next = net;
+ }
+ prev = net;
}
}
xmlXPathFreeObject(obj);
static char *
qemudNetworkIfaceConnect(struct qemud_server *server,
struct qemud_vm *vm,
- struct qemud_vm_net_def *net)
+ struct qemud_vm_net_def *net,
+ int vlan)
{
- struct qemud_network *network;
- const char *tapifname;
+ struct qemud_network *network = NULL;
+ char *brname;
+ char *ifname;
char tapfdstr[4+3+32+7];
char *retval = NULL;
int err;
int tapfd = -1;
int *tapfds;
- if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) {
- qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
- "Network '%s' not found", net->dst.network.name);
- goto error;
- } else if (network->bridge[0] == '\0') {
+ if (net->type == QEMUD_NET_NETWORK) {
+ if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "Network '%s' not found", net->dst.network.name);
+ goto error;
+ } else if (network->bridge[0] == '\0') {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "Network '%s' not active", net->dst.network.name);
+ goto error;
+ }
+ brname = network->bridge;
+ if (net->dst.network.ifname[0] == '\0' ||
+ strchr(net->dst.network.ifname, '%')) {
+ strcpy(net->dst.network.ifname, "vnet%d");
+ }
+ ifname = net->dst.network.ifname;
+ } else if (net->type == QEMUD_NET_BRIDGE) {
+ brname = net->dst.bridge.brname;
+ if (net->dst.bridge.ifname[0] == '\0' ||
+ strchr(net->dst.bridge.ifname, '%')) {
+ strcpy(net->dst.bridge.ifname, "vnet%d");
+ }
+ ifname = net->dst.bridge.ifname;
+ } else {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
- "Network '%s' not active", net->dst.network.name);
+ "Network type %d is not supported", net->type);
goto error;
}
- if (net->dst.network.tapifname[0] == '\0' ||
- strchr(net->dst.network.tapifname, '%')) {
- tapifname = "vnet%d";
- } else {
- tapifname = net->dst.network.tapifname;
- }
-
- if ((err = brAddTap(server->brctl, network->bridge, tapifname,
- &net->dst.network.tapifname[0], BR_IFNAME_MAXLEN, &tapfd))) {
+ if ((err = brAddTap(server->brctl, brname,
+ ifname, BR_IFNAME_MAXLEN, &tapfd))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Failed to add tap interface '%s' to bridge '%s' : %s",
- tapifname, network->bridge, strerror(err));
+ ifname, brname, strerror(err));
goto error;
}
- if ((err = iptablesAddPhysdevForward(server->iptables, net->dst.network.tapifname))) {
- qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
- "Failed to add iptables rule to allow bridging from '%s' :%s",
- net->dst.network.tapifname, strerror(err));
- goto error;
+ if (net->type == QEMUD_NET_NETWORK && network->def->forward) {
+ if ((err = iptablesAddPhysdevForward(server->iptables, ifname, network->def->forwardDev))) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "Failed to add iptables rule to allow bridging from '%s' :%s",
+ ifname, strerror(err));
+ goto error;
+ }
}
- snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=", tapfd);
+ snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=,vlan=%d", tapfd, vlan);
if (!(retval = strdup(tapfdstr)))
goto no_memory;
return retval;
no_memory:
- iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname);
+ if (net->type == QEMUD_NET_NETWORK && network->def->forward)
+ iptablesRemovePhysdevForward(server->iptables, ifname, network->def->forwardDev);
qemudReportError(server, VIR_ERR_NO_MEMORY, "tapfds");
error:
if (retval)
if (!((*argv)[++n] = strdup("none")))
goto no_memory;
} else {
+ int vlan = 0;
while (net) {
char nic[3+1+7+1+17+1];
- if (!net->mac[0] && !net->mac[1] && !net->mac[2] &&
- !net->mac[3] && !net->mac[4] && !net->mac[5]) {
- strncpy(nic, "nic", 4);
- } else {
- sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
- net->mac[0], net->mac[1],
- net->mac[2], net->mac[3],
- net->mac[4], net->mac[5]);
- }
+ sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d",
+ net->mac[0], net->mac[1],
+ net->mac[2], net->mac[3],
+ net->mac[4], net->mac[5],
+ vlan);
if (!((*argv)[++n] = strdup("-net")))
goto no_memory;
if (!((*argv)[++n] = strdup(nic)))
goto no_memory;
+
if (!((*argv)[++n] = strdup("-net")))
goto no_memory;
- if (net->type != QEMUD_NET_NETWORK) {
- /* XXX don't hardcode user */
- if (!((*argv)[++n] = strdup("user")))
- goto no_memory;
- } else {
- if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net)))
+ switch (net->type) {
+ case QEMUD_NET_NETWORK:
+ case QEMUD_NET_BRIDGE:
+ if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net, vlan)))
goto error;
+ break;
+
+ case QEMUD_NET_ETHERNET:
+ {
+ char arg[PATH_MAX];
+ if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
+ net->dst.ethernet.ifname,
+ net->dst.ethernet.script,
+ vlan) >= (PATH_MAX-1))
+ goto error;
+
+ if (!((*argv)[++n] = strdup(arg)))
+ goto no_memory;
+ }
+ break;
+
+ case QEMUD_NET_CLIENT:
+ case QEMUD_NET_SERVER:
+ case QEMUD_NET_MCAST:
+ {
+ char arg[PATH_MAX];
+ const char *mode = NULL;
+ switch (net->type) {
+ case QEMUD_NET_CLIENT:
+ mode = "connect";
+ break;
+ case QEMUD_NET_SERVER:
+ mode = "listen";
+ break;
+ case QEMUD_NET_MCAST:
+ mode = "mcast";
+ break;
+ }
+ if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
+ mode,
+ net->dst.socket.address,
+ net->dst.socket.port,
+ vlan) >= (PATH_MAX-1))
+ goto error;
+
+ if (!((*argv)[++n] = strdup(arg)))
+ goto no_memory;
+ }
+ break;
+
+ case QEMUD_NET_USER:
+ default:
+ {
+ char arg[PATH_MAX];
+ if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
+ goto error;
+
+ if (!((*argv)[++n] = strdup(arg)))
+ goto no_memory;
+ }
}
net = net->next;
+ vlan++;
}
}
xmlDocPtr xml) {
xmlNodePtr root = NULL;
xmlXPathContextPtr ctxt = NULL;
- xmlXPathObjectPtr obj = NULL;
+ xmlXPathObjectPtr obj = NULL, tmp = NULL;
struct qemud_network_def *def;
if (!(def = calloc(1, sizeof(struct qemud_network_def)))) {
}
xmlXPathFreeObject(obj);
+ obj = xmlXPathEval(BAD_CAST "count(/network/forward) > 0", ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) &&
+ obj->boolval) {
+ def->forward = 1;
+ tmp = xmlXPathEval(BAD_CAST "string(/network/forward[1]/@dev)", ctxt);
+ if ((tmp != NULL) && (tmp->type == XPATH_STRING) &&
+ (tmp->stringval != NULL) && (tmp->stringval[0] != 0)) {
+ int len;
+ if ((len = xmlStrlen(tmp->stringval)) >= (BR_IFNAME_MAXLEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "forward device name '%s' is too long",
+ (char*)tmp->stringval);
+ goto error;
+ }
+ strcpy(def->forwardDev, (char*)tmp->stringval);
+ } else {
+ def->forwardDev[0] = '\0';
+ }
+ xmlXPathFreeObject(tmp);
+ tmp = NULL;
+ } else {
+ def->forward = 0;
+ }
+ xmlXPathFreeObject(obj);
+
/* Parse bridge information */
obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
the caller ? */
if (obj)
xmlXPathFreeObject(obj);
+ if (tmp)
+ xmlXPathFreeObject(tmp);
if (ctxt)
xmlXPathFreeContext(ctxt);
qemudFreeNetworkDef(def);
while (net) {
const char *types[] = {
"user",
- "tap",
+ "ethernet",
"server",
"client",
"mcast",
"network",
- "vde",
+ "bridge",
};
if (qemudBufferPrintf(&buf, " <interface type='%s'>\n",
types[net->type]) < 0)
goto no_memory;
- if (net->mac[0] && net->mac[1] && net->mac[2] &&
- net->mac[3] && net->mac[4] && net->mac[5] &&
- qemudBufferPrintf(&buf, " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+ if (qemudBufferPrintf(&buf, " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
net->mac[0], net->mac[1], net->mac[2],
net->mac[3], net->mac[4], net->mac[5]) < 0)
goto no_memory;
- if (net->type == QEMUD_NET_NETWORK) {
- if (qemudBufferPrintf(&buf, " <source network='%s'", net->dst.network.name) < 0)
+ switch (net->type) {
+ case QEMUD_NET_NETWORK:
+ if (qemudBufferPrintf(&buf, " <source network='%s'/>\n", net->dst.network.name) < 0)
goto no_memory;
- if (net->dst.network.tapifname[0] != '\0' &&
- qemudBufferPrintf(&buf, " tapifname='%s'", net->dst.network.tapifname) < 0)
- goto no_memory;
+ if (net->dst.network.ifname[0] != '\0') {
+ if (qemudBufferPrintf(&buf, " <target dev='%s'/>\n", net->dst.network.ifname) < 0)
+ goto no_memory;
+ }
+ break;
- if (qemudBufferPrintf(&buf, "/>\n") < 0)
+ case QEMUD_NET_ETHERNET:
+ if (net->dst.ethernet.ifname[0] != '\0') {
+ if (qemudBufferPrintf(&buf, " <target dev='%s'/>\n", net->dst.ethernet.ifname) < 0)
+ goto no_memory;
+ }
+ if (net->dst.ethernet.script[0] != '\0') {
+ if (qemudBufferPrintf(&buf, " <script path='%s'/>\n", net->dst.ethernet.script) < 0)
+ goto no_memory;
+ }
+ break;
+
+ case QEMUD_NET_BRIDGE:
+ if (qemudBufferPrintf(&buf, " <source dev='%s'/>\n", net->dst.bridge.brname) < 0)
goto no_memory;
+ if (net->dst.bridge.ifname[0] != '\0') {
+ if (qemudBufferPrintf(&buf, " <target dev='%s'/>\n", net->dst.bridge.ifname) < 0)
+ goto no_memory;
+ }
+ break;
+
+ case QEMUD_NET_SERVER:
+ case QEMUD_NET_CLIENT:
+ case QEMUD_NET_MCAST:
+ if (net->dst.socket.address[0] != '\0') {
+ if (qemudBufferPrintf(&buf, " <source address='%s' port='%d'/>\n",
+ net->dst.socket.address, net->dst.socket.port) < 0)
+ goto no_memory;
+ } else {
+ if (qemudBufferPrintf(&buf, " <source port='%d'/>\n",
+ net->dst.socket.port) < 0)
+ goto no_memory;
+ }
}
if (qemudBufferPrintf(&buf, " </interface>\n") < 0)
uuid[12], uuid[13], uuid[14], uuid[15]) < 0)
goto no_memory;
+ if (def->forward) {
+ if (def->forwardDev[0]) {
+ qemudBufferPrintf(&buf, " <forward dev='%s'/>\n",
+ def->forwardDev);
+ } else {
+ qemudBufferAdd(&buf, " <forward/>\n");
+ }
+ }
+
if ((def->bridge != '\0' || def->disableSTP || def->forwardDelay) &&
qemudBufferPrintf(&buf, " <bridge name='%s' stp='%s' delay='%d' />\n",
def->bridge,
int tcp)
{
char portstr[32];
- int ret;
snprintf(portstr, sizeof(portstr), "%d", port);
portstr[sizeof(portstr) - 1] = '\0';
- ret = iptablesAddRemoveRule(ctx->input_filter,
- action,
- "--in-interface", iface,
- "--protocol", tcp ? "tcp" : "udp",
- "--destination-port", portstr,
- "--jump", "ACCEPT",
- NULL);
-
- return ret;
+ return iptablesAddRemoveRule(ctx->input_filter,
+ action,
+ "--in-interface", iface,
+ "--protocol", tcp ? "tcp" : "udp",
+ "--destination-port", portstr,
+ "--jump", "ACCEPT",
+ NULL);
}
int
static int
iptablesPhysdevForward(iptablesContext *ctx,
const char *iface,
+ const char *target,
int action)
{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--match", "physdev",
- "--physdev-in", iface,
- "--jump", "ACCEPT",
- NULL);
+ if (target && target[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--match", "physdev",
+ "--physdev-in", iface,
+ "--out", target,
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--match", "physdev",
+ "--physdev-in", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ }
}
int
iptablesAddPhysdevForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesPhysdevForward(ctx, iface, ADD);
+ return iptablesPhysdevForward(ctx, iface, target, ADD);
}
int
iptablesRemovePhysdevForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesPhysdevForward(ctx, iface, REMOVE);
+ return iptablesPhysdevForward(ctx, iface, target, REMOVE);
}
static int
iptablesInterfaceForward(iptablesContext *ctx,
const char *iface,
+ const char *target,
int action)
{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--in-interface", iface,
- "--jump", "ACCEPT",
- NULL);
+ if (target && target[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--out-interface", target,
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ }
}
int
iptablesAddInterfaceForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesInterfaceForward(ctx, iface, ADD);
+ return iptablesInterfaceForward(ctx, iface, target, ADD);
}
int
iptablesRemoveInterfaceForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesInterfaceForward(ctx, iface, REMOVE);
+ return iptablesInterfaceForward(ctx, iface, target, REMOVE);
}
static int
iptablesStateForward(iptablesContext *ctx,
const char *iface,
+ const char *target,
int action)
{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--out-interface", iface,
- "--match", "state",
- "--state", "ESTABLISHED,RELATED",
- "--jump", "ACCEPT",
- NULL);
+ if (target && target[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", target,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state", "ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state", "ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ }
}
int
iptablesAddStateForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesStateForward(ctx, iface, ADD);
+ return iptablesStateForward(ctx, iface, target, ADD);
}
int
iptablesRemoveStateForward(iptablesContext *ctx,
- const char *iface)
+ const char *iface,
+ const char *target)
{
- return iptablesStateForward(ctx, iface, REMOVE);
+ return iptablesStateForward(ctx, iface, target, REMOVE);
}
static int
iptablesNonBridgedMasq(iptablesContext *ctx,
+ const char *target,
int action)
{
- return iptablesAddRemoveRule(ctx->nat_postrouting,
- action,
- "--match", "physdev",
- "!", "--physdev-is-bridged",
- "--jump", "MASQUERADE",
- NULL);
+ if (target && target[0]) {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--out-interface", target,
+ "--match", "physdev",
+ "!", "--physdev-is-bridged",
+ "--jump", "MASQUERADE",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--match", "physdev",
+ "!", "--physdev-is-bridged",
+ "--jump", "MASQUERADE",
+ NULL);
+ }
}
int
-iptablesAddNonBridgedMasq(iptablesContext *ctx)
+iptablesAddNonBridgedMasq(iptablesContext *ctx,
+ const char *target)
{
- return iptablesNonBridgedMasq(ctx, ADD);
+ return iptablesNonBridgedMasq(ctx, target, ADD);
}
int
-iptablesRemoveNonBridgedMasq(iptablesContext *ctx)
+iptablesRemoveNonBridgedMasq(iptablesContext *ctx,
+ const char *target)
{
- return iptablesNonBridgedMasq(ctx, REMOVE);
+ return iptablesNonBridgedMasq(ctx, target, REMOVE);
}
/*
qemudNetworkIfaceDisconnect(struct qemud_server *server,
struct qemud_vm *vm ATTRIBUTE_UNUSED,
struct qemud_vm_net_def *net) {
- iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname);
+ struct qemud_network *network;
+ if (net->type != QEMUD_NET_NETWORK)
+ return;
+
+ if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) {
+ return;
+ } else if (network->bridge[0] == '\0') {
+ return;
+ }
+
+ if (network->def->forward)
+ iptablesRemovePhysdevForward(server->iptables, net->dst.network.ifname, network->def->forwardDev);
}
int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
struct qemud_network *network,
char ***argv) {
int i, len;
- char buf[BR_INET_ADDR_MAXLEN * 2];
+ char buf[PATH_MAX];
struct qemud_dhcp_range_def *range;
len =
1 + /* --bind-interfaces */
2 + /* --pid-file "" */
2 + /* --conf-file "" */
+ /*2 + *//* --interface virbr0 */
2 + /* --except-interface lo */
2 + /* --listen-address 10.0.0.1 */
+ 1 + /* --dhcp-leasefile=path */
(2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
1; /* NULL */
APPEND_ARG(*argv, i++, "--conf-file");
APPEND_ARG(*argv, i++, "");
+ /*
+ * XXX does not actually work, due to some kind of
+ * race condition setting up ipv6 addresses on the
+ * interface. A sleep(10) makes it work, but that's
+ * clearly not practical
+ *
+ * APPEND_ARG(*argv, i++, "--interface");
+ * APPEND_ARG(*argv, i++, network->def->bridge);
+ */
+ APPEND_ARG(*argv, i++, "--listen-address");
+ APPEND_ARG(*argv, i++, network->def->ipAddress);
+
APPEND_ARG(*argv, i++, "--except-interface");
APPEND_ARG(*argv, i++, "lo");
- APPEND_ARG(*argv, i++, "--listen-address");
- APPEND_ARG(*argv, i++, network->def->ipAddress);
+ /*
+ * NB, dnsmasq command line arg bug means we need to
+ * use a single arg '--dhcp-leasefile=path' rather than
+ * two separate args in '--dhcp-leasefile path' style
+ */
+ snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases",
+ LOCAL_STATE_DIR, network->def->name);
+ APPEND_ARG(*argv, i++, buf);
range = network->def->ranges;
while (range) {
}
/* allow bridging from the bridge interface itself */
- if ((err = iptablesAddPhysdevForward(server->iptables, network->bridge))) {
+ if ((err = iptablesAddPhysdevForward(server->iptables, network->bridge, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow bridging from '%s' : %s\n",
network->bridge, strerror(err));
}
/* allow forwarding packets from the bridge interface */
- if ((err = iptablesAddInterfaceForward(server->iptables, network->bridge))) {
+ if ((err = iptablesAddInterfaceForward(server->iptables, network->bridge, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow forwarding from '%s' : %s\n",
network->bridge, strerror(err));
}
/* allow forwarding packets to the bridge interface if they are part of an existing connection */
- if ((err = iptablesAddStateForward(server->iptables, network->bridge))) {
+ if ((err = iptablesAddStateForward(server->iptables, network->bridge, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow forwarding to '%s' : %s\n",
network->bridge, strerror(err));
}
/* enable masquerading */
- if ((err = iptablesAddNonBridgedMasq(server->iptables))) {
+ if ((err = iptablesAddNonBridgedMasq(server->iptables, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to enable masquerading : %s\n",
strerror(err));
err6:
iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
err5:
- iptablesRemoveNonBridgedMasq(server->iptables);
+ iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
err4:
- iptablesRemoveStateForward(server->iptables, network->bridge);
+ iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
err3:
- iptablesRemoveInterfaceForward(server->iptables, network->bridge);
+ iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
err2:
- iptablesRemovePhysdevForward(server->iptables, network->bridge);
+ iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
err1:
return 0;
}
static void
qemudRemoveIptablesRules(struct qemud_server *server,
struct qemud_network *network) {
- iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
- iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
- iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
- iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
- iptablesRemoveNonBridgedMasq(server->iptables);
- iptablesRemoveStateForward(server->iptables, network->bridge);
- iptablesRemoveInterfaceForward(server->iptables, network->bridge);
- iptablesRemovePhysdevForward(server->iptables, network->bridge);
+ if (network->def->forward) {
+ iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
+ iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
+ iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
+ iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
+ iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
+ iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
+ iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
+ iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
+ }
}
static int
goto err_delbr;
}
- if (!qemudAddIptablesRules(server, network))
+ if (network->def->forward &&
+ !qemudAddIptablesRules(server, network))
goto err_delbr1;
- if (!qemudEnableIpForwarding()) {
+ if (network->def->forward &&
+ !qemudEnableIpForwarding()) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to enable IP forwarding : %s\n", strerror(err));
goto err_delbr2;