Skip to content

Commit

Permalink
Replace exec uuid2mac and getIPfromDHCPLease to native golang
Browse files Browse the repository at this point in the history
  • Loading branch information
zchee committed Sep 20, 2015
1 parent 97fb55a commit a26df39
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 53 deletions.
16 changes: 0 additions & 16 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,6 @@ func uuidgen() string {
return strings.Replace(out, "\n", "", 1)
}

func uuid2mac(uuid string) string {
cmd := exec.Command("sudo", "uuid2mac", uuid)

var stdout bytes.Buffer
cmd.Stdout = &stdout
log.Debugf("execute: %v %v", cmd, uuid)

err := cmd.Run()
if err != nil {
log.Error(err)
}

out := stdout.String()
return strings.Replace(out, "\n", "", 1)
}

func hdiutil(args ...string) error {
cmd := exec.Command("hdiutil", args...)

Expand Down
86 changes: 86 additions & 0 deletions vmnet/dhcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package vmnet

import (
"bufio"
"fmt"
"os"
"strings"
)

const (
DHCPD_LEASES_FILE = "/var/db/dhcpd_leases"
)

type DHCPEntry struct {
Name string
IPAddress string
HWAddress string
ID string
Lease string
}

func parseDHCPdLeasesFile() ([]DHCPEntry, error) {
file, err := os.Open(DHCPD_LEASES_FILE)
if err != nil {
return nil, err
}
defer file.Close()

var (
dhcpEntry *DHCPEntry
dhcpEntries []DHCPEntry
)

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "{" {
dhcpEntry = new(DHCPEntry)
}
if strings.HasPrefix(line, "name=") {
dhcpEntry.Name = line[5:]
}
if strings.HasPrefix(line, "ip_address=") {
dhcpEntry.IPAddress = line[11:]
}
if strings.HasPrefix(line, "hw_address=") {
dhcpEntry.HWAddress = line[13:]
}
if strings.HasPrefix(line, "identifier=") {
dhcpEntry.ID = line[11:]
}
if strings.HasPrefix(line, "lease=") {
dhcpEntry.Lease = line[6:]
}
if line == "}" {
dhcpEntries = append(dhcpEntries, *dhcpEntry)
}
}
return dhcpEntries, scanner.Err()
}

func GetIPAddressByMACAddress(mac string) (string, error) {
dhcpEntries, err := parseDHCPdLeasesFile()
if err != nil {
return "", err
}
for _, dhcpEntry := range dhcpEntries {
if dhcpEntry.HWAddress == mac {
return dhcpEntry.IPAddress, nil
}
}
return "", fmt.Errorf("Could not find an IP address for %s", mac)
}

func GetIPAddressByName(name string) (string, error) {
dhcpEntries, err := parseDHCPdLeasesFile()
if err != nil {
return "", err
}
for _, dhcpEntry := range dhcpEntries {
if dhcpEntry.Name == name {
return dhcpEntry.IPAddress, nil
}
}
return "", fmt.Errorf("Could not find an IP address for %s", name)
}
153 changes: 153 additions & 0 deletions vmnet/uuid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*-
* Copyright (c) 2002,2005 Marcel Moolenaar
* Copyright (c) 2002 Hiten Mahesh Pandya
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/

#pragma once

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define _UUID_NODE_LEN 6

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
struct uuid {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version;
uint8_t clock_seq_hi_and_reserved;
uint8_t clock_seq_low;
uint8_t node[_UUID_NODE_LEN];
};
#pragma clang diagnostic pop

typedef struct uuid uuid_internal_t;

/*
* This implementation mostly conforms to the DCE 1.1 specification.
* See Also:
* uuidgen(1), uuidgen(2), uuid(3)
*/

/* Status codes returned by the functions. */
#define uuid_s_ok 0
#define uuid_s_bad_version 1
#define uuid_s_invalid_string_uuid 2
#define uuid_s_no_memory 3

/*
* uuid_create_nil() - create a nil UUID.
* See also:
* http://www.opengroup.org/onlinepubs/009629399/uuid_create_nil.htm
*/
static inline void
uuid_create_nil(uuid_t *u, uint32_t *status)
{
if (status)
*status = uuid_s_ok;

bzero(u, sizeof(*u));
}

static inline void
uuid_enc_le(void *buf, uuid_t *uuid)
{
uuid_internal_t *u = (uuid_internal_t *) ((void *) uuid);
uint8_t *p = buf;
int i;

memcpy(p, &u->time_low, 4);
memcpy(p, &u->time_mid, 2);
memcpy(p, &u->time_hi_and_version, 2);
p[8] = u->clock_seq_hi_and_reserved;
p[9] = u->clock_seq_low;
for (i = 0; i < _UUID_NODE_LEN; i++)
p[10 + i] = u->node[i];
}

/*
* uuid_from_string() - convert a string representation of an UUID into
* a binary representation.
* See also:
* http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm
*
* NOTE: The sequence field is in big-endian, while the time fields are in
* native byte order.
*/
static inline void
uuid_from_string(const char *s, uuid_t *uuid, uint32_t *status)
{
uuid_internal_t *u = (uuid_internal_t *) ((void *) uuid);
int n;

/* Short-circuit 2 special cases: NULL pointer and empty string. */
if (s == NULL || *s == '\0') {
uuid_create_nil(((uuid_t *) u), status);
return;
}

/* Assume the worst. */
if (status != NULL)
*status = uuid_s_invalid_string_uuid;

/* The UUID string representation has a fixed length. */
if (strlen(s) != 36)
return;

/*
* We only work with "new" UUIDs. New UUIDs have the form:
* 01234567-89ab-cdef-0123-456789abcdef
* The so called "old" UUIDs, which we don't support, have the form:
* 0123456789ab.cd.ef.01.23.45.67.89.ab
*/
if (s[8] != '-')
return;

n = sscanf(s,
"%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
&u->time_low, &u->time_mid, &u->time_hi_and_version,
&u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0],
&u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]);

/* Make sure we have all conversions. */
if (n != 11)
return;

/* We have a successful scan. Check semantics... */
n = u->clock_seq_hi_and_reserved;
if ((n & 0x80) != 0x00 && /* variant 0? */
(n & 0xc0) != 0x80 && /* variant 1? */
(n & 0xe0) != 0xc0) { /* variant 2? */
if (status != NULL)
*status = uuid_s_bad_version;
} else {
if (status != NULL)
*status = uuid_s_ok;
}
}
133 changes: 133 additions & 0 deletions vmnet/vmnet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*-
* Copyright (c) 2011 NetApp, Inc.
* Copyright (c) 2015 xhyve developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/

/*
* https://github.com/mirage/ocaml-vmnet/blob/master/lib/vmnet_stubs.c
*
* Copyright (C) 2014 Anil Madhavapeddy <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <stdio.h>

#include <vmnet/vmnet.h>

#include "uuid.h"

static char*
vmnet_get_mac_address_from_uuid(char *guest_uuid_str) {
/*
* from vmn_create() in https://github.com/mist64/xhyve/blob/master/src/pci_virtio_vmnet.c
*/
xpc_object_t interface_desc;
uuid_t uuid;
__block interface_ref iface;
__block vmnet_return_t iface_status;
__block char* mac = malloc(18);
dispatch_semaphore_t iface_created, iface_stopped;
dispatch_queue_t if_create_q, if_stop_q;
uint32_t uuid_status;

interface_desc = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(interface_desc, vmnet_operation_mode_key, VMNET_SHARED_MODE);

uuid_from_string(guest_uuid_str, &uuid, &uuid_status);
if (uuid_status != uuid_s_ok) {
fprintf(stderr, "Invalid UUID\n");
return NULL;
}

xpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, uuid);
iface = NULL;
iface_status = 0;

if_create_q = dispatch_queue_create("org.xhyve.vmnet.create", DISPATCH_QUEUE_SERIAL);

iface_created = dispatch_semaphore_create(0);

iface = vmnet_start_interface(interface_desc, if_create_q,
^(vmnet_return_t status, xpc_object_t interface_param)
{
iface_status = status;
if (status != VMNET_SUCCESS || !interface_param) {
dispatch_semaphore_signal(iface_created);
return;
}

//printf("%s\n", xpc_dictionary_get_string(interface_param, vmnet_mac_address_key));
const char *macStr = xpc_dictionary_get_string(interface_param, vmnet_mac_address_key);
strcpy(mac, macStr);

dispatch_semaphore_signal(iface_created);
});

dispatch_semaphore_wait(iface_created, DISPATCH_TIME_FOREVER);
dispatch_release(if_create_q);

if (iface == NULL || iface_status != VMNET_SUCCESS) {
fprintf(stderr, "virtio_net: Could not create vmnet interface, "
"permission denied or no entitlement?\n");
return NULL;
}

iface_status = 0;

if_stop_q = dispatch_queue_create("org.xhyve.vmnet.stop", DISPATCH_QUEUE_SERIAL);

iface_stopped = dispatch_semaphore_create(0);

iface_status = vmnet_stop_interface(iface, if_stop_q,
^(vmnet_return_t status)
{
iface_status = status;
dispatch_semaphore_signal(iface_stopped);
});

dispatch_semaphore_wait(iface_stopped, DISPATCH_TIME_FOREVER);
dispatch_release(if_stop_q);

if (iface_status != VMNET_SUCCESS) {
fprintf(stderr, "virtio_net: Could not stop vmnet interface, "
"permission denied or no entitlement?\n");
return NULL;
}

return mac;
}
Loading

0 comments on commit a26df39

Please sign in to comment.