+static void
+bond_unixctl_hash(struct unixctl_conn *conn, const char *args_,
+ void *aux OVS_UNUSED)
+{
+ char *args = (char *) args_;
+ uint8_t mac[ETH_ADDR_LEN];
+ uint8_t hash;
+ char *hash_cstr;
+ unsigned int vlan;
+ char *mac_s, *vlan_s;
+ char *save_ptr = NULL;
+
+ mac_s = strtok_r(args, " ", &save_ptr);
+ vlan_s = strtok_r(NULL, " ", &save_ptr);
+
+ if (vlan_s) {
+ if (sscanf(vlan_s, "%u", &vlan) != 1) {
+ unixctl_command_reply(conn, 501, "invalid vlan");
+ return;
+ }
+ } else {
+ vlan = OFP_VLAN_NONE;
+ }
+
+ if (sscanf(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
+ == ETH_ADDR_SCAN_COUNT) {
+ hash = bond_hash_src(mac, vlan);
+
+ hash_cstr = xasprintf("%u", hash);
+ unixctl_command_reply(conn, 200, hash_cstr);
+ free(hash_cstr);
+ } else {
+ unixctl_command_reply(conn, 501, "invalid mac");
+ }
+}
+
+static void
+bond_init(void)
+{
+ unixctl_command_register("bond/list", bond_unixctl_list, NULL);
+ unixctl_command_register("bond/show", bond_unixctl_show, NULL);
+ unixctl_command_register("bond/migrate", bond_unixctl_migrate, NULL);
+ unixctl_command_register("bond/set-active-slave",
+ bond_unixctl_set_active_slave, NULL);
+ unixctl_command_register("bond/enable-slave", bond_unixctl_enable_slave,
+ NULL);
+ unixctl_command_register("bond/disable-slave", bond_unixctl_disable_slave,
+ NULL);
+ unixctl_command_register("bond/hash", bond_unixctl_hash, NULL);
+}
+\f
+/* Port functions. */
+
+static void
+lacp_send_pdu_cb(void *aux, const struct lacp_pdu *pdu)
+{
+ struct iface *iface = aux;
+ uint8_t ea[ETH_ADDR_LEN];
+ int error;
+
+ error = netdev_get_etheraddr(iface->netdev, ea);
+ if (!error) {
+ struct ofpbuf packet;
+ struct lacp_pdu *packet_pdu;
+
+ ofpbuf_init(&packet, 0);
+ packet_pdu = compose_packet(&packet, eth_addr_lacp, ea, ETH_TYPE_LACP,
+ sizeof *packet_pdu);
+ memcpy(packet_pdu, pdu, sizeof *packet_pdu);
+ ofproto_send_packet(iface->port->bridge->ofproto,
+ iface->dp_ifidx, 0, &packet);
+ ofpbuf_uninit(&packet);
+ } else {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
+ VLOG_ERR_RL(&rl, "iface %s: failed to obtain Ethernet address "
+ "(%s)", iface->name, strerror(error));
+ }
+}
+
+static void
+port_run(struct port *port)
+{
+ if (port->monitor) {
+ char *devname;
+
+ /* Track carrier going up and down on interfaces. */
+ while (!netdev_monitor_poll(port->monitor, &devname)) {
+ struct iface *iface;
+
+ iface = port_lookup_iface(port, devname);
+ if (iface) {
+ iface_update_carrier(iface);
+ }
+ free(devname);
+ }
+ } else if (time_msec() >= port->miimon_next_update) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ iface_update_carrier(iface);
+ }
+ port->miimon_next_update = time_msec() + port->miimon_interval;
+ }
+
+ if (port->lacp) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ lacp_slave_enable(port->lacp, iface, iface->enabled);
+ }