Skip to content

Commit

Permalink
ovn-controller: Add support for Logical_Flow control meters
Browse files Browse the repository at this point in the history
Add a new 'controller_meter' column to OVN Southbound Logical_Flow
table. This stores an optional string which should correspond to
the Meter that must be used for rate limiting controller actions
generated by packets hitting the flow.

Add a new 'ofctrl_add_flow_metered' function to create a new 'ovn_flow'
with an attached controller meter.

Change ofctrl_check_and_add_flow to allow specifying a meter ID for
packets that are punted to controller.

Change consider_logical_flow to parse controller_meter from the logical
flow and use it when building openflow entries.

Add a new 'ctrl_meter_id' field to 'struct ovnact_encode_params' to be
used when encoding controller actions from logical flow actions.

Acked-by: Mark D. Gray <mark.d.gray@redhat.com>
Co-authored-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Mark Michelson <mmichels@redhat.com>
  • Loading branch information
2 people authored and putnopvut committed Jul 23, 2021
1 parent c8565bb commit 71f2b56
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 63 deletions.
40 changes: 36 additions & 4 deletions controller/lflow.c
Expand Up @@ -575,6 +575,27 @@ update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs)
return false;
}

static void
lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow,
struct ovn_extend_table *meter_table,
uint32_t *meter_id)
{
ovs_assert(meter_id);
*meter_id = NX_CTLR_NO_METER;

if (lflow->controller_meter) {
*meter_id = ovn_extend_table_assign_id(meter_table,
lflow->controller_meter,
lflow->header_.uuid);
if (*meter_id == EXT_TABLE_ID_INVALID) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_WARN_RL(&rl, "Unable to assign id for meter: %s",
lflow->controller_meter);
return;
}
}
}

static void
add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
const struct sbrec_datapath_binding *dp,
Expand All @@ -592,6 +613,13 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
.lfrr = l_ctx_out->lfrr,
};

/* Parse any meter to be used if this flow should punt packets to
* controller.
*/
uint32_t ctrl_meter_id = NX_CTLR_NO_METER;
lflow_parse_ctrl_meter(lflow, l_ctx_out->meter_table,
&ctrl_meter_id);

/* Encode OVN logical actions into OpenFlow. */
uint64_t ofpacts_stub[1024 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
Expand All @@ -615,6 +643,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
.ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP,
.fdb_ptable = OFTABLE_GET_FDB,
.fdb_lookup_ptable = OFTABLE_LOOKUP_FDB,
.ctrl_meter_id = ctrl_meter_id,
};
ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts);

Expand All @@ -639,9 +668,11 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
}
}
if (!m->n) {
ofctrl_add_flow(l_ctx_out->flow_table, ptable, lflow->priority,
lflow->header_.uuid.parts[0], &m->match, &ofpacts,
&lflow->header_.uuid);
ofctrl_add_flow_metered(l_ctx_out->flow_table, ptable,
lflow->priority,
lflow->header_.uuid.parts[0], &m->match,
&ofpacts, &lflow->header_.uuid,
ctrl_meter_id);
} else {
uint64_t conj_stubs[64 / 8];
struct ofpbuf conj;
Expand All @@ -659,7 +690,8 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,

ofctrl_add_or_append_flow(l_ctx_out->flow_table, ptable,
lflow->priority, 0,
&m->match, &conj, &lflow->header_.uuid);
&m->match, &conj, &lflow->header_.uuid,
ctrl_meter_id);
ofpbuf_uninit(&conj);
}
}
Expand Down
56 changes: 39 additions & 17 deletions controller/ofctrl.c
Expand Up @@ -66,6 +66,7 @@ struct ovn_flow {
struct ofpact *ofpacts;
size_t ofpacts_len;
uint64_t cookie;
uint32_t ctrl_meter_id; /* Meter to be used for controller actions. */
};

/* A desired flow, in struct ovn_desired_flow_table, calculated by the
Expand Down Expand Up @@ -220,7 +221,8 @@ static struct desired_flow *desired_flow_alloc(
uint16_t priority,
uint64_t cookie,
const struct match *match,
const struct ofpbuf *actions);
const struct ofpbuf *actions,
uint32_t meter_id);
static struct desired_flow *desired_flow_lookup(
struct ovn_desired_flow_table *,
const struct ovn_flow *target);
Expand Down Expand Up @@ -1014,8 +1016,9 @@ link_flow_to_sb(struct ovn_desired_flow_table *flow_table,
/* Flow table interfaces to the rest of ovn-controller. */

/* Adds a flow to 'desired_flows' with the specified 'match' and 'actions' to
* the OpenFlow table numbered 'table_id' with the given 'priority' and
* OpenFlow 'cookie'. The caller retains ownership of 'match' and 'actions'.
* the OpenFlow table numbered 'table_id' with the given 'priority', OpenFlow
* 'cookie' and 'meter_id'. The caller retains ownership of 'match' and
* 'actions'.
*
* The flow is also linked to the sb_uuid that generates it.
*
Expand All @@ -1024,15 +1027,15 @@ link_flow_to_sb(struct ovn_desired_flow_table *flow_table,
*
* The caller should initialize its own hmap to hold the flows. */
void
ofctrl_check_and_add_flow(struct ovn_desired_flow_table *flow_table,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid,
bool log_duplicate_flow)
ofctrl_check_and_add_flow_metered(struct ovn_desired_flow_table *flow_table,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid,
uint32_t meter_id, bool log_duplicate_flow)
{
struct desired_flow *f = desired_flow_alloc(table_id, priority, cookie,
match, actions);
match, actions, meter_id);

if (desired_flow_lookup_check_uuid(flow_table, &f->flow, sb_uuid)) {
if (log_duplicate_flow) {
Expand Down Expand Up @@ -1060,8 +1063,20 @@ ofctrl_add_flow(struct ovn_desired_flow_table *desired_flows,
const struct match *match, const struct ofpbuf *actions,
const struct uuid *sb_uuid)
{
ofctrl_check_and_add_flow(desired_flows, table_id, priority, cookie,
match, actions, sb_uuid, true);
ofctrl_add_flow_metered(desired_flows, table_id, priority, cookie,
match, actions, sb_uuid, NX_CTLR_NO_METER);
}

void
ofctrl_add_flow_metered(struct ovn_desired_flow_table *desired_flows,
uint8_t table_id, uint16_t priority, uint64_t cookie,
const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid, uint32_t meter_id)
{
ofctrl_check_and_add_flow_metered(desired_flows, table_id, priority,
cookie, match, actions, sb_uuid,
meter_id, true);
}

/* Either add a new flow, or append actions on an existing flow. If the
Expand All @@ -1072,12 +1087,14 @@ ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
uint8_t table_id, uint16_t priority, uint64_t cookie,
const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid)
const struct uuid *sb_uuid,
uint32_t meter_id)
{
struct desired_flow *existing;
struct desired_flow *f;

f = desired_flow_alloc(table_id, priority, cookie, match, actions);
f = desired_flow_alloc(table_id, priority, cookie, match, actions,
meter_id);
existing = desired_flow_lookup_conjunctive(desired_flows, &f->flow);
if (existing) {
/* There's already a flow with this particular match and action
Expand Down Expand Up @@ -1281,7 +1298,7 @@ ofctrl_flood_remove_flows(struct ovn_desired_flow_table *flow_table,
static void
ovn_flow_init(struct ovn_flow *f, uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *match,
const struct ofpbuf *actions)
const struct ofpbuf *actions, uint32_t meter_id)
{
f->table_id = table_id;
f->priority = priority;
Expand All @@ -1290,11 +1307,13 @@ ovn_flow_init(struct ovn_flow *f, uint8_t table_id, uint16_t priority,
f->ofpacts_len = actions->size;
f->hash = ovn_flow_match_hash(f);
f->cookie = cookie;
f->ctrl_meter_id = meter_id;
}

static struct desired_flow *
desired_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie,
const struct match *match, const struct ofpbuf *actions)
const struct match *match, const struct ofpbuf *actions,
uint32_t meter_id)
{
struct desired_flow *f = xmalloc(sizeof *f);
ovs_list_init(&f->references);
Expand All @@ -1303,7 +1322,8 @@ desired_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie,
ovs_list_init(&f->track_list_node);
f->installed_flow = NULL;
f->is_deleted = false;
ovn_flow_init(&f->flow, table_id, priority, cookie, match, actions);
ovn_flow_init(&f->flow, table_id, priority, cookie, match, actions,
meter_id);

return f;
}
Expand All @@ -1329,6 +1349,7 @@ installed_flow_dup(struct desired_flow *src)
dst->flow.ofpacts_len = src->flow.ofpacts_len;
dst->flow.hash = src->flow.hash;
dst->flow.cookie = src->flow.cookie;
dst->flow.ctrl_meter_id = src->flow.ctrl_meter_id;
return dst;
}

Expand All @@ -1355,6 +1376,7 @@ desired_flow_lookup__(struct ovn_desired_flow_table *flow_table,
struct ovn_flow *f = &d->flow;
if (f->table_id == target->table_id
&& f->priority == target->priority
&& f->ctrl_meter_id == target->ctrl_meter_id
&& minimatch_equal(&f->match, &target->match)) {

if (!match_cb || match_cb(d, arg)) {
Expand Down
21 changes: 15 additions & 6 deletions controller/ofctrl.h
Expand Up @@ -80,7 +80,15 @@ void ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid);
const struct uuid *sb_uuid,
uint32_t meter_id);

void ofctrl_add_flow_metered(struct ovn_desired_flow_table *desired_flows,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *match,
const struct ofpbuf *actions,
const struct uuid *sb_uuid,
uint32_t meter_id);

/* Removes a bundles of flows from the flow table for a specific sb_uuid. The
* flows are removed only if they are not referenced by any other sb_uuid(s).
Expand Down Expand Up @@ -110,11 +118,12 @@ void ovn_desired_flow_table_init(struct ovn_desired_flow_table *);
void ovn_desired_flow_table_clear(struct ovn_desired_flow_table *);
void ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *);

void ofctrl_check_and_add_flow(struct ovn_desired_flow_table *,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *,
const struct ofpbuf *ofpacts,
const struct uuid *, bool log_duplicate_flow);
void ofctrl_check_and_add_flow_metered(struct ovn_desired_flow_table *,
uint8_t table_id, uint16_t priority,
uint64_t cookie, const struct match *,
const struct ofpbuf *ofpacts,
const struct uuid *, uint32_t meter_id,
bool log_duplicate_flow);


bool ofctrl_is_connected(void);
Expand Down
9 changes: 5 additions & 4 deletions controller/physical.c
Expand Up @@ -847,8 +847,8 @@ put_local_common_flows(uint32_t dp_key,
* If a parent port has multiple child ports, then this if condition
* will be hit multiple times, but we want to add only one flow.
* ofctrl_add_flow() logs a warning message for duplicate flows.
* So use the function 'ofctrl_check_and_add_flow' which doesn't
* log a warning.
* So use the function 'ofctrl_check_and_add_flow_metered' which
* doesn't log a warning.
*
* Other option is to add this flow for all the ports which are not
* nested containers. In which case we will add this flow for all the
Expand All @@ -867,8 +867,9 @@ put_local_common_flows(uint32_t dp_key,
put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p);
put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
ofctrl_check_and_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0,
&match, ofpacts_p, hc_uuid, false);
ofctrl_check_and_add_flow_metered(flow_table, OFTABLE_SAVE_INPORT, 100,
0, &match, ofpacts_p, hc_uuid,
NX_CTLR_NO_METER, false);
}
}

Expand Down
2 changes: 2 additions & 0 deletions include/ovn/actions.h
Expand Up @@ -796,6 +796,8 @@ struct ovnact_encode_params {
* 'get_fdb' to resubmit. */
uint8_t fdb_lookup_ptable; /* OpenFlow table for
* 'lookup_fdb' to resubmit. */
uint32_t ctrl_meter_id; /* Meter to be used if the resulting flow
sends packets to controller. */
};

void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
Expand Down

0 comments on commit 71f2b56

Please sign in to comment.