+static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port);
+
+static struct xbridge *xbridge_lookup(const struct ofproto_dpif *);
+static struct xbundle *xbundle_lookup(const struct ofbundle *);
+static struct xport *xport_lookup(const struct ofport_dpif *);
+static struct xport *get_ofp_port(const struct xbridge *, ofp_port_t ofp_port);
+static struct skb_priority_to_dscp *get_skb_priority(const struct xport *,
+ uint32_t skb_priority);
+static void clear_skb_priorities(struct xport *);
+static bool dscp_from_skb_priority(const struct xport *, uint32_t skb_priority,
+ uint8_t *dscp);
+
+static struct xc_entry *xlate_cache_add_entry(struct xlate_cache *xc,
+ enum xc_type type);
+
+void
+xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
+ struct dpif *dpif, struct rule_dpif *miss_rule,
+ struct rule_dpif *no_packet_in_rule,
+ const struct mac_learning *ml, struct stp *stp,
+ const struct mbridge *mbridge,
+ const struct dpif_sflow *sflow,
+ const struct dpif_ipfix *ipfix,
+ const struct netflow *netflow, enum ofp_config_flags frag,
+ bool forward_bpdu, bool has_in_band,
+ bool enable_recirc,
+ bool variable_length_userdata,
+ size_t max_mpls_depth)
+{
+ struct xbridge *xbridge = xbridge_lookup(ofproto);
+
+ if (!xbridge) {
+ xbridge = xzalloc(sizeof *xbridge);
+ xbridge->ofproto = ofproto;
+
+ hmap_insert(&xbridges, &xbridge->hmap_node, hash_pointer(ofproto, 0));
+ hmap_init(&xbridge->xports);
+ list_init(&xbridge->xbundles);
+ }
+
+ if (xbridge->ml != ml) {
+ mac_learning_unref(xbridge->ml);
+ xbridge->ml = mac_learning_ref(ml);
+ }
+
+ if (xbridge->mbridge != mbridge) {
+ mbridge_unref(xbridge->mbridge);
+ xbridge->mbridge = mbridge_ref(mbridge);
+ }
+
+ if (xbridge->sflow != sflow) {
+ dpif_sflow_unref(xbridge->sflow);
+ xbridge->sflow = dpif_sflow_ref(sflow);
+ }
+
+ if (xbridge->ipfix != ipfix) {
+ dpif_ipfix_unref(xbridge->ipfix);
+ xbridge->ipfix = dpif_ipfix_ref(ipfix);
+ }
+
+ if (xbridge->stp != stp) {
+ stp_unref(xbridge->stp);
+ xbridge->stp = stp_ref(stp);
+ }
+
+ if (xbridge->netflow != netflow) {
+ netflow_unref(xbridge->netflow);
+ xbridge->netflow = netflow_ref(netflow);
+ }
+
+ free(xbridge->name);
+ xbridge->name = xstrdup(name);
+
+ xbridge->dpif = dpif;
+ xbridge->forward_bpdu = forward_bpdu;
+ xbridge->has_in_band = has_in_band;
+ xbridge->frag = frag;
+ xbridge->miss_rule = miss_rule;
+ xbridge->no_packet_in_rule = no_packet_in_rule;
+ xbridge->enable_recirc = enable_recirc;
+ xbridge->variable_length_userdata = variable_length_userdata;
+ xbridge->max_mpls_depth = max_mpls_depth;
+}
+
+void
+xlate_remove_ofproto(struct ofproto_dpif *ofproto)
+{
+ struct xbridge *xbridge = xbridge_lookup(ofproto);
+ struct xbundle *xbundle, *next_xbundle;
+ struct xport *xport, *next_xport;
+
+ if (!xbridge) {
+ return;
+ }
+
+ HMAP_FOR_EACH_SAFE (xport, next_xport, ofp_node, &xbridge->xports) {
+ xlate_ofport_remove(xport->ofport);
+ }
+
+ LIST_FOR_EACH_SAFE (xbundle, next_xbundle, list_node, &xbridge->xbundles) {
+ xlate_bundle_remove(xbundle->ofbundle);
+ }
+
+ hmap_remove(&xbridges, &xbridge->hmap_node);
+ mac_learning_unref(xbridge->ml);
+ mbridge_unref(xbridge->mbridge);
+ dpif_sflow_unref(xbridge->sflow);
+ dpif_ipfix_unref(xbridge->ipfix);
+ stp_unref(xbridge->stp);
+ hmap_destroy(&xbridge->xports);
+ free(xbridge->name);
+ free(xbridge);
+}
+
+void
+xlate_bundle_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
+ const char *name, enum port_vlan_mode vlan_mode, int vlan,
+ unsigned long *trunks, bool use_priority_tags,
+ const struct bond *bond, const struct lacp *lacp,
+ bool floodable)
+{
+ struct xbundle *xbundle = xbundle_lookup(ofbundle);
+
+ if (!xbundle) {
+ xbundle = xzalloc(sizeof *xbundle);
+ xbundle->ofbundle = ofbundle;
+ xbundle->xbridge = xbridge_lookup(ofproto);
+
+ hmap_insert(&xbundles, &xbundle->hmap_node, hash_pointer(ofbundle, 0));
+ list_insert(&xbundle->xbridge->xbundles, &xbundle->list_node);
+ list_init(&xbundle->xports);
+ }
+
+ ovs_assert(xbundle->xbridge);
+
+ free(xbundle->name);
+ xbundle->name = xstrdup(name);
+
+ xbundle->vlan_mode = vlan_mode;
+ xbundle->vlan = vlan;
+ xbundle->trunks = trunks;
+ xbundle->use_priority_tags = use_priority_tags;
+ xbundle->floodable = floodable;
+
+ if (xbundle->bond != bond) {
+ bond_unref(xbundle->bond);
+ xbundle->bond = bond_ref(bond);
+ }
+
+ if (xbundle->lacp != lacp) {
+ lacp_unref(xbundle->lacp);
+ xbundle->lacp = lacp_ref(lacp);
+ }
+}
+
+void
+xlate_bundle_remove(struct ofbundle *ofbundle)
+{
+ struct xbundle *xbundle = xbundle_lookup(ofbundle);
+ struct xport *xport, *next;
+
+ if (!xbundle) {
+ return;
+ }
+
+ LIST_FOR_EACH_SAFE (xport, next, bundle_node, &xbundle->xports) {
+ list_remove(&xport->bundle_node);
+ xport->xbundle = NULL;
+ }
+
+ hmap_remove(&xbundles, &xbundle->hmap_node);
+ list_remove(&xbundle->list_node);
+ bond_unref(xbundle->bond);
+ lacp_unref(xbundle->lacp);
+ free(xbundle->name);
+ free(xbundle);
+}
+
+void
+xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
+ struct ofport_dpif *ofport, ofp_port_t ofp_port,
+ odp_port_t odp_port, const struct netdev *netdev,
+ const struct cfm *cfm, const struct bfd *bfd,
+ struct ofport_dpif *peer, int stp_port_no,
+ const struct ofproto_port_queue *qdscp_list, size_t n_qdscp,
+ enum ofputil_port_config config,
+ enum ofputil_port_state state, bool is_tunnel,
+ bool may_enable)
+{
+ struct xport *xport = xport_lookup(ofport);
+ size_t i;
+
+ if (!xport) {
+ xport = xzalloc(sizeof *xport);
+ xport->ofport = ofport;
+ xport->xbridge = xbridge_lookup(ofproto);
+ xport->ofp_port = ofp_port;
+
+ hmap_init(&xport->skb_priorities);
+ hmap_insert(&xports, &xport->hmap_node, hash_pointer(ofport, 0));
+ hmap_insert(&xport->xbridge->xports, &xport->ofp_node,
+ hash_ofp_port(xport->ofp_port));
+ }
+
+ ovs_assert(xport->ofp_port == ofp_port);
+
+ xport->config = config;
+ xport->state = state;
+ xport->stp_port_no = stp_port_no;
+ xport->is_tunnel = is_tunnel;
+ xport->may_enable = may_enable;
+ xport->odp_port = odp_port;
+
+ if (xport->netdev != netdev) {
+ netdev_close(xport->netdev);
+ xport->netdev = netdev_ref(netdev);
+ }
+
+ if (xport->cfm != cfm) {
+ cfm_unref(xport->cfm);
+ xport->cfm = cfm_ref(cfm);
+ }
+
+ if (xport->bfd != bfd) {
+ bfd_unref(xport->bfd);
+ xport->bfd = bfd_ref(bfd);
+ }
+
+ if (xport->peer) {
+ xport->peer->peer = NULL;
+ }
+ xport->peer = xport_lookup(peer);
+ if (xport->peer) {
+ xport->peer->peer = xport;
+ }
+
+ if (xport->xbundle) {
+ list_remove(&xport->bundle_node);
+ }
+ xport->xbundle = xbundle_lookup(ofbundle);
+ if (xport->xbundle) {
+ list_insert(&xport->xbundle->xports, &xport->bundle_node);
+ }
+
+ clear_skb_priorities(xport);
+ for (i = 0; i < n_qdscp; i++) {
+ struct skb_priority_to_dscp *pdscp;
+ uint32_t skb_priority;
+
+ if (dpif_queue_to_priority(xport->xbridge->dpif, qdscp_list[i].queue,
+ &skb_priority)) {
+ continue;
+ }
+
+ pdscp = xmalloc(sizeof *pdscp);
+ pdscp->skb_priority = skb_priority;
+ pdscp->dscp = (qdscp_list[i].dscp << 2) & IP_DSCP_MASK;
+ hmap_insert(&xport->skb_priorities, &pdscp->hmap_node,
+ hash_int(pdscp->skb_priority, 0));
+ }
+}
+
+void
+xlate_ofport_remove(struct ofport_dpif *ofport)
+{
+ struct xport *xport = xport_lookup(ofport);
+
+ if (!xport) {
+ return;
+ }