struct xport *peer; /* Patch port peer or null. */
enum ofputil_port_config config; /* OpenFlow port configuration. */
- int stp_port_no; /* STP port number or 0 if not in use. */
+ int stp_port_no; /* STP port number or -1 if not in use. */
struct hmap skb_priorities; /* Map of 'skb_priority_to_dscp's. */
}
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);
}
static struct stp_port *
xport_get_stp_port(const struct xport *xport)
{
- return xport->xbridge->stp && xport->stp_port_no
+ return xport->xbridge->stp && xport->stp_port_no != -1
? stp_get_port(xport->xbridge->stp, xport->stp_port_no)
: NULL;
}
struct xbundle *in_xbundle;
struct xport *in_port;
struct mac_entry *mac;
+ void *mac_port;
uint16_t vlan;
uint16_t vid;
/* Determine output bundle. */
ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
- if (mac) {
- struct xbundle *mac_xbundle = xbundle_lookup(mac->port.p);
+ mac_port = mac ? mac->port.p : NULL;
+ ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
+
+ if (mac_port) {
+ struct xbundle *mac_xbundle = xbundle_lookup(mac_port);
if (mac_xbundle && mac_xbundle != in_xbundle) {
xlate_report(ctx, "forwarding to learned port");
output_normal(ctx, mac_xbundle, vlan);
}
ctx->xout->nf_output_iface = NF_OUT_FLOOD;
}
- ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
}
/* Compose SAMPLE action for sFlow or IPFIX. The given probability is
out_port = ofp_port_to_odp_port(ctx->xbridge, vlandev_port);
flow->vlan_tci = htons(0);
}
- flow->pkt_mark &= ~IPSEC_MARK;
}
if (out_port != ODPP_NONE) {
compose_output_action__(ctx, ofp_port, true);
}
+static void
+xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule)
+ OVS_RELEASES(rule)
+{
+ struct rule_dpif *old_rule = ctx->rule;
+ const struct ofpact *ofpacts;
+ size_t ofpacts_len;
+
+ if (ctx->xin->resubmit_stats) {
+ rule_dpif_credit_stats(rule, ctx->xin->resubmit_stats);
+ }
+
+ ctx->recurse++;
+ ctx->rule = rule;
+ rule_dpif_get_actions(rule, &ofpacts, &ofpacts_len);
+ do_xlate_actions(ofpacts, ofpacts_len, ctx);
+ ctx->rule = old_rule;
+ ctx->recurse--;
+
+ rule_dpif_release(rule);
+}
+
static void
xlate_table_action(struct xlate_ctx *ctx,
ofp_port_t in_port, uint8_t table_id, bool may_packet_in)
struct rule_dpif *rule;
ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
uint8_t old_table_id = ctx->table_id;
+ bool got_rule;
ctx->table_id = table_id;
- /* Look up a flow with 'in_port' as the input port. */
+ /* Look up a flow with 'in_port' as the input port. Then restore the
+ * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
+ * have surprising behavior). */
ctx->xin->flow.in_port.ofp_port = in_port;
- rule_dpif_lookup_in_table(ctx->xbridge->ofproto, &ctx->xin->flow,
- &ctx->xout->wc, table_id, &rule);
-
- /* Restore the original input port. Otherwise OFPP_NORMAL and
- * OFPP_IN_PORT will have surprising behavior. */
+ got_rule = rule_dpif_lookup_in_table(ctx->xbridge->ofproto,
+ &ctx->xin->flow, &ctx->xout->wc,
+ table_id, &rule);
ctx->xin->flow.in_port.ofp_port = old_in_port;
if (ctx->xin->resubmit_hook) {
ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
}
- if (rule == NULL && may_packet_in) {
+ if (got_rule) {
+ xlate_recursively(ctx, rule);
+ } else if (may_packet_in) {
struct xport *xport;
- /* Makes clang's thread safety analysis happy. */
- rule_release(rule);
-
/* XXX
* check if table configuration flags
* OFPTC_TABLE_MISS_CONTROLLER, default.
* OFPTC_TABLE_MISS_DROP
* When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
- rule = choose_miss_rule(xport ? xport->config : 0,
- ctx->xbridge->miss_rule,
- ctx->xbridge->no_packet_in_rule);
- ovs_rwlock_rdlock(&rule->up.evict);
+ choose_miss_rule(xport ? xport->config : 0,
+ ctx->xbridge->miss_rule,
+ ctx->xbridge->no_packet_in_rule, &rule);
+ xlate_recursively(ctx, rule);
}
- if (rule && ctx->xin->resubmit_stats) {
- rule_credit_stats(rule, ctx->xin->resubmit_stats);
- }
-
- if (rule) {
- struct rule_dpif *old_rule = ctx->rule;
-
- ctx->recurse++;
- ctx->rule = rule;
- do_xlate_actions(rule->up.ofpacts, rule->up.ofpacts_len, ctx);
- ctx->rule = old_rule;
- ctx->recurse--;
- }
- rule_release(rule);
-
ctx->table_id = old_table_id;
} else {
static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
pin->reason = reason;
pin->controller_id = controller_id;
pin->table_id = ctx->table_id;
- pin->cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
+ pin->cookie = ctx->rule ? rule_dpif_get_flow_cookie(ctx->rule) : 0;
pin->send_len = len;
flow_get_metadata(&ctx->xin->flow, &pin->fmd);
ofproto_dpif_flow_mod(ctx->xbridge->ofproto, fm);
}
-/* Reduces '*timeout' to no more than 'max'. A value of zero in either case
- * means "infinite". */
-static void
-reduce_timeout(uint16_t max, uint16_t *timeout)
-{
- if (max && (!*timeout || *timeout > max)) {
- *timeout = max;
- }
-}
-
static void
xlate_fin_timeout(struct xlate_ctx *ctx,
const struct ofpact_fin_timeout *oft)
{
if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
- struct rule_dpif *rule = ctx->rule;
-
- ovs_mutex_lock(&rule->up.ofproto->expirable_mutex);
- if (list_is_empty(&rule->up.expirable)) {
- list_insert(&rule->up.ofproto->expirable, &rule->up.expirable);
- }
- ovs_mutex_unlock(&rule->up.ofproto->expirable_mutex);
-
- ovs_mutex_lock(&rule->up.timeout_mutex);
- reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout);
- reduce_timeout(oft->fin_hard_timeout, &rule->up.hard_timeout);
- ovs_mutex_unlock(&rule->up.timeout_mutex);
+ rule_dpif_reduce_timeouts(ctx->rule, oft->fin_idle_timeout,
+ oft->fin_hard_timeout);
}
}
ofpact_get_OUTPUT(a)->max_len, true);
break;
+ case OFPACT_GROUP:
+ /* XXX not yet implemented */
+ break;
+
case OFPACT_CONTROLLER:
controller = ofpact_get_CONTROLLER(a);
execute_controller_action(ctx, controller->max_len,
}
/* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts'
- * into datapath actions in 'odp_actions', using 'ctx'. */
+ * into datapath actions in 'odp_actions', using 'ctx'.
+ *
+ * The caller must take responsibility for eventually freeing 'xout', with
+ * xlate_out_uninit(). */
void
xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
{
ofpacts = xin->ofpacts;
ofpacts_len = xin->ofpacts_len;
} else if (xin->rule) {
- ofpacts = xin->rule->up.ofpacts;
- ofpacts_len = xin->rule->up.ofpacts_len;
+ rule_dpif_get_actions(xin->rule, &ofpacts, &ofpacts_len);
} else {
NOT_REACHED();
}