]> xenbits.xensource.com Git - libvirt.git/commitdiff
New ebtables module wrapper
authorGerhard Stenzel <gstenzel@linux.vnet.ibm.com>
Tue, 3 Nov 2009 22:11:01 +0000 (23:11 +0100)
committerDaniel Veillard <veillard@redhat.com>
Tue, 3 Nov 2009 22:44:48 +0000 (23:44 +0100)
* configure.in: look for ebtables binary location if present
* src/Makefile.am: add the new module
* src/util/ebtables.[ch]: new module and internal APIs around
  the ebtables binary
* src/libvirt_private.syms: export the symbols only internally

configure.in
src/Makefile.am
src/libvirt_private.syms
src/util/ebtables.c [new file with mode: 0644]
src/util/ebtables.h [new file with mode: 0644]

index b7d0d7b29e5dcba99b6c950daa5481c60fc3fc31..7afbc7c798ac7e592a86796523c9734bdd9b4cf8 100644 (file)
@@ -287,6 +287,9 @@ fi
 AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
 AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
 
+AC_PATH_PROG([EBTABLES_PATH], [ebtables], /sbin/ebtables, [/usr/sbin:$PATH])
+AC_DEFINE_UNQUOTED([EBTABLES_PATH], "$EBTABLES_PATH", [path to ebtables binary])
+
 if test "$with_openvz" = "yes"; then
     AC_DEFINE_UNQUOTED([WITH_OPENVZ], 1, [whether OpenVZ driver is enabled])
 fi
index 8fbfb5f0a61ddd77b580443b3685169826840d91..27973525a81826c03ebe0ab06b98062641d17b5d 100644 (file)
@@ -51,6 +51,7 @@ UTIL_SOURCES =                                                        \
                util/event.c util/event.h                       \
                util/hash.c util/hash.h                         \
                util/iptables.c util/iptables.h                 \
+               util/ebtables.c util/ebtables.h                 \
                util/logging.c util/logging.h                   \
                util/memory.c util/memory.h                     \
                util/pci.c util/pci.h                           \
index 15d75fdd1be5b0f726896dedecfcac2ed293ec5e..215addbc084eda7abdb439f751fad2fc70e1ee50 100644 (file)
@@ -174,6 +174,14 @@ virDomainEventDispatch;
 virDomainEventQueueDispatch;
 
 
+# ebtables.h
+ebtablesAddForwardAllowIn;
+ebtablesAddForwardPolicyReject;
+ebtablesContextNew;
+ebtablesRemoveForwardAllowIn;
+ebtablesSaveRules;
+
+
 # event.h
 virEventAddHandle;
 virEventAddTimeout;
@@ -213,6 +221,7 @@ virInterfaceObjListFree;
 # interface_driver.h
 interfaceRegister;
 
+
 # iptables.h
 iptablesAddForwardAllowCross;
 iptablesAddForwardAllowIn;
diff --git a/src/util/ebtables.c b/src/util/ebtables.c
new file mode 100644 (file)
index 0000000..60427d7
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2009 IBM Corp.
+ * Copyright (C) 2007-2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * based on iptables.c
+ * Authors:
+ *     Gerhard Stenzel <gerhard.stenzel@de.ibm.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#include "internal.h"
+#include "ebtables.h"
+#include "util.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+struct _ebtablesContext
+{
+    ebtRules *input_filter;
+    ebtRules *forward_filter;
+    ebtRules *nat_postrouting;
+};
+
+enum {
+    ADD = 0,
+    REMOVE,
+    CREATE,
+    POLICY,
+    INSERT
+};
+
+static void
+ebtRulesSave(ebtRules *rules)
+{
+    (void) rules;
+}
+
+static void
+ebtRuleFree(ebtRule *rule)
+{
+    VIR_FREE(rule->rule);
+
+    if (rule->argv) {
+        int i = 0;
+        while (rule->argv[i])
+            VIR_FREE(rule->argv[i++]);
+        VIR_FREE(rule->argv);
+    }
+}
+
+static int
+ebtRulesAppend(ebtRules *rules,
+               char *rule,
+               const char **argv,
+               int command_idx)
+{
+    if (VIR_REALLOC_N(rules->rules, rules->nrules+1) < 0) {
+        int i = 0;
+        while (argv[i])
+            VIR_FREE(argv[i++]);
+        VIR_FREE(argv);
+        return ENOMEM;
+    }
+
+    rules->rules[rules->nrules].rule        = rule;
+    rules->rules[rules->nrules].argv        = argv;
+    rules->rules[rules->nrules].command_idx = command_idx;
+
+    rules->nrules++;
+
+    return 0;
+}
+
+static int
+ebtRulesRemove(ebtRules *rules,
+               char *rule)
+{
+    int i;
+
+    for (i = 0; i < rules->nrules; i++)
+        if (STREQ(rules->rules[i].rule, rule))
+            break;
+
+    if (i >= rules->nrules)
+        return EINVAL;
+
+    ebtRuleFree(&rules->rules[i]);
+
+    memmove(&rules->rules[i],
+            &rules->rules[i+1],
+            (rules->nrules - i - 1) * sizeof (ebtRule));
+
+    rules->nrules--;
+
+    return 0;
+}
+
+static void
+ebtRulesFree(ebtRules *rules)
+{
+    int i;
+
+    VIR_FREE(rules->table);
+    VIR_FREE(rules->chain);
+
+    if (rules->rules) {
+        for (i = 0; i < rules->nrules; i++)
+            ebtRuleFree(&rules->rules[i]);
+
+        VIR_FREE(rules->rules);
+
+        rules->nrules = 0;
+    }
+
+    VIR_FREE(rules);
+}
+
+static ebtRules *
+ebtRulesNew(const char *table,
+            const char *chain)
+{
+    ebtRules *rules;
+
+    if (VIR_ALLOC(rules) < 0)
+        return NULL;
+
+    if (!(rules->table = strdup(table)))
+        goto error;
+
+    if (!(rules->chain = strdup(chain)))
+        goto error;
+
+    rules->rules = NULL;
+    rules->nrules = 0;
+
+    return rules;
+
+ error:
+    ebtRulesFree(rules);
+    return NULL;
+}
+
+static int
+ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
+{
+    va_list args;
+    int retval = ENOMEM;
+    const char **argv;
+    char *rule = NULL;
+    const char *s;
+    int n, command_idx;
+
+    n = 1 + /* /sbin/ebtables  */
+        2 + /*   --table foo   */
+        2 + /*   --insert bar  */
+        1;  /*   arg           */
+
+    va_start(args, arg);
+    while ((s = va_arg(args, const char *)))
+        n++;
+
+    va_end(args);
+
+    if (VIR_ALLOC_N(argv, n + 1) < 0)
+        goto error;
+
+    n = 0;
+
+    if (!(argv[n++] = strdup(EBTABLES_PATH)))
+        goto error;
+
+    command_idx = n;
+
+    if(action == ADD || action == REMOVE) {
+        if (!(argv[n++] = strdup("--insert")))
+            goto error;
+
+        if (!(argv[n++] = strdup(rules->chain)))
+            goto error;
+    }
+
+    if (!(argv[n++] = strdup(arg)))
+        goto error;
+
+    va_start(args, arg);
+
+    while ((s = va_arg(args, const char *)))
+        if (!(argv[n++] = strdup(s)))
+            goto error;
+
+    va_end(args);
+
+    if (!(rule = virArgvToString(&argv[command_idx])))
+        goto error;
+
+    if (action == REMOVE) {
+        VIR_FREE(argv[command_idx]);
+        if (!(argv[command_idx] = strdup("--delete")))
+            goto error;
+    }
+
+    if (virRun(NULL, argv, NULL) < 0) {
+        retval = errno;
+        goto error;
+    }
+
+    if (action == ADD || action == CREATE || action == POLICY ||
+        action == INSERT) {
+        retval = ebtRulesAppend(rules, rule, argv, command_idx);
+        rule = NULL;
+        argv = NULL;
+    } else {
+        retval = ebtRulesRemove(rules, rule);
+    }
+
+ error:
+    VIR_FREE(rule);
+
+    if (argv) {
+        n = 0;
+        while (argv[n])
+            VIR_FREE(argv[n++]);
+        VIR_FREE(argv);
+    }
+
+    return retval;
+}
+
+
+/**
+ * ebtablesContextNew:
+ *
+ * Create a new ebtable context
+ *
+ * Returns a pointer to the new structure or NULL in case of error
+ */
+ebtablesContext *
+ebtablesContextNew(const char *driver)
+{
+    ebtablesContext *ctx;
+    char chain[PATH_MAX];
+
+    if (VIR_ALLOC(ctx) < 0)
+        return NULL;
+
+    snprintf(chain, sizeof(chain), "libvirt_%s_INPUT", driver);
+    if (!(ctx->input_filter = ebtRulesNew("filter", chain)))
+        goto error;
+
+    snprintf(chain, sizeof(chain), "libvirt_%s_FORWARD", driver);
+    if (!(ctx->forward_filter = ebtRulesNew("filter", chain)))
+        goto error;
+
+    snprintf(chain, sizeof(chain), "libvirt_%s_POSTROUTING", driver);
+    if (!(ctx->nat_postrouting = ebtRulesNew("nat", chain)))
+        goto error;
+
+    return ctx;
+
+ error:
+    ebtablesContextFree(ctx);
+    return NULL;
+}
+
+/**
+ * ebtablesContextFree:
+ * @ctx: pointer to the EB table context
+ *
+ * Free the resources associated with an EB table context
+ */
+void
+ebtablesContextFree(ebtablesContext *ctx)
+{
+    if (ctx->input_filter)
+        ebtRulesFree(ctx->input_filter);
+    if (ctx->forward_filter)
+        ebtRulesFree(ctx->forward_filter);
+    if (ctx->nat_postrouting)
+        ebtRulesFree(ctx->nat_postrouting);
+    VIR_FREE(ctx);
+}
+
+/**
+ * ebtablesSaveRules:
+ * @ctx: pointer to the EB table context
+ *
+ * Saves all the EB table rules associated with a context
+ * to disk so that if ebtables is restarted, the rules
+ * will automatically be reload.
+ */
+void
+ebtablesSaveRules(ebtablesContext *ctx)
+{
+    ebtRulesSave(ctx->input_filter);
+    ebtRulesSave(ctx->forward_filter);
+    ebtRulesSave(ctx->nat_postrouting);
+}
+
+int
+ebtablesAddForwardPolicyReject(ebtablesContext *ctx)
+{
+    return ebtablesForwardPolicyReject(ctx, ADD);
+}
+
+
+int
+ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx)
+{
+    return ebtablesForwardPolicyReject(ctx, REMOVE);
+}
+
+int
+ebtablesForwardPolicyReject(ebtablesContext *ctx,
+                            int action)
+{
+    /* create it, if it does not exist */
+    if (action == ADD) {
+        ebtablesAddRemoveRule(ctx->forward_filter,
+                              CREATE,
+                              "--new-chain", ctx->forward_filter->chain, NULL,
+                              NULL);
+        ebtablesAddRemoveRule(ctx->forward_filter,
+                              INSERT,
+                              "--insert", "FORWARD", "--jump",
+                              ctx->forward_filter->chain, NULL);
+    }
+
+    return ebtablesAddRemoveRule(ctx->forward_filter,
+                                 POLICY,
+                                 "-P", ctx->forward_filter->chain, "DROP",
+                                 NULL);
+}
+
+/*
+ * Allow all traffic destined to the bridge, with a valid network address
+ */
+static int
+ebtablesForwardAllowIn(ebtablesContext *ctx,
+                       const char *iface,
+                       const char *macaddr,
+                       int action)
+{
+    return ebtablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--in-interface", iface,
+                                     "--source", macaddr,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+}
+
+/**
+ * ebtablesAddForwardAllowIn:
+ * @ctx: pointer to the EB table context
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the EB table context to allow the traffic on
+ * @physdev device to be forwarded to interface @iface. This allows
+ * the inbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardAllowIn(ebtablesContext *ctx,
+                          const char *iface,
+                          const unsigned char *mac)
+{
+    char *macaddr;
+
+    if (virAsprintf(&macaddr,
+                    "%02x:%02x:%02x:%02x:%02x:%02x",
+                    mac[0], mac[1],
+                    mac[2], mac[3],
+                    mac[4], mac[5]) < 0) {
+        return -1;
+    }
+    return ebtablesForwardAllowIn(ctx, iface, macaddr, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardAllowIn:
+ * @ctx: pointer to the EB table context
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the EB table context hence forbidding the traffic
+ * on the @physdev device to be forwarded to interface @iface. This
+ * stops the inbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardAllowIn(ebtablesContext *ctx,
+                             const char *iface,
+                             const unsigned char *mac)
+{
+    char *macaddr;
+
+    if (virAsprintf(&macaddr,
+                    "%02x:%02x:%02x:%02x:%02x:%02x",
+                    mac[0], mac[1],
+                    mac[2], mac[3],
+                    mac[4], mac[5]) < 0) {
+       return -1;
+    }
+    return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE);
+}
diff --git a/src/util/ebtables.h b/src/util/ebtables.h
new file mode 100644 (file)
index 0000000..cafe418
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 IBM Corp.
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ * based on iptables.h
+ * Authors:
+ *     Gerhard Stenzel <gerhard.stenzel@de.ibm.com>
+ */
+
+#ifndef __QEMUD_EBTABLES_H__
+#define __QEMUD_EBTABLES_H__
+
+typedef struct
+{
+    char  *rule;
+    const char **argv;
+    int    command_idx;
+} ebtRule;
+
+typedef struct
+{
+    char  *table;
+    char  *chain;
+
+    int      nrules;
+    ebtRule *rules;
+
+} ebtRules;
+
+typedef struct _ebtablesContext ebtablesContext;
+
+ebtablesContext *ebtablesContextNew              (const char *driver);
+void             ebtablesContextFree             (ebtablesContext *ctx);
+
+void             ebtablesSaveRules               (ebtablesContext *ctx);
+
+int              ebtablesAddForwardAllowIn       (ebtablesContext *ctx,
+                                                  const char *iface,
+                                                  const unsigned char *mac);
+int              ebtablesRemoveForwardAllowIn    (ebtablesContext *ctx,
+                                                  const char *iface,
+                                                  const unsigned char *mac);
+
+int              ebtablesAddForwardPolicyReject(ebtablesContext *ctx);
+
+int              ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx);
+
+int              ebtablesForwardPolicyReject(ebtablesContext *ctx,
+                                                  int action);
+
+#endif /* __QEMUD_ebtabLES_H__ */