X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=ofproto%2Fofproto-dpif.c;h=84f6abf26ecf813eb9163df1b4118b96d3cd2a09;hb=6fca1ffbff93d507336961602947b46320e0ef41;hp=68a87d595b615bd1a9b5a03b5c3d1d7db12555ad;hpb=be51a44695b8e2a3efd729524b2c08d32ed572db;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 68a87d59..84f6abf2 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -302,8 +302,8 @@ static void facet_account(struct ofproto_dpif *, struct facet *); static bool facet_is_controller_flow(struct facet *); -static void flow_push_stats(const struct rule_dpif *, - struct flow *, uint64_t packets, uint64_t bytes, +static void flow_push_stats(const struct rule_dpif *, const struct flow *, + uint64_t packets, uint64_t bytes, long long int used); static uint32_t rule_calculate_tag(const struct flow *, @@ -325,6 +325,18 @@ struct ofport_dpif { struct stp_port *stp_port; /* Spanning Tree Protocol, if any. */ enum stp_state stp_state; /* Always STP_DISABLED if STP not in use. */ long long int stp_state_entered; + + struct hmap priorities; /* Map of attached 'priority_to_dscp's. */ +}; + +/* Node in 'ofport_dpif''s 'priorities' map. Used to maintain a map from + * 'priority' (the datapath's term for QoS queue) to the dscp bits which all + * traffic egressing the 'ofport' with that priority should be marked with. */ +struct priority_to_dscp { + struct hmap_node hmap_node; /* Node in 'ofport_dpif''s 'priorities' map. */ + uint32_t priority; /* Priority of this queue (see struct flow). */ + + uint8_t dscp; /* DSCP bits to mark outgoing traffic with. */ }; static struct ofport_dpif * @@ -337,6 +349,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_settings *); +static void ofport_clear_priorities(struct ofport_dpif *); struct dpif_completion { struct list list_node; @@ -423,6 +436,9 @@ static void handle_miss_upcalls(struct ofproto_dpif *, /* Flow expiration. */ static int expire(struct ofproto_dpif *); +/* NetFlow. */ +static void send_netflow_active_timeouts(struct ofproto_dpif *); + /* Utilities. */ static int send_packet(struct ofproto_dpif *, uint32_t odp_port, const struct ofpbuf *packet); @@ -628,7 +644,9 @@ run(struct ofproto *ofproto_) } if (ofproto->netflow) { - netflow_run(ofproto->netflow); + if (netflow_run(ofproto->netflow)) { + send_netflow_active_timeouts(ofproto); + } } if (ofproto->sflow) { dpif_sflow_run(ofproto->sflow); @@ -691,6 +709,9 @@ wait(struct ofproto *ofproto_) HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { bundle_wait(bundle); } + if (ofproto->netflow) { + netflow_wait(ofproto->netflow); + } mac_learning_wait(ofproto->ml); stp_wait(ofproto); if (ofproto->need_revalidate) { @@ -754,24 +775,6 @@ get_tables(struct ofproto *ofproto_, struct ofp_table_stats *ots) htonll(s.n_hit + ofproto->n_matches)); } -static int -set_netflow(struct ofproto *ofproto_, - const struct netflow_options *netflow_options) -{ - struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - - if (netflow_options) { - if (!ofproto->netflow) { - ofproto->netflow = netflow_create(); - } - return netflow_set_options(ofproto->netflow, netflow_options); - } else { - netflow_destroy(ofproto->netflow); - ofproto->netflow = NULL; - return 0; - } -} - static struct ofport * port_alloc(void) { @@ -800,6 +803,7 @@ port_construct(struct ofport *port_) port->may_enable = true; port->stp_port = NULL; port->stp_state = STP_DISABLED; + hmap_init(&port->priorities); if (ofproto->sflow) { dpif_sflow_add_port(ofproto->sflow, port->odp_port, @@ -821,6 +825,9 @@ port_destruct(struct ofport *port_) if (ofproto->sflow) { dpif_sflow_del_port(ofproto->sflow, port->odp_port); } + + ofport_clear_priorities(port); + hmap_destroy(&port->priorities); } static void @@ -1172,6 +1179,82 @@ stp_process_packet(const struct ofport_dpif *ofport, } } +static struct priority_to_dscp * +get_priority(const struct ofport_dpif *ofport, uint32_t priority) +{ + struct priority_to_dscp *pdscp; + uint32_t hash; + + hash = hash_int(priority, 0); + HMAP_FOR_EACH_IN_BUCKET (pdscp, hmap_node, hash, &ofport->priorities) { + if (pdscp->priority == priority) { + return pdscp; + } + } + return NULL; +} + +static void +ofport_clear_priorities(struct ofport_dpif *ofport) +{ + struct priority_to_dscp *pdscp, *next; + + HMAP_FOR_EACH_SAFE (pdscp, next, hmap_node, &ofport->priorities) { + hmap_remove(&ofport->priorities, &pdscp->hmap_node); + free(pdscp); + } +} + +static int +set_queues(struct ofport *ofport_, + const struct ofproto_port_queue *qdscp_list, + size_t n_qdscp) +{ + struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto); + struct hmap new = HMAP_INITIALIZER(&new); + size_t i; + + for (i = 0; i < n_qdscp; i++) { + struct priority_to_dscp *pdscp; + uint32_t priority; + uint8_t dscp; + + dscp = (qdscp_list[i].dscp << 2) & IP_DSCP_MASK; + if (dpif_queue_to_priority(ofproto->dpif, qdscp_list[i].queue, + &priority)) { + continue; + } + + pdscp = get_priority(ofport, priority); + if (pdscp) { + hmap_remove(&ofport->priorities, &pdscp->hmap_node); + } else { + pdscp = xmalloc(sizeof *pdscp); + pdscp->priority = priority; + pdscp->dscp = dscp; + ofproto->need_revalidate = true; + } + + if (pdscp->dscp != dscp) { + pdscp->dscp = dscp; + ofproto->need_revalidate = true; + } + + hmap_insert(&new, &pdscp->hmap_node, hash_int(pdscp->priority, 0)); + } + + if (!hmap_is_empty(&ofport->priorities)) { + ofport_clear_priorities(ofport); + ofproto->need_revalidate = true; + } + + hmap_swap(&new, &ofport->priorities); + hmap_destroy(&new); + + return 0; +} + /* Bundles. */ /* Expires all MAC learning entries associated with 'port' and forces ofproto @@ -2605,29 +2688,6 @@ facet_max_idle(const struct ofproto_dpif *ofproto) return bucket * BUCKET_WIDTH; } -static void -facet_active_timeout(struct ofproto_dpif *ofproto, struct facet *facet) -{ - if (ofproto->netflow && !facet_is_controller_flow(facet) && - netflow_active_timeout_expired(ofproto->netflow, &facet->nf_flow)) { - struct ofexpired expired; - - if (facet->installed) { - struct dpif_flow_stats stats; - - facet_put__(ofproto, facet, facet->actions, facet->actions_len, - &stats); - facet_update_stats(ofproto, facet, &stats); - } - - expired.flow = facet->flow; - expired.packet_count = facet->packet_count; - expired.byte_count = facet->byte_count; - expired.used = facet->used; - netflow_expire(ofproto->netflow, &facet->nf_flow, &expired); - } -} - static void expire_facets(struct ofproto_dpif *ofproto, int dp_max_idle) { @@ -2635,7 +2695,6 @@ expire_facets(struct ofproto_dpif *ofproto, int dp_max_idle) struct facet *facet, *next_facet; HMAP_FOR_EACH_SAFE (facet, next_facet, hmap_node, &ofproto->facets) { - facet_active_timeout(ofproto, facet); if (facet->used < cutoff) { facet_remove(ofproto, facet); } @@ -3250,7 +3309,7 @@ push_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule) * 'rule''s actions. */ static void flow_push_stats(const struct rule_dpif *rule, - struct flow *flow, uint64_t packets, uint64_t bytes, + const struct flow *flow, uint64_t packets, uint64_t bytes, long long int used) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); @@ -3408,7 +3467,8 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes) } static int -rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) +rule_execute(struct rule *rule_, const struct flow *flow, + struct ofpbuf *packet) { struct rule_dpif *rule = rule_dpif_cast(rule_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); @@ -3654,27 +3714,26 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base, } static void -commit_vlan_action(struct action_xlate_ctx *ctx, ovs_be16 new_tci) +commit_vlan_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions) { - struct flow *base = &ctx->base_flow; - - if (base->vlan_tci == new_tci) { + if (base->vlan_tci == flow->vlan_tci) { return; } if (base->vlan_tci & htons(VLAN_CFI)) { - nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_POP_VLAN); + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN); } - if (new_tci & htons(VLAN_CFI)) { + if (flow->vlan_tci & htons(VLAN_CFI)) { struct ovs_action_push_vlan vlan; vlan.vlan_tpid = htons(ETH_TYPE_VLAN); - vlan.vlan_tci = new_tci; - nl_msg_put_unspec(ctx->odp_actions, OVS_ACTION_ATTR_PUSH_VLAN, + vlan.vlan_tci = flow->vlan_tci; + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN, &vlan, sizeof vlan); } - base->vlan_tci = new_tci; + base->vlan_tci = flow->vlan_tci; } static void @@ -3764,49 +3823,51 @@ commit_odp_actions(struct action_xlate_ctx *ctx) commit_set_tun_id_action(flow, base, odp_actions); commit_set_ether_addr_action(flow, base, odp_actions); - commit_vlan_action(ctx, flow->vlan_tci); + commit_vlan_action(flow, base, odp_actions); commit_set_nw_action(flow, base, odp_actions); commit_set_port_action(flow, base, odp_actions); commit_set_priority_action(flow, base, odp_actions); } static void -force_compose_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) +compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port, + bool check_stp) { const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port); uint16_t odp_port = ofp_port_to_odp_port(ofp_port); + uint8_t flow_nw_tos = ctx->flow.nw_tos; - if (ofport && ofport->up.opp.config & htonl(OFPPC_NO_FWD)) { - return; + if (ofport) { + struct priority_to_dscp *pdscp; + + if (ofport->up.opp.config & htonl(OFPPC_NO_FWD) + || (check_stp && !stp_forward_in_state(ofport->stp_state))) { + return; + } + + pdscp = get_priority(ofport, ctx->flow.priority); + if (pdscp) { + ctx->flow.nw_tos &= ~IP_DSCP_MASK; + ctx->flow.nw_tos |= pdscp->dscp; + } + } else { + /* We may not have an ofport record for this port, but it doesn't hurt + * to allow forwarding to it anyhow. Maybe such a port will appear + * later and we're pre-populating the flow table. */ } + commit_odp_actions(ctx); nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port); ctx->sflow_odp_port = odp_port; ctx->sflow_n_outputs++; + ctx->nf_output_iface = ofp_port; + ctx->flow.nw_tos = flow_nw_tos; } static void compose_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) { - struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port); - - if (ofport && !stp_forward_in_state(ofport->stp_state)) { - /* Forwarding disabled on port. */ - return; - } - - /* We may not have an ofport record for this port, but it doesn't hurt to - * allow forwarding to it anyhow. Maybe such a port will appear later and - * we're pre-populating the flow table. */ - force_compose_output_action(ctx, ofp_port); -} - -static void -commit_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) -{ - commit_odp_actions(ctx); - compose_output_action(ctx, ofp_port); - ctx->nf_output_iface = ofp_port; + compose_output_action__(ctx, ofp_port, true); } static void @@ -3891,7 +3952,7 @@ flood_packets(struct action_xlate_ctx *ctx, bool all) } if (all) { - force_compose_output_action(ctx, ofp_port); + compose_output_action__(ctx, ofp_port, false); } else if (!(ofport->up.opp.config & htonl(OFPPC_NO_FLOOD))) { compose_output_action(ctx, ofp_port); } @@ -3905,6 +3966,7 @@ compose_controller_action(struct action_xlate_ctx *ctx, int len) { struct user_action_cookie cookie; + commit_odp_actions(ctx); cookie.type = USER_ACTION_COOKIE_CONTROLLER; cookie.data = len; cookie.n_output = 0; @@ -3922,7 +3984,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx, switch (port) { case OFPP_IN_PORT: - commit_output_action(ctx, ctx->flow.in_port); + compose_output_action(ctx, ctx->flow.in_port); break; case OFPP_TABLE: xlate_table_action(ctx, ctx->flow.in_port, ctx->table_id); @@ -3937,17 +3999,16 @@ xlate_output_action__(struct action_xlate_ctx *ctx, flood_packets(ctx, true); break; case OFPP_CONTROLLER: - commit_odp_actions(ctx); compose_controller_action(ctx, max_len); break; case OFPP_LOCAL: - commit_output_action(ctx, OFPP_LOCAL); + compose_output_action(ctx, OFPP_LOCAL); break; case OFPP_NONE: break; default: if (port != ctx->flow.in_port) { - commit_output_action(ctx, port); + compose_output_action(ctx, port); } break; } @@ -4009,7 +4070,7 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx, /* Add datapath actions. */ flow_priority = ctx->flow.priority; ctx->flow.priority = priority; - commit_output_action(ctx, ofp_port); + compose_output_action(ctx, ofp_port); ctx->flow.priority = flow_priority; /* Update NetFlow output port. */ @@ -4495,7 +4556,7 @@ output_normal(struct action_xlate_ctx *ctx, const struct ofbundle *out_bundle, { struct ofport_dpif *port; uint16_t vid; - ovs_be16 tci; + ovs_be16 tci, old_tci; vid = output_vlan_to_vid(out_bundle, vlan); if (!out_bundle->bond) { @@ -4509,6 +4570,7 @@ output_normal(struct action_xlate_ctx *ctx, const struct ofbundle *out_bundle, } } + old_tci = ctx->flow.vlan_tci; tci = htons(vid); if (tci || out_bundle->use_priority_tags) { tci |= ctx->flow.vlan_tci & htons(VLAN_PCP_MASK); @@ -4516,10 +4578,10 @@ output_normal(struct action_xlate_ctx *ctx, const struct ofbundle *out_bundle, tci |= htons(VLAN_CFI); } } - commit_vlan_action(ctx, tci); + ctx->flow.vlan_tci = tci; compose_output_action(ctx, port->up.ofp_port); - ctx->nf_output_iface = port->up.ofp_port; + ctx->flow.vlan_tci = old_tci; } static int @@ -5043,6 +5105,26 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, } return error; } + +/* NetFlow. */ + +static int +set_netflow(struct ofproto *ofproto_, + const struct netflow_options *netflow_options) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + + if (netflow_options) { + if (!ofproto->netflow) { + ofproto->netflow = netflow_create(); + } + return netflow_set_options(ofproto->netflow, netflow_options); + } else { + netflow_destroy(ofproto->netflow); + ofproto->netflow = NULL; + return 0; + } +} static void get_netflow_ids(const struct ofproto *ofproto_, @@ -5052,6 +5134,39 @@ get_netflow_ids(const struct ofproto *ofproto_, dpif_get_netflow_ids(ofproto->dpif, engine_type, engine_id); } + +static void +send_active_timeout(struct ofproto_dpif *ofproto, struct facet *facet) +{ + if (!facet_is_controller_flow(facet) && + netflow_active_timeout_expired(ofproto->netflow, &facet->nf_flow)) { + struct ofexpired expired; + + if (facet->installed) { + struct dpif_flow_stats stats; + + facet_put__(ofproto, facet, facet->actions, facet->actions_len, + &stats); + facet_update_stats(ofproto, facet, &stats); + } + + expired.flow = facet->flow; + expired.packet_count = facet->packet_count; + expired.byte_count = facet->byte_count; + expired.used = facet->used; + netflow_expire(ofproto->netflow, &facet->nf_flow, &expired); + } +} + +static void +send_netflow_active_timeouts(struct ofproto_dpif *ofproto) +{ + struct facet *facet; + + HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) { + send_active_timeout(ofproto, facet); + } +} static struct ofproto_dpif * ofproto_dpif_lookup(const char *name) @@ -5386,6 +5501,7 @@ const struct ofproto_class ofproto_dpif_class = { get_stp_status, set_stp_port, get_stp_port_status, + set_queues, bundle_set, bundle_remove, mirror_set,