static void delete_flow__(struct rule *rule, struct ofopgroup *,
enum ofp_flow_removed_reason)
OVS_REQUIRES(ofproto_mutex);
+static bool ofproto_group_exists__(const struct ofproto *ofproto,
+ uint32_t group_id)
+ OVS_REQ_RDLOCK(ofproto->groups_rwlock);
static bool ofproto_group_exists(const struct ofproto *ofproto,
uint32_t group_id)
- OVS_REQ_RDLOCK(ofproto->groups_rwlock);
+ OVS_EXCLUDED(ofproto->groups_rwlock);
static enum ofperr add_group(struct ofproto *, struct ofputil_group_mod *);
static bool handle_openflow(struct ofconn *, const struct ofpbuf *);
static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *,
ovs_rwlock_init(&ofproto->groups_rwlock);
hmap_init(&ofproto->groups);
ovs_mutex_unlock(&ofproto_mutex);
+ ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS |
+ OFPGFC_SELECT_WEIGHT;
+ ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX;
+ ofproto->ogf.max_groups[OFPGT11_SELECT] = OFPG_MAX;
+ ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX;
+ ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX;
+ ofproto->ogf.actions[0] =
+ (1 << OFPAT11_OUTPUT) |
+ (1 << OFPAT11_COPY_TTL_OUT) |
+ (1 << OFPAT11_COPY_TTL_IN) |
+ (1 << OFPAT11_SET_MPLS_TTL) |
+ (1 << OFPAT11_DEC_MPLS_TTL) |
+ (1 << OFPAT11_PUSH_VLAN) |
+ (1 << OFPAT11_POP_VLAN) |
+ (1 << OFPAT11_PUSH_MPLS) |
+ (1 << OFPAT11_POP_MPLS) |
+ (1 << OFPAT11_SET_QUEUE) |
+ (1 << OFPAT11_GROUP) |
+ (1 << OFPAT11_SET_NW_TTL) |
+ (1 << OFPAT11_DEC_NW_TTL) |
+ (1 << OFPAT12_SET_FIELD);
+/* not supported:
+ * (1 << OFPAT13_PUSH_PBB) |
+ * (1 << OFPAT13_POP_PBB) */
error = ofproto->ofproto_class->construct(ofproto);
if (error) {
update_port(ofproto, netdev_name);
}
if (ofp_portp) {
- struct ofproto_port ofproto_port;
-
- ofproto_port_query_by_name(ofproto, netdev_get_name(netdev),
- &ofproto_port);
- *ofp_portp = error ? OFPP_NONE : ofproto_port.ofp_port;
- ofproto_port_destroy(&ofproto_port);
+ *ofp_portp = OFPP_NONE;
+ if (!error) {
+ struct ofproto_port ofproto_port;
+
+ error = ofproto_port_query_by_name(ofproto,
+ netdev_get_name(netdev),
+ &ofproto_port);
+ if (!error) {
+ *ofp_portp = ofproto_port.ofp_port;
+ ofproto_port_destroy(&ofproto_port);
+ }
+ }
}
return error;
}
/* Search for a free OpenFlow port number. We try not to
* immediately reuse them to prevent problems due to old
- * flows. */
+ * flows.
+ *
+ * We limit the automatically assigned port numbers to the lower half
+ * of the port range, to reserve the upper half for assignment by
+ * controllers. */
for (;;) {
- if (++ofproto->alloc_port_no >= ofproto->max_ports) {
+ if (++ofproto->alloc_port_no >= MIN(ofproto->max_ports, 32768)) {
ofproto->alloc_port_no = 1;
}
last_used_at = ofport_get_usage(ofproto,
}
}
-/* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are appropriate
- * for a packet with the prerequisites satisfied by 'flow' in table 'table_id'.
- * 'flow' may be temporarily modified, but is restored at return.
- */
+/* Checks that the 'ofpacts_len' bytes of action in 'ofpacts' are appropriate
+ * for 'ofproto':
+ *
+ * - If they use a meter, then 'ofproto' has that meter configured.
+ *
+ * - If they use any groups, then 'ofproto' has that group configured.
+ *
+ * Returns 0 if successful, otherwise an OpenFlow error. */
static enum ofperr
ofproto_check_ofpacts(struct ofproto *ofproto,
- struct ofpact ofpacts[], size_t ofpacts_len,
- struct flow *flow, uint8_t table_id,
- const struct ofp_header *oh)
+ const struct ofpact ofpacts[], size_t ofpacts_len)
{
- enum ofperr error;
const struct ofpact *a;
uint32_t mid;
- error = ofpacts_check(ofpacts, ofpacts_len, flow,
- u16_to_ofp(ofproto->max_ports), table_id,
- oh && oh->version > OFP10_VERSION);
- if (error) {
- return error;
+ mid = ofpacts_get_meter(ofpacts, ofpacts_len);
+ if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
+ return OFPERR_OFPMMFC_INVALID_METER;
}
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
- if (a->type == OFPACT_GROUP) {
- bool exists;
-
- ovs_rwlock_rdlock(&ofproto->groups_rwlock);
- exists = ofproto_group_exists(ofproto,
- ofpact_get_GROUP(a)->group_id);
- ovs_rwlock_unlock(&ofproto->groups_rwlock);
-
- if (!exists) {
- return OFPERR_OFPBAC_BAD_OUT_GROUP;
- }
+ if (a->type == OFPACT_GROUP
+ && !ofproto_group_exists(ofproto, ofpact_get_GROUP(a)->group_id)) {
+ return OFPERR_OFPBAC_BAD_OUT_GROUP;
}
}
- mid = ofpacts_get_meter(ofpacts, ofpacts_len);
- if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
- return OFPERR_OFPMMFC_INVALID_METER;
- }
return 0;
}
goto exit_free_ofpacts;
}
-
/* Get payload. */
if (po.buffer_id != UINT32_MAX) {
error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
/* Verify actions against packet, then send packet if successful. */
in_port_.ofp_port = po.in_port;
flow_extract(payload, 0, 0, NULL, &in_port_, &flow);
- error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0, oh);
+ error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len);
if (!error) {
error = p->ofproto_class->packet_out(p, payload, &flow,
po.ofpacts, po.ofpacts_len);
}
}
- /* Verify actions. */
- error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
- &fm->match.flow, table_id, request);
- if (error) {
- cls_rule_destroy(&cr);
- return error;
- }
-
/* Serialize against pending deletion. */
if (is_flow_deletion_pending(ofproto, &cr, table_id)) {
cls_rule_destroy(&cr);
enum ofperr error;
size_t i;
- /* Verify actions before we start to modify any rules, to avoid partial
- * flow table modifications. */
- for (i = 0; i < rules->n; i++) {
- struct rule *rule = rules->rules[i];
-
- error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
- &fm->match.flow, rule->table_id,
- request);
- if (error) {
- return error;
- }
- }
-
type = fm->command == OFPFC_ADD ? OFOPERATION_REPLACE : OFOPERATION_MODIFY;
group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id);
error = OFPERR_OFPBRC_EPERM;
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
- &ofpacts);
+ &ofpacts,
+ u16_to_ofp(ofproto->max_ports),
+ ofproto->n_tables);
+ if (!error) {
+ error = ofproto_check_ofpacts(ofproto, fm.ofpacts, fm.ofpacts_len);
+ }
if (!error) {
error = handle_flow_mod__(ofproto, ofconn, &fm, oh);
}
}
static bool
-ofproto_group_exists(const struct ofproto *ofproto, uint32_t group_id)
+ofproto_group_exists__(const struct ofproto *ofproto, uint32_t group_id)
OVS_REQ_RDLOCK(ofproto->groups_rwlock)
{
struct ofgroup *grp;
return false;
}
+static bool
+ofproto_group_exists(const struct ofproto *ofproto, uint32_t group_id)
+ OVS_EXCLUDED(ofproto->groups_rwlock)
+{
+ bool exists;
+
+ ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+ exists = ofproto_group_exists__(ofproto, group_id);
+ ovs_rwlock_unlock(&ofproto->groups_rwlock);
+
+ return exists;
+}
+
static uint32_t
group_get_ref_count(struct ofgroup *group)
OVS_EXCLUDED(ofproto_mutex)
goto unlock_out;
}
- if (ofproto_group_exists(ofproto, gm->group_id)) {
+ if (ofproto_group_exists__(ofproto, gm->group_id)) {
error = OFPERR_OFPGMFC_GROUP_EXISTS;
goto unlock_out;
}
oftable_init(struct oftable *table)
{
memset(table, 0, sizeof *table);
- classifier_init(&table->cls);
+ classifier_init(&table->cls, flow_segment_u32s);
table->max_flows = UINT_MAX;
}