Discussion:
[libvirt] [PATCH v3 14/14] Extensions for iptables rules
(too old to reply)
s***@us.ibm.com
2010-03-23 14:54:20 UTC
Permalink
This patch adds support for L3/L4 filtering using iptables. This adds
support for 'tcp', 'udp', 'icmp', 'igmp', 'sctp' etc. filtering.

As mentioned in the introduction, a .c file provided by this patch
is #include'd into a .c file. This will need work, but should be alright
for review.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
configure.ac | 7
src/conf/nwfilter_conf.c | 278 ++++++++
src/conf/nwfilter_conf.h | 73 ++
src/libvirt_private.syms | 1
src/nwfilter/nwfilter_ebiptables_driver.c | 112 +++
src/nwfilter/nwfilter_ebiptables_driver.h | 1
src/nwfilter/nwfilter_iptables.c | 1016 ++++++++++++++++++++++++++++++
7 files changed, 1477 insertions(+), 11 deletions(-)

Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -71,6 +71,9 @@
snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)


+//FIXME: only temporary
+#include "nwfilter_iptables.c"
+
static const char *supported_protocols[] = {
"ipv4",
"ipv6",
@@ -212,7 +215,8 @@ ebiptablesAddRuleInst(virConnectPtr conn
char *commandTemplate,
enum virNWFilterChainSuffixType neededChain,
char chainprefix,
- unsigned int priority)
+ unsigned int priority,
+ bool isIptablesRule)
{
ebiptablesRuleInstPtr inst;

@@ -225,6 +229,7 @@ ebiptablesAddRuleInst(virConnectPtr conn
inst->neededProtocolChain = neededChain;
inst->chainprefix = chainprefix;
inst->priority = priority;
+ inst->isIptablesRule = isIptablesRule;

return virNWFilterRuleInstAddData(conn, res, inst);
}
@@ -741,6 +746,9 @@ ebtablesCreateRuleInstance(virConnectPtr
CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
EBTABLES_DEFAULT_TABLE, chain);
break;
+
+ default:
+ return -1;
}

virBufferVSprintf(&buf,
@@ -759,7 +767,8 @@ ebtablesCreateRuleInstance(virConnectPtr
virBufferContentAndReset(&buf),
nwfilter->chainsuffix,
chainPrefix,
- rule->priority);
+ rule->priority,
+ 0);

err_exit:
virBufferFreeAndReset(&buf);
@@ -785,7 +794,7 @@ err_exit:
*/
static int
ebiptablesCreateRuleInstance(virConnectPtr conn,
- enum virDomainNetType nettype ATTRIBUTE_UNUSED,
+ enum virDomainNetType nettype,
virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule,
const char *ifname,
@@ -825,6 +834,33 @@ ebiptablesCreateRuleInstance(virConnectP
res);
}
break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_TCP:
+ case VIR_NWFILTER_RULE_PROTOCOL_UDP:
+ case VIR_NWFILTER_RULE_PROTOCOL_SCP:
+ case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
+ case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
+ case VIR_NWFILTER_RULE_PROTOCOL_ALL:
+ if (nettype == VIR_DOMAIN_NET_TYPE_DIRECT) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("'%s' protocol not support for net type '%s'"),
+ virNWFilterRuleProtocolTypeToString(rule->prtclType),
+ virDomainNetTypeToString(nettype));
+ return 1;
+ }
+ rc = iptablesCreateRuleInstance(conn,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_LAST:
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("illegal protocol type"));
+ rc = 1;
+ break;
}

return rc;
@@ -1352,16 +1388,19 @@ ebiptablesApplyRules(virConnectPtr conn,
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
int chains_in = 0, chains_out = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int haveIptables = 0;

if (inst)
qsort(inst, nruleInstances, sizeof(inst[0]),
ebiptablesRuleOrderSort);

for (i = 0; i < nruleInstances; i++) {
- if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
- chains_in |= (1 << inst[i]->neededProtocolChain);
- else
- chains_out |= (1 << inst[i]->neededProtocolChain);
+ if (!inst[i]->isIptablesRule) {
+ if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
+ chains_in |= (1 << inst[i]->neededProtocolChain);
+ else
+ chains_out |= (1 << inst[i]->neededProtocolChain);
+ }
}

ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
@@ -1369,6 +1408,7 @@ ebiptablesApplyRules(virConnectPtr conn,
ebtablesRemoveTmpSubChains(conn, &buf, ifname);
ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+ ebiptablesExecCLI(conn, &buf, &cli_status);

if (chains_in != 0)
ebtablesCreateTmpRootChain(conn, &buf, 1, ifname, 1);
@@ -1395,15 +1435,49 @@ ebiptablesApplyRules(virConnectPtr conn,
goto tear_down_tmpebchains;

for (i = 0; i < nruleInstances; i++)
- ebiptablesInstCommand(conn, &buf,
- inst[i]->commandTemplate,
- 'A', -1, 1);
+ if (!inst[i]->isIptablesRule)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'A', -1, 1);
+ else
+ haveIptables = 1;

if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
goto tear_down_tmpebchains;

// FIXME: establishment of iptables user define table tree goes here

+ if (haveIptables) {
+ iptablesUnlinkTmpRootChains(conn, &buf, ifname);
+ iptablesRemoveTmpRootChains(conn, &buf, ifname);
+
+ iptablesCreateBaseChains(conn, &buf);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ iptablesCreateTmpRootChains(conn, &buf, ifname);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpiptchains;
+
+ iptablesLinkTmpRootChains(conn, &buf, ifname);
+ iptablesSetupVirtInPost(conn, &buf, ifname);
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpiptchains;
+
+ for (i = 0; i < nruleInstances; i++) {
+ if (inst[i]->isIptablesRule)
+ iptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'A', -1, 1);
+ }
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpiptchains;
+ }
+
+
// END IPTABLES stuff

if (chains_in != 0)
@@ -1414,6 +1488,15 @@ ebiptablesApplyRules(virConnectPtr conn,
if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
goto tear_down_ebsubchains_and_unlink;

+ // clean up IPtables in any case
+ iptablesUnlinkRootChains(conn, &buf, ifname);
+ iptablesRemoveRootChains(conn, &buf, ifname);
+
+ if (haveIptables) {
+ iptablesRenameTmpRootChains(conn, &buf, ifname);
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+ }
+
ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
ebtablesUnlinkRootChain(conn, &buf, 0, ifname);

@@ -1430,10 +1513,15 @@ ebiptablesApplyRules(virConnectPtr conn,

return 0;

+
tear_down_ebsubchains_and_unlink:
ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);

+tear_down_tmpiptchains:
+ if (haveIptables)
+ iptablesRemoveTmpRootChains(conn, &buf, ifname);
+
tear_down_tmpebchains:
ebtablesRemoveTmpSubChains(conn, &buf, ifname);
ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
@@ -1510,6 +1598,10 @@ ebiptablesAllTeardown(const char *ifname
int cli_status;
virConnectPtr conn = NULL;

+ iptablesUnlinkRootChains(conn, &buf, ifname);
+ iptablesClearVirtInPost(conn, &buf, ifname);
+ iptablesRemoveRootChains(conn, &buf, ifname);
+
ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
ebtablesUnlinkRootChain(conn, &buf, 0, ifname);

Index: libvirt-acl/src/nwfilter/nwfilter_iptables.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_iptables.c
@@ -0,0 +1,1016 @@
+// all content of this file will be copied into nwfilter_ebiptables_driver.c
+
+#define IPTABLES_CMD IPTABLES_PATH
+#define GREP_CMD GREP_PATH
+#define GAWK_CMD GAWK_PATH
+
+#define VIRT_IN_CHAIN "virt-in"
+#define VIRT_OUT_CHAIN "virt-out"
+#define VIRT_IN_POST_CHAIN "virt-in-post"
+#define HOST_IN_CHAIN "host-in"
+
+#define PRINT_IPT_ROOT_CHAIN(buf, prefix, ifname) \
+ snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname)
+
+#define PHYSDEV_IN "--physdev-in"
+#define PHYSDEV_OUT "--physdev-out"
+
+static const char *m_state_out_str = "-m state --state NEW,ESTABLISHED";
+static const char *m_state_in_str = "-m state --state ESTABLISHED";
+static const char *m_physdev_in_str = "-m physdev " PHYSDEV_IN;
+static const char *m_physdev_out_str = "-m physdev " PHYSDEV_OUT;
+
+#define MATCH_STATE_OUT m_state_out_str
+#define MATCH_STATE_IN m_state_in_str
+#define MATCH_PHYSDEV_IN m_physdev_in_str
+#define MATCH_PHYSDEV_OUT m_physdev_out_str
+
+
+/* temporary local function declaration */
+static int
+printDataType(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item);
+
+static int
+ebiptablesAddRuleInst(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ char *commandTemplate,
+ enum virNWFilterChainSuffixType neededChain,
+ char chainprefix,
+ unsigned int priority,
+ bool isIptablesRule);
+
+
+
+static int iptablesLinkIPTablesBaseChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *udchain,
+ const char *syschain,
+ unsigned int pos,
+ int stopOnError)
+{
+ virBufferVSprintf(buf,
+ "res=$("
+ IPTABLES_CMD " -L %s -n --line-number | "
+ GREP_CMD " \" %s \")\n"
+ "if [ $? -ne 0 ]; then\n"
+ " " IPTABLES_CMD " -I %s %d -j %s\n"
+ "else\n"
+ " r=$(echo $res | " GAWK_CMD " '{print $1}')\n"
+ " if [ \"${r}\" != \"%d\" ]; then\n"
+ " " CMD_DEF(IPTABLES_CMD " -I %s %d -j %s") CMD_SEPARATOR
+ " " CMD_EXEC
+ " %s"
+ " let r=r+1\n"
+ " " CMD_DEF(IPTABLES_CMD " -D %s ${r}") CMD_SEPARATOR
+ " " CMD_EXEC
+ " %s"
+ " fi\n"
+ "fi\n",
+
+ syschain, udchain,
+
+ syschain, pos, udchain,
+
+ pos,
+
+ syschain, pos, udchain,
+ CMD_STOPONERR(stopOnError),
+
+ syschain,
+ CMD_STOPONERR(stopOnError));
+ return 0;
+}
+
+
+static int iptablesCreateBaseChains(virConnectPtr conn,
+ virBufferPtr buf)
+{
+ virBufferAddLit(buf, IPTABLES_CMD " -N " VIRT_IN_CHAIN CMD_SEPARATOR
+ IPTABLES_CMD " -N " VIRT_OUT_CHAIN CMD_SEPARATOR
+ IPTABLES_CMD " -N " VIRT_IN_POST_CHAIN CMD_SEPARATOR
+ IPTABLES_CMD " -N " HOST_IN_CHAIN CMD_SEPARATOR);
+ iptablesLinkIPTablesBaseChain(conn, buf,
+ VIRT_IN_CHAIN , "FORWARD", 1, 1);
+ iptablesLinkIPTablesBaseChain(conn, buf,
+ VIRT_OUT_CHAIN , "FORWARD", 2, 1);
+ iptablesLinkIPTablesBaseChain(conn, buf,
+ VIRT_IN_POST_CHAIN, "FORWARD", 3, 1);
+ iptablesLinkIPTablesBaseChain(conn, buf,
+ HOST_IN_CHAIN , "INPUT" , 1, 1);
+
+ return 0;
+}
+
+
+static int
+iptablesCreateTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ char prefix,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix[2] = {
+ prefix,
+ (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP
+ };
+
+ PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(IPTABLES_CMD " -N %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ chain,
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+iptablesCreateTmpRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesCreateTmpRootChain(conn, buf, 'F', 0, ifname, 1);
+ iptablesCreateTmpRootChain(conn, buf, 'F', 1, ifname, 1);
+ iptablesCreateTmpRootChain(conn, buf, 'H', 1, ifname, 1);
+ return 0;
+}
+
+
+static int
+_iptablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ char prefix,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix[2] = {
+ prefix,
+ };
+
+ if (isTempChain)
+ chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ else
+ chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ IPTABLES_CMD " -F %s" CMD_SEPARATOR
+ IPTABLES_CMD " -X %s" CMD_SEPARATOR,
+ chain,
+ chain);
+
+ return 0;
+}
+
+
+static int
+iptablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ char prefix,
+ int incoming,
+ const char *ifname)
+{
+ return _iptablesRemoveRootChain(conn, buf, prefix, incoming, ifname, 0);
+}
+
+
+static int
+iptablesRemoveTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ char prefix,
+ int incoming,
+ const char *ifname)
+{
+ return _iptablesRemoveRootChain(conn, buf, prefix, incoming, ifname, 1);
+}
+
+
+static int
+iptablesRemoveTmpRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesRemoveTmpRootChain(conn, buf, 'F', 0, ifname);
+ iptablesRemoveTmpRootChain(conn, buf, 'F', 1, ifname);
+ iptablesRemoveTmpRootChain(conn, buf, 'H', 1, ifname);
+ return 0;
+}
+
+
+static int
+iptablesRemoveRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesRemoveRootChain(conn, buf, 'F', 0, ifname);
+ iptablesRemoveRootChain(conn, buf, 'F', 1, ifname);
+ iptablesRemoveRootChain(conn, buf, 'H', 1, ifname);
+ return 0;
+}
+
+
+static int
+iptablesLinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *basechain,
+ char prefix,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix[2] = {
+ prefix,
+ (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP
+ };
+ const char *match = (incoming) ? MATCH_PHYSDEV_IN
+ : MATCH_PHYSDEV_OUT;
+
+ PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(IPTABLES_CMD " -A %s "
+ "%s %s -g %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ basechain,
+ match, ifname, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+iptablesLinkTmpRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesLinkTmpRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname, 1);
+ iptablesLinkTmpRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname, 1);
+ iptablesLinkTmpRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname, 1);
+
+ return 0;
+}
+
+
+static int
+iptablesSetupVirtInPost(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ const char *match = MATCH_PHYSDEV_IN;
+ virBufferVSprintf(buf,
+ "res=$(" IPTABLES_CMD " -L " VIRT_IN_POST_CHAIN
+ " | grep \"\\%s %s\")\n"
+ "if [ \"${res}\" == \"\" ]; then "
+ CMD_DEF(IPTABLES_CMD
+ " -A " VIRT_IN_POST_CHAIN
+ " %s %s -j ACCEPT") CMD_SEPARATOR
+ CMD_EXEC
+ "%s"
+ "fi\n",
+ PHYSDEV_IN, ifname,
+ match, ifname,
+ CMD_STOPONERR(1));
+ return 0;
+}
+
+
+static int
+iptablesClearVirtInPost(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ const char *match = MATCH_PHYSDEV_IN;
+ virBufferVSprintf(buf,
+ IPTABLES_CMD
+ " -D " VIRT_IN_POST_CHAIN
+ " %s %s -j ACCEPT" CMD_SEPARATOR,
+ match, ifname);
+ return 0;
+}
+
+static int
+_iptablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *basechain,
+ char prefix,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix[2] = {
+ prefix,
+ };
+ if (isTempChain)
+ chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ else
+ chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+ const char *match = (incoming) ? MATCH_PHYSDEV_IN
+ : MATCH_PHYSDEV_OUT;
+
+ PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ IPTABLES_CMD " -D %s "
+ "%s %s -g %s" CMD_SEPARATOR,
+ basechain,
+ match, ifname, chain);
+
+ return 0;
+}
+
+
+static int
+iptablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *basechain,
+ char prefix,
+ int incoming, const char *ifname)
+{
+ return _iptablesUnlinkRootChain(conn, buf,
+ basechain, prefix, incoming, ifname, 0);
+}
+
+
+static int
+iptablesUnlinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *basechain,
+ char prefix,
+ int incoming, const char *ifname)
+{
+ return _iptablesUnlinkRootChain(conn, buf,
+ basechain, prefix, incoming, ifname, 1);
+}
+
+
+static int
+iptablesUnlinkRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesUnlinkRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
+ iptablesUnlinkRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname);
+ iptablesUnlinkRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname);
+
+ return 0;
+}
+
+
+static int
+iptablesUnlinkTmpRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesUnlinkTmpRootChain(conn, buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
+ iptablesUnlinkTmpRootChain(conn, buf, VIRT_IN_CHAIN , 'F', 1, ifname);
+ iptablesUnlinkTmpRootChain(conn, buf, HOST_IN_CHAIN , 'H', 1, ifname);
+ return 0;
+}
+
+
+static int
+iptablesRenameTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ char prefix,
+ int incoming,
+ const char *ifname)
+{
+ char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char tmpChainPrefix[2] = {
+ prefix,
+ (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP
+ };
+ char chainPrefix[2] = {
+ prefix,
+ (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT
+ };
+
+ PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
+ PRINT_IPT_ROOT_CHAIN( chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ IPTABLES_CMD " -E %s %s" CMD_SEPARATOR,
+ tmpchain,
+ chain);
+ return 0;
+}
+
+
+static int
+iptablesRenameTmpRootChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ iptablesRenameTmpRootChain(conn, buf, 'F', 0, ifname);
+ iptablesRenameTmpRootChain(conn, buf, 'F', 1, ifname);
+ iptablesRenameTmpRootChain(conn, buf, 'H', 1, ifname);
+ return 0;
+}
+
+
+static void
+iptablesInstCommand(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *templ, char cmd, int pos,
+ int stopOnError)
+{
+ char position[10] = { 0 };
+ if (pos >= 0)
+ snprintf(position, sizeof(position), "%d", pos);
+ virBufferVSprintf(buf, templ, cmd, position);
+ virBufferVSprintf(buf, CMD_SEPARATOR "%s",
+ CMD_STOPONERR(stopOnError));
+}
+
+
+static int
+iptablesHandleSrcMacAddr(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ virNWFilterHashTablePtr vars,
+ nwItemDescPtr srcMacAddr,
+ int directionIn ATTRIBUTE_UNUSED)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+
+ if (HAS_ENTRY_ITEM(srcMacAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ srcMacAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -m mac %s --mac-source %s",
+ ENTRY_GET_NEG_SIGN(srcMacAddr),
+ macaddr);
+ }
+
+ return 0;
+
+err_exit:
+ virBufferFreeAndReset(buf);
+
+ return 1;
+}
+
+
+static int
+iptablesHandleIpHdr(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ virNWFilterHashTablePtr vars,
+ ipHdrDataDefPtr ipHdr,
+ int directionIn)
+{
+ char ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ const char *src = "--source";
+ const char *dst = "--destination";
+ const char *srcrange = "--src-range";
+ const char *dstrange = "--dst-range";
+ if (directionIn) {
+ src = "--destination";
+ dst = "--source";
+ srcrange = "--dst-range";
+ dstrange = "--src-range";
+ }
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " %s %s %s",
+ ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPAddr),
+ src,
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &ipHdr->dataSrcIPMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ number);
+ }
+ } else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataSrcIPFrom))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -m iprange %s %s %s",
+ ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPFrom),
+ srcrange,
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataSrcIPTo))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "-%s",
+ ipaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " %s %s %s",
+ ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPAddr),
+ dst,
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &ipHdr->dataDstIPMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ number);
+
+ }
+ } else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataDstIPFrom))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -m iprange %s %s %s",
+ ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPFrom),
+ dstrange,
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &ipHdr->dataDstIPTo))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "-%s",
+ ipaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &ipHdr->dataDSCP))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -m dscp %s --dscp %s",
+ ENTRY_GET_NEG_SIGN(&ipHdr->dataDSCP),
+ number);
+ }
+
+ return 0;
+
+err_exit:
+ virBufferFreeAndReset(buf);
+
+ return 1;
+}
+
+
+static int
+iptablesHandlePortData(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ virNWFilterHashTablePtr vars,
+ portDataDefPtr portData,
+ int directionIn)
+{
+ char portstr[20];
+ const char *sport = "--sport";
+ const char *dport = "--dport";
+ if (directionIn) {
+ sport = "--dport";
+ dport = "--sport";
+ }
+
+ if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+ &portData->dataSrcPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " %s %s %s",
+ ENTRY_GET_NEG_SIGN(&portData->dataSrcPortStart),
+ sport,
+ portstr);
+
+ if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+ &portData->dataSrcPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ ":%s",
+ portstr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+ &portData->dataDstPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " %s %s %s",
+ ENTRY_GET_NEG_SIGN(&portData->dataDstPortStart),
+ dport,
+ portstr);
+
+ if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+ &portData->dataDstPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ ":%s",
+ portstr);
+ }
+ }
+
+ return 0;
+
+err_exit:
+ return 1;
+}
+
+/*
+ * _iptablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @chainPrefix : The prefix to put in front of the name of the chain
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+_iptablesCreateRuleInstance(virConnectPtr conn,
+ int directionIn,
+ const char *chainPrefix,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res,
+ const char *match,
+ const char *accept_target)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char number[20];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ const char *target;
+
+ PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_TCP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s",
+ chain);
+
+ virBufferAddLit(&buf, " -p tcp");
+
+ if (iptablesHandleSrcMacAddr(conn,
+ &buf,
+ vars,
+ &rule->p.tcpHdrFilter.dataSrcMACAddr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandleIpHdr(conn,
+ &buf,
+ vars,
+ &rule->p.tcpHdrFilter.ipHdr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandlePortData(conn,
+ &buf,
+ vars,
+ &rule->p.tcpHdrFilter.portData,
+ directionIn))
+ goto err_exit;
+
+ if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.tcpHdrFilter.dataTCPOption))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " %s --tcp-option %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption),
+ number);
+ }
+
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_UDP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s",
+ chain);
+
+ virBufferAddLit(&buf, " -p udp");
+
+ if (iptablesHandleSrcMacAddr(conn,
+ &buf,
+ vars,
+ &rule->p.udpHdrFilter.dataSrcMACAddr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandleIpHdr(conn,
+ &buf,
+ vars,
+ &rule->p.udpHdrFilter.ipHdr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandlePortData(conn,
+ &buf,
+ vars,
+ &rule->p.udpHdrFilter.portData,
+ directionIn))
+ goto err_exit;
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_SCP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s",
+ chain);
+
+ virBufferAddLit(&buf, " -p scp");
+
+ if (iptablesHandleSrcMacAddr(conn,
+ &buf,
+ vars,
+ &rule->p.sctpHdrFilter.dataSrcMACAddr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandleIpHdr(conn,
+ &buf,
+ vars,
+ &rule->p.sctpHdrFilter.ipHdr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandlePortData(conn,
+ &buf,
+ vars,
+ &rule->p.sctpHdrFilter.portData,
+ directionIn))
+ goto err_exit;
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s",
+ chain);
+
+ virBufferAddLit(&buf, " -p icmp");
+
+ if (iptablesHandleSrcMacAddr(conn,
+ &buf,
+ vars,
+ &rule->p.icmpHdrFilter.dataSrcMACAddr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandleIpHdr(conn,
+ &buf,
+ vars,
+ &rule->p.icmpHdrFilter.ipHdr,
+ directionIn))
+ goto err_exit;
+
+ if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.icmpHdrFilter.dataICMPType))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " %s --icmp-type %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.icmpHdrFilter.dataICMPCode))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ALL:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE IPTABLES_CMD " -%%c %s %%s",
+ chain);
+
+ virBufferAddLit(&buf, " -p all");
+
+ if (iptablesHandleSrcMacAddr(conn,
+ &buf,
+ vars,
+ &rule->p.allHdrFilter.dataSrcMACAddr,
+ directionIn))
+ goto err_exit;
+
+ if (iptablesHandleIpHdr(conn,
+ &buf,
+ vars,
+ &rule->p.allHdrFilter.ipHdr,
+ directionIn))
+ goto err_exit;
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (match)
+ virBufferVSprintf(&buf, " %s", match);
+
+ if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT)
+ target = accept_target;
+ else
+ target = "DROP";
+
+ virBufferVSprintf(&buf,
+ " -j %s" CMD_DEF_POST CMD_SEPARATOR
+ CMD_EXEC,
+ target);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+
+ return ebiptablesAddRuleInst(conn,
+ res,
+ virBufferContentAndReset(&buf),
+ nwfilter->chainsuffix,
+ '\0',
+ rule->priority,
+ 1);
+
+
+err_exit:
+ virBufferFreeAndReset(&buf);
+
+ return -1;
+
+}
+
+
+static int
+iptablesCreateRuleInstance(virConnectPtr conn,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ int rc;
+ int directionIn = 0;
+ char chainPrefix[2];
+ int needState = 1;
+
+ if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
+ (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
+ directionIn = 1;
+ needState = 0;
+ }
+
+ chainPrefix[0] = 'F';
+
+ chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
+ rc = _iptablesCreateRuleInstance(conn,
+ directionIn,
+ chainPrefix,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res,
+ needState ? MATCH_STATE_OUT
+ : NULL,
+ "RETURN");
+ if (rc)
+ return rc;
+
+ chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
+ rc = _iptablesCreateRuleInstance(conn,
+ !directionIn,
+ chainPrefix,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res,
+ needState ? MATCH_STATE_IN
+ : NULL,
+ "ACCEPT");
+ if (rc)
+ return rc;
+
+ chainPrefix[0] = 'H';
+ chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
+ rc = _iptablesCreateRuleInstance(conn,
+ directionIn,
+ chainPrefix,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res,
+ NULL,
+ "ACCEPT");
+ if (rc)
+ return rc;
+
+ return rc;
+}
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.h
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -150,6 +150,10 @@ struct _ipHdrDataDef {
nwItemDesc dataDstIPAddr;
nwItemDesc dataDstIPMask;
nwItemDesc dataProtocolID;
+ nwItemDesc dataSrcIPFrom;
+ nwItemDesc dataSrcIPTo;
+ nwItemDesc dataDstIPFrom;
+ nwItemDesc dataDstIPTo;
nwItemDesc dataDSCP;
};

@@ -182,6 +186,61 @@ struct _ipv6HdrFilterDef {
};


+typedef struct _icmpHdrFilterDef icmpHdrFilterDef;
+typedef icmpHdrFilterDef *icmpHdrFilterDefPtr;
+struct _icmpHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+ nwItemDesc dataICMPType;
+ nwItemDesc dataICMPCode;
+ nwItemDesc dataStateFlags;
+};
+
+
+typedef struct _allHdrFilterDef allHdrFilterDef;
+typedef allHdrFilterDef *allHdrFilterDefPtr;
+struct _allHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+};
+
+
+typedef struct _igmpHdrFilterDef igmpHdrFilterDef;
+typedef igmpHdrFilterDef *igmpHdrFilterDefPtr;
+struct _igmpHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+};
+
+
+typedef struct _tcpHdrFilterDef tcpHdrFilterDef;
+typedef tcpHdrFilterDef *tcpHdrFilterDefPtr;
+struct _tcpHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+ nwItemDesc dataTCPOption;
+};
+
+
+typedef struct _udpHdrFilterDef udpHdrFilterDef;
+typedef udpHdrFilterDef *udpHdrFilterDefPtr;
+struct _udpHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+};
+
+
+typedef struct _sctpHdrFilterDef sctpHdrFilterDef;
+typedef sctpHdrFilterDef *sctpHdrFilterDefPtr;
+struct _sctpHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+};
+
+
enum virNWFilterRuleActionType {
VIR_NWFILTER_RULE_ACTION_DROP = 0,
VIR_NWFILTER_RULE_ACTION_ACCEPT,
@@ -210,6 +269,14 @@ enum virNWFilterRuleProtocolType {
VIR_NWFILTER_RULE_PROTOCOL_ARP,
VIR_NWFILTER_RULE_PROTOCOL_IP,
VIR_NWFILTER_RULE_PROTOCOL_IPV6,
+ VIR_NWFILTER_RULE_PROTOCOL_TCP,
+ VIR_NWFILTER_RULE_PROTOCOL_ICMP,
+ VIR_NWFILTER_RULE_PROTOCOL_IGMP,
+ VIR_NWFILTER_RULE_PROTOCOL_UDP,
+ VIR_NWFILTER_RULE_PROTOCOL_SCP,
+ VIR_NWFILTER_RULE_PROTOCOL_ALL,
+
+ VIR_NWFILTER_RULE_PROTOCOL_LAST
};

enum virNWFilterEbtablesTableType {
@@ -236,6 +303,12 @@ struct _virNWFilterRuleDef {
arpHdrFilterDef arpHdrFilter;
ipHdrFilterDef ipHdrFilter;
ipv6HdrFilterDef ipv6HdrFilter;
+ tcpHdrFilterDef tcpHdrFilter;
+ icmpHdrFilterDef icmpHdrFilter;
+ udpHdrFilterDef udpHdrFilter;
+ allHdrFilterDef allHdrFilter;
+ igmpHdrFilterDef igmpHdrFilter;
+ sctpHdrFilterDef sctpHdrFilter;
} p;

int nvars;
Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.c
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -76,6 +76,19 @@ VIR_ENUM_IMPL(virNWFilterChainSuffix, VI
"ipv4",
"ipv6");

+VIR_ENUM_IMPL(virNWFilterRuleProtocol, VIR_NWFILTER_RULE_PROTOCOL_LAST,
+ "none",
+ "mac",
+ "arp",
+ "ip",
+ "ipv6",
+ "tcp",
+ "icmp",
+ "igmp",
+ "udp",
+ "scp",
+ "all");
+

/*
* a map entry for a simple static int-to-string map
@@ -117,6 +130,10 @@ static const char srcipaddr_str[] = "
static const char srcipmask_str[] = "srcipmask";
static const char dstipaddr_str[] = "dstipaddr";
static const char dstipmask_str[] = "dstipmask";
+static const char srcipfrom_str[] = "srcipfrom";
+static const char srcipto_str[] = "srcipto";
+static const char dstipfrom_str[] = "dstipfrom";
+static const char dstipto_str[] = "dstipto";
static const char srcportstart_str[] = "srcportstart";
static const char srcportend_str[] = "srcportend";
static const char dstportstart_str[] = "dstportstart";
@@ -135,6 +152,10 @@ static const char dscp_str[] = "
#define SRCIPMASK srcipmask_str
#define DSTIPADDR dstipaddr_str
#define DSTIPMASK dstipmask_str
+#define SRCIPFROM srcipfrom_str
+#define SRCIPTO srcipto_str
+#define DSTIPFROM dstipfrom_str
+#define DSTIPTO dstipto_str
#define SRCPORTSTART srcportstart_str
#define SRCPORTEND srcportend_str
#define DSTPORTSTART dstportstart_str
@@ -831,6 +852,149 @@ static const virXMLAttr2Struct ipv6Attri
};


+#define COMMON_L3_MAC_PROPS(STRUCT) \
+ {\
+ .name = SRCMACADDR,\
+ .datatype = DATATYPE_MACADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.dataSrcMACAddr),\
+ }
+
+#define COMMON_IP_PROPS(STRUCT) \
+ COMMON_L3_MAC_PROPS(STRUCT),\
+ {\
+ .name = SRCIPADDR,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPAddr),\
+ },\
+ {\
+ .name = DSTIPADDR,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPAddr),\
+ },\
+ {\
+ .name = SRCIPMASK,\
+ .datatype = DATATYPE_IPMASK,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPMask),\
+ },\
+ {\
+ .name = DSTIPMASK,\
+ .datatype = DATATYPE_IPMASK,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPMask),\
+ },\
+ {\
+ .name = SRCIPFROM,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPFrom),\
+ },\
+ {\
+ .name = SRCIPTO,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPTo),\
+ },\
+ {\
+ .name = DSTIPFROM,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPFrom),\
+ },\
+ {\
+ .name = DSTIPTO,\
+ .datatype = DATATYPE_IPADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPTo),\
+ },\
+ {\
+ .name = DSCP,\
+ .datatype = DATATYPE_UINT8,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDSCP),\
+ .validator = dscpValidator,\
+ }
+
+#define COMMON_PORT_PROPS(STRUCT) \
+ {\
+ .name = SRCPORTSTART,\
+ .datatype = DATATYPE_UINT16,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortStart),\
+ },\
+ {\
+ .name = SRCPORTEND,\
+ .datatype = DATATYPE_UINT16,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortEnd),\
+ },\
+ {\
+ .name = DSTPORTSTART,\
+ .datatype = DATATYPE_UINT16,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortStart),\
+ },\
+ {\
+ .name = DSTPORTEND,\
+ .datatype = DATATYPE_UINT16,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortEnd),\
+ }
+
+static const virXMLAttr2Struct tcpAttributes[] = {
+ COMMON_IP_PROPS(tcpHdrFilter),
+ COMMON_PORT_PROPS(tcpHdrFilter),
+ {
+ .name = "option",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const virXMLAttr2Struct udpAttributes[] = {
+ COMMON_IP_PROPS(udpHdrFilter),
+ COMMON_PORT_PROPS(udpHdrFilter),
+ {
+ .name = NULL,
+ }
+};
+
+
+static const virXMLAttr2Struct sctpAttributes[] = {
+ COMMON_IP_PROPS(sctpHdrFilter),
+ COMMON_PORT_PROPS(sctpHdrFilter),
+ {
+ .name = NULL,
+ }
+};
+
+
+static const virXMLAttr2Struct icmpAttributes[] = {
+ COMMON_IP_PROPS(icmpHdrFilter),
+ {
+ .name = "type",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType),
+ },
+ {
+ .name = "code",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+
+static const virXMLAttr2Struct allAttributes[] = {
+ COMMON_IP_PROPS(allHdrFilter),
+ {
+ .name = NULL,
+ }
+};
+
+
+static const virXMLAttr2Struct igmpAttributes[] = {
+ COMMON_IP_PROPS(igmpHdrFilter),
+ {
+ .name = NULL,
+ }
+};
+
+
typedef struct _virAttributes virAttributes;
struct _virAttributes {
const char *id;
@@ -857,6 +1021,30 @@ static const virAttributes virAttr[] = {
.att = ipv6Attributes,
.prtclType = VIR_NWFILTER_RULE_PROTOCOL_IPV6,
}, {
+ .id = "tcp",
+ .att = tcpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_TCP,
+ }, {
+ .id = "udp",
+ .att = udpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_UDP,
+ }, {
+ .id = "sctp",
+ .att = sctpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_SCP,
+ }, {
+ .id = "icmp",
+ .att = icmpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ICMP,
+ }, {
+ .id = "all", // = 'any'
+ .att = allAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ALL,
+ }, {
+ .id = "igmp",
+ .att = igmpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IGMP,
+ }, {
.id = NULL,
}
};
@@ -1274,8 +1462,96 @@ virNWFilterRuleDefFixup(virNWFilterRuleD
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
break;
- }

+ case VIR_NWFILTER_RULE_PROTOCOL_TCP:
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.tcpHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.tcpHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.tcpHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.tcpHdrFilter.ipHdr.dataDstIPFrom);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataSrcPortEnd,
+ rule->p.tcpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortStart,
+ rule->p.tcpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortEnd,
+ rule->p.tcpHdrFilter.portData.dataSrcPortStart);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_UDP:
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.udpHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.udpHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.udpHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.udpHdrFilter.ipHdr.dataDstIPFrom);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataSrcPortEnd,
+ rule->p.udpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortStart,
+ rule->p.udpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortEnd,
+ rule->p.udpHdrFilter.portData.dataSrcPortStart);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_SCP:
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.sctpHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.sctpHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.sctpHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.sctpHdrFilter.ipHdr.dataDstIPFrom);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataSrcPortEnd,
+ rule->p.sctpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortStart,
+ rule->p.sctpHdrFilter.portData.dataSrcPortStart);
+ COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortEnd,
+ rule->p.sctpHdrFilter.portData.dataSrcPortStart);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
+ COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.icmpHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.icmpHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.icmpHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.icmpHdrFilter.ipHdr.dataDstIPFrom);
+ COPY_NEG_SIGN(rule->p.icmpHdrFilter.dataICMPCode,
+ rule->p.icmpHdrFilter.dataICMPType);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ALL:
+ COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.allHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.allHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.allHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.allHdrFilter.ipHdr.dataDstIPFrom);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
+ COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.igmpHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.igmpHdrFilter.ipHdr.dataDstIPAddr);
+ COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPTo,
+ rule->p.igmpHdrFilter.ipHdr.dataSrcIPFrom);
+ COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPTo,
+ rule->p.igmpHdrFilter.ipHdr.dataDstIPFrom);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_LAST:
+ break;
+ }
#undef COPY_NEG_SIGN
}

Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -448,6 +448,7 @@ virNWFilterPoolObjListFree;
virNWFilterDefFormat;
virNWFilterChainSuffixTypeToString;
virNWFilterRuleActionTypeToString;
+virNWFilterRuleProtocolTypeToString;
virNWFilterJumpTargetTypeToString;
virNWFilterRegisterCallbackDriver;
virNWFilterTestUnassignDef;
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.h
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
@@ -32,6 +32,7 @@ struct _ebiptablesRuleInst {
enum virNWFilterChainSuffixType neededProtocolChain;
char chainprefix; // I for incoming, O for outgoing
unsigned int priority;
+ bool isIptablesRule;
};

extern virNWFilterTechDriver ebiptables_driver;
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -303,6 +303,13 @@ AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IP
AC_PATH_PROG([EBTABLES_PATH], [ebtables], /sbin/ebtables, [/usr/sbin:$PATH])
AC_DEFINE_UNQUOTED([EBTABLES_PATH], "$EBTABLES_PATH", [path to ebtables binary])

+AC_PATH_PROG([GREP_PATH], [grep], /bin/grep, [/bin:$PATH])
+AC_DEFINE_UNQUOTED([GREP_PATH], "$GREP_PATH", [path to grep binary])
+
+AC_PATH_PROG([GAWK_PATH], [gawk], /bin/gawk, [/bin:$PATH])
+AC_DEFINE_UNQUOTED([GAWK_PATH], "$GAWK_PATH", [path to gawk binary])
+
+
if test "$with_openvz" = "yes"; then
AC_DEFINE_UNQUOTED([WITH_OPENVZ], 1, [whether OpenVZ driver is enabled])
fi
s***@us.ibm.com
2010-03-23 14:54:10 UTC
Permalink
This patch adds the implementation of the public API for the network
filtering (ACL) extensions to libvirt.c .

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/libvirt.c | 586 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 586 insertions(+)

Index: libvirt-acl/src/libvirt.c
===================================================================
--- libvirt-acl.orig/src/libvirt.c
+++ libvirt-acl/src/libvirt.c
@@ -91,6 +91,8 @@ static virDeviceMonitorPtr virDeviceMoni
static int virDeviceMonitorTabCount = 0;
static virSecretDriverPtr virSecretDriverTab[MAX_DRIVERS];
static int virSecretDriverTabCount = 0;
+static virNWFilterDriverPtr virNWFilterDriverTab[MAX_DRIVERS];
+static int virNWFilterDriverTabCount = 0;
#ifdef WITH_LIBVIRTD
static virStateDriverPtr virStateDriverTab[MAX_DRIVERS];
static int virStateDriverTabCount = 0;
@@ -655,6 +657,32 @@ virLibSecretError(virSecretPtr secret, v
}

/**
+ * virLibNWFilterError:
+ * @conn: the connection if available
+ * @error: the error number
+ * @info: extra information string
+ *
+ * Handle an error at the connection level
+ */
+static void
+virLibNWFilterError(virNWFilterPtr pool, virErrorNumber error,
+ const char *info)
+{
+ virConnectPtr conn = NULL;
+ const char *errmsg;
+
+ if (error == VIR_ERR_OK)
+ return;
+
+ errmsg = virErrorMsg(error, info);
+ if (error != VIR_ERR_INVALID_NWFILTER)
+ conn = pool->conn;
+
+ virRaiseError(conn, NULL, NULL, VIR_FROM_NWFILTER, error, VIR_ERR_ERROR,
+ errmsg, info, NULL, 0, 0, errmsg, info);
+}
+
+/**
* virRegisterNetworkDriver:
* @driver: pointer to a network driver block
*
@@ -810,6 +838,38 @@ virRegisterSecretDriver(virSecretDriverP
}

/**
+ * virRegisterNWFilterDriver:
+ * @driver: pointer to a network filter driver block
+ *
+ * Register a network filter virtualization driver
+ *
+ * Returns the driver priority or -1 in case of error.
+ */
+int
+virRegisterNWFilterDriver(virNWFilterDriverPtr driver)
+{
+ if (virInitialize() < 0)
+ return -1;
+
+ if (driver == NULL) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ if (virNWFilterDriverTabCount >= MAX_DRIVERS) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ DEBUG ("registering %s as network filter driver %d",
+ driver->name, virNWFilterDriverTabCount);
+
+ virNWFilterDriverTab[virNWFilterDriverTabCount] = driver;
+ return virNWFilterDriverTabCount++;
+}
+
+
+/**
* virRegisterDriver:
* @driver: pointer to a driver block
*
@@ -1253,6 +1313,26 @@ do_open (const char *name,
}
}

+ /* Network filter driver. Optional */
+ for (i = 0; i < virNWFilterDriverTabCount; i++) {
+ res = virNWFilterDriverTab[i]->open (ret, auth, flags);
+ DEBUG("nwfilter driver %d %s returned %s",
+ i, virNWFilterDriverTab[i]->name,
+ res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
+ (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
+ (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
+ if (res == VIR_DRV_OPEN_ERROR) {
+ if (STREQ(virNWFilterDriverTab[i]->name, "remote")) {
+ virLibConnWarning (NULL, VIR_WAR_NO_NWFILTER,
+ _("Is the daemon running ?"));
+ }
+ break;
+ } else if (res == VIR_DRV_OPEN_SUCCESS) {
+ ret->nwfilterDriver = virNWFilterDriverTab[i];
+ break;
+ }
+ }
+
return ret;

failed:
@@ -11011,6 +11091,512 @@ error:
}


+
+/**
+ * virConnectNumOfNWFilters:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of nwfilters.
+ *
+ * Returns the number of nwfilters found or -1 in case of error
+ */
+int
+virConnectNumOfNWFilters(virConnectPtr conn)
+{
+ DEBUG("conn=%p", conn);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->numOfNWFilters) {
+ int ret;
+ ret = conn->nwfilterDriver->numOfNWFilters (conn);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virConnectListNWFilters:
+ * @conn: pointer to the hypervisor connection
+ * @names: array to collect the list of names of network filters
+ * @maxnames: size of @names
+ *
+ * Collect the list of network filters, and store their names in @names
+ *
+ * Returns the number of network filters found or -1 in case of error
+ */
+int
+virConnectListNWFilters(virConnectPtr conn, char **const names, int maxnames)
+{
+ DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if ((names == NULL) || (maxnames < 0)) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->listNWFilters) {
+ int ret;
+ ret = conn->nwfilterDriver->listNWFilters (conn, names, maxnames);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virNWFilterLookupByName:
+ * @conn: pointer to the hypervisor connection
+ * @name: name for the network filter
+ *
+ * Try to lookup a network filter on the given hypervisor based on its name.
+ *
+ * Returns a new nwfilter object or NULL in case of failure. If the
+ * network filter cannot be found, then VIR_ERR_NO_NWFILTER error is raised.
+ */
+virNWFilterPtr
+virNWFilterLookupByName(virConnectPtr conn, const char *name)
+{
+ DEBUG("conn=%p, name=%s", conn, name);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ if (name == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterLookupByName) {
+ virNWFilterPtr ret;
+ ret = conn->nwfilterDriver->nwfilterLookupByName (conn, name);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+/**
+ * virNWFilterLookupByUUID:
+ * @conn: pointer to the hypervisor connection
+ * @uuid: the raw UUID for the network filter
+ *
+ * Try to lookup a network filter on the given hypervisor based on its UUID.
+ *
+ * Returns a new nwfilter object or NULL in case of failure. If the
+ * nwfdilter cannot be found, then VIR_ERR_NO_NWFILTER error is raised.
+ */
+virNWFilterPtr
+virNWFilterLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ DEBUG("conn=%p, uuid=%s", conn, uuid);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ if (uuid == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterLookupByUUID){
+ virNWFilterPtr ret;
+ ret = conn->nwfilterDriver->nwfilterLookupByUUID (conn, uuid);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+/**
+ * virNWFIlterLookupByUUIDString:
+ * @conn: pointer to the hypervisor connection
+ * @uuidstr: the string UUID for the nwfilter
+ *
+ * Try to lookup an nwfilter on the given hypervisor based on its UUID.
+ *
+ * Returns a new nwfilter object or NULL in case of failure. If the
+ * nwfilter cannot be found, then VIR_ERR_NO_NWFILTER error is raised.
+ */
+virNWFilterPtr
+virNWFilterLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
+{
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ if (uuidstr == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (virUUIDParse(uuidstr, uuid) < 0) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ return virNWFilterLookupByUUID(conn, &uuid[0]);
+
+error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+/**
+ * virNWFilterFree:
+ * @nwfilter: a nwfilter object
+ *
+ * Free the nwfilter object. The running instance is kept alive.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virNWFilterFree(virNWFilterPtr nwfilter)
+{
+ DEBUG("nwfilter=%p", nwfilter);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (virUnrefNWFilter(nwfilter) < 0) {
+ virDispatchError(NULL);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * virNWFilterGetName:
+ * @nwfilter: a nwfilter object
+ *
+ * Get the public name for the network filter
+ *
+ * Returns a pointer to the name or NULL, the string need not be deallocated
+ * its lifetime will be the same as the nwfilter object.
+ */
+const char *
+virNWFilterGetName(virNWFilterPtr nwfilter)
+{
+ DEBUG("nwfilter=%p", nwfilter);
+
+ virResetLastError();
+
+ if (!VIR_IS_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ return (nwfilter->name);
+}
+
+/**
+ * virNWFilterGetUUID:
+ * @nwfilter: a nwfilter object
+ * @uuid: pointer to a VIR_UUID_BUFLEN bytes array
+ *
+ * Get the UUID for a network filter
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virNWFilterGetUUID(virNWFilterPtr nwfilter, unsigned char *uuid)
+{
+ DEBUG("nwfilter=%p, uuid=%p", nwfilter, uuid);
+
+ virResetLastError();
+
+ if (!VIR_IS_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (uuid == NULL) {
+ virLibNWFilterError(nwfilter, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ memcpy(uuid, &nwfilter->uuid[0], VIR_UUID_BUFLEN);
+
+ return 0;
+
+error:
+ virDispatchError(nwfilter->conn);
+ return -1;
+}
+
+/**
+ * virNWFilterGetUUIDString:
+ * @nwfilter: a nwfilter object
+ * @buf: pointer to a VIR_UUID_STRING_BUFLEN bytes array
+ *
+ * Get the UUID for a network filter as string. For more information about
+ * UUID see RFC4122.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virNWFilterGetUUIDString(virNWFilterPtr nwfilter, char *buf)
+{
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ DEBUG("nwfilter=%p, buf=%p", nwfilter, buf);
+
+ virResetLastError();
+
+ if (!VIR_IS_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (buf == NULL) {
+ virLibNWFilterError(nwfilter, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (virNWFilterGetUUID(nwfilter, &uuid[0]))
+ goto error;
+
+ virUUIDFormat(uuid, buf);
+ return 0;
+
+error:
+ virDispatchError(nwfilter->conn);
+ return -1;
+}
+
+
+/**
+ * virNWFilterDefineXML:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: an XML description of the nwfilter
+ *
+ * Define a new network filter, based on an XML description
+ * similar to the one returned by virNWFilterGetXMLDesc()
+ *
+ * Returns a new nwfilter object or NULL in case of failure
+ */
+virNWFilterPtr
+virNWFilterDefineXML(virConnectPtr conn, const char *xmlDesc)
+{
+ DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ if (xmlDesc == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ if (conn->flags & VIR_CONNECT_RO) {
+ virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->defineXML) {
+ virNWFilterPtr ret;
+ ret = conn->nwfilterDriver->defineXML (conn, xmlDesc, 0);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virNWFilterUndefine:
+ * @nwfilter: a nwfilter object
+ *
+ * Undefine the nwfilter object. This call will not succeed if
+ * a running VM is referencing the filter. This does not free the
+ * associated virNWFilterPtr object.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virNWFilterUndefine(virNWFilterPtr nwfilter)
+{
+ virConnectPtr conn;
+ DEBUG("nwfilter=%p", nwfilter);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ conn = nwfilter->conn;
+ if (conn->flags & VIR_CONNECT_RO) {
+ virLibNWFilterError(nwfilter, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->undefine) {
+ int ret;
+ ret = conn->nwfilterDriver->undefine (nwfilter);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(nwfilter->conn);
+ return -1;
+}
+
+
+/**
+ * virNWFilterGetXMLDesc:
+ * @nwfilter: a nwfilter object
+ * @flags: an OR'ed set of extraction flags, not used yet
+ *
+ * Provide an XML description of the network filter. The description may be
+ * reused later to redefine the network filter with virNWFilterCreateXML().
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ * the caller must free() the returned value.
+ */
+char *
+virNWFilterGetXMLDesc(virNWFilterPtr nwfilter, int flags)
+{
+ virConnectPtr conn;
+ DEBUG("nwfilter=%p, flags=%d", nwfilter, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_NWFILTER(nwfilter)) {
+ virLibNWFilterError(NULL, VIR_ERR_INVALID_NWFILTER, __FUNCTION__);
+ virDispatchError(NULL);
+ return (NULL);
+ }
+ if (flags != 0) {
+ virLibNWFilterError(nwfilter, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ conn = nwfilter->conn;
+
+ if (conn->nwfilterDriver && conn->nwfilterDriver->getXMLDesc) {
+ char *ret;
+ ret = conn->nwfilterDriver->getXMLDesc (nwfilter, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(nwfilter->conn);
+ return NULL;
+}
+
+
+/**
+ * virNWFilterRef:
+ * @nwfilter: the nwfilter to hold a reference on
+ *
+ * Increment the reference count on the nwfilter. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virNWFilterFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using an nwfilter would increment
+ * the reference count.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNWFilterRef(virNWFilterPtr nwfilter)
+{
+ if ((!VIR_IS_CONNECTED_NWFILTER(nwfilter))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ virMutexLock(&nwfilter->conn->lock);
+ DEBUG("nwfilter=%p refs=%d", nwfilter, nwfilter->refs);
+ nwfilter->refs++;
+ virMutexUnlock(&nwfilter->conn->lock);
+ return 0;
+}
+
+
/**
* virInterfaceIsActive:
* @iface: pointer to the interface object
Daniel P. Berrange
2010-03-25 10:58:17 UTC
Permalink
Post by s***@us.ibm.com
This patch adds the implementation of the public API for the network
filtering (ACL) extensions to libvirt.c .
---
src/libvirt.c | 586 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 586 insertions(+)
ACK, all looks good.


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:15 UTC
Permalink
This patch extends the domain XML processing to parse the top level
referenced filter along with potentially provided parameters and also
converts the internal data back into XML representation.

Signed-off-by: Stefan Berger <***@us.ibm.com>
Signed-off-by: Gerhard Stenzel <***@de.ibm.com>

---
src/conf/domain_conf.c | 39 +++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 4 ++++
2 files changed, 43 insertions(+)

Index: libvirt-acl/src/conf/domain_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.c
+++ libvirt-acl/src/conf/domain_conf.c
@@ -42,6 +42,7 @@
#include "logging.h"
#include "network.h"
#include "macvtap.h"
+#include "nwfilter_conf.h"

#define VIR_FROM_THIS VIR_FROM_DOMAIN

@@ -456,6 +457,9 @@ void virDomainNetDefFree(virDomainNetDef

virDomainDeviceInfoClear(&def->info);

+ VIR_FREE(def->filter);
+ virNWFilterHashTableFree(def->filterparams);
+
VIR_FREE(def);
}

@@ -1724,9 +1728,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *address = NULL;
char *port = NULL;
char *model = NULL;
+ char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
char *mode = NULL;
+ virNWFilterHashTablePtr filterparams = NULL;

if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1795,6 +1801,9 @@ virDomainNetDefParseXML(virCapsPtr caps,
script = virXMLPropString(cur, "path");
} else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
model = virXMLPropString(cur, "type");
+ } else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
+ filter = virXMLPropString(cur, "filter");
+ filterparams = virNWFilterParseParamAttributes(cur);
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
xmlStrEqual(cur->name, BAD_CAST "state")) {
/* Legacy back-compat. Don't add any more attributes here */
@@ -1970,6 +1979,22 @@ virDomainNetDefParseXML(virCapsPtr caps,
model = NULL;
}

+ if (filter != NULL) {
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_DIRECT:
+ def->filter = filter;
+ filter = NULL;
+ def->filterparams = filterparams;
+ filterparams = NULL;
+ break;
+ default:
+ break;
+ }
+ }
+
cleanup:
VIR_FREE(macaddr);
VIR_FREE(network);
@@ -1980,10 +2005,12 @@ cleanup:
VIR_FREE(script);
VIR_FREE(bridge);
VIR_FREE(model);
+ VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
VIR_FREE(devaddr);
VIR_FREE(mode);
+ virNWFilterHashTableFree(filterparams);

return def;

@@ -4878,6 +4905,7 @@ virDomainNetDefFormat(virBufferPtr buf,
int flags)
{
const char *type = virDomainNetTypeToString(def->type);
+ char *attrs;

if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4952,6 +4980,17 @@ virDomainNetDefFormat(virBufferPtr buf,
if (def->model)
virBufferEscapeString(buf, " <model type='%s'/>\n",
def->model);
+ if (def->filter) {
+ virBufferEscapeString(buf, " <filterref filter='%s'",
+ def->filter);
+ attrs = virNWFilterFormatParamAttributes(def->filterparams,
+ " ");
+ if (!attrs || strlen(attrs) <= 1)
+ virBufferAddLit(buf, "/>\n");
+ else
+ virBufferVSprintf(buf, ">\n%s </filterref>\n", attrs);
+ VIR_FREE(attrs);
+ }

if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
Index: libvirt-acl/src/conf/domain_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.h
+++ libvirt-acl/src/conf/domain_conf.h
@@ -36,6 +36,8 @@
# include "threads.h"
# include "hash.h"
# include "network.h"
+# include "nwfilter_params.h"
+# include "nwfilter_conf.h"

/* Private component of virDomainXMLFlags */
typedef enum {
@@ -282,6 +284,8 @@ struct _virDomainNetDef {
} data;
char *ifname;
virDomainDeviceInfo info;
+ char *filter;
+ virNWFilterHashTablePtr filterparams;
};

enum virDomainChrTargetType {
Daniel P. Berrange
2010-03-25 11:04:32 UTC
Permalink
Post by s***@us.ibm.com
This patch extends the domain XML processing to parse the top level
referenced filter along with potentially provided parameters and also
converts the internal data back into XML representation.
---
src/conf/domain_conf.c | 39 +++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 4 ++++
2 files changed, 43 insertions(+)
ACK, looks good, though it would be good to also update the docs/schemas/domain.rng
schema with the new element info. That's fine as a followup patch - no need to
respin the whole series.

Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Kumar L Srikanth-B22348
2010-03-25 11:15:00 UTC
Permalink
Hi Daniel,
I am trying to create an interface with the type 'direct' with 'vepa'
mode.
I assigned an ip '10.0.0.1' to the eth2 interface of the host machine.
My domain XML format is shown below.

<domain type='lxc' id='1'>
<name>vm1_fedora</name>
<memory>500000</memory>
<os>
<type>exe</type>
<init>/bin/bash</init>
</os>
<vcpu>1</vcpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/libexec/libvirt_lxc</emulator>
<filesystem type='mount'>
<source dir='/root/lxc/fedora_fresh'/>
<target dir='/'/>
</filesystem>
<interface type='direct'>
<source dev='eth2' mode='vepa'/>
</interface>
<console type='pty' />
</devices>
</domain>

When I am trying to define the domain, I am getting the following error:

virsh # define /root/lxc_devel/fedora.xml
error: Failed to define domain from /root/lxc_devel/fedora.xml
error: internal error unknown interface type 'direct'

Can you please let me know the problem here.

Regards,
Srikanth.
Stefan Berger
2010-03-25 12:23:35 UTC
Permalink
Post by Kumar L Srikanth-B22348
Hi Daniel,
I am trying to create an interface with the type 'direct' with 'vepa'
mode.
I assigned an ip '10.0.0.1' to the eth2 interface of the host machine.
My domain XML format is shown below.
<domain type='lxc' id='1'>
<name>vm1_fedora</name>
<memory>500000</memory>
<os>
<type>exe</type>
<init>/bin/bash</init>
</os>
<vcpu>1</vcpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/libexec/libvirt_lxc</emulator>
<filesystem type='mount'>
<source dir='/root/lxc/fedora_fresh'/>
<target dir='/'/>
</filesystem>
<interface type='direct'>
<source dev='eth2' mode='vepa'/>
</interface>
<console type='pty' />
</devices>
</domain>
virsh # define /root/lxc_devel/fedora.xml
error: Failed to define domain from /root/lxc_devel/fedora.xml
error: internal error unknown interface type 'direct'
Can you please let me know the problem here.
The direct interface type only works for VMs of type 'kvm'. I'll send an
update for the online documentation to
mention that. Otherwise, for direct device support you would need to
compile libvirt on a system with a fairly
recent Linux kernel (release candidates of 2.6.34 for example) and have
their include files installed so that
linux/if_link.h contains this fragment here:

enum macvlan_mode {
MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext
bridge */
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
};

Then the result of a './configure ...' of libvirt should show this result
here :

[...]
configure: Libvirtd: yes
configure: netcf: yes
configure: macvtap: yes
configure:
configure: Storage Drivers
configure:
[...]

Hope this helps.

Regards,
Stefan
Post by Kumar L Srikanth-B22348
Regards,
Srikanth.
--
libvir-list mailing list
https://www.redhat.com/mailman/listinfo/libvir-list
Stefan Berger
2010-03-25 11:30:18 UTC
Permalink
[image removed]
Re: [libvirt] [PATCH v3 09/14] Add XML parser extensions to the
domain XML processing
Daniel P. Berrange
Stefan Berger
03/25/2010 07:05 AM
libvir-list, Gerhard Stenzel
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
This patch extends the domain XML processing to parse the top level
referenced filter along with potentially provided parameters and also
converts the internal data back into XML representation.
---
src/conf/domain_conf.c | 39 +++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 4 ++++
2 files changed, 43 insertions(+)
ACK, looks good, though it would be good to also update the docs/
schemas/domain.rng
schema with the new element info. That's fine as a followup patch - no need to
respin the whole series.
We will follow up on this in a separate patch.

Regards,
Stefan
Regards,
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Gerhard Stenzel
2010-03-25 13:33:17 UTC
Permalink
This patch changes the original element info for referencing a filter
from "<filter name=".."/> to "<filterref filter=""/>, as it is currently
implemented.

Signed-off-by: Gerhard Stenzel <***@de.ibm.com>

Index: libvirt/docs/schemas/domain.rng
===================================================================
--- libvirt.orig/docs/schemas/domain.rng
+++ libvirt/docs/schemas/domain.rng
@@ -806,8 +806,8 @@
<ref name="address"/>
</optional>
<optional>
- <element name="filter">
- <attribute name="name">
+ <element name="filterref">
+ <attribute name="filter">
<ref name="genericName"/>
</attribute>
<empty/>
--
Best regards,

Gerhard Stenzel,
-----------------------------------------------------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
s***@us.ibm.com
2010-03-23 14:54:08 UTC
Permalink
This patch adds extensions to libvirt's public API necessary for
controlling the new functionality from remote for example.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
include/libvirt/libvirt.h.in | 63 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)

Index: libvirt-acl/include/libvirt/libvirt.h.in
===================================================================
--- libvirt-acl.orig/include/libvirt/libvirt.h.in
+++ libvirt-acl/include/libvirt/libvirt.h.in
@@ -1861,4 +1861,67 @@ int virDomainAbortJob(virDomainPtr dom);
}
#endif

+
+/**
+ * virNWFilter:
+ *
+ * a virNWFilter is a private structure representing a network filter
+ */
+typedef struct _virNWFilter virNWFilter;
+
+/**
+ * virNWFilterPtr:
+ *
+ * a virNWFilterPtr is pointer to a virNWFilter private structure,
+ * this is the type used to reference a network filter in the API.
+ */
+typedef virNWFilter *virNWFilterPtr;
+
+
+/*
+ * List NWFilters
+ */
+int virConnectNumOfNWFilters (virConnectPtr conn);
+int virConnectListNWFilters (virConnectPtr conn,
+ char **const names,
+ int maxnames);
+
+/*
+ * Lookup nwfilter by name or uuid
+ */
+virNWFilterPtr virNWFilterLookupByName (virConnectPtr conn,
+ const char *name);
+virNWFilterPtr virNWFilterLookupByUUID (virConnectPtr conn,
+ const unsigned char *uuid);
+virNWFilterPtr virNWFilterLookupByUUIDString (virConnectPtr conn,
+ const char *uuid);
+
+/*
+ * Define persistent nwfilter
+ */
+virNWFilterPtr virNWFilterDefineXML (virConnectPtr conn,
+ const char *xmlDesc);
+
+/*
+ * Delete persistent nwfilter
+ */
+int virNWFilterUndefine (virNWFilterPtr nwfilter);
+
+/*
+ * NWFilter destroy/free
+ */
+int virNWFilterRef (virNWFilterPtr nwfilter);
+int virNWFilterFree (virNWFilterPtr nwfilter);
+
+/*
+ * NWFilter information
+ */
+const char* virNWFilterGetName (virNWFilterPtr nwfilter);
+int virNWFilterGetUUID (virNWFilterPtr nwfilter,
+ unsigned char *uuid);
+int virNWFilterGetUUIDString (virNWFilterPtr nwfilter,
+ char *buf);
+char * virNWFilterGetXMLDesc (virNWFilterPtr nwfilter,
+ int flags);
+
#endif /* __VIR_VIRLIB_H__ */
Daniel P. Berrange
2010-03-25 10:56:39 UTC
Permalink
Post by s***@us.ibm.com
This patch adds extensions to libvirt's public API necessary for
controlling the new functionality from remote for example.
---
include/libvirt/libvirt.h.in | 63 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
Index: libvirt-acl/include/libvirt/libvirt.h.in
===================================================================
--- libvirt-acl.orig/include/libvirt/libvirt.h.in
+++ libvirt-acl/include/libvirt/libvirt.h.in
@@ -1861,4 +1861,67 @@ int virDomainAbortJob(virDomainPtr dom);
}
#endif
+
+/**
+ *
+ * a virNWFilter is a private structure representing a network filter
+ */
+typedef struct _virNWFilter virNWFilter;
+
+/**
+ *
+ * a virNWFilterPtr is pointer to a virNWFilter private structure,
+ * this is the type used to reference a network filter in the API.
+ */
+typedef virNWFilter *virNWFilterPtr;
+
+
+/*
+ * List NWFilters
+ */
+int virConnectNumOfNWFilters (virConnectPtr conn);
+int virConnectListNWFilters (virConnectPtr conn,
+ char **const names,
+ int maxnames);
+
+/*
+ * Lookup nwfilter by name or uuid
+ */
+virNWFilterPtr virNWFilterLookupByName (virConnectPtr conn,
+ const char *name);
+virNWFilterPtr virNWFilterLookupByUUID (virConnectPtr conn,
+ const unsigned char *uuid);
+virNWFilterPtr virNWFilterLookupByUUIDString (virConnectPtr conn,
+ const char *uuid);
+
+/*
+ * Define persistent nwfilter
+ */
+virNWFilterPtr virNWFilterDefineXML (virConnectPtr conn,
+ const char *xmlDesc);
+
+/*
+ * Delete persistent nwfilter
+ */
+int virNWFilterUndefine (virNWFilterPtr nwfilter);
+
+/*
+ * NWFilter destroy/free
+ */
+int virNWFilterRef (virNWFilterPtr nwfilter);
+int virNWFilterFree (virNWFilterPtr nwfilter);
+
+/*
+ * NWFilter information
+ */
+const char* virNWFilterGetName (virNWFilterPtr nwfilter);
+int virNWFilterGetUUID (virNWFilterPtr nwfilter,
+ unsigned char *uuid);
+int virNWFilterGetUUIDString (virNWFilterPtr nwfilter,
+ char *buf);
+char * virNWFilterGetXMLDesc (virNWFilterPtr nwfilter,
+ int flags);
+
ACK


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:19 UTC
Permalink
This patch adds IPv6 support for the ebtables layer. Since the parser
etc. are all parameterized, it was fairly easy to add this...

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/conf/nwfilter_conf.c | 230 +++++++++++++++++++++++++++++-
src/conf/nwfilter_conf.h | 18 ++
src/nwfilter/nwfilter_ebiptables_driver.c | 155 ++++++++++++++++++++
3 files changed, 399 insertions(+), 4 deletions(-)

Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.c
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -73,7 +73,8 @@ VIR_ENUM_IMPL(virNWFilterEbtablesTable,
VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
"root",
"arp",
- "ipv4");
+ "ipv4",
+ "ipv6");


/*
@@ -366,6 +367,9 @@ static const struct int_map macProtoMap[
.attr = ETHERTYPE_IP,
.val = "ipv4",
}, {
+ .attr = ETHERTYPE_IPV6,
+ .val = "ipv6",
+ }, {
.val = NULL,
}
};
@@ -449,6 +453,13 @@ checkIPv4Mask(enum attrDatatype datatype
return checkValidMask(maskptr, 4);
}

+static bool
+checkIPv6Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ return checkValidMask(maskptr, 16);
+}
+

static bool
checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
@@ -765,6 +776,61 @@ static const virXMLAttr2Struct ipAttribu
};


+static const virXMLAttr2Struct ipv6Attributes[] = {
+ COMMON_MAC_PROPS(ipv6HdrFilter),
+ {
+ .name = SRCIPADDR,
+ .datatype = DATATYPE_IPV6ADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
+ },
+ {
+ .name = DSTIPADDR,
+ .datatype = DATATYPE_IPV6ADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
+ },
+ {
+ .name = SRCIPMASK,
+ .datatype = DATATYPE_IPV6MASK,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataSrcIPMask),
+ },
+ {
+ .name = DSTIPMASK,
+ .datatype = DATATYPE_IPV6MASK,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataDstIPMask),
+ },
+ {
+ .name = "protocol",
+ .datatype = DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataProtocolID),
+ .validator= checkIPProtocolID,
+ .formatter= formatIPProtocolID,
+ },
+ {
+ .name = SRCPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortStart),
+ },
+ {
+ .name = SRCPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortEnd),
+ },
+ {
+ .name = DSTPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortStart),
+ },
+ {
+ .name = DSTPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortEnd),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+
typedef struct _virAttributes virAttributes;
struct _virAttributes {
const char *id;
@@ -787,6 +853,10 @@ static const virAttributes virAttr[] = {
.att = ipAttributes,
.prtclType = VIR_NWFILTER_RULE_PROTOCOL_IP,
}, {
+ .id = "ipv6",
+ .att = ipv6Attributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IPV6,
+ }, {
.id = NULL,
}
};
@@ -825,6 +895,89 @@ virNWIPv4AddressParser(const char *input
}


+static bool
+virNWIPv6AddressParser(const char *input,
+ nwIPAddressPtr output)
+{
+ int i, j, pos;
+ uint16_t n;
+ int shiftpos = -1;
+ char prevchar;
+ char base;
+
+ memset(output, 0x0, sizeof(*output));
+
+ output->isIPv6 = 1;
+
+ pos = 0;
+ i = 0;
+
+ while (i < 8) {
+ j = 0;
+ n = 0;
+ while (1) {
+ prevchar = input[pos++];
+ if (prevchar == ':' || prevchar == 0) {
+ if (j > 0) {
+ output->addr.ipv6Addr[i * 2 + 0] = n >> 8;
+ output->addr.ipv6Addr[i * 2 + 1] = n;
+ i++;
+ }
+ break;
+ }
+
+ if (j >= 4)
+ return 0;
+
+ if (prevchar >= '0' && prevchar <= '9')
+ base = '0';
+ else if (prevchar >= 'a' && prevchar <= 'f')
+ base = 'a' - 10;
+ else if (prevchar >= 'A' && prevchar <= 'F')
+ base = 'A' - 10;
+ else
+ return 0;
+ n <<= 4;
+ n |= (prevchar - base);
+ j++;
+ }
+
+ if (prevchar == 0)
+ break;
+
+ if (input[pos] == ':') {
+ pos ++;
+ // sequence of zeros
+ if (prevchar != ':')
+ return 0;
+
+ if (shiftpos != -1)
+ return 0;
+
+ shiftpos = i;
+ }
+ }
+
+ if (shiftpos != -1) {
+ if (i >= 7)
+ return 0;
+ i--;
+ j = 0;
+ while (i >= shiftpos) {
+ output->addr.ipv6Addr[15 - (j*2) - 1] =
+ output->addr.ipv6Addr[i * 2 + 0];
+ output->addr.ipv6Addr[15 - (j*2) - 0] =
+ output->addr.ipv6Addr[i * 2 + 1];
+ output->addr.ipv6Addr[i * 2 + 0] = 0;
+ output->addr.ipv6Addr[i * 2 + 1] = 0;
+ i--;
+ j++;
+ }
+ }
+ return 1;
+}
+
+
static int
virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
xmlNodePtr node,
@@ -969,6 +1122,41 @@ virNWFilterRuleDetailsParse(virConnectPt
found = 1;
break;

+ case DATATYPE_IPV6ADDR:
+ storage_ptr = &item->u.ipaddr;
+ if (!virNWIPv6AddressParser(prop,
+ (nwIPAddressPtr)storage_ptr)) {
+ rc = -1;
+ }
+ found = 1;
+ break;
+
+ case DATATYPE_IPV6MASK:
+ storage_ptr = &item->u.u8;
+ if (!virNWIPv6AddressParser(prop, &ipaddr)) {
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 128) {
+ if (!validator)
+ *(uint8_t *)storage_ptr =
+ (uint8_t)int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ } else {
+ if (checkIPv6Mask(datatype,
+ ipaddr.addr.ipv6Addr, nwf))
+ *(uint8_t *)storage_ptr =
+ getMaskNumBits(ipaddr.addr.ipv6Addr,
+ sizeof(ipaddr.addr.ipv6Addr));
+ else
+ rc = -1;
+ found = 1;
+ }
+ break;
+
case DATATYPE_STRING:
if (!validator) {
// not supported
@@ -1076,6 +1264,13 @@ virNWFilterRuleDefFixup(virNWFilterRuleD
rule->p.ipHdrFilter.ipHdr.dataDstIPAddr);
break;

+ case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
+ COPY_NEG_SIGN(rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask,
+ rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr);
+ break;
+
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
break;
@@ -1930,7 +2125,36 @@ virNWIPAddressFormat(virBufferPtr buf, n
ipaddr->addr.ipv4Addr[2],
ipaddr->addr.ipv4Addr[3]);
} else {
- virBufferAddLit(buf, "MISSING IPv6 ADDRESS FORMATTER");
+ int i;
+ int dcshown = 0, in_dc = 0;
+ unsigned short n;
+ while (i < 8) {
+ n = (ipaddr->addr.ipv6Addr[i * 2 + 0] << 8) |
+ ipaddr->addr.ipv6Addr[i * 2 + 1];
+ if (n == 0) {
+ if (!dcshown) {
+ in_dc = 1;
+ if (i == 0)
+ virBufferAddLit(buf, ":");
+ dcshown = 1;
+ }
+ if (in_dc) {
+ i++;
+ continue;
+ }
+ }
+ if (in_dc) {
+ dcshown = 1;
+ virBufferAddLit(buf, ":");
+ in_dc = 0;
+ }
+ i++;
+ virBufferVSprintf(buf, "%x", n);
+ if (i < 8)
+ virBufferAddLit(buf, ":");
+ }
+ if (in_dc)
+ virBufferAddLit(buf, ":");
}
}

@@ -1999,6 +2223,7 @@ virNWFilterRuleDefDetailsFormat(virConne
switch (att[i].datatype) {

case DATATYPE_IPMASK:
+ case DATATYPE_IPV6MASK:
// display all masks in CIDR format
case DATATYPE_UINT8:
storage_ptr = &item->u.u8;
@@ -2011,6 +2236,7 @@ virNWFilterRuleDefDetailsFormat(virConne
break;

case DATATYPE_IPADDR:
+ case DATATYPE_IPV6ADDR:
storage_ptr = &item->u.ipaddr;
virNWIPAddressFormat(buf,
(nwIPAddressPtr)storage_ptr);
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.h
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -68,8 +68,10 @@ enum attrDatatype {
DATATYPE_IPADDR = (1 << 4),
DATATYPE_IPMASK = (1 << 5),
DATATYPE_STRING = (1 << 6),
+ DATATYPE_IPV6ADDR = (1 << 7),
+ DATATYPE_IPV6MASK = (1 << 8),

- DATATYPE_LAST = (1 << 7),
+ DATATYPE_LAST = (1 << 9),
};


@@ -86,7 +88,7 @@ struct _nwIPAddress {
int isIPv6;
union {
unsigned char ipv4Addr[4];
- /* unsigned char ipv6Addr[16]; future :-) */
+ unsigned char ipv6Addr[16];
} addr;
};

@@ -171,6 +173,15 @@ struct _ipHdrFilterDef {
};


+typedef struct _ipv6HdrFilterDef ipv6HdrFilterDef;
+typedef ipv6HdrFilterDef *ipv6HdrFilterDefPtr;
+struct _ipv6HdrFilterDef {
+ ethHdrDataDef ethHdr;
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+};
+
+
enum virNWFilterRuleActionType {
VIR_NWFILTER_RULE_ACTION_DROP = 0,
VIR_NWFILTER_RULE_ACTION_ACCEPT,
@@ -198,6 +209,7 @@ enum virNWFilterRuleProtocolType {
VIR_NWFILTER_RULE_PROTOCOL_MAC,
VIR_NWFILTER_RULE_PROTOCOL_ARP,
VIR_NWFILTER_RULE_PROTOCOL_IP,
+ VIR_NWFILTER_RULE_PROTOCOL_IPV6,
};

enum virNWFilterEbtablesTableType {
@@ -223,6 +235,7 @@ struct _virNWFilterRuleDef {
ethHdrFilterDef ethHdrFilter;
arpHdrFilterDef arpHdrFilter;
ipHdrFilterDef ipHdrFilter;
+ ipv6HdrFilterDef ipv6HdrFilter;
} p;

int nvars;
@@ -249,6 +262,7 @@ enum virNWFilterChainSuffixType {
VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
VIR_NWFILTER_CHAINSUFFIX_ARP,
VIR_NWFILTER_CHAINSUFFIX_IPv4,
+ VIR_NWFILTER_CHAINSUFFIX_IPv6,

VIR_NWFILTER_CHAINSUFFIX_LAST,
};
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -73,6 +73,7 @@

static const char *supported_protocols[] = {
"ipv4",
+ "ipv6",
"arp",
NULL,
};
@@ -117,6 +118,8 @@ printDataType(virConnectPtr conn,
nwItemDescPtr item)
{
int done;
+ int i, pos, s;
+
if (printVar(conn, vars, buf, bufsize, item, &done))
return 1;

@@ -136,6 +139,21 @@ printDataType(virConnectPtr conn,
}
break;

+ case DATATYPE_IPV6ADDR:
+ pos = 0;
+ for (i = 0; i < 16; i++) {
+ s = snprintf(&buf[pos], bufsize - pos, "%x%s",
+ (unsigned int)item->u.ipaddr.addr.ipv6Addr[i],
+ ((i & 1) && (i < 15)) ? ":" : "" );
+ if (s >= bufsize - pos) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for IPv6 address"));
+ return 1;
+ }
+ pos += s;
+ }
+ break;
+
case DATATYPE_MACADDR:
if (bufsize < VIR_MAC_STRING_BUFLEN) {
virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
@@ -155,6 +173,7 @@ printDataType(virConnectPtr conn,
}
break;

+ case DATATYPE_IPV6MASK:
case DATATYPE_IPMASK:
case DATATYPE_UINT8:
if (snprintf(buf, bufsize, "%d",
@@ -304,6 +323,7 @@ ebtablesCreateRuleInstance(virConnectPtr
{
char macaddr[VIR_MAC_STRING_BUFLEN],
ipaddr[INET_ADDRSTRLEN],
+ ipv6addr[INET6_ADDRSTRLEN],
number[20];
char chain[MAX_CHAINNAME_LENGTH];
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -587,6 +607,135 @@ ebtablesCreateRuleInstance(virConnectPtr
}
break;

+ case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.ipv6HdrFilter.ethHdr))
+ goto err_exit;
+
+ virBufferAddLit(&buf,
+ " -p ipv6");
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipv6addr, sizeof(ipv6addr),
+ &rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip6-source %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
+ ipv6addr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipv6addr, sizeof(ipv6addr),
+ &rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip6-destination %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
+ ipv6addr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.ipHdr.dataProtocolID))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip6-protocol %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.portData.dataSrcPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip6-source-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.portData.dataSrcPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.portData.dataDstPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip6-destination-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataDstPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipv6HdrFilter.portData.dataDstPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+ break;
+
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
virBufferVSprintf(&buf,
CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
@@ -650,6 +799,7 @@ ebiptablesCreateRuleInstance(virConnectP
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ case VIR_NWFILTER_RULE_PROTOCOL_IPV6:

if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
@@ -1230,6 +1380,11 @@ ebiptablesApplyRules(virConnectPtr conn,
if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "ipv4", 1);

+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "ipv6", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "ipv6", 1);
+
// keep arp as last
if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "arp", 1);
s***@us.ibm.com
2010-03-23 14:54:09 UTC
Permalink
This patch adds the internal API extensions for network filtering (ACL) support.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/driver.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)

Index: libvirt-acl/src/driver.h
===================================================================
--- libvirt-acl.orig/src/driver.h
+++ libvirt-acl/src/driver.h
@@ -994,6 +994,58 @@ struct _virStreamDriver {
};


+typedef int
+ (*virDrvConnectNumOfNWFilters) (virConnectPtr conn);
+typedef int
+ (*virDrvConnectListNWFilters) (virConnectPtr conn,
+ char **const names,
+ int maxnames);
+typedef virNWFilterPtr
+ (*virDrvNWFilterLookupByName) (virConnectPtr conn,
+ const char *name);
+typedef virNWFilterPtr
+ (*virDrvNWFilterLookupByUUID) (virConnectPtr conn,
+ const unsigned char *uuid);
+typedef virNWFilterPtr
+ (*virDrvNWFilterDefineXML) (virConnectPtr conn,
+ const char *xmlDesc,
+ unsigned int flags);
+typedef int
+ (*virDrvNWFilterUndefine) (virNWFilterPtr pool);
+
+typedef char *
+ (*virDrvNWFilterGetXMLDesc) (virNWFilterPtr pool,
+ unsigned int flags);
+
+
+typedef struct _virNWFilterDriver virNWFilterDriver;
+typedef virNWFilterDriver *virNWFilterDriverPtr;
+
+/**
+ * _virNWFilterDriver:
+ *
+ * Structure associated to a network filter driver, defining the various
+ * entry points for it.
+ *
+ * All drivers must support the following fields/methods:
+ * - open
+ * - close
+ */
+struct _virNWFilterDriver {
+ const char * name; /* the name of the driver */
+ virDrvOpen open;
+ virDrvClose close;
+
+ virDrvConnectNumOfNWFilters numOfNWFilters;
+ virDrvConnectListNWFilters listNWFilters;
+ virDrvNWFilterLookupByName nwfilterLookupByName;
+ virDrvNWFilterLookupByUUID nwfilterLookupByUUID;
+ virDrvNWFilterDefineXML defineXML;
+ virDrvNWFilterUndefine undefine;
+ virDrvNWFilterGetXMLDesc getXMLDesc;
+};
+
+
/*
* Registration
* TODO: also need ways to (des)activate a given driver
@@ -1005,6 +1057,7 @@ int virRegisterInterfaceDriver(virInterf
int virRegisterStorageDriver(virStorageDriverPtr);
int virRegisterDeviceMonitor(virDeviceMonitorPtr);
int virRegisterSecretDriver(virSecretDriverPtr);
+int virRegisterNWFilterDriver(virNWFilterDriverPtr);
# ifdef WITH_LIBVIRTD
int virRegisterStateDriver(virStateDriverPtr);
# endif
Daniel P. Berrange
2010-03-25 10:57:05 UTC
Permalink
Post by s***@us.ibm.com
This patch adds the internal API extensions for network filtering (ACL) support.
---
src/driver.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
Index: libvirt-acl/src/driver.h
===================================================================
--- libvirt-acl.orig/src/driver.h
+++ libvirt-acl/src/driver.h
@@ -994,6 +994,58 @@ struct _virStreamDriver {
};
+typedef int
+ (*virDrvConnectNumOfNWFilters) (virConnectPtr conn);
+typedef int
+ (*virDrvConnectListNWFilters) (virConnectPtr conn,
+ char **const names,
+ int maxnames);
+typedef virNWFilterPtr
+ (*virDrvNWFilterLookupByName) (virConnectPtr conn,
+ const char *name);
+typedef virNWFilterPtr
+ (*virDrvNWFilterLookupByUUID) (virConnectPtr conn,
+ const unsigned char *uuid);
+typedef virNWFilterPtr
+ (*virDrvNWFilterDefineXML) (virConnectPtr conn,
+ const char *xmlDesc,
+ unsigned int flags);
+typedef int
+ (*virDrvNWFilterUndefine) (virNWFilterPtr pool);
+
+typedef char *
+ (*virDrvNWFilterGetXMLDesc) (virNWFilterPtr pool,
+ unsigned int flags);
+
+
+typedef struct _virNWFilterDriver virNWFilterDriver;
+typedef virNWFilterDriver *virNWFilterDriverPtr;
+
+/**
+ *
+ * Structure associated to a network filter driver, defining the various
+ * entry points for it.
+ *
+ * - open
+ * - close
+ */
+struct _virNWFilterDriver {
+ const char * name; /* the name of the driver */
+ virDrvOpen open;
+ virDrvClose close;
+
+ virDrvConnectNumOfNWFilters numOfNWFilters;
+ virDrvConnectListNWFilters listNWFilters;
+ virDrvNWFilterLookupByName nwfilterLookupByName;
+ virDrvNWFilterLookupByUUID nwfilterLookupByUUID;
+ virDrvNWFilterDefineXML defineXML;
+ virDrvNWFilterUndefine undefine;
+ virDrvNWFilterGetXMLDesc getXMLDesc;
+};
+
+
/*
* Registration
* TODO: also need ways to (des)activate a given driver
@@ -1005,6 +1057,7 @@ int virRegisterInterfaceDriver(virInterf
int virRegisterStorageDriver(virStorageDriverPtr);
int virRegisterDeviceMonitor(virDeviceMonitorPtr);
int virRegisterSecretDriver(virSecretDriverPtr);
+int virRegisterNWFilterDriver(virNWFilterDriverPtr);
# ifdef WITH_LIBVIRTD
int virRegisterStateDriver(virStateDriverPtr);
# endif
ACK


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:12 UTC
Permalink
This patch extends the RPC client for the new network filtering (ACL) functionality.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
daemon/remote.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 194 insertions(+)

Index: libvirt-acl/daemon/remote.c
===================================================================
--- libvirt-acl.orig/daemon/remote.c
+++ libvirt-acl/daemon/remote.c
@@ -66,6 +66,7 @@ static virInterfacePtr get_nonnull_inter
static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool);
static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol);
static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret);
+static virNWFilterPtr get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src);
static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
@@ -73,6 +74,7 @@ static void make_nonnull_storage_pool (r
static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
static void make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
+static void make_nonnull_nwfilter (remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);


#include "remote_dispatch_prototypes.h"
@@ -5524,6 +5526,185 @@ remoteDispatchDomainMigrateSetMaxDowntim
}


+
+static int
+remoteDispatchNwfilterLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_nwfilter_lookup_by_name_args *args,
+ remote_nwfilter_lookup_by_name_ret *ret)
+{
+ virNWFilterPtr nwfilter;
+
+ nwfilter = virNWFilterLookupByName (conn, args->name);
+ if (nwfilter == NULL) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ make_nonnull_nwfilter (&ret->nwfilter, nwfilter);
+ virNWFilterFree(nwfilter);
+ return 0;
+}
+
+static int
+remoteDispatchNwfilterLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_nwfilter_lookup_by_uuid_args *args,
+ remote_nwfilter_lookup_by_uuid_ret *ret)
+{
+ virNWFilterPtr nwfilter;
+
+ nwfilter = virNWFilterLookupByUUID (conn, (unsigned char *) args->uuid);
+ if (nwfilter == NULL) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ make_nonnull_nwfilter (&ret->nwfilter, nwfilter);
+ virNWFilterFree(nwfilter);
+ return 0;
+}
+
+
+static int
+remoteDispatchNwfilterDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_nwfilter_define_xml_args *args,
+ remote_nwfilter_define_xml_ret *ret)
+{
+ virNWFilterPtr nwfilter;
+
+ nwfilter = virNWFilterDefineXML (conn, args->xml);
+ if (nwfilter == NULL) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ make_nonnull_nwfilter (&ret->nwfilter, nwfilter);
+ virNWFilterFree(nwfilter);
+ return 0;
+}
+
+
+static int
+remoteDispatchNwfilterUndefine (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_nwfilter_undefine_args *args,
+ void *ret ATTRIBUTE_UNUSED)
+{
+ virNWFilterPtr nwfilter;
+
+ nwfilter = get_nonnull_nwfilter (conn, args->nwfilter);
+ if (nwfilter == NULL) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ if (virNWFilterUndefine (nwfilter) == -1) {
+ virNWFilterFree(nwfilter);
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+ virNWFilterFree(nwfilter);
+ return 0;
+}
+
+static int
+remoteDispatchListNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_list_nwfilters_args *args,
+ remote_list_nwfilters_ret *ret)
+{
+
+ if (args->maxnames > REMOTE_NWFILTER_NAME_LIST_MAX) {
+ remoteDispatchFormatError (rerr,
+ "%s", _("maxnames > REMOTE_NWFILTER_NAME_LIST_MAX"));
+ return -1;
+ }
+
+ /* Allocate return buffer. */
+ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) {
+ remoteDispatchOOMError(rerr);
+ return -1;
+ }
+
+ ret->names.names_len =
+ virConnectListNWFilters (conn,
+ ret->names.names_val, args->maxnames);
+ if (ret->names.names_len == -1) {
+ VIR_FREE(ret->names.names_len);
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+remoteDispatchNwfilterGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ remote_nwfilter_get_xml_desc_args *args,
+ remote_nwfilter_get_xml_desc_ret *ret)
+{
+ virNWFilterPtr nwfilter;
+
+ nwfilter = get_nonnull_nwfilter (conn, args->nwfilter);
+ if (nwfilter == NULL) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ /* remoteDispatchClientRequest will free this. */
+ ret->xml = virNWFilterGetXMLDesc (nwfilter, args->flags);
+ if (!ret->xml) {
+ virNWFilterFree(nwfilter);
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+ virNWFilterFree(nwfilter);
+ return 0;
+}
+
+
+static int
+remoteDispatchNumOfNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ virConnectPtr conn,
+ remote_message_header *hdr ATTRIBUTE_UNUSED,
+ remote_error *rerr,
+ void *args ATTRIBUTE_UNUSED,
+ remote_num_of_nwfilters_ret *ret)
+{
+
+ ret->num = virConnectNumOfNWFilters (conn);
+ if (ret->num == -1) {
+ remoteDispatchConnError(rerr, conn);
+ return -1;
+ }
+
+ return 0;
+}
+
+
/*----- Helpers. -----*/

/* get_nonnull_domain and get_nonnull_network turn an on-wire
@@ -5576,6 +5757,12 @@ get_nonnull_secret (virConnectPtr conn,
return virGetSecret (conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
}

+static virNWFilterPtr
+get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
+{
+ return virGetNWFilter (conn, nwfilter.name, BAD_CAST nwfilter.uuid);
+}
+
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
@@ -5628,3 +5815,10 @@ make_nonnull_secret (remote_nonnull_secr
secret_dst->usageType = secret_src->usageType;
secret_dst->usageID = strdup (secret_src->usageID);
}
+
+static void
+make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
+{
+ nwfilter_dst->name = strdup (nwfilter_src->name);
+ memcpy (nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
+}
Daniel P. Berrange
2010-03-25 11:00:14 UTC
Permalink
Post by s***@us.ibm.com
This patch extends the RPC client for the new network filtering (ACL) functionality.
---
daemon/remote.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 194 insertions(+)
ACK, all fine


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:07 UTC
Permalink
This patch adds recursive locks necessary due to the processing of
network filter XML that can reference other network filters, including
references that cause looks. Loops in the XML are prevented but their
detection requires recursive locks.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/util/threads-pthread.c | 13 +++++++++++++
src/util/threads-win32.c | 5 +++++
src/util/threads.h | 1 +
3 files changed, 19 insertions(+)

Index: libvirt-acl/src/util/threads-pthread.c
===================================================================
--- libvirt-acl.orig/src/util/threads-pthread.c
+++ libvirt-acl/src/util/threads-pthread.c
@@ -46,6 +46,19 @@ int virMutexInit(virMutexPtr m)
return 0;
}

+int virMutexInitRecursive(virMutexPtr m)
+{
+ int ret;
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ if ((ret = pthread_mutex_init(&m->lock, &attr)) != 0) {
+ errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
void virMutexDestroy(virMutexPtr m)
{
pthread_mutex_destroy(&m->lock);
Index: libvirt-acl/src/util/threads.h
===================================================================
--- libvirt-acl.orig/src/util/threads.h
+++ libvirt-acl/src/util/threads.h
@@ -38,6 +38,7 @@ int virThreadInitialize(void) ATTRIBUTE_
void virThreadOnExit(void);

int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
+int virMutexInitRecursive(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
void virMutexDestroy(virMutexPtr m);

void virMutexLock(virMutexPtr m);
Index: libvirt-acl/src/util/threads-win32.c
===================================================================
--- libvirt-acl.orig/src/util/threads-win32.c
+++ libvirt-acl/src/util/threads-win32.c
@@ -69,6 +69,11 @@ void virThreadOnExit(void)

int virMutexInit(virMutexPtr m)
{
+ virMutexInitRecursive(m);
+}
+
+int virMutexInitRecursive(virMutexPtr m)
+{
if (!(m->lock = CreateMutex(NULL, FALSE, NULL))) {
errno = ESRCH;
return -1;
Daniel P. Berrange
2010-03-25 10:55:51 UTC
Permalink
Post by s***@us.ibm.com
This patch adds recursive locks necessary due to the processing of
network filter XML that can reference other network filters, including
references that cause looks. Loops in the XML are prevented but their
detection requires recursive locks.
---
src/util/threads-pthread.c | 13 +++++++++++++
src/util/threads-win32.c | 5 +++++
src/util/threads.h | 1 +
3 files changed, 19 insertions(+)
Index: libvirt-acl/src/util/threads-pthread.c
===================================================================
--- libvirt-acl.orig/src/util/threads-pthread.c
+++ libvirt-acl/src/util/threads-pthread.c
@@ -46,6 +46,19 @@ int virMutexInit(virMutexPtr m)
return 0;
}
+int virMutexInitRecursive(virMutexPtr m)
+{
+ int ret;
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ if ((ret = pthread_mutex_init(&m->lock, &attr)) != 0) {
+ errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
void virMutexDestroy(virMutexPtr m)
{
pthread_mutex_destroy(&m->lock);
Index: libvirt-acl/src/util/threads.h
===================================================================
--- libvirt-acl.orig/src/util/threads.h
+++ libvirt-acl/src/util/threads.h
@@ -38,6 +38,7 @@ int virThreadInitialize(void) ATTRIBUTE_
void virThreadOnExit(void);
int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
+int virMutexInitRecursive(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
void virMutexDestroy(virMutexPtr m);
void virMutexLock(virMutexPtr m);
Index: libvirt-acl/src/util/threads-win32.c
===================================================================
--- libvirt-acl.orig/src/util/threads-win32.c
+++ libvirt-acl/src/util/threads-win32.c
@@ -69,6 +69,11 @@ void virThreadOnExit(void)
int virMutexInit(virMutexPtr m)
{
+ virMutexInitRecursive(m);
+}
+
+int virMutexInitRecursive(virMutexPtr m)
+{
if (!(m->lock = CreateMutex(NULL, FALSE, NULL))) {
errno = ESRCH;
return -1;
ACK


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:13 UTC
Permalink
This patch extends the RPC dispatcher to support the newly added RPC
calls for network filtering (ACL) support.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/remote/remote_driver.c | 311 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 311 insertions(+)

Index: libvirt-acl/src/remote/remote_driver.c
===================================================================
--- libvirt-acl.orig/src/remote/remote_driver.c
+++ libvirt-acl/src/remote/remote_driver.c
@@ -248,6 +248,7 @@ static int remoteAuthPolkit (virConnectP

static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network);
+static virNWFilterPtr get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface iface);
static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool);
static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol);
@@ -259,6 +260,7 @@ static void make_nonnull_interface (remo
static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src);
static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
+static void make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src);
void remoteDomainEventFired(int watch, int fd, int event, void *data);
static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr);
void remoteDomainEventQueueFlush(int timer, void *opaque);
@@ -6086,6 +6088,287 @@ done:
return rv;
}

+/* ------------------------------------------------------------- */
+
+static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
+remoteNWFilterOpen (virConnectPtr conn,
+ virConnectAuthPtr auth,
+ int flags)
+{
+ if (inside_daemon)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (conn->driver &&
+ STREQ (conn->driver->name, "remote")) {
+ struct private_data *priv;
+
+ /* If we're here, the remote driver is already
+ * in use due to a) a QEMU uri, or b) a remote
+ * URI. So we can re-use existing connection
+ */
+ priv = conn->privateData;
+ remoteDriverLock(priv);
+ priv->localUses++;
+ conn->nwfilterPrivateData = priv;
+ remoteDriverUnlock(priv);
+ return VIR_DRV_OPEN_SUCCESS;
+ } else {
+ /* Using a non-remote driver, so we need to open a
+ * new connection for network filtering APIs, forcing it to
+ * use the UNIX transport. This handles Xen driver
+ * which doesn't have its own impl of the network filtering APIs.
+ */
+ struct private_data *priv;
+ int ret;
+ ret = remoteOpenSecondaryDriver(conn,
+ auth,
+ flags,
+ &priv);
+ if (ret == VIR_DRV_OPEN_SUCCESS)
+ conn->nwfilterPrivateData = priv;
+ return ret;
+ }
+}
+
+static int
+remoteNWFilterClose (virConnectPtr conn)
+{
+ int rv = 0;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+ priv->localUses--;
+ if (!priv->localUses) {
+ rv = doRemoteClose(conn, priv);
+ conn->nwfilterPrivateData = NULL;
+ remoteDriverUnlock(priv);
+ virMutexDestroy(&priv->lock);
+ VIR_FREE(priv);
+ }
+ if (priv)
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static int
+remoteNumOfNWFilters (virConnectPtr conn)
+{
+ int rv = -1;
+ remote_num_of_nwfilters_ret ret;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_NWFILTERS,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_remote_num_of_nwfilters_ret, (char *) &ret) == -1)
+ goto done;
+
+ rv = ret.num;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static virNWFilterPtr
+remoteNWFilterDefineXML (virConnectPtr conn, const char *xmlDesc,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ virNWFilterPtr net = NULL;
+ remote_nwfilter_define_xml_args args;
+ remote_nwfilter_define_xml_ret ret;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ args.xml = (char *) xmlDesc;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_NWFILTER_DEFINE_XML,
+ (xdrproc_t) xdr_remote_nwfilter_define_xml_args, (char *) &args,
+ (xdrproc_t) xdr_remote_nwfilter_define_xml_ret, (char *) &ret) == -1)
+ goto done;
+
+ net = get_nonnull_nwfilter (conn, ret.nwfilter);
+ xdr_free ((xdrproc_t) &xdr_remote_nwfilter_define_xml_ret, (char *) &ret);
+
+done:
+ remoteDriverUnlock(priv);
+ return net;
+}
+
+
+static int
+remoteNWFilterUndefine (virNWFilterPtr nwfilter)
+{
+ int rv = -1;
+ remote_nwfilter_undefine_args args;
+ struct private_data *priv = nwfilter->conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ make_nonnull_nwfilter (&args.nwfilter, nwfilter);
+
+ if (call (nwfilter->conn, priv, 0, REMOTE_PROC_NWFILTER_UNDEFINE,
+ (xdrproc_t) xdr_remote_nwfilter_undefine_args, (char *) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ goto done;
+
+ rv = 0;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static int
+remoteListNWFilters (virConnectPtr conn, char **const names, int maxnames)
+{
+ int rv = -1;
+ int i;
+ remote_list_nwfilters_args args;
+ remote_list_nwfilters_ret ret;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ if (maxnames > REMOTE_NWFILTER_NAME_LIST_MAX) {
+ errorf (conn, VIR_ERR_RPC,
+ _("too many remote nwfilters: %d > %d"),
+ maxnames, REMOTE_NWFILTER_NAME_LIST_MAX);
+ goto done;
+ }
+ args.maxnames = maxnames;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_LIST_NWFILTERS,
+ (xdrproc_t) xdr_remote_list_nwfilters_args, (char *) &args,
+ (xdrproc_t) xdr_remote_list_nwfilters_ret, (char *) &ret) == -1)
+ goto done;
+
+ if (ret.names.names_len > maxnames) {
+ errorf (conn, VIR_ERR_RPC,
+ _("too many remote nwfilters: %d > %d"),
+ ret.names.names_len, maxnames);
+ goto cleanup;
+ }
+
+ /* This call is caller-frees (although that isn't clear from
+ * the documentation). However xdr_free will free up both the
+ * names and the list of pointers, so we have to strdup the
+ * names here.
+ */
+ for (i = 0; i < ret.names.names_len; ++i) {
+ names[i] = strdup (ret.names.names_val[i]);
+
+ if (names[i] == NULL) {
+ for (--i; i >= 0; --i)
+ VIR_FREE(names[i]);
+
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+ rv = ret.names.names_len;
+
+cleanup:
+ xdr_free ((xdrproc_t) xdr_remote_list_nwfilters_ret, (char *) &ret);
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+
+static virNWFilterPtr
+remoteNWFilterLookupByUUID (virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ virNWFilterPtr net = NULL;
+ remote_nwfilter_lookup_by_uuid_args args;
+ remote_nwfilter_lookup_by_uuid_ret ret;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ memcpy (args.uuid, uuid, VIR_UUID_BUFLEN);
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID,
+ (xdrproc_t) xdr_remote_nwfilter_lookup_by_uuid_args, (char *) &args,
+ (xdrproc_t) xdr_remote_nwfilter_lookup_by_uuid_ret, (char *) &ret) == -1)
+ goto done;
+
+ net = get_nonnull_nwfilter (conn, ret.nwfilter);
+ xdr_free ((xdrproc_t) &xdr_remote_nwfilter_lookup_by_uuid_ret, (char *) &ret);
+
+done:
+ remoteDriverUnlock(priv);
+ return net;
+}
+
+static virNWFilterPtr
+remoteNWFilterLookupByName (virConnectPtr conn,
+ const char *name)
+{
+ virNWFilterPtr net = NULL;
+ remote_nwfilter_lookup_by_name_args args;
+ remote_nwfilter_lookup_by_name_ret ret;
+ struct private_data *priv = conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ args.name = (char *) name;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME,
+ (xdrproc_t) xdr_remote_nwfilter_lookup_by_name_args, (char *) &args,
+ (xdrproc_t) xdr_remote_nwfilter_lookup_by_name_ret, (char *) &ret) == -1)
+ goto done;
+
+ net = get_nonnull_nwfilter (conn, ret.nwfilter);
+ xdr_free ((xdrproc_t) &xdr_remote_nwfilter_lookup_by_name_ret, (char *) &ret);
+
+done:
+ remoteDriverUnlock(priv);
+ return net;
+}
+
+
+static char *
+remoteNWFilterGetXMLDesc (virNWFilterPtr nwfilter, unsigned int flags)
+{
+ char *rv = NULL;
+ remote_nwfilter_get_xml_desc_args args;
+ remote_nwfilter_get_xml_desc_ret ret;
+ struct private_data *priv = nwfilter->conn->nwfilterPrivateData;
+
+ remoteDriverLock(priv);
+
+ make_nonnull_nwfilter (&args.nwfilter, nwfilter);
+ args.flags = flags;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (nwfilter->conn, priv, 0, REMOTE_PROC_NWFILTER_GET_XML_DESC,
+ (xdrproc_t) xdr_remote_nwfilter_get_xml_desc_args, (char *) &args,
+ (xdrproc_t) xdr_remote_nwfilter_get_xml_desc_ret, (char *) &ret) == -1)
+ goto done;
+
+ /* Caller frees. */
+ rv = ret.xml;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+

/*----------------------------------------------------------------------*/

@@ -9053,6 +9336,13 @@ get_nonnull_secret (virConnectPtr conn,
return virGetSecret(conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
}

+static virNWFilterPtr
+get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
+{
+ return virGetNWFilter (conn, nwfilter.name, BAD_CAST nwfilter.uuid);
+}
+
+
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
@@ -9100,6 +9390,13 @@ make_nonnull_secret (remote_nonnull_secr
secret_dst->usageID = secret_src->usageID;
}

+static void
+make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
+{
+ nwfilter_dst->name = nwfilter_src->name;
+ memcpy (nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
+}
+
/*----------------------------------------------------------------------*/

unsigned long remoteVersion(void)
@@ -9303,6 +9600,19 @@ static virDeviceMonitor dev_monitor = {
.deviceDestroy = remoteNodeDeviceDestroy
};

+static virNWFilterDriver nwfilter_driver = {
+ .name = "remote",
+ .open = remoteNWFilterOpen,
+ .close = remoteNWFilterClose,
+ .nwfilterLookupByUUID = remoteNWFilterLookupByUUID,
+ .nwfilterLookupByName = remoteNWFilterLookupByName,
+ .getXMLDesc = remoteNWFilterGetXMLDesc,
+ .defineXML = remoteNWFilterDefineXML,
+ .undefine = remoteNWFilterUndefine,
+ .numOfNWFilters = remoteNumOfNWFilters,
+ .listNWFilters = remoteListNWFilters,
+};
+

#ifdef WITH_LIBVIRTD
static virStateDriver state_driver = {
@@ -9327,6 +9637,7 @@ remoteRegister (void)
if (virRegisterStorageDriver (&storage_driver) == -1) return -1;
if (virRegisterDeviceMonitor (&dev_monitor) == -1) return -1;
if (virRegisterSecretDriver (&secret_driver) == -1) return -1;
+ if (virRegisterNWFilterDriver(&nwfilter_driver) == -1) return -1;
#ifdef WITH_LIBVIRTD
if (virRegisterStateDriver (&state_driver) == -1) return -1;
#endif
Daniel P. Berrange
2010-03-25 11:01:41 UTC
Permalink
Post by s***@us.ibm.com
This patch extends the RPC dispatcher to support the newly added RPC
calls for network filtering (ACL) support.
---
src/remote/remote_driver.c | 311 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 311 insertions(+)
ACK, all fine.

Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:14 UTC
Permalink
This patch adds virsh support for the five new CLI commands to manage
network filters.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
tools/virsh.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 349 insertions(+)

Index: libvirt-acl/tools/virsh.c
===================================================================
--- libvirt-acl.orig/tools/virsh.c
+++ libvirt-acl/tools/virsh.c
@@ -254,6 +254,14 @@ static virNetworkPtr vshCommandOptNetwor
vshCommandOptNetworkBy(_ctl, _cmd, _name, \
VSH_BYUUID|VSH_BYNAME)

+static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
+ char **name, int flag);
+
+/* default is lookup by Name and UUID */
+#define vshCommandOptNWFilter(_ctl, _cmd, _name) \
+ vshCommandOptNWFilterBy(_ctl, _cmd, _name, \
+ VSH_BYUUID|VSH_BYNAME)
+
static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
char **name, int flag);

@@ -3850,6 +3858,300 @@ cmdInterfaceDestroy(vshControl *ctl, con
return ret;
}

+
+/*
+ * "nwfilter-define" command
+ */
+static const vshCmdInfo info_nwfilter_define[] = {
+ {"help", N_("define or update a network filter from an XML file")},
+ {"desc", N_("Define a new network filter or update an existing one.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_define[] = {
+ {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterPtr nwfilter;
+ char *from;
+ int found;
+ int ret = TRUE;
+ char *buffer;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ from = vshCommandOptString(cmd, "file", &found);
+ if (!found)
+ return FALSE;
+
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
+ return FALSE;
+
+ nwfilter = virNWFilterDefineXML(ctl->conn, buffer);
+ VIR_FREE(buffer);
+
+ if (nwfilter != NULL) {
+ vshPrint(ctl, _("Network filter %s defined from %s\n"),
+ virNWFilterGetName(nwfilter), from);
+ virNWFilterFree(nwfilter);
+ } else {
+ vshError(ctl, _("Failed to define network filter from %s"), from);
+ ret = FALSE;
+ }
+ return ret;
+}
+
+
+/*
+ * "nwfilter-undefine" command
+ */
+static const vshCmdInfo info_nwfilter_undefine[] = {
+ {"help", N_("undefine a network filter")},
+ {"desc", N_("Undefine a given network filter.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_undefine[] = {
+ {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterPtr nwfilter;
+ int ret = TRUE;
+ char *name;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name)))
+ return FALSE;
+
+ if (virNWFilterUndefine(nwfilter) == 0) {
+ vshPrint(ctl, _("Network filter %s undefined\n"), name);
+ } else {
+ vshError(ctl, _("Failed to undefine network filter %s"), name);
+ ret = FALSE;
+ }
+
+ virNWFilterFree(nwfilter);
+ return ret;
+}
+
+
+/*
+ * "nwfilter-dumpxml" command
+ */
+static const vshCmdInfo info_nwfilter_dumpxml[] = {
+ {"help", N_("network filter information in XML")},
+ {"desc", N_("Output the network filter information as an XML dump to stdout.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
+ {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterPtr nwfilter;
+ int ret = TRUE;
+ char *dump;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL)))
+ return FALSE;
+
+ dump = virNWFilterGetXMLDesc(nwfilter, 0);
+ if (dump != NULL) {
+ printf("%s", dump);
+ VIR_FREE(dump);
+ } else {
+ ret = FALSE;
+ }
+
+ virNWFilterFree(nwfilter);
+ return ret;
+}
+
+/*
+ * "nwfilter-list" command
+ */
+static const vshCmdInfo info_nwfilter_list[] = {
+ {"help", N_("list network filters")},
+ {"desc", N_("Returns list of network filters.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_list[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+ int numfilters, i;
+ char **names;
+ unsigned char uuid[VIR_UUID_STRING_BUFLEN];
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ numfilters = virConnectNumOfNWFilters(ctl->conn);
+ if (numfilters < 0) {
+ vshError(ctl, "%s", _("Failed to list network filters"));
+ return FALSE;
+ }
+
+ names = vshMalloc(ctl, sizeof(char *) * numfilters);
+
+ if ((numfilters = virConnectListNWFilters(ctl->conn, names,
+ numfilters)) < 0) {
+ vshError(ctl, "%s", _("Failed to list network filters"));
+ VIR_FREE(names);
+ return FALSE;
+ }
+
+ qsort(&names[0], numfilters, sizeof(char *), namesorter);
+
+ vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name"));
+ vshPrintExtra(ctl,
+ "----------------------------------------------------------------\n");
+
+ for (i = 0; i < numfilters; i++) {
+ virNWFilterPtr nwfilter =
+ virNWFilterLookupByName(ctl->conn, names[i]);
+
+ /* this kind of work with networks is not atomic operation */
+ if (!nwfilter) {
+ VIR_FREE(names[i]);
+ continue;
+ }
+
+ virNWFilterGetUUIDString(nwfilter, uuid);
+ vshPrint(ctl, "%-36s %-20s\n",
+ uuid,
+ virNWFilterGetName(nwfilter));
+ virNWFilterFree(nwfilter);
+ VIR_FREE(names[i]);
+ }
+
+ VIR_FREE(names);
+ return TRUE;
+}
+
+
+/*
+ * "nwfilter-edit" command
+ */
+static const vshCmdInfo info_nwfilter_edit[] = {
+ {"help", N_("edit XML configuration for a network filter")},
+ {"desc", N_("Edit the XML configuration for a network filter.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_edit[] = {
+ {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNWFilterEdit (vshControl *ctl, const vshCmd *cmd)
+{
+ int ret = FALSE;
+ virNWFilterPtr nwfilter = NULL;
+ char *tmp = NULL;
+ char *doc = NULL;
+ char *doc_edited = NULL;
+ char *doc_reread = NULL;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ goto cleanup;
+
+ nwfilter = vshCommandOptNWFilter (ctl, cmd, NULL);
+ if (nwfilter == NULL)
+ goto cleanup;
+
+ /* Get the XML configuration of the interface. */
+ doc = virNWFilterGetXMLDesc (nwfilter, 0);
+ if (!doc)
+ goto cleanup;
+
+ /* Create and open the temporary file. */
+ tmp = editWriteToTempFile (ctl, doc);
+ if (!tmp) goto cleanup;
+
+ /* Start the editor. */
+ if (editFile (ctl, tmp) == -1) goto cleanup;
+
+ /* Read back the edited file. */
+ doc_edited = editReadBackFile (ctl, tmp);
+ if (!doc_edited) goto cleanup;
+
+ unlink (tmp);
+ tmp = NULL;
+
+ /* Compare original XML with edited. Has it changed at all? */
+ if (STREQ (doc, doc_edited)) {
+ vshPrint (ctl, _("Network filter %s XML configuration not changed.\n"),
+ virNWFilterGetName (nwfilter));
+ ret = TRUE;
+ goto cleanup;
+ }
+
+ /* Now re-read the network filter XML. Did someone else change it while
+ * it was being edited? This also catches problems such as us
+ * losing a connection or the interface going away.
+ */
+ doc_reread = virNWFilterGetXMLDesc (nwfilter, 0);
+ if (!doc_reread)
+ goto cleanup;
+
+ if (STRNEQ (doc, doc_reread)) {
+ vshError(ctl, "%s",
+ _("ERROR: the XML configuration was changed by another user"));
+ goto cleanup;
+ }
+
+ /* Everything checks out, so redefine the interface. */
+ virNWFilterFree (nwfilter);
+ nwfilter = virNWFilterDefineXML (ctl->conn, doc_edited);
+ if (!nwfilter)
+ goto cleanup;
+
+ vshPrint (ctl, _("Network filter %s XML configuration edited.\n"),
+ virNWFilterGetName(nwfilter));
+
+ ret = TRUE;
+
+cleanup:
+ if (nwfilter)
+ virNWFilterFree (nwfilter);
+
+ VIR_FREE(doc);
+ VIR_FREE(doc_edited);
+ VIR_FREE(doc_reread);
+
+ if (tmp) {
+ unlink (tmp);
+ VIR_FREE(tmp);
+ }
+
+ return ret;
+}
+
+
/**************************************************************************/
/*
* "pool-autostart" command
@@ -7848,6 +8150,12 @@ static const vshCmdDef commands[] = {
{"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
{"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},

+ {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define},
+ {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine},
+ {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml},
+ {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list},
+ {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit},
+
{"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
{"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
{"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
@@ -8320,6 +8628,47 @@ vshCommandOptNetworkBy(vshControl *ctl,
return network;
}

+
+static virNWFilterPtr
+vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
+ char **name, int flag)
+{
+ virNWFilterPtr nwfilter = NULL;
+ char *n;
+ const char *optname = "nwfilter";
+ if (!cmd_has_option (ctl, cmd, optname))
+ return NULL;
+
+ if (!(n = vshCommandOptString(cmd, optname, NULL))) {
+ vshError(ctl, "%s", _("undefined nwfilter name"));
+ return NULL;
+ }
+
+ vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
+ cmd->def->name, optname, n);
+
+ if (name)
+ *name = n;
+
+ /* try it by UUID */
+ if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
+ vshDebug(ctl, 5, "%s: <%s> trying as nwfilter UUID\n",
+ cmd->def->name, optname);
+ nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n);
+ }
+ /* try it by NAME */
+ if (nwfilter == NULL && (flag & VSH_BYNAME)) {
+ vshDebug(ctl, 5, "%s: <%s> trying as nwfilter NAME\n",
+ cmd->def->name, optname);
+ nwfilter = virNWFilterLookupByName(ctl->conn, n);
+ }
+
+ if (!nwfilter)
+ vshError(ctl, _("failed to get nwfilter '%s'"), n);
+
+ return nwfilter;
+}
+
static virInterfacePtr
vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
char **name, int flag)
Daniel P. Berrange
2010-03-25 11:02:27 UTC
Permalink
Post by s***@us.ibm.com
This patch adds virsh support for the five new CLI commands to manage
network filters.
---
tools/virsh.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 349 insertions(+)
ACK, all follows the standard pattern.


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:11 UTC
Permalink
This patch adds the definition of the wire format for RPC calls for the
new network filtering (ACL) functionality added to libvirt.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/remote/remote_protocol.x | 72 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)

Index: libvirt-acl/src/remote/remote_protocol.x
===================================================================
--- libvirt-acl.orig/src/remote/remote_protocol.x
+++ libvirt-acl/src/remote/remote_protocol.x
@@ -103,6 +103,9 @@ const REMOTE_NODE_DEVICE_NAME_LIST_MAX =
/* Upper limit on lists of node device capabilities. */
const REMOTE_NODE_DEVICE_CAPS_LIST_MAX = 16384;

+/* Upper limit on lists of network filter names. */
+const REMOTE_NWFILTER_NAME_LIST_MAX = 1024;
+
/* Upper limit on list of scheduler parameters. */
const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16;

@@ -176,6 +179,12 @@ struct remote_nonnull_network {
remote_uuid uuid;
};

+/* A network filter which may not be NULL. */
+struct remote_nonnull_nwfilter {
+ remote_nonnull_string name;
+ remote_uuid uuid;
+};
+
/* An interface which may not be NULL. */
struct remote_nonnull_interface {
remote_nonnull_string name;
@@ -210,6 +219,7 @@ struct remote_nonnull_secret {
/* A domain or network which may be NULL. */
typedef remote_nonnull_domain *remote_domain;
typedef remote_nonnull_network *remote_network;
+typedef remote_nonnull_nwfilter *remote_nwfilter;
typedef remote_nonnull_storage_pool *remote_storage_pool;
typedef remote_nonnull_storage_vol *remote_storage_vol;
typedef remote_nonnull_node_device *remote_node_device;
@@ -234,6 +244,7 @@ struct remote_error {
int int1;
int int2;
remote_network net;
+ remote_nwfilter nwfilter;
};

/* Authentication types available thus far.... */
@@ -843,6 +854,57 @@ struct remote_network_set_autostart_args
int autostart;
};

+/* network filter calls */
+
+struct remote_num_of_nwfilters_ret {
+ int num;
+};
+
+struct remote_list_nwfilters_args {
+ int maxnames;
+};
+
+struct remote_list_nwfilters_ret {
+ remote_nonnull_string names<REMOTE_NWFILTER_NAME_LIST_MAX>;
+};
+
+struct remote_nwfilter_lookup_by_uuid_args {
+ remote_uuid uuid;
+};
+
+struct remote_nwfilter_lookup_by_uuid_ret {
+ remote_nonnull_nwfilter nwfilter;
+};
+
+struct remote_nwfilter_lookup_by_name_args {
+ remote_nonnull_string name;
+};
+
+struct remote_nwfilter_lookup_by_name_ret {
+ remote_nonnull_nwfilter nwfilter;
+};
+
+struct remote_nwfilter_define_xml_args {
+ remote_nonnull_string xml;
+};
+
+struct remote_nwfilter_define_xml_ret {
+ remote_nonnull_nwfilter nwfilter;
+};
+
+struct remote_nwfilter_undefine_args {
+ remote_nonnull_nwfilter nwfilter;
+};
+
+struct remote_nwfilter_get_xml_desc_args {
+ remote_nonnull_nwfilter nwfilter;
+ int flags;
+};
+
+struct remote_nwfilter_get_xml_desc_ret {
+ remote_nonnull_string xml;
+};
+

/* Interface calls: */

@@ -1717,7 +1779,15 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163,
REMOTE_PROC_DOMAIN_ABORT_JOB = 164,
REMOTE_PROC_STORAGE_VOL_WIPE = 165,
- REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166
+ REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166,
+ REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME = 167,
+ REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID = 168,
+ REMOTE_PROC_NWFILTER_GET_XML_DESC = 169,
+ REMOTE_PROC_NUM_OF_NWFILTERS = 170,
+
+ REMOTE_PROC_LIST_NWFILTERS = 171,
+ REMOTE_PROC_NWFILTER_DEFINE_XML = 172,
+ REMOTE_PROC_NWFILTER_UNDEFINE = 173

/*
* Notice how the entries are grouped in sets of 10 ?
Daniel P. Berrange
2010-03-25 10:59:22 UTC
Permalink
Post by s***@us.ibm.com
This patch adds the definition of the wire format for RPC calls for the
new network filtering (ACL) functionality added to libvirt.
---
src/remote/remote_protocol.x | 72 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
ACK, all looks good



Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:18 UTC
Permalink
This patch adds build support for the network filtering framework.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
configure.ac | 12 ++++++++++++
daemon/Makefile.am | 4 ++++
src/Makefile.am | 34 +++++++++++++++++++++++++++++++++-
src/libvirt_private.syms | 39 +++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 15 +++++++++++++++
5 files changed, 103 insertions(+), 1 deletion(-)

Index: libvirt-acl/src/Makefile.am
===================================================================
--- libvirt-acl.orig/src/Makefile.am
+++ libvirt-acl/src/Makefile.am
@@ -97,9 +97,17 @@ DOMAIN_EVENT_SOURCES = \
conf/domain_event.c conf/domain_event.h

# Network driver generic impl APIs
-NETWORK_CONF_SOURCES = \
+NETWORK_CONF_SOURCES = \
conf/network_conf.c conf/network_conf.h

+# Network filter driver generic impl APIs
+NWFILTER_PARAM_CONF_SOURCES = \
+ conf/nwfilter_params.c conf/nwfilter_conf.h
+
+NWFILTER_CONF_SOURCES = \
+ $(NWFILTER_PARAM_CONF_SOURCES) \
+ conf/nwfilter_conf.c conf/nwfilter_conf.h
+
# Storage driver generic impl APIs
STORAGE_CONF_SOURCES = \
conf/storage_conf.h conf/storage_conf.c
@@ -126,6 +134,7 @@ CONF_SOURCES = \
$(DOMAIN_CONF_SOURCES) \
$(DOMAIN_EVENT_SOURCES) \
$(NETWORK_CONF_SOURCES) \
+ $(NWFILTER_CONF_SOURCES) \
$(NODE_DEVICE_CONF_SOURCES) \
$(STORAGE_CONF_SOURCES) \
$(ENCRYPTION_CONF_SOURCES) \
@@ -275,6 +284,11 @@ STORAGE_DRIVER_DISK_SOURCES = \
STORAGE_HELPER_DISK_SOURCES = \
storage/parthelper.c

+# Network filters
+NWFILTER_DRIVER_SOURCES = \
+ nwfilter/nwfilter_driver.h nwfilter/nwfilter_driver.c \
+ nwfilter/nwfilter_gentech_driver.c \
+ nwfilter/nwfilter_ebiptables_driver.c

# Security framework and drivers for various models
SECURITY_DRIVER_SOURCES = \
@@ -718,6 +732,22 @@ endif
endif


+if WITH_NWFILTER
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_nwfilter.la
+else
+libvirt_la_LIBADD += libvirt_driver_nwfilter.la
+noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
+endif
+libvirt_driver_nwfilter_la_CFLAGS = \
+ -***@top_srcdir@/src/conf
+if WITH_DRIVER_MODULES
+libvirt_driver_nwfilter_la_LDFLAGS = -module -avoid-version ../gnulib/lib/libgnu.la
+endif
+libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
+endif
+
+
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
noinst_LTLIBRARIES += libvirt_driver_security.la
libvirt_la_LIBADD += libvirt_driver_security.la
@@ -761,6 +791,7 @@ EXTRA_DIST += \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
+ $(NWFILTER_DRIVER_SOURCES) \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
$(SECRET_DRIVER_SOURCES) \
@@ -900,6 +931,7 @@ libvirt_lxc_SOURCES = \
$(NODE_INFO_SOURCES) \
$(ENCRYPTION_CONF_SOURCES) \
$(DOMAIN_CONF_SOURCES) \
+ $(NWFILTER_PARAM_CONF_SOURCES) \
$(CPU_CONF_SOURCES)
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS)
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -105,6 +105,8 @@ virUnrefConnect;
virUnrefSecret;
virGetStream;
virUnrefStream;
+virGetNWFilter;
+virUnrefNWFiler;


# domain_conf.h
@@ -294,6 +296,7 @@ virRegisterNetworkDriver;
virRegisterStorageDriver;
virRegisterDeviceMonitor;
virRegisterSecretDriver;
+virRegisterNWFilterDriver;


# json.h
@@ -429,6 +432,42 @@ virNodeDeviceGetWWNs;
virNodeDeviceGetParentHost;


+# nwfilter_conf.h
+virNWFilterPoolLoadAllConfigs;
+virNWFilterPoolObjAssignDef;
+virNWFilterPoolObjSaveDef;
+virNWFilterPoolObjFindByName;
+virNWFilterPoolObjFindByUUID;
+virNWFilterPoolObjLock;
+virNWFilterPoolObjUnlock;
+virNWFilterPoolObjRemove;
+virNWFilterDefFree;
+virNWFilterDefParseString;
+virNWFilterPoolObjDeleteDef;
+virNWFilterPoolObjListFree;
+virNWFilterDefFormat;
+virNWFilterChainSuffixTypeToString;
+virNWFilterRuleActionTypeToString;
+virNWFilterJumpTargetTypeToString;
+virNWFilterRegisterCallbackDriver;
+virNWFilterTestUnassignDef;
+virNWFilterConfLayerInit;
+virNWFilterConfLayerShutdown;
+
+
+#nwfilter_params.h
+virNWFilterHashTableCreate;
+virNWFilterHashTableFree;
+virNWFilterHashTablePut;
+virNWFilterHashTablePutAll;
+virNWFilterHashTableRemoveEntry;
+
+
+# nwfilter_gentech_driver.h
+virNWFilterInstantiateFilter;
+virNWFilterTeardownFilter;
+
+
# pci.h
pciGetDevice;
pciFreeDevice;
Index: libvirt-acl/daemon/Makefile.am
===================================================================
--- libvirt-acl.orig/daemon/Makefile.am
+++ libvirt-acl/daemon/Makefile.am
@@ -116,6 +116,10 @@ endif
if WITH_SECRETS
libvirtd_LDADD += ../src/libvirt_driver_secret.la
endif
+
+if WITH_NWFILTER
+ libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la
+endif
endif

libvirtd_LDADD += ../src/libvirt.la
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -294,6 +294,9 @@ if test x"$with_rhel5_api" = x"yes"; the
AC_DEFINE([WITH_RHEL5_API], [1], [whether building for the RHEL-5 API])
fi

+AC_PATH_PROG([BASH_PATH], [bash], /bin/bash, [/bin:$PATH])
+AC_DEFINE_UNQUOTED([BASH_PATH], "$BASH_PATH", [path to bash binary])
+
AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])

@@ -1268,6 +1271,15 @@ if test "$with_secrets" = "yes" ; then
fi
AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])

+with_nwfilter=yes
+if test "$with_libvirtd" = "no"; then
+ with_nwfilter=no
+fi
+if test "$with_nwfilter" = "yes" ; then
+ AC_DEFINE([WITH_NWFILTER], 1, [whether local network filter management driver is available])
+fi
+AM_CONDITIONAL([WITH_NWFILTER], [test "$with_nwfilter" = "yes"])
+

AC_ARG_WITH([storage-fs],
AC_HELP_STRING([--with-storage-fs], [with FileSystem backend for the storage driver @<:@default=check@:>@]),[],[with_storage_fs=check])
Index: libvirt-acl/src/libvirt_public.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_public.syms
+++ libvirt-acl/src/libvirt_public.syms
@@ -362,6 +362,21 @@ LIBVIRT_0.7.8 {
global:
virStorageVolWipe;
virDomainMigrateSetMaxDowntime;
+ virConnectListNWFilters;
+ virConnectNumOfNWFilters;
+ virNWFilterLookupByName;
+ virNWFilterLookupByUUID;
+ virNWFilterLookupByUUIDString;
+ virNWFilterFree;
+ virNWFilterGetName;
+ virNWFilterGetUUID;
+ virNWFilterGetUUIDString;
+ virNWFilterGetXMLDesc;
+ virNWFilterRef;
+ virNWFilterTest;
+ virNWFilterDefineXML;
+ virNWFilterUndefine;
} LIBVIRT_0.7.7;

+
# .... define new API here using predicted next version number ....
Daniel P. Berrange
2010-03-25 11:46:38 UTC
Permalink
Post by s***@us.ibm.com
This patch adds build support for the network filtering framework.
---
configure.ac | 12 ++++++++++++
daemon/Makefile.am | 4 ++++
src/Makefile.am | 34 +++++++++++++++++++++++++++++++++-
src/libvirt_private.syms | 39 +++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 15 +++++++++++++++
5 files changed, 103 insertions(+), 1 deletion(-)
Index: libvirt-acl/src/libvirt_public.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_public.syms
+++ libvirt-acl/src/libvirt_public.syms
@@ -362,6 +362,21 @@ LIBVIRT_0.7.8 {
virStorageVolWipe;
virDomainMigrateSetMaxDowntime;
+ virConnectListNWFilters;
+ virConnectNumOfNWFilters;
+ virNWFilterLookupByName;
+ virNWFilterLookupByUUID;
+ virNWFilterLookupByUUIDString;
+ virNWFilterFree;
+ virNWFilterGetName;
+ virNWFilterGetUUID;
+ virNWFilterGetUUIDString;
+ virNWFilterGetXMLDesc;
+ virNWFilterRef;
+ virNWFilterTest;
+ virNWFilterDefineXML;
+ virNWFilterUndefine;
} LIBVIRT_0.7.7;
I think virNWFilterTest is a left-over here, since I don't see that in
the public libvirt.h header file


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 12:29:39 UTC
Permalink
Post by Daniel P. Berrange
Post by s***@us.ibm.com
---
configure.ac | 12 ++++++++++++
daemon/Makefile.am | 4 ++++
src/Makefile.am | 34 +++++++++++++++++++++++++++++++++-
src/libvirt_private.syms | 39
+++++++++++++++++++++++++++++++++++++++
Post by Daniel P. Berrange
Post by s***@us.ibm.com
src/libvirt_public.syms | 15 +++++++++++++++
5 files changed, 103 insertions(+), 1 deletion(-)
Index: libvirt-acl/src/libvirt_public.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_public.syms
+++ libvirt-acl/src/libvirt_public.syms
@@ -362,6 +362,21 @@ LIBVIRT_0.7.8 {
virStorageVolWipe;
virDomainMigrateSetMaxDowntime;
+ virConnectListNWFilters;
+ virConnectNumOfNWFilters;
+ virNWFilterLookupByName;
+ virNWFilterLookupByUUID;
+ virNWFilterLookupByUUIDString;
+ virNWFilterFree;
+ virNWFilterGetName;
+ virNWFilterGetUUID;
+ virNWFilterGetUUIDString;
+ virNWFilterGetXMLDesc;
+ virNWFilterRef;
+ virNWFilterTest;
+ virNWFilterDefineXML;
+ virNWFilterUndefine;
} LIBVIRT_0.7.7;
I think virNWFilterTest is a left-over here, since I don't see that in
the public libvirt.h header file
Yes, right. Didn't see that... Thanks.


Stefan
Post by Daniel P. Berrange
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
Post by Daniel P. Berrange
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
Post by Daniel P. Berrange
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
Post by Daniel P. Berrange
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:16 UTC
Permalink
Add support for Qemu to have firewall rules applied and removed on VM
startup and shutdown respectively. This patch also provides support for
the updating of a filter that causes all VMs that reference the filter
to have their ebtables/iptables rules updated.

Signed-off-by: Stefan Berger <***@us.ibm.com>

---
src/qemu/qemu_conf.c | 29 +++++++++++++++++++++++++++++
src/qemu/qemu_driver.c | 27 +++++++++++++++++++++++++++
2 files changed, 56 insertions(+)

Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -54,6 +54,7 @@
#include "network.h"
#include "macvtap.h"
#include "cpu/cpu.h"
+#include "nwfilter/nwfilter_gentech_driver.h"

#define VIR_FROM_THIS VIR_FROM_QEMU

@@ -1472,6 +1473,17 @@ qemudPhysIfaceConnect(virConnectPtr conn
net->ifname);
}
}
+
+ if (rc >= 0) {
+ if ((net->filter) && (net->ifname)) {
+ err = virNWFilterInstantiateFilter(conn, net);
+ if (err) {
+ close(rc);
+ rc = -1;
+ delMacvtap(net->ifname);
+ }
+ }
+ }
#else
(void)conn;
(void)net;
@@ -1594,6 +1606,16 @@ qemudNetworkIfaceConnect(virConnectPtr c
}
}

+ if (tapfd >= 0) {
+ if ((net->filter) && (net->ifname)) {
+ err = virNWFilterInstantiateFilter(conn, net);
+ if (err) {
+ close(tapfd);
+ tapfd = -1;
+ }
+ }
+ }
+
cleanup:
VIR_FREE(brname);

@@ -3301,6 +3323,7 @@ int qemudBuildCommandLine(virConnectPtr
char domid[50];
char *cpu;
char *smp;
+ int last_good_net = -1;

uname_normalize(&ut);

@@ -3955,6 +3978,7 @@ int qemudBuildCommandLine(virConnectPtr
goto error;
ADD_ARG(host);
}
+ last_good_net = i;
}
}

@@ -4415,6 +4439,11 @@ int qemudBuildCommandLine(virConnectPtr
VIR_FREE((qenv)[i]);
VIR_FREE(qenv);
}
+ for (i = 0; i <= last_good_net; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+ }
return -1;

#undef ADD_ARG
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -83,6 +83,7 @@
#include "xml.h"
#include "cpu/cpu.h"
#include "macvtap.h"
+#include "nwfilter/nwfilter_gentech_driver.h"


#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3041,6 +3042,13 @@ static void qemudShutdownVMDaemon(struct
* reporting so we don't squash a legit error. */
orig_err = virSaveLastError();

+ def = vm->def;
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+ }
+
if (driver->macFilter) {
def = vm->def;
for (i = 0 ; i < def->nnets ; i++) {
@@ -7052,6 +7060,9 @@ qemudDomainDetachNetDevice(struct qemud_
}
}

+ if ((detach->ifname) && (detach->filter))
+ virNWFilterTeardownFilter(detach);
+
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
vm->def->nets + i + 1,
@@ -9687,8 +9698,24 @@ static virStateDriver qemuStateDriver =
.active = qemudActive,
};

+static int
+qemudVMFilterRebuild(virConnectPtr conn,
+ virHashIterator iter, void *data)
+{
+ (void)conn;
+ virHashForEach(qemu_driver->domains.objs, iter, data);
+ return 0;
+}
+
+
+static virNWFilterCallbackDriver qemuCallbackDriver = {
+ .name = "QEMU",
+ .vmFilterRebuild = qemudVMFilterRebuild,
+};
+
int qemuRegister(void) {
virRegisterDriver(&qemuDriver);
virRegisterStateDriver(&qemuStateDriver);
+ virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
return 0;
}
Daniel P. Berrange
2010-03-25 11:09:24 UTC
Permalink
Post by s***@us.ibm.com
Add support for Qemu to have firewall rules applied and removed on VM
startup and shutdown respectively. This patch also provides support for
the updating of a filter that causes all VMs that reference the filter
to have their ebtables/iptables rules updated.
---
src/qemu/qemu_conf.c | 29 +++++++++++++++++++++++++++++
src/qemu/qemu_driver.c | 27 +++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -83,6 +83,7 @@
#include "xml.h"
#include "cpu/cpu.h"
#include "macvtap.h"
+#include "nwfilter/nwfilter_gentech_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3041,6 +3042,13 @@ static void qemudShutdownVMDaemon(struct
* reporting so we don't squash a legit error. */
orig_err = virSaveLastError();
+ def = vm->def;
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+ }
+
I think we might also need to run this in qemudStartuVMDaemon() in
the 'cleanup' path taken when virExecDaemonize fails.
Post by s***@us.ibm.com
if (driver->macFilter) {
def = vm->def;
for (i = 0 ; i < def->nnets ; i++) {
@@ -7052,6 +7060,9 @@ qemudDomainDetachNetDevice(struct qemud_
}
}
+ if ((detach->ifname) && (detach->filter))
+ virNWFilterTeardownFilter(detach);
+
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
vm->def->nets + i + 1,
Also might need this in the cleanup path for qemudDomainAttachNetDevice
when it fails to hotplug

Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 14:02:38 UTC
Permalink
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
Add support for Qemu to have firewall rules applied and removed on VM
startup and shutdown respectively. This patch also provides support for
the updating of a filter that causes all VMs that reference the filter
to have their ebtables/iptables rules updated.
---
src/qemu/qemu_conf.c | 29 +++++++++++++++++++++++++++++
src/qemu/qemu_driver.c | 27 +++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -83,6 +83,7 @@
#include "xml.h"
#include "cpu/cpu.h"
#include "macvtap.h"
+#include "nwfilter/nwfilter_gentech_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3041,6 +3042,13 @@ static void qemudShutdownVMDaemon(struct
* reporting so we don't squash a legit error. */
orig_err = virSaveLastError();
+ def = vm->def;
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+ }
+
I think we might also need to run this in qemudStartuVMDaemon() in
the 'cleanup' path taken when virExecDaemonize fails.
Fixed. This and the above now calls a function qemuTearVMNWFilters() which
in turn calls qemuTearNWFilter();
Post by s***@us.ibm.com
if (driver->macFilter) {
def = vm->def;
for (i = 0 ; i < def->nnets ; i++) {
@@ -7052,6 +7060,9 @@ qemudDomainDetachNetDevice(struct qemud_
}
}
+ if ((detach->ifname) && (detach->filter))
+ virNWFilterTeardownFilter(detach);
+
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
vm->def->nets + i + 1,
Also might need this in the cleanup path for qemudDomainAttachNetDevice
when it fails to hotplug
Fixed. This and the above now calls qemuTearNWFilter().

Due to these and other changes I would like to post a 'v4' patch series
with an additional patch installing a couple of example filters.

Thanks and regards,
Stefan
Regards,
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Daniel P. Berrange
2010-03-25 14:18:25 UTC
Permalink
Post by Stefan Berger
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
Add support for Qemu to have firewall rules applied and removed on VM
startup and shutdown respectively. This patch also provides support
for
Post by s***@us.ibm.com
the updating of a filter that causes all VMs that reference the filter
to have their ebtables/iptables rules updated.
---
src/qemu/qemu_conf.c | 29 +++++++++++++++++++++++++++++
src/qemu/qemu_driver.c | 27 +++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -83,6 +83,7 @@
#include "xml.h"
#include "cpu/cpu.h"
#include "macvtap.h"
+#include "nwfilter/nwfilter_gentech_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3041,6 +3042,13 @@ static void qemudShutdownVMDaemon(struct
* reporting so we don't squash a legit error. */
orig_err = virSaveLastError();
+ def = vm->def;
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+ }
+
I think we might also need to run this in qemudStartuVMDaemon() in
the 'cleanup' path taken when virExecDaemonize fails.
Fixed. This and the above now calls a function qemuTearVMNWFilters() which
in turn calls qemuTearNWFilter();
Post by s***@us.ibm.com
if (driver->macFilter) {
def = vm->def;
for (i = 0 ; i < def->nnets ; i++) {
@@ -7052,6 +7060,9 @@ qemudDomainDetachNetDevice(struct qemud_
}
}
+ if ((detach->ifname) && (detach->filter))
+ virNWFilterTeardownFilter(detach);
+
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
vm->def->nets + i + 1,
Also might need this in the cleanup path for qemudDomainAttachNetDevice
when it fails to hotplug
Fixed. This and the above now calls qemuTearNWFilter().
Due to these and other changes I would like to post a 'v4' patch series
with an additional patch installing a couple of example filters.
That's fine with me - BTW, i notice in the nwfilter_conf.c some of the
objects are called 'FilterPool' instead of just 'Filter' - is that
delibrate, or a cut +paste mistake from copying existing storage_conf.c
code.


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 14:33:18 UTC
Permalink
Please respond to "Daniel P. Berrange"
Post by Stefan Berger
Due to these and other changes I would like to post a 'v4' patch series
with an additional patch installing a couple of example filters.
That's fine with me - BTW, i notice in the nwfilter_conf.c some of the
objects are called 'FilterPool' instead of just 'Filter' - is that
delibrate, or a cut +paste mistake from copying existing storage_conf.c
code.
Some of that is (still) deliberate because from the perspective of the
driver I
regard the collection of filters as a pool and within that pool I can
search
for filters by for example UUID or name and that's where function names
like
virNWFilterPoolObjFindByUUID/ByName stem from. So, yes, it's derived from
storage_conf.c but to me the naming of those functions still makes
sense...

Stefan
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
s***@us.ibm.com
2010-03-23 14:54:17 UTC
Permalink
This patch implements the core driver and provides
- management functionality for managing the filter XMLs
- compiling the internal filter representation into ebtables rules
- applying ebtables rules on a network (tap,macvtap) interface
- tearing down ebtables rules that were applied on behalf of an
interface
- updating of filters while VMs are running and causing the firewalls to
be rebuilt
- other bits and pieces


Signed-off-by: Stefan Berger <***@us.ibm.com>

---
daemon/libvirtd.c | 7
include/libvirt/virterror.h | 7
python/generator.py | 2
src/conf/nwfilter_conf.c | 2222 ++++++++++++++++++++++++++++++
src/conf/nwfilter_conf.h | 457 ++++++
src/conf/nwfilter_params.c | 318 ++++
src/conf/nwfilter_params.h | 53
src/datatypes.c | 142 +
src/datatypes.h | 32
src/nwfilter/nwfilter_driver.c | 416 +++++
src/nwfilter/nwfilter_driver.h | 36
src/nwfilter/nwfilter_ebiptables_driver.c | 1381 ++++++++++++++++++
src/nwfilter/nwfilter_ebiptables_driver.h | 41
src/nwfilter/nwfilter_gentech_driver.c | 656 ++++++++
src/nwfilter/nwfilter_gentech_driver.h | 52
src/util/virterror.c | 27
16 files changed, 5848 insertions(+), 1 deletion(-)

Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -0,0 +1,2222 @@
+/*
+ * nwfilter_conf.c: network filter XML processing
+ * (derived from storage_conf.c)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <net/ethernet.h>
+
+#include "internal.h"
+
+#include "uuid.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "nwfilter_params.h"
+#include "nwfilter_conf.h"
+#include "domain_conf.h"
+#include "nwfilter/nwfilter_gentech_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#define virNWFilterError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NWFILTER, code, __FILE__,\
+ __FUNCTION__, __LINE__, fmt)
+
+VIR_ENUM_IMPL(virNWFilterRuleAction, VIR_NWFILTER_RULE_ACTION_LAST,
+ "drop",
+ "accept");
+
+VIR_ENUM_IMPL(virNWFilterJumpTarget, VIR_NWFILTER_RULE_ACTION_LAST,
+ "DROP",
+ "ACCEPT");
+
+VIR_ENUM_IMPL(virNWFilterRuleDirection, VIR_NWFILTER_RULE_DIRECTION_LAST,
+ "in",
+ "out",
+ "inout");
+
+VIR_ENUM_IMPL(virNWFilterChainPolicy, VIR_NWFILTER_CHAIN_POLICY_LAST,
+ "ACCEPT",
+ "DROP");
+
+VIR_ENUM_IMPL(virNWFilterEbtablesTable, VIR_NWFILTER_EBTABLES_TABLE_LAST,
+ "filter",
+ "nat",
+ "broute");
+
+VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
+ "root",
+ "arp",
+ "ipv4");
+
+
+/*
+ * a map entry for a simple static int-to-string map
+ */
+struct int_map {
+ int32_t attr;
+ const char *val;
+};
+
+
+/*
+ * only one filter update allowed
+ */
+static virMutex updateMutex;
+
+static void
+virNWFilterLockFilterUpdates(void) {
+ virMutexLock(&updateMutex);
+}
+
+static void
+virNWFilterUnlockFilterUpdates(void) {
+ virMutexUnlock(&updateMutex);
+}
+
+
+/*
+ * attribute names for the rules XML
+ */
+static const char srcmacaddr_str[] = "srcmacaddr";
+static const char srcmacmask_str[] = "srcmacmask";
+static const char dstmacaddr_str[] = "dstmacaddr";
+static const char dstmacmask_str[] = "dstmacmask";
+static const char arpsrcmacaddr_str[]= "arpsrcmacaddr";
+static const char arpdstmacaddr_str[]= "arpdstmacaddr";
+static const char arpsrcipaddr_str[] = "arpsrcipaddr";
+static const char arpdstipaddr_str[] = "arpdstipaddr";
+static const char srcipaddr_str[] = "srcipaddr";
+static const char srcipmask_str[] = "srcipmask";
+static const char dstipaddr_str[] = "dstipaddr";
+static const char dstipmask_str[] = "dstipmask";
+static const char srcportstart_str[] = "srcportstart";
+static const char srcportend_str[] = "srcportend";
+static const char dstportstart_str[] = "dstportstart";
+static const char dstportend_str[] = "dstportend";
+static const char dscp_str[] = "dscp";
+
+#define SRCMACADDR srcmacaddr_str
+#define SRCMACMASK srcmacmask_str
+#define DSTMACADDR dstmacaddr_str
+#define DSTMACMASK dstmacmask_str
+#define ARPSRCMACADDR arpsrcmacaddr_str
+#define ARPDSTMACADDR arpdstmacaddr_str
+#define ARPSRCIPADDR arpsrcipaddr_str
+#define ARPDSTIPADDR arpdstipaddr_str
+#define SRCIPADDR srcipaddr_str
+#define SRCIPMASK srcipmask_str
+#define DSTIPADDR dstipaddr_str
+#define DSTIPMASK dstipmask_str
+#define SRCPORTSTART srcportstart_str
+#define SRCPORTEND srcportend_str
+#define DSTPORTSTART dstportstart_str
+#define DSTPORTEND dstportend_str
+#define DSCP dscp_str
+
+
+/**
+ * intMapGetByInt:
+ * @intmap: Pointer to int-to-string map
+ * @attr: The attribute to look up
+ * @res: Pointer to string pointer for result
+ *
+ * Returns 1 if value was found with result returned, 0 otherwise.
+ *
+ * lookup a map entry given the integer.
+ */
+static bool
+intMapGetByInt(const struct int_map *intmap, int32_t attr, const char **res)
+{
+ int i = 0;
+ bool found = 0;
+ while (intmap[i].val && !found) {
+ if (intmap[i].attr == attr) {
+ *res = intmap[i].val;
+ found = 1;
+ }
+ i++;
+ }
+ return found;
+}
+
+
+/**
+ * intMapGetByString:
+ * @intmap: Pointer to int-to-string map
+ * @str: Pointer to string for which to find the entry
+ * @casecmp : Whether to ignore case when doing string matching
+ * @result: Pointer to int for result
+ *
+ * Returns 0 if no entry was found, 1 otherwise.
+ *
+ * Do a lookup in the map trying to find an integer key using the string
+ * value. Returns 1 if entry was found with result returned, 0 otherwise.
+ */
+static bool
+intMapGetByString(const struct int_map *intmap, const char *str, int casecmp,
+ int32_t *result)
+{
+ int i = 0;
+ bool found = 0;
+ while (intmap[i].val && !found) {
+ if ( (casecmp && STRCASEEQ(intmap[i].val, str)) ||
+ STREQ (intmap[i].val, str) ) {
+ *result = intmap[i].attr;
+ found = 1;
+ }
+ i++;
+ }
+ return found;
+}
+
+
+void
+virNWFilterRuleDefFree(virNWFilterRuleDefPtr def) {
+ int i;
+ if (!def)
+ return;
+
+ for (i = 0; i < def->nvars; i++)
+ VIR_FREE(def->vars[i]);
+
+ VIR_FREE(def->vars);
+
+ VIR_FREE(def);
+}
+
+
+static void
+virNWFilterIncludeDefFree(virNWFilterIncludeDefPtr inc) {
+ if (!inc)
+ return;
+ virNWFilterHashTableFree(inc->params);
+ VIR_FREE(inc->filterref);
+ VIR_FREE(inc);
+}
+
+
+static void
+virNWFilterEntryFree(virNWFilterEntryPtr entry) {
+ if (!entry)
+ return;
+
+ virNWFilterRuleDefFree(entry->rule);
+ virNWFilterIncludeDefFree(entry->include);
+ VIR_FREE(entry);
+}
+
+
+void
+virNWFilterDefFree(virNWFilterDefPtr def) {
+ int i;
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+
+ for (i = 0; i < def->nentries; i++)
+ virNWFilterEntryFree(def->filterEntries[i]);
+
+ VIR_FREE(def->filterEntries);
+
+ VIR_FREE(def);
+}
+
+
+void
+virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj) {
+ if (!obj)
+ return;
+
+ virNWFilterDefFree(obj->def);
+ virNWFilterDefFree(obj->newDef);
+
+ VIR_FREE(obj->configFile);
+
+ virMutexDestroy(&obj->lock);
+
+ VIR_FREE(obj);
+}
+
+
+void
+virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools)
+{
+ unsigned int i;
+ for (i = 0 ; i < pools->count ; i++)
+ virNWFilterPoolObjFree(pools->objs[i]);
+ VIR_FREE(pools->objs);
+ pools->count = 0;
+}
+
+
+static int
+virNWFilterRuleDefAddVar(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virNWFilterRuleDefPtr nwf,
+ nwItemDesc *item,
+ const char *var)
+{
+ int i = 0;
+
+ if (nwf->vars) {
+ for (i = 0; i < nwf->nvars; i++)
+ if (STREQ(nwf->vars[i], var)) {
+ item->var = nwf->vars[i];
+ return 0;
+ }
+ }
+
+ if (VIR_REALLOC_N(nwf->vars, nwf->nvars+1) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ nwf->vars[nwf->nvars] = strdup(var);
+
+ if (!nwf->vars[nwf->nvars]) {
+ virReportOOMError();
+ return 1;
+ }
+
+ item->var = nwf->vars[nwf->nvars++];
+
+ return 0;
+}
+
+
+void
+virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+ virNWFilterPoolObjPtr pool)
+{
+ unsigned int i;
+
+ virNWFilterPoolObjUnlock(pool);
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (pools->objs[i] == pool) {
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ virNWFilterPoolObjFree(pools->objs[i]);
+
+ if (i < (pools->count - 1))
+ memmove(pools->objs + i, pools->objs + i + 1,
+ sizeof(*(pools->objs)) * (pools->count - (i + 1)));
+
+ if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ pools->count--;
+
+ break;
+ }
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+}
+
+
+
+typedef bool (*valueValidator)(enum attrDatatype datatype, void *valptr,
+ virNWFilterRuleDefPtr nwf);
+typedef bool (*valueFormatter)(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf);
+
+typedef struct _virXMLAttr2Struct virXMLAttr2Struct;
+struct _virXMLAttr2Struct
+{
+ const char *name; // attribute name
+ enum attrDatatype datatype;
+ int dataIdx; // offset of the hasXYZ boolean
+ valueValidator validator; // beyond-standard checkers
+ valueFormatter formatter; // beyond-standard formatter
+};
+
+
+static const struct int_map macProtoMap[] = {
+ {
+ .attr = ETHERTYPE_ARP,
+ .val = "arp",
+ }, {
+ .attr = ETHERTYPE_IP,
+ .val = "ipv4",
+ }, {
+ .val = NULL,
+ }
+};
+
+
+static bool
+checkMacProtocolID(enum attrDatatype datatype, void *value,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(macProtoMap, (char *)value, 1, &res) == 0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT16) {
+ if (intMapGetByInt(macProtoMap,
+ (int32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.ethHdrFilter.dataProtocolID.u.u16 = res;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static bool
+macProtocolIDFormatter(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(macProtoMap,
+ nwf->p.ethHdrFilter.dataProtocolID.u.u16,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* generic function to check for a valid (ipv4,ipv6, mac) mask
+ * A mask is valid of there is a sequence of 1's followed by a sequence
+ * of 0s or only 1s or only 0s
+ */
+static bool
+checkValidMask(unsigned char *data, int len)
+{
+ uint32_t idx = 0;
+ uint8_t mask = 0x80;
+ int checkones = 1;
+
+ while ((idx >> 3) < len) {
+ if (checkones) {
+ if (!(data[idx>>3] & mask))
+ checkones = 0;
+ } else {
+ if ((data[idx>>3] & mask))
+ return 0;
+ }
+
+ idx++;
+ mask >>= 1;
+ if (!mask)
+ mask = 0x80;
+ }
+ return 1;
+}
+
+
+/* check for a valid IPv4 mask */
+static bool
+checkIPv4Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ return checkValidMask(maskptr, 4);
+}
+
+
+static bool
+checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
+ void *macMask,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ return checkValidMask((unsigned char *)macMask, 6);
+}
+
+
+static int getMaskNumBits(const unsigned char *mask, int len) {
+ int i = 0;
+ while (i < (len << 3)) {
+ if (!(mask[i>>3] & (0x80 >> (i & 3))))
+ break;
+ i++;
+ }
+ return i;
+}
+
+/*
+ * supported arp opcode -- see 'ebtables -h arp' for the naming
+ */
+static const struct int_map arpOpcodeMap[] = {
+ {
+ .attr = 1,
+ .val = "Request",
+ } , {
+ .attr = 2,
+ .val = "Reply",
+ } , {
+ .attr = 3,
+ .val = "Request_Reverse",
+ } , {
+ .attr = 4,
+ .val = "Reply_Reverse",
+ } , {
+ .attr = 5,
+ .val = "DRARP_Request",
+ } , {
+ .attr = 6,
+ .val = "DRARP_Reply",
+ } , {
+ .attr = 7,
+ .val = "DRARP_Error",
+ } , {
+ .attr = 8,
+ .val = "InARP_Request",
+ } , {
+ .attr = 9,
+ .val = "ARP_NAK",
+ } , {
+ .val = NULL,
+ }
+};
+
+
+static bool
+arpOpcodeValidator(enum attrDatatype datatype,
+ void *value,
+ virNWFilterRuleDefPtr nwf)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(arpOpcodeMap, (char *)value, 1, &res) == 0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT16) {
+ if (intMapGetByInt(arpOpcodeMap,
+ (uint32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.arpHdrFilter.dataOpcode.u.u16 = res;
+ nwf->p.arpHdrFilter.dataOpcode.datatype = DATATYPE_UINT16;
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool
+arpOpcodeFormatter(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(arpOpcodeMap,
+ nwf->p.arpHdrFilter.dataOpcode.u.u16,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+static const struct int_map ipProtoMap[] = {
+ {
+ .attr = IPPROTO_TCP,
+ .val = "tcp",
+ } , {
+ .attr = IPPROTO_UDP,
+ .val = "udp",
+ } , {
+ .attr = IPPROTO_ICMP,
+ .val = "icmp",
+ } , {
+ .attr = IPPROTO_IGMP,
+ .val = "igmp",
+#ifdef IPPROTO_SCTP
+ } , {
+ .attr = IPPROTO_SCTP,
+ .val = "sctp",
+#endif
+ } , {
+ .val = NULL,
+ }
+};
+
+
+static bool checkIPProtocolID(enum attrDatatype datatype,
+ void *value,
+ virNWFilterRuleDefPtr nwf)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(ipProtoMap, (char *)value, 1, &res) == 0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT8) {
+ // may just accept what user provides and not test...
+ if (intMapGetByInt(ipProtoMap,
+ (uint32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8 = res;
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype = DATATYPE_UINT8;
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool
+formatIPProtocolID(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(ipProtoMap,
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool
+dscpValidator(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ uint8_t dscp = *(uint16_t *)val;
+ if (dscp > 63)
+ return 0;
+ return 1;
+}
+
+#define COMMON_MAC_PROPS(STRUCT) \
+ {\
+ .name = SRCMACADDR,\
+ .datatype = DATATYPE_MACADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef,p.STRUCT.ethHdr.dataSrcMACAddr),\
+ },\
+ {\
+ .name = SRCMACMASK,\
+ .datatype = DATATYPE_MACMASK,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ethHdr.dataSrcMACMask),\
+ },\
+ {\
+ .name = DSTMACADDR,\
+ .datatype = DATATYPE_MACADDR,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ethHdr.dataDstMACAddr),\
+ },\
+ {\
+ .name = DSTMACMASK,\
+ .datatype = DATATYPE_MACMASK,\
+ .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ethHdr.dataDstMACMask),\
+ }
+
+
+static const virXMLAttr2Struct macAttributes[] = {
+ COMMON_MAC_PROPS(ethHdrFilter),
+ {
+ .name = "protocolid",
+ .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataProtocolID),
+ .validator= checkMacProtocolID,
+ .formatter= macProtocolIDFormatter,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const virXMLAttr2Struct arpAttributes[] = {
+ COMMON_MAC_PROPS(arpHdrFilter),
+ {
+ .name = "hwtype",
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataHWType),
+ }, {
+ .name = "protocoltype",
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataProtocolType),
+ }, {
+ .name = "opcode",
+ .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataOpcode),
+ .validator= arpOpcodeValidator,
+ .formatter= arpOpcodeFormatter,
+ }, {
+ .name = ARPSRCMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPSrcMACAddr),
+ }, {
+ .name = ARPDSTMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPDstMACAddr),
+ }, {
+ .name = ARPSRCIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPSrcIPAddr),
+ }, {
+ .name = ARPDSTIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPDstIPAddr),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const virXMLAttr2Struct ipAttributes[] = {
+ COMMON_MAC_PROPS(ipHdrFilter),
+ {
+ .name = "version",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataIPVersion),
+ },
+ {
+ .name = SRCIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcIPAddr),
+ },
+ {
+ .name = DSTIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstIPAddr),
+ },
+ {
+ .name = SRCIPMASK,
+ .datatype = DATATYPE_IPMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcIPMask),
+ },
+ {
+ .name = DSTIPMASK,
+ .datatype = DATATYPE_IPMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstIPMask),
+ },
+ {
+ .name = "protocol",
+ .datatype = DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataProtocolID),
+ .validator= checkIPProtocolID,
+ .formatter= formatIPProtocolID,
+ },
+ {
+ .name = SRCPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortStart),
+ },
+ {
+ .name = SRCPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortEnd),
+ },
+ {
+ .name = DSTPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortStart),
+ },
+ {
+ .name = DSTPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortEnd),
+ },
+ {
+ .name = DSCP,
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDSCP),
+ .validator = dscpValidator,
+ },
+ {
+ .name = NULL,
+ }
+};
+
+
+typedef struct _virAttributes virAttributes;
+struct _virAttributes {
+ const char *id;
+ const virXMLAttr2Struct *att;
+ enum virNWFilterRuleProtocolType prtclType;
+};
+
+
+static const virAttributes virAttr[] = {
+ {
+ .id = "arp",
+ .att = arpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ARP,
+ }, {
+ .id = "mac",
+ .att = macAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_MAC,
+ }, {
+ .id = "ip",
+ .att = ipAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IP,
+ }, {
+ .id = NULL,
+ }
+};
+
+
+static bool
+virNWMACAddressParser(const char *input,
+ nwMACAddressPtr output)
+{
+ if (virParseMacAddr(input, &output->addr[0]) == 0)
+ return 1;
+ return 0;
+}
+
+
+static bool
+virNWIPv4AddressParser(const char *input,
+ nwIPAddressPtr output)
+{
+ int i;
+ char *endptr;
+ const char *n = input;
+ long int d;
+
+ for (i = 0; i < 4; i++) {
+ d = strtol(n, &endptr, 10);
+ if (d < 0 || d > 255 ||
+ (endptr - n > 3 ) ||
+ (i <= 2 && *endptr != '.' ) ||
+ (i == 3 && *endptr != '\0'))
+ return 0;
+ output->addr.ipv4Addr[i] = (unsigned char)d;
+ n = endptr + 1;
+ }
+ return 1;
+}
+
+
+static int
+virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
+ xmlNodePtr node,
+ virNWFilterRuleDefPtr nwf,
+ const virXMLAttr2Struct *att)
+{
+ int rc = 0;
+ int idx = 0;
+ char *prop;
+ int found = 0;
+ enum attrDatatype datatype, att_datatypes;
+ enum virNWFilterEntryItemFlags *flags ,match_flag = 0, flags_set = 0;
+ nwItemDesc *item;
+ int int_val;
+ void *data_ptr, *storage_ptr;
+ valueValidator validator;
+ char *match = virXMLPropString(node, "match");
+ nwIPAddress ipaddr;
+
+ if (match && STREQ(match, "no"))
+ match_flag = NWFILTER_ENTRY_ITEM_FLAG_IS_NEG;
+ VIR_FREE(match);
+ match = NULL;
+
+ while (att[idx].name != NULL && rc == 0) {
+ prop = virXMLPropString(node, att[idx].name);
+
+ item = (nwItemDesc *)((char *)nwf + att[idx].dataIdx);
+ flags = &item->flags;
+ flags_set = match_flag;
+
+ if (prop) {
+ found = 0;
+
+ validator = NULL;
+
+ if (STRPREFIX(prop, "$")) {
+ flags_set |= NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR;
+ storage_ptr = NULL;
+
+ if (virNWFilterRuleDefAddVar(conn,
+ nwf,
+ item,
+ &prop[1]))
+ rc = -1;
+ found = 1;
+ }
+
+ datatype = 1;
+
+ att_datatypes = att[idx].datatype;
+
+ while (datatype <= DATATYPE_LAST && found == 0 && rc == 0) {
+ if ((att_datatypes & datatype)) {
+
+ att_datatypes ^= datatype;
+
+ validator = att[idx].validator;
+
+ switch (datatype) {
+
+ case DATATYPE_UINT8:
+ storage_ptr = &item->u.u8;
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 0xff) {
+ if (!validator)
+ *(uint8_t *)storage_ptr = int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ break;
+
+ case DATATYPE_UINT16:
+ storage_ptr = &item->u.u16;
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 0xffff) {
+ if (!validator)
+ *(uint16_t *)storage_ptr = int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ break;
+
+ case DATATYPE_IPADDR:
+ storage_ptr = &item->u.ipaddr;
+ if (!virNWIPv4AddressParser(prop,
+ (nwIPAddressPtr)storage_ptr)) {
+ rc = -1;
+ }
+ found = 1;
+ break;
+
+ case DATATYPE_IPMASK:
+ storage_ptr = &item->u.u8;
+ if (!virNWIPv4AddressParser(prop, &ipaddr)) {
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 32) {
+ if (!validator)
+ *(uint8_t *)storage_ptr =
+ (uint8_t)int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ } else {
+ if (checkIPv4Mask(datatype,
+ ipaddr.addr.ipv4Addr, nwf))
+ *(uint8_t *)storage_ptr =
+ getMaskNumBits(ipaddr.addr.ipv4Addr,
+ sizeof(ipaddr.addr.ipv4Addr));
+ else
+ rc = -1;
+ found = 1;
+ }
+ break;
+
+ case DATATYPE_MACADDR:
+ storage_ptr = &item->u.macaddr;
+ if (!virNWMACAddressParser(prop,
+ (nwMACAddressPtr)storage_ptr)) {
+ rc = -1;
+ }
+ found = 1;
+ break;
+
+ case DATATYPE_MACMASK:
+ validator = checkMACMask;
+ storage_ptr = &item->u.macaddr;
+ if (!virNWMACAddressParser(prop,
+ (nwMACAddressPtr)storage_ptr)) {
+ rc = -1;
+ }
+ data_ptr = storage_ptr;
+ found = 1;
+ break;
+
+ case DATATYPE_STRING:
+ if (!validator) {
+ // not supported
+ rc = -1;
+ break;
+ }
+ data_ptr = prop;
+ found = 1;
+ break;
+
+ case DATATYPE_LAST:
+ default:
+ break;
+ }
+ }
+
+ if (rc != 0 && att_datatypes != 0) {
+ rc = 0;
+ found = 0;
+ }
+
+ datatype <<= 1;
+ } /* while */
+
+ if (found == 1 && rc == 0) {
+ *flags = NWFILTER_ENTRY_ITEM_FLAG_EXISTS | flags_set;
+ item->datatype = datatype >> 1;
+ if (validator) {
+ if (!validator(datatype >> 1, data_ptr, nwf)) {
+ rc = -1;
+ *flags = 0;
+ }
+ }
+ }
+
+ if (!found || rc) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("%s has illegal value %s"),
+ att[idx].name, prop);
+ rc = -1;
+ }
+ VIR_FREE(prop);
+ }
+ idx++;
+ }
+
+ return rc;
+}
+
+
+
+
+static virNWFilterIncludeDefPtr
+virNWFilterIncludeParse(virConnectPtr conn,
+ xmlNodePtr cur)
+{
+ virNWFilterIncludeDefPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->filterref = virXMLPropString(cur, "filter");
+ if (!ret->filterref) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires action attribute"));
+ goto err_exit;
+ }
+
+ ret->params = virNWFilterParseParamAttributes(cur);
+ if (!ret->params)
+ goto err_exit;
+
+cleanup:
+ return ret;
+
+err_exit:
+ virNWFilterIncludeDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+
+static void
+virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule)
+{
+#define COPY_NEG_SIGN(A, B) \
+ (A).flags = ((A).flags & ~NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) | \
+ ((B).flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG);
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ COPY_NEG_SIGN(rule->p.ethHdrFilter.ethHdr.dataSrcMACMask,
+ rule->p.ethHdrFilter.ethHdr.dataSrcMACAddr);
+ COPY_NEG_SIGN(rule->p.ethHdrFilter.ethHdr.dataDstMACMask,
+ rule->p.ethHdrFilter.ethHdr.dataDstMACAddr);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcIPMask,
+ rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr);
+ COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataDstIPMask,
+ rule->p.ipHdrFilter.ipHdr.dataDstIPAddr);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ break;
+ }
+
+#undef COPY_NEG_SIGN
+}
+
+
+static virNWFilterRuleDefPtr
+virNWFilterRuleParse(virConnectPtr conn,
+ xmlNodePtr node)
+{
+ char *action;
+ char *direction;
+ char *prio;
+ int found;
+ int found_i;
+ unsigned int priority;
+
+ xmlNodePtr cur;
+ virNWFilterRuleDefPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ action = virXMLPropString(node, "action");
+ direction = virXMLPropString(node, "direction");
+ prio = virXMLPropString(node, "priority");
+
+ if (!action) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires action attribute"));
+ goto err_exit;
+ }
+
+ if ((ret->action = virNWFilterRuleActionTypeFromString(action)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("unknown rule action attribute value"));
+ goto err_exit;
+ }
+
+ if (!direction) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires direction attribute"));
+ goto err_exit;
+ }
+
+ if ((ret->tt = virNWFilterRuleDirectionTypeFromString(direction)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("unknown rule direction attribute value"));
+ goto err_exit;
+ }
+
+ ret->priority = MAX_RULE_PRIORITY / 2;
+
+ if (prio) {
+ if (sscanf(prio, "%d", (int *)&priority) == 1) {
+ if ((int)priority >= 0 && priority <= MAX_RULE_PRIORITY)
+ ret->priority = priority;
+ }
+ }
+
+ cur = node->children;
+
+ found = 0;
+
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ int i = 0;
+ while (1) {
+ if (found)
+ i = found_i;
+
+ if (xmlStrEqual(cur->name, BAD_CAST virAttr[i].id)) {
+
+ found_i = i;
+ found = 1;
+ ret->prtclType = virAttr[i].prtclType;
+
+ if (virNWFilterRuleDetailsParse(conn,
+ cur,
+ ret,
+ virAttr[i].att) < 0) {
+ /* we ignore malformed rules
+ goto err_exit;
+ */
+ }
+ break;
+ }
+ if (!found) {
+ i++;
+ if (!virAttr[i].id)
+ break;
+ } else
+ break;
+ }
+ }
+
+ cur = cur->next;
+ }
+
+ virNWFilterRuleDefFixup(ret);
+
+cleanup:
+ VIR_FREE(prio);
+ VIR_FREE(action);
+ VIR_FREE(direction);
+
+ return ret;
+
+err_exit:
+ virNWFilterRuleDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParseXML(virConnectPtr conn,
+ xmlXPathContextPtr ctxt) {
+ virNWFilterDefPtr ret;
+ xmlNodePtr curr = ctxt->node;
+ char *uuid = NULL;
+ char *chain = NULL;
+ virNWFilterEntryPtr entry;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->name = virXPathString("string(./@name)", ctxt);
+ if (!ret->name) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("filter has no name"));
+ goto cleanup;
+ }
+
+ ret->chainsuffix = VIR_NWFILTER_CHAINSUFFIX_ROOT;
+ chain = virXPathString("string(./@chain)", ctxt);
+ if (chain) {
+ if ((ret->chainsuffix =
+ virNWFilterChainSuffixTypeFromString(chain)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown chain suffix '%s'"), chain);
+ goto cleanup;
+ }
+ }
+
+ uuid = virXPathString("string(./uuid)", ctxt);
+ if (uuid == NULL) {
+ if (virUUIDGenerate(ret->uuid) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to generate uuid"));
+ goto cleanup;
+ }
+ } else {
+ if (virUUIDParse(uuid, ret->uuid) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("malformed uuid element"));
+ goto cleanup;
+ }
+ VIR_FREE(uuid);
+ }
+
+ curr = curr->children;
+
+ while (curr != NULL) {
+ if (curr->type == XML_ELEMENT_NODE) {
+ if (VIR_ALLOC(entry) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* ignore malformed rule and include elements */
+ if (xmlStrEqual(curr->name, BAD_CAST "rule"))
+ entry->rule = virNWFilterRuleParse(conn, curr);
+ else if (xmlStrEqual(curr->name, BAD_CAST "filterref"))
+ entry->include = virNWFilterIncludeParse(conn, curr);
+
+ if (entry->rule || entry->include) {
+ if (VIR_REALLOC_N(ret->filterEntries, ret->nentries+1) < 0) {
+ VIR_FREE(entry);
+ virReportOOMError();
+ goto cleanup;
+ }
+ ret->filterEntries[ret->nentries++] = entry;
+ } else
+ VIR_FREE(entry);
+ }
+ curr = curr->next;
+ }
+
+ VIR_FREE(chain);
+
+ return ret;
+
+ cleanup:
+ VIR_FREE(chain);
+ VIR_FREE(uuid);
+ return NULL;
+}
+
+
+/* Called from SAX on parsing errors in the XML. */
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+ if (ctxt) {
+ virConnectPtr conn = ctxt->_private;
+
+ if (conn &&
+ conn->err.code == VIR_ERR_NONE &&
+ ctxt->lastError.level == XML_ERR_FATAL &&
+ ctxt->lastError.message != NULL) {
+ virNWFilterReportError(conn, VIR_ERR_XML_DETAIL,
+ _("at line %d: %s"),
+ ctxt->lastError.line,
+ ctxt->lastError.message);
+ }
+ }
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root) {
+ xmlXPathContextPtr ctxt = NULL;
+ virNWFilterDefPtr def = NULL;
+
+ if (STRNEQ((const char *)root->name, "filter")) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s",
+ _("unknown root element for nw filter pool"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virNWFilterDefParseXML(conn, ctxt);
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParse(virConnectPtr conn,
+ const char *xmlStr,
+ const char *filename) {
+ virNWFilterDefPtr ret = NULL;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr node = NULL;
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+ pctxt->_private = conn;
+
+ if (conn) virResetError (&conn->err);
+ if (filename) {
+ xml = xmlCtxtReadFile (pctxt, filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ } else {
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
+ "nwfilter.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ }
+
+ if (!xml) {
+ if (conn && conn->err.code == VIR_ERR_NONE)
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s",_("failed to parse xml document"));
+ goto cleanup;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing root element"));
+ goto cleanup;
+ }
+
+ ret = virNWFilterDefParseNode(conn, xml, node);
+
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc(xml);
+
+ return ret;
+
+ cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc(xml);
+ return NULL;
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseString(virConnectPtr conn,
+ const char *xmlStr)
+{
+ return virNWFilterDefParse(conn, xmlStr, NULL);
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseFile(virConnectPtr conn,
+ const char *filename)
+{
+ return virNWFilterDefParse(conn, NULL, filename);
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+ const unsigned char *uuid)
+{
+ unsigned int i;
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return pools->objs[i];
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+
+ return NULL;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+ const char *name)
+{
+ unsigned int i;
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (STREQ(pools->objs[i]->def->name, name))
+ return pools->objs[i];
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+
+ return NULL;
+}
+
+
+int virNWFilterSaveXML(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def,
+ const char *xml)
+{
+ char *configFile = NULL;
+ int fd = -1, ret = -1;
+ size_t towrite;
+ int err;
+
+ if ((configFile = virNWFilterConfigFile(conn, configDir, def->name)) == NULL)
+ goto cleanup;
+
+ if ((err = virFileMakePath(configDir))) {
+ virReportSystemError(err,
+ _("cannot create config directory '%s'"),
+ configDir);
+ goto cleanup;
+ }
+
+ if ((fd = open(configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virReportSystemError(errno,
+ _("cannot create config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) < 0) {
+ virReportSystemError(errno,
+ _("cannot write config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virReportSystemError(errno,
+ _("cannot save config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+
+ VIR_FREE(configFile);
+
+ return ret;
+}
+
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def)
+{
+ int ret = -1;
+ char *xml;
+
+ if (!(xml = virNWFilterDefFormat(conn, def)))
+ goto cleanup;
+
+ if (virNWFilterSaveXML(conn, configDir, def, xml))
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(xml);
+ return ret;
+}
+
+
+static int
+_virNWFilterDefLoopDetect(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def,
+ const char *filtername)
+{
+ int rc = 0;
+ int i;
+ virNWFilterEntryPtr entry;
+ virNWFilterPoolObjPtr obj;
+
+ if (!def)
+ return 0;
+
+ for (i = 0; i < def->nentries; i++) {
+ entry = def->filterEntries[i];
+ if (entry->include) {
+
+ if (STREQ(filtername, entry->include->filterref)) {
+ rc = 1;
+ break;
+ }
+
+ obj = virNWFilterPoolObjFindByName(pools,
+ entry->include->filterref);
+ if (obj) {
+ rc = _virNWFilterDefLoopDetect(conn,
+ pools,
+ obj->def, filtername);
+
+ virNWFilterPoolObjUnlock(obj);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * virNWFilterDefLoopDetect:
+ * @conn: pointer to virConnect object
+ * @pools : the pools to search
+ * @def : the filter definiton that may add a loop and is to be tested
+ *
+ * Detect a loop introduced through the filters being able to
+ * reference each other.
+ *
+ * Returns 0 in case no loop was detected, 1 otherwise.
+ */
+static int
+virNWFilterDefLoopDetect(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def)
+{
+ return _virNWFilterDefLoopDetect(conn, pools, def, def->name);
+}
+
+int nCallbackDriver;
+#define MAX_CALLBACK_DRIVER 10
+static virNWFilterCallbackDriverPtr callbackDrvArray[MAX_CALLBACK_DRIVER];
+
+void
+virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr cbd)
+{
+ if (nCallbackDriver < MAX_CALLBACK_DRIVER) {
+ callbackDrvArray[nCallbackDriver++] = cbd;
+ }
+}
+
+
+struct cbStruct {
+ virConnectPtr conn;
+ int doUpdate;
+ int err;
+};
+
+static void
+virNWFilterDomainFWUpdateCB(void *payload,
+ const char *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainObjPtr obj = payload;
+ virDomainDefPtr vm = obj->def;
+ struct cbStruct *cb = data;
+ int i;
+
+ virDomainObjLock(obj);
+
+ if (virDomainObjIsActive(obj)) {
+ for (i = 0; i < vm->nnets; i++) {
+ virDomainNetDefPtr net = vm->nets[i];
+ if ((net->filter) && (net->ifname)) {
+ if (cb->doUpdate)
+ cb->err = virNWFilterUpdateInstantiateFilter(cb->conn,
+ net);
+ else
+ cb->err = virNWFilterRollbackUpdateFilter(cb->conn, net);
+ if (cb->err)
+ break;
+ }
+ }
+ }
+
+ virDomainObjUnlock(obj);
+}
+
+
+static int
+virNWFilterTriggerVMFilterRebuild(virConnectPtr conn)
+{
+ int i;
+ int err;
+ struct cbStruct cb = {
+ .conn = conn,
+ .err = 0,
+ .doUpdate = 1,
+ };
+
+ for (i = 0; i < nCallbackDriver; i++) {
+ callbackDrvArray[i]->vmFilterRebuild(conn,
+ virNWFilterDomainFWUpdateCB,
+ &cb);
+ }
+
+ err = cb.err;
+
+ if (err) {
+ cb.doUpdate = 0; // rollback
+ cb.err = 0;
+
+ for (i = 0; i < nCallbackDriver; i++)
+ callbackDrvArray[i]->vmFilterRebuild(conn,
+ virNWFilterDomainFWUpdateCB,
+ &cb);
+ }
+
+ return err;
+}
+
+
+int
+virNWFilterTestUnassignDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool)
+{
+ int rc = 0;
+
+ virNWFilterLockFilterUpdates();
+
+ pool->wantRemoved = 1;
+ // trigger the update on VMs referencing the filter
+ if (virNWFilterTriggerVMFilterRebuild(conn))
+ rc = 1;
+
+ pool->wantRemoved = 0;
+ virNWFilterUnlockFilterUpdates();
+ return rc;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjAssignDef(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def)
+{
+ virNWFilterPoolObjPtr pool;
+
+ if (virNWFilterDefLoopDetect(conn, pools, def)) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("filter would introduce loop"));
+ return NULL;
+ }
+
+ if ((pool = virNWFilterPoolObjFindByName(pools, def->name))) {
+ virNWFilterLockFilterUpdates();
+ pool->newDef = def;
+ // trigger the update on VMs referencing the filter
+ if (virNWFilterTriggerVMFilterRebuild(conn)) {
+ pool->newDef = NULL;
+ virNWFilterUnlockFilterUpdates();
+ virNWFilterPoolObjUnlock(pool);
+ return NULL;
+ }
+
+ virNWFilterDefFree(pool->def);
+ pool->def = def;
+ pool->newDef = NULL;
+ virNWFilterUnlockFilterUpdates();
+ return pool;
+ }
+
+ if (VIR_ALLOC(pool) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virMutexInitRecursive(&pool->lock) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialize mutex"));
+ VIR_FREE(pool);
+ return NULL;
+ }
+ virNWFilterPoolObjLock(pool);
+ pool->active = 0;
+ pool->def = def;
+
+ if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
+ pool->def = NULL;
+ virNWFilterPoolObjUnlock(pool);
+ virNWFilterPoolObjFree(pool);
+ virReportOOMError();
+ return NULL;
+ }
+ pools->objs[pools->count++] = pool;
+
+ return pool;
+}
+
+
+static virNWFilterPoolObjPtr
+virNWFilterPoolObjLoad(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *file,
+ const char *path)
+{
+ virNWFilterDefPtr def;
+ virNWFilterPoolObjPtr pool;
+
+ if (!(def = virNWFilterDefParseFile(conn, path))) {
+ return NULL;
+ }
+
+ if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+ virNWFilterError(conn, VIR_ERR_INVALID_NWFILTER,
+ "NWFilter pool config filename '%s' does not match pool name '%s'",
+ path, def->name);
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ if (!(pool = virNWFilterPoolObjAssignDef(conn, pools, def))) {
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ pool->configFile = strdup(path);
+ if (pool->configFile == NULL) {
+ virReportOOMError();
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ return pool;
+}
+
+
+int
+virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *configDir)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ if (!(dir = opendir(configDir))) {
+ if (errno == ENOENT) {
+ return 0;
+ }
+ virReportSystemError(errno, _("Failed to open dir '%s'"),
+ configDir);
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ char path[PATH_MAX];
+ virNWFilterPoolObjPtr pool;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!virFileHasSuffix(entry->d_name, ".xml"))
+ continue;
+
+ if (virFileBuildPath(configDir, entry->d_name,
+ NULL, path, PATH_MAX) < 0) {
+ virNWFilterError(conn, VIR_ERR_INTERNAL_ERROR,
+ "Config filename '%s/%s' is too long",
+ configDir, entry->d_name);
+ continue;
+ }
+
+ pool = virNWFilterPoolObjLoad(conn, pools, entry->d_name, path);
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+
+int
+virNWFilterPoolObjSaveDef(virConnectPtr conn,
+ virNWFilterDriverStatePtr driver,
+ virNWFilterPoolObjPtr pool,
+ virNWFilterDefPtr def)
+{
+ char *xml;
+ int fd = -1, ret = -1;
+ ssize_t towrite;
+
+ if (!pool->configFile) {
+ int err;
+ char path[PATH_MAX];
+
+ if ((err = virFileMakePath(driver->configDir))) {
+ virReportSystemError(err,
+ _("cannot create config directory %s"),
+ driver->configDir);
+ return -1;
+ }
+
+ if (virFileBuildPath(driver->configDir, def->name, ".xml",
+ path, sizeof(path)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot construct config file path"));
+ return -1;
+ }
+ if (!(pool->configFile = strdup(path))) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+
+ if (!(xml = virNWFilterDefFormat(conn, def))) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to generate XML"));
+ return -1;
+ }
+
+ if ((fd = open(pool->configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virReportSystemError(errno,
+ _("cannot create config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) != towrite) {
+ virReportSystemError(errno,
+ _("cannot write config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virReportSystemError(errno,
+ _("cannot save config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+
+ VIR_FREE(xml);
+
+ return ret;
+}
+
+
+int
+virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool)
+{
+ if (!pool->configFile) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no config file for %s"), pool->def->name);
+ return -1;
+ }
+
+ if (unlink(pool->configFile) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot remove config for %s"),
+ pool->def->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+virNWIPAddressFormat(virBufferPtr buf, nwIPAddressPtr ipaddr)
+{
+ if (!ipaddr->isIPv6) {
+ virBufferVSprintf(buf, "%d.%d.%d.%d",
+ ipaddr->addr.ipv4Addr[0],
+ ipaddr->addr.ipv4Addr[1],
+ ipaddr->addr.ipv4Addr[2],
+ ipaddr->addr.ipv4Addr[3]);
+ } else {
+ virBufferAddLit(buf, "MISSING IPv6 ADDRESS FORMATTER");
+ }
+}
+
+
+static void
+virNWFilterRuleDefDetailsFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *type,
+ const virXMLAttr2Struct *att,
+ virNWFilterRuleDefPtr def)
+{
+ int i, j;
+ bool typeShown = 0;
+ bool neverShown = 1;
+ enum match {
+ MATCH_NONE = 0,
+ MATCH_YES,
+ MATCH_NO
+ } matchShown = MATCH_NONE;
+ nwItemDesc *item;
+
+ while (att[i].name) {
+ item = (nwItemDesc *)((char *)def + att[i].dataIdx);
+ enum virNWFilterEntryItemFlags flags = item->flags;
+ void *storage_ptr;
+ if ((flags & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)) {
+ if (!typeShown) {
+ virBufferVSprintf(buf, " <%s", type);
+ typeShown = 1;
+ neverShown = 0;
+ }
+
+ if ((flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG)) {
+ if (matchShown == MATCH_NONE) {
+ virBufferAddLit(buf, " match='no'");
+ matchShown = MATCH_NO;
+ } else if (matchShown == MATCH_YES) {
+ virBufferAddLit(buf, "/>\n");
+ typeShown = 0;
+ matchShown = MATCH_NONE;
+ continue;
+ }
+ } else {
+ if (matchShown == MATCH_NO) {
+ virBufferAddLit(buf, "/>\n");
+ typeShown = 0;
+ matchShown = MATCH_NONE;
+ continue;
+ }
+ matchShown = MATCH_YES;
+ }
+
+ virBufferVSprintf(buf, " %s='",
+ att[i].name);
+ if (att[i].formatter) {
+ if (!att[i].formatter(buf, def)) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("formatter for %s %s reported error"),
+ type,
+ att[i].name);
+ goto err_exit;
+ }
+ } else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+ virBufferVSprintf(buf, "$%s", item->var);
+ } else {
+ switch (att[i].datatype) {
+
+ case DATATYPE_IPMASK:
+ // display all masks in CIDR format
+ case DATATYPE_UINT8:
+ storage_ptr = &item->u.u8;
+ virBufferVSprintf(buf, "%d", *(uint8_t *)storage_ptr);
+ break;
+
+ case DATATYPE_UINT16:
+ storage_ptr = &item->u.u16;
+ virBufferVSprintf(buf, "%d", *(uint16_t *)storage_ptr);
+ break;
+
+ case DATATYPE_IPADDR:
+ storage_ptr = &item->u.ipaddr;
+ virNWIPAddressFormat(buf,
+ (nwIPAddressPtr)storage_ptr);
+ break;
+
+ case DATATYPE_MACMASK:
+ case DATATYPE_MACADDR:
+ storage_ptr = &item->u.macaddr;
+ for (j = 0; j < 6; j++)
+ virBufferVSprintf(buf, "%02x%s",
+ ((nwMACAddressPtr)storage_ptr)->addr[j],
+ (j < 5) ? ":" : "");
+ break;
+
+ case DATATYPE_STRING:
+ default:
+ virBufferVSprintf(buf,
+ "UNSUPPORTED DATATYPE 0x%02x\n",
+ att[i].datatype);
+ }
+ }
+ virBufferAddLit(buf, "'");
+ }
+ i++;
+ }
+ if (typeShown)
+ virBufferAddLit(buf, "/>\n");
+
+ if (neverShown)
+ virBufferVSprintf(buf,
+ " <%s/>\n", type);
+
+err_exit:
+ return;
+}
+
+
+static char *
+virNWFilterRuleDefFormat(virConnectPtr conn,
+ virNWFilterRuleDefPtr def)
+{
+ int i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virBuffer buf2 = VIR_BUFFER_INITIALIZER;
+ char *data;
+
+ virBufferVSprintf(&buf, " <rule action='%s' direction='%s' priority='%d'",
+ virNWFilterRuleActionTypeToString(def->action),
+ virNWFilterRuleDirectionTypeToString(def->tt),
+ def->priority);
+
+ i = 0;
+ while (virAttr[i].id) {
+ if (virAttr[i].prtclType == def->prtclType) {
+ virNWFilterRuleDefDetailsFormat(conn,
+ &buf2,
+ virAttr[i].id,
+ virAttr[i].att,
+ def);
+ break;
+ }
+ i++;
+ }
+
+ if (virBufferError(&buf2))
+ goto no_memory;
+
+ data = virBufferContentAndReset(&buf2);
+
+ if (data) {
+ virBufferAddLit(&buf, ">\n");
+ virBufferVSprintf(&buf, "%s </rule>\n", data);
+ VIR_FREE(data);
+ } else
+ virBufferAddLit(&buf, "/>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+no_memory:
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ virBufferFreeAndReset(&buf2);
+
+ return NULL;
+}
+
+
+static char *
+virNWFilterIncludeDefFormat(virNWFilterIncludeDefPtr inc)
+{
+ char *attrs;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferVSprintf(&buf," <filterref filter='%s'",
+ inc->filterref);
+
+ attrs = virNWFilterFormatParamAttributes(inc->params, " ");
+
+ if (!attrs || strlen(attrs) <= 1)
+ virBufferAddLit(&buf, "/>\n");
+ else
+ virBufferVSprintf(&buf, ">\n%s </filterref>\n", attrs);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+
+static char *
+virNWFilterEntryFormat(virConnectPtr conn,
+ virNWFilterEntryPtr entry)
+{
+ if (entry->rule)
+ return virNWFilterRuleDefFormat(conn, entry->rule);
+ return virNWFilterIncludeDefFormat(entry->include);
+}
+
+
+char *
+virNWFilterDefFormat(virConnectPtr conn,
+ virNWFilterDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ int i;
+ char *xml;
+
+ virBufferVSprintf(&buf, "<filter name='%s' chain='%s'",
+ def->name,
+ virNWFilterChainSuffixTypeToString(def->chainsuffix));
+ virBufferAddLit(&buf, ">\n");
+
+ virUUIDFormat(def->uuid, uuid);
+ virBufferVSprintf(&buf," <uuid>%s</uuid>\n", uuid);
+
+ for (i = 0; i < def->nentries; i++) {
+ xml = virNWFilterEntryFormat(conn, def->filterEntries[i]);
+ if (!xml)
+ goto err_exit;
+ virBufferVSprintf(&buf, "%s", xml);
+ VIR_FREE(xml);
+ }
+
+ virBufferAddLit(&buf, "</filter>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+ no_memory:
+ virReportOOMError();
+
+ err_exit:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+
+char *virNWFilterConfigFile(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *dir,
+ const char *name)
+{
+ char *ret = NULL;
+
+ if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+int virNWFilterConfLayerInit(void)
+{
+ if (virMutexInit(&updateMutex))
+ return 1;
+
+ if (virNWFilterParamConfLayerInit())
+ return 1;
+
+ return 0;
+}
+
+
+void virNWFilterConfLayerShutdown(void)
+{
+ virNWFilterParamConfLayerShutdown();
+}
+
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj)
+{
+ virMutexLock(&obj->lock);
+}
+
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj)
+{
+ virMutexUnlock(&obj->lock);
+}
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -0,0 +1,457 @@
+/*
+ * nwfilter_conf.h: network filter XML processing
+ * (derived from storage_conf.h)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+#ifndef NWFILTER_CONF_H
+#define NWFILTER_CONF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "internal.h"
+#include "util.h"
+#include "hash.h"
+#include "xml.h"
+
+/**
+ * Chain suffix size is:
+ * max. user define table name length -
+ * sizeof("FO-") -
+ * max. interface name size -
+ * sizeof("-") -
+ * terminating '0' =
+ * 32-3-15-1-1 = 12
+ */
+#define MAX_CHAIN_SUFFIX_SIZE 12
+
+
+enum virNWFilterEntryItemFlags {
+ NWFILTER_ENTRY_ITEM_FLAG_EXISTS = 1 << 0,
+ NWFILTER_ENTRY_ITEM_FLAG_IS_NEG = 1 << 1,
+ NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR = 1 << 2,
+};
+
+
+#define HAS_ENTRY_ITEM(data) \
+ (((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)
+
+#define ENTRY_GET_NEG_SIGN(data) \
+ ((((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) ? "!" : "")
+
+// datatypes appearing in rule attributes
+enum attrDatatype {
+ DATATYPE_UINT16 = (1 << 0),
+ DATATYPE_UINT8 = (1 << 1),
+ DATATYPE_MACADDR = (1 << 2),
+ DATATYPE_MACMASK = (1 << 3),
+ DATATYPE_IPADDR = (1 << 4),
+ DATATYPE_IPMASK = (1 << 5),
+ DATATYPE_STRING = (1 << 6),
+
+ DATATYPE_LAST = (1 << 7),
+};
+
+
+typedef struct _nwMACAddress nwMACAddress;
+typedef nwMACAddress *nwMACAddressPtr;
+struct _nwMACAddress {
+ unsigned char addr[6];
+};
+
+
+typedef struct _nwIPAddress nwIPAddress;
+typedef nwIPAddress *nwIPAddressPtr;
+struct _nwIPAddress {
+ int isIPv6;
+ union {
+ unsigned char ipv4Addr[4];
+ /* unsigned char ipv6Addr[16]; future :-) */
+ } addr;
+};
+
+
+typedef struct _nwItemDesc nwItemDesc;
+typedef nwItemDesc *nwItemDescPtr;
+struct _nwItemDesc {
+ enum virNWFilterEntryItemFlags flags;
+ char *var;
+ enum attrDatatype datatype;
+ union {
+ nwMACAddress macaddr;
+ nwIPAddress ipaddr;
+ uint8_t u8;
+ uint16_t u16;
+ char protocolID[10];
+ } u;
+};
+
+
+typedef struct _ethHdrDataDef ethHdrDataDef;
+typedef ethHdrDataDef *ethHdrDataDefPtr;
+struct _ethHdrDataDef {
+ nwItemDesc dataSrcMACAddr;
+ nwItemDesc dataSrcMACMask;
+ nwItemDesc dataDstMACAddr;
+ nwItemDesc dataDstMACMask;
+};
+
+
+typedef struct _ethHdrFilterDef ethHdrFilterDef;
+typedef ethHdrFilterDef *ethHdrFilterDefPtr;
+struct _ethHdrFilterDef {
+ ethHdrDataDef ethHdr;
+ nwItemDesc dataProtocolID;
+};
+
+
+typedef struct _arpHdrFilterDef arpHdrFilterDef;
+typedef arpHdrFilterDef *arpHdrFilterDefPtr;
+struct _arpHdrFilterDef {
+ ethHdrDataDef ethHdr;
+ nwItemDesc dataHWType;
+ nwItemDesc dataProtocolType;
+ nwItemDesc dataOpcode;
+ nwItemDesc dataARPSrcMACAddr;
+ nwItemDesc dataARPSrcIPAddr;
+ nwItemDesc dataARPDstMACAddr;
+ nwItemDesc dataARPDstIPAddr;
+};
+
+
+typedef struct _ipHdrDataDef ipHdrDataDef;
+typedef ipHdrDataDef *ipHdrDataDefPtr;
+struct _ipHdrDataDef {
+ nwItemDesc dataIPVersion;
+ nwItemDesc dataSrcIPAddr;
+ nwItemDesc dataSrcIPMask;
+ nwItemDesc dataDstIPAddr;
+ nwItemDesc dataDstIPMask;
+ nwItemDesc dataProtocolID;
+ nwItemDesc dataDSCP;
+};
+
+
+typedef struct _portDataDef portDataDef;
+typedef portDataDef *portDataDefPtr;
+struct _portDataDef {
+ nwItemDesc dataSrcPortStart;
+ nwItemDesc dataSrcPortEnd;
+ nwItemDesc dataDstPortStart;
+ nwItemDesc dataDstPortEnd;
+};
+
+
+typedef struct _ipHdrFilterDef ipHdrFilterDef;
+typedef ipHdrFilterDef *ipHdrFilterDefPtr;
+struct _ipHdrFilterDef {
+ ethHdrDataDef ethHdr;
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+};
+
+
+enum virNWFilterRuleActionType {
+ VIR_NWFILTER_RULE_ACTION_DROP = 0,
+ VIR_NWFILTER_RULE_ACTION_ACCEPT,
+
+ VIR_NWFILTER_RULE_ACTION_LAST,
+};
+
+enum virNWFilterRuleDirectionType {
+ VIR_NWFILTER_RULE_DIRECTION_IN = 0,
+ VIR_NWFILTER_RULE_DIRECTION_OUT,
+ VIR_NWFILTER_RULE_DIRECTION_INOUT,
+
+ VIR_NWFILTER_RULE_DIRECTION_LAST,
+};
+
+enum virNWFilterChainPolicyType {
+ VIR_NWFILTER_CHAIN_POLICY_ACCEPT = 0,
+ VIR_NWFILTER_CHAIN_POLICY_DROP,
+
+ VIR_NWFILTER_CHAIN_POLICY_LAST,
+};
+
+enum virNWFilterRuleProtocolType {
+ VIR_NWFILTER_RULE_PROTOCOL_NONE = 0,
+ VIR_NWFILTER_RULE_PROTOCOL_MAC,
+ VIR_NWFILTER_RULE_PROTOCOL_ARP,
+ VIR_NWFILTER_RULE_PROTOCOL_IP,
+};
+
+enum virNWFilterEbtablesTableType {
+ VIR_NWFILTER_EBTABLES_TABLE_FILTER = 0,
+ VIR_NWFILTER_EBTABLES_TABLE_NAT,
+ VIR_NWFILTER_EBTABLES_TABLE_BROUTE,
+
+ VIR_NWFILTER_EBTABLES_TABLE_LAST,
+};
+
+
+#define MAX_RULE_PRIORITY 1000
+
+
+typedef struct _virNWFilterRuleDef virNWFilterRuleDef;
+typedef virNWFilterRuleDef *virNWFilterRuleDefPtr;
+struct _virNWFilterRuleDef {
+ unsigned int priority;
+ int action; /*enum virNWFilterRuleActionType*/
+ int tt; /*enum virNWFilterRuleDirectionType*/
+ enum virNWFilterRuleProtocolType prtclType;
+ union {
+ ethHdrFilterDef ethHdrFilter;
+ arpHdrFilterDef arpHdrFilter;
+ ipHdrFilterDef ipHdrFilter;
+ } p;
+
+ int nvars;
+ char **vars;
+};
+
+
+typedef struct _virNWFilterIncludeDef virNWFilterIncludeDef;
+typedef virNWFilterIncludeDef *virNWFilterIncludeDefPtr;
+struct _virNWFilterIncludeDef {
+ char *filterref;
+ virNWFilterHashTablePtr params;
+};
+
+
+typedef struct _virNWFilterEntry virNWFilterEntry;
+typedef virNWFilterEntry *virNWFilterEntryPtr;
+struct _virNWFilterEntry {
+ virNWFilterRuleDef *rule;
+ virNWFilterIncludeDef *include;
+};
+
+enum virNWFilterChainSuffixType {
+ VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
+ VIR_NWFILTER_CHAINSUFFIX_ARP,
+ VIR_NWFILTER_CHAINSUFFIX_IPv4,
+
+ VIR_NWFILTER_CHAINSUFFIX_LAST,
+};
+
+
+typedef struct _virNWFilterDef virNWFilterDef;
+typedef virNWFilterDef *virNWFilterDefPtr;
+
+struct _virNWFilterDef {
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ int chainsuffix; /*enum virNWFilterChainSuffixType */
+
+ int nentries;
+ virNWFilterEntryPtr *filterEntries;
+};
+
+
+typedef struct _virNWFilterPoolObj virNWFilterPoolObj;
+typedef virNWFilterPoolObj *virNWFilterPoolObjPtr;
+
+struct _virNWFilterPoolObj {
+ virMutex lock;
+
+ char *configFile;
+ int active;
+ int wantRemoved;
+
+ virNWFilterDefPtr def;
+ virNWFilterDefPtr newDef;
+};
+
+
+typedef struct _virNWFilterPoolObjList virNWFilterPoolObjList;
+typedef virNWFilterPoolObjList *virNWFilterPoolObjListPtr;
+struct _virNWFilterPoolObjList {
+ unsigned int count;
+ virNWFilterPoolObjPtr *objs;
+};
+
+
+typedef struct _virNWFilterDriverState virNWFilterDriverState;
+typedef virNWFilterDriverState *virNWFilterDriverStatePtr;
+struct _virNWFilterDriverState {
+ virMutex lock;
+
+ virNWFilterPoolObjList pools;
+
+ char *configDir;
+};
+
+
+typedef struct _virNWFilterTechDriver virNWFilterTechDriver;
+typedef virNWFilterTechDriver *virNWFilterTechDriverPtr;
+
+
+typedef struct _virNWFilterRuleInst virNWFilterRuleInst;
+typedef virNWFilterRuleInst *virNWFilterRuleInstPtr;
+struct _virNWFilterRuleInst {
+ int ndata;
+ void **data;
+ virNWFilterTechDriverPtr techdriver;
+};
+
+
+enum virDomainNetType;
+
+typedef int (*virNWFilterRuleCreateInstance)(virConnectPtr conn,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res);
+
+typedef int (*virNWFilterRuleApplyRules)(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst);
+
+typedef int (*virNWFilterRuleRemoveRules)(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst);
+
+typedef int (*virNWFilterRuleAllTeardown)(const char *ifname);
+
+typedef int (*virNWFilterRuleFreeInstanceData)(void * _inst);
+
+typedef int (*virNWFilterRuleDisplayInstanceData)(virConnectPtr conn,
+ void *_inst);
+
+
+struct _virNWFilterTechDriver {
+ const char *name;
+
+ virNWFilterRuleCreateInstance createRuleInstance;
+ virNWFilterRuleApplyRules applyRules;
+ virNWFilterRuleRemoveRules removeRules;
+ virNWFilterRuleAllTeardown allTeardown;
+ virNWFilterRuleFreeInstanceData freeRuleInstance;
+ virNWFilterRuleDisplayInstanceData displayRuleInstance;
+};
+
+
+
+void virNWFilterRuleDefFree(virNWFilterRuleDefPtr def);
+
+void virNWFilterDefFree(virNWFilterDefPtr def);
+void virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools);
+void virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+ virNWFilterPoolObjPtr pool);
+
+void virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj);
+
+virNWFilterPoolObjPtr
+ virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+ const unsigned char *uuid);
+
+virNWFilterPoolObjPtr
+ virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+ const char *name);
+
+
+int virNWFilterPoolObjSaveDef(virConnectPtr conn,
+ virNWFilterDriverStatePtr driver,
+ virNWFilterPoolObjPtr pool,
+ virNWFilterDefPtr def);
+
+int virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool);
+
+virNWFilterPoolObjPtr virNWFilterPoolObjAssignDef(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def);
+
+int virNWFilterTestUnassignDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool);
+
+virNWFilterDefPtr virNWFilterDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root);
+
+char *virNWFilterDefFormat(virConnectPtr conn,
+ virNWFilterDefPtr def);
+
+int virNWFilterSaveXML(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def,
+ const char *xml);
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def);
+
+int virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *configDir);
+
+char *virNWFilterConfigFile(virConnectPtr conn,
+ const char *dir,
+ const char *name);
+
+virNWFilterDefPtr virNWFilterDefParseString(virConnectPtr conn,
+ const char *xml);
+virNWFilterDefPtr virNWFilterDefParseFile(virConnectPtr conn,
+ const char *filename);
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj);
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj);
+
+int virNWFilterConfLayerInit(void);
+void virNWFilterConfLayerShutdown(void);
+
+int virNWFilterParamConfLayerInit(void);
+void virNWFilterParamConfLayerShutdown(void);
+
+#define virNWFilterReportError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NWFILTER, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+
+typedef int (*virNWFilterRebuild)(virConnectPtr conn,
+ virHashIterator, void *data);
+
+typedef struct _virNWFilterCallbackDriver virNWFilterCallbackDriver;
+typedef virNWFilterCallbackDriver *virNWFilterCallbackDriverPtr;
+struct _virNWFilterCallbackDriver {
+ const char *name;
+
+ virNWFilterRebuild vmFilterRebuild;
+};
+
+void virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr);
+
+
+VIR_ENUM_DECL(virNWFilterRuleAction);
+VIR_ENUM_DECL(virNWFilterRuleDirection);
+VIR_ENUM_DECL(virNWFilterRuleProtocol);
+VIR_ENUM_DECL(virNWFilterJumpTarget);
+VIR_ENUM_DECL(virNWFilterChainPolicy);
+VIR_ENUM_DECL(virNWFilterEbtablesTable);
+VIR_ENUM_DECL(virNWFilterChainSuffix);
+
+#endif /* NWFILTER_CONF_H */
Index: libvirt-acl/include/libvirt/virterror.h
===================================================================
--- libvirt-acl.orig/include/libvirt/virterror.h
+++ libvirt-acl/include/libvirt/virterror.h
@@ -69,7 +69,8 @@ typedef enum {
VIR_FROM_PHYP, /* Error from IBM power hypervisor */
VIR_FROM_SECRET, /* Error from secret storage */
VIR_FROM_CPU, /* Error from CPU driver */
- VIR_FROM_XENAPI /* Error from XenAPI */
+ VIR_FROM_XENAPI, /* Error from XenAPI */
+ VIR_FROM_NWFILTER /* Error from network filter driver */
} virErrorDomain;


@@ -169,6 +170,10 @@ typedef enum {
VIR_ERR_NO_INTERFACE, /* interface driver not running */
VIR_ERR_INVALID_INTERFACE, /* invalid interface object */
VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */
+ VIR_WAR_NO_NWFILTER, /* failed to start nwfilter driver */
+ VIR_ERR_INVALID_NWFILTER, /* invalid nwfilter object */
+ VIR_ERR_NO_NWFILTER, /* nw filter pool not found */
+ VIR_ERR_BUILD_FIREWALL, /* nw filter pool not found */
VIR_WAR_NO_SECRET, /* failed to start secret storage */
VIR_ERR_INVALID_SECRET, /* invalid secret */
VIR_ERR_NO_SECRET, /* secret not found */
Index: libvirt-acl/src/util/virterror.c
===================================================================
--- libvirt-acl.orig/src/util/virterror.c
+++ libvirt-acl/src/util/virterror.c
@@ -178,6 +178,9 @@ static const char *virErrorDomainName(vi
case VIR_FROM_CPU:
dom = "CPU ";
break;
+ case VIR_FROM_NWFILTER:
+ dom = "Network Filter";
+ break;
}
return(dom);
}
@@ -1100,6 +1103,30 @@ virErrorMsg(virErrorNumber error, const
else
errmsg = _("Secret not found: %s");
break;
+ case VIR_WAR_NO_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Failed to start the nwfilter driver");
+ else
+ errmsg = _("Failed to start the nwfilter driver: %s");
+ break;
+ case VIR_ERR_INVALID_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Invalid network filter");
+ else
+ errmsg = _("Invalid network filter: %s");
+ break;
+ case VIR_ERR_NO_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Network filter not found");
+ else
+ errmsg = _("Network filter not found: %s");
+ break;
+ case VIR_ERR_BUILD_FIREWALL:
+ if (info == NULL)
+ errmsg = _("Error while building firewall");
+ else
+ errmsg = _("Error while building firewall: %s");
+ break;
case VIR_ERR_CONFIG_UNSUPPORTED:
if (info == NULL)
errmsg = _("unsupported configuration");
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -0,0 +1,416 @@
+/*
+ * nwfilter_driver.c: core driver for network filter APIs
+ * (based on storage_driver.c)
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <***@redhat.com>
+ * Stefan Berger <***@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include "internal.h"
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "memory.h"
+#include "domain_conf.h"
+#include "nwfilter_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#define nwfilterLog(msg...) fprintf(stderr, msg)
+
+
+static virNWFilterDriverStatePtr driverState;
+
+static int nwfilterDriverShutdown(void);
+
+static void nwfilterDriverLock(virNWFilterDriverStatePtr driver)
+{
+ virMutexLock(&driver->lock);
+}
+static void nwfilterDriverUnlock(virNWFilterDriverStatePtr driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+
+/**
+ * virNWFilterStartup:
+ *
+ * Initialization function for the QEmu daemon
+ */
+static int
+nwfilterDriverStartup(int privileged) {
+ char *base = NULL;
+
+ if (virNWFilterConfLayerInit() < 0)
+ return -1;
+
+ if (VIR_ALLOC(driverState) < 0)
+ goto alloc_err_exit;
+
+ if (virMutexInit(&driverState->lock) < 0)
+ goto alloc_err_exit;
+
+ nwfilterDriverLock(driverState);
+
+ if (privileged) {
+ if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
+ goto out_of_memory;
+ } else {
+ uid_t uid = geteuid();
+ char *userdir = virGetUserDirectory(uid);
+
+ if (!userdir)
+ goto error;
+
+ if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
+ nwfilterLog("out of memory in virAsprintf");
+ VIR_FREE(userdir);
+ goto out_of_memory;
+ }
+ VIR_FREE(userdir);
+ }
+
+ if (virAsprintf(&driverState->configDir,
+ "%s/nwfilter", base) == -1)
+ goto out_of_memory;
+
+ VIR_FREE(base);
+
+ if (virNWFilterPoolLoadAllConfigs(NULL,
+ &driverState->pools,
+ driverState->configDir) < 0)
+ goto error;
+
+ nwfilterDriverUnlock(driverState);
+
+ return 0;
+
+out_of_memory:
+ nwfilterLog("virNWFilterStartup: out of memory");
+
+error:
+ VIR_FREE(base);
+ nwfilterDriverUnlock(driverState);
+ nwfilterDriverShutdown();
+
+alloc_err_exit:
+ virNWFilterConfLayerShutdown();
+
+ return -1;
+}
+
+/**
+ * virNWFilterReload:
+ *
+ * Function to restart the nwfilter driver, it will recheck the configuration
+ * files and update its state
+ */
+static int
+nwfilterDriverReload(void) {
+ if (!driverState) {
+ return -1;
+ }
+
+ nwfilterDriverLock(driverState);
+ virNWFilterPoolLoadAllConfigs(NULL,
+ &driverState->pools,
+ driverState->configDir);
+ nwfilterDriverUnlock(driverState);
+
+ return 0;
+}
+
+/**
+ * virNWFilterActive:
+ *
+ * Checks if the nwfilter driver is active, i.e. has an active pool
+ *
+ * Returns 1 if active, 0 otherwise
+ */
+static int
+nwfilterDriverActive(void) {
+ if (!driverState->pools.count)
+ return 0;
+ return 1;
+}
+
+/**
+ * virNWFilterShutdown:
+ *
+ * Shutdown the nwfilter driver, it will stop all active nwfilter pools
+ */
+static int
+nwfilterDriverShutdown(void) {
+ if (!driverState)
+ return -1;
+
+ nwfilterDriverLock(driverState);
+
+ /* free inactive pools */
+ virNWFilterPoolObjListFree(&driverState->pools);
+
+ VIR_FREE(driverState->configDir);
+ nwfilterDriverUnlock(driverState);
+ virMutexDestroy(&driverState->lock);
+ VIR_FREE(driverState);
+
+ return 0;
+}
+
+
+static virNWFilterPtr
+nwfilterLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, uuid);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ "%s", _("no pool with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virNWFilterPtr
+nwfilterLookupByName(virConnectPtr conn,
+ const char *name) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByName(&driver->pools, name);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("no pool with matching name '%s'"), name);
+ goto cleanup;
+ }
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virDrvOpenStatus
+nwfilterOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED) {
+ if (!driverState)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->nwfilterPrivateData = driverState;
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+static int
+nwfilterClose(virConnectPtr conn) {
+ conn->nwfilterPrivateData = NULL;
+ return 0;
+}
+
+
+static int
+nwfilterNumNWFilters(virConnectPtr conn) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ return driver->pools.count;
+}
+
+
+static int
+nwfilterListNWFilters(virConnectPtr conn,
+ char **const names,
+ int nnames) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ int got = 0, i;
+
+ nwfilterDriverLock(driver);
+ for (i = 0 ; i < driver->pools.count && got < nnames ; i++) {
+ virNWFilterPoolObjLock(driver->pools.objs[i]);
+ if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) {
+ virNWFilterPoolObjUnlock(driver->pools.objs[i]);
+ virReportOOMError();
+ goto cleanup;
+ }
+ got++;
+ virNWFilterPoolObjUnlock(driver->pools.objs[i]);
+ }
+ nwfilterDriverUnlock(driver);
+ return got;
+
+ cleanup:
+ nwfilterDriverUnlock(driver);
+ for (i = 0 ; i < got ; i++)
+ VIR_FREE(names[i]);
+ memset(names, 0, nnames * sizeof(*names));
+ return -1;
+}
+
+
+static virNWFilterPtr
+nwfilterDefine(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterDefPtr def;
+ virNWFilterPoolObjPtr pool = NULL;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ if (!(def = virNWFilterDefParseString(conn, xml)))
+ goto cleanup;
+
+ if (!(pool = virNWFilterPoolObjAssignDef(conn, &driver->pools, def)))
+ goto cleanup;
+
+ if (virNWFilterPoolObjSaveDef(conn, driver, pool, def) < 0) {
+ virNWFilterPoolObjRemove(&driver->pools, pool);
+ def = NULL;
+ goto cleanup;
+ }
+ def = NULL;
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ virNWFilterDefFree(def);
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ nwfilterDriverUnlock(driver);
+ return ret;
+}
+
+
+static int
+nwfilterUndefine(virNWFilterPtr obj) {
+ virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ int ret = -1;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
+ if (!pool) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("no nwfilter pool with matching uuid"));
+ goto cleanup;
+ }
+
+ if (virNWFilterTestUnassignDef(obj->conn, pool)) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s",
+ _("nwfilter is in use"));
+ goto cleanup;
+ }
+
+ if (virNWFilterPoolObjDeleteDef(obj->conn, pool) < 0)
+ goto cleanup;
+
+ VIR_FREE(pool->configFile);
+
+ virNWFilterPoolObjRemove(&driver->pools, pool);
+ pool = NULL;
+ ret = 0;
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ nwfilterDriverUnlock(driver);
+ return ret;
+}
+
+
+static char *
+nwfilterDumpXML(virNWFilterPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ char *ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("no nwfilter pool with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virNWFilterDefFormat(obj->conn, pool->def);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virNWFilterDriver nwfilterDriver = {
+ .name = "nwfilter",
+ .open = nwfilterOpen,
+ .close = nwfilterClose,
+ .numOfNWFilters = nwfilterNumNWFilters,
+ .listNWFilters = nwfilterListNWFilters,
+ .nwfilterLookupByName = nwfilterLookupByName,
+ .nwfilterLookupByUUID = nwfilterLookupByUUID,
+ .defineXML = nwfilterDefine,
+ .undefine = nwfilterUndefine,
+ .getXMLDesc = nwfilterDumpXML,
+};
+
+
+static virStateDriver stateDriver = {
+ .name = "NWFilter",
+ .initialize = nwfilterDriverStartup,
+ .cleanup = nwfilterDriverShutdown,
+ .reload = nwfilterDriverReload,
+ .active = nwfilterDriverActive,
+};
+
+int nwfilterRegister(void) {
+ virRegisterNWFilterDriver(&nwfilterDriver);
+ virRegisterStateDriver(&stateDriver);
+ return 0;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.h
@@ -0,0 +1,36 @@
+/*
+ * nwfilter_driver.h: core driver for nwfilter APIs
+ * (based on storage driver)
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <***@redhat.com>
+ * Stefan Berger <***@us.ibm.com>
+ */
+
+#ifndef __VIR_NWFILTER_DRIVER_H__
+#define __VIR_NWFILTER_DRIVER_H__
+
+#include "nwfilter_params.h"
+#include "nwfilter_conf.h"
+
+int nwfilterRegister(void);
+
+#endif /* __VIR_NWFILTER_DRIVER_H__ */
Index: libvirt-acl/src/datatypes.h
===================================================================
--- libvirt-acl.orig/src/datatypes.h
+++ libvirt-acl/src/datatypes.h
@@ -121,6 +121,17 @@


/**
+ * VIR_NWFILTER_MAGIC:
+ *
+ * magic value used to protect the API when pointers to network filter
+ * pool structures are passed down by the users.
+ */
+#define VIR_NWFILTER_MAGIC 0xDEAD7777
+#define VIR_IS_NWFILTER(obj) ((obj) && (obj)->magic==VIR_NWFILTER_MAGIC)
+#define VIR_IS_CONNECTED_NWFILTER(obj) (VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn))
+
+
+/**
* _virConnect:
*
* Internal structure associated to a connection
@@ -141,6 +152,7 @@ struct _virConnect {
virStorageDriverPtr storageDriver;
virDeviceMonitorPtr deviceMonitor;
virSecretDriverPtr secretDriver;
+ virNWFilterDriverPtr nwfilterDriver;

/* Private data pointer which can be used by driver and
* network driver as they wish.
@@ -152,6 +164,7 @@ struct _virConnect {
void * storagePrivateData;
void * devMonPrivateData;
void * secretPrivateData;
+ void * nwfilterPrivateData;

/*
* The lock mutex must be acquired before accessing/changing
@@ -173,6 +186,7 @@ struct _virConnect {
virHashTablePtr storageVols;/* hash table for known storage vols */
virHashTablePtr nodeDevices; /* hash table for known node devices */
virHashTablePtr secrets; /* hash taboe for known secrets */
+ virHashTablePtr nwfilterPools; /* hash tables ofr known nw filter pools */
int refs; /* reference count */
};

@@ -336,4 +350,22 @@ int virUnrefSecret(virSecretPtr secret);
virStreamPtr virGetStream(virConnectPtr conn);
int virUnrefStream(virStreamPtr st);

+/**
+* _virNWFilter:
+*
+* Internal structure associated to a network filter
+*/
+struct _virNWFilter {
+ unsigned int magic; /* specific value to check */
+ int refs; /* reference count */
+ virConnectPtr conn; /* pointer back to the connection */
+ char *name; /* the network filter external name */
+ unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique identifier */
+};
+
+virNWFilterPtr virGetNWFilter(virConnectPtr conn,
+ const char *name,
+ const unsigned char *uuid);
+int virUnrefNWFilter(virNWFilterPtr pool);
+
#endif
Index: libvirt-acl/src/datatypes.c
===================================================================
--- libvirt-acl.orig/src/datatypes.c
+++ libvirt-acl/src/datatypes.c
@@ -175,6 +175,9 @@ virGetConnect(void) {
ret->secrets = virHashCreate(20);
if (ret->secrets == NULL)
goto failed;
+ ret->nwfilterPools = virHashCreate(20);
+ if (ret->nwfilterPools == NULL)
+ goto failed;

ret->refs = 1;
return(ret);
@@ -1362,3 +1365,142 @@ int virUnrefStream(virStreamPtr st) {
virMutexUnlock(&st->conn->lock);
return (refs);
}
+
+
+/**
+ * virGetNWFilter:
+ * @conn: the hypervisor connection
+ * @name: pointer to the network filter pool name
+ * @uuid: pointer to the uuid
+ *
+ * Lookup if the network filter is already registered for that connection,
+ * if yes return a new pointer to it, if no allocate a new structure,
+ * and register it in the table. In any case a corresponding call to
+ * virFreeNWFilterPool() is needed to not leak data.
+ *
+ * Returns a pointer to the network, or NULL in case of failure
+ */
+virNWFilterPtr
+virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) {
+ virNWFilterPtr ret = NULL;
+
+ if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+ virMutexLock(&conn->lock);
+
+ /* TODO search by UUID first as they are better differenciators */
+
+ ret = (virNWFilterPtr) virHashLookup(conn->nwfilterPools, name);
+ /* TODO check the UUID */
+ if (ret == NULL) {
+ if (VIR_ALLOC(ret) < 0) {
+ virMutexUnlock(&conn->lock);
+ virReportOOMError();
+ goto error;
+ }
+ ret->name = strdup(name);
+ if (ret->name == NULL) {
+ virMutexUnlock(&conn->lock);
+ virReportOOMError();
+ goto error;
+ }
+ ret->magic = VIR_NWFILTER_MAGIC;
+ ret->conn = conn;
+ if (uuid != NULL)
+ memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
+
+ if (virHashAddEntry(conn->nwfilterPools, name, ret) < 0) {
+ virMutexUnlock(&conn->lock);
+ virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to add network filter pool to connection hash table"));
+ goto error;
+ }
+ conn->refs++;
+ }
+ ret->refs++;
+ virMutexUnlock(&conn->lock);
+ return(ret);
+
+error:
+ if (ret != NULL) {
+ VIR_FREE(ret->name);
+ VIR_FREE(ret);
+ }
+ return(NULL);
+}
+
+
+/**
+ * virReleaseNWFilterPool:
+ * @pool: the pool to release
+ *
+ * Unconditionally release all memory associated with a pool.
+ * The conn.lock mutex must be held prior to calling this, and will
+ * be released prior to this returning. The pool obj must not
+ * be used once this method returns.
+ *
+ * It will also unreference the associated connection object,
+ * which may also be released if its ref count hits zero.
+ */
+static void
+virReleaseNWFilterPool(virNWFilterPtr pool) {
+ virConnectPtr conn = pool->conn;
+ DEBUG("release pool %p %s", pool, pool->name);
+
+ /* TODO search by UUID first as they are better differenciators */
+ if (virHashRemoveEntry(conn->nwfilterPools, pool->name, NULL) < 0) {
+ virMutexUnlock(&conn->lock);
+ virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("pool missing from connection hash table"));
+ conn = NULL;
+ }
+
+ pool->magic = -1;
+ VIR_FREE(pool->name);
+ VIR_FREE(pool);
+
+ if (conn) {
+ DEBUG("unref connection %p %d", conn, conn->refs);
+ conn->refs--;
+ if (conn->refs == 0) {
+ virReleaseConnect(conn);
+ /* Already unlocked mutex */
+ return;
+ }
+ virMutexUnlock(&conn->lock);
+ }
+}
+
+
+/**
+ * virUnrefNWFilter:
+ * @pool: the nwfilter to unreference
+ *
+ * Unreference the networkf itler. If the use count drops to zero, the
+ * structure is actually freed.
+ *
+ * Returns the reference count or -1 in case of failure.
+ */
+int
+virUnrefNWFilter(virNWFilterPtr pool) {
+ int refs;
+
+ if (!VIR_IS_CONNECTED_NWFILTER(pool)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+ virMutexLock(&pool->conn->lock);
+ DEBUG("unref pool %p %s %d", pool, pool->name, pool->refs);
+ pool->refs--;
+ refs = pool->refs;
+ if (refs == 0) {
+ virReleaseNWFilterPool(pool);
+ /* Already unlocked mutex */
+ return (0);
+ }
+
+ virMutexUnlock(&pool->conn->lock);
+ return (refs);
+}
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -0,0 +1,1381 @@
+/*
+ * nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include "internal.h"
+
+#include "buf.h"
+#include "memory.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "domain_conf.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+
+#define EBTABLES_DEFAULT_TABLE "nat"
+#define EBTABLES_CHAIN_INCOMING "PREROUTING"
+#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
+
+#define CHAINPREFIX_HOST_IN 'I'
+#define CHAINPREFIX_HOST_OUT 'O'
+#define CHAINPREFIX_HOST_IN_TEMP 'J'
+#define CHAINPREFIX_HOST_OUT_TEMP 'P'
+
+
+#define CMD_SEPARATOR "\n"
+#define CMD_DEF_PRE "cmd=\""
+#define CMD_DEF_POST "\""
+#define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST
+#define CMD_EXEC "res=`${cmd}`" CMD_SEPARATOR
+#define CMD_STOPONERR(X) \
+ X ? "if [ $? -ne 0 ]; then" \
+ " echo \"Failure to execute command '${cmd}'.\";" \
+ " exit 1;" \
+ "fi" CMD_SEPARATOR \
+ : ""
+
+
+#define EBTABLES_CMD EBTABLES_PATH
+#define BASH_CMD BASH_PATH
+
+#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
+ snprintf(buf, sizeof(buf), "%c-%s", prefix, ifname)
+#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
+ snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)
+
+
+static const char *supported_protocols[] = {
+ "ipv4",
+ "arp",
+ NULL,
+};
+
+
+static int
+printVar(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item,
+ int *done)
+{
+ *done = 0;
+
+ if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+ char *val = (char *)virHashLookup(vars->hashTable, item->var);
+ if (!val) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("cannot find value for '%s'"),
+ item->var);
+ return 1;
+ }
+
+ if (!virStrcpy(buf, val, bufsize)) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer to small to print MAC address "
+ "'%s' into"),
+ item->var);
+ return 1;
+ }
+
+ *done = 1;
+ }
+ return 0;
+}
+
+
+static int
+printDataType(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item)
+{
+ int done;
+ if (printVar(conn, vars, buf, bufsize, item, &done))
+ return 1;
+
+ if (done)
+ return 0;
+
+ switch (item->datatype) {
+ case DATATYPE_IPADDR:
+ if (snprintf(buf, bufsize, "%d.%d.%d.%d",
+ item->u.ipaddr.addr.ipv4Addr[0],
+ item->u.ipaddr.addr.ipv4Addr[1],
+ item->u.ipaddr.addr.ipv4Addr[2],
+ item->u.ipaddr.addr.ipv4Addr[3]) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for IP address"));
+ return 1;
+ }
+ break;
+
+ case DATATYPE_MACADDR:
+ if (bufsize < VIR_MAC_STRING_BUFLEN) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for MAC address"));
+ return 1;
+ }
+
+ virFormatMacAddr(item->u.macaddr.addr, buf);
+ break;
+
+ case DATATYPE_UINT16:
+ if (snprintf(buf, bufsize, "%d",
+ item->u.u16) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for uint16 type"));
+ return 1;
+ }
+ break;
+
+ case DATATYPE_IPMASK:
+ case DATATYPE_UINT8:
+ if (snprintf(buf, bufsize, "%d",
+ item->u.u8) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for uint8 type"));
+ return 1;
+ }
+ break;
+
+ default:
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Unhandled datatype %x"), item->datatype);
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+
+static void
+ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
+{
+ if (!inst)
+ return;
+
+ VIR_FREE(inst->commandTemplate);
+ VIR_FREE(inst);
+}
+
+
+static int
+ebiptablesAddRuleInst(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ char *commandTemplate,
+ enum virNWFilterChainSuffixType neededChain,
+ char chainprefix,
+ unsigned int priority)
+{
+ ebiptablesRuleInstPtr inst;
+
+ if (VIR_ALLOC(inst) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ inst->commandTemplate = commandTemplate;
+ inst->neededProtocolChain = neededChain;
+ inst->chainprefix = chainprefix;
+ inst->priority = priority;
+
+ return virNWFilterRuleInstAddData(conn, res, inst);
+}
+
+
+static int
+ebtablesHandleEthHdr(virConnectPtr conn,
+ virBufferPtr buf,
+ virNWFilterHashTablePtr vars,
+ ethHdrDataDefPtr ethHdr)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -s %s %s",
+ ENTRY_GET_NEG_SIGN(&ethHdr->dataSrcMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataSrcMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -d %s %s",
+ ENTRY_GET_NEG_SIGN(&ethHdr->dataDstMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataDstMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ return 0;
+
+ err_exit:
+ virBufferFreeAndReset(buf);
+
+ return 1;
+}
+
+/*
+ * ebtablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @chainPrefix : The prefix to put in front of the name of the chain
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+ebtablesCreateRuleInstance(virConnectPtr conn,
+ char chainPrefix,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString(nwfilter->chainsuffix));
+
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.ethHdrFilter.ethHdr))
+ goto err_exit;
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ethHdrFilter.dataProtocolID))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " -p %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
+ number);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.arpHdrFilter.ethHdr))
+ goto err_exit;
+
+ virBufferAddLit(&buf, " -p arp");
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataHWType))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-htype %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataOpcode))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-opcode %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataProtocolType))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-ptype %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataARPSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-src %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataARPDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-dst %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataARPSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-src %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr),
+ macaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataARPDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-dst %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr),
+ macaddr);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.ipHdrFilter.ethHdr))
+ goto err_exit;
+
+ virBufferAddLit(&buf,
+ " -p ipv4");
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataSrcIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataDstIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataProtocolID))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-protocol %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataSrcPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataSrcPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataDstPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataDstPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDSCP)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataDSCP))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-tos %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP),
+ number);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+ break;
+ }
+
+ virBufferVSprintf(&buf,
+ " -j %s" CMD_DEF_POST CMD_SEPARATOR
+ CMD_EXEC,
+ virNWFilterJumpTargetTypeToString(rule->action));
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+
+ return ebiptablesAddRuleInst(conn,
+ res,
+ virBufferContentAndReset(&buf),
+ nwfilter->chainsuffix,
+ chainPrefix,
+ rule->priority);
+
+err_exit:
+ virBufferFreeAndReset(&buf);
+
+ return -1;
+}
+
+
+/*
+ * ebiptablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+ebiptablesCreateRuleInstance(virConnectPtr conn,
+ enum virDomainNetType nettype ATTRIBUTE_UNUSED,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ int rc = 0;
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_IN_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ if (rc)
+ return rc;
+ }
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_OUT_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ }
+ break;
+ }
+
+ return rc;
+}
+
+
+static int
+ebiptablesFreeRuleInstance(void *_inst)
+{
+ ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
+ return 0;
+}
+
+
+static int
+ebiptablesDisplayRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
+ void *_inst)
+{
+ ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
+ printf("Command Template: %s\nNeeded protocol: %s\n\n",
+ inst->commandTemplate,
+ virNWFilterChainSuffixTypeToString(inst->neededProtocolChain));
+ return 0;
+}
+
+
+/**
+ * ebiptablesWriteToTempFile:
+ * @conn: pointer to virConnect object
+ * @string : the string to write into the file
+ *
+ * Returns the tempory filename where the string was written into,
+ * NULL in case of error with the error reported.
+ *
+ * Write the string into a temporary file and return the name of
+ * the temporary file. The string is assumed to contain executable
+ * commands. A line '#!/bin/bash' will automatically be written
+ * as the first line in the file. The permissions of the file are
+ * set so that the file can be run as an executable script.
+ */
+static char *
+ebiptablesWriteToTempFile(virConnectPtr conn,
+ const char *string) {
+ char filename[] = "/tmp/virtdXXXXXX";
+ int len;
+ char *filnam;
+ const char header[] = "#!" BASH_CMD "\n";
+ size_t written;
+
+ int fd = mkstemp(filename);
+
+ if (fd < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot create temporary file"));
+ return NULL;
+ }
+
+ if (fchmod(fd, S_IXUSR| S_IRUSR | S_IWUSR) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot change permissions on temp. file"));
+ goto err_exit;
+ }
+
+ len = strlen(header);
+ written = safewrite(fd, header, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ len = strlen(string);
+ written = safewrite(fd, string, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ filnam = strdup(filename);
+ if (!filnam) {
+ virReportOOMError();
+ goto err_exit;
+ }
+
+ close(fd);
+ return filnam;
+
+err_exit:
+ close(fd);
+ unlink(filename);
+ return NULL;
+}
+
+
+/**
+ * ebiptablesExecCLI:
+ * @conn : pointer to virConnect object
+ * @buf : pointer to virBuffer containing the string with the commands to
+ * execute.
+ * @status: Pointer to an integer for returning the status of the
+ * commands executed via the script the was run.
+ *
+ * Returns 0 in case of success, != 0 in case of an error. The returned
+ * value is NOT the result of running the commands inside the bash
+ * script.
+ *
+ * Execute a sequence of commands (held in the given buffer) as a bash
+ * script and return the status of the execution.
+ */
+static int
+ebiptablesExecCLI(virConnectPtr conn,
+ virBufferPtr buf,
+ int *status)
+{
+ char *cmds;
+ char *filename;
+ int rc;
+ const char *argv[] = {NULL, NULL};
+
+ if (virBufferError(buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(buf);
+ return 1;
+ }
+
+ *status = 0;
+
+ cmds = virBufferContentAndReset(buf);
+
+ VIR_DEBUG("%s", cmds);
+
+ if (!cmds)
+ return 0;
+
+ filename = ebiptablesWriteToTempFile(conn, cmds);
+ VIR_FREE(cmds);
+
+ if (!filename)
+ return 1;
+
+ argv[0] = filename;
+ rc = virRun(argv, status);
+
+ *status >>= 8;
+
+ VIR_DEBUG("rc = %d, status = %d\n",rc, *status);
+
+ unlink(filename);
+
+ VIR_FREE(filename);
+
+ return rc;
+}
+
+
+static int
+ebtablesCreateTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE, chain,
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+ebtablesLinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char iodev = (incoming) ? 'i' : 'o';
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -%c %s -j %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix;
+ if (isTempChain)
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ else
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE, chain,
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesRemoveTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+_ebtablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char iodev = (incoming) ? 'i' : 'o';
+ char chainPrefix;
+
+ if (isTempChain) {
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ } else {
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+ }
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -%c %s -j %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesUnlinkRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesUnlinkTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+ebtablesCreateTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int stopOnError)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s"
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -p %s -j %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ CMD_STOPONERR(stopOnError),
+
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int isTempChain)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix;
+ if (isTempChain) {
+ chainPrefix =(incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ } else {
+ chainPrefix =(incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+ }
+
+ PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -p %s -j %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 0);
+}
+
+
+static int
+ebtablesRemoveSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveSubChain(conn, buf, 1, ifname, supported_protocols[i]);
+ ebtablesRemoveSubChain(conn, buf, 0, ifname, supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveTmpSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 1);
+}
+
+
+static int
+ebtablesRemoveTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveTmpSubChain(conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRemoveTmpSubChain(conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ if (protocol) {
+ PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
+ PRINT_CHAIN( chain, chainPrefix, ifname, protocol);
+ } else {
+ PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
+ PRINT_ROOT_CHAIN( chain, chainPrefix, ifname);
+ }
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -E %s %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ tmpchain,
+ chain);
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRenameTmpSubChain (conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRenameTmpSubChain (conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname)
+{
+ return ebtablesRenameTmpSubChain(conn, buf, incoming, ifname, NULL);
+}
+
+
+static void
+ebiptablesInstCommand(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *templ, char cmd, int pos,
+ int stopOnError)
+{
+ char position[10] = { 0 };
+ if (pos >= 0)
+ snprintf(position, sizeof(position), "%d", pos);
+ virBufferVSprintf(buf, templ, cmd, position);
+ virBufferVSprintf(buf, CMD_SEPARATOR "%s",
+ CMD_STOPONERR(stopOnError));
+}
+
+
+static int
+ebiptablesRuleOrderSort(const void *a, const void *b)
+{
+ const ebiptablesRuleInstPtr *insta = a;
+ const ebiptablesRuleInstPtr *instb = b;
+ return ((*insta)->priority - (*instb)->priority);
+}
+
+
+static int
+ebiptablesApplyRules(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst)
+{
+ int i;
+ int cli_status;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+ int chains_in = 0, chains_out = 0;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (inst)
+ qsort(inst, nruleInstances, sizeof(inst[0]),
+ ebiptablesRuleOrderSort);
+
+ for (i = 0; i < nruleInstances; i++) {
+ if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
+ chains_in |= (1 << inst[i]->neededProtocolChain);
+ else
+ chains_out |= (1 << inst[i]->neededProtocolChain);
+ }
+
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ if (chains_in != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "ipv4", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "ipv4", 1);
+
+ // keep arp as last
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "arp", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "arp", 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'A', -1, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ // FIXME: establishment of iptables user define table tree goes here
+
+ // END IPTABLES stuff
+
+ if (chains_in != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_ebsubchains_and_unlink;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRenameTmpSubChains(conn, &buf, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+
+tear_down_ebsubchains_and_unlink:
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+
+tear_down_tmpebchains:
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("Some rules could not be created."));
+
+ return 1;
+}
+
+
+/**
+ * ebiptablesRemoveRules:
+ * @conn : pointer to virConnect object
+ * @ifname : the name of the interface to which the rules apply
+ * @nRuleInstance : the number of given rules
+ * @_inst : array of rule instantiation data
+ *
+ * Remove all rules one after the other
+ *
+ * Return 0 on success, 1 if execution of one or more cleanup
+ * commands failed.
+ */
+static int
+ebiptablesRemoveRules(virConnectPtr conn,
+ const char *ifname ATTRIBUTE_UNUSED,
+ int nruleInstances,
+ void **_inst)
+{
+ int rc = 0;
+ int cli_status;
+ int i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'D', -1,
+ 0);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status))
+ goto err_exit;
+
+ if (cli_status) {
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("error while executing CLI commands"));
+ rc = 1;
+ }
+
+err_exit:
+ return rc;
+}
+
+
+/**
+ * ebiptablesAllTeardown:
+ * @ifname : the name of the interface to which the rules apply
+ *
+ * Unconditionally remove all possible user defined tables and rules
+ * that were created for the given interface (ifname).
+ *
+ * Always returns 0.
+ */
+static int
+ebiptablesAllTeardown(const char *ifname)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int cli_status;
+ virConnectPtr conn = NULL;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+}
+
+
+virNWFilterTechDriver ebiptables_driver = {
+ .name = EBIPTABLES_DRIVER_ID,
+
+ .createRuleInstance = ebiptablesCreateRuleInstance,
+ .applyRules = ebiptablesApplyRules,
+ .allTeardown = ebiptablesAllTeardown,
+ .removeRules = ebiptablesRemoveRules,
+ .freeRuleInstance = ebiptablesFreeRuleInstance,
+ .displayRuleInstance = ebiptablesDisplayRuleInstance,
+};
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
@@ -0,0 +1,656 @@
+/*
+ * nwfilter_gentech_driver.c: generic technology driver
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+
+#include "internal.h"
+
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "virterror_internal.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+
+#define NWFILTER_STD_VAR_MAC "MAC"
+
+
+static virNWFilterTechDriverPtr filter_tech_drivers[] = {
+ &ebiptables_driver,
+ NULL
+};
+
+
+virNWFilterTechDriverPtr
+virNWFilterTechDriverForName(const char *name) {
+ int i = 0;
+ while (filter_tech_drivers[i]) {
+ if (!strcmp(filter_tech_drivers[i]->name, name))
+ return filter_tech_drivers[i];
+ i++;
+ }
+ return NULL;
+}
+
+
+/**
+ * virNWFilterRuleInstAddData:
+ * @conn : pointer to virConnect object
+ * @res : pointer to virNWFilterRuleInst object collecting the instantiation
+ * data of a single firewall rule.
+ * @data : the opaque data that the driver wants to add
+ *
+ * Add instantiation data to a firewall rule. An instantiated firewall
+ * rule may hold multiple data structure representing its instantiation
+ * data. This may for example be the case if a rule has been defined
+ * for bidirectional traffic and data needs to be added to the incoming
+ * and outgoing chains.
+ *
+ * Returns 0 in case of success, 1 in case of an error with the error
+ * message attached to the virConnect object.
+ */
+int
+virNWFilterRuleInstAddData(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virNWFilterRuleInstPtr res,
+ void *data)
+{
+ if (VIR_REALLOC_N(res->data, res->ndata+1) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+ res->data[res->ndata++] = data;
+ return 0;
+}
+
+
+static void
+virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
+{
+ int i;
+ if (!inst)
+ return;
+
+ for (i = 0; i < inst->ndata; i++)
+ inst->techdriver->freeRuleInstance(inst->data[i]);
+
+ VIR_FREE(inst->data);
+ VIR_FREE(inst);
+}
+
+
+/**
+ * virNWFilterVarHashmapAddStdValues:
+ * @conn: Poijter to virConnect object
+ * @tables: pointer to hash tabel to add values to
+ * @macaddr: The string of the MAC address to add to the hash table,
+ * may be NULL
+ *
+ * Returns 0 in case of success, 1 in case an error happened with
+ * error having been reported.
+ *
+ * Adds a couple of standard keys (MAC, IP) to the hash table.
+ */
+static int
+virNWFilterVarHashmapAddStdValues(virConnectPtr conn,
+ virNWFilterHashTablePtr table,
+ char *macaddr)
+{
+ if (macaddr) {
+ if (virHashAddEntry(table->hashTable,
+ NWFILTER_STD_VAR_MAC,
+ macaddr) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Could not add variable 'MAC' to hashmap"));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * virNWFilterCreateVarHashmap:
+ * @conn: pointer to virConnect object
+ * @macaddr: pointer to string containing formatted MAC address of interface
+ *
+ * Create a hashmap used for evaluating the firewall rules. Initializes
+ * it with the standard variable 'MAC'.
+ *
+ * Returns pointer to hashmap, NULL if an error occcurred and error message
+ * is attached to the virConnect object.
+ */
+virNWFilterHashTablePtr
+virNWFilterCreateVarHashmap(virConnectPtr conn,
+ char *macaddr) {
+ virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
+ if (!table) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virNWFilterVarHashmapAddStdValues(conn, table, macaddr)) {
+ virNWFilterHashTableFree(table);
+ return NULL;
+ }
+ return table;
+}
+
+
+/**
+ * virNWFilterRuleInstantiate:
+ * @conn: pointer to virConnect object
+ * @techdriver: the driver to use for instantiation
+ * @filter: The filter the rule is part of
+ * @rule : The rule that is to be instantiated
+ * @ifname: The name of the interface
+ * @vars: map containing variable names and value used for instantiation
+ *
+ * Returns virNWFilterRuleInst object on success, NULL on error with
+ * error reported.
+ *
+ * Instantiate a single rule. Return a pointer to virNWFilterRuleInst
+ * object that will hold an array of driver-specific data resulting
+ * from the instantiation. Returns NULL on error with error reported.
+ */
+static virNWFilterRuleInstPtr
+virNWFilterRuleInstantiate(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars)
+{
+ int rc;
+ int i;
+ virNWFilterRuleInstPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->techdriver = techdriver;
+
+ rc = techdriver->createRuleInstance(conn, nettype, filter,
+ rule, ifname, vars, ret);
+
+ if (rc) {
+ for (i = 0; i < ret->ndata; i++)
+ techdriver->freeRuleInstance(ret->data[i]);
+ VIR_FREE(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * virNWFilterCreateVarsFrom:
+ * @conn: pointer to virConnect object
+ * @vars1: pointer to hash table
+ * @vars2: pointer to hash table
+ *
+ * Returns pointer to new hashtable or NULL in case of error with
+ * error already reported.
+ *
+ * Creates a new hash table with contents of var1 and var2 added where
+ * contents of var2 will overwrite those of var1.
+ */
+static virNWFilterHashTablePtr
+virNWFilterCreateVarsFrom(virConnectPtr conn,
+ virNWFilterHashTablePtr vars1,
+ virNWFilterHashTablePtr vars2)
+{
+ virNWFilterHashTablePtr res = virNWFilterHashTableCreate(0);
+ if (!res) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virNWFilterHashTablePutAll(conn, vars1, res))
+ goto err_exit;
+
+ if (virNWFilterHashTablePutAll(conn, vars2, res))
+ goto err_exit;
+
+ return res;
+
+err_exit:
+ virNWFilterHashTableFree(res);
+ return NULL;
+}
+
+
+/**
+ * _virNWFilterPoolInstantiateRec:
+ * @conn: pointer to virConnect object
+ * @techdriver: The driver to use for instantiation
+ * @filter: The filter to instantiate
+ * @ifname: The name of the interface to apply the rules to
+ * @vars: A map holding variable names and values used for instantiating
+ * the filter and its subfilters.
+ * @nEntries: number of virNWFilterInst objects collected
+ * @insts: pointer to array for virNWFilterIns object pointers
+ * @useNewFilter: instruct whether to use a newDef pointer rather than a
+ * def ptr which is useful during a filter update
+ * @foundNewFilter: pointer to int indivating whether a newDef pointer was
+ * ever used; variable expected to be initialized to 0 by caller
+ *
+ * Returns 0 on success, a value otherwise.
+ *
+ * Recursively instantiate a filter by instantiating the given filter along
+ * with all its subfilters in a depth-first traversal of the tree of
+ * referenced filters. The name of the interface to which the rules belong
+ * must be provided. Apply the values of variables as needed. Terminate with
+ * error when a referenced filter is missing or a variable could not be
+ * resolved -- among other reasons.
+ */
+static int
+_virNWFilterInstantiateRec(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ int *nEntries,
+ virNWFilterRuleInstPtr **insts,
+ enum instCase useNewFilter, int *foundNewFilter)
+{
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr obj;
+ int rc = 0;
+ int i;
+ virNWFilterRuleInstPtr inst;
+ virNWFilterDefPtr next_filter;
+
+ for (i = 0; i < filter->nentries; i++) {
+ virNWFilterRuleDefPtr rule = filter->filterEntries[i]->rule;
+ virNWFilterIncludeDefPtr inc = filter->filterEntries[i]->include;
+ if (rule) {
+ inst = virNWFilterRuleInstantiate(conn,
+ techdriver,
+ nettype,
+ filter,
+ rule,
+ ifname,
+ vars);
+ if (!inst) {
+ rc = 1;
+ break;
+ }
+
+ if (VIR_REALLOC_N(*insts, (*nEntries)+1) < 0) {
+ virReportOOMError();
+ rc = 1;
+ break;
+ }
+
+ (*insts)[(*nEntries)++] = inst;
+
+ } else if (inc) {
+ VIR_DEBUG("Instantiating filter %s\n", inc->filterref);
+ obj = virNWFilterPoolObjFindByName(&driver->pools,
+ inc->filterref);
+ if (obj) {
+
+ if (obj->wantRemoved) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Filter '%s' is in use."),
+ inc->filterref);
+ rc = 1;
+ virNWFilterPoolObjUnlock(obj);
+ break;
+ }
+
+ // create a temporary hashmap for depth-first tree traversal
+ virNWFilterHashTablePtr tmpvars =
+ virNWFilterCreateVarsFrom(conn,
+ inc->params,
+ vars);
+ if (!tmpvars) {
+ virReportOOMError();
+ rc = 1;
+ virNWFilterPoolObjUnlock(obj);
+ break;
+ }
+
+ next_filter = obj->def;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ if (obj->newDef) {
+ next_filter = obj->newDef;
+ *foundNewFilter = 1;
+ }
+ break;
+ case INSTANTIATE_ROLLBACK_NEWFILTER:
+ if (obj->newDef)
+ *foundNewFilter = 1;
+ break;
+ case INSTANTIATE_ALWAYS:
+ break;
+ }
+
+ rc = _virNWFilterInstantiateRec(conn,
+ techdriver,
+ nettype,
+ next_filter,
+ ifname,
+ tmpvars,
+ nEntries, insts,
+ useNewFilter,
+ foundNewFilter);
+
+ virNWFilterHashTableFree(tmpvars);
+
+ virNWFilterPoolObjUnlock(obj);
+ if (rc)
+ break;
+ } else {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("referenced filter '%s' is missing"),
+ inc->filterref);
+ rc = 1;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+
+static int
+virNWFilterRuleInstancesToArray(int nEntries,
+ virNWFilterRuleInstPtr *insts,
+ void ***ptrs,
+ int *nptrs)
+{
+ int i,j;
+
+ *nptrs = 0;
+
+ for (j = 0; j < nEntries; j++)
+ (*nptrs) += insts[j]->ndata;
+
+ if ((*nptrs) == 0)
+ return 0;
+
+ if (VIR_ALLOC_N((*ptrs), (*nptrs)) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ (*nptrs) = 0;
+
+ for (j = 0; j < nEntries; j++)
+ for (i = 0; i < insts[j]->ndata; i++)
+ (*ptrs)[(*nptrs)++] = insts[j]->data[i];
+
+ return 0;
+}
+
+
+/**
+ * virNWFilterInstantiate:
+ * @conn: pointer to virConnect object
+ * @techdriver: The driver to use for instantiation
+ * @filter: The filter to instantiate
+ * @ifname: The name of the interface to apply the rules to
+ * @vars: A map holding variable names and values used for instantiating
+ * the filter and its subfilters.
+ *
+ * Returns 0 on success, a value otherwise.
+ *
+ * Instantiate a filter by instantiating the filter itself along with
+ * all its subfilters in a depth-first traversal of the tree of referenced
+ * filters. The name of the interface to which the rules belong must be
+ * provided. Apply the values of variables as needed.
+ */
+static int
+virNWFilterInstantiate(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ enum instCase useNewFilter, int *foundNewFilter)
+{
+ int rc;
+ int j, nptrs;
+ int nEntries = 0;
+ virNWFilterRuleInstPtr *insts = NULL;
+ void **ptrs = NULL;
+ int instantiate = 1;
+
+ rc = _virNWFilterInstantiateRec(conn,
+ techdriver,
+ nettype,
+ filter,
+ ifname,
+ vars,
+ &nEntries, &insts,
+ useNewFilter, foundNewFilter);
+
+ if (rc)
+ goto err_exit;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_ROLLBACK_NEWFILTER:
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ instantiate = *foundNewFilter;
+ break;
+ case INSTANTIATE_ALWAYS:
+ instantiate = 1;
+ break;
+ }
+
+ if (instantiate) {
+
+ rc = virNWFilterRuleInstancesToArray(nEntries, insts,
+ &ptrs, &nptrs);
+ if (rc)
+ goto err_exit;
+
+ rc = techdriver->applyRules(conn, ifname, nptrs, ptrs);
+
+ VIR_FREE(ptrs);
+ }
+
+err_exit:
+
+ for (j = 0; j < nEntries; j++)
+ virNWFilterRuleInstFree(insts[j]);
+
+ VIR_FREE(insts);
+
+ return rc;
+}
+
+
+static int
+_virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net,
+ enum instCase useNewFilter)
+{
+ int rc;
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterTechDriverPtr techdriver;
+ virNWFilterPoolObjPtr obj;
+ virNWFilterHashTablePtr vars, vars1;
+ virNWFilterDefPtr filter;
+ char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
+ int foundNewFilter = 0;
+ char *str_macaddr = NULL;
+
+ techdriver = virNWFilterTechDriverForName(drvname);
+
+ if (!techdriver) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+ return 1;
+ }
+
+ VIR_DEBUG("filter name: %s\n", net->filter);
+
+ obj = virNWFilterPoolObjFindByName(&driver->pools, net->filter);
+ if (!obj) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Could not find filter '%s'"),
+ net->filter);
+ return 1;
+ }
+
+ if (obj->wantRemoved) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Filter '%s' is in use."),
+ net->filter);
+ rc = 1;
+ goto err_exit;
+ }
+
+ virFormatMacAddr(net->mac, vmmacaddr);
+ str_macaddr = strdup(vmmacaddr);
+ if (!str_macaddr) {
+ virReportOOMError();
+ rc = 1;
+ goto err_exit;
+ }
+
+ vars1 = virNWFilterCreateVarHashmap(conn,
+ str_macaddr);
+ if (!vars1) {
+ rc = 1;
+ goto err_exit;
+ }
+
+ str_macaddr = NULL;
+
+ vars = virNWFilterCreateVarsFrom(conn,
+ vars1,
+ net->filterparams);
+ if (!vars) {
+ rc = 1;
+ goto err_exit_vars1;
+ }
+
+ filter = obj->def;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ if (obj->newDef) {
+ filter = obj->newDef;
+ foundNewFilter = 1;
+ }
+ break;
+
+ case INSTANTIATE_ROLLBACK_NEWFILTER:
+ if (obj->newDef)
+ foundNewFilter = 1;
+ break;
+
+ case INSTANTIATE_ALWAYS:
+ break;
+ }
+
+ rc = virNWFilterInstantiate(conn,
+ techdriver,
+ net->type,
+ filter,
+ net->ifname,
+ vars,
+ useNewFilter, &foundNewFilter);
+
+ virNWFilterHashTableFree(vars);
+
+err_exit_vars1:
+ virNWFilterHashTableFree(vars1);
+
+err_exit:
+
+ virNWFilterPoolObjUnlock(obj);
+
+ VIR_FREE(str_macaddr);
+
+ return rc;
+}
+
+
+int
+virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ INSTANTIATE_ALWAYS);
+}
+
+
+int
+virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ INSTANTIATE_FOLLOW_NEWFILTER);
+}
+
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ INSTANTIATE_ROLLBACK_NEWFILTER);
+}
+
+
+int
+virNWFilterTeardownFilter(const virDomainNetDefPtr net)
+{
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterTechDriverPtr techdriver;
+ techdriver = virNWFilterTechDriverForName(drvname);
+
+ if (!techdriver) {
+#if 0
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+#endif
+ return 1;
+ }
+
+ techdriver->allTeardown(net->ifname);
+
+ return 0;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
@@ -0,0 +1,52 @@
+/*
+ * nwfilter_gentech_driver.h: generic technology driver include file
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+#ifndef __NWFILTER_GENTECH_DRIVER_H
+#define __NWFILTER_GENTECH_DRIVER_H
+
+virNWFilterTechDriverPtr virNWFilterTechDriverForName(const char *name);
+
+int virNWFilterRuleInstAddData(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ void *data);
+
+
+enum instCase {
+ INSTANTIATE_ALWAYS,
+ INSTANTIATE_FOLLOW_NEWFILTER,
+ INSTANTIATE_ROLLBACK_NEWFILTER,
+};
+
+
+int virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+
+int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
+
+virNWFilterHashTablePtr virNWFilterCreateVarHashmap(virConnectPtr conn,
+ char *macaddr);
+
+#endif
Index: libvirt-acl/daemon/libvirtd.c
===================================================================
--- libvirt-acl.orig/daemon/libvirtd.c
+++ libvirt-acl/daemon/libvirtd.c
@@ -96,6 +96,9 @@
# ifdef WITH_SECRETS
# include "secret/secret_driver.h"
# endif
+# ifdef WITH_NWFILTER
+# include "nwfilter/nwfilter_driver.h"
+# endif
#endif


@@ -876,6 +879,7 @@ static struct qemud_server *qemudInitial
virDriverLoadModule("lxc");
virDriverLoadModule("uml");
virDriverLoadModule("one");
+ virDriverLoadModule("nwfilter");
#else
# ifdef WITH_NETWORK
networkRegister();
@@ -892,6 +896,9 @@ static struct qemud_server *qemudInitial
# ifdef WITH_SECRETS
secretRegister();
# endif
+# ifdef WITH_NWFILTER
+ nwfilterRegister();
+# endif
# ifdef WITH_QEMU
qemuRegister();
# endif
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
@@ -0,0 +1,41 @@
+/*
+ * nwfilter_ebiptables_driver.h: ebtables/iptables driver support
+ *
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+#ifndef VIR_NWFILTER_EBTABLES_DRIVER_H__
+#define VIR_NWFILTER_EBTABLES_DRIVER_H__
+
+#define MAX_CHAINNAME_LENGTH 32 /* see linux/netfilter_bridge/ebtables.h */
+
+typedef struct _ebiptablesRuleInst ebiptablesRuleInst;
+typedef ebiptablesRuleInst *ebiptablesRuleInstPtr;
+struct _ebiptablesRuleInst {
+ char *commandTemplate;
+ enum virNWFilterChainSuffixType neededProtocolChain;
+ char chainprefix; // I for incoming, O for outgoing
+ unsigned int priority;
+};
+
+extern virNWFilterTechDriver ebiptables_driver;
+
+#define EBIPTABLES_DRIVER_ID "ebiptables"
+
+#endif
Index: libvirt-acl/python/generator.py
===================================================================
--- libvirt-acl.orig/python/generator.py
+++ libvirt-acl/python/generator.py
@@ -170,6 +170,7 @@ skipped_types = {
# 'int *': "usually a return type",
'virConnectDomainEventCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
+ 'virNWFilterPtr': "No function types in python",
}

#######################################################################
@@ -268,6 +269,7 @@ skip_impl = (
'virConnectListStorageVols',
'virConnectListDefinedStorageVols',
'virConnectListDefinedInterfaces',
+ 'virConnectListNWFilters',
'virConnGetLastError',
'virGetLastError',
'virDomainGetInfo',
Index: libvirt-acl/src/conf/nwfilter_params.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_params.c
@@ -0,0 +1,318 @@
+/*
+ * nwfilter_params.c: parsing and data maintenance of filter parameters
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <regex.h>
+
+#include "internal.h"
+
+#include "memory.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "nwfilter_params.h"
+#include "domain_conf.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+/*
+ * regular expressions for parameter names and values
+ */
+static regex_t regex_nam;
+static regex_t regex_val;
+
+
+static void
+hashDealloc(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+ VIR_FREE(payload);
+}
+
+
+/**
+ * virNWFilterHashTablePut:
+ * @table: Pointer to a virNWFilterHashTable
+ * @name: name of the key to enter
+ * @val: The value associated with the key
+ * @freeName: Whether the name must be freed on table destruction
+ *
+ * Returns 0 on success, 1 on failure.
+ *
+ * Put an entry into the hashmap replacing and freeing an existing entry
+ * if one existed.
+ */
+int
+virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+ const char *name,
+ char *val,
+ int copyName)
+{
+ if (!virHashLookup(table->hashTable, name)) {
+ if (copyName) {
+ name = strdup(name);
+ if (!name)
+ return 1;
+
+ if (VIR_REALLOC_N(table->names, table->nNames + 1) < 0) {
+ VIR_FREE(name);
+ return 1;
+ }
+ table->names[table->nNames++] = (char *)name;
+ }
+
+ if (virHashAddEntry(table->hashTable, name, val) != 0) {
+ if (copyName) {
+ VIR_FREE(name);
+ table->nNames--;
+ }
+ return 1;
+ }
+ } else {
+ if (virHashUpdateEntry(table->hashTable, name, val, hashDealloc) != 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * virNWFilterHashTableFree:
+ * @table: Pointer to virNWFilterHashTable
+ *
+ * Free a hashtable de-allocating memory for all its entries.
+ *
+ * All hash tables within the NWFilter driver must use this
+ * function to deallocate and free their content.
+ */
+void
+virNWFilterHashTableFree(virNWFilterHashTablePtr table)
+{
+ int i;
+ if (!table)
+ return;
+ virHashFree(table->hashTable, hashDealloc);
+
+ for (i = 0; i < table->nNames; i++)
+ VIR_FREE(table->names[i]);
+ VIR_FREE(table->names);
+ VIR_FREE(table);
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterHashTableCreate(int n) {
+ virNWFilterHashTablePtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ ret->hashTable = virHashCreate(n);
+ if (!ret->hashTable) {
+ virReportOOMError();
+ VIR_FREE(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+
+int
+virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr ht,
+ const char *entry)
+{
+ int i;
+ int rc = virHashRemoveEntry(ht->hashTable, entry, hashDealloc);
+
+ if (rc == 0) {
+ for (i = 0; i < ht->nNames; i++) {
+ if (STREQ(ht->names[i], entry)) {
+ VIR_FREE(ht->names[i]);
+ ht->names[i] = ht->names[--ht->nNames];
+ ht->names[ht->nNames] = NULL;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+
+struct addToTableStruct {
+ virNWFilterHashTablePtr target;
+ int errOccurred;
+ virConnectPtr conn;
+};
+
+
+static void
+addToTable(void *payload, const char *name, void *data)
+{
+ struct addToTableStruct *atts = (struct addToTableStruct *)data;
+ char *val;
+
+ if (atts->errOccurred)
+ return;
+
+ val = strdup((char *)payload);
+ if (!val) {
+ virReportOOMError();
+ atts->errOccurred = 1;
+ return;
+ }
+
+ if (virNWFilterHashTablePut(atts->target, name, val, 1) != 0) {
+ virNWFilterReportError(atts->conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not put variable '%s' into hashmap"),
+ name);
+ atts->errOccurred = 1;
+ VIR_FREE(val);
+ }
+}
+
+
+int
+virNWFilterHashTablePutAll(virConnectPtr conn,
+ virNWFilterHashTablePtr src,
+ virNWFilterHashTablePtr dest)
+{
+ struct addToTableStruct atts = {
+ .target = dest,
+ .errOccurred = 0,
+ .conn = conn,
+ };
+
+ virHashForEach(src->hashTable, addToTable, &atts);
+ if (atts.errOccurred)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ return 1;
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterParseParamAttributes(xmlNodePtr cur)
+{
+ char *nam, *val;
+
+ virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
+ if (!table) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ cur = cur->children;
+
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameter")) {
+ nam = virXMLPropString(cur, "name");
+ val = virXMLPropString(cur, "value");
+ if (nam != NULL && val != NULL) {
+ if (regexec(&regex_nam, nam, 0, NULL, 0) != 0)
+ goto skip_entry;
+ if (regexec(&regex_val, val, 0, NULL, 0) != 0)
+ goto skip_entry;
+ if (virNWFilterHashTablePut(table, nam, val, 1)) {
+ VIR_FREE(nam);
+ VIR_FREE(val);
+ virNWFilterHashTableFree(table);
+ return NULL;
+ }
+ val = NULL;
+ }
+skip_entry:
+ VIR_FREE(nam);
+ VIR_FREE(val);
+ }
+ }
+ cur = cur->next;
+ }
+ return table;
+}
+
+
+struct formatterParam {
+ virBufferPtr buf;
+ const char *indent;
+};
+
+
+static void
+_formatParameterAttrs(void *payload, const char *name, void *data)
+{
+ struct formatterParam *fp = (struct formatterParam *)data;
+
+ virBufferVSprintf(fp->buf, "%s<parameter name='%s' value='%s'/>\n",
+ fp->indent,
+ name,
+ (char *)payload);
+}
+
+
+char *
+virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+ const char *indent)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ struct formatterParam fp = {
+ .buf = &buf,
+ .indent = indent,
+ };
+
+ virHashForEach(table->hashTable, _formatParameterAttrs, &fp);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+
+int virNWFilterParamConfLayerInit(void) {
+
+ if (regcomp(&regex_nam, "^[a-zA-Z0-9_]+$" ,
+ REG_NOSUB|REG_EXTENDED) != 0)
+ return 1;
+
+ if (regcomp(&regex_val, "^[a-zA-Z0-9_.:]+$",
+ REG_NOSUB|REG_EXTENDED) != 0) {
+ regfree(&regex_nam);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void virNWFilterParamConfLayerShutdown(void) {
+ regfree(&regex_nam);
+ regfree(&regex_val);
+}
Index: libvirt-acl/src/conf/nwfilter_params.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_params.h
@@ -0,0 +1,53 @@
+/*
+ * nwfilter_params.h: parsing and data maintenance of filter parameters
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <***@us.ibm.com>
+ */
+#ifndef NWFILTER_PARAMS_H
+#define NWFILTER_PARAMS_H
+
+#include "hash.h"
+
+typedef struct _virNWFilterHashTable virNWFilterHashTable;
+typedef virNWFilterHashTable *virNWFilterHashTablePtr;
+struct _virNWFilterHashTable {
+ virHashTablePtr hashTable;
+
+ int nNames;
+ char **names;
+};
+
+
+virNWFilterHashTablePtr virNWFilterParseParamAttributes(xmlNodePtr cur);
+char * virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+ const char *indent);
+
+virNWFilterHashTablePtr virNWFilterHashTableCreate(int n);
+void virNWFilterHashTableFree(virNWFilterHashTablePtr table);
+int virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+ const char *name,
+ char *val,
+ int freeName);
+int virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table,
+ const char *name);
+int virNWFilterHashTablePutAll(virConnectPtr conn,
+ virNWFilterHashTablePtr src,
+ virNWFilterHashTablePtr dest);
+
+#endif /* NWFILTER_PARAMS_H */
Daniel P. Berrange
2010-03-25 15:49:05 UTC
Permalink
Post by s***@us.ibm.com
+/*
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+ebtablesCreateRuleInstance(virConnectPtr conn,
+ char chainPrefix,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do paranoid
validation on the 'chain' and 'ifname' fields, since they ultimately come
from the user specified XML. Validate that it only contains a-Z, 0-0, -, _


It would also be nice to put a variety of XML files in a tests/nwfilterdata
directory and making a test suite to run the parser API against them, as
well as adding some real world examples in the examples/nwfilter directory
for end users to start from.

Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 15:59:11 UTC
Permalink
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
+/*
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString
(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do paranoid
validation on the 'chain' and 'ifname' fields, since they ultimately come
from the user specified XML. Validate that it only contains a-Z, 0-0, -, _
Actually the user specified XML only currently allows the chain names
'arp',
'ipv4', 'ipv6' and 'root'. Others will already be rejected when parsing
the filter.

With the interface names I was assuming that at the point where this part
here
gets called is already well after the establishment of tap interfaces and
the
net->ifname contains valid values otherwise the creation of the tap or
macvtap
would have blown earlier.
It would also be nice to put a variety of XML files in a
tests/nwfilterdata
directory and making a test suite to run the parser API against them, as
well as adding some real world examples in the examples/nwfilter directory
for end users to start from.
In the v4 patch series I am adding filters to examples/xml/nwfilter that
are
automatically copied to /etc/libvirt/nwfilter for libvirt to pick up.

Gerhard has written a couple of test cases but they are for the external
test suite from what I know. So, yes, we'll add test cases over time.

Regards,
Stefan
Regards,
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 16:26:34 UTC
Permalink
Post by Stefan Berger
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
+/*
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString
(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do paranoid
validation on the 'chain' and 'ifname' fields, since they ultimately come
from the user specified XML. Validate that it only contains a-Z, 0-0, -, _
Actually the user specified XML only currently allows the chain names
'arp',
Post by Stefan Berger
'ipv4', 'ipv6' and 'root'. Others will already be rejected when
parsing the filter.
Actually, yes, there's a problem with target device names like t\"t that
do create an
interface named t\"t but end up creating an ebtables entry with interface
t"t. So
if I don't go through bash it works correctly, otherwise it does not and I
guess I
would need to escape the '\' with '\\\'.

Stefan
Post by Stefan Berger
It would also be nice to put a variety of XML files in a
tests/nwfilterdata
Post by Stefan Berger
directory and making a test suite to run the parser API against them, as
well as adding some real world examples in the examples/nwfilter directory
for end users to start from.
In the v4 patch series I am adding filters to examples/xml/nwfilter that
are
Post by Stefan Berger
automatically copied to /etc/libvirt/nwfilter for libvirt to pick up.
Gerhard has written a couple of test cases but they are for the external
test suite from what I know. So, yes, we'll add test cases over time.
Regards,
Stefan
Regards,
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/
berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o- http://
deltacloud.org:|
|: http://autobuild.org -o- http://search.cpan.org/
~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742
7D3B 9505 :|--
libvir-list mailing list
https://www.redhat.com/mailman/listinfo/libvir-list
Daniel P. Berrange
2010-03-25 16:40:15 UTC
Permalink
Post by Stefan Berger
Post by Stefan Berger
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
+/*
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString
(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do paranoid
validation on the 'chain' and 'ifname' fields, since they ultimately
come
Post by Stefan Berger
from the user specified XML. Validate that it only contains a-Z, 0-0,
-, _
Post by Stefan Berger
Actually the user specified XML only currently allows the chain names
'arp',
Post by Stefan Berger
'ipv4', 'ipv6' and 'root'. Others will already be rejected when
parsing the filter.
Actually, yes, there's a problem with target device names like t\"t that
do create an
interface named t\"t but end up creating an ebtables entry with interface
t"t. So
if I don't go through bash it works correctly, otherwise it does not and I
guess I
would need to escape the '\' with '\\\'.
Such interface names are insane & we should just refuse them, rather than
trying todo escaping :-)

Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Stefan Berger
2010-03-25 16:44:42 UTC
Permalink
Please respond to "Daniel P. Berrange"
Post by Stefan Berger
Post by Stefan Berger
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
+/*
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString
(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do paranoid
validation on the 'chain' and 'ifname' fields, since they ultimately
come
Post by Stefan Berger
from the user specified XML. Validate that it only contains a-Z, 0-0,
-, _
Post by Stefan Berger
Actually the user specified XML only currently allows the chain names
'arp',
Post by Stefan Berger
'ipv4', 'ipv6' and 'root'. Others will already be rejected when
parsing the filter.
Actually, yes, there's a problem with target device names like t\"t that
do create an
interface named t\"t but end up creating an ebtables entry with interface
t"t. So
if I don't go through bash it works correctly, otherwise it does not and I
guess I
would need to escape the '\' with '\\\'.
Such interface names are insane & we should just refuse them, rather than
trying todo escaping :-)
Right, but at what level should they be refused? When such names are
parsed ?

I do have a patch that does away with as much of the external scripting as
possible
and there I don't see that problem anymore when going directly through
virRun().
I wrote that patch on top of the others and would submit it as a separate
patch in
the series.

Stefan
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o-
http://deltacloud.org:|
|: http://autobuild.org -o-
http://search.cpan.org/~danberr/:|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Daniel P. Berrange
2010-03-25 17:05:52 UTC
Permalink
Please respond to "Daniel P. Berrange"
11:49:05
Post by Stefan Berger
Post by Stefan Berger
Please respond to "Daniel P. Berrange"
Post by s***@us.ibm.com
+/*
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString
(nwfilter->chainsuffix));
Since we're passing this into the shell, I think we should do
paranoid
Post by Stefan Berger
Post by Stefan Berger
validation on the 'chain' and 'ifname' fields, since they
ultimately
Post by Stefan Berger
come
Post by Stefan Berger
from the user specified XML. Validate that it only contains a-Z,
0-0,
Post by Stefan Berger
-, _
Post by Stefan Berger
Actually the user specified XML only currently allows the chain
names
Post by Stefan Berger
'arp',
Post by Stefan Berger
'ipv4', 'ipv6' and 'root'. Others will already be rejected when
parsing the filter.
Actually, yes, there's a problem with target device names like t\"t
that
Post by Stefan Berger
do create an
interface named t\"t but end up creating an ebtables entry with
interface
Post by Stefan Berger
t"t. So
if I don't go through bash it works correctly, otherwise it does not
and I
Post by Stefan Berger
guess I
would need to escape the '\' with '\\\'.
Such interface names are insane & we should just refuse them, rather
than
trying todo escaping :-)
Right, but at what level should they be refused? When such names are
parsed ?
We should likely refuse it in the src/conf/domain_conf.c parser


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Daniel P. Berrange
2010-03-25 11:37:14 UTC
Permalink
One comment about the instantiation of the rules: Since the XML allows
to create nearly any possible combination of parameters to ebtables or
iptables commands, I haven't used the ebtables or iptables wrappers.
Instead, I am writing ebtables/iptables command into a buffer, add
command line options to each one of them as described in the rule's XML,
write the buffer into a file and run it as a script. For those commands
that are not allowed to fail I am using the following format to run
cmd="ebtables <some options>"
r=`${cmd}`
if [ $? -ne 0 ]; then
echo "Failure in command ${cmd}."
exit 1
fi
cmd="..."
[...]
If one of the command fails in such a batch, the libvirt code is going
pick up the error code '1', tear down anything previously established
and report an error back. The actual error message shown above is
currently not reported back, but can be later on with some changes to
the commands running external programs that need to read the script's
stdout.
I've tried out this patch series, but not entirely sure whether it is
working correctly, since there are lots of errors in the libvirt debug
logs.

I have a guest

<interface type='network'>
<mac address='52:54:00:4d:c8:5f'/>
<source network='default'/>
<filterref filter='demofilter4'>
<parameter name='IP' value='9.59.241.151'/>
</filterref>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</interface>

And demofilter4 is setup as:

<filter name='demofilter4' chain='root'>
<uuid>d33d17bf-0198-6b89-0b03-55abba1eae7f</uuid>
<filterref filter='no-mac-spoofing'/>
<filterref filter='no-mac-broadcast'/>
<filterref filter='no-arp-spoofing'/>
<filterref filter='allow-dhcp'>
<parameter name='DHCPSERVER' value='10.0.0.1'/>
</filterref>
</filter>

The filter it references here are the XML examples you sent out previously

The guest starts without error, and I get a lot of things in the ebtables
'nat' table, but nothing in the 'filter' table - is that expected ?

# ebtables -t nat -L
Bridge table: nat

Bridge chain: PREROUTING, entries: 1, policy: ACCEPT
-i vnet0 -j I-vnet0

Bridge chain: OUTPUT, entries: 0, policy: ACCEPT

Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT
-o vnet0 -j O-vnet0

Bridge chain: I-vnet0, entries: 2, policy: ACCEPT
-p IPv4 -j I-vnet0-ipv4
-p ARP -j I-vnet0-arp

Bridge chain: O-vnet0, entries: 2, policy: ACCEPT
-p IPv4 -j O-vnet0-ipv4
-p ARP -j O-vnet0-arp

Bridge chain: I-vnet0-ipv4, entries: 3, policy: ACCEPT
-s ! 52:54:0:4d:c8:5f -j DROP
-p IPv4 --ip-src 0.0.0.0 --ip-dst 255.255.255.255 --ip-proto udp --ip-sport 68 --ip-dport 67 -j ACCEPT
-d Broadcast -j DROP

Bridge chain: O-vnet0-ipv4, entries: 1, policy: ACCEPT
-p IPv4 --ip-src 10.0.0.1 --ip-proto udp --ip-sport 67 --ip-dport 68 -j ACCEPT

Bridge chain: I-vnet0-arp, entries: 5, policy: ACCEPT
-p ARP --arp-mac-src ! 52:54:0:4d:c8:5f -j DROP
-p ARP --arp-ip-src ! 9.59.241.151 -j DROP
-p ARP --arp-op Request -j ACCEPT
-p ARP --arp-op Reply -j ACCEPT
-j DROP

Bridge chain: O-vnet0-arp, entries: 5, policy: ACCEPT
-p ARP --arp-op Reply --arp-mac-dst ! 52:54:0:4d:c8:5f -j DROP
-p ARP --arp-ip-dst ! 9.59.241.151 -j DROP
-p ARP --arp-op Request -j ACCEPT
-p ARP --arp-op Reply -j ACCEPT
-j DROP



The libvirt logs show a bunch of shell erorrs - see the attachment to this
mail. Are these errors to be expected, or are they actual errors ?


Also, I'm wondering if it is possible to include 'libvirt-' in the custom
ebtables/iptables chains that we create ? I think that would be useful
for sysadmins who might be surprised at where all these rules are coming
Stefan Berger
2010-03-25 12:26:42 UTC
Permalink
Please respond to "Daniel P. Berrange"
One comment about the instantiation of the rules: Since the XML allows
to create nearly any possible combination of parameters to ebtables or
iptables commands, I haven't used the ebtables or iptables wrappers.
Instead, I am writing ebtables/iptables command into a buffer, add
command line options to each one of them as described in the rule's XML,
write the buffer into a file and run it as a script. For those commands
that are not allowed to fail I am using the following format to run
cmd="ebtables <some options>"
r=`${cmd}`
if [ $? -ne 0 ]; then
echo "Failure in command ${cmd}."
exit 1
fi
cmd="..."
[...]
If one of the command fails in such a batch, the libvirt code is going
pick up the error code '1', tear down anything previously established
and report an error back. The actual error message shown above is
currently not reported back, but can be later on with some changes to
the commands running external programs that need to read the script's
stdout.
I've tried out this patch series, but not entirely sure whether it is
working correctly, since there are lots of errors in the libvirt debug
logs.
The errors in the debugging log are due to attempts to cleanup
user-defined tables
that do not exist. Though attempting to clean them up gets the system into
a well
known start state. The errors could be avoided with a sequence of checking
for
existence of the user-defined chain first and then try to flush and delete
them,
but it's faster not to do so.
I have a guest
<interface type='network'>
<mac address='52:54:00:4d:c8:5f'/>
<source network='default'/>
<filterref filter='demofilter4'>
<parameter name='IP' value='9.59.241.151'/>
</filterref>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</interface>
<filter name='demofilter4' chain='root'>
<uuid>d33d17bf-0198-6b89-0b03-55abba1eae7f</uuid>
<filterref filter='no-mac-spoofing'/>
<filterref filter='no-mac-broadcast'/>
<filterref filter='no-arp-spoofing'/>
<filterref filter='allow-dhcp'>
<parameter name='DHCPSERVER' value='10.0.0.1'/>
</filterref>
</filter>
The filter it references here are the XML examples you sent out previously
The guest starts without error, and I get a lot of things in the ebtables
'nat' table, but nothing in the 'filter' table - is that expected ?
Yes, this is correct. The nat table handles the filtering correctly and
with the
PREROUTING chain we can filter for traffic coming from the VM (that
becomes
incoming to the host - prefix letter 'I') and in the POSTROUTING chain
traffic going to the VM (outgoing from the host - prefix letter 'O').
# ebtables -t nat -L
Bridge table: nat
Bridge chain: PREROUTING, entries: 1, policy: ACCEPT
-i vnet0 -j I-vnet0
Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT
-o vnet0 -j O-vnet0
Bridge chain: I-vnet0, entries: 2, policy: ACCEPT
-p IPv4 -j I-vnet0-ipv4
-p ARP -j I-vnet0-arp
Bridge chain: O-vnet0, entries: 2, policy: ACCEPT
-p IPv4 -j O-vnet0-ipv4
-p ARP -j O-vnet0-arp
Bridge chain: I-vnet0-ipv4, entries: 3, policy: ACCEPT
-s ! 52:54:0:4d:c8:5f -j DROP
-p IPv4 --ip-src 0.0.0.0 --ip-dst 255.255.255.255 --ip-proto udp --
ip-sport 68 --ip-dport 67 -j ACCEPT
-d Broadcast -j DROP
Bridge chain: O-vnet0-ipv4, entries: 1, policy: ACCEPT
-p IPv4 --ip-src 10.0.0.1 --ip-proto udp --ip-sport 67 --ip-dport 68-j
ACCEPT
Bridge chain: I-vnet0-arp, entries: 5, policy: ACCEPT
-p ARP --arp-mac-src ! 52:54:0:4d:c8:5f -j DROP
-p ARP --arp-ip-src ! 9.59.241.151 -j DROP
-p ARP --arp-op Request -j ACCEPT
-p ARP --arp-op Reply -j ACCEPT
-j DROP
Bridge chain: O-vnet0-arp, entries: 5, policy: ACCEPT
-p ARP --arp-op Reply --arp-mac-dst ! 52:54:0:4d:c8:5f -j DROP
-p ARP --arp-ip-dst ! 9.59.241.151 -j DROP
-p ARP --arp-op Request -j ACCEPT
-p ARP --arp-op Reply -j ACCEPT
-j DROP
The libvirt logs show a bunch of shell erorrs - see the attachment to this
mail. Are these errors to be expected, or are they actual errors ?
They are due to attempted cleanups that try to cleanup user-defined tables
that did not exist on your system,
however. As said, this gets the system into a well known start-out state
so that those user-defined ebtables
tables can be established with rules. As seen above, every interface gets
a 'tree' of user-defined tables.
Following the chain identifier in the above XML

<filter name='demofilter4' chain='root'>
<uuid>d33d17bf-0198-6b89-0b03-55abba1eae7f</uuid>
[...]

which can be either left out entirely for meaning of 'root', or be 'root'
explicitly or have the values 'arp' or 'ipv4'.

The patterns of the user-defined ebtables tables is due to 32 byte size
restrictions (including trailing 0) as follows:

<one letter prefix>-<name of the interface>-<filter chain identifier>:

This then leads to

I-vnet0 and
I-vnet0-ipv4 etc.

as shown above.

However, the tricky part are updates of filters. You can, using
virsh-define, update any filter while it is being used by running
VMs. For updates I decided not to compare the current filter tree against
the new one, calculating 'diffs'
for the rules and remove rules that don't exist in the new one along with
user defined tables that may not exist anymore
etc., which would be much more complicated. Instead, I am completely
rebuilding the filter tree. So, a temporary filter
tree is established with user-defined names following the above pattern
while the current filter tree is still active.
However, the prefixes are different. So the temporary filter tree would
have user-defined tables named

J-vnet0 and
J-vnet0-ipv4 etc.

where all the rules are established. Then, while the 'old' filter tree is
active, the new one is anchored, leading to
entries like this one:

Bridge chain: PREROUTING, entries: 1, policy: ACCEPT
-i vnet0 -j I-vnet0
-i vnet0 -j J-vnet0


Yes, temporarily you would have two parallel filter trees for an
interface, but the old one is still active. Then
comes the switch-over to the new tree where the old filter tree is
un-anchored, leading to this situation:

Bridge chain: PREROUTING, entries: 1, policy: ACCEPT
-i vnet0 -j J-vnet0

Now all possible chains starting with prefix I-vnet0-<XYZ> are flushed and
deleted.
In the subsequent step I rename the filter tree starting with
J-<vnet0>-<XYZ> to I-<vnet0>-<XYZ> leading to

Bridge chain: PREROUTING, entries: 1, policy: ACCEPT
-i vnet0 -j I-vnet0

which is where we want to be so that the next update can do the same
procedure again.

I have made some changes to the core patch (part 11) that split up the
application of new filter rules into
3 different (interface) functions, for application of new rules, switch
over + tear down of old, or
tear down of new in case an error happened.
Also, I'm wondering if it is possible to include 'libvirt-' in the custom
ebtables/iptables chains that we create ? I think that would be useful
for sysadmins who might be surprised at where all these rules are coming
Daniel P. Berrange
2010-03-25 14:57:39 UTC
Permalink
Post by Stefan Berger
Post by Daniel P. Berrange
The libvirt logs show a bunch of shell erorrs - see the attachment to
this
Post by Daniel P. Berrange
mail. Are these errors to be expected, or are they actual errors ?
They are due to attempted cleanups that try to cleanup user-defined tables
that did not exist on your system,
however. As said, this gets the system into a well known start-out state
so that those user-defined ebtables
tables can be established with rules. As seen above, every interface gets
a 'tree' of user-defined tables.
Ok, thanks for the confirming that's operating normally


Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Continue reading on narkive:
Loading...