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_meter' 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. Signed-off-by: Dumitru Ceara <[email protected]> --- controller/lflow.c | 37 ++++++++++++++++++++++++++++++---- controller/ofctrl.c | 29 +++++++++++++++++++++----- controller/ofctrl.h | 13 ++++++++++-- controller/physical.c | 3 ++- include/ovn/actions.h | 2 ++ lib/actions.c | 54 +++++++++++++++++++++++++------------------------ ovn-sb.ovsschema | 6 ++++- ovn-sb.xml | 6 +++++ 8 files changed, 109 insertions(+), 41 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index 36150bd..6d2ddf7 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -536,6 +536,26 @@ update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs) return true; } +static void +lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow, + struct ovn_extend_table *meter_table, + uint32_t *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 bool consider_logical_flow( struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath, @@ -669,6 +689,12 @@ consider_logical_flow( return true; } + /* 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, 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); @@ -686,6 +712,7 @@ consider_logical_flow( .output_ptable = output_ptable, .mac_bind_ptable = OFTABLE_MAC_BINDING, .mac_lookup_ptable = OFTABLE_MAC_LOOKUP, + .ctrl_meter_id = ctrl_meter_id, }; ovnacts_encode(ovnacts.data, ovnacts.size, &ep, &ofpacts); ovnacts_free(ovnacts.data, ovnacts.size); @@ -717,9 +744,10 @@ consider_logical_flow( } } if (!m->n) { - ofctrl_add_flow(flow_table, ptable, lflow->priority, - lflow->header_.uuid.parts[0], &m->match, &ofpacts, - &lflow->header_.uuid); + ofctrl_add_flow_meter(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; @@ -736,7 +764,8 @@ consider_logical_flow( } ofctrl_add_or_append_flow(flow_table, ptable, lflow->priority, 0, - &m->match, &conj, &lflow->header_.uuid); + &m->match, &conj, &lflow->header_.uuid, + ctrl_meter_id); ofpbuf_uninit(&conj); } } diff --git a/controller/ofctrl.c b/controller/ofctrl.c index 10edd84..81d001f 100644 --- a/controller/ofctrl.c +++ b/controller/ofctrl.c @@ -67,13 +67,15 @@ 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. */ }; static struct ovn_flow *ovn_flow_alloc(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); static uint32_t ovn_flow_match_hash(const struct ovn_flow *); static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target, @@ -660,10 +662,11 @@ ofctrl_check_and_add_flow(struct ovn_desired_flow_table *flow_table, 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 ovn_flow *f = ovn_flow_alloc(table_id, priority, cookie, match, - actions, sb_uuid); + actions, sb_uuid, meter_id); ovn_flow_log(f, "ofctrl_add_flow"); @@ -715,8 +718,18 @@ ofctrl_add_flow(struct ovn_desired_flow_table *desired_flows, const struct match *match, const struct ofpbuf *actions, const struct uuid *sb_uuid) { + ofctrl_add_flow_meter(desired_flows, table_id, priority, cookie, + match, actions, sb_uuid, NX_CTLR_NO_METER); +} + +void +ofctrl_add_flow_meter(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(desired_flows, table_id, priority, cookie, - match, actions, sb_uuid, true); + match, actions, sb_uuid, meter_id, true); } void @@ -724,10 +737,11 @@ 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 ovn_flow *f = ovn_flow_alloc(table_id, priority, cookie, match, - actions, sb_uuid); + actions, sb_uuid, meter_id); ovn_flow_log(f, "ofctrl_add_or_append_flow"); @@ -762,7 +776,7 @@ ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows, static struct ovn_flow * ovn_flow_alloc(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 ovn_flow *f = xmalloc(sizeof *f); f->table_id = table_id; @@ -774,6 +788,7 @@ ovn_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie, f->match_hmap_node.hash = ovn_flow_match_hash(f); f->uuid_hindex_node.hash = uuid_hash(&f->sb_uuid); f->cookie = cookie; + f->ctrl_meter_id = meter_id; return f; } @@ -799,6 +814,7 @@ ofctrl_dup_flow(struct ovn_flow *src) dst->sb_uuid = src->sb_uuid; dst->match_hmap_node.hash = src->match_hmap_node.hash; dst->uuid_hindex_node.hash = uuid_hash(&src->sb_uuid); + dst->ctrl_meter_id = src->ctrl_meter_id; return dst; } @@ -814,6 +830,7 @@ ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target, flow_table) { 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 (!cmp_sb_uuid || uuid_equals(&target->sb_uuid, &f->sb_uuid)) { return f; diff --git a/controller/ofctrl.h b/controller/ofctrl.h index 21d2ce6..2e65374 100644 --- a/controller/ofctrl.h +++ b/controller/ofctrl.h @@ -74,7 +74,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_meter(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); void ofctrl_remove_flows(struct ovn_desired_flow_table *, const struct uuid *); @@ -86,7 +94,8 @@ 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); + const struct uuid *, uint32_t meter_id, + bool log_duplicate_flow); bool ofctrl_is_connected(void); void ofctrl_set_probe_interval(int probe_interval); diff --git a/controller/physical.c b/controller/physical.c index 500d419..0ca6052 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -818,7 +818,8 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, 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); + &match, ofpacts_p, hc_uuid, + NX_CTLR_NO_METER, false); } } diff --git a/include/ovn/actions.h b/include/ovn/actions.h index f4997e9..8fc7727 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -645,6 +645,8 @@ struct ovnact_encode_params { resubmit. */ uint8_t mac_lookup_ptable; /* OpenFlow table for 'lookup_arp'/'lookup_nd' 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, diff --git a/lib/actions.c b/lib/actions.c index a999a4f..32bc4d5 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -105,10 +105,10 @@ encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts) } static void -encode_controller_op(enum action_opcode opcode, struct ofpbuf *ofpacts) +encode_controller_op(enum action_opcode opcode, uint32_t meter_id, + struct ofpbuf *ofpacts) { - size_t ofs = encode_start_controller_op(opcode, false, NX_CTLR_NO_METER, - ofpacts); + size_t ofs = encode_start_controller_op(opcode, false, meter_id, ofpacts); encode_finish_controller_op(ofs, ofpacts); } @@ -1320,7 +1320,7 @@ encode_nested_actions(const struct ovnact_nest *on, * packet to ARP or NA and then send the packet and actions back to the * switch inside an OFPT_PACKET_OUT message. */ size_t oc_offset = encode_start_controller_op(opcode, false, - NX_CTLR_NO_METER, ofpacts); + ep->ctrl_meter_id, ofpacts); ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, ofpacts, OFP13_VERSION); encode_finish_controller_op(oc_offset, ofpacts); @@ -1363,10 +1363,10 @@ encode_ICMP6(const struct ovnact_nest *on, static void encode_IGMP(const struct ovnact_null *a OVS_UNUSED, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_controller_op(ACTION_OPCODE_IGMP, ofpacts); + encode_controller_op(ACTION_OPCODE_IGMP, ep->ctrl_meter_id, ofpacts); } static void @@ -1592,6 +1592,7 @@ format_PUT_ND(const struct ovnact_put_mac_bind *put_mac, struct ds *s) static void encode_put_mac(const struct ovnact_put_mac_bind *put_mac, + const struct ovnact_encode_params *ep, enum mf_field_id ip_field, enum action_opcode opcode, struct ofpbuf *ofpacts) { @@ -1601,31 +1602,31 @@ encode_put_mac(const struct ovnact_put_mac_bind *put_mac, { expr_resolve_field(&put_mac->mac), MFF_ETH_SRC } }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); - encode_controller_op(opcode, ofpacts); + encode_controller_op(opcode, ep->ctrl_meter_id, ofpacts); encode_restore_args(args, ARRAY_SIZE(args), ofpacts); } static void encode_PUT_ARP(const struct ovnact_put_mac_bind *put_mac, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_put_mac(put_mac, MFF_REG0, ACTION_OPCODE_PUT_ARP, ofpacts); + encode_put_mac(put_mac, ep, MFF_REG0, ACTION_OPCODE_PUT_ARP, ofpacts); } static void encode_PUT_ND(const struct ovnact_put_mac_bind *put_mac, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_put_mac(put_mac, MFF_XXREG0, ACTION_OPCODE_PUT_ND, ofpacts); + encode_put_mac(put_mac, ep, MFF_XXREG0, ACTION_OPCODE_PUT_ND, ofpacts); } static void ovnact_put_mac_bind_free(struct ovnact_put_mac_bind *put_mac OVS_UNUSED) { } - + static void format_lookup_mac(const struct ovnact_lookup_mac_bind *lookup_mac, struct ds *s, const char *name) { @@ -2115,13 +2116,13 @@ encode_put_dhcpv6_option(const struct ovnact_gen_option *o, static void encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS, - true, NX_CTLR_NO_METER, + true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); @@ -2147,13 +2148,13 @@ encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, static void encode_PUT_DHCPV6_OPTS(const struct ovnact_put_opts *pdo, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_DHCPV6_OPTS, true, NX_CTLR_NO_METER, ofpacts); + ACTION_OPCODE_PUT_DHCPV6_OPTS, true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2242,13 +2243,13 @@ format_DNS_LOOKUP(const struct ovnact_dns_lookup *dl, struct ds *s) static void encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&dl->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_DNS_LOOKUP, - true, NX_CTLR_NO_METER, + true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); @@ -2407,13 +2408,14 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o, static void encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&po->dst); - size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_ND_RA_OPTS, true, NX_CTLR_NO_METER, ofpacts); + size_t oc_offset = + encode_start_controller_op(ACTION_OPCODE_PUT_ND_RA_OPTS, true, + ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2688,15 +2690,15 @@ format_OVNFIELD_LOAD(const struct ovnact_load *load , struct ds *s) static void encode_OVNFIELD_LOAD(const struct ovnact_load *load, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { const struct ovn_field *f = ovn_field_from_name(load->dst.symbol->name); switch (f->id) { case OVN_ICMP4_FRAG_MTU: { - size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true, NX_CTLR_NO_METER, - ofpacts); + size_t oc_offset = + encode_start_controller_op(ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true, + ep->ctrl_meter_id, ofpacts); ofpbuf_put(ofpacts, &load->imm.value.be16_int, sizeof(ovs_be16)); encode_finish_controller_op(oc_offset, ofpacts); break; @@ -2800,7 +2802,7 @@ encode_BIND_VPORT(const struct ovnact_bind_vport *vp, }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_BIND_VPORT, - false, NX_CTLR_NO_METER, + false, ep->ctrl_meter_id, ofpacts); ovs_be32 vp_key = htonl(vport_key); ofpbuf_put(ofpacts, &vp_key, sizeof(ovs_be32)); diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 5c013b1..5895d89 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "2.5.0", - "cksum": "1257419092 20387", + "version": "2.6.0", + "cksum": "3178216375 20519", "tables": { "SB_Global": { "columns": { @@ -86,6 +86,8 @@ "maxInteger": 65535}}}, "match": {"type": "string"}, "actions": {"type": "string"}, + "controller_meter": {"type": {"key": {"type": "string"}, + "min": 0, "max": 1}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-sb.xml b/ovn-sb.xml index e5fb51a..58b3bfd 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -2100,6 +2100,12 @@ tcp.flags = RST; </dl> </column> + <column name="controller_meter"> + The name of the meter in table <ref table="Meter"/> to be used for + all packets that the logical flow might send to + <code>ovn-controller</code>. + </column> + <column name="external_ids" key="stage-name"> Human-readable name for this flow's stage in the pipeline. </column> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
