X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=73481ddd6da5bd4f01e27d423dfbda8ce4e142ce;hb=ae412e7dd89489911a32c6723d4109c6d1de3a38;hp=e42d41f49b67dac7d3b2640a093ba0f74c8ca2fa;hpb=6cefe1da7705efebd272e956c9bf9423a2eb407b;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e42d41f4..73481ddd 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -147,6 +147,7 @@ struct port { long long int bond_next_fake_iface_update; /* Time of next update. */ int bond_rebalance_interval; /* Interval between rebalances, in ms. */ long long int bond_next_rebalance; /* Next rebalancing time. */ + struct netdev_monitor *monitor; /* Tracks carrier up/down status. */ /* Port mirroring info. */ mirror_mask_t src_mirrors; /* Mirrors triggered when packet received. */ @@ -451,38 +452,27 @@ reconfigure_iface_netdev(struct iface *iface) return error; } +/* Callback for iterate_and_prune_ifaces(). */ static bool -check_iface_netdev(struct bridge *br OVS_UNUSED, struct iface *iface, - void *aux OVS_UNUSED) +check_iface(struct bridge *br, struct iface *iface, void *aux OVS_UNUSED) { if (!iface->netdev) { - int error = create_iface_netdev(iface); - if (error) { - VLOG_WARN("could not open netdev on %s, dropping: %s", iface->name, - strerror(error)); - return false; - } + /* We already reported a related error, don't bother duplicating it. */ + return false; } - return true; -} - -static bool -check_iface_dp_ifidx(struct bridge *br, struct iface *iface, - void *aux OVS_UNUSED) -{ - if (iface->dp_ifidx >= 0) { - VLOG_DBG("%s has interface %s on port %d", - dpif_name(br->dpif), - iface->name, iface->dp_ifidx); - return true; - } else { + if (iface->dp_ifidx < 0) { VLOG_ERR("%s interface not in %s, dropping", iface->name, dpif_name(br->dpif)); return false; } + + VLOG_DBG("%s has interface %s on port %d", dpif_name(br->dpif), + iface->name, iface->dp_ifidx); + return true; } +/* Callback for iterate_and_prune_ifaces(). */ static bool set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface, void *aux OVS_UNUSED) @@ -667,38 +657,58 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) shash_init(&cur_ifaces); for (i = 0; i < n_dpif_ports; i++) { const char *name = dpif_ports[i].devname; - shash_add_once(&cur_ifaces, name, NULL); + shash_add_once(&cur_ifaces, name, &dpif_ports[i]); } - free(dpif_ports); /* Get the set of interfaces we want on this datapath. */ bridge_get_all_ifaces(br, &want_ifaces); + hmap_clear(&br->ifaces); SHASH_FOR_EACH (node, &want_ifaces) { const char *if_name = node->name; struct iface *iface = node->data; - - if (shash_find(&cur_ifaces, if_name)) { - /* Already exists on the datapath. If we have it open, - * reconfigure it; otherwise we'll open it later. */ - if (iface && iface->netdev) { - reconfigure_iface_netdev(iface); + bool internal = !iface || !strcmp(iface->type, "internal"); + struct odp_port *dpif_port = shash_find_data(&cur_ifaces, if_name); + int error; + + /* If we have a port or a netdev already, and it's not the type we + * want, then delete the port (if any) and close the netdev (if + * any). */ + if (internal + ? dpif_port && !(dpif_port->flags & ODP_PORT_INTERNAL) + : (iface->netdev + && strcmp(iface->type, netdev_get_type(iface->netdev)))) + { + if (dpif_port) { + error = ofproto_port_del(br->ofproto, dpif_port->port); + if (error) { + continue; + } + dpif_port = NULL; } - } else { - bool internal = !strcmp(iface->type, "internal"); - int error; + if (iface) { + netdev_close(iface->netdev); + iface->netdev = NULL; + } + } - /* Create interface if it doesn't already exist. */ - if (!internal) { + /* If it's not an internal port, open (possibly create) the + * netdev. */ + if (!internal) { + if (!iface->netdev) { error = create_iface_netdev(iface); if (error) { VLOG_WARN("could not create iface %s: %s", iface->name, strerror(error)); + continue; } - continue; + } else { + reconfigure_iface_netdev(iface); } + } - /* Add to datapath. */ + /* If it's not part of the datapath, add it. */ + if (!dpif_port) { error = dpif_port_add(br->dpif, if_name, internal ? ODP_PORT_INTERNAL : 0, NULL); if (error == EFBIG) { @@ -708,9 +718,25 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) } else if (error) { VLOG_ERR("failed to add %s interface to %s: %s", if_name, dpif_name(br->dpif), strerror(error)); + continue; + } + } + + /* If it's an internal port, open the netdev. */ + if (internal) { + if (iface && !iface->netdev) { + error = create_iface_netdev(iface); + if (error) { + VLOG_WARN("could not create iface %s: %s", iface->name, + strerror(error)); + continue; + } } + } else { + assert(iface->netdev != NULL); } } + free(dpif_ports); shash_destroy(&cur_ifaces); shash_destroy(&want_ifaces); } @@ -724,8 +750,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) bridge_fetch_dp_ifaces(br); - iterate_and_prune_ifaces(br, check_iface_netdev, NULL); - iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL); + iterate_and_prune_ifaces(br, check_iface, NULL); /* Pick local port hardware address, datapath ID. */ bridge_pick_local_hw_addr(br, ea, &hw_addr_iface); @@ -1726,7 +1751,7 @@ bridge_reconfigure_remotes(struct bridge *br, if (!n_controllers && ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) { union ofp_action action; - flow_t flow; + struct flow flow; memset(&action, 0, sizeof action); action.type = htons(OFPAT_OUTPUT); @@ -2030,6 +2055,21 @@ bond_run(struct bridge *br) struct port *port = br->ports[i]; if (port->n_ifaces >= 2) { + char *devname; + + /* Track carrier going up and down on interfaces. */ + while (!netdev_monitor_poll(port->monitor, &devname)) { + struct iface *iface; + bool carrier; + + iface = port_lookup_iface(port, devname); + if (iface && !netdev_get_carrier(iface->netdev, &carrier)) { + bond_link_status_update(iface, carrier); + port_update_bond_compat(port); + } + free(devname); + } + for (j = 0; j < port->n_ifaces; j++) { struct iface *iface = port->ifaces[j]; if (time_msec() >= iface->delay_expires) { @@ -2061,6 +2101,7 @@ bond_wait(struct bridge *br) if (port->n_ifaces < 2) { continue; } + netdev_monitor_poll_wait(port->monitor); for (j = 0; j < port->n_ifaces; j++) { struct iface *iface = port->ifaces[j]; if (iface->delay_expires != LLONG_MAX) { @@ -2074,7 +2115,7 @@ bond_wait(struct bridge *br) } static bool -set_dst(struct dst *p, const flow_t *flow, +set_dst(struct dst *p, const struct flow *flow, const struct port *in_port, const struct port *out_port, tag_type *tags) { @@ -2163,7 +2204,7 @@ port_includes_vlan(const struct port *port, uint16_t vlan) } static size_t -compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan, +compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, const struct port *in_port, const struct port *out_port, struct dst dsts[], tag_type *tags, uint16_t *nf_output_iface) { @@ -2251,7 +2292,7 @@ print_dsts(const struct dst *dsts, size_t n) } static void -compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan, +compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, const struct port *in_port, const struct port *out_port, tag_type *tags, struct odp_actions *actions, uint16_t *nf_output_iface) @@ -2285,7 +2326,7 @@ compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan, * 802.1Q header and implicitly tagged ports. A value of 0 indicates that * the packet is untagged and -1 indicates it has an invalid header and * should be dropped. */ -static int flow_get_vlan(struct bridge *br, const flow_t *flow, +static int flow_get_vlan(struct bridge *br, const struct flow *flow, struct port *in_port, bool have_packet) { /* Note that dl_vlan of 0 and of OFP_VLAN_NONE both mean that the packet @@ -2331,7 +2372,7 @@ static int flow_get_vlan(struct bridge *br, const flow_t *flow, * migration. Older Citrix-patched Linux DomU used gratuitous ARP replies to * indicate this; newer upstream kernels use gratuitous ARP requests. */ static bool -is_gratuitous_arp(const flow_t *flow) +is_gratuitous_arp(const struct flow *flow) { return (flow->dl_type == htons(ETH_TYPE_ARP) && eth_addr_is_broadcast(flow->dl_dst) @@ -2341,7 +2382,7 @@ is_gratuitous_arp(const flow_t *flow) } static void -update_learning_table(struct bridge *br, const flow_t *flow, int vlan, +update_learning_table(struct bridge *br, const struct flow *flow, int vlan, struct port *in_port) { enum grat_arp_lock_type lock_type; @@ -2389,7 +2430,7 @@ update_learning_table(struct bridge *br, const flow_t *flow, int vlan, * so in one special case. */ static bool -is_admissible(struct bridge *br, const flow_t *flow, bool have_packet, +is_admissible(struct bridge *br, const struct flow *flow, bool have_packet, tag_type *tags, int *vlanp, struct port **in_portp) { struct iface *in_iface; @@ -2478,7 +2519,7 @@ is_admissible(struct bridge *br, const flow_t *flow, bool have_packet, * returns true. Otherwise, the actions should only be applied to 'packet', or * not at all, if 'packet' was NULL. */ static bool -process_flow(struct bridge *br, const flow_t *flow, +process_flow(struct bridge *br, const struct flow *flow, const struct ofpbuf *packet, struct odp_actions *actions, tag_type *tags, uint16_t *nf_output_iface) { @@ -2528,45 +2569,8 @@ done: return true; } -/* Careful: 'opp' is in host byte order and opp->port_no is an OFP port - * number. */ -static void -bridge_port_changed_ofhook_cb(enum ofp_port_reason reason, - const struct ofp_phy_port *opp, - void *br_) -{ - struct bridge *br = br_; - struct iface *iface; - struct port *port; - - iface = iface_from_dp_ifidx(br, ofp_port_to_odp_port(opp->port_no)); - if (!iface) { - return; - } - port = iface->port; - - if (reason == OFPPR_DELETE) { - VLOG_WARN("bridge %s: interface %s deleted unexpectedly", - br->name, iface->name); - iface_destroy(iface); - if (!port->n_ifaces) { - VLOG_WARN("bridge %s: port %s has no interfaces, dropping", - br->name, port->name); - port_destroy(port); - } - - bridge_flush(br); - } else { - if (port->n_ifaces > 1) { - bool up = !(opp->state & OFPPS_LINK_DOWN); - bond_link_status_update(iface, up); - port_update_bond_compat(port); - } - } -} - static bool -bridge_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet, +bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet, struct odp_actions *actions, tag_type *tags, uint16_t *nf_output_iface, void *br_) { @@ -2578,7 +2582,7 @@ bridge_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet, } static void -bridge_account_flow_ofhook_cb(const flow_t *flow, tag_type tags, +bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags, const union odp_action *actions, size_t n_actions, unsigned long long int n_bytes, void *br_) @@ -2638,7 +2642,6 @@ bridge_account_checkpoint_ofhook_cb(void *br_) } static struct ofhooks bridge_ofhooks = { - bridge_port_changed_ofhook_cb, bridge_normal_ofhook_cb, bridge_account_flow_ofhook_cb, bridge_account_checkpoint_ofhook_cb, @@ -2960,7 +2963,7 @@ bond_send_learning_packets(struct port *port) union ofp_action actions[2], *a; uint16_t dp_ifidx; tag_type tags = 0; - flow_t flow; + struct flow flow; int retval; if (e->port == port->port_idx @@ -3527,6 +3530,7 @@ port_destroy(struct port *port) del = br->ports[port->port_idx] = br->ports[--br->n_ports]; del->port_idx = port->port_idx; + netdev_monitor_destroy(port->monitor); free(port->ifaces); bitmap_free(port->trunks); free(port->name); @@ -3558,6 +3562,10 @@ port_lookup_iface(const struct port *port, const char *name) static void port_update_bonding(struct port *port) { + if (port->monitor) { + netdev_monitor_destroy(port->monitor); + port->monitor = NULL; + } if (port->n_ifaces < 2) { /* Not a bonded port. */ if (port->bond_hash) { @@ -3567,9 +3575,9 @@ port_update_bonding(struct port *port) port->bond_fake_iface = false; } } else { - if (!port->bond_hash) { - size_t i; + size_t i; + if (!port->bond_hash) { port->bond_hash = xcalloc(BOND_MASK + 1, sizeof *port->bond_hash); for (i = 0; i <= BOND_MASK; i++) { struct bond_entry *e = &port->bond_hash[i]; @@ -3587,6 +3595,11 @@ port_update_bonding(struct port *port) } port->bond_compat_is_stale = true; port->bond_fake_iface = port->cfg->bond_fake_iface; + + port->monitor = netdev_monitor_create(); + for (i = 0; i < port->n_ifaces; i++) { + netdev_monitor_add(port->monitor, port->ifaces[i]->netdev); + } } }