diff --git a/libnozzle/libnozzle.c b/libnozzle/libnozzle.c
index 948e8363..95ab1132 100644
--- a/libnozzle/libnozzle.c
+++ b/libnozzle/libnozzle.c
@@ -1,1153 +1,1148 @@
 /*
  * Copyright (C) 2010-2018 Red Hat, Inc.  All rights reserved.
  *
  * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
  *
  * This software licensed under GPL-2.0+, LGPL-2.0+
  */
 
 #include "config.h"
 
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <net/ethernet.h>
 #include <pthread.h>
 #include <limits.h>
 #include <stdio.h>
 #include <net/if.h>
 #include <ifaddrs.h>
 #include <stdint.h>
 
 #ifdef KNET_LINUX
 #include <linux/if_tun.h>
 #include <netinet/ether.h>
 #endif
 #ifdef KNET_BSD
 #include <net/if_dl.h>
 #endif
 
 #include "libnozzle.h"
 #include "internals.h"
 
 /*
  * internal functions are all _unlocked_
  * locking should be handled at external API functions
  */
 static int lib_init = 0;
 static struct nozzle_lib_config lib_cfg;
 static pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * internal helpers
  */
 
 static void _close(nozzle_t nozzle)
 {
 #ifdef KNET_BSD
 	struct ifreq ifr;
 #endif
 
 	if (!nozzle)
 		return;
 
 	if (nozzle->fd)
 		close(nozzle->fd);
 
 #ifdef KNET_BSD
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 
 	ioctl(lib_cfg.ioctlfd, SIOCIFDESTROY, &ifr);
 #endif
 
 	free(nozzle);
 
 	return;
 }
 
 static void _close_cfg(void)
 {
 	if (lib_cfg.head == NULL) {
 		close(lib_cfg.ioctlfd);
 		lib_init = 0;
 	}
 }
 
-static int _set_down(nozzle_t nozzle, char **error_down, char **error_postdown)
+static int _set_down(nozzle_t nozzle)
 {
 	int err = 0, savederrno = 0;
 	struct ifreq ifr;
 
 	if (!nozzle->up) {
 		goto out_clean;
 	}
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	ifr.ifr_flags &= ~IFF_UP;
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	nozzle->up = 0;
 
 out_clean:
 	errno = savederrno;
 	return err;
 }
 
 static int _set_ip(nozzle_t nozzle, const char *command,
 		      const char *ipaddr, const char *prefix,
 		      char **error_string, int secondary)
 {
 	char *broadcast = NULL;
 	char cmdline[4096];
 #ifdef KNET_BSD
 	char proto[6];
 	int v4 = 1;
 
 	snprintf(proto, sizeof(proto), "inet");
 #endif
 
 	if (!strchr(ipaddr, ':')) {
 		broadcast = generate_v4_broadcast(ipaddr, prefix);
 		if (!broadcast) {
 			errno = EINVAL;
 			return -1;
 		}
 	}
 #ifdef KNET_BSD
 	  else {
 		v4 = 0;
 		snprintf(proto, sizeof(proto), "inet6");
 	}
 #endif
 
 	memset(cmdline, 0, sizeof(cmdline));
 
 #ifdef KNET_LINUX
 	if (broadcast) {
 		snprintf(cmdline, sizeof(cmdline)-1,
 			 "ip addr %s %s/%s dev %s broadcast %s",
 			 command, ipaddr, prefix,
 			 nozzle->name, broadcast);
 	} else {
 		snprintf(cmdline, sizeof(cmdline)-1,
 			 "ip addr %s %s/%s dev %s",
 			command, ipaddr, prefix,
 			nozzle->name);
 	}
 #endif
 #ifdef KNET_BSD
 	if (!strcmp(command, "add")) {
 		snprintf(cmdline, sizeof(cmdline)-1,
 			 "ifconfig %s %s %s/%s",
 			 nozzle->name, proto, ipaddr, prefix);
 		if (broadcast) {
 			snprintf(cmdline + strlen(cmdline),
 				 sizeof(cmdline) - strlen(cmdline) -1,
 				 " broadcast %s", broadcast);
 		}
 		if ((secondary) && (v4)) {
 			snprintf(cmdline + strlen(cmdline),
 				 sizeof(cmdline) - strlen(cmdline) -1,
 				 " alias");
 		}
 	} else {
 		snprintf(cmdline, sizeof(cmdline)-1,
 				 "ifconfig %s %s %s/%s delete",
 				 nozzle->name, proto, ipaddr, prefix);
 	}
 #endif
 	if (broadcast) {
 		free(broadcast);
 	}
 	return execute_bin_sh_command(cmdline, error_string);
 }
 
 /*
  * internal helpers below should be completed
  *
  * keep all ioctl work within this file
  */
 
 static int is_valid_nozzle(const nozzle_t nozzle)
 {
 	nozzle_t temp;
 
 	if (!nozzle) {
 		return 0;
 	}
 
 	if (!lib_init) {
 		return 0;
 	}
 
 	temp = lib_cfg.head;
 
 	while (temp != NULL) {
 		if (nozzle == temp)
 			return 1;
 
 		temp = temp->next;
 	}
 
 	return 0;
 }
 
 static int get_iface_mtu(const nozzle_t nozzle)
 {
 	int err = 0, savederrno = 0;
 	struct ifreq ifr;
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFMTU, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	err = ifr.ifr_mtu;
 
 out_clean:
 	errno = savederrno;
 	return err;
 }
 
 static int get_iface_mac(const nozzle_t nozzle, char **ether_addr)
 {
 	int err = 0, savederrno = 0;
 	struct ifreq ifr;
 	char mac[MACADDR_CHAR_MAX];
 #ifdef KNET_BSD
 	struct ifaddrs *ifap = NULL;
 	struct ifaddrs *ifa;
 	int found = 0;
 #endif
 
 	memset(&mac, 0, MACADDR_CHAR_MAX);
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 
 #ifdef KNET_LINUX
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	ether_ntoa_r((struct ether_addr *)ifr.ifr_hwaddr.sa_data, mac);
 #endif
 #ifdef KNET_BSD
 	/*
 	 * there is no ioctl to get the ether address of an interface on FreeBSD
 	 * (not to be confused with hwaddr). Use workaround described here:
 	 * https://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007394.html
 	 */
 	err = getifaddrs(&ifap);
 	if (err < 0) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	ifa = ifap;
 
 	while (ifa) {
 		if (!strncmp(nozzle->name, ifa->ifa_name, IFNAMSIZ)) {
 			found = 1;
 			break;
 		}
 		ifa=ifa->ifa_next;
 	}
 
 	if (found) {
 		ether_ntoa_r((struct ether_addr *)LLADDR((struct sockaddr_dl *)ifa->ifa_addr), mac);
 	} else {
 		errno = EINVAL;
 		err = -1;
 	}
 
 	freeifaddrs(ifap);
 
 	if (err) {
 		goto out_clean;
 	}
 
 #endif
 	*ether_addr = strdup(mac);
 	if (!*ether_addr) {
 		savederrno = errno;
 		err = -1;
 	}
 
 out_clean:
 	errno = savederrno;
 	return err;
 }
 
 /*
  * public API
  */
 
 nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath)
 {
 	int savederrno = 0;
 	nozzle_t nozzle = NULL;
 	char *temp_mac = NULL;
 #ifdef KNET_LINUX
 	struct ifreq ifr;
 #endif
 #ifdef KNET_BSD
 	uint16_t i;
 	long int nozzlenum = 0;
 	char curnozzle[IFNAMSIZ];
 #endif
 
 	if (devname == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
 	if (devname_size < IFNAMSIZ) {
 		errno = EINVAL;
 		return NULL;
 	}
 
 	if (strlen(devname) > IFNAMSIZ) {
 		errno = E2BIG;
 		return NULL;
 	}
 
 #ifdef KNET_BSD
 	/*
 	 * BSD does not support named devices like Linux
 	 * but it is possible to force a nozzleX device number
 	 * where X is 0 to 255.
 	 */
 	if (strlen(devname)) {
 		if (strncmp(devname, "tap", 3)) {
 			errno = EINVAL;
 			return NULL;
 		}
 		errno = 0;
 		nozzlenum = strtol(devname+3, NULL, 10);
 		if (errno) {
 			errno = EINVAL;
 			return NULL;
 		}
 		if ((nozzlenum < 0) || (nozzlenum > 255)) {
 			errno = EINVAL;
 			return NULL;
 		}
 	}
 #endif
 
 	if (updownpath) {
 		/* only absolute paths */
 		if (updownpath[0] != '/') {
 			errno = EINVAL;
 			return NULL;
 		}
 		if (strlen(updownpath) >= UPDOWN_PATH_MAX) {
 			errno = E2BIG;
 			return NULL;
 		}
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return NULL;
 	}
 
 	if (!lib_init) {
 		lib_cfg.head = NULL;
 #ifdef KNET_LINUX
 		lib_cfg.ioctlfd = socket(AF_INET, SOCK_STREAM, 0);
 #endif
 #ifdef KNET_BSD
 		lib_cfg.ioctlfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
 #endif
 		if (lib_cfg.ioctlfd < 0) {
 			savederrno = errno;
 			goto out_error;
 		}
 		lib_init = 1;
 	}
 
 	nozzle = malloc(sizeof(struct nozzle_iface));
 	if (!nozzle) {
 		savederrno = ENOMEM;
 		goto out_error;
 	}
 
 	memset(nozzle, 0, sizeof(struct nozzle_iface));
 
 #ifdef KNET_BSD
 	if (!strlen(devname)) {
 		for (i = 0; i < 256; i++) {
 			snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/tap%u", i);
 			nozzle->fd = open(curnozzle, O_RDWR);
 			savederrno = errno;
 			if (nozzle->fd > 0) {
 				break;
 			}
 		}
 		snprintf(curnozzle, sizeof(curnozzle) -1 , "tap%u", i);
 	} else {
 		snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/%s", devname);
 		nozzle->fd = open(curnozzle, O_RDWR);
 		savederrno = errno;
 		snprintf(curnozzle, sizeof(curnozzle) - 1, "%s", devname);
 	}
 	if (nozzle->fd < 0) {
 		errno = EBUSY;
 		goto out_error;
 	}
 	strncpy(devname, curnozzle, IFNAMSIZ);
 	strncpy(nozzle->name, curnozzle, IFNAMSIZ);
 #endif
 
 #ifdef KNET_LINUX
 	if ((nozzle->fd = open("/dev/net/tun", O_RDWR)) < 0) {
 		savederrno = errno;
 		goto out_error;
 	}
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, devname, IFNAMSIZ);
 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
 
 	if (ioctl(nozzle->fd, TUNSETIFF, &ifr) < 0) {
 		savederrno = errno;
 		goto out_error;
 	}
 
 	if ((strlen(devname) > 0) && (strcmp(devname, ifname) != 0)) {
 		errno = EBUSY;
 		goto out_error;
 	}
 
 	strncpy(devname, ifname, IFNAMSIZ);
 	strncpy(nozzle->name, ifname, IFNAMSIZ);
 #endif
 
 	nozzle->default_mtu = get_iface_mtu(nozzle);
 	if (nozzle->default_mtu < 0) {
 		savederrno = errno;
 		goto out_error;
 	}
 
 	if (get_iface_mac(nozzle, &temp_mac) < 0) {
 		savederrno = errno;
 		goto out_error;
 	}
 
 	strncpy(nozzle->default_mac, temp_mac, 18);
 	free(temp_mac);
 
 	if (updownpath) {
 		int len = strlen(updownpath);
 
 		strcpy(nozzle->updownpath, updownpath);
 		if (nozzle->updownpath[len-1] != '/') {
 			nozzle->updownpath[len] = '/';
 		}
 		nozzle->hasupdown = 1;
 	}
 
 	nozzle->next = lib_cfg.head;
 	lib_cfg.head = nozzle;
 
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return nozzle;
 
 out_error:
 	_close(nozzle);
 	_close_cfg();
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return NULL;
 }
 
 int nozzle_close(nozzle_t nozzle,  char **error_down, char **error_postdown)
 {
 	int err = 0, savederrno = 0;
 	nozzle_t temp = lib_cfg.head;
 	nozzle_t prev = lib_cfg.head;
 	struct nozzle_ip *ip, *ip_next;
 	char *error_string = NULL;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	while ((temp) && (temp != nozzle)) {
 		prev = temp;
 		temp = temp->next;
 	}
 
 	if (nozzle == prev) {
 		lib_cfg.head = nozzle->next;
 	} else {
 		prev->next = nozzle->next;
 	}
 
-	_set_down(nozzle, error_down, error_postdown);
+	_set_down(nozzle);
 
 	ip = nozzle->ip;
 	while (ip) {
 		ip_next = ip->next;
 		_set_ip(nozzle, "del", ip->ipaddr, ip->prefix, &error_string, 0);
 		if (error_string) {
 			free(error_string);
 			error_string = NULL;
 		}
 		free(ip);
 		ip = ip_next;
 	}
 
 	_close(nozzle);
 	_close_cfg();
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_set_mtu(nozzle_t nozzle, const int mtu, char **error_string)
 {
 	int err = 0, savederrno = 0;
 	struct nozzle_ip *tmp_ip;
 	struct ifreq ifr;
 
 	if ((!mtu) || (!error_string)) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	err = nozzle->current_mtu = get_iface_mtu(nozzle);
 	if (err < 0) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 	ifr.ifr_mtu = mtu;
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCSIFMTU, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	if ((nozzle->current_mtu < 1280) && (mtu >= 1280)) {
 		tmp_ip = nozzle->ip;
 		while(tmp_ip) {
 			if (tmp_ip->domain == AF_INET6) {
 				err = _set_ip(nozzle, "add", tmp_ip->ipaddr, tmp_ip->prefix, error_string, 0);
 				if (err) {
 					savederrno = errno;
 					err = -1;
 					goto out_clean;
 				}
 			}
 			tmp_ip = tmp_ip->next;
 		}
 	}
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_reset_mtu(nozzle_t nozzle, char **error_string)
 {
 	return nozzle_set_mtu(nozzle, nozzle->default_mtu, error_string);
 }
 
 int nozzle_set_up(nozzle_t nozzle, char **error_preup, char **error_up)
 {
 	int err = 0, savederrno = 0;
 	struct ifreq ifr;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	if ((nozzle->hasupdown) && ((!error_preup) || (!error_up))) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	if (nozzle->up) {
 		goto out_clean;
 	}
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
 	err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	nozzle->up = 1;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
-int nozzle_set_down(nozzle_t nozzle, char **error_down, char **error_postdown)
+int nozzle_set_down(nozzle_t nozzle)
 {
 	int err = 0, savederrno = 0;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
-	if ((nozzle->hasupdown) && ((!error_down) || (!error_postdown))) {
-		savederrno = EINVAL;
-		err = -1;
-		goto out_clean;
-	}
-
-	err = _set_down(nozzle, error_down, error_postdown);
+	err = _set_down(nozzle);
 	savederrno = errno;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_add_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string)
 {
 	int err = 0, savederrno = 0;
 	int found = 0;
 	struct nozzle_ip *ip = NULL, *ip_prev = NULL, *ip_last = NULL;
 	int secondary = 0;
 
 	if ((!ipaddr) || (!prefix) || (!error_string)) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev);
 	if (found) {
 		goto out_clean;
 	}
 
 	ip = malloc(sizeof(struct nozzle_ip));
 	if (!ip) {
 		savederrno = errno;
 		err = -1 ;
 		goto out_clean;
 	}
 
 	memset(ip, 0, sizeof(struct nozzle_ip));
 	strncpy(ip->ipaddr, ipaddr, IPADDR_CHAR_MAX);
 	strncpy(ip->prefix, prefix, PREFIX_CHAR_MAX);
 	if (!strchr(ip->ipaddr, ':')) {
 		ip->domain = AF_INET;
 	} else {
 		ip->domain = AF_INET6;
 	}
 
 	/*
 	 * if user asks for an IPv6 address, but MTU < 1280
 	 * store the IP and bring it up later if and when MTU > 1280
 	 */
 	if ((ip->domain == AF_INET6) && (get_iface_mtu(nozzle) < 1280)) {
 		err = 0;
 	} else {
 		if (nozzle->ip) {
 			secondary = 1;
 		}
 		err = _set_ip(nozzle, "add", ipaddr, prefix, error_string, secondary);
 		savederrno = errno;
 	}
 
 	if (err) {
 		free(ip);
 		goto out_clean;
 	}
 
 	if (nozzle->ip) {
 		ip_last = nozzle->ip;
 		while (ip_last->next != NULL) {
 			ip_last = ip_last->next;
 		}
 		ip_last->next = ip;
 	} else {
 		nozzle->ip = ip;
 	}
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_del_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string)
 {
 	int err = 0, savederrno = 0;
         int found = 0;
 	struct nozzle_ip *ip = NULL, *ip_prev = NULL;
 
 	if ((!ipaddr) || (!prefix) || (!error_string)) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev);
 	if (!found) {
 		goto out_clean;
 	}
 
 	err = _set_ip(nozzle, "del", ipaddr, prefix, error_string, 0);
 	savederrno = errno;
 	if (!err) {
 		if (ip == ip_prev) {
 			nozzle->ip = ip->next;
 		} else {
 			ip_prev->next = ip->next;
 		}
 		free(ip);
 	}
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_get_ips(const nozzle_t nozzle, char **ipaddr_list, int *entries)
 {
 	int err = 0, savederrno = 0;
 	int found = 0;
 	char *ip_list = NULL;
 	int size = 0, offset = 0, len;
 	struct nozzle_ip *ip = NULL;
 
 	if ((!ipaddr_list) || (!entries)) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		goto out_clean;
 	}
 
 	ip = nozzle->ip;
 
 	while (ip) {
 		found++;
 		ip = ip->next;
 	}
 
 	if (!found) {
 		*ipaddr_list = NULL;
 		*entries = 0;
 		goto out_clean;
 	}
 
 	size = found * (IPADDR_CHAR_MAX + PREFIX_CHAR_MAX + 2);
 
 	ip_list = malloc(size);
 	if (!ip_list) {
 		savederrno = errno;
 		err = -1;
 		goto out_clean;
 	}
 
 	memset(ip_list, 0, size);
 
 	ip = nozzle->ip;
 
 	while (ip) {
 		len = strlen(ip->ipaddr);
 		memmove(ip_list + offset, ip->ipaddr, len);
 		offset = offset + len + 1;
 		len = strlen(ip->prefix);
 		memmove(ip_list + offset, ip->prefix, len);
 		offset = offset + len + 1;
 		ip = ip->next;
 	}
 
 	*ipaddr_list = ip_list;
 	*entries = found;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_run_updown(const nozzle_t nozzle, uint8_t action, char **exec_string)
 {
 	int err = 0, savederrno = 0;
 	char command[PATH_MAX];
 	const char *action_str = NULL;
 	struct stat sb;
 
 	if (action > NOZZLE_POSTDOWN) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	if (!exec_string) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	if (!nozzle->hasupdown) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	switch(action) {
 		case NOZZLE_PREUP:
 			action_str = "pre-up.d";
 			break;
 		case NOZZLE_UP:
 			action_str = "up.d";
 			break;
 		case NOZZLE_DOWN:
 			action_str = "down.d";
 			break;
 		case NOZZLE_POSTDOWN:
 			action_str = "post-down.d";
 			break;
 	}
 
 	memset(command, 0, PATH_MAX);
 
 	snprintf(command, PATH_MAX, "%s%s/%s", nozzle->updownpath, action_str, nozzle->name);
 
 	err = stat(command, &sb);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	err = execute_bin_sh_command(command, exec_string);
+	savederrno = errno;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno =  savederrno;
 	return err;
 }
 
 /*
  * functions below should be completed
  */
 
 int nozzle_get_mtu(const nozzle_t nozzle)
 {
 	int err = 0, savederrno = 0;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	err = get_iface_mtu(nozzle);
 	savederrno = errno;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	savederrno = errno;
 	return err;
 }
 
 int nozzle_get_mac(const nozzle_t nozzle, char **ether_addr)
 {
 	int err = 0, savederrno = 0;
 
 	if (!ether_addr) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	err = get_iface_mac(nozzle, ether_addr);
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_set_mac(nozzle_t nozzle, const char *ether_addr)
 {
 	int err = 0, savederrno = 0;
 	struct ifreq ifr;
 
 	if (!ether_addr) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = EINVAL;
 		err = -1;
 		goto out_clean;
 	}
 
 	memset(&ifr, 0, sizeof(struct ifreq));
 	strncpy(ifname, nozzle->name, IFNAMSIZ);
 #ifdef KNET_LINUX
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	memmove(ifr.ifr_hwaddr.sa_data, ether_aton(ether_addr), ETH_ALEN);
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCSIFHWADDR, &ifr);
 	savederrno = errno;
 #endif
 #ifdef KNET_BSD
 	err = ioctl(lib_cfg.ioctlfd, SIOCGIFADDR, &ifr);
 	if (err) {
 		savederrno = errno;
 		goto out_clean;
 	}
 
 	memmove(ifr.ifr_addr.sa_data, ether_aton(ether_addr), ETHER_ADDR_LEN);
 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
 
 	err = ioctl(lib_cfg.ioctlfd, SIOCSIFLLADDR, &ifr);
 	savederrno = errno;
 #endif
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return err;
 }
 
 int nozzle_reset_mac(nozzle_t nozzle)
 {
 	return nozzle_set_mac(nozzle, nozzle->default_mac);
 }
 
 nozzle_t nozzle_get_handle_by_name(const char *devname)
 {
 	int savederrno = 0;
 	nozzle_t nozzle;
 
 	if ((devname == NULL) || (strlen(devname) > IFNAMSIZ)) {
 		errno = EINVAL;
 		return NULL;
 	}
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return NULL;
 	}
 
 	nozzle = lib_cfg.head;
 	while (nozzle != NULL) {
 		if (!strcmp(devname, nozzle->name))
 			break;
 		nozzle = nozzle->next;
 	}
 
 	if (!nozzle) {
 		savederrno = ENOENT;
 	}
 
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return nozzle;
 }
 
 const char *nozzle_get_name_by_handle(const nozzle_t nozzle)
 {
 	int savederrno = 0;
 	char *name = NULL;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return NULL;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = ENOENT;
 		goto out_clean;
 	}
 
 	name = nozzle->name;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return name;
 }
 
 int nozzle_get_fd(const nozzle_t nozzle)
 {
 	int fd = -1, savederrno = 0;
 
 	savederrno = pthread_mutex_lock(&config_mutex);
 	if (savederrno) {
 		errno = savederrno;
 		return -1;
 	}
 
 	if (!is_valid_nozzle(nozzle)) {
 		savederrno = ENOENT;
 		fd = -1;
 		goto out_clean;
 	}
 
 	fd = nozzle->fd;
 
 out_clean:
 	pthread_mutex_unlock(&config_mutex);
 	errno = savederrno;
 	return fd;
 }
diff --git a/libnozzle/libnozzle.h b/libnozzle/libnozzle.h
index 5d28154e..ce3b66a8 100644
--- a/libnozzle/libnozzle.h
+++ b/libnozzle/libnozzle.h
@@ -1,357 +1,346 @@
 /*
  * Copyright (C) 2010-2018 Red Hat, Inc.  All rights reserved.
  *
  * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
  *
  * This software licensed under GPL-2.0+, LGPL-2.0+
  */
 
 #ifndef __LIBNOZZLE_H__
 #define __LIBNOZZLE_H__
 
 #include <sys/types.h>
 #include <net/if.h>
 
 /**
  *
  * @file libnozzle.h
  * @brief tap interfaces management API include file
  * @copyright Copyright (C) 2010-2017 Red Hat, Inc.  All rights reserved.
  *
  * nozzle is a commodity library to manage tap (ethernet) interfaces
  */
 
 typedef struct nozzle_iface *nozzle_t;
 
 /**
  * nozzle_open
  * @brief create a new tap device on the system.
  *
  * devname - pointer to device name of at least size IFNAMSIZ.
  *           if the dev strlen is 0, then the system will assign a name automatically.
  *           if a string is specified, the system will try to create a device with
  *           the specified name.
  *           NOTE: on FreeBSD the tap device names can only be tapX where X is a
  *           number from 0 to 255. On Linux such limitation does not apply.
  *           The name must be unique to the system. If an interface with the same
  *           name is already configured on the system, an error will be returned.
  *
  * devname_size - length of the buffer provided in dev (has to be at least IFNAMSIZ).
  *
  * updownpath - nozzle supports the typical filesystem structure to execute
  *              actions for: down.d  post-down.d  pre-up.d  up.d
  *              in the form of:
  *              updownpath/<action>/<interface_name>
  *              updownpath specifies where to find those directories on the
  *              filesystem and it must be an absolute path.
  *
  * @return
  * nozzle_open returns
  * a pointer to a nozzle struct on success
  * NULL on error and errno is set.
  */
 
 nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath);
 
 /**
  * nozzle_close
  * @brief deconfigure and destroy a nozzle device
  *
  * nozzle - pointer to the nozzle struct to destroy
  *
  * error_down - pointers to string to record errors from executing down.d
  *              when configured. The string is malloc'ed, the caller needs to free those
  *              buffers.
  *
  * error_postdown - pointers to string to record errors from executing post-down.d
  *                  when configured. The string is malloc'ed, the caller needs to free
  *                  those buffers.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  * error_down / error_postdown are set to NULL if execution of external scripts
  * is sucessful
  * error_down / error_postdown will contain strings recording the execution error.
  */
 
 int nozzle_close(nozzle_t nozzle, char **error_down, char **error_postdown);
 
 
 #define NOZZLE_PREUP    0
 #define NOZZLE_UP       1
 #define NOZZLE_DOWN     2
 #define NOZZLE_POSTDOWN 3
 
 /**
  * nozzle_run_updown
  * @brief execute updown commands associated with a nozzle device
  *
  * nozzle - pointer to the nozzle struct
  *
  * action - pre-up.d / up.d / down.d / post-down.d (see defines above)
  *
  * exec_string - pointers to string to record executing action stdout/stderr.
  *               The string is malloc'ed, the caller needs to free the buffer.
  *               If the script generates no output this string might be NULL.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  */
 
 int nozzle_run_updown(const nozzle_t nozzle, uint8_t action, char **exec_string);
 
 /**
  * nozzle_set_up
  * @brief equivalent of ifconfig up, executes pre-up.d up.d if configured
  *
  * nozzle - pointer to the nozzle struct
  *
  * error_preup - pointer to string pointer to record errors from executing pre-up.d
  *               when configured. The string is malloc'ed, the caller needs to free that
  *               buffer.
  *
  * error_up - pointer to string pointer to record errors from executing up.d
  *            when configured. The string is malloc'ed, the caller needs to free that
  *            buffer.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  * error_preup / error_up are set to NULL if execution of external scripts
  * is sucessful
  * error_preup / error_up will contain strings recording the execution error.
  */
 
 int nozzle_set_up(nozzle_t nozzle, char **error_preup, char **error_up);
 
 /**
  * nozzle_set_down
- * @brief equivalent of ifconfig down, executes down.d post-down.d
+ * @brief equivalent of ifconfig down
  *
  * nozzle - pointer to the nozzle struct
  *
- * error_down - pointer to a string pointer to record errors from executing down.d
- *              when configured. The string is malloc'ed, the caller needs to free that
- *              buffer.
- *
- * error_postdown - pointer to a string pointer to record errors from executing post-down.d
- *                  when configured. The string is malloc'ed, the caller needs to free
- *                  that buffer.
- *
  * @return
  * 0 on success
  * -1 on error and errno is set.
- * error_down / error_postdown are set to NULL if execution of external scripts
- * is sucessful
- * error_down / error_postdown will contain strings recording the execution error.
  */
 
-int nozzle_set_down(nozzle_t nozzle, char **error_down, char **error_postdown);
+int nozzle_set_down(nozzle_t nozzle);
 
 /**
  * nozzle_add_ip
  * @brief equivalent of ip addr or ifconfig <ipaddress/prefix>
  *
  * nozzle - pointer to the nozzle struct
  *
  * ipaddr - string containing either an IPv4 or an IPv6 address.
  *           Please note that Linux will automatically remove any IPv6 addresses from an interface
  *           with MTU < 1280. libnozzle will cache those IPs and re-instate them when MTU is > 1280.
  *           MTU must be set via nozzle_set_mtu for IPv6 to be re-instated.
  *
  * prefix - 24, 64 or any valid network prefix for the requested address.
  *
  * error_string - pointers to string to record errors from ipaddr2 (Linux) or ifconfig (BSD).
  *                The string is malloc'ed, the caller needs to free this buffer.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  *  error_string is set to NULL on success
  *  error_string will contain a string recording the execution error.
  */
 
 int nozzle_add_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string);
 
 /**
  * nozzle_del_ip
  * @brief equivalent of ip addr del or ifconfig del <ipaddress/prefix>
  *
  * nozzle - pointer to the nozzle struct
  *
  * ipaddr - string containing either an IPv4 or an IPv6 address.
  *
  * prefix - 24, 64 or any valid network prefix for the requested address.
  *
  * error_string - pointers to string to record errors from ipaddr2 (Linux) or ifconfig (BSD).
  *                The string is malloc'ed, the caller needs to free this buffer.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  *  error_string is set to NULL on success
  *  error_string will contain a string recording the execution error.
  */
 
 int nozzle_del_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string);
 
 /**
  * nozzle_get_ips
  * @brief retrive the list of all configured ips for a given interface
  *
  * TODO: change to use a ipaddr_list struct!
  *
  * nozzle - pointer to the nozzle struct
  *
  * ipaddr_list - list of strings containing either an IPv4 or an IPv6 address and their prefixes.
  *
  * entries - entries recorded.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  * ipaddr_list is a malloc'ed buffer that the user needs to parse and free after use. ipaddr_list can
  * be NULL if entries is 0.
  *
  */
 
 int nozzle_get_ips(const nozzle_t nozzle, char **ipaddr_list, int *entries);
 
 /**
  * nozzle_get_mtu
  * @brief retrive mtu on a given nozzle interface
  *
  * nozzle - pointer to the nozzle struct
  *
  * @return
  * MTU on success
  * -1 on error and errno is set.
  */
 
 int nozzle_get_mtu(const nozzle_t nozzle);
 
 /**
  * nozzle_set_mtu
  * @brief set mtu on a given nozzle interface
  *
  * nozzle - pointer to the nozzle struct
  *
  * mtu - new MTU value
  *
  * error_string - pointer to string to record errors from ipaddr2 (Linux) or ifconfig (BSD)
  *                when re-instanting IPv6 address if MTU is becoming again > 1280.
  *                The string is malloc'ed, the caller needs to free this buffer.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  * error_string is set to NULL on success
  * error_string will contain a string recording the execution error.
  */
 
 int nozzle_set_mtu(nozzle_t nozzle, const int mtu, char **error_string);
 
 /**
  * nozzle_reset_mtu
  * @brief reset mtu on a given nozzle interface to the system default
  *
  * nozzle - pointer to the nozzle struct
  *
  * error_string - pointer to string to record errors from ipaddr2 (Linux) or ifconfig (BSD)
  *                when re-instanting IPv6 address if MTU is becoming again > 1280.
  *                The string is malloc'ed, the caller needs to free this buffer.
  *
  * @return
  * 0 on success
  * -1 on error and errno is set.
  * error_string is set to NULL on success
  * error_string will contain a string recording the execution error.
  */
 
 int nozzle_reset_mtu(nozzle_t nozzle, char **error_string);
 
 /**
  * nozzle_get_mac
  * @brief retrive mac address on a given nozzle interface
  *
  * nozzle - pointer to the nozzle struct
  *
  * ether_addr - pointers to string containing the current mac address.
  *              The string is malloc'ed, the caller needs to free this buffer.
  * @return
  * 0 on success.
  * -1 on error and errno is set.
  */
 
 int nozzle_get_mac(const nozzle_t nozzle, char **ether_addr);
 
 /**
  * nozzle_set_mac
  * @brief set mac address on a given nozzle interface
  *
  * nozzle - pointer to the nozzle struct
  *
  * ether_addr - pointers to string containing the new mac address.
  *
  * @return
  * 0 on success.
  * -1 on error and errno is set.
  */
 
 int nozzle_set_mac(nozzle_t nozzle, const char *ether_addr);
 
 /**
  * nozzle_reset_mac
  * @brief reset mac address on a given nozzle interface to system default
  *
  * nozzle - pointer to the nozzle struct
  *
  * @return
  * 0 on success.
  * -1 on error and errno is set.
  */
 
 int nozzle_reset_mac(nozzle_t nozzle);
 
 /**
  * nozzle_get_handle_by_name
  * @brief find a nozzle handle by device name
  *
  * devname - string containing the name of the interface
  *
  * @return
  * handle on success.
  * NULL on error and errno is set.
  */
 
 nozzle_t nozzle_get_handle_by_name(const char *devname);
 
 /**
  * nozzle_get_name_by_handle
  * @brief retrive nozzle interface name by handle
  *
  * nozzle - pointer to the nozzle struct
  *
  * @return
  * pointer to the interface name
  * NULL on error and errno is set.
  */
 
 const char *nozzle_get_name_by_handle(const nozzle_t nozzle);
 
 /**
  * nozzle_get_fd
  * @brief 
  *
  * nozzle - pointer to the nozzle struct
  *
  * @return
  * fd associated to a given nozzle on success.
  * -1 on error and errno is set.
  */
 
 int nozzle_get_fd(const nozzle_t nozzle);
 
 #endif
diff --git a/libnozzle/tests/nozzle_test.c b/libnozzle/tests/nozzle_test.c
index b83f62c4..b1cb72a3 100644
--- a/libnozzle/tests/nozzle_test.c
+++ b/libnozzle/tests/nozzle_test.c
@@ -1,1507 +1,1516 @@
 /*
  * Copyright (C) 2010-2017 Red Hat, Inc.  All rights reserved.
  *
  * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
  *
  * This software licensed under GPL-2.0+, LGPL-2.0+
  */
 
 #include "config.h"
 
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <errno.h>
 #include <ifaddrs.h>
 #include <stdint.h>
 #include <limits.h>
 
 #ifdef KNET_LINUX
 #include <linux/if_tun.h>
 #include <netinet/ether.h>
 #endif
 #ifdef KNET_BSD
 #include <net/if_dl.h>
 #endif
 
 #include "libnozzle.h"
 #include "internals.h"
 
 char testipv4_1[1024];
 char testipv4_2[1024];
 char testipv6_1[1024];
 char testipv6_2[1024];
 /*
  * use this one to randomize knet interface name
  * for named creation test
  */
 uint8_t randombyte = 0;
 
 static int is_if_in_system(char *name)
 {
 	struct ifaddrs *ifap = NULL;
 	struct ifaddrs *ifa;
 	int found = 0;
 
 	if (getifaddrs(&ifap) < 0) {
 		printf("Unable to get interface list.\n");
 		return -1;
 	}
 
 	ifa = ifap;
 
 	while (ifa) {
 		if (!strncmp(name, ifa->ifa_name, IFNAMSIZ)) {
 			found = 1;
 			break;
 		}
 		ifa=ifa->ifa_next;
 	}
 
 	freeifaddrs(ifap);
 	return found;
 }
 
 static int test_iface(char *name, size_t size, const char *updownpath)
 {
 	nozzle_t nozzle;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	nozzle=nozzle_open(name, size, updownpath);
 	if (!nozzle) {
 		printf("Unable to open knet.\n");
 		return -1;
 	}
 	printf("Created interface: %s\n", name);
 
 	if (is_if_in_system(name) > 0) {
 		printf("Found interface %s on the system\n", name);
 	} else {
 		printf("Unable to find interface %s on the system\n", name);
 	}
 
 	if (!nozzle_get_handle_by_name(name)) {
 		printf("Unable to find interface %s in nozzle db\n", name);
 	} else {
 		printf("Found interface %s in nozzle db\n", name);
 	}
 
 	nozzle_close(nozzle, &error_down, &error_postdown);
 
 	if (error_down) {
 		printf("Error from error_down: %s\n", error_down);
 		free(error_down);
 	}
 
 	if (error_postdown) {
 		printf("Error from error_down: %s\n", error_postdown);
 		free(error_postdown);
 	}
 
 	if (is_if_in_system(name) == 0)
 		printf("Successfully removed interface %s from the system\n", name);
 
 	return 0;
 }
 
 static int check_nozzle_open_close(void)
 {
 	char device_name[2*IFNAMSIZ];
 	char fakepath[PATH_MAX];
 	size_t size = IFNAMSIZ;
 
 	memset(device_name, 0, sizeof(device_name));
 
 	printf("Creating random nozzle interface:\n");
 	if (test_iface(device_name, size,  NULL) < 0) {
 		printf("Unable to create random interface\n");
 		return -1;
 	}
 
 #ifdef KNET_LINUX
 	printf("Creating kronostest%u nozzle interface:\n", randombyte);
 	snprintf(device_name, IFNAMSIZ, "kronostest%u", randombyte);
 	if (test_iface(device_name, size, NULL) < 0) {
 		printf("Unable to create kronostest%u interface\n", randombyte);
 		return -1;
 	}
 #endif
 #ifdef KNET_BSD
 	printf("Creating tap%u nozzle interface:\n", randombyte);
 	snprintf(device_name, IFNAMSIZ, "tap%u", randombyte);
 	if (test_iface(device_name, size, NULL) < 0) {
 		printf("Unable to create tap%u interface\n", randombyte);
 		return -1;
 	}
 
 	printf("Creating kronostest%u nozzle interface:\n", randombyte);
 	snprintf(device_name, IFNAMSIZ, "kronostest%u", randombyte);
 	if (test_iface(device_name, size, NULL) == 0) {
 		printf("BSD should not accept kronostest%u interface\n", randombyte);
 		return -1;
 	}
 #endif
 
 	printf("Testing ERROR conditions\n");
 
 	printf("Testing dev == NULL\n");
 	errno=0;
 	if ((test_iface(NULL, size, NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_open sanity checks\n");
 		return -1;
 	}
 
 	printf("Testing size < IFNAMSIZ\n");
 	errno=0;
 	if ((test_iface(device_name, 1, NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_open sanity checks\n");
 		return -1;
 	}
 
 	printf("Testing device_name size > IFNAMSIZ\n");
 	errno=0;
 	strcpy(device_name, "abcdefghilmnopqrstuvwz");
 	if ((test_iface(device_name, IFNAMSIZ, NULL) >= 0) || (errno != E2BIG)) {
 		printf("Something is wrong in nozzle_open sanity checks\n");
 		return -1;
 	}
 
 	printf("Testing updown path != abs\n");
 	errno=0;
 
 	memset(device_name, 0, IFNAMSIZ);
 	if ((test_iface(device_name, IFNAMSIZ, "foo")  >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_open sanity checks\n");
 		return -1;
 	}
 
 	memset(fakepath, 0, PATH_MAX);
 	memset(fakepath, '/', PATH_MAX - 2);
 
 	printf("Testing updown path > PATH_MAX\n");
 	errno=0;
 
 	memset(device_name, 0, IFNAMSIZ);
 	if ((test_iface(device_name, IFNAMSIZ, fakepath)  >= 0) || (errno != E2BIG)) {
 		printf("Something is wrong in nozzle_open sanity checks\n");
 		return -1;
 	}
 
 	return 0;
 }
 
 static int check_knet_multi_eth(void)
 {
 	char device_name1[IFNAMSIZ];
 	char device_name2[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	int err=0;
 	nozzle_t nozzle1 = NULL;
 	nozzle_t nozzle2 = NULL;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing multiple knet interface instances\n");
 
 	memset(device_name1, 0, size);
 	memset(device_name2, 0, size);
 
 	nozzle1 = nozzle_open(device_name1, size, NULL);
 	if (!nozzle1) {
 		printf("Unable to init %s\n", device_name1);
 		err = -1;
 		goto out_clean;
 	}
 
 	if (is_if_in_system(device_name1) > 0) {
 		printf("Found interface %s on the system\n", device_name1);
 	} else {
 		printf("Unable to find interface %s on the system\n", device_name1);
 	}
 
 	nozzle2 = nozzle_open(device_name2, size, NULL);
 	if (!nozzle2) {
 		printf("Unable to init %s\n", device_name2);
 		err = -1;
 		goto out_clean;
 	}
 
 	if (is_if_in_system(device_name2) > 0) {
 		printf("Found interface %s on the system\n", device_name2);
 	} else {
 		printf("Unable to find interface %s on the system\n", device_name2);
 	}
 
 	if (nozzle1) {
 		nozzle_close(nozzle1, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	if (nozzle2) {
 		nozzle_close(nozzle2, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	printf("Testing error conditions\n");
 
 	printf("Open same device twice\n");
 
 	memset(device_name1, 0, size);
 
 	nozzle1 = nozzle_open(device_name1, size, NULL);
 	if (!nozzle1) {
 		printf("Unable to init %s\n", device_name1);
 		err = -1;
 		goto out_clean;
 	}
 
 	if (is_if_in_system(device_name1) > 0) {
 		printf("Found interface %s on the system\n", device_name1);
 	} else {
 		printf("Unable to find interface %s on the system\n", device_name1);
 	}
 
 	nozzle2 = nozzle_open(device_name1, size, NULL);
 	if (nozzle2) {
 		printf("We were able to init 2 interfaces with the same name!\n");
 		err = -1;
 		goto out_clean;
 	}
 
 out_clean:
 	if (nozzle1) {
 		nozzle_close(nozzle1, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	if (nozzle2) {
 		nozzle_close(nozzle2, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	return err;
 }
 
 static int check_knet_mtu(void)
 {
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	int err=0;
 	nozzle_t nozzle;
 	char *error_down = NULL, *error_postdown = NULL;
 	char *error_string = NULL;
 
 	int current_mtu = 0;
 	int expected_mtu = 1500;
 
 	printf("Testing get/set MTU\n");
 
 	memset(device_name, 0, size);
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Comparing default MTU\n");
 	current_mtu = nozzle_get_mtu(nozzle);
 	if (current_mtu < 0) {
 		printf("Unable to get MTU\n");
 		err = -1;
 		goto out_clean;
 	}
 	if (current_mtu != expected_mtu) {
 		printf("current mtu [%d] does not match expected default [%d]\n", current_mtu, expected_mtu);
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Setting MTU to 9000\n");
 	expected_mtu = 9000;
 	if (nozzle_set_mtu(nozzle, expected_mtu, &error_string) < 0) {
 		printf("Unable to set MTU to %d\n", expected_mtu);
 		if (error_string) {
 			printf("error: %s\n", error_string);
 			free(error_string);
 		}
 		err = -1;
 		goto out_clean;
 	}
 
 	current_mtu = nozzle_get_mtu(nozzle);
 	if (current_mtu < 0) {
 		printf("Unable to get MTU\n");
 		err = -1;
 		goto out_clean;
 	}
 	if (current_mtu != expected_mtu) {
 		printf("current mtu [%d] does not match expected value [%d]\n", current_mtu, expected_mtu);
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Testing ERROR conditions\n");
 
 	printf("Passing empty struct to get_mtu\n");
 	if (nozzle_get_mtu(NULL) > 0) {
 		printf("Something is wrong in nozzle_get_mtu sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Passing empty struct to set_mtu\n");
 	if (nozzle_set_mtu(NULL, 1500, &error_string) == 0) {
 		printf("Something is wrong in nozzle_set_mtu sanity checks\n"); 
 		if (error_string) {
 			printf("error: %s\n", error_string);
 			free(error_string);
 		}
 		err = -1;
 		goto out_clean;
 	}
 
 out_clean:
 	if (nozzle) {
 		nozzle_close(nozzle, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	return err;
 }
 
 static int check_knet_mtu_ipv6(void)
 {
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	char verifycmd[1024];
 	int err=0;
 	nozzle_t nozzle;
 	char *error_string = NULL;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing get/set MTU with IPv6 address\n");
 
 	memset(device_name, 0, size);
 
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Adding ip: %s/64\n", testipv6_1);
 
 	err = nozzle_add_ip(nozzle, testipv6_1, "64", &error_string);
 	if (error_string) {
 		printf("add ipv6 output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		sleep(30);
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Setting MTU to 1200\n");
 	if (nozzle_set_mtu(nozzle, 1200, &error_string) < 0) {
 		printf("Unable to set MTU to 1200\n");
 		if (error_string) {
 			printf("error: %s\n", error_string);
 			free(error_string);
 		}
 		err = -1;
 		goto out_clean;
 	}
 
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 #ifdef KNET_LINUX
 	if (!err) {
 #endif
 #ifdef KNET_BSD
 	if (err) {
 #endif
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Adding ip: %s/64\n", testipv6_2);
 	err = nozzle_add_ip(nozzle, testipv6_2, "64", &error_string);
 	if (error_string) {
 		printf("add ipv6 output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_2);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_2);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Restoring MTU to default\n");
 	if (nozzle_reset_mtu(nozzle, &error_string) < 0) {
 		printf("Unable to reset mtu\n");
 		if (error_string) {
 			printf("error: %s\n", error_string);
 			free(error_string);
 		}
 		err = -1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_2);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_2);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 out_clean:
 	if (nozzle) {
 		nozzle_close(nozzle, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	return err;
 }
 
 static int check_knet_mac(void)
 {
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	int err=0;
 	nozzle_t nozzle;
 	char *current_mac = NULL, *temp_mac = NULL, *err_mac = NULL;
 	struct ether_addr *cur_mac, *tmp_mac;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing get/set MAC\n");
 
 	memset(device_name, 0, size);
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Get current MAC\n");
 
 	if (nozzle_get_mac(nozzle, &current_mac) < 0) {
 		printf("Unable to get current MAC address.\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Current MAC: %s\n", current_mac);
 
 	printf("Setting MAC: 00:01:01:01:01:01\n");
 
 	if (nozzle_set_mac(nozzle, "00:01:01:01:01:01") < 0) {
 		printf("Unable to set current MAC address.\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	if (nozzle_get_mac(nozzle, &temp_mac) < 0) {
 		printf("Unable to get current MAC address.\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Current MAC: %s\n", temp_mac);
 
 	cur_mac = ether_aton(current_mac);
 	tmp_mac = ether_aton(temp_mac);
 
 	printf("Comparing MAC addresses\n");
 	if (memcmp(cur_mac, tmp_mac, sizeof(struct ether_addr))) {
 		printf("Mac addresses are not the same?!\n");
 		err = -1;
 		sleep(20);
 		goto out_clean;
 	}
 
 	printf("Testing ERROR conditions\n");
 
 	printf("Pass NULL to get_mac (pass1)\n");
 	errno = 0;
 	if ((nozzle_get_mac(NULL, &err_mac) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_get_mac sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to get_mac (pass2)\n");
 	errno = 0;
 	if ((nozzle_get_mac(nozzle, NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_get_mac sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to set_mac (pass1)\n");
 	errno = 0;
 	if ((nozzle_set_mac(nozzle, NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_mac sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to set_mac (pass2)\n");
 	errno = 0;
 	if ((nozzle_set_mac(NULL, err_mac) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_mac sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 out_clean:
 	if (err_mac) {
 		printf("Something managed to set err_mac!\n");
 		err = -1;
 		free(err_mac);
 	}
 
 	if (current_mac)
 		free(current_mac);
 	if (temp_mac)
 		free(temp_mac);
 
 	if (nozzle) {
 		nozzle_close(nozzle, &error_down, &error_postdown);
 		if (error_down) {
 			printf("Error from error_down: %s\n", error_down);
 			free(error_down);
 		}
 		if (error_postdown) {
 			printf("Error from error_down: %s\n", error_postdown);
 			free(error_postdown);
 		}
 	}
 
 	return err;
 }
 
 static int check_nozzle_execute_bin_sh_command(void)
 {
 	int err = 0;
 	char command[4096];
 	char *error_string = NULL;
 
 	memset(command, 0, sizeof(command));
 
 	printf("Testing execute_bin_sh_command\n");
 
 	printf("command true\n");
 
 	err = execute_bin_sh_command("true", &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to execute true ?!?!\n");
 		goto out_clean;
 	}
 
 	printf("Testing ERROR conditions\n");
 
 	printf("command false\n");
 
 	err = execute_bin_sh_command("false", &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Can we really execute false successfully?!?!\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("command that outputs to stdout (enforcing redirect)\n");
 
 	err = execute_bin_sh_command("grep -h 2>&1", &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Can we really execute grep -h successfully?!?\n");
 		err = -1;
 		goto out_clean;
 	} 
 
 	printf("command that outputs to stderr\n");
 	err = execute_bin_sh_command("grep -h", &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Can we really execute grep -h successfully?!?\n");
 		err = -1;
 		goto out_clean;
 	} 
 
 	printf("empty command\n");
 	err = execute_bin_sh_command(NULL, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Can we really execute (nil) successfully?!?!\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("empty error\n");
 	err = execute_bin_sh_command("true", NULL);
 	if (!err) {
 		printf("Check EINVAL filter for no error_string!\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	err = 0;
 
 out_clean:
 
 	return err;
 }
 
 static int check_knet_up_down(void)
 {
 	char verifycmd[1024];
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	int err=0;
 	nozzle_t nozzle;
 	char *error_string = NULL;
 	char *error_preup = NULL, *error_up = NULL;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing interface up/down\n");
 
 	memset(device_name, 0, size);
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Put the interface up\n");
 
 	err = nozzle_set_up(nozzle, &error_preup, &error_up);
 	if (error_preup) {
 		printf("preup output: %s\n", error_preup);
 		free(error_preup);
 		error_preup = NULL;
 	}
 	if (error_up) {
 		printf("up output: %s\n", error_up);
 		free(error_up);
 		error_up = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to set interface up\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q UP", nozzle->name);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q UP", nozzle->name);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to verify inteface UP\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Put the interface down\n");
 
-	err = nozzle_set_down(nozzle, &error_down, &error_postdown);
+	err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_down);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_DOWN error: %s\n", strerror(errno));
+	}
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
-	if (error_postdown) {
-		printf("postdown output: %s\n", error_down);
-		free(error_down);
-		error_down = NULL;
-	}
+	err = nozzle_set_down(nozzle);
 	if (err < 0) {
 		printf("Unable to put the interface down\n");
 		err = -1;
 		goto out_clean;
 	}
+	err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_postdown);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_POSTDOWN error: %s\n", strerror(errno));
+	}
+	if (error_postdown) {
+		printf("postdown output: %s\n", error_down);
+		free(error_down);
+		error_down = NULL;
+	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q UP", nozzle->name);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q UP", nozzle->name);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Unable to verify inteface DOWN\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	printf("Testing interface pre-up/up/down/post-down (exec errors)\n");
 
 	memset(device_name, 0, size);
 	nozzle = nozzle_open(device_name, size, ABSBUILDDIR "/nozzle_updown_bad");
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Put the interface up\n");
 
 	err = nozzle_set_up(nozzle, &error_preup, &error_up);
 	if (error_preup) {
 		printf("preup output: %s\n", error_preup);
 		free(error_preup);
 		error_preup = NULL;
 	}
 	if (error_up) {
 		printf("up output: %s\n", error_up);
 		free(error_up);
 		error_up = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to set interface up\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Put the interface down\n");
 
-	err = nozzle_set_down(nozzle, &error_down, &error_postdown);
+	err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_down);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_DOWN error: %s\n", strerror(errno));
+	}
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
-	if (error_postdown) {
-		printf("postdown output: %s\n", error_down);
-		free(error_down);
-		error_down = NULL;
-	}
+	err = nozzle_set_down(nozzle);
 	if (err < 0) {
 		printf("Unable to put the interface down\n");
 		err = -1;
 		goto out_clean;
 	}
+	err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_postdown);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_POSTDOWN error: %s\n", strerror(errno));
+	}
+	if (error_postdown) {
+		printf("postdown output: %s\n", error_down);
+		free(error_down);
+		error_down = NULL;
+	}
 
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	printf("Testing interface pre-up/up/down/post-down\n");
 
 	memset(device_name, 0, size);
 
 	nozzle = nozzle_open(device_name, size, ABSBUILDDIR "/nozzle_updown_good");
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Put the interface up\n");
 
 	err = nozzle_set_up(nozzle, &error_preup, &error_up);
 	if (error_preup) {
 		printf("preup output: %s\n", error_preup);
 		free(error_preup);
 		error_preup = NULL;
 	}
 	if (error_up) {
 		printf("up output: %s\n", error_up);
 		free(error_up);
 		error_up = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to set interface up\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Put the interface down\n");
 
-	err = nozzle_set_down(nozzle, &error_down, &error_postdown);
+	err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_down);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_DOWN error: %s\n", strerror(errno));
+	}
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
-	if (error_postdown) {
-		printf("postdown output: %s\n", error_down);
-		free(error_down);
-		error_down = NULL;
-	}
+	err = nozzle_set_down(nozzle);
 	if (err < 0) {
 		printf("Unable to put the interface down\n");
 		err = -1;
 		goto out_clean;
 	}
+	err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_postdown);
+	if (err) {
+		printf("nozzle_run_updown NOZZLE_POSTDOWN error: %s\n", strerror(errno));
+	}
+	if (error_postdown) {
+		printf("postdown output: %s\n", error_down);
+		free(error_down);
+		error_down = NULL;
+	}
 
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	printf("Test ERROR conditions\n");
 
 	printf("Pass NULL to nozzle set_up\n");
+	err = 0;
 	errno = 0;
 	if ((nozzle_set_up(NULL, &error_preup, &error_up) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_up sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to error_preup set_up\n");
 	errno = 0;
 	if ((nozzle_set_up(nozzle, NULL, &error_up) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_up sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to error_up set_up\n");
 	errno = 0;
 	if ((nozzle_set_up(nozzle, &error_preup, NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_up sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 	printf("Pass NULL to nozzle set_down\n");
 	errno = 0;
-	if ((nozzle_set_down(NULL, &error_down, &error_postdown) >= 0) || (errno != EINVAL)) {
-		printf("Something is wrong in nozzle_set_down sanity checks\n");
-		err = -1;
-		goto out_clean;
-	}
-
-	printf("Pass NULL to error_down set_down\n");
-	errno = 0;
-	if ((nozzle_set_down(nozzle, NULL, &error_postdown) >= 0) || (errno != EINVAL)) {
-		printf("Something is wrong in nozzle_set_down sanity checks\n");
-		err = -1;
-		goto out_clean;
-	}
-
-	printf("Pass NULL to error_postdown set_down\n");
-	errno = 0;
-	if ((nozzle_set_down(nozzle, &error_down, NULL) >= 0) || (errno != EINVAL)) {
+	if ((nozzle_set_down(NULL) >= 0) || (errno != EINVAL)) {
 		printf("Something is wrong in nozzle_set_down sanity checks\n");
 		err = -1;
 		goto out_clean;
 	}
 
 out_clean:
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	return err;
 }
 
 static int check_knet_close_leak(void)
 {
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	int err=0;
 	nozzle_t nozzle;
 	char *error_string = NULL;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing close leak (needs valgrind)\n");
 
 	memset(device_name, 0, size);
 
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Adding ip: %s/24\n", testipv4_1);
 
 	err = nozzle_add_ip(nozzle, testipv4_1, "24", &error_string);
 	if (error_string) {
 		printf("add ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Adding ip: %s/24\n", testipv4_2);
 
 	err = nozzle_add_ip(nozzle, testipv4_2, "24", &error_string);
 	if (error_string) {
 		printf("add ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 out_clean:
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	return err;
 }
 
 static int check_knet_set_del_ip(void)
 {
 	char device_name[IFNAMSIZ];
 	size_t size = IFNAMSIZ;
 	char verifycmd[1024];
 	int err=0;
 	nozzle_t nozzle;
 	char *ip_list = NULL;
 	int ip_list_entries = 0, i, offset = 0;
 	char *error_string = NULL;
 	char *error_down = NULL, *error_postdown = NULL;
 
 	printf("Testing interface add/remove ip\n");
 
 	memset(device_name, 0, size);
 
 	nozzle = nozzle_open(device_name, size, NULL);
 	if (!nozzle) {
 		printf("Unable to init %s\n", device_name);
 		return -1;
 	}
 
 	printf("Adding ip: %s/24\n", testipv4_1);
 
 	err = nozzle_add_ip(nozzle, testipv4_1, "24", &error_string);
 	if (error_string) {
 		printf("add ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Adding ip: %s/24\n", testipv4_2);
 
 	err = nozzle_add_ip(nozzle, testipv4_2, "24", &error_string);
 	if (error_string) {
 		printf("add ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Adding duplicate ip: %s/24\n", testipv4_1);
 
 	err = nozzle_add_ip(nozzle, testipv4_1, "24", &error_string);
 	if (error_string) {
 		printf("add ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to find IP address in libnozzle db\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Checking ip: %s/24\n", testipv4_1);
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv4_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Get ip list from libnozzle:\n");
 
 	if (nozzle_get_ips(nozzle, &ip_list, &ip_list_entries) < 0) {
 		printf("Not enough mem?\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	if (ip_list_entries != 2) {
 		printf("Didn't get enough ip back from libnozzle?\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	for (i = 1; i <= ip_list_entries; i++) {
 		printf("Found IP %s %s in libnozzle db\n", ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1);
 		offset = offset + strlen(ip_list) + 1;
 		offset = offset + strlen(ip_list + offset) + 1;
 	}
 
 	free(ip_list);
 
 	printf("Deleting ip: %s/24\n", testipv4_1);
 
 	err = nozzle_del_ip(nozzle, testipv4_1, "24", &error_string);
 	if (error_string) {
 		printf("del ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to delete IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Deleting ip: %s/24\n", testipv4_2);
 
 	err = nozzle_del_ip(nozzle, testipv4_2, "24", &error_string);
 	if (error_string) {
 		printf("del ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to delete IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Deleting again ip: %s/24\n", testipv4_1);
 
 	err = nozzle_del_ip(nozzle, testipv4_1, "24", &error_string);
 	if (error_string) {
 		printf("del ip output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to delete IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv4_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Adding ip: %s/64\n", testipv6_1);
 
 	err = nozzle_add_ip(nozzle, testipv6_1, "64", &error_string);
 	if (error_string) {
 		printf("add ipv6 output: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err < 0) {
 		printf("Unable to assign IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	printf("Deleting ip: %s/64\n", testipv6_1);
 
 	err = nozzle_del_ip(nozzle, testipv6_1, "64", &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (err) {
 		printf("Unable to delete IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 	memset(verifycmd, 0, sizeof(verifycmd));
 	snprintf(verifycmd, sizeof(verifycmd)-1,
 #ifdef KNET_LINUX
 		 "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1);
 #endif
 #ifdef KNET_BSD
 		 "ifconfig %s | grep -q %s", nozzle->name, testipv6_1);
 #endif
 	err = execute_bin_sh_command(verifycmd, &error_string);
 	if (error_string) {
 		printf("Error string: %s\n", error_string);
 		free(error_string);
 		error_string = NULL;
 	}
 	if (!err) {
 		printf("Unable to verify IP address\n");
 		err=-1;
 		goto out_clean;
 	}
 
 out_clean:
 	nozzle_close(nozzle, &error_down, &error_postdown);
 	if (error_down) {
 		printf("down output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 	if (error_postdown) {
 		printf("postdown output: %s\n", error_down);
 		free(error_down);
 		error_down = NULL;
 	}
 
 	return err;
 }
 
 static void make_local_ips(void)
 {
 	pid_t mypid;
 	uint8_t *pid;
 	uint8_t i;
 
 	if (sizeof(pid_t) < 4) {
 		printf("pid_t is smaller than 4 bytes?\n");
 		exit(77);
 	}
 
 	memset(testipv4_1, 0, sizeof(testipv4_1));
 	memset(testipv4_2, 0, sizeof(testipv4_2));
 	memset(testipv6_1, 0, sizeof(testipv6_1));
 	memset(testipv6_2, 0, sizeof(testipv6_2));
 
 	mypid = getpid();
 	pid = (uint8_t *)&mypid;
 
 	for (i = 0; i < sizeof(pid_t); i++) {
 		if (pid[i] == 0) {
 			pid[i] = 128;
 		}
 	}
 
 	randombyte = pid[1];
 
 	snprintf(testipv4_1,
 		 sizeof(testipv4_1) - 1,
 		 "127.%u.%u.%u",
 		 pid[1],
 		 pid[2],
 		 pid[0]);
 
 	snprintf(testipv4_2,
 		 sizeof(testipv4_2) - 1,
 		 "127.%u.%d.%u",
 		 pid[1],
 		 pid[2]+1,
 		 pid[0]);
 
 	snprintf(testipv6_1,
 		 sizeof(testipv6_1) - 1,
 		 "fd%x:%x%x::1",
 		 pid[1],
 		 pid[2],
 		 pid[0]);
 
 	snprintf(testipv6_2,
 		 sizeof(testipv6_2) - 1,
 		 "fd%x:%x%x:1::1",
 		 pid[1],
 		 pid[2],
 		 pid[0]);
 }
 
 int main(void)
 {
 	if (geteuid() != 0) {
 		printf("This test requires root privileges\n");
 		exit(77);
 	}
 
 	make_local_ips();
 
 	if (check_nozzle_open_close() < 0)
 		return -1;
 
 	if (check_knet_multi_eth() < 0)
 		return -1;
 
 	if (check_knet_mtu() < 0)
 		return -1;
 
 	if (check_knet_mtu_ipv6() < 0)
 		return -1;
 
 	if (check_knet_mac() < 0)
 		return -1;
 
 	if (check_nozzle_execute_bin_sh_command() < 0)
 		return -1;
 
 	if (check_knet_up_down() < 0)
 		return -1;
 
 	if (check_knet_set_del_ip() < 0)
 		return -1;
 
 	if (check_knet_close_leak() < 0)
 		return -1;
 
 	return 0;
 }