- COVERAGE_INC(ofproto_update_port);
-
- /* Query the datapath for port information. */
- error = dpif_port_query_by_name(p->dpif, devname, &dpif_port);
-
- /* Find the old ofport. */
- old_ofport = shash_find_data(&p->port_by_name, devname);
- if (!error) {
- if (!old_ofport) {
- /* There's no port named 'devname' but there might be a port with
- * the same port number. This could happen if a port is deleted
- * and then a new one added in its place very quickly, or if a port
- * is renamed. In the former case we want to send an OFPPR_DELETE
- * and an OFPPR_ADD, and in the latter case we want to send a
- * single OFPPR_MODIFY. We can distinguish the cases by comparing
- * the old port's ifindex against the new port, or perhaps less
- * reliably but more portably by comparing the old port's MAC
- * against the new port's MAC. However, this code isn't that smart
- * and always sends an OFPPR_MODIFY (XXX). */
- old_ofport = get_port(p, dpif_port.port_no);
- }
- } else if (error != ENOENT && error != ENODEV) {
- VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
- "%s", strerror(error));
- goto exit;
- }
-
- /* Create a new ofport. */
- new_ofport = !error ? make_ofport(&dpif_port) : NULL;
-
- /* Eliminate a few pathological cases. */
- if (!old_ofport && !new_ofport) {
- goto exit;
- } else if (old_ofport && new_ofport) {
- /* Most of the 'config' bits are OpenFlow soft state, but
- * OFPPC_PORT_DOWN is maintained by the kernel. So transfer the
- * OpenFlow bits from old_ofport. (make_ofport() only sets
- * OFPPC_PORT_DOWN and leaves the other bits 0.) */
- new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
-
- if (ofport_equal(old_ofport, new_ofport)) {
- /* False alarm--no change. */
- ofport_free(new_ofport);
- goto exit;
- }
- }
-
- /* Now deal with the normal cases. */
- if (old_ofport) {
- ofport_remove(p, old_ofport);
- }
- if (new_ofport) {
- ofport_install(p, new_ofport);
- }
- connmgr_send_port_status(p->connmgr,
- new_ofport ? &new_ofport->opp : &old_ofport->opp,
- (!old_ofport ? OFPPR_ADD
- : !new_ofport ? OFPPR_DELETE
- : OFPPR_MODIFY));
- ofport_free(old_ofport);
-
-exit:
- dpif_port_destroy(&dpif_port);
-}
-
-static int
-init_ports(struct ofproto *p)
-{
- struct dpif_port_dump dump;
- struct dpif_port dpif_port;
-
- DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) {
- if (!ofport_conflicts(p, &dpif_port)) {
- struct ofport *ofport = make_ofport(&dpif_port);
- if (ofport) {
- ofport_install(p, ofport);
- }
- }
- }
-
- return 0;
-}
-\f
-/* Returns true if 'rule' should be hidden from the controller.
- *
- * Rules with priority higher than UINT16_MAX are set up by ofproto itself
- * (e.g. by in-band control) and are intentionally hidden from the
- * controller. */
-static bool
-rule_is_hidden(const struct rule *rule)
-{
- return rule->cr.priority > UINT16_MAX;
-}
-
-/* Creates and returns a new rule initialized as specified.
- *
- * The caller is responsible for inserting the rule into the classifier (with
- * rule_insert()). */
-static struct rule *
-rule_create(const struct cls_rule *cls_rule,
- 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->cr = *cls_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;
- list_init(&rule->facets);
- if (n_actions > 0) {
- rule->n_actions = n_actions;
- rule->actions = xmemdup(actions, n_actions * sizeof *actions);
- }
-
- 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);
-}
-
-/* Destroys 'rule' and iterates through all of its facets and revalidates them,
- * destroying any that no longer has a rule (which is probably all of them).
- *
- * The caller must have already removed 'rule' from the classifier. */
-static void
-rule_destroy(struct ofproto *ofproto, struct rule *rule)
-{
- struct facet *facet, *next_facet;
- LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) {
- facet_revalidate(ofproto, facet);
- }
- rule_free(rule);
-}
-
-/* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
- * that outputs to 'out_port' (output to OFPP_FLOOD and OFPP_ALL doesn't
- * count). */
-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, const struct flow *flow,
- const struct nlattr *odp_actions, size_t actions_len,
- struct ofpbuf *packet)
-{
- if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t))
- && odp_actions->nla_type == ODP_ACTION_ATTR_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 dpif_upcall upcall;
-
- upcall.type = DPIF_UC_ACTION;
- upcall.packet = packet;
- upcall.key = NULL;
- upcall.key_len = 0;
- upcall.userdata = nl_attr_get_u64(odp_actions);
- upcall.sample_pool = 0;
- upcall.actions = NULL;
- upcall.actions_len = 0;
-
- send_packet_in(ofproto, &upcall, flow, false);
-
- return true;
- } else {
- int error;
-
- error = dpif_execute(ofproto->dpif, odp_actions, actions_len, packet);
- ofpbuf_delete(packet);
- return !error;
- }
-}
-
-/* Executes the actions indicated by 'facet' on 'packet' and credits 'facet''s
- * statistics appropriately. 'packet' must have at least sizeof(struct
- * ofp_packet_in) bytes of headroom.
- *
- * For correct results, 'packet' must actually be in 'facet''s flow; that is,
- * applying flow_extract() to 'packet' would yield the same flow as
- * 'facet->flow'.
- *
- * 'facet' must have accurately composed ODP actions; that is, it must not be
- * in need of revalidation.
- *
- * Takes ownership of 'packet'. */
-static void
-facet_execute(struct ofproto *ofproto, struct facet *facet,
- struct ofpbuf *packet)
-{
- struct dpif_flow_stats stats;
-
- assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
-
- flow_extract_stats(&facet->flow, packet, &stats);
- stats.used = time_msec();
- if (execute_odp_actions(ofproto, &facet->flow,
- facet->actions, facet->actions_len, packet)) {
- facet_update_stats(ofproto, facet, &stats);
- }
-}
-
-/* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s
- * statistics (or the statistics for one of its facets) appropriately.
- * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of headroom.
- *
- * 'packet' doesn't necessarily have to match 'rule'. 'rule' will be credited
- * with statistics for 'packet' either way.
- *
- * Takes ownership of 'packet'. */
-static void
-rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port,
- struct ofpbuf *packet)
-{
- struct action_xlate_ctx ctx;
- struct ofpbuf *odp_actions;
- struct facet *facet;
- struct flow flow;
- size_t size;
-
- assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
-
- flow_extract(packet, 0, in_port, &flow);
-
- /* First look for a related facet. If we find one, account it to that. */
- facet = facet_lookup_valid(ofproto, &flow);
- if (facet && facet->rule == rule) {
- facet_execute(ofproto, facet, packet);
- return;
- }
-
- /* Otherwise, if 'rule' is in fact the correct rule for 'packet', then
- * create a new facet for it and use that. */
- if (rule_lookup(ofproto, &flow) == rule) {
- facet = facet_create(ofproto, rule, &flow, packet);
- facet_execute(ofproto, facet, packet);
- facet_install(ofproto, facet, true);
- return;
- }
-
- /* We can't account anything to a facet. If we were to try, then that
- * facet would have a non-matching rule, busting our invariants. */
- action_xlate_ctx_init(&ctx, ofproto, &flow, packet);
- odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions);
- size = packet->size;
- if (execute_odp_actions(ofproto, &flow, odp_actions->data,
- odp_actions->size, packet)) {
- rule->used = time_msec();
- rule->packet_count++;
- rule->byte_count += size;
- flow_push_stats(ofproto, rule, &flow, 1, size, rule->used);
- }
- ofpbuf_delete(odp_actions);
-}
-
-/* Inserts 'rule' into 'p''s flow table. */
-static void
-rule_insert(struct ofproto *p, struct rule *rule)
-{
- struct rule *displaced_rule;
-
- displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
- if (displaced_rule) {
- rule_destroy(p, displaced_rule);
- }
- p->need_revalidate = true;
-}
-
-/* Creates and returns a new facet within 'ofproto' owned by 'rule', given a
- * 'flow' and an example 'packet' within that flow.
- *
- * The caller must already have determined that no facet with an identical
- * 'flow' exists in 'ofproto' and that 'flow' is the best match for 'rule' in
- * 'ofproto''s classifier table. */
-static struct facet *
-facet_create(struct ofproto *ofproto, struct rule *rule,
- const struct flow *flow, const struct ofpbuf *packet)
-{
- struct facet *facet;
-
- facet = xzalloc(sizeof *facet);
- facet->used = time_msec();
- hmap_insert(&ofproto->facets, &facet->hmap_node, flow_hash(flow, 0));
- list_push_back(&rule->facets, &facet->list_node);
- facet->rule = rule;
- facet->flow = *flow;
- netflow_flow_init(&facet->nf_flow);
- netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used);
-
- facet_make_actions(ofproto, facet, packet);
-
- return facet;
-}
-
-static void
-facet_free(struct facet *facet)
-{
- free(facet->actions);
- free(facet);
-}
-
-/* Remove 'rule' from 'ofproto' and free up the associated memory:
- *
- * - Removes 'rule' from the classifier.
- *
- * - If 'rule' has facets, revalidates them (and possibly uninstalls and
- * destroys them), via rule_destroy().
- */
-static void
-rule_remove(struct ofproto *ofproto, struct rule *rule)
-{
- COVERAGE_INC(ofproto_del_rule);
- ofproto->need_revalidate = true;
- classifier_remove(&ofproto->cls, &rule->cr);
- rule_destroy(ofproto, rule);
-}
-
-/* Remove 'facet' from 'ofproto' and free up the associated memory:
- *
- * - If 'facet' was installed in the datapath, uninstalls it and updates its
- * rule's statistics, via facet_uninstall().
- *
- * - Removes 'facet' from its rule and from ofproto->facets.
- */
-static void
-facet_remove(struct ofproto *ofproto, struct facet *facet)
-{
- facet_uninstall(ofproto, facet);
- facet_flush_stats(ofproto, facet);
- hmap_remove(&ofproto->facets, &facet->hmap_node);
- list_remove(&facet->list_node);
- facet_free(facet);
-}
-
-/* Composes the ODP actions for 'facet' based on its rule's actions. */
-static void
-facet_make_actions(struct ofproto *p, struct facet *facet,
- const struct ofpbuf *packet)
-{
- const struct rule *rule = facet->rule;
- struct ofpbuf *odp_actions;
- struct action_xlate_ctx ctx;
-
- action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
- odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions);
- facet->tags = ctx.tags;
- facet->may_install = ctx.may_set_up_flow;
- facet->nf_flow.output_iface = ctx.nf_output_iface;
-
- if (facet->actions_len != odp_actions->size
- || memcmp(facet->actions, odp_actions->data, odp_actions->size)) {
- free(facet->actions);
- facet->actions_len = odp_actions->size;
- facet->actions = xmemdup(odp_actions->data, odp_actions->size);
- }
-
- ofpbuf_delete(odp_actions);
-}
-
-static int
-facet_put__(struct ofproto *ofproto, struct facet *facet,
- const struct nlattr *actions, size_t actions_len,
- struct dpif_flow_stats *stats)
-{
- struct odputil_keybuf keybuf;
- enum dpif_flow_put_flags flags;
- struct ofpbuf key;
-
- 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);
- assert(key.base == &keybuf);
-
- return dpif_flow_put(ofproto->dpif, flags, key.data, key.size,
- actions, actions_len, stats);
-}
-
-/* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If
- * 'zero_stats' is true, clears any existing statistics from the datapath for
- * 'facet'. */
-static void
-facet_install(struct ofproto *p, struct facet *facet, bool zero_stats)
-{
- struct dpif_flow_stats stats;
-
- if (facet->may_install
- && !facet_put__(p, facet, facet->actions, facet->actions_len,
- zero_stats ? &stats : NULL)) {
- facet->installed = true;
- }
-}
-
-/* Ensures that the bytes in 'facet', plus 'extra_bytes', have been passed up
- * to the accounting hook function in the ofhooks structure. */
-static void
-facet_account(struct ofproto *ofproto,
- struct facet *facet, uint64_t extra_bytes)
-{
- uint64_t total_bytes = facet->byte_count + extra_bytes;
-
- if (ofproto->ofhooks->account_flow_cb
- && total_bytes > facet->accounted_bytes)
- {
- ofproto->ofhooks->account_flow_cb(
- &facet->flow, facet->tags, facet->actions, facet->actions_len,
- total_bytes - facet->accounted_bytes, ofproto->aux);
- facet->accounted_bytes = total_bytes;