From: Dumitru Ceara <dce...@redhat.com> Change the ovn-northd implementation to set the new 'controller_meter' field for flows that need to punt packets to ovn-controller.
Protocol packets for which CoPP is enforced when sending packets to ovn-controller (if configured): - ARP - ND_NS - ND_NA - ND_RA - DNS - IGMP - packets that require ARP resolution before forwarding - packets that require ND_NS before forwarding - packets that need to be replied to with ICMP Errors - packets that need to be replied to with TCP RST - packets that need to be replied to with DHCP_OPTS - packets that trigger a SCTP abort action - contoller_events - BFD Co-authored-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> Signed-off-by: Dumitru Ceara <dce...@redhat.com> --- include/ovn/actions.h | 1 - lib/actions.c | 50 +--- lib/copp.c | 1 + lib/copp.h | 1 + northd/ovn-northd.c | 497 ++++++++++++++++++++++++-------------- ovn-nb.xml | 3 + tests/atlocal.in | 3 + tests/ovn.at | 9 +- tests/system-ovn.at | 138 +++++++++++ utilities/ovn-nbctl.8.xml | 3 + 10 files changed, 477 insertions(+), 229 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index a33d02681..f023a37b9 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -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. */ diff --git a/lib/actions.c b/lib/actions.c index 2355a9ace..c572e88ae 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -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 diff --git a/lib/copp.c b/lib/copp.c index e3d14938a..bbe66924b 100644 --- a/lib/copp.c +++ b/lib/copp.c @@ -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", }; diff --git a/lib/copp.h b/lib/copp.h index c34e1e029..e238d963a 100644 --- a/lib/copp.h +++ b/lib/copp.h @@ -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, }; diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 4b8cb9ad5..11e45ce77 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -3326,11 +3326,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; @@ -3382,6 +3382,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 @@ -4186,8 +4187,8 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, \ 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) @@ -4206,9 +4207,14 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, false, \ NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) -#define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ +#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, false, \ - NULL, NULL, OVS_SOURCE_LOCATOR) + CTRL_METER, NULL, OVS_SOURCE_LOCATOR) + +#define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ + ovn_lflow_add_unique__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \ + NULL) static struct ovn_lflow * ovn_lflow_find(const struct hmap *lflows, const struct ovn_datapath *od, @@ -5157,11 +5163,7 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip); struct ds match = DS_EMPTY_INITIALIZER; - char *meter = "", *action; - - if (meter_groups && shash_find(meter_groups, "event-elb")) { - meter = "event-elb"; - } + char *action; ds_put_format(&match, "ip%s.dst == %s && %s", ipv4 ? "4": "6", lb_vip->vip_str, lb->protocol); @@ -5175,14 +5177,18 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, } action = xasprintf("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)); - ovn_lflow_add_with_hint(lflows, od, pl, 130, ds_cstr(&match), action, - &lb->header_); + + const struct nbrec_copp *copp = (od->nbr ? od->nbr->copp : od->nbs->copp); + ovn_lflow_add_with_hint__(lflows, od, pl, 130, ds_cstr(&match), action, + copp_meter_get(COPP_EVENT_ELB, copp, + meter_groups), + &lb->header_); ds_destroy(&match); if (lb_vip->vip_port) { free(vip); @@ -5550,9 +5556,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); @@ -6052,7 +6061,7 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { static void build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, - struct ovn_northd_lb *lb) + struct ovn_northd_lb *lb, struct shash *meter_groups) { struct ds action = DS_EMPTY_INITIALIZER; struct ds match = DS_EMPTY_INITIALIZER; @@ -6097,20 +6106,24 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, } /* 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); + if (reject) { + meter = copp_meter_get(COPP_REJECT, od->nbs->copp, meter_groups); + } ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, lb_vip->vip_str); if (lb_vip->vip_port) { ds_put_format(&match, " && %s.dst == %d", proto, lb_vip->vip_port); - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 120, - ds_cstr(&match), ds_cstr(&action), - &lb->nlb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_STATEFUL, 120, + ds_cstr(&match), ds_cstr(&action), + meter, &lb->nlb->header_); } else { - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 110, - ds_cstr(&match), ds_cstr(&action), - &lb->nlb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_STATEFUL, 110, + ds_cstr(&match), ds_cstr(&action), + meter, &lb->nlb->header_); } } ds_destroy(&action); @@ -6118,7 +6131,8 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, } static void -build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) +build_stateful(struct ovn_datapath *od, struct hmap *lflows, + struct hmap *lbs, struct shash *meter_groups) { /* Ingress and Egress stateful Table (Priority 0): Packets are * allowed by default. */ @@ -6146,7 +6160,7 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) ovn_northd_lb_find(lbs, &od->nbs->load_balancer[i]->header_.uuid); ovs_assert(lb); - build_lb_rules(od, lflows, lb); + build_lb_rules(od, lflows, lb, meter_groups); } } @@ -6671,6 +6685,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; @@ -6694,11 +6709,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 @@ -6718,11 +6736,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 @@ -6756,6 +6777,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; @@ -6778,11 +6800,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 */ @@ -6920,7 +6945,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, build_acl_hints(od, lflows); build_acls(od, lflows, port_groups, meter_groups); build_qos(od, lflows); - build_stateful(od, lflows, lbs); + build_stateful(od, lflows, lbs, meter_groups); build_lb_hairpin(od, lflows); } } @@ -6976,6 +7001,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) { @@ -7117,11 +7143,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). */ @@ -7199,7 +7228,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)) { @@ -7228,17 +7258,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); } } } @@ -7268,13 +7298,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;"; @@ -7311,7 +7343,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) { @@ -7332,12 +7365,16 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, } ds_put_cstr(actions, "igmp;"); /* Punt IGMP traffic to controller. */ - ovn_lflow_add_unique(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_unique(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. @@ -8731,23 +8768,29 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, struct ds *match, struct ds *actions, int priority, enum lb_snat_type snat_type, struct ovn_lb_vip *lb_vip, const char *proto, struct nbrec_load_balancer *lb, - struct shash *meter_groups, struct sset *nat_entries) + struct shash *meter_groups, struct sset *nat_entries, + bool reject) { build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT, meter_groups); + const char *meter = NULL; + if (reject) { + meter = copp_meter_get(COPP_REJECT, od->nbr->copp, meter_groups); + } /* A match and actions for new connections. */ char *new_match = xasprintf("ct.new && %s", ds_cstr(match)); if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) { char *new_actions = xasprintf("flags.%s_snat_for_lb = 1; %s", snat_type == SKIP_SNAT ? "skip" : "force", ds_cstr(actions)); - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, - new_match, new_actions, &lb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, new_actions, meter, &lb->header_); free(new_actions); } else { - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, - new_match, ds_cstr(actions), &lb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, ds_cstr(actions), meter, + &lb->header_); } /* A match and actions for established connections. */ @@ -8873,8 +8916,8 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od, struct ovn_lb_vip *lb_vip = &lb->vips[j]; struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[j]; ds_clear(actions); - build_lb_vip_actions(lb_vip, lb_vip_nb, actions, - lb->selection_fields, false); + bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, actions, + lb->selection_fields, false); if (!sset_contains(&all_ips, lb_vip->vip_str)) { sset_add(&all_ips, lb_vip->vip_str); @@ -8939,7 +8982,7 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od, } add_router_lb_flow(lflows, od, match, actions, prio, snat_type, lb_vip, proto, nb_lb, - meter_groups, nat_entries); + meter_groups, nat_entries, reject); } } sset_destroy(&all_ips); @@ -9176,7 +9219,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; @@ -9198,6 +9241,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 { " @@ -9214,11 +9259,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); } @@ -9226,7 +9273,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; @@ -9236,7 +9284,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, @@ -9248,7 +9296,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; @@ -9291,12 +9340,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, @@ -9469,7 +9518,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; @@ -9488,9 +9538,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); @@ -9505,9 +9557,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); @@ -9587,7 +9641,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) { @@ -9667,14 +9722,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)); } } @@ -9749,7 +9810,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; @@ -9842,9 +9904,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 && " @@ -10467,7 +10532,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) { @@ -10529,10 +10595,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) { @@ -10558,10 +10628,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_); } } } @@ -10616,7 +10690,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++) { @@ -10653,26 +10728,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;"); } } @@ -10803,7 +10885,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 @@ -10846,7 +10929,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 */ @@ -10861,9 +10944,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, @@ -10873,9 +10960,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, @@ -10888,9 +10979,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, @@ -10903,9 +10998,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_); } } @@ -10936,9 +11035,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_); } } @@ -10946,7 +11048,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) { @@ -10972,7 +11075,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. */ @@ -10987,7 +11090,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); } } } @@ -10996,7 +11099,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. */ @@ -11034,7 +11138,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++) { @@ -11054,9 +11158,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 @@ -11133,7 +11240,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 (!smap_get(&op->od->nbr->options, "chassis") @@ -11151,9 +11259,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, @@ -11163,9 +11275,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, @@ -11175,9 +11291,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, @@ -11190,9 +11310,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_); } } @@ -11236,7 +11360,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. */ @@ -11251,7 +11376,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); } } } @@ -11932,15 +12058,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); @@ -11949,13 +12076,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->meter_groups, lsi->lbs, &lsi->match, &lsi->actions); } @@ -11975,9 +12103,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); @@ -11991,16 +12121,17 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, &lsi->actions); build_ip_routing_flows_for_lrouter_port(op, 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); } diff --git a/ovn-nb.xml b/ovn-nb.xml index 384c7ebc9..c1ffa586c 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -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"> diff --git a/tests/atlocal.in b/tests/atlocal.in index b5bc0818b..310fd46a5 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -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.) diff --git a/tests/ovn.at b/tests/ovn.at index bc494fcad..a5ed3a64e 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1665,10 +1665,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' @@ -17716,6 +17712,10 @@ AT_CLEANUP OVN_FOR_EACH_NORTHD([ AT_SETUP([ovn -- controller event]) AT_KEYWORDS([ovn_controller_event]) + +dnl This test is not suported by ovn-northd-ddlog yet. +AT_SKIP_IF([test NORTHD_TYPE = ovn-northd-ddlog && test "$RUN_ANYWAY" != yes]) + ovn_start # Create hypervisors hv[12]. @@ -17779,6 +17779,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 diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 1b8bb3803..c4ca42a4a 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -6371,3 +6371,141 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) 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]) + +dnl This test is not suported by ovn-northd-ddlog yet. +AT_SKIP_IF([test NORTHD_TYPE = ovn-northd-ddlog && test "$RUN_ANYWAY" != yes]) + +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([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP +]) diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 101849911..987797860 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -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> -- 2.31.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev