Index: libvirt-0.4.0/src/qemu_conf.c =================================================================== --- libvirt-0.4.0.orig/src/qemu_conf.c 2008-02-25 22:53:29.000000000 +0100 +++ libvirt-0.4.0/src/qemu_conf.c 2008-02-25 22:56:57.000000000 +0100 @@ -2375,6 +2375,41 @@ } xmlXPathFreeObject(obj); + /* IPv4 routing setup */ + obj = xmlXPathEval(BAD_CAST "count(/network/route) > 0", ctxt); + if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) && + obj->boolval) { + if (!def->ipAddress[0] || + !def->netmask[0] || + def->forward) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "Routing requested, but no IPv4 address/netmask provided, or forwarding already enabled"); + goto error; + } + + def->route = 1; + tmp = xmlXPathEval(BAD_CAST "string(/network/route[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(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "route device name '%s' is too long", + (char*)tmp->stringval); + goto error; + } + strcpy(def->routeDev, (char*)tmp->stringval); + } else { + def->routeDev[0] = '\0'; + } + xmlXPathFreeObject(tmp); + tmp = NULL; + } else { + def->route = 0; + } + xmlXPathFreeObject(obj); + + xmlXPathFreeContext(ctxt); return def; @@ -2982,6 +3017,16 @@ } } + if (def->route) { + if (def->routeDev[0]) { + virBufferVSprintf(buf, " \n", + def->routeDev); + } else { + virBufferAdd(buf, " \n", -1); + } + } + + virBufferAdd(buf, " bridge) < 0) Index: libvirt-0.4.0/src/qemu_conf.h =================================================================== --- libvirt-0.4.0.orig/src/qemu_conf.h 2008-02-25 22:53:14.000000000 +0100 +++ libvirt-0.4.0/src/qemu_conf.h 2008-02-25 22:57:44.000000000 +0100 @@ -266,6 +266,9 @@ int forward; char forwardDev[BR_IFNAME_MAXLEN]; + int route; + char routeDev[BR_IFNAME_MAXLEN]; + char ipAddress[BR_INET_ADDR_MAXLEN]; char netmask[BR_INET_ADDR_MAXLEN]; char network[BR_INET_ADDR_MAXLEN+BR_INET_ADDR_MAXLEN+1]; Index: libvirt-0.4.0/docs/network.rng =================================================================== --- libvirt-0.4.0.orig/docs/network.rng 2008-03-02 22:08:28.000000000 +0100 +++ libvirt-0.4.0/docs/network.rng 2008-03-02 22:09:15.000000000 +0100 @@ -58,4 +58,11 @@ + + + + + + + Index: libvirt-0.4.0/src/qemu_driver.c =================================================================== --- libvirt-0.4.0.orig/src/qemu_driver.c 2008-02-25 23:19:03.000000000 +0100 +++ libvirt-0.4.0/src/qemu_driver.c 2008-03-02 23:18:44.000000000 +0100 @@ -941,6 +941,98 @@ } static int +qemudAddMasqueradingIptablesRules(virConnectPtr conn, + struct qemud_driver *driver, + struct qemud_network *network) { + int err; + /* allow forwarding packets from the bridge interface */ + if ((err = iptablesAddForwardAllowOut(driver->iptables, + network->def->network, + network->bridge, + network->def->forwardDev))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow forwarding from '%s' : %s\n", + network->bridge, strerror(err)); + goto masqerr1; + } + + /* allow forwarding packets to the bridge interface if they are part of an existing connection */ + if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables, + network->def->network, + network->bridge, + network->def->forwardDev))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow forwarding to '%s' : %s\n", + network->bridge, strerror(err)); + goto masqerr2; + } + + /* enable masquerading */ + if ((err = iptablesAddForwardMasquerade(driver->iptables, + network->def->network, + network->def->forwardDev))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to enable masquerading : %s\n", + strerror(err)); + goto masqerr3; + } + + return 1; + + masqerr3: + iptablesRemoveForwardAllowRelatedIn(driver->iptables, + network->def->network, + network->bridge, + network->def->forwardDev); + masqerr2: + iptablesRemoveForwardAllowOut(driver->iptables, + network->def->network, + network->bridge, + network->def->forwardDev); + masqerr1: + return 0; +} + +static int +qemudAddRoutingIptablesRules(virConnectPtr conn, + struct qemud_driver *driver, + struct qemud_network *network) { + int err; + /* allow routing packets from the bridge interface */ + if ((err = iptablesAddForwardAllowOut(driver->iptables, + network->def->network, + network->bridge, + network->def->routeDev))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow routing from '%s' : %s\n", + network->bridge, strerror(err)); + goto routeerr1; + } + + /* allow routing packets to the bridge interface */ + if ((err = iptablesAddForwardAllowIn(driver->iptables, + network->def->network, + network->bridge, + network->def->routeDev))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow routing to '%s' : %s\n", + network->bridge, strerror(err)); + goto routeerr2; + } + + return 1; + + + routeerr2: + iptablesRemoveForwardAllowOut(driver->iptables, + network->def->network, + network->bridge, + network->def->forwardDev); + routeerr1: + return 0; +} + +static int qemudAddIptablesRules(virConnectPtr conn, struct qemud_driver *driver, struct qemud_network *network) { @@ -1007,55 +1099,19 @@ goto err7; } - - /* The remaining rules are only needed for IP forwarding */ - if (!network->def->forward) - return 1; - - /* allow forwarding packets from the bridge interface */ - if ((err = iptablesAddForwardAllowOut(driver->iptables, - network->def->network, - network->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "failed to add iptables rule to allow forwarding from '%s' : %s\n", - network->bridge, strerror(err)); - goto err8; - } - - /* allow forwarding packets to the bridge interface if they are part of an existing connection */ - if ((err = iptablesAddForwardAllowIn(driver->iptables, - network->def->network, - network->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "failed to add iptables rule to allow forwarding to '%s' : %s\n", - network->bridge, strerror(err)); - goto err9; + /* If masquerading is enabled, set up the rules*/ + if (network->def->forward) { + if (qemudAddMasqueradingIptablesRules(conn, driver, network)) + return 1; } - - /* enable masquerading */ - if ((err = iptablesAddForwardMasquerade(driver->iptables, - network->def->network, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "failed to add iptables rule to enable masquerading : %s\n", - strerror(err)); - goto err10; + /* else if routing is enabled, set up the rules*/ + else if (network->def->route) { + if (qemudAddRoutingIptablesRules(conn, driver, network)) + return 1; } + else + return 1; - return 1; - - err10: - iptablesRemoveForwardAllowIn(driver->iptables, - network->def->network, - network->bridge, - network->def->forwardDev); - err9: - iptablesRemoveForwardAllowOut(driver->iptables, - network->def->network, - network->bridge, - network->def->forwardDev); err8: iptablesRemoveForwardAllowCross(driver->iptables, network->bridge); @@ -1077,6 +1133,7 @@ return 0; } + static void qemudRemoveIptablesRules(struct qemud_driver *driver, struct qemud_network *network) { @@ -1196,7 +1253,7 @@ if (!qemudAddIptablesRules(conn, driver, network)) goto err_delbr1; - if (network->def->forward && + if ((network->def->forward || network->def->route) && !qemudEnableIpForwarding()) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "failed to enable IP forwarding : %s\n", strerror(err)); Index: libvirt-0.4.0/src/iptables.c =================================================================== --- libvirt-0.4.0.orig/src/iptables.c 2008-03-02 23:19:44.000000000 +0100 +++ libvirt-0.4.0/src/iptables.c 2008-03-02 23:25:29.000000000 +0100 @@ -808,7 +808,7 @@ * and associated with an existing connection */ static int -iptablesForwardAllowIn(iptablesContext *ctx, +iptablesForwardAllowRelatedIn(iptablesContext *ctx, const char *network, const char *iface, const char *physdev, @@ -837,7 +837,7 @@ } /** - * iptablesAddForwardAllowIn: + * iptablesAddForwardAllowRelatedIn: * @ctx: pointer to the IP table context * @network: the source network name * @iface: the output interface name @@ -850,6 +850,77 @@ * Returns 0 in case of success or an error code otherwise */ int +iptablesAddForwardAllowRelatedIn(iptablesContext *ctx, + const char *network, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, ADD); +} + +/** + * iptablesRemoveForwardAllowRelatedIn: + * @ctx: pointer to the IP table context + * @network: the source network name + * @iface: the output interface name + * @physdev: the physical input device or NULL + * + * Remove rules from the IP table context hence forbidding the traffic for + * network @network on @physdev device to be forwarded to + * interface @iface. This stops the inbound traffic on a bridge. + * + * Returns 0 in case of success or an error code otherwise + */ +int +iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx, + const char *network, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, REMOVE); +} + +/* Allow all traffic destined to the bridge, with a valid network address + */ +static int +iptablesForwardAllowIn(iptablesContext *ctx, + const char *network, + const char *iface, + const char *physdev, + int action) +{ + if (physdev && physdev[0]) { + return iptablesAddRemoveRule(ctx->forward_filter, + action, + "--destination", network, + "--in-interface", physdev, + "--out-interface", iface, + "--jump", "ACCEPT", + NULL); + } else { + return iptablesAddRemoveRule(ctx->forward_filter, + action, + "--destination", network, + "--out-interface", iface, + "--jump", "ACCEPT", + NULL); + } +} + +/** + * iptablesAddForwardAllowIn: + * @ctx: pointer to the IP table context + * @network: the source network name + * @iface: the output interface name + * @physdev: the physical input device or NULL + * + * Add rules to the IP table context to allow the traffic for the + * network @network on @physdev device to be forwarded to + * interface @iface. This allow the inbound traffic on a bridge. + * + * Returns 0 in case of success or an error code otherwise + */ +int iptablesAddForwardAllowIn(iptablesContext *ctx, const char *network, const char *iface,