Improve support for virtual networking

This commit is contained in:
Daniel P. Berrange 2007-03-13 22:43:22 +00:00
parent 06b3f3ced3
commit a534de5281
11 changed files with 596 additions and 192 deletions

View File

@ -1,3 +1,39 @@
Tue Mar 13 18:04:14 EST 2007 Daniel P. Berrange <berrange@redhat.com>
* qemud/qemud.c: Use the --dhcp-leasefile arg to dnsmasq to
ensure multiple instances of dnsmasq can co-exist without
splaterring each other's leases.
* qemud/bridge.c: Use a single ifname arg instead of two separate
ifnameOrFmt & ifname args to simply use by callers
* qemud/conf.c: Autogenerate a MAC address if none is provided.
Added support for ethernet, bridge, mcast, client and server
networking config types in XML parser, generator and command
line args. Use the 'vlan' attribute for all QEMU nics to ensure
they don't all appear on same virtual LAN. Ensure order of
QEMU NICs matches order they are declared in the XML. Tweak
existing XML generation of 'network' type to match syntax
used by Xen for specifying tap device name. Add support for
creating isolated networks, or networks forwarding to an
explicit named physical device.
* qemud/default-network.xml: Add <forward/> to make default network
automatically forward to any active physical device.
* qemud/internal.h: Added struct fields for new types of network
config, and for tracking network forward device.
* qemud/iptables.h, qemud/iptables.c: Allow an optional target
device name to be passed in to restrict IP tables forwarding
rules.
* qemud/Makefile.am: Create $sysconfdir/lib/libvirt for DHCP
leases file
* libvirt.spec.in: Include %{_sysconfdir}/lib/libvirt for DHCP
leases file
Mon Mar 12 23:17:11 EST 2007 Daniel P. Berrange <berrange@redhat.com> Mon Mar 12 23:17:11 EST 2007 Daniel P. Berrange <berrange@redhat.com>
* libvirt.spec.in: Don't run UUID generation on first install, * libvirt.spec.in: Don't run UUID generation on first install,

View File

@ -113,6 +113,7 @@ fi
%config %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml %config %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
%{_sysconfdir}/rc.d/init.d/libvirtd %{_sysconfdir}/rc.d/init.d/libvirtd
%dir %{_localstatedir}/run/libvirt/ %dir %{_localstatedir}/run/libvirt/
%dir %{_localstatedir}/lib/libvirt/
%attr(4755, root, root) %{_libexecdir}/libvirt_proxy %attr(4755, root, root) %{_libexecdir}/libvirt_proxy
%attr(0755, root, root) %{_sbindir}/libvirt_qemud %attr(0755, root, root) %{_sbindir}/libvirt_qemud
%doc docs/libvirt.rng %doc docs/libvirt.rng

View File

@ -28,12 +28,14 @@ install-data-local:
test -e $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml || \ test -e $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml || \
ln -s ../default.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml ln -s ../default.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
mkdir -p $(DESTDIR)$(localstatedir)/run/libvirt mkdir -p $(DESTDIR)$(localstatedir)/run/libvirt
mkdir -p $(DESTDIR)$(localstatedir)/lib/libvirt
uninstall-local: uninstall-local:
rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || : rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || :
rmdir $(DESTDIR)$(localstatedir)/run/libvirt || : rmdir $(DESTDIR)$(localstatedir)/run/libvirt || :
rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || :
EXTRA_DIST = libvirtd.in default-network.xml EXTRA_DIST = libvirtd.in default-network.xml

View File

@ -190,27 +190,22 @@ brDeleteInterface(brControl *ctl,
return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface); return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface);
} }
int int
brAddTap(brControl *ctl, brAddTap(brControl *ctl,
const char *bridge, const char *bridge,
const char *ifnameOrFmt,
char *ifname, char *ifname,
int maxlen, int maxlen,
int *tapfd) int *tapfd)
{ {
int id, subst, fd; int id, subst, fd;
if (!ctl || !ctl->fd || !bridge || !ifnameOrFmt || !tapfd) if (!ctl || !ctl->fd || !bridge || !ifname || !tapfd)
return EINVAL; return EINVAL;
if (!ifname)
maxlen = BR_IFNAME_MAXLEN;
else if (maxlen >= BR_IFNAME_MAXLEN)
maxlen = BR_IFNAME_MAXLEN;
subst = id = 0; subst = id = 0;
if (strstr(ifnameOrFmt, "%d")) if (strstr(ifname, "%d"))
subst = 1; subst = 1;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
@ -225,19 +220,19 @@ brAddTap(brControl *ctl,
try.ifr_flags = IFF_TAP|IFF_NO_PI; try.ifr_flags = IFF_TAP|IFF_NO_PI;
if (subst) { if (subst) {
len = snprintf(try.ifr_name, maxlen, ifnameOrFmt, id); len = snprintf(try.ifr_name, maxlen, ifname, id);
if (len >= maxlen) { if (len >= maxlen) {
errno = EADDRINUSE; errno = EADDRINUSE;
goto error; goto error;
} }
} else { } else {
len = strlen(ifnameOrFmt); len = strlen(ifname);
if (len >= maxlen - 1) { if (len >= maxlen - 1) {
errno = EINVAL; errno = EINVAL;
goto error; goto error;
} }
strncpy(try.ifr_name, ifnameOrFmt, len); strncpy(try.ifr_name, ifname, len);
try.ifr_name[len] = '\0'; try.ifr_name[len] = '\0';
} }

View File

@ -49,7 +49,6 @@ int brDeleteInterface (brControl *ctl,
int brAddTap (brControl *ctl, int brAddTap (brControl *ctl,
const char *bridge, const char *bridge,
const char *ifnameOrFmt,
char *ifname, char *ifname,
int maxlen, int maxlen,
int *tapfd); int *tapfd);

View File

@ -444,6 +444,15 @@ static struct qemud_vm_disk_def *qemudParseDiskXML(struct qemud_server *server,
return NULL; 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 */ /* Parse the XML definition for a network interface */
static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *server, static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *server,
@ -453,7 +462,11 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
xmlChar *macaddr = NULL; xmlChar *macaddr = NULL;
xmlChar *type = NULL; xmlChar *type = NULL;
xmlChar *network = NULL; xmlChar *network = NULL;
xmlChar *tapifname = NULL; xmlChar *bridge = NULL;
xmlChar *ifname = NULL;
xmlChar *script = NULL;
xmlChar *address = NULL;
xmlChar *port = NULL;
if (!net) { if (!net) {
qemudReportError(server, VIR_ERR_NO_MEMORY, "net"); qemudReportError(server, VIR_ERR_NO_MEMORY, "net");
@ -466,8 +479,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
if (type != NULL) { if (type != NULL) {
if (xmlStrEqual(type, BAD_CAST "user")) if (xmlStrEqual(type, BAD_CAST "user"))
net->type = QEMUD_NET_USER; net->type = QEMUD_NET_USER;
else if (xmlStrEqual(type, BAD_CAST "tap")) else if (xmlStrEqual(type, BAD_CAST "ethernet"))
net->type = QEMUD_NET_TAP; net->type = QEMUD_NET_ETHERNET;
else if (xmlStrEqual(type, BAD_CAST "server")) else if (xmlStrEqual(type, BAD_CAST "server"))
net->type = QEMUD_NET_SERVER; net->type = QEMUD_NET_SERVER;
else if (xmlStrEqual(type, BAD_CAST "client")) else if (xmlStrEqual(type, BAD_CAST "client"))
@ -476,10 +489,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
net->type = QEMUD_NET_MCAST; net->type = QEMUD_NET_MCAST;
else if (xmlStrEqual(type, BAD_CAST "network")) else if (xmlStrEqual(type, BAD_CAST "network"))
net->type = QEMUD_NET_NETWORK; net->type = QEMUD_NET_NETWORK;
/* else if (xmlStrEqual(type, BAD_CAST "bridge"))
else if (xmlStrEqual(type, BAD_CAST "vde")) net->type = QEMUD_NET_BRIDGE;
typ = QEMUD_NET_VDE;
*/
else else
net->type = QEMUD_NET_USER; net->type = QEMUD_NET_USER;
xmlFree(type); xmlFree(type);
@ -496,17 +507,32 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
(net->type == QEMUD_NET_NETWORK) && (net->type == QEMUD_NET_NETWORK) &&
(xmlStrEqual(cur->name, BAD_CAST "source"))) { (xmlStrEqual(cur->name, BAD_CAST "source"))) {
network = xmlGetProp(cur, BAD_CAST "network"); network = xmlGetProp(cur, BAD_CAST "network");
} else if ((tapifname == NULL) && } else if ((network == NULL) &&
(net->type == QEMUD_NET_NETWORK) && (net->type == QEMUD_NET_BRIDGE) &&
xmlStrEqual(cur->name, BAD_CAST "tap")) { (xmlStrEqual(cur->name, BAD_CAST "source"))) {
tapifname = xmlGetProp(cur, BAD_CAST "ifname"); 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; cur = cur->next;
} }
net->vlan = 0;
if (macaddr) { if (macaddr) {
unsigned int mac[6]; unsigned int mac[6];
sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
@ -524,6 +550,9 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
net->mac[5] = mac[5]; net->mac[5] = mac[5];
xmlFree(macaddr); xmlFree(macaddr);
macaddr = NULL;
} else {
qemudRandomMAC(net);
} }
if (net->type == QEMUD_NET_NETWORK) { if (net->type == QEMUD_NET_NETWORK) {
@ -533,7 +562,7 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"No <source> 'network' attribute specified with <interface type='network'/>"); "No <source> 'network' attribute specified with <interface type='network'/>");
goto error; 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, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Network name '%s' too long", network); "Network name '%s' too long", network);
goto error; goto error;
@ -542,20 +571,118 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
net->dst.network.name[len] = '\0'; net->dst.network.name[len] = '\0';
} }
if (network) if (network) {
xmlFree(network); xmlFree(network);
network = NULL;
}
if (tapifname != NULL) { if (ifname != NULL) {
if ((len == xmlStrlen(tapifname)) >= BR_IFNAME_MAXLEN) { if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"TAP interface name '%s' is too long", tapifname); "TAP interface name '%s' is too long", ifname);
goto error; goto error;
} else { } else {
strncpy(net->dst.network.tapifname, (char *)tapifname, len); strncpy(net->dst.network.ifname, (char *)ifname, len);
net->dst.network.tapifname[len] = '\0'; net->dst.network.ifname[len] = '\0';
} }
xmlFree(tapifname); xmlFree(ifname);
ifname = NULL;
} }
} else if (net->type == QEMUD_NET_ETHERNET) {
int len;
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", ifname);
goto error;
} else {
strncpy(net->dst.ethernet.ifname, (char *)ifname, len);
net->dst.ethernet.ifname[len] = '\0';
}
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; return net;
@ -563,8 +690,16 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
error: error:
if (network) if (network)
xmlFree(network); xmlFree(network);
if (tapifname) if (address)
xmlFree(tapifname); xmlFree(address);
if (port)
xmlFree(port);
if (ifname)
xmlFree(ifname);
if (script)
xmlFree(script);
if (bridge)
xmlFree(bridge);
free(net); free(net);
return NULL; return NULL;
} }
@ -886,14 +1021,20 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt); obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) && if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
struct qemud_vm_disk_def *prev = NULL;
for (i = 0; i < obj->nodesetval->nodeNr; i++) { for (i = 0; i < obj->nodesetval->nodeNr; i++) {
struct qemud_vm_disk_def *disk; struct qemud_vm_disk_def *disk;
if (!(disk = qemudParseDiskXML(server, obj->nodesetval->nodeTab[i]))) { if (!(disk = qemudParseDiskXML(server, obj->nodesetval->nodeTab[i]))) {
goto error; goto error;
} }
def->ndisks++; def->ndisks++;
disk->next = def->disks; disk->next = NULL;
if (i == 0) {
def->disks = disk; def->disks = disk;
} else {
prev->next = disk;
}
prev = disk;
} }
} }
xmlXPathFreeObject(obj); xmlXPathFreeObject(obj);
@ -903,14 +1044,20 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt); obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) && if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
struct qemud_vm_net_def *prev = NULL;
for (i = 0; i < obj->nodesetval->nodeNr; i++) { for (i = 0; i < obj->nodesetval->nodeNr; i++) {
struct qemud_vm_net_def *net; struct qemud_vm_net_def *net;
if (!(net = qemudParseInterfaceXML(server, obj->nodesetval->nodeTab[i]))) { if (!(net = qemudParseInterfaceXML(server, obj->nodesetval->nodeTab[i]))) {
goto error; goto error;
} }
def->nnets++; def->nnets++;
net->next = def->nets; net->next = NULL;
if (i == 0) {
def->nets = net; def->nets = net;
} else {
prev->next = net;
}
prev = net;
} }
} }
xmlXPathFreeObject(obj); xmlXPathFreeObject(obj);
@ -933,16 +1080,19 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
static char * static char *
qemudNetworkIfaceConnect(struct qemud_server *server, qemudNetworkIfaceConnect(struct qemud_server *server,
struct qemud_vm *vm, struct qemud_vm *vm,
struct qemud_vm_net_def *net) struct qemud_vm_net_def *net,
int vlan)
{ {
struct qemud_network *network; struct qemud_network *network = NULL;
const char *tapifname; char *brname;
char *ifname;
char tapfdstr[4+3+32+7]; char tapfdstr[4+3+32+7];
char *retval = NULL; char *retval = NULL;
int err; int err;
int tapfd = -1; int tapfd = -1;
int *tapfds; int *tapfds;
if (net->type == QEMUD_NET_NETWORK) {
if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) { if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Network '%s' not found", net->dst.network.name); "Network '%s' not found", net->dst.network.name);
@ -952,30 +1102,43 @@ qemudNetworkIfaceConnect(struct qemud_server *server,
"Network '%s' not active", net->dst.network.name); "Network '%s' not active", net->dst.network.name);
goto error; goto error;
} }
brname = network->bridge;
if (net->dst.network.tapifname[0] == '\0' || if (net->dst.network.ifname[0] == '\0' ||
strchr(net->dst.network.tapifname, '%')) { strchr(net->dst.network.ifname, '%')) {
tapifname = "vnet%d"; 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 { } else {
tapifname = net->dst.network.tapifname; qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Network type %d is not supported", net->type);
goto error;
} }
if ((err = brAddTap(server->brctl, network->bridge, tapifname, if ((err = brAddTap(server->brctl, brname,
&net->dst.network.tapifname[0], BR_IFNAME_MAXLEN, &tapfd))) { ifname, BR_IFNAME_MAXLEN, &tapfd))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Failed to add tap interface '%s' to bridge '%s' : %s", "Failed to add tap interface '%s' to bridge '%s' : %s",
tapifname, network->bridge, strerror(err)); ifname, brname, strerror(err));
goto error; goto error;
} }
if ((err = iptablesAddPhysdevForward(server->iptables, net->dst.network.tapifname))) { if (net->type == QEMUD_NET_NETWORK && network->def->forward) {
if ((err = iptablesAddPhysdevForward(server->iptables, ifname, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"Failed to add iptables rule to allow bridging from '%s' :%s", "Failed to add iptables rule to allow bridging from '%s' :%s",
net->dst.network.tapifname, strerror(err)); ifname, strerror(err));
goto error; 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))) if (!(retval = strdup(tapfdstr)))
goto no_memory; goto no_memory;
@ -990,7 +1153,8 @@ qemudNetworkIfaceConnect(struct qemud_server *server,
return retval; return retval;
no_memory: 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"); qemudReportError(server, VIR_ERR_NO_MEMORY, "tapfds");
error: error:
if (retval) if (retval)
@ -1137,36 +1301,88 @@ int qemudBuildCommandLine(struct qemud_server *server,
if (!((*argv)[++n] = strdup("none"))) if (!((*argv)[++n] = strdup("none")))
goto no_memory; goto no_memory;
} else { } else {
int vlan = 0;
while (net) { while (net) {
char nic[3+1+7+1+17+1]; char nic[3+1+7+1+17+1];
if (!net->mac[0] && !net->mac[1] && !net->mac[2] && sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d",
!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[0], net->mac[1],
net->mac[2], net->mac[3], net->mac[2], net->mac[3],
net->mac[4], net->mac[5]); net->mac[4], net->mac[5],
} vlan);
if (!((*argv)[++n] = strdup("-net"))) if (!((*argv)[++n] = strdup("-net")))
goto no_memory; goto no_memory;
if (!((*argv)[++n] = strdup(nic))) if (!((*argv)[++n] = strdup(nic)))
goto no_memory; goto no_memory;
if (!((*argv)[++n] = strdup("-net"))) if (!((*argv)[++n] = strdup("-net")))
goto no_memory; goto no_memory;
if (net->type != QEMUD_NET_NETWORK) { switch (net->type) {
/* XXX don't hardcode user */ case QEMUD_NET_NETWORK:
if (!((*argv)[++n] = strdup("user"))) case QEMUD_NET_BRIDGE:
goto no_memory; if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net, vlan)))
} else {
if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net)))
goto error; 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; net = net->next;
vlan++;
} }
} }
@ -1567,7 +1783,7 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
xmlDocPtr xml) { xmlDocPtr xml) {
xmlNodePtr root = NULL; xmlNodePtr root = NULL;
xmlXPathContextPtr ctxt = NULL; xmlXPathContextPtr ctxt = NULL;
xmlXPathObjectPtr obj = NULL; xmlXPathObjectPtr obj = NULL, tmp = NULL;
struct qemud_network_def *def; struct qemud_network_def *def;
if (!(def = calloc(1, sizeof(struct qemud_network_def)))) { if (!(def = calloc(1, sizeof(struct qemud_network_def)))) {
@ -1620,6 +1836,31 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
} }
xmlXPathFreeObject(obj); 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 */ /* Parse bridge information */
obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt); obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) && if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
@ -1649,6 +1890,8 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
the caller ? */ the caller ? */
if (obj) if (obj)
xmlXPathFreeObject(obj); xmlXPathFreeObject(obj);
if (tmp)
xmlXPathFreeObject(tmp);
if (ctxt) if (ctxt)
xmlXPathFreeContext(ctxt); xmlXPathFreeContext(ctxt);
qemudFreeNetworkDef(def); qemudFreeNetworkDef(def);
@ -2320,35 +2563,66 @@ char *qemudGenerateXML(struct qemud_server *server,
while (net) { while (net) {
const char *types[] = { const char *types[] = {
"user", "user",
"tap", "ethernet",
"server", "server",
"client", "client",
"mcast", "mcast",
"network", "network",
"vde", "bridge",
}; };
if (qemudBufferPrintf(&buf, " <interface type='%s'>\n", if (qemudBufferPrintf(&buf, " <interface type='%s'>\n",
types[net->type]) < 0) types[net->type]) < 0)
goto no_memory; goto no_memory;
if (net->mac[0] && net->mac[1] && net->mac[2] && if (qemudBufferPrintf(&buf, " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
net->mac[3] && net->mac[4] && net->mac[5] &&
qemudBufferPrintf(&buf, " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
net->mac[0], net->mac[1], net->mac[2], net->mac[0], net->mac[1], net->mac[2],
net->mac[3], net->mac[4], net->mac[5]) < 0) net->mac[3], net->mac[4], net->mac[5]) < 0)
goto no_memory; goto no_memory;
if (net->type == QEMUD_NET_NETWORK) { switch (net->type) {
if (qemudBufferPrintf(&buf, " <source network='%s'", net->dst.network.name) < 0) case QEMUD_NET_NETWORK:
if (qemudBufferPrintf(&buf, " <source network='%s'/>\n", net->dst.network.name) < 0)
goto no_memory; goto no_memory;
if (net->dst.network.tapifname[0] != '\0' && if (net->dst.network.ifname[0] != '\0') {
qemudBufferPrintf(&buf, " tapifname='%s'", net->dst.network.tapifname) < 0) if (qemudBufferPrintf(&buf, " <target dev='%s'/>\n", net->dst.network.ifname) < 0)
goto no_memory; 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; 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) if (qemudBufferPrintf(&buf, " </interface>\n") < 0)
goto no_memory; goto no_memory;
@ -2428,6 +2702,15 @@ char *qemudGenerateNetworkXML(struct qemud_server *server,
uuid[12], uuid[13], uuid[14], uuid[15]) < 0) uuid[12], uuid[13], uuid[14], uuid[15]) < 0)
goto no_memory; 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) && if ((def->bridge != '\0' || def->disableSTP || def->forwardDelay) &&
qemudBufferPrintf(&buf, " <bridge name='%s' stp='%s' delay='%d' />\n", qemudBufferPrintf(&buf, " <bridge name='%s' stp='%s' delay='%d' />\n",
def->bridge, def->bridge,

View File

@ -1,6 +1,7 @@
<network> <network>
<name>default</name> <name>default</name>
<bridge name="virbr0" /> <bridge name="virbr0" />
<forward/>
<ip address="192.168.122.1" netmask="255.255.255.0"> <ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp> <dhcp>
<range start="192.168.122.2" end="192.168.122.254" /> <range start="192.168.122.2" end="192.168.122.254" />

View File

@ -103,43 +103,35 @@ struct qemud_vm_disk_def {
/* 5 different types of networking config */ /* 5 different types of networking config */
enum qemud_vm_net_type { enum qemud_vm_net_type {
QEMUD_NET_USER, QEMUD_NET_USER,
QEMUD_NET_TAP, QEMUD_NET_ETHERNET,
QEMUD_NET_SERVER, QEMUD_NET_SERVER,
QEMUD_NET_CLIENT, QEMUD_NET_CLIENT,
QEMUD_NET_MCAST, QEMUD_NET_MCAST,
QEMUD_NET_NETWORK, QEMUD_NET_NETWORK,
/* QEMUD_NET_VDE*/ QEMUD_NET_BRIDGE,
}; };
/* Stores the virtual network interface configuration */ /* Stores the virtual network interface configuration */
struct qemud_vm_net_def { struct qemud_vm_net_def {
int type; int type;
int vlan;
unsigned char mac[QEMUD_MAC_ADDRESS_LEN]; unsigned char mac[QEMUD_MAC_ADDRESS_LEN];
union { union {
struct { struct {
char ifname[NAME_MAX]; char ifname[BR_IFNAME_MAXLEN];
char script[PATH_MAX]; char script[PATH_MAX];
} tap; } ethernet;
struct { struct {
struct sockaddr_in listen; char address[BR_INET_ADDR_MAXLEN];
int port; int port;
} server; } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
struct {
struct sockaddr_in connect;
int port;
} client;
struct {
struct sockaddr_in group;
int port;
} mcast;
struct {
char vlan[PATH_MAX];
} vde;
struct { struct {
char name[QEMUD_MAX_NAME_LEN]; char name[QEMUD_MAX_NAME_LEN];
char tapifname[BR_IFNAME_MAXLEN]; char ifname[BR_IFNAME_MAXLEN];
} network; } network;
struct {
char brname[BR_IFNAME_MAXLEN];
char ifname[BR_IFNAME_MAXLEN];
} bridge;
} dst; } dst;
struct qemud_vm_net_def *next; struct qemud_vm_net_def *next;
@ -249,6 +241,9 @@ struct qemud_network_def {
int disableSTP; int disableSTP;
int forwardDelay; int forwardDelay;
int forward;
char forwardDev[BR_IFNAME_MAXLEN];
char ipAddress[BR_INET_ADDR_MAXLEN]; char ipAddress[BR_INET_ADDR_MAXLEN];
char netmask[BR_INET_ADDR_MAXLEN]; char netmask[BR_INET_ADDR_MAXLEN];

View File

@ -532,20 +532,17 @@ iptablesInput(iptablesContext *ctx,
int tcp) int tcp)
{ {
char portstr[32]; char portstr[32];
int ret;
snprintf(portstr, sizeof(portstr), "%d", port); snprintf(portstr, sizeof(portstr), "%d", port);
portstr[sizeof(portstr) - 1] = '\0'; portstr[sizeof(portstr) - 1] = '\0';
ret = iptablesAddRemoveRule(ctx->input_filter, return iptablesAddRemoveRule(ctx->input_filter,
action, action,
"--in-interface", iface, "--in-interface", iface,
"--protocol", tcp ? "tcp" : "udp", "--protocol", tcp ? "tcp" : "udp",
"--destination-port", portstr, "--destination-port", portstr,
"--jump", "ACCEPT", "--jump", "ACCEPT",
NULL); NULL);
return ret;
} }
int int
@ -583,61 +580,97 @@ iptablesRemoveUdpInput(iptablesContext *ctx,
static int static int
iptablesPhysdevForward(iptablesContext *ctx, iptablesPhysdevForward(iptablesContext *ctx,
const char *iface, const char *iface,
const char *target,
int action) int action)
{ {
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, return iptablesAddRemoveRule(ctx->forward_filter,
action, action,
"--match", "physdev", "--match", "physdev",
"--physdev-in", iface, "--physdev-in", iface,
"--jump", "ACCEPT", "--jump", "ACCEPT",
NULL); NULL);
}
} }
int int
iptablesAddPhysdevForward(iptablesContext *ctx, iptablesAddPhysdevForward(iptablesContext *ctx,
const char *iface) const char *iface,
const char *target)
{ {
return iptablesPhysdevForward(ctx, iface, ADD); return iptablesPhysdevForward(ctx, iface, target, ADD);
} }
int int
iptablesRemovePhysdevForward(iptablesContext *ctx, 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 static int
iptablesInterfaceForward(iptablesContext *ctx, iptablesInterfaceForward(iptablesContext *ctx,
const char *iface, const char *iface,
const char *target,
int action) int action)
{ {
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, return iptablesAddRemoveRule(ctx->forward_filter,
action, action,
"--in-interface", iface, "--in-interface", iface,
"--jump", "ACCEPT", "--jump", "ACCEPT",
NULL); NULL);
}
} }
int int
iptablesAddInterfaceForward(iptablesContext *ctx, iptablesAddInterfaceForward(iptablesContext *ctx,
const char *iface) const char *iface,
const char *target)
{ {
return iptablesInterfaceForward(ctx, iface, ADD); return iptablesInterfaceForward(ctx, iface, target, ADD);
} }
int int
iptablesRemoveInterfaceForward(iptablesContext *ctx, 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 static int
iptablesStateForward(iptablesContext *ctx, iptablesStateForward(iptablesContext *ctx,
const char *iface, const char *iface,
const char *target,
int action) int action)
{ {
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, return iptablesAddRemoveRule(ctx->forward_filter,
action, action,
"--out-interface", iface, "--out-interface", iface,
@ -645,44 +678,60 @@ iptablesStateForward(iptablesContext *ctx,
"--state", "ESTABLISHED,RELATED", "--state", "ESTABLISHED,RELATED",
"--jump", "ACCEPT", "--jump", "ACCEPT",
NULL); NULL);
}
} }
int int
iptablesAddStateForward(iptablesContext *ctx, iptablesAddStateForward(iptablesContext *ctx,
const char *iface) const char *iface,
const char *target)
{ {
return iptablesStateForward(ctx, iface, ADD); return iptablesStateForward(ctx, iface, target, ADD);
} }
int int
iptablesRemoveStateForward(iptablesContext *ctx, 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 static int
iptablesNonBridgedMasq(iptablesContext *ctx, iptablesNonBridgedMasq(iptablesContext *ctx,
const char *target,
int action) int action)
{ {
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, return iptablesAddRemoveRule(ctx->nat_postrouting,
action, action,
"--match", "physdev", "--match", "physdev",
"!", "--physdev-is-bridged", "!", "--physdev-is-bridged",
"--jump", "MASQUERADE", "--jump", "MASQUERADE",
NULL); NULL);
}
} }
int int
iptablesAddNonBridgedMasq(iptablesContext *ctx) iptablesAddNonBridgedMasq(iptablesContext *ctx,
const char *target)
{ {
return iptablesNonBridgedMasq(ctx, ADD); return iptablesNonBridgedMasq(ctx, target, ADD);
} }
int int
iptablesRemoveNonBridgedMasq(iptablesContext *ctx) iptablesRemoveNonBridgedMasq(iptablesContext *ctx,
const char *target)
{ {
return iptablesNonBridgedMasq(ctx, REMOVE); return iptablesNonBridgedMasq(ctx, target, REMOVE);
} }
/* /*

View File

@ -42,22 +42,30 @@ int iptablesRemoveUdpInput (iptablesContext *ctx,
int port); int port);
int iptablesAddPhysdevForward (iptablesContext *ctx, int iptablesAddPhysdevForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesRemovePhysdevForward (iptablesContext *ctx, int iptablesRemovePhysdevForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesAddInterfaceForward (iptablesContext *ctx, int iptablesAddInterfaceForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesRemoveInterfaceForward (iptablesContext *ctx, int iptablesRemoveInterfaceForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesAddStateForward (iptablesContext *ctx, int iptablesAddStateForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesRemoveStateForward (iptablesContext *ctx, int iptablesRemoveStateForward (iptablesContext *ctx,
const char *iface); const char *iface,
const char *target);
int iptablesAddNonBridgedMasq (iptablesContext *ctx); int iptablesAddNonBridgedMasq (iptablesContext *ctx,
int iptablesRemoveNonBridgedMasq (iptablesContext *ctx); const char *target);
int iptablesRemoveNonBridgedMasq (iptablesContext *ctx,
const char *target);
#endif /* __QEMUD_IPTABLES_H__ */ #endif /* __QEMUD_IPTABLES_H__ */

View File

@ -1032,7 +1032,18 @@ static void
qemudNetworkIfaceDisconnect(struct qemud_server *server, qemudNetworkIfaceDisconnect(struct qemud_server *server,
struct qemud_vm *vm ATTRIBUTE_UNUSED, struct qemud_vm *vm ATTRIBUTE_UNUSED,
struct qemud_vm_net_def *net) { 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) { int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
@ -1105,7 +1116,7 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
struct qemud_network *network, struct qemud_network *network,
char ***argv) { char ***argv) {
int i, len; int i, len;
char buf[BR_INET_ADDR_MAXLEN * 2]; char buf[PATH_MAX];
struct qemud_dhcp_range_def *range; struct qemud_dhcp_range_def *range;
len = len =
@ -1114,8 +1125,10 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
1 + /* --bind-interfaces */ 1 + /* --bind-interfaces */
2 + /* --pid-file "" */ 2 + /* --pid-file "" */
2 + /* --conf-file "" */ 2 + /* --conf-file "" */
/*2 + *//* --interface virbr0 */
2 + /* --except-interface lo */ 2 + /* --except-interface lo */
2 + /* --listen-address 10.0.0.1 */ 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 */ (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
1; /* NULL */ 1; /* NULL */
@ -1142,11 +1155,29 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
APPEND_ARG(*argv, i++, "--conf-file"); APPEND_ARG(*argv, i++, "--conf-file");
APPEND_ARG(*argv, i++, ""); 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++, "--except-interface");
APPEND_ARG(*argv, i++, "lo"); 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; range = network->def->ranges;
while (range) { while (range) {
@ -1211,7 +1242,7 @@ qemudAddIptablesRules(struct qemud_server *server,
} }
/* allow bridging from the bridge interface itself */ /* 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, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow bridging from '%s' : %s\n", "failed to add iptables rule to allow bridging from '%s' : %s\n",
network->bridge, strerror(err)); network->bridge, strerror(err));
@ -1219,7 +1250,7 @@ qemudAddIptablesRules(struct qemud_server *server,
} }
/* allow forwarding packets from the bridge interface */ /* 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, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow forwarding from '%s' : %s\n", "failed to add iptables rule to allow forwarding from '%s' : %s\n",
network->bridge, strerror(err)); network->bridge, strerror(err));
@ -1227,7 +1258,7 @@ qemudAddIptablesRules(struct qemud_server *server,
} }
/* allow forwarding packets to the bridge interface if they are part of an existing connection */ /* 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, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to allow forwarding to '%s' : %s\n", "failed to add iptables rule to allow forwarding to '%s' : %s\n",
network->bridge, strerror(err)); network->bridge, strerror(err));
@ -1235,7 +1266,7 @@ qemudAddIptablesRules(struct qemud_server *server,
} }
/* enable masquerading */ /* enable masquerading */
if ((err = iptablesAddNonBridgedMasq(server->iptables))) { if ((err = iptablesAddNonBridgedMasq(server->iptables, network->def->forwardDev))) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to add iptables rule to enable masquerading : %s\n", "failed to add iptables rule to enable masquerading : %s\n",
strerror(err)); strerror(err));
@ -1281,13 +1312,13 @@ qemudAddIptablesRules(struct qemud_server *server,
err6: err6:
iptablesRemoveTcpInput(server->iptables, network->bridge, 67); iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
err5: err5:
iptablesRemoveNonBridgedMasq(server->iptables); iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
err4: err4:
iptablesRemoveStateForward(server->iptables, network->bridge); iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
err3: err3:
iptablesRemoveInterfaceForward(server->iptables, network->bridge); iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
err2: err2:
iptablesRemovePhysdevForward(server->iptables, network->bridge); iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
err1: err1:
return 0; return 0;
} }
@ -1295,14 +1326,16 @@ qemudAddIptablesRules(struct qemud_server *server,
static void static void
qemudRemoveIptablesRules(struct qemud_server *server, qemudRemoveIptablesRules(struct qemud_server *server,
struct qemud_network *network) { struct qemud_network *network) {
if (network->def->forward) {
iptablesRemoveUdpInput(server->iptables, network->bridge, 53); iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
iptablesRemoveTcpInput(server->iptables, network->bridge, 53); iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
iptablesRemoveUdpInput(server->iptables, network->bridge, 67); iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
iptablesRemoveTcpInput(server->iptables, network->bridge, 67); iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
iptablesRemoveNonBridgedMasq(server->iptables); iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
iptablesRemoveStateForward(server->iptables, network->bridge); iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
iptablesRemoveInterfaceForward(server->iptables, network->bridge); iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
iptablesRemovePhysdevForward(server->iptables, network->bridge); iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
}
} }
static int static int
@ -1379,10 +1412,12 @@ int qemudStartNetworkDaemon(struct qemud_server *server,
goto err_delbr; goto err_delbr;
} }
if (!qemudAddIptablesRules(server, network)) if (network->def->forward &&
!qemudAddIptablesRules(server, network))
goto err_delbr1; goto err_delbr1;
if (!qemudEnableIpForwarding()) { if (network->def->forward &&
!qemudEnableIpForwarding()) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"failed to enable IP forwarding : %s\n", strerror(err)); "failed to enable IP forwarding : %s\n", strerror(err));
goto err_delbr2; goto err_delbr2;