@@ -394,7 +394,6 @@ struct ovnact_controller_event {
int event_type; /* controller event type */
struct ovnact_gen_option *options;
size_t n_options;
- char *meter;
};
/* OVNACT_BIND_VPORT. */
@@ -1644,9 +1644,6 @@ format_TRIGGER_EVENT(const struct ovnact_controller_event *event,
{
ds_put_format(s, "trigger_event(event = \"%s\"",
event_to_string(event->event_type));
- if (event->meter) {
- ds_put_format(s, ", meter = \"%s\"", event->meter);
- }
for (const struct ovnact_gen_option *o = event->options;
o < &event->options[event->n_options]; o++) {
ds_put_cstr(s, ", ");
@@ -1821,24 +1818,11 @@ encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts,
static void
encode_TRIGGER_EVENT(const struct ovnact_controller_event *event,
- const struct ovnact_encode_params *ep OVS_UNUSED,
+ const struct ovnact_encode_params *ep,
struct ofpbuf *ofpacts)
{
- uint32_t meter_id = NX_CTLR_NO_METER;
- size_t oc_offset;
-
- if (event->meter) {
- meter_id = ovn_extend_table_assign_id(ep->meter_table, event->meter,
- ep->lflow_uuid);
- if (meter_id == EXT_TABLE_ID_INVALID) {
- VLOG_WARN("Unable to assign id for trigger meter: %s",
- event->meter);
- return;
- }
- }
-
- oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false,
- meter_id, ofpacts);
+ size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false,
+ ep->ctrl_meter_id, ofpacts);
ovs_be32 ofs = htonl(event->event_type);
ofpbuf_put(ofpacts, &ofs, sizeof ofs);
@@ -2372,27 +2356,12 @@ parse_trigger_event(struct action_context *ctx,
sizeof *event->options);
}
- if (lexer_match_id(ctx->lexer, "meter")) {
- if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
- return;
- }
- /* If multiple meters are given, use the most recent. */
- if (ctx->lexer->token.type == LEX_T_STRING &&
- strlen(ctx->lexer->token.s)) {
- free(event->meter);
- event->meter = xstrdup(ctx->lexer->token.s);
- } else if (ctx->lexer->token.type != LEX_T_STRING) {
- lexer_syntax_error(ctx->lexer, "expecting string");
- return;
- }
- lexer_get(ctx->lexer);
- } else {
- struct ovnact_gen_option *o = &event->options[event->n_options++];
- memset(o, 0, sizeof *o);
- parse_gen_opt(ctx, o,
- &ctx->pp->controller_event_opts->event_opts[event_type],
- event_to_string(event_type));
- }
+ struct ovnact_gen_option *o = &event->options[event->n_options++];
+ memset(o, 0, sizeof *o);
+ parse_gen_opt(ctx, o,
+ &ctx->pp->controller_event_opts->event_opts[event_type],
+ event_to_string(event_type));
+
if (ctx->lexer->error) {
return;
}
@@ -2413,7 +2382,6 @@ static void
ovnact_controller_event_free(struct ovnact_controller_event *event)
{
free_gen_options(event->options, event->n_options);
- free(event->meter);
}
static void
@@ -37,6 +37,7 @@ static char *copp_proto_names[COPP_PROTO_MAX] = {
[COPP_ND_NS_RESOLVE] = "nd-ns-resolve",
[COPP_ND_RA_OPTS] = "nd-ra-opts",
[COPP_TCP_RESET] = "tcp-reset",
+ [COPP_REJECT] = "reject",
[COPP_BFD] = "bfd",
};
@@ -36,6 +36,7 @@ enum copp_proto {
COPP_ND_RA_OPTS,
COPP_TCP_RESET,
COPP_BFD,
+ COPP_REJECT,
COPP_PROTO_MAX,
COPP_PROTO_INVALID = COPP_PROTO_MAX,
};
@@ -30,7 +30,8 @@ ddlog_sources = \
northd/ovn.dl \
northd/ovn.rs \
northd/helpers.dl \
- northd/bitwise.dl
+ northd/bitwise.dl \
+ northd/copp.dl
ddlog_nodist_sources = \
northd/OVN_Northbound.dl \
northd/OVN_Southbound.dl
new file mode 100644
@@ -0,0 +1,30 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function cOPP_ARP() : string { "arp" }
+function cOPP_ARP_RESOLVE() : string { "arp-resolve" }
+function cOPP_DHCPV4_OPTS() : string { "dhcpv4-opts" }
+function cOPP_DHCPV6_OPTS() : string { "dhcpv6-opts" }
+function cOPP_DNS() : string { "dns" }
+function cOPP_EVENT_ELB() : string { "event-elb" }
+function cOPP_ICMP4_ERR() : string { "icmp4-error" }
+function cOPP_ICMP6_ERR() : string { "icmp6-error" }
+function cOPP_IGMP() : string { "igmp" }
+function cOPP_ND_NA() : string { "nd-na" }
+function cOPP_ND_NS() : string { "nd-ns" }
+function cOPP_ND_NS_RESOLVE() : string { "nd-ns-resolve" }
+function cOPP_ND_RA_OPTS() : string { "nd-ra-opts" }
+function cOPP_TCP_RESET() : string { "tcp-reset" }
+function cOPP_REJECT() : string { "reject" }
+function cOPP_BFD() : string { "bfd" }
@@ -431,6 +431,23 @@ LogicalRouterLBs(lr, vec_empty()) :-
nb::Logical_Router(._uuid = lr),
not LogicalRouterLB(lr, _).
+// LogicalRouterCopp maps from each LR to its collection of Copp meters,
+// dropping any Copp meter whose meter name doesn't exist.
+relation LogicalRouterCopp(lr: uuid, meters: Map<string,string>)
+LogicalRouterCopp(lr, meters) :- LogicalRouterCopp0(lr, meters).
+LogicalRouterCopp(lr, map_empty()) :-
+ nb::Logical_Router(._uuid = lr),
+ not LogicalRouterCopp0(lr, _).
+
+relation LogicalRouterCopp0(lr: uuid, meters: Map<string,string>)
+LogicalRouterCopp0(lr, meters) :-
+ nb::Logical_Router(._uuid = lr, .copp = Some{copp_uuid}),
+ nb::Copp(._uuid = copp_uuid, .meters = meters),
+ var entry = FlatMap(meters),
+ (var copp_id, var meter_name) = entry,
+ &nb::Meter(.name = meter_name),
+ var meters = (copp_id, meter_name).group_by(lr).to_map().
+
/* Router relation collects all attributes of a logical router.
*
* `l3dgw_port` - optional redirect port (see `DistributedGatewayPort`)
@@ -466,6 +483,7 @@ typedef Router = Router {
mcast_cfg: Intern<McastRouterCfg>,
learn_from_arp_request: bool,
force_lb_snat: bool,
+ copp: Map<string, string>,
}
relation Router[Intern<Router>]
@@ -492,13 +510,15 @@ Router[Router{
.lbs = lbs,
.mcast_cfg = mcast_cfg,
.learn_from_arp_request = learn_from_arp_request,
- .force_lb_snat = force_lb_snat}.intern()] :-
+ .force_lb_snat = force_lb_snat,
+ .copp = copp}.intern()] :-
lr in nb::Logical_Router(),
lr.is_enabled(),
LogicalRouterRedirectPort(lr._uuid, l3dgw_port),
LogicalRouterNATs(lr._uuid, nats),
LogicalRouterLBs(lr._uuid, lbs),
LogicalRouterSnatIPs(lr._uuid, snat_ips),
+ LogicalRouterCopp(lr._uuid, copp),
mcast_cfg in &McastRouterCfg(.datapath = lr._uuid),
var learn_from_arp_request = lr.options.get_bool_def("always_learn_from_arp_request", true),
var force_lb_snat = lb_force_snat_router_ip(lr.options).
@@ -202,6 +202,23 @@ LogicalSwitchHasNonRouterPort(ls, false) :-
nb::Logical_Switch(._uuid = ls),
not LogicalSwitchHasNonRouterPort0(ls).
+// LogicalSwitchCopp maps from each LS to its collection of Copp meters,
+// dropping any Copp meter whose meter name doesn't exist.
+relation LogicalSwitchCopp(ls: uuid, meters: Map<string,string>)
+LogicalSwitchCopp(ls, meters) :- LogicalSwitchCopp0(ls, meters).
+LogicalSwitchCopp(ls, map_empty()) :-
+ nb::Logical_Switch(._uuid = ls),
+ not LogicalSwitchCopp0(ls, _).
+
+relation LogicalSwitchCopp0(ls: uuid, meters: Map<string,string>)
+LogicalSwitchCopp0(ls, meters) :-
+ nb::Logical_Switch(._uuid = ls, .copp = Some{copp_uuid}),
+ nb::Copp(._uuid = copp_uuid, .meters = meters),
+ var entry = FlatMap(meters),
+ (var copp_id, var meter_name) = entry,
+ &nb::Meter(.name = meter_name),
+ var meters = (copp_id, meter_name).group_by(ls).to_map().
+
/* Switch relation collects all attributes of a logical switch */
typedef Switch = Switch {
@@ -223,6 +240,7 @@ typedef Switch = Switch {
ipv6_prefix: Option<in6_addr>,
mcast_cfg: Intern<McastSwitchCfg>,
is_vlan_transparent: bool,
+ copp: Map<string, string>,
/* Does this switch have at least one port with type != "router"? */
has_non_router_port: bool
@@ -259,6 +277,7 @@ Switch[Switch{
.ipv6_prefix = ipv6_prefix,
.mcast_cfg = mcast_cfg,
.has_non_router_port = has_non_router_port,
+ .copp = copp,
.is_vlan_transparent = is_vlan_transparent
}.intern()] :-
nb::Logical_Switch[ls],
@@ -269,6 +288,7 @@ Switch[Switch{
LogicalSwitchHasUnknownPorts(ls._uuid, has_unknown_ports),
LogicalSwitchLocalnetPorts(ls._uuid, localnet_ports),
LogicalSwitchHasNonRouterPort(ls._uuid, has_non_router_port),
+ LogicalSwitchCopp(ls._uuid, copp),
mcast_cfg in &McastSwitchCfg(.datapath = ls._uuid),
var subnet =
match (ls.other_config.get("subnet")) {
@@ -3460,11 +3460,11 @@ ovn_lb_svc_create(struct northd_context *ctx, struct ovn_northd_lb *lb,
}
}
-static
-void build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
- struct ovn_northd_lb_vip *lb_vip_nb,
- struct ds *action, char *selection_fields,
- bool ls_dp)
+static bool
+build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
+ struct ovn_northd_lb_vip *lb_vip_nb,
+ struct ds *action, char *selection_fields,
+ bool ls_dp)
{
bool skip_hash_fields = false, reject = false;
@@ -3516,6 +3516,7 @@ void build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
ds_chomp(action, ')');
ds_put_format(action, "; hash_fields=\"%s\");", selection_fields);
}
+ return reject;
}
static void
@@ -4351,11 +4352,15 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od,
ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
NULL, NULL, OVS_SOURCE_LOCATOR)
-#define ovn_lflow_add_ctrl(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
- CTRL_METER) \
+#define ovn_lflow_metered(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
+ CTRL_METER) \
ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \
ACTIONS, CTRL_METER, NULL)
+#define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \
+ ACTIONS, CTRL_METER) \
+ ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \
+ CTRL_METER, NULL, OVS_SOURCE_LOCATOR)
static struct ovn_lflow *
ovn_lflow_find(const struct hmap *lflows, const struct ovn_datapath *od,
@@ -5300,7 +5305,6 @@ ls_has_dns_records(const struct nbrec_logical_switch *nbs)
static bool
build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
const struct nbrec_load_balancer *lb,
- struct shash *meter_groups,
struct ds *match, struct ds *action)
{
bool controller_event = smap_get_bool(&lb->options, "event", false) ||
@@ -5314,11 +5318,6 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
ds_clear(match);
bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip);
- char *meter = "";
-
- if (meter_groups && shash_find(meter_groups, "event-elb")) {
- meter = "event-elb";
- }
ds_put_format(match, "ip%s.dst == %s && %s",
ipv4 ? "4": "6", lb_vip->vip_str, lb->protocol);
@@ -5333,11 +5332,11 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
ds_put_format(action,
"trigger_event(event = \"%s\", "
- "meter = \"%s\", vip = \"%s\", "
+ "vip = \"%s\", "
"protocol = \"%s\", "
"load_balancer = \"" UUID_FMT "\");",
event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS),
- meter, vip, lb->protocol,
+ vip, lb->protocol,
UUID_ARGS(&lb->header_.uuid));
if (lb_vip->vip_port) {
free(vip);
@@ -5693,9 +5692,12 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
"reject { "
"/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
"outport <-> inport; %s };", next_action);
- ovn_lflow_add_with_hint(lflows, od, stage,
- acl->priority + OVN_ACL_PRI_OFFSET,
- ds_cstr(&match), ds_cstr(&actions), stage_hint);
+ ovn_lflow_add_with_hint__(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ ds_cstr(&match), ds_cstr(&actions),
+ copp_meter_get(COPP_REJECT, od->nbs->copp,
+ meter_groups),
+ stage_hint);
free(next_action);
ds_destroy(&match);
@@ -6191,7 +6193,8 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) {
static void
build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
- struct ds *match, struct ds *action)
+ struct ds *match, struct ds *action,
+ struct shash *meter_groups)
{
for (size_t i = 0; i < lb->n_vips; i++) {
struct ovn_lb_vip *lb_vip = &lb->vips[i];
@@ -6233,8 +6236,9 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
}
/* New connections in Ingress table. */
- build_lb_vip_actions(lb_vip, lb_vip_nb, action,
- lb->selection_fields, true);
+ const char *meter = NULL;
+ bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, action,
+ lb->selection_fields, true);
ds_put_format(match, "ct.new && %s.dst == %s", ip_match,
lb_vip->vip_str);
@@ -6244,9 +6248,16 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
priority = 120;
}
for (size_t j = 0; j < lb->n_nb_ls; j++) {
- ovn_lflow_add_with_hint(lflows, lb->nb_ls[j], S_SWITCH_IN_STATEFUL,
- priority, ds_cstr(match),
- ds_cstr(action), &lb->nlb->header_);
+ struct ovn_datapath *od = lb->nb_ls[j];
+
+ if (reject) {
+ meter = copp_meter_get(COPP_REJECT, od->nbs->copp,
+ meter_groups);
+ }
+ ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_STATEFUL,
+ priority, ds_cstr(match),
+ ds_cstr(action), meter,
+ &lb->nlb->header_);
}
}
}
@@ -6851,6 +6862,7 @@ static void
build_dhcpv4_options_flows(struct ovn_port *op,
struct lport_addresses *lsp_addrs,
const char *json_key, bool is_external,
+ struct shash *meter_groups,
struct hmap *lflows)
{
struct ds match = DS_EMPTY_INITIALIZER;
@@ -6874,11 +6886,14 @@ build_dhcpv4_options_flows(struct ovn_port *op,
op->json_key);
}
- ovn_lflow_add_with_hint(lflows, op->od,
- S_SWITCH_IN_DHCP_OPTIONS, 100,
- ds_cstr(&match),
- ds_cstr(&options_action),
- &op->nbsp->dhcpv4_options->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od,
+ S_SWITCH_IN_DHCP_OPTIONS, 100,
+ ds_cstr(&match),
+ ds_cstr(&options_action),
+ copp_meter_get(COPP_DHCPV4_OPTS,
+ op->od->nbs->copp,
+ meter_groups),
+ &op->nbsp->dhcpv4_options->header_);
ds_clear(&match);
/* Allow ip4.src = OFFER_IP and
* ip4.dst = {SERVER_IP, 255.255.255.255} for the below
@@ -6898,11 +6913,14 @@ build_dhcpv4_options_flows(struct ovn_port *op,
op->json_key);
}
- ovn_lflow_add_with_hint(lflows, op->od,
- S_SWITCH_IN_DHCP_OPTIONS, 100,
- ds_cstr(&match),
- ds_cstr(&options_action),
- &op->nbsp->dhcpv4_options->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od,
+ S_SWITCH_IN_DHCP_OPTIONS, 100,
+ ds_cstr(&match),
+ ds_cstr(&options_action),
+ copp_meter_get(COPP_DHCPV4_OPTS,
+ op->od->nbs->copp,
+ meter_groups),
+ &op->nbsp->dhcpv4_options->header_);
ds_clear(&match);
/* If REGBIT_DHCP_OPTS_RESULT is set, it means the
@@ -6936,6 +6954,7 @@ static void
build_dhcpv6_options_flows(struct ovn_port *op,
struct lport_addresses *lsp_addrs,
const char *json_key, bool is_external,
+ struct shash *meter_groups,
struct hmap *lflows)
{
struct ds match = DS_EMPTY_INITIALIZER;
@@ -6958,11 +6977,14 @@ build_dhcpv6_options_flows(struct ovn_port *op,
op->json_key);
}
- ovn_lflow_add_with_hint(lflows, op->od,
- S_SWITCH_IN_DHCP_OPTIONS, 100,
- ds_cstr(&match),
- ds_cstr(&options_action),
- &op->nbsp->dhcpv6_options->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od,
+ S_SWITCH_IN_DHCP_OPTIONS, 100,
+ ds_cstr(&match),
+ ds_cstr(&options_action),
+ copp_meter_get(COPP_DHCPV6_OPTS,
+ op->od->nbs->copp,
+ meter_groups),
+ &op->nbsp->dhcpv6_options->header_);
/* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the
* put_dhcpv6_opts action is successful */
@@ -7152,6 +7174,7 @@ static void
build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
struct hmap *lflows,
struct hmap *ports,
+ struct shash *meter_groups,
struct ds *actions,
struct ds *match)
{
@@ -7297,11 +7320,14 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
op->lsp_addrs[i].ipv6_addrs[j].addr_s,
op->lsp_addrs[i].ipv6_addrs[j].addr_s,
op->lsp_addrs[i].ea_s);
- ovn_lflow_add_with_hint(lflows, op->od,
- S_SWITCH_IN_ARP_ND_RSP, 50,
- ds_cstr(match),
- ds_cstr(actions),
- &op->nbsp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od,
+ S_SWITCH_IN_ARP_ND_RSP, 50,
+ ds_cstr(match),
+ ds_cstr(actions),
+ copp_meter_get(COPP_ND_NA,
+ op->od->nbs->copp,
+ meter_groups),
+ &op->nbsp->header_);
/* Do not reply to a solicitation from the port that owns
* the address (otherwise DAD detection will fail). */
@@ -7421,7 +7447,8 @@ build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb,
* priority 100 flows. */
static void
build_lswitch_dhcp_options_and_response(struct ovn_port *op,
- struct hmap *lflows)
+ struct hmap *lflows,
+ struct shash *meter_groups)
{
if (op->nbsp) {
if (!lsp_is_enabled(op->nbsp) || lsp_is_router(op->nbsp)) {
@@ -7450,17 +7477,17 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op,
build_dhcpv4_options_flows(
op, &op->lsp_addrs[i],
op->od->localnet_ports[j]->json_key, is_external,
- lflows);
+ meter_groups, lflows);
build_dhcpv6_options_flows(
op, &op->lsp_addrs[i],
op->od->localnet_ports[j]->json_key, is_external,
- lflows);
+ meter_groups, lflows);
}
} else {
build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op->json_key,
- is_external, lflows);
+ is_external, meter_groups, lflows);
build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op->json_key,
- is_external, lflows);
+ is_external, meter_groups, lflows);
}
}
}
@@ -7490,13 +7517,15 @@ build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od,
*/
static void
build_lswitch_dns_lookup_and_response(struct ovn_datapath *od,
- struct hmap *lflows)
+ struct hmap *lflows,
+ struct shash *meter_groups)
{
if (od->nbs && ls_has_dns_records(od->nbs)) {
-
- ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100,
- "udp.dst == 53",
- REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;");
+ ovn_lflow_metered(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100,
+ "udp.dst == 53",
+ REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;",
+ copp_meter_get(COPP_DNS, od->nbs->copp,
+ meter_groups));
const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; "
"udp.dst = udp.src; udp.src = 53; outport = inport; "
"flags.loopback = 1; output;";
@@ -7533,7 +7562,8 @@ build_lswitch_external_port(struct ovn_port *op,
static void
build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
struct hmap *lflows,
- struct ds *actions)
+ struct ds *actions,
+ struct shash *meter_groups)
{
if (od->nbs) {
@@ -7554,12 +7584,16 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
}
ds_put_cstr(actions, "igmp;");
/* Punt IGMP traffic to controller. */
- ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
- "ip4 && ip.proto == 2", ds_cstr(actions));
+ ovn_lflow_add_unique(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
+ "ip4 && ip.proto == 2", ds_cstr(actions),
+ copp_meter_get(COPP_IGMP, od->nbs->copp,
+ meter_groups));
/* Punt MLD traffic to controller. */
- ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
- "mldv1 || mldv2", ds_cstr(actions));
+ ovn_lflow_add_unique(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
+ "mldv1 || mldv2", ds_cstr(actions),
+ copp_meter_get(COPP_IGMP, od->nbs->copp,
+ meter_groups));
/* Flood all IP multicast traffic destined to 224.0.0.X to all
* ports - RFC 4541, section 2.1.2, item 2.
@@ -8951,7 +8985,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
struct ovn_northd_lb *lb,
struct ovn_northd_lb_vip *vips_nb,
struct hmap *lflows,
- struct ds *match, struct ds *action)
+ struct ds *match, struct ds *action,
+ struct shash *meter_groups)
{
char *skip_snat_new_action = NULL;
char *skip_snat_est_action = NULL;
@@ -8961,8 +8996,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
ds_clear(match);
ds_clear(action);
- build_lb_vip_actions(lb_vip, vips_nb, action,
- lb->selection_fields, false);
+ bool reject = build_lb_vip_actions(lb_vip, vips_nb, action,
+ lb->selection_fields, false);
/* Higher priority rules are added for load-balancing in DNAT
* table. For every match (on a VIP[:port]), we add two flows.
@@ -9045,6 +9080,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
char *new_match_p = new_match;
char *est_match_p = est_match;
char *est_actions = NULL;
+ const char *meter = NULL;
+
+ if (reject) {
+ meter = copp_meter_get(COPP_REJECT, od->nbr->copp, meter_groups);
+ }
if (sset_contains(&od->external_ips, lb_vip->vip_str)) {
/* The load balancer vip is also present in the NAT entries.
@@ -9080,18 +9120,18 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
}
if (snat_type == SKIP_SNAT) {
- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
- new_match_p, skip_snat_new_action,
- &lb->nlb->header_);
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, prio,
+ new_match_p, skip_snat_new_action,
+ meter, &lb->nlb->header_);
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
est_match_p, skip_snat_est_action,
&lb->nlb->header_);
} else if (snat_type == FORCE_SNAT) {
char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s",
ds_cstr(action));
- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
- new_match_p, new_actions,
- &lb->nlb->header_);
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, prio,
+ new_match_p, new_actions,
+ meter, &lb->nlb->header_);
free(new_actions);
est_actions = xasprintf("flags.force_snat_for_lb = 1; "
@@ -9100,9 +9140,9 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
est_match_p, est_actions,
&lb->nlb->header_);
} else {
- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
- new_match_p, ds_cstr(action),
- &lb->nlb->header_);
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, prio,
+ new_match_p, ds_cstr(action),
+ meter, &lb->nlb->header_);
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
est_match_p, "next;",
&lb->nlb->header_);
@@ -9164,14 +9204,18 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
struct ovn_lb_vip *lb_vip = &lb->vips[i];
/* pre-stateful lb */
- if (!build_empty_lb_event_flow(lb_vip, lb->nlb, meter_groups,
- match, action)) {
+ if (!build_empty_lb_event_flow(lb_vip, lb->nlb, match, action)) {
continue;
}
for (size_t j = 0; j < lb->n_nb_ls; j++) {
- ovn_lflow_add_with_hint(lflows, lb->nb_ls[j],
- S_SWITCH_IN_PRE_LB, 130, ds_cstr(match),
- ds_cstr(action), &lb->nlb->header_);
+ struct ovn_datapath *od = lb->nb_ls[j];
+ ovn_lflow_add_with_hint__(lflows, od,
+ S_SWITCH_IN_PRE_LB, 130, ds_cstr(match),
+ ds_cstr(action),
+ copp_meter_get(COPP_EVENT_ELB,
+ od->nbs->copp,
+ meter_groups),
+ &lb->nlb->header_);
}
/* Ignore L4 port information in the key because fragmented packets
* may not have L4 information. The pre-stateful table will send
@@ -9185,7 +9229,7 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
* a higher priority rule for load balancing below also commits the
* connection, so it is okay if we do not hit the above match on
* REGBIT_CONNTRACK_COMMIT. */
- build_lb_rules(lflows, lb, match, action);
+ build_lb_rules(lflows, lb, match, action, meter_groups);
}
static void
@@ -9201,16 +9245,20 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
struct ovn_lb_vip *lb_vip = &lb->vips[i];
build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i],
- lflows, match, action);
+ lflows, match, action,
+ meter_groups);
- if (!build_empty_lb_event_flow(lb_vip, lb->nlb, meter_groups,
- match, action)) {
+ if (!build_empty_lb_event_flow(lb_vip, lb->nlb, match, action)) {
continue;
}
for (size_t j = 0; j < lb->n_nb_lr; j++) {
- ovn_lflow_add_with_hint(lflows, lb->nb_lr[j], S_ROUTER_IN_DNAT,
- 130, ds_cstr(match), ds_cstr(action),
- &lb->nlb->header_);
+ struct ovn_datapath *od = lb->nb_lr[j];
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT,
+ 130, ds_cstr(match), ds_cstr(action),
+ copp_meter_get(COPP_EVENT_ELB,
+ od->nbr->copp,
+ meter_groups),
+ &lb->nlb->header_);
}
}
@@ -9512,7 +9560,7 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
const char *sn_ip_address, const char *eth_addr,
struct ds *extra_match, bool drop, uint16_t priority,
const struct ovsdb_idl_row *hint,
- struct hmap *lflows)
+ struct hmap *lflows, struct shash *meter_groups)
{
struct ds match = DS_EMPTY_INITIALIZER;
struct ds actions = DS_EMPTY_INITIALIZER;
@@ -9534,6 +9582,8 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
if (drop) {
ds_put_format(&actions, "drop;");
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
+ ds_cstr(&match), ds_cstr(&actions), hint);
} else {
ds_put_format(&actions,
"%s { "
@@ -9550,11 +9600,13 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
ip_address,
ip_address,
eth_addr);
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
+ ds_cstr(&match), ds_cstr(&actions),
+ copp_meter_get(COPP_ND_NA, od->nbr->copp,
+ meter_groups),
+ hint);
}
- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
- ds_cstr(&match), ds_cstr(&actions), hint);
-
ds_destroy(&match);
ds_destroy(&actions);
}
@@ -9562,7 +9614,8 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
static void
build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od,
struct ovn_nat *nat_entry,
- struct hmap *lflows)
+ struct hmap *lflows,
+ struct shash *meter_groups)
{
struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
const struct nbrec_nat *nat = nat_entry->nb;
@@ -9572,7 +9625,7 @@ build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od,
ext_addrs->ipv6_addrs[0].addr_s,
ext_addrs->ipv6_addrs[0].sn_addr_s,
REG_INPORT_ETH_ADDR, NULL, false, 90,
- &nat->header_, lflows);
+ &nat->header_, lflows, meter_groups);
} else {
build_lrouter_arp_flow(od, NULL,
ext_addrs->ipv4_addrs[0].addr_s,
@@ -9584,7 +9637,8 @@ build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od,
static void
build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
struct ovn_nat *nat_entry,
- struct hmap *lflows)
+ struct hmap *lflows,
+ struct shash *meter_groups)
{
struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
const struct nbrec_nat *nat = nat_entry->nb;
@@ -9627,12 +9681,12 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
ext_addrs->ipv6_addrs[0].addr_s,
ext_addrs->ipv6_addrs[0].sn_addr_s,
mac_s, &match, false, 92,
- &nat->header_, lflows);
+ &nat->header_, lflows, meter_groups);
build_lrouter_nd_flow(op->od, op, "nd_na",
ext_addrs->ipv6_addrs[0].addr_s,
ext_addrs->ipv6_addrs[0].sn_addr_s,
mac_s, NULL, true, 91,
- &nat->header_, lflows);
+ &nat->header_, lflows, meter_groups);
} else {
build_lrouter_arp_flow(op->od, op,
ext_addrs->ipv4_addrs[0].addr_s,
@@ -9805,7 +9859,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op,
}
static void
-build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op)
+build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op,
+ struct shash *meter_groups)
{
if (!op->has_bfd) {
return;
@@ -9824,9 +9879,11 @@ build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op)
ds_clear(&match);
ds_put_format(&match, "ip4.dst == %s && udp.dst == 3784",
ds_cstr(&ip_list));
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
- ds_cstr(&match), "handle_bfd_msg(); ",
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
+ ds_cstr(&match), "handle_bfd_msg(); ",
+ copp_meter_get(COPP_BFD, op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
if (op->lrp_networks.n_ipv6_addrs) {
ds_clear(&ip_list);
@@ -9841,9 +9898,11 @@ build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op)
ds_clear(&match);
ds_put_format(&match, "ip6.dst == %s && udp.dst == 3784",
ds_cstr(&ip_list));
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
- ds_cstr(&match), "handle_bfd_msg(); ",
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
+ ds_cstr(&match), "handle_bfd_msg(); ",
+ copp_meter_get(COPP_BFD, op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
ds_destroy(&ip_list);
@@ -9923,7 +9982,8 @@ build_adm_ctrl_flows_for_lrouter_port(
static void
build_neigh_learning_flows_for_lrouter(
struct ovn_datapath *od, struct hmap *lflows,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
if (od->nbr) {
@@ -10003,14 +10063,20 @@ build_neigh_learning_flows_for_lrouter(
ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100,
ds_cstr(match), "next;");
- ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
- "arp", "put_arp(inport, arp.spa, arp.sha); next;");
+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
+ "arp", "put_arp(inport, arp.spa, arp.sha); next;",
+ copp_meter_get(COPP_ARP, od->nbr->copp,
+ meter_groups));
- ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
- "nd_na", "put_nd(inport, nd.target, nd.tll); next;");
+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
+ "nd_na", "put_nd(inport, nd.target, nd.tll); next;",
+ copp_meter_get(COPP_ND_NA, od->nbr->copp,
+ meter_groups));
- ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
- "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;");
+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
+ "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;",
+ copp_meter_get(COPP_ND_NS, od->nbr->copp,
+ meter_groups));
}
}
@@ -10085,7 +10151,8 @@ build_neigh_learning_flows_for_lrouter_port(
static void
build_ND_RA_flows_for_lrouter_port(
struct ovn_port *op, struct hmap *lflows,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
if (!op->nbrp || op->nbrp->peer || !op->peer) {
return;
@@ -10178,9 +10245,12 @@ build_ND_RA_flows_for_lrouter_port(
if (add_rs_response_flow) {
ds_put_cstr(actions, "); next;");
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS,
- 50, ds_cstr(match), ds_cstr(actions),
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS,
+ 50, ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(COPP_ND_RA_OPTS,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(actions);
ds_clear(match);
ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && "
@@ -10833,7 +10903,8 @@ static void
build_check_pkt_len_flows_for_lrouter(
struct ovn_datapath *od, struct hmap *lflows,
struct hmap *ports,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
if (od->nbr) {
@@ -10895,10 +10966,14 @@ build_check_pkt_len_flows_for_lrouter(
rp->lrp_networks.ipv4_addrs[0].addr_s,
gw_mtu,
ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
- ovn_lflow_add_with_hint(lflows, od,
- S_ROUTER_IN_LARGER_PKTS, 50,
- ds_cstr(match), ds_cstr(actions),
- &rp->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, od,
+ S_ROUTER_IN_LARGER_PKTS, 50,
+ ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(
+ COPP_ICMP4_ERR,
+ rp->od->nbr->copp,
+ meter_groups),
+ &rp->nbrp->header_);
}
if (rp->lrp_networks.ipv6_addrs) {
@@ -10924,10 +10999,14 @@ build_check_pkt_len_flows_for_lrouter(
rp->lrp_networks.ipv6_addrs[0].addr_s,
gw_mtu,
ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
- ovn_lflow_add_with_hint(lflows, od,
- S_ROUTER_IN_LARGER_PKTS, 50,
- ds_cstr(match), ds_cstr(actions),
- &rp->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, od,
+ S_ROUTER_IN_LARGER_PKTS, 50,
+ ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(
+ COPP_ICMP6_ERR,
+ rp->od->nbr->copp,
+ meter_groups),
+ &rp->nbrp->header_);
}
}
}
@@ -10982,7 +11061,8 @@ build_gateway_redirect_flows_for_lrouter(
static void
build_arp_request_flows_for_lrouter(
struct ovn_datapath *od, struct hmap *lflows,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
if (od->nbr) {
for (int i = 0; i < od->nbr->n_static_routes; i++) {
@@ -11019,26 +11099,33 @@ build_arp_request_flows_for_lrouter(
"};", ETH_ADDR_ARGS(eth_dst), sn_addr_s,
route->nexthop);
- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200,
- ds_cstr(match), ds_cstr(actions),
- &route->header_);
- }
-
- ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
- "eth.dst == 00:00:00:00:00:00 && ip4",
- "arp { "
- "eth.dst = ff:ff:ff:ff:ff:ff; "
- "arp.spa = " REG_SRC_IPV4 "; "
- "arp.tpa = " REG_NEXT_HOP_IPV4 "; "
- "arp.op = 1; " /* ARP request */
- "output; "
- "};");
- ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
- "eth.dst == 00:00:00:00:00:00 && ip6",
- "nd_ns { "
- "nd.target = " REG_NEXT_HOP_IPV6 "; "
- "output; "
- "};");
+ ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200,
+ ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(COPP_ND_NS_RESOLVE,
+ od->nbr->copp,
+ meter_groups),
+ &route->header_);
+ }
+
+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
+ "eth.dst == 00:00:00:00:00:00 && ip4",
+ "arp { "
+ "eth.dst = ff:ff:ff:ff:ff:ff; "
+ "arp.spa = " REG_SRC_IPV4 "; "
+ "arp.tpa = " REG_NEXT_HOP_IPV4 "; "
+ "arp.op = 1; " /* ARP request */
+ "output; "
+ "};",
+ copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp,
+ meter_groups));
+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
+ "eth.dst == 00:00:00:00:00:00 && ip6",
+ "nd_ns { "
+ "nd.target = " REG_NEXT_HOP_IPV6 "; "
+ "output; "
+ "};",
+ copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp,
+ meter_groups));
ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;");
}
}
@@ -11169,7 +11256,8 @@ build_dhcpv6_reply_flows_for_lrouter_port(
static void
build_ipv6_input_flows_for_lrouter_port(
struct ovn_port *op, struct hmap *lflows,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
if (op->nbrp && (!op->derived)) {
/* No ingress packets are accepted on a chassisredirect
@@ -11212,7 +11300,7 @@ build_ipv6_input_flows_for_lrouter_port(
op->lrp_networks.ipv6_addrs[i].addr_s,
op->lrp_networks.ipv6_addrs[i].sn_addr_s,
REG_INPORT_ETH_ADDR, match, false, 90,
- &op->nbrp->header_, lflows);
+ &op->nbrp->header_, lflows, meter_groups);
}
/* UDP/TCP/SCTP port unreachable */
@@ -11226,9 +11314,13 @@ build_ipv6_input_flows_for_lrouter_port(
"eth.dst <-> eth.src; "
"ip6.dst <-> ip6.src; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_TCP_RESET,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11238,9 +11330,13 @@ build_ipv6_input_flows_for_lrouter_port(
"eth.dst <-> eth.src; "
"ip6.dst <-> ip6.src; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_TCP_RESET,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11253,9 +11349,13 @@ build_ipv6_input_flows_for_lrouter_port(
"icmp6.type = 1; "
"icmp6.code = 4; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_ICMP6_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11268,9 +11368,13 @@ build_ipv6_input_flows_for_lrouter_port(
"icmp6.type = 1; "
"icmp6.code = 3; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 70, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 70, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_ICMP6_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
}
@@ -11301,9 +11405,12 @@ build_ipv6_input_flows_for_lrouter_port(
"icmp6.code = 0; /* TTL exceeded in transit */ "
"next; };",
op->lrp_networks.ipv6_addrs[i].addr_s);
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
- ds_cstr(match), ds_cstr(actions),
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
+ ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(COPP_ICMP6_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
}
@@ -11311,7 +11418,8 @@ build_ipv6_input_flows_for_lrouter_port(
static void
build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od,
- struct hmap *lflows)
+ struct hmap *lflows,
+ struct shash *meter_groups)
{
if (od->nbr) {
@@ -11337,7 +11445,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od,
if (!strcmp(nat_entry->nb->type, "snat")) {
continue;
}
- build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows);
+ build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups);
}
/* Now handle SNAT entries too, one per unique SNAT IP. */
@@ -11352,7 +11460,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od,
struct ovn_nat *nat_entry =
CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
struct ovn_nat, ext_addr_list_node);
- build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows);
+ build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups);
}
}
}
@@ -11361,7 +11469,8 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od,
static void
build_lrouter_ipv4_ip_input(struct ovn_port *op,
struct hmap *lflows,
- struct ds *match, struct ds *actions)
+ struct ds *match, struct ds *actions,
+ struct shash *meter_groups)
{
/* No ingress packets are accepted on a chassisredirect
* port, so no need to program flows for that port. */
@@ -11399,7 +11508,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
}
/* BFD msg handling */
- build_lrouter_bfd_flows(lflows, op);
+ build_lrouter_bfd_flows(lflows, op, meter_groups);
/* ICMP time exceeded */
for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
@@ -11419,9 +11528,12 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
"ip.ttl = 255; "
"next; };",
op->lrp_networks.ipv4_addrs[i].addr_s);
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
- ds_cstr(match), ds_cstr(actions),
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
+ ds_cstr(match), ds_cstr(actions),
+ copp_meter_get(COPP_ICMP4_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
/* ARP reply. These flows reply to ARP requests for the router's own
@@ -11498,7 +11610,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
build_lrouter_nd_flow(op->od, op, "nd_na",
ip_address, NULL, REG_INPORT_ETH_ADDR,
- match, false, 90, NULL, lflows);
+ match, false, 90, NULL,
+ lflows, meter_groups);
}
if (!op->od->is_gw_router && !op->od->l3dgw_port) {
@@ -11515,9 +11628,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
"icmp4.type = 3; "
"icmp4.code = 3; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_ICMP4_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11527,9 +11644,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
"eth.dst <-> eth.src; "
"ip4.dst <-> ip4.src; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_TCP_RESET,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11539,9 +11660,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
"eth.dst <-> eth.src; "
"ip4.dst <-> ip4.src; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 80, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_TCP_RESET,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
ds_clear(match);
ds_put_format(match,
@@ -11554,9 +11679,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
"icmp4.type = 3; "
"icmp4.code = 2; "
"next; };";
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 70, ds_cstr(match), action,
- &op->nbrp->header_);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 70, ds_cstr(match), action,
+ copp_meter_get(
+ COPP_ICMP4_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_);
}
}
@@ -11600,7 +11729,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
if (!strcmp(nat_entry->nb->type, "snat")) {
continue;
}
- build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
+ build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
+ meter_groups);
}
/* Now handle SNAT entries too, one per unique SNAT IP. */
@@ -11615,7 +11745,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
struct ovn_nat *nat_entry =
CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
struct ovn_nat, ext_addr_list_node);
- build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
+ build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows,
+ meter_groups);
}
}
}
@@ -12290,15 +12421,16 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
build_lswitch_input_port_sec_od(od, lsi->lflows);
build_lswitch_learn_fdb_od(od, lsi->lflows);
build_lswitch_arp_nd_responder_default(od, lsi->lflows);
- build_lswitch_dns_lookup_and_response(od, lsi->lflows);
+ build_lswitch_dns_lookup_and_response(od, lsi->lflows, lsi->meter_groups);
build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows);
- build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions);
+ build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions,
+ lsi->meter_groups);
build_lswitch_output_port_sec_od(od, lsi->lflows);
/* Build Logical Router Flows. */
build_adm_ctrl_flows_for_lrouter(od, lsi->lflows);
build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match,
- &lsi->actions);
+ &lsi->actions, lsi->meter_groups);
build_ND_RA_flows_for_lrouter(od, lsi->lflows);
build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports,
lsi->bfd_connections);
@@ -12307,13 +12439,14 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->ports);
build_arp_resolve_flows_for_lrouter(od, lsi->lflows);
build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->ports,
- &lsi->match, &lsi->actions);
+ &lsi->match, &lsi->actions,
+ lsi->meter_groups);
build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match,
&lsi->actions);
build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match,
- &lsi->actions);
+ &lsi->actions, lsi->meter_groups);
build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows);
- build_lrouter_arp_nd_for_datapath(od, lsi->lflows);
+ build_lrouter_arp_nd_for_datapath(od, lsi->lflows, lsi->meter_groups);
build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->lbs,
&lsi->match, &lsi->actions);
}
@@ -12333,9 +12466,11 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op,
&lsi->match);
build_lswitch_arp_nd_responder_known_ips(op, lsi->lflows,
lsi->ports,
+ lsi->meter_groups,
&lsi->actions,
&lsi->match);
- build_lswitch_dhcp_options_and_response(op, lsi->lflows);
+ build_lswitch_dhcp_options_and_response(op, lsi->lflows,
+ lsi->meter_groups);
build_lswitch_external_port(op, lsi->lflows);
build_lswitch_ip_unicast_lookup(op, lsi->lflows, lsi->mcgroups,
&lsi->actions, &lsi->match);
@@ -12349,16 +12484,17 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op,
&lsi->actions);
build_ip_routing_flows_for_lrouter_port(op, lsi->ports, lsi->lflows);
build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
- &lsi->actions);
+ &lsi->actions, lsi->meter_groups);
build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports,
&lsi->match, &lsi->actions);
build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
&lsi->actions);
build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match);
build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
- &lsi->match, &lsi->actions);
+ &lsi->match, &lsi->actions,
+ lsi->meter_groups);
build_lrouter_ipv4_ip_input(op, lsi->lflows,
- &lsi->match, &lsi->actions);
+ &lsi->match, &lsi->actions, lsi->meter_groups);
build_lrouter_force_snat_flows_op(op, lsi->lflows, &lsi->match,
&lsi->actions);
}
@@ -14,6 +14,7 @@
import OVN_Northbound as nb
import OVN_Southbound as sb
+import copp
import ovsdb
import allocate
import ovn
@@ -1626,6 +1627,22 @@ function mFF_N_LOG_REGS() : bit<32> = 10
* enables or disables this feature.
*/
+// A Flow including a 'controller_meter' column for metering.
+//
+// Most flows have an empty 'controller_meter' so we provide a Flow relation
+// that provides it as empty without specifying it explicitly.
+relation MeteredFlow(
+ logical_datapath: uuid,
+ stage: Stage,
+ priority: integer,
+ __match: string,
+ actions: string,
+ controller_meter: Option<string>,
+ external_ids: Map<string,string>
+)
+MeteredFlow(logical_datapath, stage, priority, __match, actions, None, external_ids) :-
+ Flow(logical_datapath, stage, priority, __match, actions, external_ids).
+
relation Flow(
logical_datapath: uuid,
stage: Stage,
@@ -1651,6 +1668,7 @@ relation AggregatedFlow (
priority: integer,
__match: string,
actions: string,
+ controller_meter: Option<string>,
external_ids: Map<string,string>
)
AggregatedFlow(.logical_datapaths = g.to_set(),
@@ -1658,18 +1676,20 @@ AggregatedFlow(.logical_datapaths = g.to_set(),
.priority = priority,
.__match = __match,
.actions = actions,
+ .controller_meter = controller_meter,
.external_ids = external_ids) :-
UseLogicalDatapathGroups[true],
- Flow(logical_datapath, stage, priority, __match, actions, external_ids),
- var g = logical_datapath.group_by((stage, priority, __match, actions, external_ids)).
+ MeteredFlow(logical_datapath, stage, priority, __match, actions, controller_meter, external_ids),
+ var g = logical_datapath.group_by((stage, priority, __match, actions, external_ids, controller_meter)).
AggregatedFlow(.logical_datapaths = set_singleton(logical_datapath),
.stage = stage,
.priority = priority,
.__match = __match,
.actions = actions,
+ .controller_meter = controller_meter,
.external_ids = external_ids) :-
UseLogicalDatapathGroups[false],
- Flow(logical_datapath, stage, priority, __match, actions, external_ids).
+ MeteredFlow(logical_datapath, stage, priority, __match, actions, controller_meter, external_ids).
for (f in AggregatedFlow()) {
var pipeline = if (f.stage.pipeline == Ingress) "ingress" else "egress" in
@@ -1677,26 +1697,26 @@ for (f in AggregatedFlow()) {
if (f.logical_datapaths.size() == 1) {
Some{var dp} = f.logical_datapaths.nth(0) in
sb::Out_Logical_Flow(
- ._uuid = hash128((dp, f.stage, f.priority, f.__match, f.actions, f.external_ids)),
+ ._uuid = hash128((dp, f.stage, f.priority, f.__match, f.actions, f.controller_meter, f.external_ids)),
.logical_datapath = Some{dp},
.logical_dp_group = None,
.pipeline = pipeline,
.table_id = f.stage.table_id,
.priority = f.priority,
- .controller_meter = None,
+ .controller_meter = f.controller_meter,
.__match = f.__match,
.actions = f.actions,
.external_ids = external_ids)
} else {
var group_uuid = hash128(f.logical_datapaths) in {
sb::Out_Logical_Flow(
- ._uuid = hash128((group_uuid, f.stage, f.priority, f.__match, f.actions, f.external_ids)),
+ ._uuid = hash128((group_uuid, f.stage, f.priority, f.__match, f.actions, f.controller_meter, f.external_ids)),
.logical_datapath = None,
.logical_dp_group = Some{group_uuid},
.pipeline = pipeline,
.table_id = f.stage.table_id,
.priority = f.priority,
- .controller_meter = None,
+ .controller_meter = f.controller_meter,
.__match = f.__match,
.actions = f.actions,
.external_ids = external_ids);
@@ -2031,18 +2051,8 @@ if (lsp.__type == "router" or lsp.__type == "localnet") {
.external_ids = stage_hint(lsp._uuid))
}
-relation HasEventElbMeter(has_meter: bool)
-
-HasEventElbMeter(true) :-
- &nb::Meter(.name = "event-elb").
-
-HasEventElbMeter(false) :-
- Unit(),
- not &nb::Meter(.name = "event-elb").
-
/* Empty LoadBalancer Controller event */
-function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>,
- meter: bool): Option<(string, string)> {
+function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>): Option<(string, string)> {
(var ip, var port) = match (ip_address_and_port_from_lb_key(key)) {
Some{(ip, port)} -> (ip, port),
_ -> return None
@@ -2052,10 +2062,6 @@ function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>,
Some{"tcp"} -> "tcp",
_ -> "udp"
};
- var meter = match (meter) {
- true -> "event-elb",
- _ -> ""
- };
var vip = match (port) {
0 -> "${ip}",
_ -> "${ip.to_bracketed_string()}:${port}"
@@ -2069,7 +2075,6 @@ function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>,
var action = "trigger_event("
"event = \"empty_lb_backends\", "
- "meter = \"${meter}\", "
"vip = \"${vip}\", "
"protocol = \"${protocol}\", "
"load_balancer = \"${uuid2str(lb._uuid)}\");";
@@ -2094,20 +2099,19 @@ LoadBalancerEmptyEvents(lb) :-
var local_events = local_options.get_bool_def("event", false),
global_events or local_events.
-Flow(.logical_datapath = sw._uuid,
- .stage = s_SWITCH_IN_PRE_LB(),
- .priority = 130,
- .__match = __match,
- .actions = __action,
- .external_ids = stage_hint(lb._uuid)) :-
+MeteredFlow(.logical_datapath = sw._uuid,
+ .stage = s_SWITCH_IN_PRE_LB(),
+ .priority = 130,
+ .__match = __match,
+ .actions = __action,
+ .controller_meter = sw.copp.get(cOPP_EVENT_ELB()),
+ .external_ids = stage_hint(lb._uuid)) :-
SwitchLBVIP(.sw_uuid = sw_uuid, .lb = lb, .vip = vip, .backends = backends),
LoadBalancerEmptyEvents(lb),
not lb.options.get_bool_def("reject", false),
sw in &Switch(._uuid = sw_uuid),
backends == "",
- HasEventElbMeter(has_elb_meter),
- Some {(var __match, var __action)} = build_empty_lb_event_flow(
- vip, lb, has_elb_meter).
+ Some {(var __match, var __action)} = build_empty_lb_event_flow(vip, lb).
/* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send
* packet to conntrack for defragmentation.
@@ -2298,6 +2302,7 @@ relation Reject(
stage: Stage,
acl: Intern<nb::ACL>,
fair_meter: bool,
+ controller_meter: Option<string>,
extra_match: string,
extra_actions: string)
@@ -2309,7 +2314,8 @@ function next_to_stage(stage: Stage): string {
};
"next(pipeline=${pipeline},table=${stage.table_id})"
}
-for (Reject(lsuuid, pipeline, stage, acl, fair_meter, extra_match_, extra_actions_)) {
+for (Reject(lsuuid, pipeline, stage, acl, fair_meter, controller_meter,
+ extra_match_, extra_actions_)) {
var extra_match = match (extra_match_) {
"" -> "",
s -> "(${s}) && "
@@ -2328,12 +2334,13 @@ for (Reject(lsuuid, pipeline, stage, acl, fair_meter, extra_match_, extra_action
"reject { "
"/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
"outport <-> inport; ${next_to_stage(next_stage)}; };" in
- Flow(.logical_datapath = lsuuid,
- .stage = stage,
- .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(acl._uuid))
+ MeteredFlow(.logical_datapath = lsuuid,
+ .stage = stage,
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = controller_meter,
+ .external_ids = stage_hint(acl._uuid))
}
/* build_acls */
@@ -2674,12 +2681,13 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {
* use for this datapath. In that case, the actions differ
* depending on whether the connection was previously committed
* to the connection tracker with ct_commit. */
+ var controller_meter = sw.copp.get(cOPP_REJECT()) in
if (has_stateful) {
/* If the packet is not tracked or not part of an established
* connection, then we can simply reject/drop it. */
var __match = "${rEGBIT_ACL_HINT_DROP()} == 1" in
if (acl.action == "reject") {
- Reject(sw._uuid, pipeline, stage, acl, fair_meter, __match, "")
+ Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match, "")
} else {
Flow(.logical_datapath = sw._uuid,
.stage = stage,
@@ -2702,7 +2710,7 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {
var __match = "${rEGBIT_ACL_HINT_BLOCK()} == 1" in
var actions = "ct_commit { ct_label.blocked = 1; }; " in
if (acl.action == "reject") {
- Reject(sw._uuid, pipeline, stage, acl, fair_meter, __match, actions)
+ Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match, actions)
} else {
Flow(.logical_datapath = sw._uuid,
.stage = stage,
@@ -2716,7 +2724,7 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {
* so a "reject/drop" ACL is simply the "reject/drop"
* logical flow action in all cases. */
if (acl.action == "reject") {
- Reject(sw._uuid, pipeline, stage, acl, fair_meter, "", "")
+ Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, "", "")
} else {
Flow(.logical_datapath = sw._uuid,
.stage = stage,
@@ -2958,7 +2966,7 @@ function ct_lb(backends: string,
}
function build_lb_vip_actions(lbvip: Intern<LBVIPWithStatus>,
stage: Stage,
- actions0: string): string {
+ actions0: string): (string, bool) {
var up_backends = set_empty();
for (pair in lbvip.backends) {
(var backend, var up) = pair;
@@ -2973,27 +2981,28 @@ function build_lb_vip_actions(lbvip: Intern<LBVIPWithStatus>,
if (up_backends.is_empty()) {
if (lbvip.lb.options.get_bool_def("reject", false)) {
- return "reg0 = 0; reject { outport <-> inport; ${next_to_stage(stage)};};"
+ return ("reg0 = 0; reject { outport <-> inport; ${next_to_stage(stage)};};", true)
} else if (lbvip.health_check.is_some()) {
- return "drop;"
+ return ("drop;", false)
} // else fall through
};
var actions = ct_lb(up_backends.to_vec().join(","), lbvip.lb.selection_fields,
lbvip.lb.protocol);
- actions0 ++ actions
+ (actions0 ++ actions, false)
}
-Flow(.logical_datapath = sw._uuid,
- .stage = s_SWITCH_IN_STATEFUL(),
- .priority = priority,
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(lb._uuid)) :-
+MeteredFlow(.logical_datapath = sw._uuid,
+ .stage = s_SWITCH_IN_STATEFUL(),
+ .priority = priority,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = meter,
+ .external_ids = stage_hint(lb._uuid)) :-
sw in &Switch(),
LBVIPWithStatus[lbvip@&LBVIPWithStatus{.lb = lb}],
sw.load_balancer.contains(lb._uuid),
var priority = if (lbvip.vip_port != 0) { 120 } else { 110 },
- var actions = {
+ (var actions, var reject) = {
/* Store the original destination IP to be used when generating
* hairpin flows.
*/
@@ -3013,6 +3022,11 @@ Flow(.logical_datapath = sw._uuid,
build_lb_vip_actions(lbvip, s_SWITCH_OUT_QOS_MARK(), actions0 ++ actions1)
},
+ var meter = if (reject) {
+ sw.copp.get(cOPP_REJECT())
+ } else {
+ None
+ },
var __match = "ct.new && " ++ get_match_for_lb_key(lbvip.vip_addr, lbvip.vip_port, lb.protocol, false, false).
/* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0).
@@ -3444,12 +3458,13 @@ for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam
"output; "
"};" in
{
- Flow(.logical_datapath = sw._uuid,
- .stage = s_SWITCH_IN_ARP_ND_RSP(),
- .priority = 50,
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(lsp._uuid));
+ MeteredFlow(.logical_datapath = sw._uuid,
+ .stage = s_SWITCH_IN_ARP_ND_RSP(),
+ .priority = 50,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = sw.copp.get(cOPP_ND_NA()),
+ .external_ids = stage_hint(lsp._uuid));
/* Do not reply to a solicitation from the port that owns the
* address (otherwise DAD detection will fail). */
@@ -3701,12 +3716,13 @@ for (lsp in &SwitchPort
"ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
"udp.src == 68 && udp.dst == 67" ++ sfx
in
- Flow(.logical_datapath = lsuuid,
- .stage = s_SWITCH_IN_DHCP_OPTIONS(),
- .priority = 100,
- .__match = __match,
- .actions = options_action,
- .external_ids = stage_hint(lsp.lsp._uuid));
+ MeteredFlow(.logical_datapath = lsuuid,
+ .stage = s_SWITCH_IN_DHCP_OPTIONS(),
+ .priority = 100,
+ .__match = __match,
+ .actions = options_action,
+ .controller_meter = lsp.sw.copp.get(cOPP_DHCPV4_OPTS()),
+ .external_ids = stage_hint(lsp.lsp._uuid));
/* Allow ip4.src = OFFER_IP and
* ip4.dst = {SERVER_IP, 255.255.255.255} for the below
@@ -3718,12 +3734,13 @@ for (lsp in &SwitchPort
*/
var __match = pfx ++ "eth.src == ${ea} && "
"${ipv4_addr_match} && udp.src == 68 && udp.dst == 67" ++ sfx in
- Flow(.logical_datapath = lsuuid,
- .stage = s_SWITCH_IN_DHCP_OPTIONS(),
- .priority = 100,
- .__match = __match,
- .actions = options_action,
- .external_ids = stage_hint(lsp.lsp._uuid));
+ MeteredFlow(.logical_datapath = lsuuid,
+ .stage = s_SWITCH_IN_DHCP_OPTIONS(),
+ .priority = 100,
+ .__match = __match,
+ .actions = options_action,
+ .controller_meter = lsp.sw.copp.get(cOPP_DHCPV4_OPTS()),
+ .external_ids = stage_hint(lsp.lsp._uuid));
/* If REGBIT_DHCP_OPTS_RESULT is set, it means the
* put_dhcp_opts action is successful. */
@@ -3757,12 +3774,13 @@ for (lsp in &SwitchPort
" && ip6.dst == ff02::1:2 && udp.src == 546 &&"
" udp.dst == 547" ++ sfx in
{
- Flow(.logical_datapath = lsuuid,
- .stage = s_SWITCH_IN_DHCP_OPTIONS(),
- .priority = 100,
- .__match = __match,
- .actions = options_action,
- .external_ids = stage_hint(lsp.lsp._uuid));
+ MeteredFlow(.logical_datapath = lsuuid,
+ .stage = s_SWITCH_IN_DHCP_OPTIONS(),
+ .priority = 100,
+ .__match = __match,
+ .actions = options_action,
+ .controller_meter = lsp.sw.copp.get(cOPP_DHCPV6_OPTS()),
+ .external_ids = stage_hint(lsp.lsp._uuid));
/* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the
* put_dhcpv6_opts action is successful */
@@ -3873,6 +3891,7 @@ Flow(.logical_datapath = sw._uuid,
for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)
if (mcast_cfg.enabled)) {
+ var controller_meter = sw.copp.get(cOPP_IGMP()) in
for (SwitchMcastFloodRelayPorts(sw, relay_ports)) {
for (SwitchMcastFloodReportPorts(sw, flood_report_ports)) {
for (SwitchMcastFloodPorts(sw, flood_ports)) {
@@ -3891,20 +3910,22 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)
}
} in {
/* Punt IGMP traffic to controller. */
- Flow(.logical_datapath = ls_uuid,
- .stage = s_SWITCH_IN_L2_LKUP(),
- .priority = 100,
- .__match = "ip4 && ip.proto == 2",
- .actions = "${igmp_act}",
- .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = ls_uuid,
+ .stage = s_SWITCH_IN_L2_LKUP(),
+ .priority = 100,
+ .__match = "ip4 && ip.proto == 2",
+ .actions = "${igmp_act}",
+ .controller_meter = controller_meter,
+ .external_ids = map_empty());
/* Punt MLD traffic to controller. */
- Flow(.logical_datapath = ls_uuid,
- .stage = s_SWITCH_IN_L2_LKUP(),
- .priority = 100,
- .__match = "mldv1 || mldv2",
- .actions = "${igmp_act}",
- .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = ls_uuid,
+ .stage = s_SWITCH_IN_L2_LKUP(),
+ .priority = 100,
+ .__match = "mldv1 || mldv2",
+ .actions = "${igmp_act}",
+ .controller_meter = controller_meter,
+ .external_ids = map_empty());
/* Flood all IP multicast traffic destined to 224.0.0.X to
* all ports - RFC 4541, section 2.1.2, item 2.
@@ -4666,7 +4687,9 @@ for (&RouterPort(.lrp = lrp,
* */
/* Flows for LOOKUP_NEIGHBOR. */
-for (&Router(._uuid = lr_uuid, .learn_from_arp_request = learn_from_arp_request))
+for (&Router(._uuid = lr_uuid,
+ .learn_from_arp_request = learn_from_arp_request,
+ .copp = copp))
var rLNR = rEGBIT_LOOKUP_NEIGHBOR_RESULT() in
var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in
{
@@ -4718,30 +4741,27 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in
{ if (learn_from_arp_request) "" else " || ${rLNIR} == 0" },
.actions = "next;",
.external_ids = map_empty());
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
- .priority = 90,
- .__match = "arp",
- .actions = "put_arp(inport, arp.spa, arp.sha); next;",
- .external_ids = map_empty());
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
- .priority = 90,
- .__match = "arp",
- .actions = "put_arp(inport, arp.spa, arp.sha); next;",
- .external_ids = map_empty());
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
- .priority = 90,
- .__match = "nd_na",
- .actions = "put_nd(inport, nd.target, nd.tll); next;",
- .external_ids = map_empty());
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
- .priority = 90,
- .__match = "nd_ns",
- .actions = "put_nd(inport, ip6.src, nd.sll); next;",
- .external_ids = map_empty())
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
+ .priority = 90,
+ .__match = "arp",
+ .actions = "put_arp(inport, arp.spa, arp.sha); next;",
+ .controller_meter = copp.get(cOPP_ARP()),
+ .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
+ .priority = 90,
+ .__match = "nd_na",
+ .actions = "put_nd(inport, nd.target, nd.tll); next;",
+ .controller_meter = copp.get(cOPP_ND_NA()),
+ .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_LEARN_NEIGHBOR(),
+ .priority = 90,
+ .__match = "nd_ns",
+ .actions = "put_nd(inport, ip6.src, nd.sll); next;",
+ .controller_meter = copp.get(cOPP_ND_NS()),
+ .external_ids = map_empty())
}
/* Check if we need to learn mac-binding from ARP requests. */
@@ -5133,12 +5153,13 @@ relation LogicalRouterNdFlow(
drop: bool,
priority: integer,
external_ids: Map<string,string>)
-Flow(.logical_datapath = lr._uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = priority,
- .__match = __match,
- .actions = actions,
- .external_ids = external_ids) :-
+MeteredFlow(.logical_datapath = lr._uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = priority,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = controller_meter,
+ .external_ids = external_ids) :-
LogicalRouterNdFlow(.lr = lr, .lrp = lrp, .action = action, .ip = ip,
.sn_ip = sn_ip, .mac = mac, .extra_match = extra_match,
.drop = drop, .priority = priority,
@@ -5156,18 +5177,19 @@ Flow(.logical_datapath = lr._uuid,
clauses.append(extra_match.to_vec());
clauses.join(" && ")
},
- var actions = if (drop) {
- "drop;"
+ (var actions, var controller_meter) = if (drop) {
+ ("drop;", None)
} else {
- "${action} { "
- "eth.src = ${mac}; "
- "ip6.src = ${ip}; "
- "nd.target = ${ip}; "
- "nd.tll = ${mac}; "
- "outport = inport; "
- "flags.loopback = 1; "
- "output; "
- "};"
+ ("${action} { "
+ "eth.src = ${mac}; "
+ "ip6.src = ${ip}; "
+ "nd.target = ${ip}; "
+ "nd.tll = ${mac}; "
+ "outport = inport; "
+ "flags.loopback = 1; "
+ "output; "
+ "};",
+ lr.copp.get(cOPP_ND_NA()))
}.
/* ICMP time exceeded */
@@ -5289,60 +5311,65 @@ for (RouterPortNetworksIPv4Addr(
.port = &RouterPort{
.router = &Router{._uuid = lr_uuid,
.l3dgw_port = None,
- .is_gateway = false},
+ .is_gateway = false,
+ .copp = copp},
.lrp = lrp},
.addr = addr))
{
/* UDP/TCP/SCTP port unreachable. */
var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && udp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "icmp4 {"
- "eth.dst <-> eth.src; "
- "ip4.dst <-> ip4.src; "
- "ip.ttl = 255; "
- "icmp4.type = 3; "
- "icmp4.code = 3; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "icmp4 {"
+ "eth.dst <-> eth.src; "
+ "ip4.dst <-> ip4.src; "
+ "ip.ttl = 255; "
+ "icmp4.type = 3; "
+ "icmp4.code = 3; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_ICMP4_ERR()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && tcp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "tcp_reset {"
- "eth.dst <-> eth.src; "
- "ip4.dst <-> ip4.src; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "tcp_reset {"
+ "eth.dst <-> eth.src; "
+ "ip4.dst <-> ip4.src; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_TCP_RESET()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && sctp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "sctp_abort {"
- "eth.dst <-> eth.src; "
- "ip4.dst <-> ip4.src; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "sctp_abort {"
+ "eth.dst <-> eth.src; "
+ "ip4.dst <-> ip4.src; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_TCP_RESET()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 70,
- .__match = __match,
- .actions = "icmp4 {"
- "eth.dst <-> eth.src; "
- "ip4.dst <-> ip4.src; "
- "ip.ttl = 255; "
- "icmp4.type = 3; "
- "icmp4.code = 2; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid))
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 70,
+ .__match = __match,
+ .actions = "icmp4 {"
+ "eth.dst <-> eth.src; "
+ "ip4.dst <-> ip4.src; "
+ "ip.ttl = 255; "
+ "icmp4.type = 3; "
+ "icmp4.code = 2; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_ICMP4_ERR()),
+ .external_ids = stage_hint(lrp._uuid))
}
/* DHCPv6 reply handling */
@@ -5416,60 +5443,65 @@ for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.lrp = lrp,
for (RouterPortNetworksIPv6Addr(
.port = &RouterPort{.router = &Router{._uuid = lr_uuid,
.l3dgw_port = None,
- .is_gateway = false},
+ .is_gateway = false,
+ .copp = copp},
.lrp = lrp,
.json_name = json_name},
.addr = addr))
{
var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && tcp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "tcp_reset {"
- "eth.dst <-> eth.src; "
- "ip6.dst <-> ip6.src; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "tcp_reset {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst <-> ip6.src; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_TCP_RESET()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && sctp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "sctp_abort {"
- "eth.dst <-> eth.src; "
- "ip6.dst <-> ip6.src; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "sctp_abort {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst <-> ip6.src; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_TCP_RESET()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && udp" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 80,
- .__match = __match,
- .actions = "icmp6 {"
- "eth.dst <-> eth.src; "
- "ip6.dst <-> ip6.src; "
- "ip.ttl = 255; "
- "icmp6.type = 1; "
- "icmp6.code = 4; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 80,
+ .__match = __match,
+ .actions = "icmp6 {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst <-> ip6.src; "
+ "ip.ttl = 255; "
+ "icmp6.type = 1; "
+ "icmp6.code = 4; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_ICMP6_ERR()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag" in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 70,
- .__match = __match,
- .actions = "icmp6 {"
- "eth.dst <-> eth.src; "
- "ip6.dst <-> ip6.src; "
- "ip.ttl = 255; "
- "icmp6.type = 1; "
- "icmp6.code = 3; "
- "next; };",
- .external_ids = stage_hint(lrp._uuid))
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 70,
+ .__match = __match,
+ .actions = "icmp6 {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst <-> ip6.src; "
+ "ip.ttl = 255; "
+ "icmp6.type = 1; "
+ "icmp6.code = 3; "
+ "next; };",
+ .controller_meter = copp.get(cOPP_ICMP6_ERR()),
+ .external_ids = stage_hint(lrp._uuid))
}
/* ICMPv6 time exceeded */
@@ -5491,12 +5523,13 @@ for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.router = router,
"icmp6.type = 3; /* Time exceeded */ "
"icmp6.code = 0; /* TTL exceeded in transit */ "
"next; };" in
- Flow(.logical_datapath = router._uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 40,
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(lrp._uuid))
+ MeteredFlow(.logical_datapath = router._uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 40,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = router.copp.get(cOPP_ICMP6_ERR()),
+ .external_ids = stage_hint(lrp._uuid))
}
/* NAT, Defrag and load balancing. */
@@ -6139,16 +6172,15 @@ for (RouterLBVIP(
{
if (backends == "" and not lb.options.get_bool_def("reject", false)) {
for (LoadBalancerEmptyEvents(lb)) {
- for (HasEventElbMeter(has_elb_meter)) {
- Some {(var __match, var __action)} =
- build_empty_lb_event_flow(vip, lb, has_elb_meter) in
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_DNAT(),
- .priority = 130,
- .__match = __match,
- .actions = __action,
- .external_ids = stage_hint(lb._uuid))
- }
+ Some {(var __match, var __action)} =
+ build_empty_lb_event_flow(vip, lb) in
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_DNAT(),
+ .priority = 130,
+ .__match = __match,
+ .actions = __action,
+ .controller_meter = r.copp.get(cOPP_EVENT_ELB()),
+ .external_ids = stage_hint(lb._uuid))
}
};
@@ -6304,12 +6336,13 @@ for (RouterLBVIP(
* via add_router_lb_flow(). One flow is for specific matching
* on ct.new with an action of "ct_lb($targets);". The other
* flow is for ct.est with an action of "ct_dnat;". */
-Flow(.logical_datapath = r._uuid,
- .stage = s_ROUTER_IN_DNAT(),
- .priority = priority,
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(lb._uuid)) :-
+MeteredFlow(.logical_datapath = r._uuid,
+ .stage = s_ROUTER_IN_DNAT(),
+ .priority = priority,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = meter,
+ .external_ids = stage_hint(lb._uuid)) :-
r in &Router(),
r.l3dgw_port.is_some() or r.is_gateway,
LBVIPWithStatus[lbvip@&LBVIPWithStatus{.lb = lb}],
@@ -6327,7 +6360,12 @@ Flow(.logical_datapath = r._uuid,
ForceSNAT -> "flags.force_snat_for_lb = 1; ",
_ -> ""
},
- var actions = build_lb_vip_actions(lbvip, s_ROUTER_OUT_SNAT(), force_snat).
+ (var actions, var reject) = build_lb_vip_actions(lbvip, s_ROUTER_OUT_SNAT(), force_snat),
+ var meter = if (reject) {
+ r.copp.get(cOPP_REJECT())
+ } else {
+ None
+ }.
/* Defaults based on MaxRtrInterval and MinRtrInterval from RFC 4861 section
@@ -6468,12 +6506,13 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@&nb::Logical_Router_Port{.peer = Non
Some{prf} -> ", router_preference = \"${prf}\""
} in
var actions = actions0 ++ router_preference ++ prefix ++ "); next;" in
- Flow(.logical_datapath = router._uuid,
- .stage = s_ROUTER_IN_ND_RA_OPTIONS(),
- .priority = 50,
- .__match = __match,
- .actions = actions,
- .external_ids = stage_hint(lrp._uuid));
+ MeteredFlow(.logical_datapath = router._uuid,
+ .stage = s_ROUTER_IN_ND_RA_OPTIONS(),
+ .priority = 50,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = router.copp.get(cOPP_ND_RA_OPTS()),
+ .external_ids = stage_hint(lrp._uuid));
var __match = "inport == ${json_name} && ip6.dst == ff02::2 && "
"nd_ra && ${rEGBIT_ND_RA_OPTS_RESULT()}" in
@@ -7370,24 +7409,25 @@ Flow(.logical_datapath = lr_uuid,
var gw_mtu = l3dgw_port.options.get_int_def("gateway_mtu", 0),
gw_mtu > 0,
var mtu = gw_mtu + vLAN_ETH_HEADER_LEN().
-Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LARGER_PKTS(),
- .priority = 50,
- .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
- "ip4 && ${rEGBIT_PKT_LARGER()}",
- .actions = "icmp4_error {"
- "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
- "eth.dst = ${rp.networks.ea}; "
- "ip4.dst = ip4.src; "
- "ip4.src = ${first_ipv4.addr}; "
- "ip.ttl = 255; "
- "icmp4.type = 3; /* Destination Unreachable. */ "
- "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
- /* Set icmp4.frag_mtu to gw_mtu */
- "icmp4.frag_mtu = ${gw_mtu}; "
- "next(pipeline=ingress, table=0); "
- "};",
- .external_ids = stage_hint(rp.lrp._uuid)) :-
+MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_LARGER_PKTS(),
+ .priority = 50,
+ .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
+ "ip4 && ${rEGBIT_PKT_LARGER()}",
+ .actions = "icmp4_error {"
+ "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
+ "eth.dst = ${rp.networks.ea}; "
+ "ip4.dst = ip4.src; "
+ "ip4.src = ${first_ipv4.addr}; "
+ "ip.ttl = 255; "
+ "icmp4.type = 3; /* Destination Unreachable. */ "
+ "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
+ /* Set icmp4.frag_mtu to gw_mtu */
+ "icmp4.frag_mtu = ${gw_mtu}; "
+ "next(pipeline=ingress, table=0); "
+ "};",
+ .controller_meter = r.copp.get(cOPP_ICMP4_ERR()),
+ .external_ids = stage_hint(rp.lrp._uuid)) :-
r in &Router(._uuid = lr_uuid),
Some{var l3dgw_port} = r.l3dgw_port,
var l3dgw_port_json_name = json_string_escape(l3dgw_port.name),
@@ -7397,24 +7437,25 @@ Flow(.logical_datapath = lr_uuid,
rp in &RouterPort(.router = r),
rp.lrp != l3dgw_port,
Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0).
-Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_LARGER_PKTS(),
- .priority = 50,
- .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
- "ip6 && ${rEGBIT_PKT_LARGER()}",
- .actions = "icmp6_error {"
- "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
- "eth.dst = ${rp.networks.ea}; "
- "ip6.dst = ip6.src; "
- "ip6.src = ${first_ipv6.addr}; "
- "ip.ttl = 255; "
- "icmp6.type = 2; /* Packet Too Big. */ "
- "icmp6.code = 0; "
- /* Set icmp6.frag_mtu to gw_mtu */
- "icmp6.frag_mtu = ${gw_mtu}; "
- "next(pipeline=ingress, table=0); "
- "};",
- .external_ids = stage_hint(rp.lrp._uuid)) :-
+MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_LARGER_PKTS(),
+ .priority = 50,
+ .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
+ "ip6 && ${rEGBIT_PKT_LARGER()}",
+ .actions = "icmp6_error {"
+ "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
+ "eth.dst = ${rp.networks.ea}; "
+ "ip6.dst = ip6.src; "
+ "ip6.src = ${first_ipv6.addr}; "
+ "ip.ttl = 255; "
+ "icmp6.type = 2; /* Packet Too Big. */ "
+ "icmp6.code = 0; "
+ /* Set icmp6.frag_mtu to gw_mtu */
+ "icmp6.frag_mtu = ${gw_mtu}; "
+ "next(pipeline=ingress, table=0); "
+ "};",
+ .controller_meter = r.copp.get(cOPP_ICMP6_ERR()),
+ .external_ids = stage_hint(rp.lrp._uuid)) :-
r in &Router(._uuid = lr_uuid),
Some{var l3dgw_port} = r.l3dgw_port,
var l3dgw_port_json_name = json_string_escape(l3dgw_port.name),
@@ -7462,12 +7503,13 @@ for (&Router(._uuid = lr_uuid,
* In the common case where the Ethernet destination has been resolved,
* this table outputs the packet (priority 0). Otherwise, it composes
* and sends an ARP/IPv6 NA request (priority 100). */
-Flow(.logical_datapath = router._uuid,
- .stage = s_ROUTER_IN_ARP_REQUEST(),
- .priority = 200,
- .__match = __match,
- .actions = actions,
- .external_ids = map_empty()) :-
+MeteredFlow(.logical_datapath = router._uuid,
+ .stage = s_ROUTER_IN_ARP_REQUEST(),
+ .priority = 200,
+ .__match = __match,
+ .actions = actions,
+ .controller_meter = router.copp.get(cOPP_ND_NS_RESOLVE()),
+ .external_ids = map_empty()) :-
rsr in RouterStaticRoute(.router = router),
var dst = FlatMap(rsr.dsts),
IPv6{var gw_ip6} = dst.nexthop,
@@ -7483,30 +7525,32 @@ Flow(.logical_datapath = router._uuid,
"output; "
"};".
-for (&Router(._uuid = lr_uuid))
+for (&Router(._uuid = lr_uuid, .copp = copp))
{
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_ARP_REQUEST(),
- .priority = 100,
- .__match = "eth.dst == 00:00:00:00:00:00 && ip4",
- .actions = "arp { "
- "eth.dst = ff:ff:ff:ff:ff:ff; "
- "arp.spa = ${rEG_SRC()}; "
- "arp.tpa = ${rEG_NEXT_HOP()}; "
- "arp.op = 1; " /* ARP request */
- "output; "
- "};",
- .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_ARP_REQUEST(),
+ .priority = 100,
+ .__match = "eth.dst == 00:00:00:00:00:00 && ip4",
+ .actions = "arp { "
+ "eth.dst = ff:ff:ff:ff:ff:ff; "
+ "arp.spa = ${rEG_SRC()}; "
+ "arp.tpa = ${rEG_NEXT_HOP()}; "
+ "arp.op = 1; " /* ARP request */
+ "output; "
+ "};",
+ .controller_meter = copp.get(cOPP_ARP_RESOLVE()),
+ .external_ids = map_empty());
- Flow(.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_ARP_REQUEST(),
- .priority = 100,
- .__match = "eth.dst == 00:00:00:00:00:00 && ip6",
- .actions = "nd_ns { "
- "nd.target = xx${rEG_NEXT_HOP()}; "
- "output; "
- "};",
- .external_ids = map_empty());
+ MeteredFlow(.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_ARP_REQUEST(),
+ .priority = 100,
+ .__match = "eth.dst == 00:00:00:00:00:00 && ip6",
+ .actions = "nd_ns { "
+ "nd.target = xx${rEG_NEXT_HOP()}; "
+ "output; "
+ "};",
+ .controller_meter = copp.get(cOPP_ND_NS_RESOLVE()),
+ .external_ids = map_empty());
Flow(.logical_datapath = lr_uuid,
.stage = s_ROUTER_IN_ARP_REQUEST(),
@@ -8177,8 +8221,12 @@ nb::Out_BFD(bfd_uuid, Some{status}) :-
* Logical router BFD flows
*/
-function lrouter_bfd_flows(lr_uuid: uuid, lrp_uuid: uuid, ipX: string, networks: string)
- : (Flow, Flow)
+function lrouter_bfd_flows(lr_uuid: uuid,
+ lrp_uuid: uuid,
+ ipX: string,
+ networks: string,
+ controller_meter: Option<string>)
+ : (Flow, MeteredFlow)
{
(Flow{.logical_datapath = lr_uuid,
.stage = s_ROUTER_IN_IP_INPUT(),
@@ -8186,27 +8234,32 @@ function lrouter_bfd_flows(lr_uuid: uuid, lrp_uuid: uuid, ipX: string, networks:
.__match = "${ipX}.src == ${networks} && udp.dst == 3784",
.actions = "next; ",
.external_ids = stage_hint(lrp_uuid)},
- Flow{.logical_datapath = lr_uuid,
- .stage = s_ROUTER_IN_IP_INPUT(),
- .priority = 110,
- .__match = "${ipX}.dst == ${networks} && udp.dst == 3784",
- .actions = "handle_bfd_msg(); ",
- .external_ids = stage_hint(lrp_uuid)})
+ MeteredFlow{.logical_datapath = lr_uuid,
+ .stage = s_ROUTER_IN_IP_INPUT(),
+ .priority = 110,
+ .__match = "${ipX}.dst == ${networks} && udp.dst == 3784",
+ .actions = "handle_bfd_msg(); ",
+ .controller_meter = controller_meter,
+ .external_ids = stage_hint(lrp_uuid)})
}
for (&RouterPort(.router = router, .networks = networks, .lrp = lrp, .has_bfd = true)) {
- if (not networks.ipv4_addrs.is_empty()) {
- (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip4",
- format_v4_networks(networks, false)) in {
- Flow[a];
- Flow[b]
- }
- };
+ var controller_meter = router.copp.get(cOPP_BFD()) in {
+ if (not networks.ipv4_addrs.is_empty()) {
+ (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip4",
+ format_v4_networks(networks, false),
+ controller_meter) in {
+ Flow[a];
+ MeteredFlow[b]
+ }
+ };
- if (not networks.ipv6_addrs.is_empty()) {
- (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip6",
- format_v6_networks(networks)) in {
- Flow[a];
- Flow[b]
+ if (not networks.ipv6_addrs.is_empty()) {
+ (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip6",
+ format_v6_networks(networks),
+ controller_meter) in {
+ Flow[a];
+ MeteredFlow[b]
+ }
}
}
}
@@ -414,6 +414,9 @@
<column name="meters" key="bfd">
Rate limiting meter for BFD packets.
</column>
+ <column name="meters" key="reject">
+ Rate limiting meter for packets that trigger a reject action
+ </column>
</table>
<table name="Logical_Switch" title="L2 logical switch">
@@ -169,6 +169,9 @@ find_command tcpdump
# Set HAVE_LFTP
find_command lftp
+# Set HAVE_SCAPY
+find_command scapy
+
CURL_OPT="-g -v --max-time 1 --retry 2 --retry-delay 1 --connect-timeout 1"
# Determine whether "diff" supports "normal" diffs. (busybox diff does not.)
@@ -1668,10 +1668,6 @@ reject { };
trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63)
-trigger_event(event = "empty_lb_backends", meter="event-elb" vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
- formats as trigger_event(event = "empty_lb_backends", meter = "event-elb", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
- encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63,meter_id=5)
-
# Testing invalid vip results in extra error messages from socket-util.c
trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "aarp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
Load balancer protocol 'aarp' is not 'tcp', 'udp', or 'sctp'
@@ -17837,6 +17833,7 @@ AT_CLEANUP
OVN_FOR_EACH_NORTHD([
AT_SETUP([controller event])
AT_KEYWORDS([ovn_controller_event])
+
ovn_start
# Create hypervisors hv[12].
@@ -17900,6 +17897,7 @@ ovn-nbctl ls-lb-add sw0 lb2
uuid_lb2=$(ovn-nbctl --bare --columns=_uuid find load_balancer name=lb2)
ovn-nbctl --wait=hv meter-add event-elb drop 100 pktps 10
+ovn-nbctl --wait=hv ls-copp-add sw0 event-elb event-elb
OVN_POPULATE_ARP
wait_for_ports_up
@@ -6612,3 +6612,138 @@ NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 172.18.2.12 | FORMAT_PING], \
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- CoPP])
+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
+AT_SKIP_IF([test $HAVE_SCAPY = no])
+AT_KEYWORDS([ovn-copp])
+
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_BR([br-int])
+ADD_BR([br-ext])
+
+check ovs-ofctl add-flow br-ext action=normal
+# Set external-ids in br-int needed for ovn-controller
+check ovs-vsctl \
+ -- set Open_vSwitch . external-ids:system-id=hv1 \
+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+check ovn-nbctl lr-add R1
+check ovn-nbctl ls-add sw0
+check ovn-nbctl ls-add public
+
+check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
+check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 1000::a/64 \
+ -- lrp-set-gateway-chassis rp-public hv1
+
+check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
+ type=router options:router-port=rp-sw0 \
+ -- lsp-set-addresses sw0-rp router
+
+check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
+ type=router options:router-port=rp-public \
+ -- lsp-set-addresses public-rp router
+
+ADD_NAMESPACES(sw01)
+ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
+ "192.168.1.1")
+check ovn-nbctl lsp-add sw0 sw01 \
+ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2"
+
+ADD_NAMESPACES(server)
+NS_CHECK_EXEC([server], [ip link set dev lo up])
+ADD_VETH(s1, server, br-ext, "172.16.1.50/24", "f0:00:00:01:02:05", \
+ "172.16.1.1")
+
+AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext])
+check ovn-nbctl lsp-add public public1 \
+ -- lsp-set-addresses public1 unknown \
+ -- lsp-set-type public1 localnet \
+ -- lsp-set-options public1 network_name=phynet
+
+NS_EXEC([sw01], [tcpdump -n -i sw01 icmp -Q in > reject.pcap &])
+check ovn-nbctl meter-add acl-meter drop 1 pktps 0
+check ovn-nbctl --wait=hv ls-copp-add sw0 reject acl-meter
+check ovn-nbctl acl-add sw0 from-lport 1002 'inport == "sw01" && ip && udp' reject
+
+AT_CHECK([ovn-nbctl ls-copp-list sw0], [0], [dnl
+reject: acl-meter
+])
+
+ip netns exec sw01 scapy -H <<-EOF
+p = IP(src="192.168.1.2", dst="192.168.1.1")/ UDP(dport = 12345) / Raw(b"X"*64)
+send (p, iface='sw01', loop = 0, verbose = 0, count = 20)
+EOF
+
+sleep 2
+kill $(pidof tcpdump)
+
+# 1pps + 1 burst size
+OVS_WAIT_UNTIL([
+ n_reject=$(grep unreachable reject.pcap | wc -l)
+ test "${n_reject}" = "2"
+])
+
+rm -f reject.pcap
+NS_EXEC([sw01], [tcpdump -n -i sw01 icmp -Q in > reject.pcap &])
+check ovn-nbctl --wait=hv ls-copp-del sw0 reject
+
+ip netns exec sw01 scapy -H <<-EOF
+p = IP(src="192.168.1.2", dst="192.168.1.1")/ UDP(dport = 12345) / Raw(b"X"*64)
+send (p, iface='sw01', loop = 0, verbose = 0, count = 20)
+EOF
+
+sleep 2
+kill $(pidof tcpdump)
+
+OVS_WAIT_UNTIL([
+ n_reject=$(grep unreachable reject.pcap | wc -l)
+ test "${n_reject}" = "20"
+])
+
+NS_EXEC([server], [tcpdump -n -i s1 arp[[24:4]]=0xac100164 > arp.pcap &])
+check ovn-nbctl meter-add arp-meter drop 1 pktps 0
+check ovn-nbctl --wait=hv lr-copp-add R1 arp-resolve arp-meter
+AT_CHECK([ovn-nbctl lr-copp-list R1], [0], [dnl
+arp-resolve: arp-meter
+])
+
+ip netns exec sw01 scapy -H <<-EOF
+p = IP(src="192.168.1.2", dst="172.16.1.100")/ TCP(dport = 80, flags="S") / Raw(b"X"*64)
+send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
+EOF
+
+sleep 2
+kill $(pidof tcpdump)
+
+# 1pps + 1 burst size
+OVS_WAIT_UNTIL([
+ n_arp=$(grep ARP arp.pcap | wc -l)
+ test "${n_arp}" = "2"
+])
+
+kill $(pidof ovn-controller)
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
+/.*terminating with signal 15.*/d"])
+AT_CLEANUP
+])
@@ -1466,6 +1466,9 @@
<li>packets that need to be replied to with ICMP Errors</li>
<li>packets that need to be replied to with TCP RST</li>
<li>packets that need to be replied to with DHCP_OPTS</li>
+ <li>packets that trigger a reject action</li>
+ <li>packets that trigger a SCTP abort action</li>
+ <li>controller_events</li>
<li>BFD</li>
</ul>
</p>