Accepting request 183123 from Virtualization

- update hv_kvp_daemon (merge 0783d72fa from v3.9-rc1)
  Fix how ifcfg-* file is created

- update hv_kvp_daemon (changes up to 3.11-rc1):
  Improve error logging in KVP daemon.
  Fix file descriptor leaks
  Check retrun value of strchr call
  Check return value of poll call
  Check return value of setsockopt call
  daemon should check type of received Netlink msg
  daemon setsockopt should use options macros
  daemon should subscribe only to CN_KVP_IDX group

- Fix a bug in IPV6 subnet enumeration (bnc#828714)

- Update hv_vss_daemon (bnc#811033)

- add hv_vss_daemon (fate#314921)
  helper to support host initiated backup

- build hv_kvp_daemon with -D_GNU_SOURCE to get O_CLOEXEC

- update hv_kvp_daemon
  Use CLOEXEC when opening kvp_pool files
  Fix permissions of created directory and files
  Fix /var subdirectory (move state files from /var/opt to /var/lib)
  Fix string types

OBS-URL: https://build.opensuse.org/request/show/183123
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/hyper-v?expand=0&rev=10
This commit is contained in:
Stephan Kulow 2013-07-16 13:32:58 +00:00 committed by Git OBS Bridge
commit 3d47681214
7 changed files with 603 additions and 89 deletions

View File

@ -1,3 +1,52 @@
-------------------------------------------------------------------
Mon Jul 15 16:16:06 CEST 2013 - ohering@suse.de
- update hv_kvp_daemon (merge 0783d72fa from v3.9-rc1)
Fix how ifcfg-* file is created
-------------------------------------------------------------------
Mon Jul 15 15:24:00 CEST 2013 - ohering@suse.de
- update hv_kvp_daemon (changes up to 3.11-rc1):
Improve error logging in KVP daemon.
Fix file descriptor leaks
Check retrun value of strchr call
Check return value of poll call
Check return value of setsockopt call
daemon should check type of received Netlink msg
daemon setsockopt should use options macros
daemon should subscribe only to CN_KVP_IDX group
-------------------------------------------------------------------
Mon Jul 15 12:04:05 CEST 2013 - ohering@suse.de
- Fix a bug in IPV6 subnet enumeration (bnc#828714)
-------------------------------------------------------------------
Tue Mar 26 18:03:47 CET 2013 - ohering@suse.de
- Update hv_vss_daemon (bnc#811033)
-------------------------------------------------------------------
Fri Mar 22 17:23:36 CET 2013 - ohering@suse.de
- add hv_vss_daemon (fate#314921)
helper to support host initiated backup
-------------------------------------------------------------------
Fri Mar 22 16:56:57 CET 2013 - ohering@suse.de
- build hv_kvp_daemon with -D_GNU_SOURCE to get O_CLOEXEC
-------------------------------------------------------------------
Fri Mar 22 16:19:38 CET 2013 - ohering@suse.de
- update hv_kvp_daemon
Use CLOEXEC when opening kvp_pool files
Fix permissions of created directory and files
Fix /var subdirectory (move state files from /var/opt to /var/lib)
Fix string types
-------------------------------------------------------------------
Tue Nov 27 11:19:32 CET 2012 - ohering@suse.de

View File

@ -27,6 +27,63 @@
#include <linux/types.h>
/*
* Implementation of host controlled snapshot of the guest.
*/
#define VSS_OP_REGISTER 128
enum hv_vss_op {
VSS_OP_CREATE = 0,
VSS_OP_DELETE,
VSS_OP_HOT_BACKUP,
VSS_OP_GET_DM_INFO,
VSS_OP_BU_COMPLETE,
/*
* Following operations are only supported with IC version >= 5.0
*/
VSS_OP_FREEZE, /* Freeze the file systems in the VM */
VSS_OP_THAW, /* Unfreeze the file systems */
VSS_OP_AUTO_RECOVER,
VSS_OP_COUNT /* Number of operations, must be last */
};
/*
* Header for all VSS messages.
*/
struct hv_vss_hdr {
__u8 operation;
__u8 reserved[7];
} __attribute__((packed));
/*
* Flag values for the hv_vss_check_feature. Linux supports only
* one value.
*/
#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
struct hv_vss_check_feature {
__u32 flags;
} __attribute__((packed));
struct hv_vss_check_dm_info {
__u32 flags;
} __attribute__((packed));
struct hv_vss_msg {
union {
struct hv_vss_hdr vss_hdr;
int error;
};
union {
struct hv_vss_check_feature vss_cf;
struct hv_vss_check_dm_info dm_info;
};
} __attribute__((packed));
/*
* An implementation of HyperV key value pair (KVP) functionality for Linux.
*

82
hyper-v.init.vss.sh Normal file
View File

@ -0,0 +1,82 @@
#!/bin/sh
#
# LSB compatible service control script; see http://www.linuxbase.org/spec/
#
### BEGIN INIT INFO
# Provides: hv_vss_daemon
# Required-Start: $null
# Should-Start: $syslog $remote_fs $time
# Required-Stop: $null
# Should-Stop: $syslog $remote_fs $time
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: hv_vss_daemon assists with host initiated backup
# Description: Start hv_vss_daemon to allow the host to snapshot this guest
### END INIT INFO
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
HV_VSS_BIN=/usr/sbin/hv_vss_daemon
test -x $HV_VSS_BIN || { echo "$HV_VSS_BIN not installed";
if [ "$1" = "stop" ]; then exit 0;
else exit 5; fi; }
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo -n "Starting Hyper-V VSS daemon "
env PATH=/usr/lib/hyper-v/bin:$PATH \
startproc $HV_VSS_BIN
rc_status -v
;;
stop)
echo -n "Shutting down Hyper-V VSS daemon "
killproc -TERM $HV_VSS_BIN
rc_status -v
;;
try-restart|condrestart)
if test "$1" = "condrestart"; then
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
fi
$0 status
if test $? = 0; then
$0 restart
else
rc_reset # Not running is not a failure.
fi
# Remember status and be quiet
rc_status
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
# Remember status and be quiet
rc_status
;;
force-reload)
echo -n "Reload service Hyper-V VSS daemon "
$0 try-restart
rc_status
;;
reload)
rc_failed 3
rc_status -v
;;
status)
echo -n "Checking for service Hyper-V VSS daemon "
checkproc $HV_VSS_BIN
rc_status -v
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}"
exit 1
;;
esac
rc_exit

View File

@ -1,7 +1,7 @@
#
# spec file for package hyper-v
#
# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@ -17,22 +17,27 @@
%define hv_kvp_daemon hv_kvp_daemon
%define hv_vss_daemon hv_vss_daemon
Name: hyper-v
ExclusiveArch: %ix86 x86_64
PreReq: %insserv_prereq
Requires(pre): coreutils
Summary: Microsoft Hyper-V tools
License: GPL-2.0
Group: System/Kernel
Supplements: modalias(dmi*:svn*MicrosoftCorporation*:pn*VirtualMachine*:rn*VirtualMachine*)
Supplements: modalias(pci:v00001414d00005353sv*sd*bc*sc*i*)
Url: http://www.kernel.org
Version: 4
# Arbitrary version number
Version: 5
Release: 0
Source5: hyper-v.kvptest.ps1.txt
Source9: hyper-v.include.linux.hyperv.h
Source10: hyper-v.tools.hv.hv_kvp_daemon.c
Source11: hyper-v.init.sh
Source12: hyper-v.tools.hv.hv_vss_daemon.c
Source13: hyper-v.init.vss.sh
Source20: hyper-v.tools.hv.hv_get_dhcp_info.sh
Source21: hyper-v.tools.hv.hv_get_dns_info.sh
Source22: hyper-v.tools.hv.hv_set_ifconfig.sh
@ -47,23 +52,38 @@ This package contains the Microsoft Hyper-V tools.
cp -avL %{S:5} kvptest.ps1.txt
cp -vL %{S:9} %{hv_kvp_daemon}.h
cp -vL %{S:10} %{hv_kvp_daemon}.c
cp -vL %{S:12} %{hv_vss_daemon}.c
%build
sed -i~ '/#include <linux.hyperv.h>/d' %{hv_kvp_daemon}.c
sed -i~ '/#include <linux.hyperv.h>/d' %{hv_vss_daemon}.c
gcc \
$RPM_OPT_FLAGS \
-Wno-unused-variable \
-Wno-pointer-sign \
-D_GNU_SOURCE \
-g \
%{hv_kvp_daemon}.c \
-include %{hv_kvp_daemon}.h \
-DCN_KVP_IDX=0x9 \
-DCN_KVP_VAL=0x1 \
-o %{hv_kvp_daemon}
gcc \
$RPM_OPT_FLAGS \
-Wno-unused-variable \
-Wno-pointer-sign \
-D_GNU_SOURCE \
-g \
%{hv_vss_daemon}.c \
-include %{hv_kvp_daemon}.h \
-DCN_VSS_IDX=0xa \
-DCN_VSS_VAL=0x1 \
-o %{hv_vss_daemon}
%install
mkdir -p $RPM_BUILD_ROOT/usr/sbin
install -m755 %{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin
install -m755 %{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin
mkdir -p $RPM_BUILD_ROOT/usr/lib/%{name}/bin
cp -avL %{S:20} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dhcp_info
cp -avL %{S:21} $RPM_BUILD_ROOT/usr/lib/%{name}/bin/hv_get_dns_info
@ -72,15 +92,35 @@ chmod 755 $RPM_BUILD_ROOT/usr/lib/%{name}/bin/*
mkdir -p $RPM_BUILD_ROOT/etc/init.d
install -m755 %{S:11} $RPM_BUILD_ROOT/etc/init.d/%{hv_kvp_daemon}
ln -sfvbn ../../etc/init.d/%{hv_kvp_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_kvp_daemon}
install -m755 %{S:13} $RPM_BUILD_ROOT/etc/init.d/%{hv_vss_daemon}
ln -sfvbn ../../etc/init.d/%{hv_vss_daemon} $RPM_BUILD_ROOT/usr/sbin/rc%{hv_vss_daemon}
%files
%defattr (-,root,root)
%doc kvptest.ps1.txt
/etc/init.d/%{hv_kvp_daemon}
/usr/sbin/rc%{hv_kvp_daemon}
/usr/sbin/%{hv_kvp_daemon}
/etc/init.d/*
/usr/sbin/*
/usr/lib/%{name}
%pre
# hv_kvp_daemon in SLES11 SP2 stored temporary state files in /var/opt
# move them to /var/lib and remove old directory, if possible.
if test -d /var/opt/hyperv
then
if mkdir -p -v -m 0755 /var/lib/hyperv && pushd /var/lib/hyperv > /dev/null
then
for oldfile in /var/opt/hyperv/ifcfg-* /var/opt/hyperv/.kvp_pool_*
do
if test -e "${oldfile}"
then
mv -vfb "${oldfile}" . || :
fi
done
popd > /dev/null
fi
rmdir -v /var/opt/hyperv || :
fi
%post
board_vendor=
product_name=
@ -100,10 +140,13 @@ if test "${board_vendor}" = "Microsoft Corporation" -a "${product_name}" = "Virt
then
echo "Enabling %{hv_kvp_daemon} on '${product_name}' from '${board_vendor}'"
%{insserv_force_if_yast %{hv_kvp_daemon}}
echo "Enabling %{hv_vss_daemon} on '${product_name}' from '${board_vendor}'"
%{insserv_force_if_yast %{hv_vss_daemon}}
fi
%preun
%stop_on_removal %{hv_kvp_daemon}
%stop_on_removal %{hv_vss_daemon}
%postun
# no restart on update because the daemon can not be restarted

View File

@ -97,11 +97,15 @@ static struct utsname uts_buf;
* The location of the interface configuration file.
*/
#define KVP_CONFIG_LOC "/var/opt/"
#define KVP_CONFIG_LOC "/var/lib/hyperv"
#define MAX_FILE_NAME 100
#define ENTRIES_PER_BLOCK 50
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
struct kvp_record {
char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
@ -123,7 +127,8 @@ static void kvp_acquire_lock(int pool)
fl.l_pid = getpid();
if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
@ -134,8 +139,8 @@ static void kvp_release_lock(int pool)
fl.l_pid = getpid();
if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
perror("fcntl");
syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
@ -151,10 +156,11 @@ static void kvp_update_file(int pool)
*/
kvp_acquire_lock(pool);
filep = fopen(kvp_file_info[pool].fname, "w");
filep = fopen(kvp_file_info[pool].fname, "we");
if (!filep) {
syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
errno, strerror(errno));
kvp_release_lock(pool);
syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
exit(EXIT_FAILURE);
}
@ -182,10 +188,11 @@ static void kvp_update_mem_state(int pool)
kvp_acquire_lock(pool);
filep = fopen(kvp_file_info[pool].fname, "r");
filep = fopen(kvp_file_info[pool].fname, "re");
if (!filep) {
syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
errno, strerror(errno));
kvp_release_lock(pool);
syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
exit(EXIT_FAILURE);
}
for (;;) {
@ -234,9 +241,10 @@ static int kvp_file_init(void)
int i;
int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
if (access("/var/opt/hyperv", F_OK)) {
if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
if (access(KVP_CONFIG_LOC, F_OK)) {
if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
@ -245,20 +253,23 @@ static int kvp_file_init(void)
fname = kvp_file_info[i].fname;
records_read = 0;
num_blocks = 1;
sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
if (fd == -1)
return 1;
filep = fopen(fname, "r");
if (!filep)
filep = fopen(fname, "re");
if (!filep) {
close(fd);
return 1;
}
record = malloc(alloc_unit * num_blocks);
if (record == NULL) {
fclose(filep);
close(fd);
return 1;
}
for (;;) {
@ -282,6 +293,7 @@ static int kvp_file_init(void)
num_blocks);
if (record == NULL) {
fclose(filep);
close(fd);
return 1;
}
continue;
@ -299,7 +311,7 @@ static int kvp_file_init(void)
return 0;
}
static int kvp_key_delete(int pool, __u8 *key, int key_size)
static int kvp_key_delete(int pool, const char *key, int key_size)
{
int i;
int j, k;
@ -342,7 +354,7 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size)
return 1;
}
static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
int value_size)
{
int i;
@ -396,7 +408,7 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
return 0;
}
static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
static int kvp_get_value(int pool, const char *key, int key_size, char *value,
int value_size)
{
int i;
@ -428,8 +440,8 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
return 1;
}
static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
__u8 *value, int value_size)
static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
char *value, int value_size)
{
struct kvp_record *record;
@ -761,7 +773,9 @@ static void kvp_process_ipconfig_file(char *cmd,
break;
x = strchr(p, '\n');
*x = '\0';
if (x)
*x = '\0';
strcat(config_buf, p);
strcat(config_buf, ";");
}
@ -1012,9 +1026,10 @@ kvp_get_ip_info(int family, char *if_name, int op,
if (sn_offset == 0)
strcpy(sn_str, cidr_mask);
else
else {
strcat((char *)ip_buffer->sub_net, ";");
strcat(sn_str, cidr_mask);
strcat((char *)ip_buffer->sub_net, ";");
}
sn_offset += strlen(sn_str) + 1;
}
@ -1162,16 +1177,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
snprintf(str, sizeof(str), "%s", "DNS");
break;
}
if (i != 0) {
if (type != DNS) {
snprintf(sub_str, sizeof(sub_str),
"_%d", i++);
} else {
snprintf(sub_str, sizeof(sub_str),
"%d", ++i);
}
} else if (type == DNS) {
if (type == DNS) {
snprintf(sub_str, sizeof(sub_str), "%d", ++i);
} else if (type == GATEWAY && i == 0) {
++i;
} else {
snprintf(sub_str, sizeof(sub_str), "%d", i++);
}
@ -1191,17 +1203,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
snprintf(str, sizeof(str), "%s", "DNS");
break;
}
if ((j != 0) || (type == DNS)) {
if (type != DNS) {
snprintf(sub_str, sizeof(sub_str),
"_%d", j++);
} else {
snprintf(sub_str, sizeof(sub_str),
"%d", ++i);
}
} else if (type == DNS) {
snprintf(sub_str, sizeof(sub_str),
"%d", ++i);
if (type == DNS) {
snprintf(sub_str, sizeof(sub_str), "%d", ++i);
} else if (j == 0) {
++j;
} else {
snprintf(sub_str, sizeof(sub_str), "_%d", j++);
}
} else {
return HV_INVALIDARG;
@ -1244,18 +1252,19 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
* Here is the format of the ip configuration file:
*
* HWADDR=macaddr
* IF_NAME=interface name
* DHCP=yes (This is optional; if yes, DHCP is configured)
* DEVICE=interface name
* BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
* or "none" if no boot-time protocol should be used)
*
* IPADDR=ipaddr1
* IPADDR_1=ipaddr2
* IPADDR_x=ipaddry (where y = x + 1)
* IPADDR0=ipaddr1
* IPADDR1=ipaddr2
* IPADDRx=ipaddry (where y = x + 1)
*
* NETMASK=netmask1
* NETMASK_x=netmasky (where y = x + 1)
* NETMASK0=netmask1
* NETMASKx=netmasky (where y = x + 1)
*
* GATEWAY=ipaddr1
* GATEWAY_x=ipaddry (where y = x + 1)
* GATEWAYx=ipaddry (where y = x + 1)
*
* DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
*
@ -1271,12 +1280,13 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
*/
snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
"hyperv/ifcfg-", if_name);
"/ifcfg-", if_name);
file = fopen(if_file, "w");
if (file == NULL) {
syslog(LOG_ERR, "Failed to open config file");
syslog(LOG_ERR, "Failed to open config file; error: %d %s",
errno, strerror(errno));
return HV_E_FAIL;
}
@ -1294,12 +1304,12 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
if (error)
goto setval_error;
error = kvp_write_file(file, "IF_NAME", "", if_name);
error = kvp_write_file(file, "DEVICE", "", if_name);
if (error)
goto setval_error;
if (new_val->dhcp_enabled) {
error = kvp_write_file(file, "DHCP", "", "yes");
error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
if (error)
goto setval_error;
@ -1307,6 +1317,11 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
* We are done!.
*/
goto setval_done;
} else {
error = kvp_write_file(file, "BOOTPROTO", "", "none");
if (error)
goto setval_error;
}
/*
@ -1408,7 +1423,7 @@ netlink_send(int fd, struct cn_msg *msg)
int main(void)
{
int fd, len, sock_opt;
int fd, len, nl_group;
int error;
struct cn_msg *message;
struct pollfd pfd;
@ -1438,23 +1453,30 @@ int main(void)
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd < 0) {
syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
syslog(LOG_ERR, "netlink socket creation failed; error: %d %s", errno,
strerror(errno));
exit(EXIT_FAILURE);
}
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = 0;
addr.nl_groups = CN_KVP_IDX;
addr.nl_groups = 0;
error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (error < 0) {
syslog(LOG_ERR, "bind failed; error:%d", error);
syslog(LOG_ERR, "bind failed; error: %d %s", errno, strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
sock_opt = addr.nl_groups;
setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
nl_group = CN_KVP_IDX;
if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
syslog(LOG_ERR, "setsockopt failed; error: %d %s", errno, strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
/*
* Register ourselves with the kernel.
*/
@ -1469,7 +1491,7 @@ int main(void)
len = netlink_send(fd, message);
if (len < 0) {
syslog(LOG_ERR, "netlink_send failed; error:%d", len);
syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
@ -1481,7 +1503,16 @@ int main(void)
socklen_t addr_l = sizeof(addr);
pfd.events = POLLIN;
pfd.revents = 0;
poll(&pfd, 1, -1);
if (poll(&pfd, 1, -1) < 0) {
syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
if (errno == EINVAL) {
close(fd);
exit(EXIT_FAILURE);
}
else
continue;
}
len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
addr_p, &addr_l);
@ -1500,6 +1531,10 @@ int main(void)
}
incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
if (incoming_msg->nlmsg_type != NLMSG_DONE)
continue;
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
@ -1688,7 +1723,8 @@ kvp_done:
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
syslog(LOG_ERR, "net_link send failed; error:%d", len);
syslog(LOG_ERR, "net_link send failed; error: %d %s", errno,
strerror(errno));
exit(EXIT_FAILURE);
}
}

View File

@ -10,18 +10,19 @@
# Here is the format of the ip configuration file:
#
# HWADDR=macaddr
# IF_NAME=interface name
# DHCP=yes (This is optional; if yes, DHCP is configured)
# DEVICE=interface name
# BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
# or "none" if no boot-time protocol should be used)
#
# IPADDR=ipaddr1
# IPADDR_1=ipaddr2
# IPADDR_x=ipaddry (where y = x + 1)
# IPADDR0=ipaddr1
# IPADDR1=ipaddr2
# IPADDRx=ipaddry (where y = x + 1)
#
# NETMASK=netmask1
# NETMASK_x=netmasky (where y = x + 1)
# NETMASK0=netmask1
# NETMASKx=netmasky (where y = x + 1)
#
# GATEWAY=ipaddr1
# GATEWAY_x=ipaddry (where y = x + 1)
# GATEWAYx=ipaddry (where y = x + 1)
#
# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
#
@ -53,8 +54,8 @@ else
fi
# remove known config variables from environment
unset HWADDR
unset DHCP
unset IF_NAME
unset BOOTPROTO
unset DEVICE
unset ${!IPADDR*}
unset ${!NETMASK*}
unset ${!GATEWAY*}
@ -64,9 +65,9 @@ unset ${!IPV6_DEFAULTGW*}
unset ${!DNS*}
. "$1"
#
if test -z "${IF_NAME}"
if test -z "${DEVICE}"
then
echo "Missing IF_NAME= in ${cfg}"
echo "Missing DEVICE= in ${cfg}"
exit 1
fi
#
@ -91,7 +92,7 @@ fi
: # ignore HWADDR, it just repeats the existing MAC value
fi
#
if test "${DHCP}" = "yes"
if test "${BOOTPROTO}" = "dhcp"
then
echo "BOOTPROTO=dhcp"
fi
@ -145,11 +146,11 @@ fi
(
if test -n "${GATEWAY}"
then
echo "default $GATEWAY - $IF_NAME"
echo "default $GATEWAY - $DEVICE"
fi
if test -n "${IPV6_DEFAULTGW}"
then
echo "default $IPV6_DEFAULTGW - $IF_NAME"
echo "default $IPV6_DEFAULTGW - $DEVICE"
fi
) >> "${t_ifroute}"
# Only a single default gateway is supported
@ -172,14 +173,14 @@ do
fi
done
#
echo "$0: working on network interface ifcfg-${IF_NAME}"
cp -fb ${t_ifcfg} "/etc/sysconfig/network/ifcfg-${IF_NAME}"
cp -fb ${t_ifroute} "/etc/sysconfig/network/ifroute-${IF_NAME}"
echo "$0: working on network interface ifcfg-${DEVICE}"
cp -fb ${t_ifcfg} "/etc/sysconfig/network/ifcfg-${DEVICE}"
cp -fb ${t_ifroute} "/etc/sysconfig/network/ifroute-${DEVICE}"
if test -w /etc/sysconfig/network/config
then
sed -i "s@^NETCONFIG_DNS_STATIC_SERVERS=.*@NETCONFIG_DNS_STATIC_SERVERS='$_DNS_'@" /etc/sysconfig/network/config
netconfig update -m dns
fi
ifdown "${IF_NAME}"
ifup "${IF_NAME}"
ifdown "${DEVICE}"
ifup "${DEVICE}"
) 2>&1 | logger -t "${0##*/}[$PPID / $$]"

View File

@ -0,0 +1,246 @@
/*
* An implementation of the host initiated guest snapshot for Hyper-V.
*
*
* Copyright (C) 2013, Microsoft, Inc.
* Author : K. Y. Srinivasan <kys@microsoft.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This program 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, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <mntent.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <arpa/inet.h>
#include <linux/fs.h>
#include <linux/connector.h>
#include <linux/hyperv.h>
#include <linux/netlink.h>
#include <syslog.h>
static char vss_recv_buffer[4096];
static char vss_send_buffer[4096];
static struct sockaddr_nl addr;
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
static int vss_do_freeze(char *dir, unsigned int cmd, char *fs_op)
{
int ret, fd = open(dir, O_RDONLY);
if (fd < 0)
return -1;
ret = ioctl(fd, cmd, 0);
syslog(LOG_INFO, "VSS: %s of %s: %s\n", fs_op, dir, strerror(errno));
close(fd);
return !!ret;
}
static int vss_operate(int operation)
{
char *fs_op;
char match[] = "/dev/";
FILE *mounts;
struct mntent *ent;
unsigned int cmd;
int error = 0, root_seen = 0;
switch (operation) {
case VSS_OP_FREEZE:
cmd = FIFREEZE;
fs_op = "freeze";
break;
case VSS_OP_THAW:
cmd = FITHAW;
fs_op = "thaw";
break;
default:
return -1;
}
mounts = setmntent("/proc/mounts", "r");
if (mounts == NULL)
return -1;
while((ent = getmntent(mounts))) {
if (strncmp(ent->mnt_fsname, match, strlen(match)))
continue;
if (strcmp(ent->mnt_dir, "/") == 0) {
root_seen = 1;
continue;
}
error |= vss_do_freeze(ent->mnt_dir, cmd, fs_op);
}
endmntent(mounts);
if (root_seen) {
error |= vss_do_freeze("/", cmd, fs_op);
}
return error;
}
static int netlink_send(int fd, struct cn_msg *msg)
{
struct nlmsghdr *nlh;
unsigned int size;
struct msghdr message;
char buffer[64];
struct iovec iov[2];
size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
nlh = (struct nlmsghdr *)buffer;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = getpid();
nlh->nlmsg_type = NLMSG_DONE;
nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
nlh->nlmsg_flags = 0;
iov[0].iov_base = nlh;
iov[0].iov_len = sizeof(*nlh);
iov[1].iov_base = msg;
iov[1].iov_len = size;
memset(&message, 0, sizeof(message));
message.msg_name = &addr;
message.msg_namelen = sizeof(addr);
message.msg_iov = iov;
message.msg_iovlen = 2;
return sendmsg(fd, &message, 0);
}
int main(void)
{
int fd, len, nl_group;
int error;
struct cn_msg *message;
struct pollfd pfd;
struct nlmsghdr *incoming_msg;
struct cn_msg *incoming_cn_msg;
int op;
struct hv_vss_msg *vss_msg;
if (daemon(1, 0))
return 1;
openlog("Hyper-V VSS", 0, LOG_USER);
syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd < 0) {
syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
exit(EXIT_FAILURE);
}
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = 0;
addr.nl_groups = 0;
error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (error < 0) {
syslog(LOG_ERR, "bind failed; error:%d", error);
close(fd);
exit(EXIT_FAILURE);
}
nl_group = CN_VSS_IDX;
setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
/*
* Register ourselves with the kernel.
*/
message = (struct cn_msg *)vss_send_buffer;
message->id.idx = CN_VSS_IDX;
message->id.val = CN_VSS_VAL;
message->ack = 0;
vss_msg = (struct hv_vss_msg *)message->data;
vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
message->len = sizeof(struct hv_vss_msg);
len = netlink_send(fd, message);
if (len < 0) {
syslog(LOG_ERR, "netlink_send failed; error:%d", len);
close(fd);
exit(EXIT_FAILURE);
}
pfd.fd = fd;
while (1) {
struct sockaddr *addr_p = (struct sockaddr *) &addr;
socklen_t addr_l = sizeof(addr);
pfd.events = POLLIN;
pfd.revents = 0;
poll(&pfd, 1, -1);
len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
addr_p, &addr_l);
if (len < 0) {
syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
addr.nl_pid, errno, strerror(errno));
close(fd);
return -1;
}
if (addr.nl_pid) {
syslog(LOG_WARNING, "Received packet from untrusted pid:%u",
addr.nl_pid);
continue;
}
incoming_msg = (struct nlmsghdr *)vss_recv_buffer;
if (incoming_msg->nlmsg_type != NLMSG_DONE)
continue;
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data;
op = vss_msg->vss_hdr.operation;
error = HV_S_OK;
switch (op) {
case VSS_OP_FREEZE:
case VSS_OP_THAW:
error = vss_operate(op);
if (error)
error = HV_E_FAIL;
break;
default:
syslog(LOG_ERR, "Illegal op:%d\n", op);
}
vss_msg->error = error;
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
syslog(LOG_ERR, "net_link send failed; error:%d", len);
exit(EXIT_FAILURE);
}
}
}