[libvirt] [PATCH 9/9] add DHCP snooping support to nwfilter

David L Stevens dlstevens at us.ibm.com
Mon May 9 20:12:10 UTC 2011


This patch removes remaining pieces of IP address learning.

diff --git a/src/Makefile.am b/src/Makefile.am
index 3da0797..53cdc00 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -389,9 +389,7 @@ NWFILTER_DRIVER_SOURCES =					\
 		nwfilter/nwfilter_dhcpsnoop.c				\
 		nwfilter/nwfilter_dhcpsnoop.h				\
 		nwfilter/nwfilter_ebiptables_driver.c			\
-		nwfilter/nwfilter_ebiptables_driver.h			\
-		nwfilter/nwfilter_learnipaddr.c				\
-		nwfilter/nwfilter_learnipaddr.h
+		nwfilter/nwfilter_ebiptables_driver.h
 
 
 # Security framework and drivers for various models
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index 2e20e59..3a73fa4 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -40,7 +40,6 @@
 #include "configmake.h"
 
 #include "nwfilter_dhcpsnoop.h"
-#include "nwfilter_learnipaddr.h"
 
 #define VIR_FROM_THIS VIR_FROM_NWFILTER
 
@@ -69,8 +68,6 @@ nwfilterDriverStartup(int privileged) {
 
     if (virNWFilterDHCPSnoopInit() < 0)
         return -1;
-    if (virNWFilterLearnInit() < 0)
-        return -1;
 
     virNWFilterTechDriversInit(privileged);
 
@@ -131,7 +128,6 @@ alloc_err_exit:
 conf_init_err:
     virNWFilterTechDriversShutdown();
     virNWFilterDHCPSnoopEnd(0);
-    virNWFilterLearnShutdown();
 
     return -1;
 }
@@ -154,7 +150,7 @@ nwfilterDriverReload(void) {
 
     if (conn) {
         /* shut down all threads -- they will be restarted if necessary */
-        virNWFilterLearnThreadsTerminate(true);
+        virNWFilterDHCPSnoopEnd(0);
 
         nwfilterDriverLock(driverState);
         virNWFilterCallbackDriversLock();
@@ -206,7 +202,6 @@ nwfilterDriverShutdown(void) {
     virNWFilterConfLayerShutdown();
     virNWFilterTechDriversShutdown();
     virNWFilterDHCPSnoopEnd(0);
-    virNWFilterLearnShutdown();
 
     nwfilterDriverLock(driverState);
 
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index c6e6600..42fd965 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -34,7 +34,6 @@
 #include "nwfilter_gentech_driver.h"
 #include "nwfilter_ebiptables_driver.h"
 #include "nwfilter_dhcpsnoop.h"
-#include "nwfilter_learnipaddr.h"
 
 
 #define VIR_FROM_THIS VIR_FROM_NWFILTER
@@ -625,14 +624,10 @@ virNWFilterChangeVar(virConnectPtr conn,
         return 1;
     }
 
-    if (virNWFilterLockIface(ifname))
-         goto err_exit;
-
      if (delete)
          rc = techdriver->removeRules(conn, ifname, nptrs, ptrs);
      else
          rc = techdriver->addRules(conn, ifname, nptrs, ptrs);
-     virNWFilterUnlockIface(ifname);
      VIR_FREE(ptrs);
 
 err_exit:
@@ -755,9 +750,6 @@ virNWFilterInstantiate(virConnectPtr conn,
         if (rc)
             goto err_exit;
 
-        if (virNWFilterLockIface(ifname))
-            goto err_exit;
-
         rc = techdriver->applyNewRules(conn, ifname, nptrs, ptrs);
 
         if (teardownOld && rc == 0)
@@ -768,8 +760,6 @@ virNWFilterInstantiate(virConnectPtr conn,
             techdriver->allTeardown(ifname);
             rc = 1;
         }
-
-        virNWFilterUnlockIface(ifname);
     }
 
 err_exit:
@@ -811,7 +801,6 @@ __virNWFilterInstantiateFilter(virConnectPtr conn,
     virNWFilterDefPtr filter;
     char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
     char *str_macaddr = NULL;
-    const char *ipaddr;
     char *str_ipaddr = NULL;
 
     techdriver = virNWFilterTechDriverForName(drvname);
@@ -850,16 +839,6 @@ __virNWFilterInstantiateFilter(virConnectPtr conn,
         goto err_exit;
     }
 
-    ipaddr = virNWFilterGetIpAddrForIfname(ifname);
-    if (ipaddr) {
-        str_ipaddr = strdup(ipaddr);
-        if (!str_ipaddr) {
-            virReportOOMError();
-            rc = 1;
-            goto err_exit;
-        }
-    }
-
     vars1 = virNWFilterCreateVarHashmap(str_macaddr, str_ipaddr);
     if (!vars1) {
         rc = 1;
@@ -1031,7 +1010,6 @@ int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
                                     const virDomainNetDefPtr net)
 {
     const char *drvname = EBIPTABLES_DRIVER_ID;
-    int ifindex;
     virNWFilterTechDriverPtr techdriver;
 
     techdriver = virNWFilterTechDriverForName(drvname);
@@ -1043,11 +1021,6 @@ int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
         return 1;
     }
 
-    /* don't tear anything while the address is being learned */
-    if (ifaceGetIndex(true, net->ifname, &ifindex) == 0 &&
-        virNWFilterLookupLearnReq(ifindex) != NULL)
-        return 0;
-
     return techdriver->tearNewRules(conn, net->ifname);
 }
 
@@ -1057,7 +1030,6 @@ virNWFilterTearOldFilter(virConnectPtr conn,
                          virDomainNetDefPtr net)
 {
     const char *drvname = EBIPTABLES_DRIVER_ID;
-    int ifindex;
     virNWFilterTechDriverPtr techdriver;
 
     techdriver = virNWFilterTechDriverForName(drvname);
@@ -1069,11 +1041,6 @@ virNWFilterTearOldFilter(virConnectPtr conn,
         return 1;
     }
 
-    /* don't tear anything while the address is being learned */
-    if (ifaceGetIndex(true, net->ifname, &ifindex) == 0 &&
-        virNWFilterLookupLearnReq(ifindex) != NULL)
-        return 0;
-
     return techdriver->tearOldRules(conn, net->ifname);
 }
 
@@ -1095,17 +1062,8 @@ _virNWFilterTeardownFilter(const char *ifname)
 
     virNWFilterDHCPSnoopEnd(ifname);
 
-    virNWFilterTerminateLearnReq(ifname);
-
-    if (virNWFilterLockIface(ifname))
-       return 1;
-
     techdriver->allTeardown(ifname);
 
-    virNWFilterDelIpAddrForIfname(ifname);
-
-    virNWFilterUnlockIface(ifname);
-
     return 0;
 }
 
diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c
deleted file mode 100644
index 96d2a55..0000000
--- a/src/nwfilter/nwfilter_learnipaddr.c
+++ /dev/null
@@ -1,891 +0,0 @@
-/*
- * nwfilter_learnipaddr.c: support for learning IP address used by a VM
- *                         on an interface
- *
- * Copyright (C) 2011 Red Hat, Inc.
- * 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 <stefanb at us.ibm.com>
- */
-
-#include <config.h>
-
-#ifdef HAVE_LIBPCAP
-# include <pcap.h>
-#endif
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <arpa/inet.h>
-#include <net/ethernet.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <net/if_arp.h>
-#include <intprops.h>
-
-#include "internal.h"
-
-#include "buf.h"
-#include "memory.h"
-#include "logging.h"
-#include "datatypes.h"
-#include "interface.h"
-#include "virterror_internal.h"
-#include "threads.h"
-#include "conf/nwfilter_params.h"
-#include "conf/domain_conf.h"
-#include "nwfilter_gentech_driver.h"
-#include "nwfilter_ebiptables_driver.h"
-#include "nwfilter_learnipaddr.h"
-
-#define VIR_FROM_THIS VIR_FROM_NWFILTER
-
-#define IFINDEX2STR(VARNAME, ifindex) \
-    char VARNAME[INT_BUFSIZE_BOUND(ifindex)]; \
-    snprintf(VARNAME, sizeof(VARNAME), "%d", ifindex);
-
-#define PKT_TIMEOUT_MS 500 /* ms */
-
-/* structure of an ARP request/reply message */
-struct f_arphdr {
-    struct arphdr arphdr;
-    uint8_t ar_sha[ETH_ALEN];
-    uint32_t ar_sip;
-    uint8_t ar_tha[ETH_ALEN];
-    uint32_t ar_tip;
-} ATTRIBUTE_PACKED;
-
-
-struct dhcp_option {
-    uint8_t code;
-    uint8_t len;
-    uint8_t value[0]; /* length varies */
-} ATTRIBUTE_PACKED;
-
-
-/* structure representing DHCP message */
-struct dhcp {
-    uint8_t op;
-    uint8_t htype;
-    uint8_t hlen;
-    uint8_t hops;
-    uint32_t xid;
-    uint16_t secs;
-    uint16_t flags;
-    uint32_t ciaddr;
-    uint32_t yiaddr;
-    uint32_t siaddr;
-    uint32_t giaddr;
-    uint8_t chaddr[16];
-    uint8_t zeroes[192];
-    uint32_t magic;
-    struct dhcp_option options[0];
-} ATTRIBUTE_PACKED;
-
-#define DHCP_MSGT_DHCPOFFER 2
-#define DHCP_MSGT_DHCPACK   5
-
-
-#define DHCP_OPT_BCASTADDRESS 28
-#define DHCP_OPT_MESSAGETYPE  53
-
-struct ether_vlan_header
-{
-    uint8_t dhost[ETH_ALEN];
-    uint8_t shost[ETH_ALEN];
-    uint16_t vlan_type;
-    uint16_t vlan_flags;
-    uint16_t ether_type;
-} ATTRIBUTE_PACKED;
-
-
-static virMutex pendingLearnReqLock;
-static virHashTablePtr pendingLearnReq;
-
-static virMutex ipAddressMapLock;
-static virNWFilterHashTablePtr ipAddressMap;
-
-static virMutex ifaceMapLock;
-static virHashTablePtr ifaceLockMap;
-
-typedef struct _virNWFilterIfaceLock virNWFilterIfaceLock;
-typedef virNWFilterIfaceLock *virNWFilterIfaceLockPtr;
-struct _virNWFilterIfaceLock {
-    char ifname[IF_NAMESIZE];
-    virMutex lock;
-    int refctr;
-};
-
-
-static bool threadsTerminate = false;
-
-
-int
-virNWFilterLockIface(const char *ifname) {
-    virNWFilterIfaceLockPtr ifaceLock;
-
-    virMutexLock(&ifaceMapLock);
-
-    ifaceLock = virHashLookup(ifaceLockMap, ifname);
-    if (!ifaceLock) {
-        if (VIR_ALLOC(ifaceLock) < 0) {
-            virReportOOMError();
-            goto err_exit;
-        }
-
-        if (virMutexInitRecursive(&ifaceLock->lock)) {
-            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("mutex initialization failed"));
-            VIR_FREE(ifaceLock);
-            goto err_exit;
-        }
-
-        if (virStrcpyStatic(ifaceLock->ifname, ifname) == NULL) {
-            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
-                                   _("interface name %s does not fit into "
-                                     "buffer "),
-                                   ifaceLock->ifname);
-            VIR_FREE(ifaceLock);
-            goto err_exit;
-        }
-
-        while (virHashAddEntry(ifaceLockMap, ifname, ifaceLock)) {
-            VIR_FREE(ifaceLock);
-            goto err_exit;
-        }
-
-        ifaceLock->refctr = 0;
-    }
-
-    ifaceLock->refctr++;
-
-    virMutexUnlock(&ifaceMapLock);
-
-    virMutexLock(&ifaceLock->lock);
-
-    return 0;
-
- err_exit:
-    virMutexUnlock(&ifaceMapLock);
-
-    return 1;
-}
-
-
-static void
-freeIfaceLock(void *payload, const void *name ATTRIBUTE_UNUSED) {
-    VIR_FREE(payload);
-}
-
-
-void
-virNWFilterUnlockIface(const char *ifname) {
-    virNWFilterIfaceLockPtr ifaceLock;
-
-    virMutexLock(&ifaceMapLock);
-
-    ifaceLock = virHashLookup(ifaceLockMap, ifname);
-
-    if (ifaceLock) {
-        virMutexUnlock(&ifaceLock->lock);
-
-        ifaceLock->refctr--;
-        if (ifaceLock->refctr == 0)
-            virHashRemoveEntry(ifaceLockMap, ifname);
-    }
-
-    virMutexUnlock(&ifaceMapLock);
-}
-
-
-static void
-virNWFilterIPAddrLearnReqFree(virNWFilterIPAddrLearnReqPtr req) {
-    if (!req)
-        return;
-
-    VIR_FREE(req->filtername);
-    virNWFilterHashTableFree(req->filterparams);
-
-    VIR_FREE(req);
-}
-
-
-#if HAVE_LIBPCAP
-
-static int
-virNWFilterRegisterLearnReq(virNWFilterIPAddrLearnReqPtr req) {
-    int res = -1;
-    IFINDEX2STR(ifindex_str, req->ifindex);
-
-    virMutexLock(&pendingLearnReqLock);
-
-    if (!virHashLookup(pendingLearnReq, ifindex_str))
-        res = virHashAddEntry(pendingLearnReq, ifindex_str, req);
-
-    virMutexUnlock(&pendingLearnReqLock);
-
-    return res;
-}
-
-
-#endif
-
-int
-virNWFilterTerminateLearnReq(const char *ifname) {
-    int rc = 1;
-    int ifindex;
-    virNWFilterIPAddrLearnReqPtr req;
-
-    if (ifaceGetIndex(false, ifname, &ifindex) == 0) {
-
-        IFINDEX2STR(ifindex_str, ifindex);
-
-        virMutexLock(&pendingLearnReqLock);
-
-        req = virHashLookup(pendingLearnReq, ifindex_str);
-        if (req) {
-            rc = 0;
-            req->terminate = true;
-        }
-
-        virMutexUnlock(&pendingLearnReqLock);
-    }
-
-    return rc;
-}
-
-
-virNWFilterIPAddrLearnReqPtr
-virNWFilterLookupLearnReq(int ifindex) {
-    void *res;
-    IFINDEX2STR(ifindex_str, ifindex);
-
-    virMutexLock(&pendingLearnReqLock);
-
-    res = virHashLookup(pendingLearnReq, ifindex_str);
-
-    virMutexUnlock(&pendingLearnReqLock);
-
-    return res;
-}
-
-
-static void
-freeLearnReqEntry(void *payload, const void *name ATTRIBUTE_UNUSED) {
-    virNWFilterIPAddrLearnReqFree(payload);
-}
-
-
-#ifdef HAVE_LIBPCAP
-
-static virNWFilterIPAddrLearnReqPtr
-virNWFilterDeregisterLearnReq(int ifindex) {
-    virNWFilterIPAddrLearnReqPtr res;
-    IFINDEX2STR(ifindex_str, ifindex);
-
-    virMutexLock(&pendingLearnReqLock);
-
-    res = virHashSteal(pendingLearnReq, ifindex_str);
-
-    virMutexUnlock(&pendingLearnReqLock);
-
-    return res;
-}
-
-
-
-static int
-virNWFilterAddIpAddrForIfname(const char *ifname, char *addr) {
-    int ret;
-
-    virMutexLock(&ipAddressMapLock);
-
-    ret = virNWFilterHashTablePut(ipAddressMap, ifname, addr, 1);
-
-    virMutexUnlock(&ipAddressMapLock);
-
-    return ret;
-}
-#endif
-
-
-void
-virNWFilterDelIpAddrForIfname(const char *ifname) {
-
-    virMutexLock(&ipAddressMapLock);
-
-    if (virHashLookup(ipAddressMap->hashTable, ifname))
-        virNWFilterHashTableRemoveEntry(ipAddressMap, ifname);
-
-    virMutexUnlock(&ipAddressMapLock);
-}
-
-
-const char *
-virNWFilterGetIpAddrForIfname(const char *ifname) {
-    const char *res;
-
-    virMutexLock(&ipAddressMapLock);
-
-    res = virHashLookup(ipAddressMap->hashTable, ifname);
-
-    virMutexUnlock(&ipAddressMapLock);
-
-    return res;
-}
-
-
-#ifdef HAVE_LIBPCAP
-
-static void
-procDHCPOpts(struct dhcp *dhcp, int dhcp_opts_len,
-             uint32_t *vmaddr, uint32_t *bcastaddr,
-             enum howDetect *howDetected) {
-    struct dhcp_option *dhcpopt = &dhcp->options[0];
-
-    while (dhcp_opts_len >= 2) {
-
-        switch (dhcpopt->code) {
-
-        case DHCP_OPT_BCASTADDRESS: /* Broadcast address */
-            if (dhcp_opts_len >= 6) {
-                uint32_t *tmp = (uint32_t *)&dhcpopt->value;
-                (*bcastaddr) = ntohl(*tmp);
-            }
-        break;
-
-        case DHCP_OPT_MESSAGETYPE: /* Message type */
-            if (dhcp_opts_len >= 3) {
-                uint8_t *val = (uint8_t *)&dhcpopt->value;
-                switch (*val) {
-                case DHCP_MSGT_DHCPACK:
-                case DHCP_MSGT_DHCPOFFER:
-                    *vmaddr = dhcp->yiaddr;
-                    *howDetected = DETECT_DHCP;
-                break;
-                }
-            }
-        }
-        dhcp_opts_len -= (2 + dhcpopt->len);
-        dhcpopt = (struct dhcp_option*)((char *)dhcpopt + 2 + dhcpopt->len);
-    }
-}
-
-
-/**
- * learnIPAddressThread
- * arg: pointer to virNWFilterIPAddrLearnReq structure
- *
- * Learn the IP address being used on an interface. Use ARP Request and
- * Reply messages, DHCP offers and the first IP packet being sent from
- * the VM to detect the IP address it is using. Detects only one IP address
- * per interface (IP aliasing not supported). The method on how the
- * IP address is detected can be chosen through flags. DETECT_DHCP will
- * require that the IP address is detected from a DHCP OFFER, DETECT_STATIC
- * will require that the IP address was taken from an ARP packet or an IPv4
- * packet. Both flags can be set at the same time.
- */
-static void *
-learnIPAddressThread(void *arg)
-{
-    char errbuf[PCAP_ERRBUF_SIZE] = {0};
-    pcap_t *handle = NULL;
-    struct bpf_program fp;
-    struct pcap_pkthdr header;
-    const u_char *packet;
-    struct ether_header *ether_hdr;
-    struct ether_vlan_header *vlan_hdr;
-    virNWFilterIPAddrLearnReqPtr req = arg;
-    uint32_t vmaddr = 0, bcastaddr = 0;
-    unsigned int ethHdrSize;
-    char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev
-                                                  : req->ifname;
-    int dhcp_opts_len;
-    char macaddr[VIR_MAC_STRING_BUFLEN];
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    char *filter = NULL;
-    uint16_t etherType;
-    bool showError = true;
-    enum howDetect howDetected = 0;
-    virNWFilterTechDriverPtr techdriver = req->techdriver;
-
-    if (virNWFilterLockIface(req->ifname))
-       goto err_no_lock;
-
-    req->status = 0;
-
-    /* anything change to the VM's interface -- check at least once */
-    if (ifaceCheck(false, req->ifname, NULL, req->ifindex)) {
-        req->status = ENODEV;
-        goto done;
-    }
-
-    handle = pcap_open_live(listen_if, BUFSIZ, 0, PKT_TIMEOUT_MS, errbuf);
-
-    if (handle == NULL) {
-        VIR_DEBUG("Couldn't open device %s: %s\n", listen_if, errbuf);
-        req->status = ENODEV;
-        goto done;
-    }
-
-    virFormatMacAddr(req->macaddr, macaddr);
-
-    switch (req->howDetect) {
-    case DETECT_DHCP:
-        if (techdriver->applyDHCPOnlyRules(req->ifname,
-                                           req->macaddr,
-                                           NULL)) {
-            req->status = EINVAL;
-            goto done;
-        }
-        virBufferVSprintf(&buf, " ether dst %s"
-                                " and src port 67 and dst port 68",
-                          macaddr);
-        break;
-    default:
-        if (techdriver->applyBasicRules(req->ifname,
-                                        req->macaddr)) {
-            req->status = EINVAL;
-            goto done;
-        }
-        virBufferVSprintf(&buf, "ether host %s", macaddr);
-    }
-
-    if (virBufferError(&buf)) {
-        req->status = ENOMEM;
-        goto done;
-    }
-
-    filter = virBufferContentAndReset(&buf);
-
-    if (pcap_compile(handle, &fp, filter, 1, 0) != 0) {
-        VIR_DEBUG("Couldn't compile filter '%s'.\n", filter);
-        req->status = EINVAL;
-        goto done;
-    }
-
-    if (pcap_setfilter(handle, &fp) != 0) {
-        VIR_DEBUG("Couldn't set filter '%s'.\n", filter);
-        req->status = EINVAL;
-        pcap_freecode(&fp);
-        goto done;
-    }
-
-    pcap_freecode(&fp);
-
-    while (req->status == 0 && vmaddr == 0) {
-        packet = pcap_next(handle, &header);
-
-        if (!packet) {
-
-            if (threadsTerminate || req->terminate) {
-                req->status = ECANCELED;
-                showError = false;
-                break;
-            }
-
-            /* check whether VM's dev is still there */
-            if (ifaceCheck(false, req->ifname, NULL, req->ifindex)) {
-                req->status = ENODEV;
-                showError = false;
-                break;
-            }
-            continue;
-        }
-
-        if (header.len >= sizeof(struct ether_header)) {
-            ether_hdr = (struct ether_header*)packet;
-
-            switch (ntohs(ether_hdr->ether_type)) {
-
-            case ETHERTYPE_IP:
-                ethHdrSize = sizeof(struct ether_header);
-                etherType = ntohs(ether_hdr->ether_type);
-                break;
-
-            case ETHERTYPE_VLAN:
-                ethHdrSize = sizeof(struct ether_vlan_header);
-                vlan_hdr = (struct ether_vlan_header *)packet;
-                if (ntohs(vlan_hdr->ether_type) != ETHERTYPE_IP ||
-                    header.len < ethHdrSize)
-                    continue;
-                etherType = ntohs(vlan_hdr->ether_type);
-                break;
-
-            default:
-                continue;
-            }
-
-            if (memcmp(ether_hdr->ether_shost,
-                       req->macaddr,
-                       VIR_MAC_BUFLEN) == 0) {
-                /* packets from the VM */
-
-                if (etherType == ETHERTYPE_IP &&
-                    (header.len >= ethHdrSize +
-                                   sizeof(struct iphdr))) {
-                    struct iphdr *iphdr = (struct iphdr*)(packet +
-                                                          ethHdrSize);
-                    vmaddr = iphdr->saddr;
-                    /* skip mcast addresses (224.0.0.0 - 239.255.255.255),
-                     * class E (240.0.0.0 - 255.255.255.255, includes eth.
-                     * bcast) and zero address in DHCP Requests */
-                    if ( (ntohl(vmaddr) & 0xe0000000) == 0xe0000000 ||
-                         vmaddr == 0) {
-                        vmaddr = 0;
-                        continue;
-                    }
-
-                    howDetected = DETECT_STATIC;
-                } else if (etherType == ETHERTYPE_ARP &&
-                           (header.len >= ethHdrSize +
-                                          sizeof(struct f_arphdr))) {
-                    struct f_arphdr *arphdr = (struct f_arphdr*)(packet +
-                                                         ethHdrSize);
-                    switch (ntohs(arphdr->arphdr.ar_op)) {
-                    case ARPOP_REPLY:
-                        vmaddr = arphdr->ar_sip;
-                        howDetected = DETECT_STATIC;
-                    break;
-                    case ARPOP_REQUEST:
-                        vmaddr = arphdr->ar_tip;
-                        howDetected = DETECT_STATIC;
-                    break;
-                    }
-                }
-            } else if (memcmp(ether_hdr->ether_dhost,
-                              req->macaddr,
-                              VIR_MAC_BUFLEN) == 0) {
-                /* packets to the VM */
-                if (etherType == ETHERTYPE_IP &&
-                    (header.len >= ethHdrSize +
-                                   sizeof(struct iphdr))) {
-                    struct iphdr *iphdr = (struct iphdr*)(packet +
-                                                          ethHdrSize);
-                    if ((iphdr->protocol == IPPROTO_UDP) &&
-                        (header.len >= ethHdrSize +
-                                       iphdr->ihl * 4 +
-                                       sizeof(struct udphdr))) {
-                        struct udphdr *udphdr= (struct udphdr *)
-                                          ((char *)iphdr + iphdr->ihl * 4);
-                        if (ntohs(udphdr->source) == 67 &&
-                            ntohs(udphdr->dest)   == 68 &&
-                            header.len >= ethHdrSize +
-                                          iphdr->ihl * 4 +
-                                          sizeof(struct udphdr) +
-                                          sizeof(struct dhcp)) {
-                            struct dhcp *dhcp = (struct dhcp *)
-                                        ((char *)udphdr + sizeof(udphdr));
-                            if (dhcp->op == 2 /* BOOTREPLY */ &&
-                                !memcmp(&dhcp->chaddr[0],
-                                        req->macaddr,
-                                        6)) {
-                                dhcp_opts_len = header.len -
-                                    (ethHdrSize + iphdr->ihl * 4 +
-                                     sizeof(struct udphdr) +
-                                     sizeof(struct dhcp));
-                                procDHCPOpts(dhcp, dhcp_opts_len,
-                                             &vmaddr,
-                                             &bcastaddr,
-                                             &howDetected);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        if (vmaddr && (req->howDetect & howDetected) == 0) {
-            vmaddr = 0;
-            howDetected = 0;
-        }
-    } /* while */
-
- done:
-    VIR_FREE(filter);
-
-    if (handle)
-        pcap_close(handle);
-
-    if (req->status == 0) {
-        int ret;
-        virSocketAddr sa;
-        sa.len = sizeof(sa.data.inet4);
-        sa.data.inet4.sin_family = AF_INET;
-        sa.data.inet4.sin_addr.s_addr = vmaddr;
-        char *inetaddr;
-
-        if ((inetaddr = virSocketFormatAddr(&sa))!= NULL) {
-            virNWFilterAddIpAddrForIfname(req->ifname, inetaddr);
-
-            ret = virNWFilterInstantiateFilterLate(NULL,
-                                                   req->ifname,
-                                                   req->ifindex,
-                                                   req->linkdev,
-                                                   req->nettype,
-                                                   req->macaddr,
-                                                   req->filtername,
-                                                   req->filterparams,
-                                                   req->driver);
-            VIR_DEBUG("Result from applying firewall rules on "
-                      "%s with IP addr %s : %d\n", req->ifname, inetaddr, ret);
-        }
-    } else {
-        if (showError)
-            virReportSystemError(req->status,
-                                 _("encountered an error on interface %s "
-                                   "index %d"),
-                                 req->ifname, req->ifindex);
-
-        techdriver->applyDropAllRules(req->ifname);
-    }
-
-    memset(&req->thread, 0x0, sizeof(req->thread));
-
-    VIR_DEBUG("pcap thread terminating for interface %s\n",req->ifname);
-
-    virNWFilterUnlockIface(req->ifname);
-
- err_no_lock:
-    virNWFilterDeregisterLearnReq(req->ifindex);
-
-    virNWFilterIPAddrLearnReqFree(req);
-
-    return 0;
-}
-
-
-/**
- * virNWFilterLearnIPAddress
- * @techdriver : driver to build firewalls
- * @ifname: the name of the interface
- * @ifindex: the index of the interface
- * @linkdev : the name of the link device; currently only used in case of a
- *     macvtap device
- * @nettype : the type of interface
- * @macaddr : the MAC address of the interface
- * @filtername : the name of the top-level filter to apply to the interface
- *               once its IP address has been detected
- * @driver : the network filter driver
- * @howDetect : the method on how the thread is supposed to detect the
- *              IP address; must choose any of the available flags
- *
- * Instruct to learn the IP address being used on a given interface (ifname).
- * Unless there already is a thread attempting to learn the IP address
- * being used on the interface, a thread is started that will listen on
- * the traffic being sent on the interface (or link device) with the
- * MAC address that is provided. Will then launch the application of the
- * firewall rules on the interface.
- */
-int
-virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver,
-                          const char *ifname,
-                          int ifindex,
-                          const char *linkdev,
-                          enum virDomainNetType nettype,
-                          const unsigned char *macaddr,
-                          const char *filtername,
-                          virNWFilterHashTablePtr filterparams,
-                          virNWFilterDriverStatePtr driver,
-                          enum howDetect howDetect) {
-    int rc;
-    virNWFilterIPAddrLearnReqPtr req = NULL;
-    virNWFilterHashTablePtr ht = NULL;
-
-    if (howDetect == 0)
-        return 1;
-
-    if ( !techdriver->canApplyBasicRules()) {
-        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("IP parameter must be provided since "
-                                 "snooping the IP address does not work "
-                                 "possibly due to missing tools"));
-        return 1;
-    }
-
-    if (VIR_ALLOC(req) < 0) {
-        virReportOOMError();
-        goto err_no_req;
-    }
-
-    ht = virNWFilterHashTableCreate(0);
-    if (ht == NULL) {
-        virReportOOMError();
-        goto err_free_req;
-    }
-
-    if (virNWFilterHashTablePutAll(filterparams, ht))
-        goto err_free_ht;
-
-    req->filtername = strdup(filtername);
-    if (req->filtername == NULL) {
-        virReportOOMError();
-        goto err_free_ht;
-    }
-
-    if (virStrcpyStatic(req->ifname, ifname) == NULL) {
-        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Destination buffer for ifname ('%s') "
-                               "not large enough"), ifname);
-        goto err_free_ht;
-    }
-
-    if (linkdev) {
-        if (virStrcpyStatic(req->linkdev, linkdev) == NULL) {
-            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
-                                   _("Destination buffer for linkdev ('%s') "
-                                   "not large enough"), linkdev);
-            goto err_free_ht;
-        }
-    }
-
-    req->ifindex = ifindex;
-    req->nettype = nettype;
-    memcpy(req->macaddr, macaddr, sizeof(req->macaddr));
-    req->driver = driver;
-    req->filterparams = ht;
-    ht = NULL;
-    req->howDetect = howDetect;
-    req->techdriver = techdriver;
-
-    rc = virNWFilterRegisterLearnReq(req);
-
-    if (rc)
-        goto err_free_req;
-
-    if (pthread_create(&req->thread,
-                       NULL,
-                       learnIPAddressThread,
-                       req) != 0)
-        goto err_dereg_req;
-
-    return 0;
-
-err_dereg_req:
-    virNWFilterDeregisterLearnReq(ifindex);
-err_free_ht:
-    virNWFilterHashTableFree(ht);
-err_free_req:
-    virNWFilterIPAddrLearnReqFree(req);
-err_no_req:
-    return 1;
-}
-
-#else
-
-int
-virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver ATTRIBUTE_UNUSED,
-                          const char *ifname ATTRIBUTE_UNUSED,
-                          int ifindex ATTRIBUTE_UNUSED,
-                          const char *linkdev ATTRIBUTE_UNUSED,
-                          enum virDomainNetType nettype ATTRIBUTE_UNUSED,
-                          const unsigned char *macaddr ATTRIBUTE_UNUSED,
-                          const char *filtername ATTRIBUTE_UNUSED,
-                          virNWFilterHashTablePtr filterparams ATTRIBUTE_UNUSED,
-                          virNWFilterDriverStatePtr driver ATTRIBUTE_UNUSED,
-                          enum howDetect howDetect ATTRIBUTE_UNUSED) {
-    virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("IP parameter must be given since libvirt "
-                             "was not compiled with IP address learning "
-                             "support"));
-    return 1;
-}
-#endif /* HAVE_LIBPCAP */
-
-
-/**
- * virNWFilterLearnInit
- * Initialization of this layer
- */
-int
-virNWFilterLearnInit(void) {
-
-    if (pendingLearnReq)
-        return 0;
-
-    threadsTerminate = false;
-
-    pendingLearnReq = virHashCreate(0, freeLearnReqEntry);
-    if (!pendingLearnReq) {
-        return 1;
-    }
-
-    if (virMutexInit(&pendingLearnReqLock)) {
-        virNWFilterLearnShutdown();
-        return 1;
-    }
-
-    ipAddressMap = virNWFilterHashTableCreate(0);
-    if (!ipAddressMap) {
-        virReportOOMError();
-        virNWFilterLearnShutdown();
-        return 1;
-    }
-
-    if (virMutexInit(&ipAddressMapLock)) {
-        virNWFilterLearnShutdown();
-        return 1;
-    }
-
-    ifaceLockMap = virHashCreate(0, freeIfaceLock);
-    if (!ifaceLockMap) {
-        virNWFilterLearnShutdown();
-        return 1;
-    }
-
-    if (virMutexInit(&ifaceMapLock)) {
-        virNWFilterLearnShutdown();
-        return 1;
-    }
-
-    return 0;
-}
-
-
-void
-virNWFilterLearnThreadsTerminate(bool allowNewThreads) {
-    threadsTerminate = true;
-
-    while (virHashSize(pendingLearnReq) != 0)
-        usleep((PKT_TIMEOUT_MS * 1000) / 3);
-
-    if (allowNewThreads)
-        threadsTerminate = false;
-}
-
-/**
- * virNWFilterLearnShutdown
- * Shutdown of this layer
- */
-void
-virNWFilterLearnShutdown(void)
-{
-    if (!pendingLearnReq)
-        return;
-
-    virNWFilterLearnThreadsTerminate(false);
-
-    virHashFree(pendingLearnReq);
-    pendingLearnReq = NULL;
-
-    virNWFilterHashTableFree(ipAddressMap);
-    ipAddressMap = NULL;
-
-    virHashFree(ifaceLockMap);
-    ifaceLockMap = NULL;
-}
diff --git a/src/nwfilter/nwfilter_learnipaddr.h b/src/nwfilter/nwfilter_learnipaddr.h
deleted file mode 100644
index e4b9811..0000000
--- a/src/nwfilter/nwfilter_learnipaddr.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * nwfilter_learnipaddr.h: support for learning IP address used by a VM
- *                         on an interface
- *
- * 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 <stefanb at us.ibm.com>
- */
-
-#ifndef __NWFILTER_LEARNIPADDR_H
-# define __NWFILTER_LEARNIPADDR_H
-
-enum howDetect {
-  DETECT_DHCP = 1,
-  DETECT_STATIC = 2,
-};
-
-typedef struct _virNWFilterIPAddrLearnReq virNWFilterIPAddrLearnReq;
-typedef virNWFilterIPAddrLearnReq *virNWFilterIPAddrLearnReqPtr;
-struct _virNWFilterIPAddrLearnReq {
-    virNWFilterTechDriverPtr techdriver;
-    char ifname[IF_NAMESIZE];
-    int ifindex;
-    char linkdev[IF_NAMESIZE];
-    enum virDomainNetType nettype;
-    unsigned char macaddr[VIR_MAC_BUFLEN];
-    char *filtername;
-    virNWFilterHashTablePtr filterparams;
-    virNWFilterDriverStatePtr driver;
-    enum howDetect howDetect;
-
-    int status;
-    pthread_t thread;
-    volatile bool terminate;
-};
-
-int virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver,
-                              const char *ifname,
-                              int ifindex,
-                              const char *linkdev,
-                              enum virDomainNetType nettype,
-                              const unsigned char *macaddr,
-                              const char *filtername,
-                              virNWFilterHashTablePtr filterparams,
-                              virNWFilterDriverStatePtr driver,
-                              enum howDetect howDetect);
-
-virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(int ifindex);
-int virNWFilterTerminateLearnReq(const char *ifname);
-
-void virNWFilterDelIpAddrForIfname(const char *ifname);
-const char *virNWFilterGetIpAddrForIfname(const char *ifname);
-
-int virNWFilterLockIface(const char *ifname) ATTRIBUTE_RETURN_CHECK;
-void virNWFilterUnlockIface(const char *ifname);
-
-int virNWFilterLearnInit(void);
-void virNWFilterLearnShutdown(void);
-void virNWFilterLearnThreadsTerminate(bool allowNewThreads);
-
-#endif /* __NWFILTER_LEARNIPADDR_H */





More information about the libvir-list mailing list