예제 #1
0
static int set_if_addr(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res;
	unsigned char *ipaddr;
	int i;
	struct {
		char *req_name;
		char *desc;
		int g_ioctl;
		int s_ioctl;
	} ifra[] = {
		{"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR},
		{"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR},
		{"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR},
		{"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK},
		{NULL, NULL, 0, 0},
	};

	for (i = 0; ifra[i].req_name; i++) {
		strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
		res = ioctl(skfd, ifra[i].g_ioctl, &ifr);
		if (res < 0) {
			int saved_errno = errno;

			v_print("Interface '%s': Error: SIOCG%s failed: %s\n",
				master_ifname, ifra[i].req_name,
				strerror(saved_errno));

			ifr.ifr_addr.sa_family = AF_INET;
			memset(ifr.ifr_addr.sa_data, 0,
			       sizeof(ifr.ifr_addr.sa_data));
		}

		strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
		res = ioctl(skfd, ifra[i].s_ioctl, &ifr);
		if (res < 0) {
			int saved_errno = errno;

			v_print("Interface '%s': Error: SIOCS%s failed: %s\n",
				slave_ifname, ifra[i].req_name,
				strerror(saved_errno));

		}

		ipaddr = (unsigned char *)ifr.ifr_addr.sa_data;
		v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n",
			slave_ifname, ifra[i].desc,
			ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
	}

	return 0;
}
예제 #2
0
static int change_active(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res = 0;

	if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
		fprintf(stderr,
			"Illegal operation: The specified slave interface "
			"'%s' is not a slave\n",
			slave_ifname);
		return 1;
	}

	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
	if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) &&
	    (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: "
			"%s\n",
			master_ifname, strerror(saved_errno));
		res = 1;
	}

	return res;
}
예제 #3
0
static int get_slave_flags(char *slave_ifname)
{
	int res = 0;

	strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ);
	res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags);
	if (res < 0) {
		saved_errno = errno;
		v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n",
			slave_ifname, strerror(saved_errno));
	} else {
		v_print("Slave %s: flags %04X.\n",
			slave_ifname, slave_flags.ifr_flags);
	}

	return res;
}
예제 #4
0
/*!
  @brief   Print a Vars object to the terminal.
  @ingroup print_high
  @param   ptr Pointer to Vars object.
*/
void
v_show(void *ptr)
{
    static FILE *tty = NULL;

    if (tty == NULL)
        tty = fopen("/dev/tty", "w");
    v_print(ptr, tty);
}
예제 #5
0
int main(int argc, char** argv) {
  Vector* v = (Vector*) malloc(sizeof(Vector));

  v_init(v, 0);

  int i;

  printf("[test-1] push 10 closures to bottom\n");
  for (i = 0; i < 10; i++) {
    Closure* c = (Closure*) malloc(sizeof(Closure));
    cl_init(c);
    c->level = i;
    v_push_closure(v, c);
  }
  v_print(v);

  printf("[test-2] push 10 closures next to their roots\n");
  for (i = 0; i < 10; i++) {
    Closure* c = (Closure*) malloc(sizeof(Closure));
    cl_init(c);
    c->level = i;
    v_push_closure(v, c);
  }
  v_print(v);

  printf("[test-3] pop 10 closures from top\n");
  for (i = 0; i < 10; i++) {
    Closure* c = v_pop_top(v);
    cl_free(c);
  }
  v_print(v);

  printf("[test-4] pop 10 closures from bot\n");
  for (i = 0; i < 10; i++) {
    Closure* c = v_pop_bottom(v);
    cl_free(c);
  }
  v_print(v);

  v_free(v);

  return 0;
}
예제 #6
0
static int set_slave_mtu(char *slave_ifname, int mtu)
{
	struct ifreq ifr;
	int res = 0;

	ifr.ifr_mtu = mtu;
	strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);

	res = ioctl(skfd, SIOCSIFMTU, &ifr);
	if (res < 0) {
		saved_errno = errno;
		v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n",
			slave_ifname, strerror(saved_errno));
	} else {
		v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu);
	}

	return res;
}
예제 #7
0
static int set_if_flags(char *ifname, short flags)
{
	struct ifreq ifr;
	int res = 0;

	ifr.ifr_flags = flags;
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

	res = ioctl(skfd, SIOCSIFFLAGS, &ifr);
	if (res < 0) {
		saved_errno = errno;
		v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
			ifname, strerror(saved_errno));
	} else {
		v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
	}

	return res;
}
예제 #8
0
static int clear_if_addr(char *ifname)
{
	struct ifreq ifr;
	int res = 0;

	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	ifr.ifr_addr.sa_family = AF_INET;
	memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data));

	res = ioctl(skfd, SIOCSIFADDR, &ifr);
	if (res < 0) {
		saved_errno = errno;
		v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n",
			ifname, strerror(saved_errno));
	} else {
		v_print("Interface '%s': address cleared\n", ifname);
	}

	return res;
}
예제 #9
0
static int get_drv_info(char *master_ifname)
{
	struct ifreq ifr;
	struct ethtool_drvinfo info;
	char *endptr;

	memset(&ifr, 0, sizeof(ifr));
	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	ifr.ifr_data = (caddr_t)&info;

	info.cmd = ETHTOOL_GDRVINFO;
	strncpy(info.driver, "ifenslave", 32);
	snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);

	if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) {
		if (errno == EOPNOTSUPP) {
			goto out;
		}

		saved_errno = errno;
		v_print("Master '%s': Error: get bonding info failed %s\n",
			master_ifname, strerror(saved_errno));
		return 1;
	}

	abi_ver = strtoul(info.fw_version, &endptr, 0);
	if (*endptr) {
                v_print("Master '%s': Error: got invalid string as an ABI "
			"version from the bonding module\n",
			master_ifname);
		return 1;
	}

out:
	v_print("ABI ver is %d\n", abi_ver);

	return 0;
}
예제 #10
0
static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr)
{
	unsigned char *addr = (unsigned char *)hwaddr->sa_data;
	struct ifreq ifr;
	int res = 0;

	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
	res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
	if (res < 0) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n",
			master_ifname, strerror(saved_errno));
		return res;
	} else {
		v_print("Master '%s': hardware address set to "
			"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
			master_ifname, addr[0], addr[1], addr[2],
			addr[3], addr[4], addr[5]);
	}

	return res;
}
예제 #11
0
static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr)
{
	unsigned char *addr = (unsigned char *)hwaddr->sa_data;
	struct ifreq ifr;
	int res = 0;

	strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
	memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
	res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
	if (res < 0) {
		saved_errno = errno;

		v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n",
			slave_ifname, strerror(saved_errno));

		if (saved_errno == EBUSY) {
			v_print("  The device is busy: it must be idle "
				"before running this command.\n");
		} else if (saved_errno == EOPNOTSUPP) {
			v_print("  The device does not support setting "
				"the MAC address.\n"
				"  Your kernel likely does not support slave "
				"devices.\n");
		} else if (saved_errno == EINVAL) {
			v_print("  The device's address type does not match "
				"the master's address type.\n");
		}
		return res;
	} else {
		v_print("Slave '%s': hardware address set to "
			"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
			slave_ifname, addr[0], addr[1], addr[2],
			addr[3], addr[4], addr[5]);
	}

	return res;
}
예제 #12
0
static int get_if_settings(char *ifname, struct dev_ifr ifra[])
{
	int i;
	int res = 0;

	for (i = 0; ifra[i].req_ifr; i++) {
		strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ);
		res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr);
		if (res < 0) {
			saved_errno = errno;
			v_print("Interface '%s': Error: %s failed: %s\n",
				ifname, ifra[i].req_name,
				strerror(saved_errno));

			return saved_errno;
		}
	}

	return 0;
}
예제 #13
0
/* Print contents of a queue */
void
vq_print(vqueue *q, FILE *fp)
{
    int i;

    VQ_CHECK(q);

    v_print_start();
    v_push_indent();

    v_print_type(vqueue_type, q, fp);

    for (i = 1; i < q->entries; i++) {
        v_indent(fp);
        fprintf(fp, "PRIORITY %g => ", QVAL(q, i)->priority);
        v_print(QVAL(q, i)->val, fp);
    }

    v_pop_indent();
    v_print_finish();
}
예제 #14
0
static int release(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res = 0;

	if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
		fprintf(stderr,
			"Illegal operation: The specified slave interface "
			"'%s' is not a slave\n",
			slave_ifname);
		return 1;
	}

	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
	if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
	    (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
			master_ifname, strerror(saved_errno));
		return 1;
	} else if (abi_ver < 1) {
		/* The driver is using an old ABI, so we'll set the interface
		 * down to avoid any conflicts due to same MAC/IP
		 */
		res = set_if_down(slave_ifname, slave_flags.ifr_flags);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: bring interface "
				"down failed\n",
				slave_ifname);
		}
	}

	/* set to default mtu */
	set_slave_mtu(slave_ifname, 1500);

	return res;
}
예제 #15
0
static int release(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res = 0;

	if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
		fprintf(stderr,
			"Illegal operation: The specified slave interface "
			"'%s' is not a slave\n",
			slave_ifname);
		return 1;
	}

	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
	if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
	    (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
			master_ifname, strerror(saved_errno));
		return 1;
	} else if (abi_ver < 1) {
		res = set_if_down(slave_ifname, slave_flags.ifr_flags);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: bring interface "
				"down failed\n",
				slave_ifname);
		}
	}

	
	set_slave_mtu(slave_ifname, 1500);

	return res;
}
예제 #16
0
int main(int argc, char *argv[])
{
	char **spp, *master_ifname, *slave_ifname;
	int c, i, rv;
	int res = 0;
	int exclusive = 0;

	while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) {
		switch (c) {
		case 'a': opt_a++; exclusive++; break;
		case 'c': opt_c++; exclusive++; break;
		case 'd': opt_d++; exclusive++; break;
		case 'f': opt_f++; exclusive++; break;
		case 'h': opt_h++; exclusive++; break;
		case 'u': opt_u++; exclusive++; break;
		case 'v': opt_v++; break;
		case 'V': opt_V++; exclusive++; break;

		case '?':
			fprintf(stderr, usage_msg);
			res = 2;
			goto out;
		}
	}

	/* options check */
	if (exclusive > 1) {
		fprintf(stderr, usage_msg);
		res = 2;
		goto out;
	}

	if (opt_v || opt_V) {
		printf(version);
		if (opt_V) {
			res = 0;
			goto out;
		}
	}

	if (opt_u) {
		printf(usage_msg);
		res = 0;
		goto out;
	}

	if (opt_h) {
		printf(usage_msg);
		printf(help_msg);
		res = 0;
		goto out;
	}

	/* Open a basic socket */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		res = 1;
		goto out;
	}

	if (opt_a) {
		if (optind == argc) {
			/* No remaining args */
			/* show all interfaces */
			if_print((char *)NULL);
			goto out;
		} else {
			/* Just show usage */
			fprintf(stderr, usage_msg);
			res = 2;
			goto out;
		}
	}

	/* Copy the interface name */
	spp = argv + optind;
	master_ifname = *spp++;

	if (master_ifname == NULL) {
		fprintf(stderr, usage_msg);
		res = 2;
		goto out;
	}

	/* exchange abi version with bonding module */
	res = get_drv_info(master_ifname);
	if (res) {
		fprintf(stderr,
			"Master '%s': Error: handshake with driver failed. "
			"Aborting\n",
			master_ifname);
		goto out;
	}

	slave_ifname = *spp++;

	if (slave_ifname == NULL) {
		if (opt_d || opt_c) {
			fprintf(stderr, usage_msg);
			res = 2;
			goto out;
		}

		/* A single arg means show the
		 * configuration for this interface
		 */
		if_print(master_ifname);
		goto out;
	}

	res = get_if_settings(master_ifname, master_ifra);
	if (res) {
		/* Probably a good reason not to go on */
		fprintf(stderr,
			"Master '%s': Error: get settings failed: %s. "
			"Aborting\n",
			master_ifname, strerror(res));
		goto out;
	}

	/* check if master is indeed a master;
	 * if not then fail any operation
	 */
	if (!(master_flags.ifr_flags & IFF_MASTER)) {
		fprintf(stderr,
			"Illegal operation; the specified interface '%s' "
			"is not a master. Aborting\n",
			master_ifname);
		res = 1;
		goto out;
	}

	/* check if master is up; if not then fail any operation */
	if (!(master_flags.ifr_flags & IFF_UP)) {
		fprintf(stderr,
			"Illegal operation; the specified master interface "
			"'%s' is not up.\n",
			master_ifname);
		res = 1;
		goto out;
	}

	/* Only for enslaving */
	if (!opt_c && !opt_d) {
		sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family;
		unsigned char *hwaddr =
			(unsigned char *)master_hwaddr.ifr_hwaddr.sa_data;

		/* The family '1' is ARPHRD_ETHER for ethernet. */
		if (master_family != 1 && !opt_f) {
			fprintf(stderr,
				"Illegal operation: The specified master "
				"interface '%s' is not ethernet-like.\n "
				"This program is designed to work with "
				"ethernet-like network interfaces.\n "
				"Use the '-f' option to force the "
				"operation.\n",
				master_ifname);
			res = 1;
			goto out;
		}

		/* Check master's hw addr */
		for (i = 0; i < 6; i++) {
			if (hwaddr[i] != 0) {
				hwaddr_set = 1;
				break;
			}
		}

		if (hwaddr_set) {
			v_print("current hardware address of master '%s' "
				"is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
				"type %d\n",
				master_ifname,
				hwaddr[0], hwaddr[1],
				hwaddr[2], hwaddr[3],
				hwaddr[4], hwaddr[5],
				master_family);
		}
	}

	/* Accepts only one slave */
	if (opt_c) {
		/* change active slave */
		res = get_slave_flags(slave_ifname);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: get flags failed. "
				"Aborting\n",
				slave_ifname);
			goto out;
		}
		res = change_active(master_ifname, slave_ifname);
		if (res) {
			fprintf(stderr,
				"Master '%s', Slave '%s': Error: "
				"Change active failed\n",
				master_ifname, slave_ifname);
		}
	} else {
		/* Accept multiple slaves */
		do {
			if (opt_d) {
				/* detach a slave interface from the master */
				rv = get_slave_flags(slave_ifname);
				if (rv) {
					/* Can't work with this slave. */
					/* remember the error and skip it*/
					fprintf(stderr,
						"Slave '%s': Error: get flags "
						"failed. Skipping\n",
						slave_ifname);
					res = rv;
					continue;
				}
				rv = release(master_ifname, slave_ifname);
				if (rv) {
					fprintf(stderr,
						"Master '%s', Slave '%s': Error: "
						"Release failed\n",
						master_ifname, slave_ifname);
					res = rv;
				}
			} else {
				/* attach a slave interface to the master */
				rv = get_if_settings(slave_ifname, slave_ifra);
				if (rv) {
					/* Can't work with this slave. */
					/* remember the error and skip it*/
					fprintf(stderr,
						"Slave '%s': Error: get "
						"settings failed: %s. "
						"Skipping\n",
						slave_ifname, strerror(rv));
					res = rv;
					continue;
				}
				rv = enslave(master_ifname, slave_ifname);
				if (rv) {
					fprintf(stderr,
						"Master '%s', Slave '%s': Error: "
						"Enslave failed\n",
						master_ifname, slave_ifname);
					res = rv;
				}
			}
		} while ((slave_ifname = *spp++) != NULL);
	}

out:
	if (skfd >= 0) {
		close(skfd);
	}

	return res;
}
예제 #17
0
/* Ideally, vector_append would be consistent, durable, and _atomic_, which
 * would mean that it doesn't have to be _recovered_ after a failure. This
 * is probably possible by following the instructions in "A Lock-Free
 * Dynamically Resizable Array." However, this would require a significant
 * restructuring of the vector code that we already have, so we won't do
 * this for now. Instead, when the vector needs resizing, we focus on making
 * it _recoverable_, rather than atomic; when the vector doesn't need resizing,
 * then append is consistent and durable and _repeatable_, rather than atomic.
 *
 * Note that vector_append is NOT thread-safe or "lock-free" - high-level
 * synchronization is needed so that only one append occurs at a time!
 *
 * Relevant links:
 *   http://www2.research.att.com/~bs/lock-free-vector.pdf
 *   https://parasol.tamu.edu/~peterp/slides/opodis06.pdf
 *   Intel patent, 8006064: "Lock-free vector utilizing a resource allocator...":
 *     http://www.google.com/patents/US8006064?printsec=abstract#v=onepage&q&f=false
 *   http://www.ibm.com/developerworks/aix/library/au-intelthreadbuilding/index.html?ca=drs-
 *   http://software.intel.com/en-us/blogs/2009/04/09/delusion-of-tbbconcurrent_vectors-size-or-3-ways-to-traverse-in-parallel-correctly/
 *
 * This function allows NULL pointers for the element put into the array,
 * for now. 
 *
 * NOTE: for version 3.1 (simultaneous merges with conflict detection), I
 * hacked this interface to return the element that used to be the last
 * element in the vector, before we appended this one. Hmmm...
 */
int vector_append(vector *v, const void *e, void **previous_tail)
{
	unsigned long long orig_size, new_size;
	int flush_size = 0;

	/* HEADS UP: this function is mostly the same as vector_insert(), so
	 * if you update one, you should probably update the other! */

	if (v == NULL) {
		v_error("v is NULL\n");
		return -1;
	}
	if (v->count == VECTOR_MAX_COUNT) {
		v_error("hit maximum vector length: v->count=%llu\n", v->count);
		return -1;
	}
#ifndef UNSAFE_COMMIT
//#ifdef VECTOR_ASSERT
#if 0
	/* This assert only makes sense if we're not garbage collecting or
	 * otherwise removing things from vectors. Note that the resizing
	 * code doesn't contain any explicit checks for this (it will
	 * happily reduce the size of the vector below the initial size
	 * if you remove enough things); maybe this behavior should change,
	 * but whatever. */
	if (v->size < VECTOR_INIT_SIZE) {
		v_die("vector size %llu is less than initial size %d!!\n",
				v->size, VECTOR_INIT_SIZE);
	}
#endif
#endif

	/* When the last array slot is exhausted, increase the size of the
	 * array by multiplying it by the resize factor.
	 * Resizing the array consists of two steps: A) re-allocing the memory
	 * region, and B) setting the new size of the vector. A) is repeatable,
	 * but unfortunately could result in a memory leak if we don't correctly
	 * remember the pointer AND remember the new size! To minimize the leak
	 * window here, we immediately flush both the pointer and the size (which
	 * should be adjacent to each other in the struct!) after the realloc.
	 * We calculate the size of the flush that we need to perform by using
	 * the offsetof operator, because the compiler may insert padding between
	 * members that we don't know about. This code assumes that the order of
	 * the members in the struct is [data, size, count].
	 *
	 * ...
	 */
	if (v->size == v->count) {
#ifdef VECTOR_RESIZE_PRINT
		v_print("v->size hit v->count = %llu; append resizing!!!\n",
				v->size);
#endif
		v_debug("v->size hit v->count = %llu; resizing!!!\n", v->size);
		/* Check if multiplying v->size by VECTOR_RESIZE_FACTOR will put
		 * it over the VECTOR_MAX_COUNT:
		 */
		if (v->size > (VECTOR_MAX_COUNT / VECTOR_RESIZE_FACTOR)) {
			v_debug("vector size (%llu) times resize factor (%d) would "
					"overflow max count (%llu), so setting size directly "
					"to max count\n", v->size, VECTOR_RESIZE_FACTOR,
					VECTOR_MAX_COUNT);
			new_size = VECTOR_MAX_COUNT;
		} else {
			new_size = v->size * VECTOR_RESIZE_FACTOR;
		}
#ifdef VECTOR_RESIZE_PRINT
		v_print("calculated new_size=%llu (append)\n", new_size);
#endif
		orig_size = v->size;
#ifdef UNSAFE_COMMIT
		if (new_size > UNSAFE_COMMIT_LOG_SIZE) {
			v_print("WARNING: new vector size is greater than %d, probably "
					"means that we're resizing the commit_log vector!!\n",
					UNSAFE_COMMIT_LOG_SIZE);
		}
#endif
#ifdef V_ASSERT
		if (new_size > 100) {
			v_debug("WARNING: resizing vector to new_size=%llu\n", new_size);
		}
#endif

		/* We expect the flush_size to be 12, but the compiler could possibly
		 * insert padding that changes this. On brief examination, no padding
		 * is inserted and both the data pointer and the size are flushed in
		 * a single flush.
		 * todo: could put the following code segment in its own "pcm_realloc()"
		 * function...
		 */
		if (v->use_nvm) {
			/* We only need to flush data and size; count comes _after_ size,
			 * so use it as the end of the range to flush. */
			flush_size = offsetof(vector, count) - offsetof(vector, data);
#ifdef VECTOR_ASSERT
			if (flush_size < (sizeof(void **) + sizeof(unsigned long long))) {
				v_die("got unexpected flush_size %d! offsetof(count)=%zu, "
						"offsetof(data)=%zu\n", flush_size,
						offsetof(vector, count), offsetof(vector, data));
			}
			//v_print("calculated flush_size %d from offsetof(count)=%u, "
			//		"offsetof(data)=%d\n", flush_size,
			//		offsetof(vector, count), offsetof(vector, data));
#endif
		}

		/* Leak window begin. Note that kp_realloc() doesn't flush internally,
		 * because we want to flush both the data and the size in the same
		 * cache line to get consistency
		 *   Also note that we don't currently GUARANTEE this, if the compiler
		 *   happens to allocate v->data and v->size in two different cache
		 *   lines. */
		kp_realloc((void **)&(v->data), sizeof(void*) * new_size, v->use_nvm);
		v->size = new_size;
		kp_flush_range(&(v->data), flush_size, v->use_nvm);  //flush both data and size!
		/* Leak window end. If we fail after the flush() has returned,
		 * then the next call to vector_append() will skip the resizing
		 * step.
		 */
		if (v->data == NULL) {
			v_error("kp_realloc(array) failed\n");
			/* Best effort on failure: reset size to what it was before,
			 * and let caller handle the rest.
			 */
			v->size = orig_size;
			return -1;
		}

		v_debug("re-allocated array, now has size %llu (%llu slots)\n",
				sizeof(void*) * v->size, v->size);
	}

	/* The actual append part of vector_append() is repeatable: we first
	 * fill in the element in the data array, then increment the count.
	 * If we fail in-between these two steps, then vector_append() can
	 * just be called again and we'll overwrite the memory area with the
	 * same value. We do, however, have to flush the written element before
	 * incrementing the count: we don't want the incremented count to hit
	 * memory before the new element does.
	 * ACTUALLY, this makes the vector_append ATOMIC, not repeatable (right?).
	 * After a failure, if the caller didn't get a return value from this
	 * function, then it can't be certain whether or not the append succeeded,
	 * and so it should probably do a vector_get() to check if the append
	 * happened or not.
	 */
	if (previous_tail) {  //super hacky
		if (v->count > 0) {
			*previous_tail = v->data[v->count - 1];
		} else {
			*previous_tail = NULL;
		}
		/* Don't need to flush; caller will do it... */
	}

	/* Use two flushes here to make this "repeatable" - if we fail after
	 * the first set + flush, there are no real effects. */
	v->data[v->count] = (void *)e;
	kp_flush_range(&(v->data[v->count]), sizeof(void *), v->use_nvm);
	/* Do we need a memory fence right here? Only if we're flushing (so
	 * the fence is already internal in kp_flush_range()); otherwise,
	 * we're not concerned about anybody else seeing the count and the
	 * element out-of-order... (right?). */
	v->count++;
	kp_flush_range((void *)&(v->count), sizeof(unsigned long long), v->use_nvm);
	v_debug("stored new element %s in slot %llu (now count=%llu, size=%llu)\n",
			(char *)(v->data[(v->count)-1]), v->count-1, v->count, v->size);

	return 0;
}
static int enslave(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res = 0;

	if (slave_flags.ifr_flags & IFF_SLAVE) {
		fprintf(stderr,
			"Illegal operation: The specified slave interface "
			"'%s' is already a slave\n",
			slave_ifname);
		return 1;
	}

	res = set_if_down(slave_ifname, slave_flags.ifr_flags);
	if (res) {
		fprintf(stderr,
			"Slave '%s': Error: bring interface down failed\n",
			slave_ifname);
		return res;
	}

	if (abi_ver < 2) {
		/*                                                          
                                                    
   */
		set_if_addr(master_ifname, slave_ifname);
	} else {
		res = clear_if_addr(slave_ifname);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: clear address failed\n",
				slave_ifname);
			return res;
		}
	}

	if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
		res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: set MTU failed\n",
				slave_ifname);
			return res;
		}
	}

	if (hwaddr_set) {
		/*                             
                                    
   */
		if (abi_ver < 1) {
			/*                                   
                                      
            
    */
			res = set_slave_hwaddr(slave_ifname,
					       &(master_hwaddr.ifr_hwaddr));
			if (res) {
				fprintf(stderr,
					"Slave '%s': Error: set hw address "
					"failed\n",
					slave_ifname);
				goto undo_mtu;
			}

			/*                                               
                   
    */
			res = set_if_up(slave_ifname, slave_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Slave '%s': Error: bring interface "
					"down failed\n",
					slave_ifname);
				goto undo_slave_mac;
			}
		}
		/*                               
                                        
                                    
                
   */
	} else {
		/*                             
                                 
   */
		if (abi_ver < 1) {
			/*                                    
                                    
    */
			res = set_if_down(master_ifname, master_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Master '%s': Error: bring interface "
					"down failed\n",
					master_ifname);
				goto undo_mtu;
			}
		}

		res = set_master_hwaddr(master_ifname,
					&(slave_hwaddr.ifr_hwaddr));
		if (res) {
			fprintf(stderr,
				"Master '%s': Error: set hw address "
				"failed\n",
				master_ifname);
			goto undo_mtu;
		}

		if (abi_ver < 1) {
			/*                              
             
    */
			res = set_if_up(master_ifname, master_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Master '%s': Error: bring interface "
					"up failed\n",
					master_ifname);
				goto undo_master_mac;
			}
		}

		hwaddr_set = 1;
	}

	/*                   */
	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
	if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
	    (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
			master_ifname, strerror(saved_errno));
		res = 1;
	}

	if (res) {
		goto undo_master_mac;
	}

	return 0;

/*                        */
undo_master_mac:
	set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
	hwaddr_set = 0;
	goto undo_mtu;
undo_slave_mac:
	set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
undo_mtu:
	set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
	return res;
}
예제 #19
0
/* CHECK - TODO: how consistent / durable / atomic / recoverable is this
 * function???
 *
 * This function allows NULL pointers for the element put into the array,
 * for now. */
uint64_t vector_insert(vector *v, const void *e, vector_comparator cmp)
{
	unsigned long long orig_size, new_size;
	uint64_t insert_idx, shift_idx;
	int flush_size = 0;

	/* HEADS UP: this function is mostly the same as vector_append(), so
	 * if you update one, you should probably update the other! */

	if (v == NULL) {
		v_error("v is NULL\n");
		return -1;
	}
	if (v->count == VECTOR_MAX_COUNT) {
		v_error("hit maximum vector length: v->count=%llu\n", v->count);
		return -1;
	}
#ifndef UNSAFE_COMMIT
//#ifdef VECTOR_ASSERT
#if 0
	/* This assert only makes sense if we're not garbage collecting or
	 * otherwise removing things from vectors. Note that the resizing
	 * code doesn't contain any explicit checks for this (it will
	 * happily reduce the size of the vector below the initial size
	 * if you remove enough things); this bhavior should probably
	 * change, but whatever. */
	if (v->size < VECTOR_INIT_SIZE) {
		v_die("vector size %llu is less than initial size %d!!\n",
				v->size, VECTOR_INIT_SIZE);
	}
#endif
#endif

	kp_todo("factor out the resizing code that's common to both append "
			"and insert, dummy!\n");

	/* When the last array slot is exhausted, increase the size of the
	 * array by multiplying it by the resize factor.
	 * Resizing the array consists of two steps: A) re-allocing the memory
	 * region, and B) setting the new size of the vector. A) is repeatable,
	 * but unfortunately could result in a memory leak if we don't correctly
	 * remember the pointer AND remember the new size! To minimize the leak
	 * window here, we immediately flush both the pointer and the size (which
	 * should be adjacent to each other in the struct!) after the realloc.
	 * We calculate the size of the flush that we need to perform by using
	 * the offsetof operator, because the compiler may insert padding between
	 * members that we don't know about. This code assumes that the order of
	 * the members in the struct is [data, size, count].
	 *
	 * ...
	 */
	if (v->size == v->count) {
#ifdef VECTOR_RESIZE_PRINT
		v_print("v->size hit v->count = %llu; insert resizing!!!\n",
				v->size);
#endif
		v_debug("v->size hit v->count = %llu; resizing!!!\n", v->size);
		/* Check if multiplying v->size by VECTOR_RESIZE_FACTOR will put
		 * it over the VECTOR_MAX_COUNT:
		 */
		if (v->size > (VECTOR_MAX_COUNT / VECTOR_RESIZE_FACTOR)) {
			v_debug("vector size (%llu) times resize factor (%d) would "
					"overflow max count (%llu), so setting size directly "
					"to max count\n", v->size, VECTOR_RESIZE_FACTOR,
					VECTOR_MAX_COUNT);
			new_size = VECTOR_MAX_COUNT;
		} else {
			new_size = v->size * VECTOR_RESIZE_FACTOR;
		}
#ifdef VECTOR_RESIZE_PRINT
		v_print("calculated new_size=%llu (insert)\n", new_size);
#endif
		orig_size = v->size;
#ifdef UNSAFE_COMMIT
		if (new_size > UNSAFE_COMMIT_LOG_SIZE) {
			v_print("WARNING: new vector size is greater than %d, probably "
					"means that we're resizing the commit_log vector!!\n",
					UNSAFE_COMMIT_LOG_SIZE);
		}
#endif
#ifdef V_ASSERT
		if (new_size > 100) {
			v_debug("WARNING: resizing vector to new_size=%llu\n", new_size);
		}
#endif

		/* We expect the flush_size to be 12, but the compiler could possibly
		 * insert padding that changes this. On brief examination, no padding
		 * is inserted and both the data pointer and the size are flushed in
		 * a single flush.
		 * todo: could put the following code segment in its own "pcm_realloc()"
		 * function...
		 */
		if (v->use_nvm) {
			/* We only need to flush data and size; count comes _after_ size,
			 * so use it as the end of the range to flush. */
			flush_size = offsetof(vector, count) - offsetof(vector, data);
			//v_print("calculated flush_size=%d from offsetof(count)=%u, "
			//		"offsetof(data)=%u\n", flush_size, offsetof(vector, count),
			//		offsetof(vector, data));
#ifdef VECTOR_ASSERT
			if (flush_size < (sizeof(void **) + sizeof(unsigned long long))) {
				v_die("got unexpected flush_size %d! offsetof(count)=%zu, "
						"offsetof(data)=%zu\n", flush_size,
						offsetof(vector, count), offsetof(vector, data));
			}
			//v_print("calculated flush_size %d from offsetof(count)=%u, "
			//		"offsetof(data)=%d\n", flush_size,
			//		offsetof(vector, count), offsetof(vector, data));
#endif
		}

		/* Leak window begin. Note that kp_realloc() doesn't flush internally,
		 * because we want to flush both the data and the size in the same
		 * cache line to get consistency
		 *   Also note that we don't currently GUARANTEE this, if the compiler
		 *   happens to allocate v->data and v->size in two different cache
		 *   lines. */
		kp_realloc((void **)&(v->data), sizeof(void*) * new_size, v->use_nvm);
		v->size = new_size;
		kp_flush_range(&(v->data), flush_size, v->use_nvm);  //flush both data and size!
		/* Leak window end. If we fail after the flush() has returned,
		 * then the next call to vector_append() will skip the resizing
		 * step.
		 */
		if (v->data == NULL) {
			v_error("kp_realloc(array) failed\n");
			/* Best effort on failure: reset size to what it was before,
			 * and let caller handle the rest.
			 */
			v->size = orig_size;
			return -1;
		}

		v_debug("re-allocated array, now has size %llu (%llu slots)\n",
				sizeof(void*) * v->size, v->size);
	}

	/* We expect that this function will often be an append anyway, so
	 * we start at the end of the array and then search backwards for the
	 * index to insert into. */
	insert_idx = v->count;
	/* The comparator function returns positive if e1 > e2. By using
	 * > and not >= here, we will stop as early as possible, so if
	 * elements happen to be equal to each other then the later elements
	 * will be further along in the array. */
	while (insert_idx > 0 && cmp(v->data[insert_idx-1], e) > 0) {
		insert_idx--;
	}
	//v_print("set insert_idx=%llu (count=%llu)\n", insert_idx, v->count);

	/* Start at the back of the array again and shift elements forward one
	 * at a time. This is somewhat "repeatable" - if a failure occurs while
	 * we're doing this, then we can either remember the shift index, or
	 * look through the array for duplicates, and then resume where we left
	 * off. We flush after every single shift (ouch!) so that no data can
	 * be lost. */
	shift_idx = v->count;
	while (shift_idx > insert_idx) {
		//v_print("shifting element from %llu to %llu\n", shift_idx-1, shift_idx);
		v->data[shift_idx] = v->data[shift_idx - 1];
		kp_flush_range(&(v->data[shift_idx]), sizeof(void *), v->use_nvm);
		shift_idx--;
	}
	//v_print("now inserting new element into idx=%llu\n", insert_idx);

	/* Use two flushes here to make this "repeatable" - if we fail after
	 * the first set + flush, there are no real effects (well, this was
	 * true for append... is it any different for insert??). */
	v->data[insert_idx] = (void *)e;
	kp_flush_range(&(v->data[insert_idx]), sizeof(void *), v->use_nvm);
	v->count++;
	kp_flush_range(&(v->count), sizeof(unsigned long long), v->use_nvm);
	//v_print("stored new element %s in slot %llu (now count=%llu, size=%llu)\n",
	//		(char *)(v->data[insert_idx]), insert_idx, v->count, v->size);
	//v_print("stored new element %p in slot %llu (now count=%llu, size=%llu)\n",
	//		v->data[insert_idx], insert_idx, v->count, v->size);

	return insert_idx;
}
예제 #20
0
void MoveR::IK4(const point& P)
{
  //ROS_INFO("IK\n");
  double th0=0,th1=0,th2=0,th3=0;
  double x=P.x.data;
  double y=P.y.data;
  double z=P.z.data;
  double p[3]={x,y,z};
  double temp1=pow(x,2)+pow(y,2)+pow(z,2);
  double norm_p=pow(temp1,0.5);
  double b=acos((pow(lup,2)+pow(ldn,2)-pow(norm_p,2))/(2*lup*ldn));
  th3=PI-b;  
  double a=asin((ldn/norm_p)*sin(b));
  double s[3]={0,0,0};
  double u_z[3]={0,0,1};
  double p_s[3];
  v_sub(p,s,p_s,3);
  //ROS_INFO("p\n");
  //v_print(p,3);	
  //ROS_INFO("s\n");
  //v_print(s,3);	
  //ROS_INFO("p-s\n");
  //v_print(p_s,3);	

  double norm_p_s=pow(pow(p_s[0],2)+pow(p_s[1],2)+pow(p_s[2],2),0.5);
  double u_n[3]={p_s[0]/norm_p_s,p_s[1]/norm_p_s,p_s[2]/norm_p_s};
  
  //ROS_INFO("u_n\n");
  //v_print(u_n,3);	
  double tmp[3];
  v_scalar_multip(v_dot(u_z,u_n,3),u_n,tmp,3);
  double u[3],u_u[3];
  //v_add(u_z,tmp,u,3);
  
  //u correct on 2/17
  v_cross(u_n,u_z,u);

  double norm_u=pow(pow(u[0],2)+pow(u[1],2)+pow(u[2],2),0.5);
  v_scalar_multip(1/norm_u,u,u_u,3);

  //ROS_INFO("u_u \n");
  //v_print(u_u,3);	
  double v[3],u_v[3];
  v_cross(u_n,u_u,v);
  double norm_v=pow(pow(v[0],2)+pow(v[1],2)+pow(v[2],2),0.5);
  v_scalar_multip(1/norm_v,v,u_v,3);

  //ROS_INFO("u_v \n");
  //v_print(u_v,3);	

  double c[3];
  v_scalar_multip(cos(a)*lup,u_n,tmp,3);
  v_add(s,tmp,c,3);
  double r=lup*sin(a);
  //double fi=PI/2;
  ROS_INFO("b %f\n",b);

  ROS_INFO("a %f\n",a);
  double tmp1[3],tmp2[3];
  v_scalar_multip(cos(fi),u_u,tmp1,3);
  v_scalar_multip(sin(fi),u_v,tmp2,3);
  v_add(tmp1,tmp2,tmp,3);
  v_scalar_multip(r,tmp,tmp,3);
  double e[3];
  v_add(c,tmp,e,3);
  ROS_INFO("u_u \n");
  v_print(u_u,3);	

  double ex=e[0],ey=e[1],ez=e[2];
  ROS_INFO("ex %f\n",ex);
  ROS_INFO("ey %f\n",ey);
  ROS_INFO("ez %f\n",ez);

  if(ex>=0&&ey<0)
    th0=atan((double)abs(ex)/abs(ey));
  else if(ex>=0&&ey>=0)
      th0=PI-atan((double)abs(ex)/abs(ey));
    else if(ex<0&&ey>=0)
        th0=PI+atan((double)abs(ex)/abs(ey));
      else if(ex<0&&ey<0)
          th0=-atan((double)abs(ex)/abs(ey));
  double temp2=pow(pow(ex,2)+pow(ey,2),0.5);
  if(ez>=0)
    th1=-atan((double)abs(ez)/temp2);
  else if(ez<0)
    th1=atan((double)abs(ez)/temp2);

   //ROS_INFO("IK:th0 %f\n",th0);
   //ROS_INFO("IK:th1 %f\n",th1);
   //ROS_INFO("th3 %f\n",th3);


  th2=atan2(-x*sin(th0)*sin(th1)+y*cos(th0)*sin(th1)-z*cos(th1),x*cos(th0)+y*sin(th0));
  ROS_INFO("x %f  y %f  z %f\n",x,y,z);

  ROS_INFO("th0 %f  th1 %f  th2 %f  th3 %f  fi% f\n",th0,th1,th2,th3,fi);

  if(isnan(th0)||isnan(th1)||isnan(th2)||isnan(th3)||th0>TH0_MAX||th0<TH0_MIN||th1>TH1_MAX||th1<TH1_MIN||th3>TH3_MAX||th3<TH3_MIN){
    ROS_INFO("Fail and dont move\n");
   }
  else{
    ROS_INFO("go move move time=%f\n",move_time);

    arm_angle.joint0.angle = th0;
    arm_angle.joint0.duration = move_time;
    arm_angle.joint1.angle = th1;
    arm_angle.joint1.duration = move_time;
    arm_angle.joint2.angle = th2;
    arm_angle.joint2.duration = move_time;
    arm_angle.joint3.angle = th3;
    arm_angle.joint3.duration = move_time;
  }
}
예제 #21
0
파일: physics.c 프로젝트: r0nk/atomvus
void init_physics()
{
	ions[0] = proton();
	ions[1] = electron();
	ions[0].location = (struct vector) {0,0,0};
	ions[0].velocity=(struct vector){0,0,0};
	ions[1].location = (struct vector) {0,20,0};
	ions[1].velocity=(struct vector){0.15,0,0};
}

/*
void init_physics()
{
#define RANDO ((rand()%100)-50)
	int i;
	for(i=0;i<N_IONS;i++){
		switch(rand()%8){
			case 0:
				ions[i] = nuclion(rand()%9);
				break;
			default:
				ions[i] = electron();
				break;
		}
		ions[i].location = (struct vector) {RANDO,RANDO,RANDO};
		ions[i].velocity=(struct vector){0,0,0};
	}
}
*/

void dump_state()
{
	int i;
	printf("--- IONS ---\n");
	for(i=0;i<N_IONS;i++){
		printf("[%i]\n",i);
		printf("charge %Lf \n",ions[i].charge);
		printf("mass %Lf \n",ions[i].mass);
		v_print("location",ions[i].location);
		v_printe("velocity",ions[i].velocity);
		v_printe("acceleration",ions[i].accel);
	}
	printf("-----------\n");
}

void calculate_acceleration(struct particle * p,double dt)
{
	struct vector fv = {0,0,0};
	int i;
	for(i=0;i<N_IONS;i++){
		fv = v_add(fv,gravitation(ions[i],*p));
		fv = v_add(fv,coulombs(ions[i],*p));
//		fv = v_add(fv,biotsavart(ions[i],*p));
	}
	/* because f/m=a */
	fv.x/=p->mass;
	fv.y/=p->mass;
	fv.z/=p->mass;
	p->accel = v_scalar_mul(dt,fv);
}

void apply_vel(struct particle * p)
{
	p->velocity = v_add(p->accel,p->velocity);
	p->location = v_add(p->location,p->velocity);
}

void physics_tick(double dt)
{
	int i;
	for(i=0;i<N_IONS;i++)
		calculate_acceleration(&ions[i],dt);
	for(i=0;i<N_IONS;i++)
		apply_vel(&ions[i]);
	if(keys['P'])
		dump_state();
}
int main(int argc, char *argv[])
{
	char **spp, *master_ifname, *slave_ifname;
	int c, i, rv;
	int res = 0;
	int exclusive = 0;

	while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) {
		switch (c) {
		case 'a': opt_a++; exclusive++; break;
		case 'c': opt_c++; exclusive++; break;
		case 'd': opt_d++; exclusive++; break;
		case 'f': opt_f++; exclusive++; break;
		case 'h': opt_h++; exclusive++; break;
		case 'u': opt_u++; exclusive++; break;
		case 'v': opt_v++; break;
		case 'V': opt_V++; exclusive++; break;

		case '?':
			fprintf(stderr, "%s", usage_msg);
			res = 2;
			goto out;
		}
	}

	/*               */
	if (exclusive > 1) {
		fprintf(stderr, "%s", usage_msg);
		res = 2;
		goto out;
	}

	if (opt_v || opt_V) {
		printf("%s", version);
		if (opt_V) {
			res = 0;
			goto out;
		}
	}

	if (opt_u) {
		printf("%s", usage_msg);
		res = 0;
		goto out;
	}

	if (opt_h) {
		printf("%s", usage_msg);
		printf("%s", help_msg);
		res = 0;
		goto out;
	}

	/*                     */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		res = 1;
		goto out;
	}

	if (opt_a) {
		if (optind == argc) {
			/*                   */
			/*                     */
			if_print((char *)NULL);
			goto out;
		} else {
			/*                 */
			fprintf(stderr, "%s", usage_msg);
			res = 2;
			goto out;
		}
	}

	/*                         */
	spp = argv + optind;
	master_ifname = *spp++;

	if (master_ifname == NULL) {
		fprintf(stderr, "%s", usage_msg);
		res = 2;
		goto out;
	}

	/*                                          */
	res = get_drv_info(master_ifname);
	if (res) {
		fprintf(stderr,
			"Master '%s': Error: handshake with driver failed. "
			"Aborting\n",
			master_ifname);
		goto out;
	}

	slave_ifname = *spp++;

	if (slave_ifname == NULL) {
		if (opt_d || opt_c) {
			fprintf(stderr, "%s", usage_msg);
			res = 2;
			goto out;
		}

		/*                            
                                     
   */
		if_print(master_ifname);
		goto out;
	}

	res = get_if_settings(master_ifname, master_ifra);
	if (res) {
		/*                                     */
		fprintf(stderr,
			"Master '%s': Error: get settings failed: %s. "
			"Aborting\n",
			master_ifname, strerror(res));
		goto out;
	}

	/*                                    
                                  
  */
	if (!(master_flags.ifr_flags & IFF_MASTER)) {
		fprintf(stderr,
			"Illegal operation; the specified interface '%s' "
			"is not a master. Aborting\n",
			master_ifname);
		res = 1;
		goto out;
	}

	/*                                                       */
	if (!(master_flags.ifr_flags & IFF_UP)) {
		fprintf(stderr,
			"Illegal operation; the specified master interface "
			"'%s' is not up.\n",
			master_ifname);
		res = 1;
		goto out;
	}

	/*                    */
	if (!opt_c && !opt_d) {
		sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family;
		unsigned char *hwaddr =
			(unsigned char *)master_hwaddr.ifr_hwaddr.sa_data;

		/*                                              */
		if (master_family != 1 && !opt_f) {
			fprintf(stderr,
				"Illegal operation: The specified master "
				"interface '%s' is not ethernet-like.\n "
				"This program is designed to work with "
				"ethernet-like network interfaces.\n "
				"Use the '-f' option to force the "
				"operation.\n",
				master_ifname);
			res = 1;
			goto out;
		}

		/*                        */
		for (i = 0; i < 6; i++) {
			if (hwaddr[i] != 0) {
				hwaddr_set = 1;
				break;
			}
		}

		if (hwaddr_set) {
			v_print("current hardware address of master '%s' "
				"is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
				"type %d\n",
				master_ifname,
				hwaddr[0], hwaddr[1],
				hwaddr[2], hwaddr[3],
				hwaddr[4], hwaddr[5],
				master_family);
		}
	}

	/*                        */
	if (opt_c) {
		/*                     */
		res = get_slave_flags(slave_ifname);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: get flags failed. "
				"Aborting\n",
				slave_ifname);
			goto out;
		}
		res = change_active(master_ifname, slave_ifname);
		if (res) {
			fprintf(stderr,
				"Master '%s', Slave '%s': Error: "
				"Change active failed\n",
				master_ifname, slave_ifname);
		}
	} else {
		/*                        */
		do {
			if (opt_d) {
				/*                                          */
				rv = get_slave_flags(slave_ifname);
				if (rv) {
					/*                             */
					/*                               */
					fprintf(stderr,
						"Slave '%s': Error: get flags "
						"failed. Skipping\n",
						slave_ifname);
					res = rv;
					continue;
				}
				rv = release(master_ifname, slave_ifname);
				if (rv) {
					fprintf(stderr,
						"Master '%s', Slave '%s': Error: "
						"Release failed\n",
						master_ifname, slave_ifname);
					res = rv;
				}
			} else {
				/*                                        */
				rv = get_if_settings(slave_ifname, slave_ifra);
				if (rv) {
					/*                             */
					/*                               */
					fprintf(stderr,
						"Slave '%s': Error: get "
						"settings failed: %s. "
						"Skipping\n",
						slave_ifname, strerror(rv));
					res = rv;
					continue;
				}
				rv = enslave(master_ifname, slave_ifname);
				if (rv) {
					fprintf(stderr,
						"Master '%s', Slave '%s': Error: "
						"Enslave failed\n",
						master_ifname, slave_ifname);
					res = rv;
				}
			}
		} while ((slave_ifname = *spp++) != NULL);
	}

out:
	if (skfd >= 0) {
		close(skfd);
	}

	return res;
}
예제 #23
0
static int enslave(char *master_ifname, char *slave_ifname)
{
	struct ifreq ifr;
	int res = 0;

	if (slave_flags.ifr_flags & IFF_SLAVE) {
		fprintf(stderr,
			"Illegal operation: The specified slave interface "
			"'%s' is already a slave\n",
			slave_ifname);
		return 1;
	}

	res = set_if_down(slave_ifname, slave_flags.ifr_flags);
	if (res) {
		fprintf(stderr,
			"Slave '%s': Error: bring interface down failed\n",
			slave_ifname);
		return res;
	}

	if (abi_ver < 2) {
		/* Older bonding versions would panic if the slave has no IP
		 * address, so get the IP setting from the master.
		 */
		set_if_addr(master_ifname, slave_ifname);
	} else {
		res = clear_if_addr(slave_ifname);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: clear address failed\n",
				slave_ifname);
			return res;
		}
	}

	if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
		res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
		if (res) {
			fprintf(stderr,
				"Slave '%s': Error: set MTU failed\n",
				slave_ifname);
			return res;
		}
	}

	if (hwaddr_set) {
		/* Master already has an hwaddr
		 * so set it's hwaddr to the slave
		 */
		if (abi_ver < 1) {
			/* The driver is using an old ABI, so
			 * the application sets the slave's
			 * hwaddr
			 */
			res = set_slave_hwaddr(slave_ifname,
					       &(master_hwaddr.ifr_hwaddr));
			if (res) {
				fprintf(stderr,
					"Slave '%s': Error: set hw address "
					"failed\n",
					slave_ifname);
				goto undo_mtu;
			}

			/* For old ABI the application needs to bring the
			 * slave back up
			 */
			res = set_if_up(slave_ifname, slave_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Slave '%s': Error: bring interface "
					"down failed\n",
					slave_ifname);
				goto undo_slave_mac;
			}
		}
		/* The driver is using a new ABI,
		 * so the driver takes care of setting
		 * the slave's hwaddr and bringing
		 * it up again
		 */
	} else {
		/* No hwaddr for master yet, so
		 * set the slave's hwaddr to it
		 */
		if (abi_ver < 1) {
			/* For old ABI, the master needs to be
			 * down before setting its hwaddr
			 */
			res = set_if_down(master_ifname, master_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Master '%s': Error: bring interface "
					"down failed\n",
					master_ifname);
				goto undo_mtu;
			}
		}

		res = set_master_hwaddr(master_ifname,
					&(slave_hwaddr.ifr_hwaddr));
		if (res) {
			fprintf(stderr,
				"Master '%s': Error: set hw address "
				"failed\n",
				master_ifname);
			goto undo_mtu;
		}

		if (abi_ver < 1) {
			/* For old ABI, bring the master
			 * back up
			 */
			res = set_if_up(master_ifname, master_flags.ifr_flags);
			if (res) {
				fprintf(stderr,
					"Master '%s': Error: bring interface "
					"up failed\n",
					master_ifname);
				goto undo_master_mac;
			}
		}

		hwaddr_set = 1;
	}

	/* Do the real thing */
	strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
	strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
	if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
	    (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
		saved_errno = errno;
		v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
			master_ifname, strerror(saved_errno));
		res = 1;
	}

	if (res) {
		goto undo_master_mac;
	}

	return 0;

/* rollback (best effort) */
undo_master_mac:
	set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
	hwaddr_set = 0;
	goto undo_mtu;
undo_slave_mac:
	set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
undo_mtu:
	set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
	return res;
}