- const union odp_action *actions;
- struct odp_flow_stats stats;
- size_t n_actions;
- struct odp_actions a;
-
- assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
-
- /* Grab or compose the ODP actions.
- *
- * The special case for an exact-match 'rule' where 'flow' is not the
- * rule's flow is important to avoid, e.g., sending a packet out its input
- * port simply because the ODP actions were composed for the wrong
- * scenario. */
- if (rule->cr.wc.wildcards || !flow_equal(flow, &rule->cr.flow)) {
- struct rule *super = rule->super ? rule->super : rule;
- if (xlate_actions(super->actions, super->n_actions, flow, ofproto,
- packet, &a, NULL, 0, NULL)) {
- ofpbuf_delete(packet);
- return;
- }
- actions = a.actions;
- n_actions = a.n_actions;
- } else {
- actions = rule->odp_actions;
- n_actions = rule->n_odp_actions;
- }
-
- /* Execute the ODP actions. */
- flow_extract_stats(flow, packet, &stats);
- if (execute_odp_actions(ofproto, flow->in_port,
- actions, n_actions, packet)) {
- update_stats(ofproto, rule, &stats);
- rule->used = time_msec();
- netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->used);
- }
-}
-
-/* Inserts 'rule' into 'p''s flow table.
- *
- * If 'packet' is nonnull, takes ownership of 'packet', executes 'rule''s
- * actions on it and credits the statistics for sending the packet to 'rule'.
- * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of
- * headroom. */
-static void
-rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet,
- uint16_t in_port)
-{
- struct rule *displaced_rule;
-
- /* Insert the rule in the classifier. */
- displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
- if (!rule->cr.wc.wildcards) {
- rule_make_actions(p, rule, packet);
- }
-
- /* Send the packet and credit it to the rule. */
- if (packet) {
- struct flow flow;
- flow_extract(packet, 0, in_port, &flow);
- rule_execute(p, rule, packet, &flow);
- }
-
- /* Install the rule in the datapath only after sending the packet, to
- * avoid packet reordering. */
- if (rule->cr.wc.wildcards) {
- COVERAGE_INC(ofproto_add_wc_flow);
- p->need_revalidate = true;
- } else {
- rule_install(p, rule, displaced_rule);
- }
-
- /* Free the rule that was displaced, if any. */
- if (displaced_rule) {
- rule_destroy(p, displaced_rule);
- }
-}
-
-static struct rule *
-rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
- const struct flow *flow)
-{
- struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
- rule->idle_timeout, rule->hard_timeout,
- 0, false);
- COVERAGE_INC(ofproto_subrule_create);
- cls_rule_init_exact(flow, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
- : rule->cr.priority),
- &subrule->cr);
-
- if (classifier_insert(&ofproto->cls, &subrule->cr)) {
- /* Can't happen, */
- NOT_REACHED();
- }
-
- return subrule;
-}
-
-/* Remove 'rule' from 'ofproto' and free up the associated memory:
- *
- * - If 'rule' was installed in the datapath, uninstalls it and updates
- * 'rule''s statistics (or its super-rule's statistics, if it is a
- * subrule), via rule_uninstall().
- *
- * - Removes 'rule' from the classifier.
- *
- * - If 'rule' is a super-rule that has subrules, revalidates (and possibly
- * uninstalls and destroys) its subrules, via rule_destroy().
- */
-static void
-rule_remove(struct ofproto *ofproto, struct rule *rule)
-{
- if (rule->cr.wc.wildcards) {
- COVERAGE_INC(ofproto_del_wc_flow);
- ofproto->need_revalidate = true;
- } else {
- rule_uninstall(ofproto, rule);
- }
- classifier_remove(&ofproto->cls, &rule->cr);
- rule_destroy(ofproto, rule);
-}
-
-/* Returns true if the actions changed, false otherwise. */
-static bool
-rule_make_actions(struct ofproto *p, struct rule *rule,
- const struct ofpbuf *packet)
-{
- const struct rule *super;
- struct odp_actions a;
- size_t actions_len;
-
- assert(!rule->cr.wc.wildcards);
-
- super = rule->super ? rule->super : rule;
- rule->tags = 0;
- xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p,
- packet, &a, &rule->tags, &rule->may_install,
- &rule->nf_flow.output_iface);
-
- actions_len = a.n_actions * sizeof *a.actions;
- if (rule->n_odp_actions != a.n_actions
- || memcmp(rule->odp_actions, a.actions, actions_len)) {
- COVERAGE_INC(ofproto_odp_unchanged);
- free(rule->odp_actions);
- rule->n_odp_actions = a.n_actions;
- rule->odp_actions = xmemdup(a.actions, actions_len);
- return true;
- } else {
- return false;
- }
-}
-
-static int
-do_put_flow(struct ofproto *ofproto, struct rule *rule, int flags,
- struct odp_flow_put *put)
-{
- memset(&put->flow.stats, 0, sizeof put->flow.stats);
- odp_flow_key_from_flow(&put->flow.key, &rule->cr.flow);
- put->flow.actions = rule->odp_actions;
- put->flow.n_actions = rule->n_odp_actions;
- put->flow.flags = 0;
- put->flags = flags;
- return dpif_flow_put(ofproto->dpif, put);
-}
-
-static void
-rule_install(struct ofproto *p, struct rule *rule, struct rule *displaced_rule)
-{
- assert(!rule->cr.wc.wildcards);
-
- if (rule->may_install) {
- struct odp_flow_put put;
- if (!do_put_flow(p, rule,
- ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS,
- &put)) {
- rule->installed = true;
- if (displaced_rule) {
- update_stats(p, displaced_rule, &put.flow.stats);
- rule_post_uninstall(p, displaced_rule);
- }
- }
- } else if (displaced_rule) {
- rule_uninstall(p, displaced_rule);
- }
-}
-
-static void
-rule_reinstall(struct ofproto *ofproto, struct rule *rule)
-{
- if (rule->installed) {
- struct odp_flow_put put;
- COVERAGE_INC(ofproto_dp_missed);
- do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY, &put);
- } else {
- rule_install(ofproto, rule, NULL);
- }
-}
-
-static void
-rule_update_actions(struct ofproto *ofproto, struct rule *rule)
-{
- bool actions_changed;
- uint16_t new_out_iface, old_out_iface;
-
- old_out_iface = rule->nf_flow.output_iface;
- actions_changed = rule_make_actions(ofproto, rule, NULL);
-
- if (rule->may_install) {
- if (rule->installed) {
- if (actions_changed) {
- struct odp_flow_put put;
- do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY
- | ODPPF_ZERO_STATS, &put);
- update_stats(ofproto, rule, &put.flow.stats);
-
- /* Temporarily set the old output iface so that NetFlow
- * messages have the correct output interface for the old
- * stats. */
- new_out_iface = rule->nf_flow.output_iface;
- rule->nf_flow.output_iface = old_out_iface;
- rule_post_uninstall(ofproto, rule);
- rule->nf_flow.output_iface = new_out_iface;
- }
- } else {
- rule_install(ofproto, rule, NULL);
- }
- } else {
- rule_uninstall(ofproto, rule);
- }
-}
-
-static void
-rule_account(struct ofproto *ofproto, struct rule *rule, uint64_t extra_bytes)
-{
- uint64_t total_bytes = rule->byte_count + extra_bytes;
-
- if (ofproto->ofhooks->account_flow_cb
- && total_bytes > rule->accounted_bytes)
- {
- ofproto->ofhooks->account_flow_cb(
- &rule->cr.flow, rule->tags, rule->odp_actions, rule->n_odp_actions,
- total_bytes - rule->accounted_bytes, ofproto->aux);
- rule->accounted_bytes = total_bytes;
- }
-}
-
-/* 'rule' must be an exact-match rule in 'p'.
- *
- * If 'rule' is installed in the datapath, uninstalls it and updates's
- * statistics. If 'rule' is a subrule, the statistics that are updated are
- * actually its super-rule's statistics; otherwise 'rule''s own statistics are
- * updated.
- *
- * If 'rule' is not installed, this function has no effect. */
-static void
-rule_uninstall(struct ofproto *p, struct rule *rule)
-{
- assert(!rule->cr.wc.wildcards);
- if (rule->installed) {
- struct odp_flow odp_flow;
-
- odp_flow_key_from_flow(&odp_flow.key, &rule->cr.flow);
- odp_flow.actions = NULL;
- odp_flow.n_actions = 0;
- odp_flow.flags = 0;
- if (!dpif_flow_del(p->dpif, &odp_flow)) {
- update_stats(p, rule, &odp_flow.stats);
- }
- rule->installed = false;
-
- rule_post_uninstall(p, rule);
- }
-}
-
-static bool
-is_controller_rule(struct rule *rule)
-{
- /* If the only action is send to the controller then don't report
- * NetFlow expiration messages since it is just part of the control
- * logic for the network and not real traffic. */
-
- return (rule
- && rule->super
- && rule->super->n_actions == 1
- && action_outputs_to_port(&rule->super->actions[0],
- htons(OFPP_CONTROLLER)));
-}
-
-static void
-rule_post_uninstall(struct ofproto *ofproto, struct rule *rule)
-{
- struct rule *super = rule->super;
-
- rule_account(ofproto, rule, 0);
-
- if (ofproto->netflow && !is_controller_rule(rule)) {
- struct ofexpired expired;
- expired.flow = rule->cr.flow;
- expired.packet_count = rule->packet_count;
- expired.byte_count = rule->byte_count;
- expired.used = rule->used;
- netflow_expire(ofproto->netflow, &rule->nf_flow, &expired);
- }
- if (super) {
- super->packet_count += rule->packet_count;
- super->byte_count += rule->byte_count;
-
- /* Reset counters to prevent double counting if the rule ever gets
- * reinstalled. */
- rule->packet_count = 0;
- rule->byte_count = 0;
- rule->accounted_bytes = 0;
-
- netflow_flow_clear(&rule->nf_flow);
- }
-}
-\f
-static void
-queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
- struct rconn_packet_counter *counter)
-{
- update_openflow_length(msg);
- if (rconn_send(ofconn->rconn, msg, counter)) {
- ofpbuf_delete(msg);
- }
-}
-
-static void
-send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
- int error)
-{
- struct ofpbuf *buf = make_ofp_error_msg(error, oh);
- if (buf) {
- COVERAGE_INC(ofproto_error);
- queue_tx(buf, ofconn, ofconn->reply_counter);
- }
-}
-
-static void
-hton_ofp_phy_port(struct ofp_phy_port *opp)
-{
- opp->port_no = htons(opp->port_no);
- opp->config = htonl(opp->config);
- opp->state = htonl(opp->state);
- opp->curr = htonl(opp->curr);
- opp->advertised = htonl(opp->advertised);
- opp->supported = htonl(opp->supported);
- opp->peer = htonl(opp->peer);
-}
-
-static int
-handle_echo_request(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofp_header *rq = oh;
- queue_tx(make_echo_reply(rq), ofconn, ofconn->reply_counter);
- return 0;