mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-28 04:58:32 +00:00
Merge pull request #2490 from MagnusS/update-vpnkit
Update to latest Hyperkit API
This commit is contained in:
commit
c793ea973c
@ -41,11 +41,13 @@ func runHyperKit(args []string) {
|
|||||||
var disks Disks
|
var disks Disks
|
||||||
flags.Var(&disks, "disk", "Disk config. [file=]path[,size=1G]")
|
flags.Var(&disks, "disk", "Disk config. [file=]path[,size=1G]")
|
||||||
data := flags.String("data", "", "Metadata to pass to VM (either a path to a file or a string)")
|
data := flags.String("data", "", "Metadata to pass to VM (either a path to a file or a string)")
|
||||||
ipStr := flags.String("ip", "", "IP address for the VM")
|
ipStr := flags.String("ip", "", "Preferred IPv4 address for the VM.")
|
||||||
state := flags.String("state", "", "Path to directory to keep VM state in")
|
state := flags.String("state", "", "Path to directory to keep VM state in")
|
||||||
vsockports := flags.String("vsock-ports", "", "List of vsock ports to forward from the guest on startup (comma separated). A unix domain socket for each port will be created in the state directory")
|
vsockports := flags.String("vsock-ports", "", "List of vsock ports to forward from the guest on startup (comma separated). A unix domain socket for each port will be created in the state directory")
|
||||||
networking := flags.String("networking", hyperkitNetworkingDefault, "Networking mode. Valid options are 'default', 'docker-for-mac', 'vpnkit[,socket-path]', 'vmnet' and 'none'. 'docker-for-mac' connects to the network used by Docker for Mac. 'vpnkit' connects to the VPNKit socket specified. If socket-path is omitted a new VPNKit instance will be started and 'vpnkit_eth.sock' will be created in the state directory. 'vmnet' uses the Apple vmnet framework, requires root/sudo. 'none' disables networking.`")
|
networking := flags.String("networking", hyperkitNetworkingDefault, "Networking mode. Valid options are 'default', 'docker-for-mac', 'vpnkit[,socket-path]', 'vmnet' and 'none'. 'docker-for-mac' connects to the network used by Docker for Mac. 'vpnkit' connects to the VPNKit socket specified. If socket-path is omitted a new VPNKit instance will be started and 'vpnkit_eth.sock' will be created in the state directory. 'vmnet' uses the Apple vmnet framework, requires root/sudo. 'none' disables networking.`")
|
||||||
|
|
||||||
|
vpnKitUUID := flags.String("vpnkit-uuid", "", "Optional UUID used to identify the VPNKit connection. Overrides 'uuid.vpnkit' in the state directory.")
|
||||||
|
|
||||||
// Boot type; we try to determine automatically
|
// Boot type; we try to determine automatically
|
||||||
uefiBoot := flags.Bool("uefi", false, "Use UEFI boot")
|
uefiBoot := flags.Bool("uefi", false, "Use UEFI boot")
|
||||||
isoBoot := flags.Bool("iso", false, "Boot image is an ISO")
|
isoBoot := flags.Bool("iso", false, "Boot image is an ISO")
|
||||||
@ -149,17 +151,22 @@ func runHyperKit(args []string) {
|
|||||||
isoPaths = append(isoPaths, isoPath)
|
isoPaths = append(isoPaths, isoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
vpnKitKey := ""
|
// Create UUID for VPNKit or reuse an existing one from state dir. IP addresses are
|
||||||
if *ipStr != "" {
|
// assigned to the UUID, so to get the same IP we have to store the initial UUID. If
|
||||||
// If an IP address was requested construct a "special" UUID
|
// has specified a VPNKit UUID the file is ignored.
|
||||||
// for the VM.
|
if *vpnKitUUID == "" {
|
||||||
if ip := net.ParseIP(*ipStr); len(ip) > 0 {
|
vpnKitUUIDFile := filepath.Join(*state, "uuid.vpnkit")
|
||||||
uuid := make([]byte, 16)
|
if _, err := os.Stat(vpnKitUUIDFile); os.IsNotExist(err) {
|
||||||
uuid[12] = ip.To4()[0]
|
*vpnKitUUID = uuid.NewV4().String()
|
||||||
uuid[13] = ip.To4()[1]
|
if err := ioutil.WriteFile(vpnKitUUIDFile, []byte(*vpnKitUUID), 0600); err != nil {
|
||||||
uuid[14] = ip.To4()[2]
|
log.Fatalf("Unable to write to %s: %v", vpnKitUUIDFile, err)
|
||||||
uuid[15] = ip.To4()[3]
|
}
|
||||||
vpnKitKey = fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
|
} else {
|
||||||
|
uuid, err := ioutil.ReadFile(vpnKitUUIDFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to read VPNKit UUID from %s: %v", vpnKitUUIDFile, err)
|
||||||
|
}
|
||||||
|
*vpnKitUUID = string(uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,13 +259,21 @@ func runHyperKit(args []string) {
|
|||||||
} else {
|
} else {
|
||||||
h.Bootrom = *fw
|
h.Bootrom = *fw
|
||||||
}
|
}
|
||||||
h.VPNKitKey = vpnKitKey
|
|
||||||
h.UUID = vmUUID
|
h.UUID = vmUUID
|
||||||
h.ISOImages = isoPaths
|
h.ISOImages = isoPaths
|
||||||
h.VSock = true
|
h.VSock = true
|
||||||
h.CPUs = *cpus
|
h.CPUs = *cpus
|
||||||
h.Memory = *mem
|
h.Memory = *mem
|
||||||
|
|
||||||
|
h.VPNKitUUID = *vpnKitUUID
|
||||||
|
if *ipStr != "" {
|
||||||
|
if ip := net.ParseIP(*ipStr); len(ip) > 0 && ip.To4() != nil {
|
||||||
|
h.VPNKitPreferredIPv4 = ip.String()
|
||||||
|
} else {
|
||||||
|
log.Fatalf("Unable to parse IPv4 address: %v", *ipStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = h.Run(string(cmdline))
|
err = h.Run(string(cmdline))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Cannot run hyperkit: %v", err)
|
log.Fatalf("Cannot run hyperkit: %v", err)
|
||||||
|
@ -11,7 +11,7 @@ github.com/googleapis/gax-go 8c5154c0fe5bf18cf649634d4c6df50897a32751
|
|||||||
github.com/gophercloud/gophercloud 2804b72cf099b41d2e25c8afcca786f9f962ddee
|
github.com/gophercloud/gophercloud 2804b72cf099b41d2e25c8afcca786f9f962ddee
|
||||||
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||||
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
||||||
github.com/moby/hyperkit a82b409a87f12fa3306813410c37f4eed270efac
|
github.com/moby/hyperkit 3e31617ae866c93925e2b3bc5d8006b60985e920
|
||||||
github.com/packethost/packngo 131798f2804a1b3e895ca98047d56f0d7e094e2a
|
github.com/packethost/packngo 131798f2804a1b3e895ca98047d56f0d7e094e2a
|
||||||
github.com/radu-matei/azure-sdk-for-go 3b12823551999669c9a325a32472508e0af7978e
|
github.com/radu-matei/azure-sdk-for-go 3b12823551999669c9a325a32472508e0af7978e
|
||||||
github.com/radu-matei/azure-vhd-utils e52754d5569d2a643a7775f72ff2a6cf524f4c25
|
github.com/radu-matei/azure-vhd-utils e52754d5569d2a643a7775f72ff2a6cf524f4c25
|
||||||
|
24
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/go/hyperkit.go
generated
vendored
24
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/go/hyperkit.go
generated
vendored
@ -28,6 +28,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
@ -85,8 +86,10 @@ type HyperKit struct {
|
|||||||
StateDir string `json:"state_dir"`
|
StateDir string `json:"state_dir"`
|
||||||
// VPNKitSock is the location of the VPNKit socket used for networking.
|
// VPNKitSock is the location of the VPNKit socket used for networking.
|
||||||
VPNKitSock string `json:"vpnkit_sock"`
|
VPNKitSock string `json:"vpnkit_sock"`
|
||||||
// VPNKitKey is a string containing a UUID, it can be used in conjunction with VPNKit to get consistent IP address.
|
// VPNKitUUID is a string containing a UUID, it can be used in conjunction with VPNKit to get consistent IP address.
|
||||||
VPNKitKey string `json:"vpnkit_key"`
|
VPNKitUUID string `json:"vpnkit_uuid"`
|
||||||
|
// VPNKitPreferredIPv4 is a string containing an IPv4 address, it can be used to request a specific IP for a UUID from VPNKit.
|
||||||
|
VPNKitPreferredIPv4 string `json:"vpnkit_preferred_ipv4"`
|
||||||
// UUID is a string containing a UUID, it sets BIOS DMI UUID for the VM (as found in /sys/class/dmi/id/product_uuid on Linux).
|
// UUID is a string containing a UUID, it sets BIOS DMI UUID for the VM (as found in /sys/class/dmi/id/product_uuid on Linux).
|
||||||
UUID string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
// Disks contains disk images to use/create.
|
// Disks contains disk images to use/create.
|
||||||
@ -249,6 +252,11 @@ func (h *HyperKit) execute(cmdline string) error {
|
|||||||
return fmt.Errorf("Bootrom %s does not exist", h.Bootrom)
|
return fmt.Errorf("Bootrom %s does not exist", h.Bootrom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if h.VPNKitPreferredIPv4 != "" {
|
||||||
|
if ip := net.ParseIP(h.VPNKitPreferredIPv4); ip == nil {
|
||||||
|
return fmt.Errorf("Invalid VPNKit IP: %s", h.VPNKitPreferredIPv4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create files
|
// Create files
|
||||||
if h.StateDir != "" {
|
if h.StateDir != "" {
|
||||||
@ -420,11 +428,15 @@ func (h *HyperKit) buildArgs(cmdline string) {
|
|||||||
nextSlot := 1
|
nextSlot := 1
|
||||||
|
|
||||||
if h.VPNKitSock != "" {
|
if h.VPNKitSock != "" {
|
||||||
if h.VPNKitKey == "" {
|
var uuid string
|
||||||
a = append(a, "-s", fmt.Sprintf("%d:0,virtio-vpnkit,path=%s", nextSlot, h.VPNKitSock))
|
if h.VPNKitUUID != "" {
|
||||||
} else {
|
uuid = fmt.Sprintf(",uuid=%s", h.VPNKitUUID)
|
||||||
a = append(a, "-s", fmt.Sprintf("%d:0,virtio-vpnkit,path=%s,uuid=%s", nextSlot, h.VPNKitSock, h.VPNKitKey))
|
|
||||||
}
|
}
|
||||||
|
var preferredIPv4 string
|
||||||
|
if h.VPNKitPreferredIPv4 != "" {
|
||||||
|
preferredIPv4 = fmt.Sprintf(",preferred_ipv4=%s", h.VPNKitPreferredIPv4)
|
||||||
|
}
|
||||||
|
a = append(a, "-s", fmt.Sprintf("%d:0,virtio-vpnkit,path=%s%s%s", nextSlot, h.VPNKitSock, uuid, preferredIPv4))
|
||||||
nextSlot++
|
nextSlot++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/src/lib/pci_virtio_net_vpnkit.c
generated
vendored
103
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/src/lib/pci_virtio_net_vpnkit.c
generated
vendored
@ -77,6 +77,8 @@
|
|||||||
#include <xhyve/pci_emul.h>
|
#include <xhyve/pci_emul.h>
|
||||||
#include <xhyve/mevent.h>
|
#include <xhyve/mevent.h>
|
||||||
#include <xhyve/virtio.h>
|
#include <xhyve/virtio.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
|
||||||
#define WPRINTF(format, ...) printf(format, __VA_ARGS__)
|
#define WPRINTF(format, ...) printf(format, __VA_ARGS__)
|
||||||
|
|
||||||
@ -93,13 +95,18 @@ struct msg_init {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define CMD_ETHERNET 1
|
#define CMD_ETHERNET 1
|
||||||
struct msg_common {
|
#define CMD_PREFERRED_IPV4 8
|
||||||
uint8_t command;
|
|
||||||
|
#define RESP_VIF 1
|
||||||
|
#define RESP_DISCONNECT 2
|
||||||
|
|
||||||
|
struct cmd_ethernet {
|
||||||
|
char uuid[36];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct msg_ethernet {
|
struct cmd_preferred_ipv4 {
|
||||||
uint8_t command; /* CMD_ETHERNET */
|
|
||||||
char uuid[36];
|
char uuid[36];
|
||||||
|
in_addr_t ip;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct vif_info {
|
struct vif_info {
|
||||||
@ -108,6 +115,26 @@ struct vif_info {
|
|||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct disconnect_reason {
|
||||||
|
uint8_t len;
|
||||||
|
char msg[256];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct msg_command {
|
||||||
|
uint8_t command;
|
||||||
|
union {
|
||||||
|
struct cmd_ethernet ethernet;
|
||||||
|
struct cmd_preferred_ipv4 preferred_ipv4;
|
||||||
|
};
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct msg_response {
|
||||||
|
uint8_t response_type;
|
||||||
|
union {
|
||||||
|
struct disconnect_reason disconnect;
|
||||||
|
struct vif_info vif;
|
||||||
|
};
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Host capabilities. Note that we only offer a few of these.
|
* Host capabilities. Note that we only offer a few of these.
|
||||||
@ -286,11 +313,11 @@ err:
|
|||||||
/*
|
/*
|
||||||
* wire protocol
|
* wire protocol
|
||||||
*/
|
*/
|
||||||
static int vpnkit_connect(int fd, const char uuid[36], struct vif_info *vif)
|
static int vpnkit_connect(int fd, const char uuid[36], struct vif_info *vif, in_addr_t preferred_ipv4)
|
||||||
{
|
{
|
||||||
struct msg_init init_msg = {
|
struct msg_init init_msg = {
|
||||||
.magic = { 'V', 'M', 'N', '3', 'T' },
|
.magic = { 'V', 'M', 'N', '3', 'T' },
|
||||||
.version = 1U,
|
.version = 22U,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* msg.commit is not NULL terminated */
|
/* msg.commit is not NULL terminated */
|
||||||
@ -324,21 +351,49 @@ static int vpnkit_connect(int fd, const char uuid[36], struct vif_info *vif)
|
|||||||
init_reply.magic[4],
|
init_reply.magic[4],
|
||||||
init_reply.version, (int)sizeof(init_reply.commit), init_reply.commit);
|
init_reply.version, (int)sizeof(init_reply.commit), init_reply.commit);
|
||||||
|
|
||||||
struct msg_ethernet cmd_ethernet = {
|
if (init_reply.version != init_msg.version) {
|
||||||
.command = CMD_ETHERNET,
|
fprintf(stderr, "virtio-net-vpnkit: protocol version mismatch: version %d requested, got version %d.\n",
|
||||||
};
|
init_msg.version,
|
||||||
memcpy(cmd_ethernet.uuid, uuid, sizeof(cmd_ethernet.uuid));
|
init_reply.version);
|
||||||
|
}
|
||||||
|
|
||||||
if (really_write(fd, (uint8_t*)&cmd_ethernet, sizeof(cmd_ethernet)) < 0) {
|
struct msg_command cmd;
|
||||||
fprintf(stderr, "virtio-net-vpnkit: failed to write ethernet cmd\n");
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
if (preferred_ipv4 != 0) {
|
||||||
|
cmd.command = CMD_PREFERRED_IPV4;
|
||||||
|
memcpy(cmd.preferred_ipv4.uuid, uuid, sizeof(cmd.preferred_ipv4.uuid));
|
||||||
|
/* VPNKit uses LE, so swap the IP from network byte order */
|
||||||
|
cmd.preferred_ipv4.ip = OSSwapInt32(preferred_ipv4);
|
||||||
|
} else {
|
||||||
|
/* No preferred IPv4 address, falling back to requesting a dynamic address */
|
||||||
|
cmd.command = CMD_ETHERNET;
|
||||||
|
memcpy(cmd.ethernet.uuid, uuid, sizeof(cmd.ethernet.uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (really_write(fd, (uint8_t*)&cmd, sizeof(cmd)) < 0) {
|
||||||
|
fprintf(stderr, "virtio-net-vpnkit: failed to write command\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (really_read(fd, (uint8_t*)vif, sizeof(*vif)) < 0) {
|
struct msg_response reply;
|
||||||
fprintf(stderr, "virtio-net-vpnkit: failed to read vif info\n");
|
if (really_read(fd, (uint8_t*)&reply, sizeof(reply)) < 0) {
|
||||||
|
fprintf(stderr, "virtio-net-vpnkit: failed to read response message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (reply.response_type) {
|
||||||
|
case RESP_VIF:
|
||||||
|
memcpy((uint8_t*)vif, (uint8_t*)&reply.vif, sizeof(*vif));
|
||||||
|
break;
|
||||||
|
case RESP_DISCONNECT:
|
||||||
|
fprintf(stderr, "virtio-net-vpnkit: server disconnected: %*s\n", reply.disconnect.len, reply.disconnect.msg);
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "virtio-net-vpnkit: unknown response from server: %d\n", reply.response_type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,9 +417,11 @@ vpnkit_create(struct pci_vtnet_softc *sc, const char *opts)
|
|||||||
const char *path = "/var/tmp/com.docker.slirp.socket";
|
const char *path = "/var/tmp/com.docker.slirp.socket";
|
||||||
char *macfile = NULL;
|
char *macfile = NULL;
|
||||||
char *tmp = NULL;
|
char *tmp = NULL;
|
||||||
|
char *ipv4 = NULL;
|
||||||
uuid_t uuid;
|
uuid_t uuid;
|
||||||
char uuid_string[37];
|
char uuid_string[37];
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
|
struct in_addr preferred_ipv4 = { .s_addr = 0 };
|
||||||
int fd;
|
int fd;
|
||||||
struct vpnkit_state *state = malloc(sizeof(struct vpnkit_state));
|
struct vpnkit_state *state = malloc(sizeof(struct vpnkit_state));
|
||||||
if (!state) abort();
|
if (!state) abort();
|
||||||
@ -393,11 +450,16 @@ vpnkit_create(struct pci_vtnet_softc *sc, const char *opts)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
memcpy(&uuid_string[0], &tmp[0], 36);
|
memcpy(&uuid_string[0], &tmp[0], 36);
|
||||||
fprintf(stdout, "Interface will have uuid %s\n", tmp);
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
tmp = NULL;
|
tmp = NULL;
|
||||||
} else if (strncmp(opts, "macfile=", 8) == 0) {
|
} else if (strncmp(opts, "macfile=", 8) == 0) {
|
||||||
macfile = copy_up_to_comma(opts + 8);
|
macfile = copy_up_to_comma(opts + 8);
|
||||||
|
} else if (strncmp(opts, "preferred_ipv4=", 15) == 0) {
|
||||||
|
ipv4 = copy_up_to_comma(opts + 15);
|
||||||
|
if (inet_aton(ipv4, &preferred_ipv4) == 0) {
|
||||||
|
fprintf(stderr, "Unable to parse requested IP %s\n", ipv4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "invalid option: %s\r\n", opts);
|
fprintf(stderr, "invalid option: %s\r\n", opts);
|
||||||
return 1;
|
return 1;
|
||||||
@ -407,6 +469,11 @@ vpnkit_create(struct pci_vtnet_softc *sc, const char *opts)
|
|||||||
opts = &next[1];
|
opts = &next[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "virtio-net-vpnkit: interface will have uuid %s\n", uuid_string);
|
||||||
|
if (ipv4 != NULL) {
|
||||||
|
fprintf(stdout, "virtio-net-vpnkit: requesting ip %s\n", ipv4);
|
||||||
|
}
|
||||||
|
|
||||||
state->vif.max_packet_size = 1500;
|
state->vif.max_packet_size = 1500;
|
||||||
sc->state = state;
|
sc->state = state;
|
||||||
|
|
||||||
@ -423,7 +490,7 @@ vpnkit_create(struct pci_vtnet_softc *sc, const char *opts)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vpnkit_connect(fd, uuid_string, &state->vif) == 0)
|
if (vpnkit_connect(fd, uuid_string, &state->vif, preferred_ipv4.s_addr) == 0)
|
||||||
/* success */
|
/* success */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -441,8 +508,8 @@ err:
|
|||||||
state->fd = fd;
|
state->fd = fd;
|
||||||
|
|
||||||
struct vif_info *info = &state->vif;
|
struct vif_info *info = &state->vif;
|
||||||
fprintf(stdout, "Connection established with MAC=%02x:%02x:%02x:%02x:%02x:%02x and MTU %d\n",
|
fprintf(stdout, "virtio-net-vpnkit: Connection established with MAC=%02x:%02x:%02x:%02x:%02x:%02x and MTU %d\n",
|
||||||
info->mac[0], info->mac[1], info->mac[2], info->mac[3], info->mac[4], info->mac[5],
|
info->mac[0], info->mac[1], info->mac[2], info->mac[3], info->mac[4], info->mac[5],
|
||||||
(int)info->mtu);
|
(int)info->mtu);
|
||||||
|
|
||||||
if (macfile) {
|
if (macfile) {
|
||||||
|
Loading…
Reference in New Issue
Block a user