X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=c5fe2820dddeb6826200126867257e01f4f5df0a;hb=80e5eed9c2128f04a1d7da134120d96e961dbe10;hp=0e4f8cb5695819b1d47625172941d8f8409ceb90;hpb=56c769aba6f8a7dc21f88c577bc80841f538e8cc;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 0e4f8cb5..c5fe2820 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -266,6 +266,7 @@ static void facet_update_time(struct ofproto_dpif *, struct facet *, long long int used); static void facet_update_stats(struct ofproto_dpif *, struct facet *, const struct dpif_flow_stats *); +static void facet_reset_dp_stats(struct facet *, struct dpif_flow_stats *); static void facet_push_stats(struct facet *); static void facet_account(struct ofproto_dpif *, struct facet *, uint64_t extra_bytes); @@ -296,8 +297,7 @@ ofport_dpif_cast(const struct ofport *ofport) static void port_run(struct ofport_dpif *); static void port_wait(struct ofport_dpif *); -static int set_cfm(struct ofport *, const struct cfm *, - const uint16_t *remote_mps, size_t n_remote_mps); +static int set_cfm(struct ofport *, const struct cfm_settings *); struct ofproto_dpif { struct ofproto up; @@ -351,8 +351,7 @@ static void handle_upcall(struct ofproto_dpif *, struct dpif_upcall *); static int expire(struct ofproto_dpif *); /* Utilities. */ -static int send_packet(struct ofproto_dpif *, - uint32_t odp_port, uint16_t vlan_tci, +static int send_packet(struct ofproto_dpif *, uint32_t odp_port, const struct ofpbuf *packet); /* Global variables. */ @@ -682,7 +681,7 @@ port_destruct(struct ofport *port_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto); bundle_remove(port_); - set_cfm(port_, NULL, NULL, 0); + set_cfm(port_, NULL); if (ofproto->sflow) { ofproto_sflow_del_port(ofproto->sflow, port->odp_port); } @@ -736,26 +735,19 @@ set_sflow(struct ofproto *ofproto_, } static int -set_cfm(struct ofport *ofport_, const struct cfm *cfm, - const uint16_t *remote_mps, size_t n_remote_mps) +set_cfm(struct ofport *ofport_, const struct cfm_settings *s) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); int error; - if (!cfm) { + if (!s) { error = 0; } else { if (!ofport->cfm) { - ofport->cfm = cfm_create(); + ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev)); } - ofport->cfm->mpid = cfm->mpid; - ofport->cfm->interval = cfm->interval; - memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN); - - cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps); - - if (cfm_configure(ofport->cfm)) { + if (cfm_configure(ofport->cfm, s)) { return 0; } @@ -767,11 +759,11 @@ set_cfm(struct ofport *ofport_, const struct cfm *cfm, } static int -get_cfm(struct ofport *ofport_, const struct cfm **cfmp) +get_cfm_fault(const struct ofport *ofport_) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); - *cfmp = ofport->cfm; - return 0; + + return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1; } /* Bundles. */ @@ -830,6 +822,8 @@ bundle_del_port(struct ofport_dpif *port) { struct ofbundle *bundle = port->bundle; + bundle->ofproto->need_revalidate = true; + list_remove(&port->bundle_node); port->bundle = NULL; @@ -861,6 +855,7 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port, } if (port->bundle != bundle) { + bundle->ofproto->need_revalidate = true; if (port->bundle) { bundle_del_port(port); } @@ -1029,6 +1024,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, } } else { bundle->bond = bond_create(s->bond); + ofproto->need_revalidate = true; } LIST_FOR_EACH (port, bundle_node, &bundle->ports) { @@ -1138,7 +1134,11 @@ bundle_run(struct ofbundle *bundle) LIST_FOR_EACH (port, bundle_node, &bundle->ports) { bool may_enable = lacp_slave_may_enable(bundle->lacp, port); - bond_slave_set_lacp_may_enable(bundle->bond, port, may_enable); + + if (may_enable && port->cfm) { + may_enable = !cfm_get_fault(port->cfm); + } + bond_slave_set_may_enable(bundle->bond, port, may_enable); } bond_run(bundle->bond, &bundle->ofproto->revalidate_set, @@ -1380,14 +1380,11 @@ port_run(struct ofport_dpif *ofport) if (cfm_should_send_ccm(ofport->cfm)) { struct ofpbuf packet; - struct ccm *ccm; ofpbuf_init(&packet, 0); - ccm = eth_compose(&packet, eth_addr_ccm, ofport->up.opp.hw_addr, - ETH_TYPE_CFM, sizeof *ccm); - cfm_compose_ccm(ofport->cfm, ccm); + cfm_compose_ccm(ofport->cfm, &packet, ofport->up.opp.hw_addr); send_packet(ofproto_dpif_cast(ofport->up.ofproto), - ofport->odp_port, 0, &packet); + ofport->odp_port, &packet); ofpbuf_uninit(&packet); } } @@ -1548,19 +1545,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow, { if (cfm_should_process_flow(flow)) { struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port); - if (ofport && ofport->cfm) { + if (packet && ofport && ofport->cfm) { cfm_process_heartbeat(ofport->cfm, packet); } return true; } else if (flow->dl_type == htons(ETH_TYPE_LACP)) { struct ofport_dpif *port = get_ofp_port(ofproto, flow->in_port); - if (port && port->bundle && port->bundle->lacp) { + if (packet && port && port->bundle && port->bundle->lacp) { const struct lacp_pdu *pdu = parse_lacp_packet(packet); if (pdu) { lacp_process_pdu(port->bundle->lacp, port, pdu); } - return true; } + return true; } return false; } @@ -1587,7 +1584,7 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ if (connmgr_msg_in_hook(ofproto->up.connmgr, &flow, upcall->packet)) { - send_packet(ofproto, OFPP_LOCAL, 0, upcall->packet); + send_packet(ofproto, ODPP_LOCAL, upcall->packet); } facet = facet_lookup_valid(ofproto, &flow); @@ -2010,9 +2007,16 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, return true; } else { + struct odputil_keybuf keybuf; + struct ofpbuf key; int error; - error = dpif_execute(ofproto->dpif, odp_actions, actions_len, packet); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); + + error = dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions, actions_len, packet); + ofpbuf_delete(packet); return !error; } @@ -2088,6 +2092,12 @@ facet_make_actions(struct ofproto_dpif *p, struct facet *facet, ofpbuf_delete(odp_actions); } +/* Updates 'facet''s flow in the datapath setting its actions to 'actions_len' + * bytes of actions in 'actions'. If 'stats' is non-null, statistics counters + * in the datapath will be zeroed and 'stats' will be updated with traffic new + * since 'facet' was last updated. + * + * Returns 0 if successful, otherwise a positive errno value.*/ static int facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, const struct nlattr *actions, size_t actions_len, @@ -2096,19 +2106,24 @@ facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, struct odputil_keybuf keybuf; enum dpif_flow_put_flags flags; struct ofpbuf key; + int ret; flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; if (stats) { flags |= DPIF_FP_ZERO_STATS; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, - actions, actions_len, stats); + ret = dpif_flow_put(ofproto->dpif, flags, key.data, key.size, + actions, actions_len, stats); + + if (stats) { + facet_reset_dp_stats(facet, stats); + } + + return ret; } /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If @@ -2126,6 +2141,12 @@ facet_install(struct ofproto_dpif *p, struct facet *facet, bool zero_stats) } } +static int +vlan_tci_to_openflow_vlan(ovs_be16 vlan_tci) +{ + return vlan_tci != htons(0) ? vlan_tci_to_vid(vlan_tci) : OFP_VLAN_NONE; +} + static void facet_account(struct ofproto_dpif *ofproto, struct facet *facet, uint64_t extra_bytes) @@ -2135,6 +2156,7 @@ facet_account(struct ofproto_dpif *ofproto, const struct nlattr *a; tag_type dummy = 0; unsigned int left; + ovs_be16 vlan_tci; int vlan; total_bytes = facet->byte_count + extra_bytes; @@ -2162,14 +2184,32 @@ facet_account(struct ofproto_dpif *ofproto, if (!ofproto->has_bonded_bundles) { return; } + + /* This loop feeds byte counters to bond_account() for rebalancing to use + * as a basis. We also need to track the actual VLAN on which the packet + * is going to be sent to ensure that it matches the one passed to + * bond_choose_output_slave(). (Otherwise, we will account to the wrong + * hash bucket.) */ + vlan_tci = facet->flow.vlan_tci; NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->actions, facet->actions_len) { - if (nl_attr_type(a) == ODP_ACTION_ATTR_OUTPUT) { - struct ofport_dpif *port; + struct ofport_dpif *port; + switch (nl_attr_type(a)) { + case ODP_ACTION_ATTR_OUTPUT: port = get_odp_port(ofproto, nl_attr_get_u32(a)); if (port && port->bundle && port->bundle->bond) { - bond_account(port->bundle->bond, &facet->flow, vlan, n_bytes); + bond_account(port->bundle->bond, &facet->flow, + vlan_tci_to_openflow_vlan(vlan_tci), n_bytes); } + break; + + case ODP_ACTION_ATTR_STRIP_VLAN: + vlan_tci = htons(0); + break; + + case ODP_ACTION_ATTR_SET_DL_TCI: + vlan_tci = nl_attr_get_be16(a); + break; } } } @@ -2182,16 +2222,17 @@ facet_uninstall(struct ofproto_dpif *p, struct facet *facet) struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct ofpbuf key; + int error; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { + error = dpif_flow_del(p->dpif, key.data, key.size, &stats); + facet_reset_dp_stats(facet, &stats); + if (!error) { facet_update_stats(p, facet, &stats); } facet->installed = false; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } else { assert(facet->dp_packet_count == 0); assert(facet->dp_byte_count == 0); @@ -2210,6 +2251,24 @@ facet_is_controller_flow(struct facet *facet) htons(OFPP_CONTROLLER))); } +/* Resets 'facet''s datapath statistics counters. This should be called when + * 'facet''s statistics are cleared in the datapath. If 'stats' is non-null, + * it should contain the statistics returned by dpif when 'facet' was reset in + * the datapath. 'stats' will be modified to only included statistics new + * since 'facet' was last updated. */ +static void +facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats) +{ + if (stats && facet->dp_packet_count <= stats->n_packets + && facet->dp_byte_count <= stats->n_bytes) { + stats->n_packets -= facet->dp_packet_count; + stats->n_bytes -= facet->dp_byte_count; + } + + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; +} + /* Folds all of 'facet''s statistics into its rule. Also updates the * accounting ofhook and emits a NetFlow expiration if appropriate. All of * 'facet''s statistics in the datapath should have been zeroed and folded into @@ -2613,25 +2672,26 @@ rule_modify_actions(struct rule *rule_, return error; } -/* Sends 'packet' out of port 'odp_port' within 'ofproto'. If 'vlan_tci' is - * zero the packet will not have any 802.1Q hader; if it is nonzero, then the - * packet will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'. - * +/* Sends 'packet' out of port 'odp_port' within 'p'. * Returns 0 if successful, otherwise a positive errno value. */ static int -send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, uint16_t vlan_tci, +send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, const struct ofpbuf *packet) { - struct ofpbuf odp_actions; + struct ofpbuf key, odp_actions; + struct odputil_keybuf keybuf; + struct flow flow; int error; + flow_extract((struct ofpbuf *) packet, 0, 0, &flow); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &flow); + ofpbuf_init(&odp_actions, 32); - if (vlan_tci != 0) { - nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, - ntohs(vlan_tci & ~VLAN_CFI)); - } nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port); - error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size, + error = dpif_execute(ofproto->dpif, + key.data, key.size, + odp_actions.data, odp_actions.size, packet); ofpbuf_uninit(&odp_actions); @@ -3676,13 +3736,18 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, error = validate_actions(ofp_actions, n_ofp_actions, flow, ofproto->max_ports); if (!error) { + struct odputil_keybuf keybuf; struct action_xlate_ctx ctx; struct ofpbuf *odp_actions; + struct ofpbuf key; + + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); action_xlate_ctx_init(&ctx, ofproto, flow, packet); odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions); - dpif_execute(ofproto->dpif, odp_actions->data, odp_actions->size, - packet); + dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions->data, odp_actions->size, packet); ofpbuf_delete(odp_actions); } return error; @@ -3912,6 +3977,7 @@ const struct ofproto_class ofproto_dpif_class = { port_poll, port_poll_wait, port_is_lacp_current, + NULL, /* rule_choose_table */ rule_alloc, rule_construct, rule_destruct, @@ -3926,7 +3992,7 @@ const struct ofproto_class ofproto_dpif_class = { get_netflow_ids, set_sflow, set_cfm, - get_cfm, + get_cfm_fault, bundle_set, bundle_remove, mirror_set,