> On 29/04/2021 18:04, Lorenzo Bianconi wrote: > > From: Dumitru Ceara <dce...@redhat.com> > >
[...] > > Could this be changed to copp_proto_get_name()? ack, I will fix it in v2 > > > +{ > > + if (proto >= COPP_PROTO_MAX) { > > + return "<Invalid control protocol ID>"; > > + } > > + return copp_proto_names[proto]; > > +} > > + > > +const char * > > +copp_meter_get(enum copp_proto proto, const struct nbrec_copp *copp, > > + const struct shash *meter_groups) > > +{ > > + if (!copp || proto >= COPP_PROTO_MAX) { > > + return NULL; > > + } > > + > > + const char *meter = smap_get(&copp->meters, copp_proto_names[proto]); > > + > > + if (meter && shash_find(meter_groups, meter)) { > > + return meter; > > + } > > + > > + return NULL; > > +} > > + > > +void > > +copp_list(struct ctl_context *ctx, const struct nbrec_copp *copp) > > +{ > > + if (!copp) { > > + return; > > + } > > + > > + struct smap_node *node; > > + > > + SMAP_FOR_EACH (node, &copp->meters) { > > + ds_put_format(&ctx->output, "%s: %s\n", node->key, node->value); > > + } > > +} > > + > > +const struct nbrec_copp * > > +copp_add_meter(struct ctl_context *ctx, const struct nbrec_copp *copp, > > + const char *proto_name, const char *meter) > > +{ > > + if (!copp) { > > + copp = nbrec_copp_insert(ctx->txn); > > + } > > + > > + struct smap meters; > > + smap_init(&meters); > > + smap_clone(&meters, &copp->meters); > > + smap_replace(&meters, proto_name, meter); > > + nbrec_copp_set_meters(copp, &meters); > > + smap_destroy(&meters); > > + > > + return copp; > > +} > > + > > +void > > +copp_del_meter(const struct nbrec_copp *copp, const char *proto_name) > > +{ > > + if (!copp) { > > + return; > > + } > > + > > + if (proto_name) { > > + if (smap_get(&copp->meters, proto_name)) { > > + struct smap meters; > > + smap_init(&meters); > > + smap_clone(&meters, &copp->meters); > > + smap_remove(&meters, proto_name); > > + nbrec_copp_set_meters(copp, &meters); > > + smap_destroy(&meters); > > + } > > + } else { > > + nbrec_copp_delete(copp); > > + } > > +} > > + > > +char * > > +copp_proto_validate(const char *proto_name)> +{ > > + for (size_t i = COPP_PROTO_FIRST; i < COPP_PROTO_MAX; i++) { > > + if (!strcmp(proto_name, copp_proto_get(i))) { > > + return NULL; > > + } > > + } > > + > > + struct ds usage = DS_EMPTY_INITIALIZER; > > + > > + ds_put_cstr(&usage, "Invalid control protocol. Allowed values: "); > > + for (size_t i = COPP_PROTO_FIRST; i < COPP_PROTO_MAX; i++) { > > + ds_put_format(&usage, "%s, ", copp_proto_get(i)); > > + } > > + ds_chomp(&usage, ' '); > > + ds_chomp(&usage, ','); > > + ds_put_cstr(&usage, "."); > > + > > + char *usage_str = xstrdup(ds_cstr(&usage)); > > + ds_destroy(&usage); > > + return usage_str; > > +} > > diff --git a/lib/copp.h b/lib/copp.h > > new file mode 100644 > > index 000000000..82581e7e4 > > --- /dev/null > > +++ b/lib/copp.h > > @@ -0,0 +1,60 @@ > > +/* Copyright (c) 2021, Red Hat, Inc. > > + * > > + * 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. > > + */ > > + > > +#ifndef OVN_COPP_H > > +#define OVN_COPP_H 1 > > + > > +/* > > + * Control plane protection - metered actions. > > + */ > > +enum copp_proto { > > + COPP_PROTO_FIRST, > > + COPP_ARP = COPP_PROTO_FIRST, > > + COPP_ARP_RESOLVE, > > + COPP_DHCPV4_OPTS, > > + COPP_DHCPV6_OPTS, > > + COPP_DNS, > > + COPP_EVENT_ELB, > > + COPP_ICMP4_ERR, > > + COPP_ICMP6_ERR, > > + COPP_IGMP, > > + COPP_ND_NA, > > + COPP_ND_NS, > > + COPP_ND_NS_RESOLVE, > > + COPP_ND_RA_OPTS, > > + COPP_TCP_RESET, > > + COPP_BFD, > > + COPP_PROTO_MAX, > > + COPP_PROTO_INVALID = COPP_PROTO_MAX, > > +}; > > + > > +struct nbrec_copp; > > +struct ctl_context; > > + > > +const char *copp_proto_get(enum copp_proto); > > I think this could a static and declared in copp.c as it is not used > outside of there. ack, I will fix it in v2 > > > + > > +const char *copp_meter_get(enum copp_proto proto, > > + const struct nbrec_copp *copp, > > + const struct shash *meter_groups); > > + > > +void copp_list(struct ctl_context *ctx, const struct nbrec_copp *copp); > > +const struct nbrec_copp * > > +copp_add_meter(struct ctl_context *ctx, const struct nbrec_copp *copp, > > + const char *proto_name, const char *meter); > > +void > > +copp_del_meter(const struct nbrec_copp *copp, const char *proto_name); > > +char * copp_proto_validate(const char *proto_name); > > Could you change the names of these function prototypes to be more > consistent? e.g. copp_meter_add/del/get/list() ack, I will fix it in v2 > > > + > > +#endif /* lib/copp.h */ > > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > > index 94fae5648..2e9c7de22 100644 > > --- a/northd/ovn-northd.c > > +++ b/northd/ovn-northd.c > > @@ -32,6 +32,7 @@ > > #include "ovn/lex.h" > > #include "lib/chassis-index.h" > > #include "lib/ip-mcast-index.h" > > +#include "lib/copp.h" > > #include "lib/mcast-group-index.h" > > #include "lib/ovn-l7.h" > > #include "lib/ovn-nb-idl.h" > > @@ -4018,6 +4019,7 @@ struct ovn_lflow { > > char *match; > > char *actions; > > char *stage_hint; > > + char *ctrl_meter; > > const char *where; > > }; > > > > @@ -4051,14 +4053,15 @@ ovn_lflow_equal(const struct ovn_lflow *a, const > > struct ovn_lflow *b) > > && a->stage == b->stage > > && a->priority == b->priority > > && !strcmp(a->match, b->match) > > - && !strcmp(a->actions, b->actions)); > > + && !strcmp(a->actions, b->actions) > > + && nullable_string_is_equal(a->ctrl_meter, b->ctrl_meter)); > > } > > > > static void > > ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od, > > enum ovn_stage stage, uint16_t priority, > > - char *match, char *actions, char *stage_hint, > > - const char *where) > > + char *match, char *actions, char *ctrl_meter, > > + char *stage_hint, const char *where) > > { > > hmapx_init(&lflow->od_group); > > lflow->od = od; > > @@ -4067,6 +4070,7 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct > > ovn_datapath *od, > > lflow->match = match; > > lflow->actions = actions; > > lflow->stage_hint = stage_hint; > > + lflow->ctrl_meter = ctrl_meter; > > lflow->where = where; > > } > > > > @@ -4107,6 +4111,7 @@ static void > > ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, > > enum ovn_stage stage, uint16_t priority, > > const char *match, const char *actions, bool shared, > > + const char *ctrl_meter, > > const struct ovsdb_idl_row *stage_hint, const char *where) > > { > > ovs_assert(ovn_stage_to_datapath_type(stage) == > > ovn_datapath_get_type(od)); > > @@ -4120,6 +4125,7 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct > > ovn_datapath *od, > > * one datapath in a group, so it could be hashed correctly. */ > > ovn_lflow_init(lflow, NULL, stage, priority, > > xstrdup(match), xstrdup(actions), > > + nullable_xstrdup(ctrl_meter), > > ovn_lflow_hint(stage_hint), where); > > > > hash = ovn_lflow_hash(lflow); > > @@ -4134,14 +4140,24 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct > > ovn_datapath *od, > > } > > > > /* Adds a row with the specified contents to the Logical_Flow table. */ > > +#define ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ > > + ACTIONS, CTRL_METER, STAGE_HINT) \ > > + ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, > > \ > > + CTRL_METER, STAGE_HINT, OVS_SOURCE_LOCATOR) > > + > > #define ovn_lflow_add_with_hint(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ > > ACTIONS, STAGE_HINT) \ > > - ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, > > \ > > - STAGE_HINT, OVS_SOURCE_LOCATOR) > > + ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ > > + ACTIONS, NULL, STAGE_HINT) > > > > #define ovn_lflow_add(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ > > ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, > > \ > > - NULL, OVS_SOURCE_LOCATOR) > > + NULL, NULL, OVS_SOURCE_LOCATOR) > > + > > +#define ovn_lflow_add_ctrl(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, > > \ > > + CTRL_METER) \ > > + ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ > > + ACTIONS, CTRL_METER, NULL) > > > > /* Adds a row with the specified contents to the Logical_Flow table. > > * Combining of this logical flow with already existing ones, e.g., by > > using > > @@ -4156,21 +4172,22 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct > > ovn_datapath *od, > > #define ovn_lflow_add_unique_with_hint(LFLOW_MAP, OD, STAGE, PRIORITY, > > MATCH, \ > > ACTIONS, STAGE_HINT) \ > > ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, > > false, \ > > - STAGE_HINT, OVS_SOURCE_LOCATOR) > > + NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) > > > > #define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, > > ACTIONS) \ > > ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, > > false, \ > > - NULL, OVS_SOURCE_LOCATOR) > > + NULL, NULL, OVS_SOURCE_LOCATOR) > > > > static struct ovn_lflow * > > ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od, > > enum ovn_stage stage, uint16_t priority, > > - const char *match, const char *actions, uint32_t hash) > > + const char *match, const char *actions, const char > > *ctrl_meter, > > + uint32_t hash) > > { > > struct ovn_lflow target; > > ovn_lflow_init(&target, od, stage, priority, > > CONST_CAST(char *, match), CONST_CAST(char *, actions), > > - NULL, NULL); > > + CONST_CAST(char *, ctrl_meter), NULL, NULL); > > > > return ovn_lflow_find_by_lflow(lflows, &target, hash); > > } > > @@ -4186,6 +4203,7 @@ ovn_lflow_destroy(struct hmap *lflows, struct > > ovn_lflow *lflow) > > free(lflow->match); > > free(lflow->actions); > > free(lflow->stage_hint); > > + free(lflow->ctrl_meter); > > free(lflow); > > } > > } > > @@ -12333,7 +12351,8 @@ build_lflows(struct northd_context *ctx, struct > > hmap *datapaths, > > lflow = ovn_lflow_find( > > &lflows, logical_datapath_od, > > ovn_stage_build(dp_type, pipeline, sbflow->table_id), > > - sbflow->priority, sbflow->match, sbflow->actions, > > sbflow->hash); > > + sbflow->priority, sbflow->match, sbflow->actions, > > + sbflow->controller_meter, sbflow->hash); > > if (lflow) { > > /* This is a valid lflow. Checking if the datapath group needs > > * updates. */ > > @@ -12378,6 +12397,7 @@ build_lflows(struct northd_context *ctx, struct > > hmap *datapaths, > > sbrec_logical_flow_set_priority(sbflow, lflow->priority); > > sbrec_logical_flow_set_match(sbflow, lflow->match); > > sbrec_logical_flow_set_actions(sbflow, lflow->actions); > > + sbrec_logical_flow_set_controller_meter(sbflow, lflow->ctrl_meter); > > > > /* Trim the source locator lflow->where, which looks something like > > * "ovn/northd/ovn-northd.c:1234", down to just the part following > > the > > @@ -14082,6 +14102,8 @@ main(int argc, char *argv[]) > > add_column_noalert(ovnsb_idl_loop.idl, > > &sbrec_logical_flow_col_priority); > > add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match); > > add_column_noalert(ovnsb_idl_loop.idl, > > &sbrec_logical_flow_col_actions); > > + add_column_noalert(ovnsb_idl_loop.idl, > > + &sbrec_logical_flow_col_controller_meter); > > > > ovsdb_idl_add_table(ovnsb_idl_loop.idl, > > &sbrec_table_logical_dp_group); > > diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema > > index 29019809c..fb0f3a7c0 100644 > > --- a/ovn-nb.ovsschema > > +++ b/ovn-nb.ovsschema > > @@ -1,7 +1,7 @@ > > { > > "name": "OVN_Northbound", > > - "version": "5.31.0", > > - "cksum": "2352750632 28701", > > + "version": "5.32.0", > > + "cksum": "2317195278 29378", > > "tables": { > > "NB_Global": { > > "columns": { > > @@ -30,6 +30,14 @@ > > "ipsec": {"type": "boolean"}}, > > "maxRows": 1, > > "isRoot": true}, > > + "Copp": { > > + "columns": { > > + "meters": { > > + "type": {"key": "string", > > + "value": "string", > > + "min": 0, > > + "max": "unlimited"}}}, > > + "isRoot": true}, > > "Logical_Switch": { > > "columns": { > > "name": {"type": "string"}, > > @@ -58,6 +66,9 @@ > > "refType": "weak"}, > > "min": 0, > > "max": "unlimited"}}, > > + "copp": {"type": {"key": {"type": "uuid", "refTable": > > "Copp", > > + "refType": "weak"}, > > + "min": 0, "max": 1}}, > > "other_config": { > > "type": {"key": "string", "value": "string", > > "min": 0, "max": "unlimited"}}, > > @@ -319,6 +330,9 @@ > > "refType": "weak"}, > > "min": 0, > > "max": "unlimited"}}, > > + "copp": {"type": {"key": {"type": "uuid", "refTable": > > "Copp", > > + "refType": "weak"}, > > + "min": 0, "max": 1}}, > > "options": { > > "type": {"key": "string", > > "value": "string", > > diff --git a/ovn-nb.xml b/ovn-nb.xml > > index feb38b5d3..0f03a12f2 100644 > > --- a/ovn-nb.xml > > +++ b/ovn-nb.xml > > @@ -339,6 +339,68 @@ > > > > </table> > > > > + <table name="Copp" title="Control plane protection"> > > + <p> > > + This table is used to define control plane protection policies, i.e., > > + associate entries from table <ref table="Meter"/> to control protocol > > + names. > > + </p> > > + <column name="meters" key="arp"> > > + Rate limiting meter for ARP packets (request/reply) used for learning > > + neighbors. > > + </column> > > + <column name="meters" key="arp-resolve"> > > + Rate limiting meter for packets that require resolving the next-hop > > + (through ARP). > > + </column> > > + <column name="meters" key="dhcpv4-opts"> > > + Rate limiting meter for packets that require adding DHCPv4 options. > > + </column> > > + <column name="meters" key="dhcpv6-opts"> > > + Rate limiting meter for packets that require adding DHCPv6 options. > > + </column> > > + <column name="meters" key="dns"> > > + Rate limiting meter for DNS query packets that need to be replied to. > > + </column> > > + <column name="meters" key="event-elb"> > > + Rate limiting meter for empty load balancer events. > > + </column> > > + <column name="meters" key="icmp4-error"> > > + Rate limiting meter for packets that require replying with an ICMP > > + error. > > + </column> > > + <column name="meters" key="icmp6-error"> > > + Rate limiting meter for packets that require replying with an ICMPv6 > > + error. > > + </column> > > + <column name="meters" key="igmp"> > > + Rate limiting meter for IGMP packets. > > + </column> > > + <column name="meters" key="nd-na"> > > + Rate limiting meter for ND neighbor advertisement packets used for > > + learning neighbors. > > + </column> > > + <column name="meters" key="nd-ns"> > > + Rate limiting meter for ND neighbor solicitation packets used for > > + learning neighbors. > > + </column> > > + <column name="meters" key="nd-ns-resolve"> > > + Rate limiting meter for packets that require resolving the next-hop > > + (through ND). > > + </column> > > + <column name="meters" key="nd-ra-opts"> > > + Rate limiting meter for packets that require adding ND router > > + advertisement options. > > + </column> > > + <column name="meters" key="tcp-reset"> > > + Rate limiting meter for packets that require replying with TCP RST > > + packet. > > + </column> > > + <column name="meters" key="bfd"> > > + Rate limiting meter for BFD packets. > > + </column> > > + </table> > > + > > <table name="Logical_Switch" title="L2 logical switch"> > > <p> > > Each row represents one L2 logical switch. > > @@ -572,6 +634,14 @@ > > </column> > > </group> > > > > + <column name="copp"> > > + <p> > > + The control plane protection policy from table <ref table="Copp"/> > > + used for metering packets sent to <code>ovn-controller</code> from > > + ports of this logical switch. > > + </p> > > + </column> > > + > > <group title="Other options"> > > <column name="other_config" key="vlan-passthru" > > type='{"type": "boolean"}'> > > @@ -1929,6 +1999,14 @@ > > </column> > > </group> > > > > + <column name="copp"> > > + <p> > > + The control plane protection policy from table <ref table="Copp"/> > > + used for metering packets sent to <code>ovn-controller</code> from > > + logical ports of this router. > > + </p> > > + </column> > > + > > <group title="Options"> > > <p> > > Additional options for the logical router. > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > > index 32afb4fa8..7c18e6302 100644 > > --- a/tests/ovn-northd.at > > +++ b/tests/ovn-northd.at > > Should we be adding ovn-nbctl.at tests? Or do these tests belong in > ovn-nbctl.at These tests don't test northd but rather test that things > are written correctly to NBDB. I guess here we are testing values are properly written to NB db, so we are testing both ovn-nbctl and the NB db interation, agree? Am I missing somthing? > > We probably should have tests (in ovn-northd.c) that configures NBDB and > then we check that the SBDB has meter flows present? (and various > negative tests as well) > > > @@ -2649,6 +2649,55 @@ wait_row_count bfd 3 > > AT_CLEANUP > > ]) > > > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([ovn -- check CoPP config]) > > +AT_KEYWORDS([northd-CoPP]) > > +ovn_start > > + > > +check ovn-nbctl --wait=sb lr-add r0 > > +check ovn-nbctl --wait=sb lrp-add r0 r0-sw1 00:00:00:00:00:01 > > 192.168.1.1/24 > > +check ovn-nbctl --wait=sb ls-add sw1 > > +check ovn-nbctl --wait=sb lsp-add sw1 sw1-r0 > > +check ovn-nbctl --wait=sb lsp-set-type sw1-r0 router > > +check ovn-nbctl --wait=sb lsp-set-options sw1-r0 router-port=r0-sw1 > > +check ovn-nbctl --wait=sb lsp-set-addresses sw1-r0 00:00:00:00:00:01 > > + > > +ovn-nbctl --wait=hv meter-add meter0 drop 100 pktps 10 > > +ovn-nbctl --wait=hv ls-copp-add sw1 event-elb meter0 > > +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl > > +event-elb: meter0 > > +]) > > + > > +ovn-nbctl --wait=hv meter-add meter1 drop 200 pktps 10 > > +ovn-nbctl --wait=hv ls-copp-add sw1 arp meter1 > > +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl > > +arp: meter1 > > +event-elb: meter0 > > +]) > > + > > +ovn-nbctl --wait=hv ls-copp-del sw1 arp > > +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl > > +event-elb: meter0 > > +]) > > + > > +ovn-nbctl --wait=hv ls-copp-del sw1 event-elb > > +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl > > +]) > > + > > +ovn-nbctl --wait=hv lr-copp-add r0 bfd meter0 > > +AT_CHECK([ovn-nbctl lr-copp-list r0], [0], [dnl > > +bfd: meter0 > > +]) > > + > > +ovn-nbctl --wait=hv lr-copp-add r0 igmp meter1 > > +AT_CHECK([ovn-nbctl lr-copp-list r0], [0], [dnl > > +bfd: meter0 > > +igmp: meter1 > > +]) > > What about a delete all case at the end > > ovn-nbctl lr-copp-del r0 > > Also, > > Can you test a few failure cases? For example, deleting a copp that is > not there, adding a the same copp twice, etc ack, I will do in v2 > > > + > > +AT_CLEANUP > > +]) > > + > > AT_SETUP([ovn -- check LSP attached to multiple LS]) > > ovn_start > > > > diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml > > index 03d47dba5..6c95e8104 100644 > > --- a/utilities/ovn-nbctl.8.xml > > +++ b/utilities/ovn-nbctl.8.xml > > @@ -1131,6 +1131,122 @@ > > </dd> > > </dl> > > > > + <h1> Control Plane Protection Policy commands</h1> > > + <p> > > + These commands manages meters contained in <ref table="Copp"/> table > > + linking them to logical datapaths through <code>copp</code> column in > > + <ref table="Logical_Switch" /> or <ref table="Logical_Router" /> > > tables. > > + Protocol packets for which CoPP is enforced when sending packets to > > + ovn-controller (if configured): > > + <ul> > > + <li>ARP</li> > > + <li>ND_NS</li> > > + <li>ND_NA</li> > > + <li>ND_RA</li> > > + <li>ND</li> > > + <li>DNS</li> > > + <li>IGMP</li> > > + <li>packets that require ARP resolution before forwarding</li> > > + <li>packets that require ND_NS before forwarding</li> > > + <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>BFD</li> > > Should event-elb be listed here? I think it is done in the subsequent patch > > > + </ul> > > + </p> > > + > > + <dl> > > + <dt><code>ls-copp-add</code> <var>switch</var> <var>proto</var> > > + <var>meter</var></dt> > > + <dd> > > + Adds the control <code>proto</code> to <code>meter</code> mapping > > + to the <code>switch</code> control plane protection policy. If no > > + policy exists yet, it creates one. If a mapping already existed for > > + <code>proto</code>, this will overwrite it. > > + </dd> > > + > > + <dt><code>ls-copp-del</code> <var>switch</var> > > [<var>proto</var>]</dt> > > + <dd> > > + Removes the control <code>proto</code> mapping from the > > + <code>switch</code> control plane protection policy. If > > + <code>proto</code> is not specified, the whole control plane > > + protection policy is destroyed. > > + </dd> > > + > > + <dt><code>ls-copp-list</code> <var>switch</var></dt> > > + <dd> > > + Display the current control plane protection policy for > > + <code>switch</code>. > > + </dd> > > + > > + <dt><code>lsp-copp-add</code> <var>proto</var> <var>proto</var> > > + <var>meter</var></dt> > > + <dd> > > + Adds the control <code>proto</code> to <code>meter</code> mapping > > + to the <code>port</code> control plane protection policy. If no > > + policy exists yet, it creates one. If a mapping already existed for > > + <code>proto</code>, this will overwrite it. > > + </dd> > > + > > + <dt><code>lsp-copp-del</code> <var>port</var> [<var>proto</var>]</dt> > > + <dd> > > + Removes the control <code>proto</code> mapping from the > > + <code>port</code> control plane protection policy. If > > + <code>proto</code> is not specified, the whole control plane > > + protection policy is destroyed. > > + </dd> > > + <dt><code>lsp-copp-list</code> <var>port</var></dt> > > + <dd> > > + Display the current control plane protection policy for > > + <code>port</code>. > > + </dd> > > + > > + <dt><code>lr-copp-add</code> <var>router</var> <var>proto</var> > > + <var>meter</var></dt> > > + <dd> > > + Adds the control <code>proto</code> to <code>meter</code> mapping > > + to the <code>router</code> control plane protection policy. If no > > + policy exists yet, it creates one. If a mapping already existed for > > + <code>proto</code>, this will overwrite it. > > + </dd> > > + > > + <dt><code>lr-copp-del</code> <var>router</var> > > [<var>proto</var>]</dt> > > + <dd> > > + Removes the control <code>proto</code> mapping from the > > + <code>router</code> control plane protection policy. If > > + <code>proto</code> is not specified, the whole control plane > > + protection policy is destroyed. > > + </dd> > > + > > + <dt><code>lr-copp-list</code> <var>router</var></dt> > > + <dd> > > + Display the current control plane protection policy for > > + <code>router</code>. > > + </dd> > > + > > + <dt><code>lrp-copp-add</code> <var>proto</var> <var>proto</var> > > + <var>meter</var></dt> > > + <dd> > > + Adds the control <code>proto</code> to <code>meter</code> mapping > > + to the <code>port</code> control plane protection policy. If no > > + policy exists yet, it creates one. If a mapping already existed for > > + <code>proto</code>, this will overwrite it. > > + </dd> > > I don't think the lrp-* and lsp-* variants are needed any more? ack, right. I will fix it in v2 Regards, Lorenzo > > > + > > + <dt><code>lrp-copp-del</code> <var>port</var> [<var>proto</var>]</dt> > > + <dd> > > + Removes the control <code>proto</code> mapping from the > > + <code>port</code> control plane protection policy. If > > + <code>proto</code> is not specified, the whole control plane > > + protection policy is destroyed. > > + </dd> > > + <dt><code>lrp-copp-list</code> <var>port</var></dt> > > + <dd> > > + Display the current control plane protection policy for > > + <code>port</code>. > > + </dd> > > + </dl> > > + > > <h1>Database Commands</h1> > > <p>These commands query and modify the contents of <code>ovsdb</code> > > tables. > > They are a slight abstraction of the <code>ovsdb</code> interface and > > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c > > index 042c21002..2299bc6ce 100644 > > --- a/utilities/ovn-nbctl.c > > +++ b/utilities/ovn-nbctl.c > > @@ -27,6 +27,7 @@ > > #include "jsonrpc.h" > > #include "openvswitch/json.h" > > #include "lib/acl-log.h" > > +#include "lib/copp.h" > > #include "lib/ovn-nb-idl.h" > > #include "lib/ovn-util.h" > > #include "memory.h" > > @@ -835,6 +836,28 @@ chassis with optional PRIORITY to the HA chassis group > > GRP\n\ > > ha-chassis-group-remove-chassis GRP CHASSIS Removes the HA chassis\ > > CHASSIS from the HA chassis group GRP\n\ > > \n\ > > +Control Plane Protection Policy commands:\n\ > > + ls-copp-add SWITCH PROTO METER\n\ > > + Add a copp policy for PROTO packets on > > SWITCH\n\ > > + based on an existing METER.\n\ > > + ls-copp-del SWITCH [PROTO]\n\ > > + Delete the copp policy for PROTO packets on\n\ > > + SWITCH. If PROTO is not specified, delete > > all\n\ > > + copp policies on SWITCH.\n\ > > + ls-copp-list SWITCH\n\ > > + List all copp policies defined for control\n\ > > + protocols on SWITCH.\n\ > > + lr-copp-add ROUTER PROTO METER\n\ > > + Add a copp policy for PROTO packets on > > ROUTER\n\ > > + based on an existing METER.\n\ > > + lr-copp-del ROUTER [PROTO]\n\ > > + Delete the copp policy for PROTO packets on\n\ > > + ROUTER. If PROTO is not specified, delete > > all\n\ > > + copp policies on ROUTER.\n\ > > + lr-copp-list ROUTER\n\ > > + List all copp policies defined for control\n\ > > + protocols on ROUTER.\n\ > > +\n\ > > %s\ > > %s\ > > \n\ > > @@ -5711,6 +5734,138 @@ nbctl_lr_route_list(struct ctl_context *ctx) > > free(ipv6_routes); > > } > > > > +static void > > +nbctl_ls_copp_add(struct ctl_context *ctx) > > +{ > > + const char *ls_name = ctx->argv[1]; > > + const char *proto_name = ctx->argv[2]; > > + const char *meter = ctx->argv[3]; > > + > > + char *error = copp_proto_validate(proto_name); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + const struct nbrec_logical_switch *ls = NULL; > > + error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + const struct nbrec_copp *copp = > > + copp_add_meter(ctx, ls->copp, proto_name, meter); > > + nbrec_logical_switch_set_copp(ls, copp); > > +} > > + > > +static void > > +nbctl_ls_copp_del(struct ctl_context *ctx) > > +{ > > + const char *ls_name = ctx->argv[1]; > > + const char *proto_name = NULL; > > + char *error; > > + > > + if (ctx->argc == 3) { > > + proto_name = ctx->argv[2]; > > + error = copp_proto_validate(proto_name); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + } > > + > > + const struct nbrec_logical_switch *ls = NULL; > > + error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + copp_del_meter(ls->copp, proto_name); > > +} > > + > > +static void > > +nbctl_ls_copp_list(struct ctl_context *ctx) > > +{ > > + const char *ls_name = ctx->argv[1]; > > + > > + const struct nbrec_logical_switch *ls = NULL; > > + char *error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + copp_list(ctx, ls->copp); > > +} > > + > > +static void > > +nbctl_lr_copp_add(struct ctl_context *ctx) > > +{ > > + const char *lr_name = ctx->argv[1]; > > + const char *proto_name = ctx->argv[2]; > > + const char *meter = ctx->argv[3]; > > + > > + char *error = copp_proto_validate(proto_name); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + const struct nbrec_logical_router *lr = NULL; > > + error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + const struct nbrec_copp *copp = > > + copp_add_meter(ctx, lr->copp, proto_name, meter); > > + nbrec_logical_router_set_copp(lr, copp); > > +} > > + > > +static void > > +nbctl_lr_copp_del(struct ctl_context *ctx) > > +{ > > + const char *lr_name = ctx->argv[1]; > > + const char *proto_name = NULL; > > + char *error; > > + > > + if (ctx->argc == 3) { > > + proto_name = ctx->argv[2]; > > + error = copp_proto_validate(proto_name); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + } > > + > > + const struct nbrec_logical_router *lr = NULL; > > + error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + copp_del_meter(lr->copp, proto_name); > > +} > > + > > +static void > > +nbctl_lr_copp_list(struct ctl_context *ctx) > > +{ > > + const char *lr_name = ctx->argv[1]; > > + > > + const struct nbrec_logical_router *lr = NULL; > > + char *error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + copp_list(ctx, lr->copp); > > +} > > + > > static void > > verify_connections(struct ctl_context *ctx) > > { > > @@ -6673,6 +6828,18 @@ static const struct ctl_command_syntax > > nbctl_commands[] = { > > {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL, > > nbctl_dhcp_options_get_options, NULL, "", RO }, > > > > + /* Control plane protection commands */ > > + {"ls-copp-add", 3, 3, "SWITCH PROTO METER", NULL, nbctl_ls_copp_add, > > NULL, > > + "", RW}, > > + {"ls-copp-del", 1, 2, "SWITCH [PROTO]", NULL, nbctl_ls_copp_del, NULL, > > + "", RW}, > > + {"ls-copp-list", 1, 1, "SWITCH", NULL, nbctl_ls_copp_list, NULL, "", > > RO}, > > + {"lr-copp-add", 3, 3, "ROUTER PROTO METER", NULL, nbctl_lr_copp_add, > > NULL, > > + "", RW}, > > + {"lr-copp-del", 1, 2, "ROUTER [PROTO]", NULL, nbctl_lr_copp_del, NULL, > > + "", RW}, > > + {"lr-copp-list", 1, 1, "ROUTER", NULL, nbctl_lr_copp_list, NULL, "", > > RO}, > > + > > /* Connection commands. */ > > {"get-connection", 0, 0, "", pre_connection, cmd_get_connection, NULL, > > "", RO}, > > {"del-connection", 0, 0, "", pre_connection, cmd_del_connection, NULL, > > "", RW}, > > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev