-\f
-/* Caller is responsible for initializing the 'cr' member of the returned
- * rule. */
-static struct rule *
-rule_create(struct ofproto *ofproto, struct rule *super,
- const union ofp_action *actions, size_t n_actions,
- uint16_t idle_timeout, uint16_t hard_timeout,
- ovs_be64 flow_cookie, bool send_flow_removed)
-{
- struct rule *rule = xzalloc(sizeof *rule);
- rule->idle_timeout = idle_timeout;
- rule->hard_timeout = hard_timeout;
- rule->flow_cookie = flow_cookie;
- rule->used = rule->created = time_msec();
- rule->send_flow_removed = send_flow_removed;
- rule->super = super;
- if (super) {
- list_push_back(&super->list, &rule->list);
- } else {
- list_init(&rule->list);
- }
- if (n_actions > 0) {
- rule->n_actions = n_actions;
- rule->actions = xmemdup(actions, n_actions * sizeof *actions);
- }
- netflow_flow_clear(&rule->nf_flow);
- netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->created);
-
- return rule;
-}
-
-static struct rule *
-rule_from_cls_rule(const struct cls_rule *cls_rule)
-{
- return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
-}
-
-static void
-rule_free(struct rule *rule)
-{
- free(rule->actions);
- free(rule->odp_actions);
- free(rule);
-}
-
-/* Destroys 'rule'. If 'rule' is a subrule, also removes it from its
- * super-rule's list of subrules. If 'rule' is a super-rule, also iterates
- * through all of its subrules and revalidates them, destroying any that no
- * longer has a super-rule (which is probably all of them).
- *
- * Before calling this function, the caller must make have removed 'rule' from
- * the classifier. If 'rule' is an exact-match rule, the caller is also
- * responsible for ensuring that it has been uninstalled from the datapath. */
-static void
-rule_destroy(struct ofproto *ofproto, struct rule *rule)
-{
- if (!rule->super) {
- struct rule *subrule, *next;
- LIST_FOR_EACH_SAFE (subrule, next, list, &rule->list) {
- revalidate_rule(ofproto, subrule);
- }
- } else {
- list_remove(&rule->list);
- }
- rule_free(rule);
-}
-
-static bool
-rule_has_out_port(const struct rule *rule, ovs_be16 out_port)
-{
- const union ofp_action *oa;
- struct actions_iterator i;
-
- if (out_port == htons(OFPP_NONE)) {
- return true;
- }
- for (oa = actions_first(&i, rule->actions, rule->n_actions); oa;
- oa = actions_next(&i)) {
- if (action_outputs_to_port(oa, out_port)) {
- return true;
- }
- }
- return false;
-}
-
-/* Executes, within 'ofproto', the 'n_actions' actions in 'actions' on
- * 'packet', which arrived on 'in_port'.
- *
- * Takes ownership of 'packet'. */
-static bool
-execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
- const union odp_action *actions, size_t n_actions,
- struct ofpbuf *packet)
-{
- if (n_actions == 1 && actions[0].type == ODPAT_CONTROLLER) {
- /* As an optimization, avoid a round-trip from userspace to kernel to
- * userspace. This also avoids possibly filling up kernel packet
- * buffers along the way. */
- struct odp_msg *msg;
-
- msg = ofpbuf_push_uninit(packet, sizeof *msg);
- msg->type = _ODPL_ACTION_NR;
- msg->length = sizeof(struct odp_msg) + packet->size;
- msg->port = in_port;
- msg->reserved = 0;
- msg->arg = actions[0].controller.arg;
-
- send_packet_in(ofproto, packet);
-
- return true;
- } else {
- int error;
-
- error = dpif_execute(ofproto->dpif, actions, n_actions, packet);
- ofpbuf_delete(packet);
- return !error;
- }
-}
-
-/* Executes the actions indicated by 'rule' on 'packet', which is in flow
- * 'flow' and is considered to have arrived on ODP port 'in_port'. 'packet'
- * must have at least sizeof(struct ofp_packet_in) bytes of headroom.
- *
- * The flow that 'packet' actually contains does not need to actually match
- * 'rule'; the actions in 'rule' will be applied to it either way. Likewise,
- * the packet and byte counters for 'rule' will be credited for the packet sent
- * out whether or not the packet actually matches 'rule'.
- *
- * If 'rule' is an exact-match rule and 'flow' actually equals the rule's flow,
- * the caller must already have accurately composed ODP actions for it given
- * 'packet' using rule_make_actions(). If 'rule' is a wildcard rule, or if
- * 'rule' is an exact-match rule but 'flow' is not the rule's flow, then this
- * function will compose a set of ODP actions based on 'rule''s OpenFlow
- * actions and apply them to 'packet'.
- *
- * Takes ownership of 'packet'. */
-static void
-rule_execute(struct ofproto *ofproto, struct rule *rule,
- struct ofpbuf *packet, const struct flow *flow)
-{
- 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);
- }
-}