Message ID | 20231010141224.638166-5-amusil@redhat.com |
---|---|
State | Changes Requested |
Delegated to: | Ilya Maximets |
Headers | show |
Series | Expose CT limit via DB | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | fail | github build: failed |
ovsrobot/intel-ovs-compilation | success | test: success |
On 10/10/23 16:12, Ales Musil wrote: > Propagate the CT limit that is present in the DB into > datapath. The limit is currently only propagated on change > and can be overwritten by the dpctl commands. > > Signed-off-by: Ales Musil <amusil@redhat.com> > --- > v4: Rebase on top of current master. > Make sure that the values from DB are propagated only if set. That applies to both limit and policies. > --- > ofproto/ofproto-dpif.c | 41 ++++++++++++++++++++++++++ > ofproto/ofproto-dpif.h | 5 ++++ > ofproto/ofproto-provider.h | 4 +++ > ofproto/ofproto.c | 16 ++++++++-- > ofproto/ofproto.h | 4 +++ > tests/system-traffic.at | 54 ++++++++++++++++++++++++++++++++++ > vswitchd/bridge.c | 60 +++++++++++++++++++++++++++++++------- > 7 files changed, 171 insertions(+), 13 deletions(-) > > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index ba5706f6a..4fdbf0ef0 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -220,6 +220,7 @@ static void ofproto_unixctl_init(void); > static void ct_zone_config_init(struct dpif_backer *backer); > static void ct_zone_config_uninit(struct dpif_backer *backer); > static void ct_zone_timeout_policy_sweep(struct dpif_backer *backer); > +static void ct_zone_limits_commit(struct dpif_backer *backer); > > static inline struct ofproto_dpif * > ofproto_dpif_cast(const struct ofproto *ofproto) > @@ -513,6 +514,7 @@ type_run(const char *type) > > process_dpif_port_changes(backer); > ct_zone_timeout_policy_sweep(backer); > + ct_zone_limits_commit(backer); > > return 0; > } > @@ -5522,6 +5524,8 @@ ct_zone_config_init(struct dpif_backer *backer) > cmap_init(&backer->ct_zones); > hmap_init(&backer->ct_tps); > ovs_list_init(&backer->ct_tp_kill_list); > + ovs_list_init(&backer->ct_zone_limits_to_add); > + ovs_list_init(&backer->ct_zone_limits_to_del); > clear_existing_ct_timeout_policies(backer); > } > > @@ -5545,6 +5549,8 @@ ct_zone_config_uninit(struct dpif_backer *backer) > id_pool_destroy(backer->tp_ids); > cmap_destroy(&backer->ct_zones); > hmap_destroy(&backer->ct_tps); > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); > } > > static void > @@ -5625,6 +5631,40 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) > } > } > > +BUILD_ASSERT_DECL(OFPROTO_CT_DEFAULT_ZONE_ID == CT_DPIF_DEFAULT_ZONE); Why this assertion added here? > + > +static void > +ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > + int64_t *limit) > +{ > + struct dpif_backer *backer = shash_find_data(&all_dpif_backers, > + datapath_type); > + if (!backer) { > + return; > + } > + > + if (limit) { > + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_add, zone_id, > + *limit, 0); > + } else { > + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_del, zone_id, 0, 0); > + } > +} > + > +static void > +ct_zone_limits_commit(struct dpif_backer *backer) > +{ > + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_add)) { > + ct_dpif_set_limits(backer->dpif, &backer->ct_zone_limits_to_add); > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); > + } > + > + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_del)) { > + ct_dpif_del_limits(backer->dpif, &backer->ct_zone_limits_to_del); > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); > + } > +} > + > static void > get_datapath_cap(const char *datapath_type, struct smap *cap) > { > @@ -6914,4 +6954,5 @@ const struct ofproto_class ofproto_dpif_class = { > ct_flush, /* ct_flush */ > ct_set_zone_timeout_policy, > ct_del_zone_timeout_policy, > + ct_zone_limit_update, > }; > diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h > index d8e0cd37a..b863dd6fc 100644 > --- a/ofproto/ofproto-dpif.h > +++ b/ofproto/ofproto-dpif.h > @@ -284,6 +284,11 @@ struct dpif_backer { > feature than 'bt_support'. */ > > struct atomic_count tnl_count; > + > + struct ovs_list ct_zone_limits_to_add; /* CT zone limits queued for > + * addition into datapath. */ > + struct ovs_list ct_zone_limits_to_del; /* CT zone limt queued for > + * deletion from datapath. */ > }; > > /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ > diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h > index 9f7b8b6e8..33fb99280 100644 > --- a/ofproto/ofproto-provider.h > +++ b/ofproto/ofproto-provider.h > @@ -1921,6 +1921,10 @@ struct ofproto_class { > /* Deletes the timeout policy associated with 'zone' in datapath type > * 'dp_type'. */ > void (*ct_del_zone_timeout_policy)(const char *dp_type, uint16_t zone); > + > + /* Updates the CT zone limit for specified zone. */ > + void (*ct_zone_limit_update)(const char *dp_type, int32_t zone, > + int64_t *limit); > }; > > extern const struct ofproto_class ofproto_dpif_class; > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > index e78c80d11..6df3f1b27 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -1026,6 +1026,18 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) > > } > > +void > +ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > + int64_t *limit) > +{ > + datapath_type = ofproto_normalize_type(datapath_type); > + const struct ofproto_class *class = ofproto_class_find__(datapath_type); > + > + if (class && class->ct_zone_limit_update) { > + class->ct_zone_limit_update(datapath_type, zone_id, limit); > + } > +} > + > > /* Spanning Tree Protocol (STP) configuration. */ > > @@ -6366,7 +6378,7 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm, > error = ofproto_flow_mod_start(ofproto, &ofm); > if (!error) { > ofproto_bump_tables_version(ofproto); > - error = ofproto_flow_mod_finish(ofproto, &ofm, req); > + error = ofproto_flow_mod_finish(ofproto, &ofm, req); The whitespace thing again. > ofmonitor_flush(ofproto->connmgr); > } > ovs_mutex_unlock(&ofproto_mutex); > @@ -8437,7 +8449,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) > /* Send error referring to the original message. */ > ofconn_send_error(ofconn, be->msg, error); > error = OFPERR_OFPBFC_MSG_FAILED; > - > + And here. > /* 2. Revert. Undo all the changes made above. */ > LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { > if (be->type == OFPTYPE_FLOW_MOD) { > diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h > index 8efdb20a0..bba4a9e0e 100644 > --- a/ofproto/ofproto.h > +++ b/ofproto/ofproto.h > @@ -53,6 +53,8 @@ struct lldp_status; > struct aa_settings; > struct aa_mapping_settings; > > +#define OFPROTO_CT_DEFAULT_ZONE_ID -1 > + > /* Needed for the lock annotations. */ > extern struct ovs_mutex ofproto_mutex; > > @@ -384,6 +386,8 @@ void ofproto_ct_set_zone_timeout_policy(const char *datapath_type, > struct simap *timeout_policy); > void ofproto_ct_del_zone_timeout_policy(const char *datapath_type, > uint16_t zone); > +void ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > + int64_t *limit); > void ofproto_get_datapath_cap(const char *datapath_type, > struct smap *dp_cap); > > diff --git a/tests/system-traffic.at b/tests/system-traffic.at > index f35cfaad9..d2897feb6 100644 > --- a/tests/system-traffic.at > +++ b/tests/system-traffic.at > @@ -5220,6 +5220,60 @@ default limit=0 > zone=4,limit=0,count=0 > ]) > > +dnl Test limit set via database. > +VSCTL_ADD_DATAPATH_TABLE() > + > +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=0]) > +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=3]) > + > +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10]) > +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=3]) > +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl > +default limit=10 > +zone=0,limit=5,count=0 > +]) > + > +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=0 limit=3]) > +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=3 limit=3]) > + > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > +default limit=10 > +zone=0,limit=3,count=0 > +zone=3,limit=3,count=0]) > + > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000200080000 actions=resubmit(,0)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000300080000 actions=resubmit(,0)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000400080000 actions=resubmit(,0)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000500080000 actions=resubmit(,0)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000600080000 actions=resubmit(,0)"]) > + > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3 > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3 > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3 > +]) > + > +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl > +default limit=10 > +zone=0,limit=3,count=0 > +zone=3,limit=3,count=3 > +]) > + > +AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE zone=3]) > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > +default limit=10 > +zone=0,limit=3,count=0]) Are we waiting for all the ct entries to expire here? Might take a lot of time unnecessarily. > + > +AT_CHECK([ovs-vsctl set-zone-default-limit $DP_TYPE limit=5]) > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > +default limit=5 > +zone=0,limit=3,count=0]) > + > +AT_CHECK([ovs-vsctl del-zone-default-limit $DP_TYPE]) > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > +default limit=0 > +zone=0,limit=3,count=0]) > + > OVS_TRAFFIC_VSWITCHD_STOP(["dnl > /could not create datapath/d > /(Cannot allocate memory) on packet/d"]) > diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c > index e9110c1d8..1e02cc8df 100644 > --- a/vswitchd/bridge.c > +++ b/vswitchd/bridge.c > @@ -157,6 +157,7 @@ struct aa_mapping { > /* Internal representation of conntrack zone configuration table in OVSDB. */ > struct ct_zone { > uint16_t zone_id; > + int64_t limit; /* Limit of allowed entries. */ > struct simap tp; /* A map from timeout policy attribute to > * timeout value. */ > struct hmap_node node; /* Node in 'struct datapath' 'ct_zones' > @@ -176,6 +177,7 @@ struct datapath { > unsigned int last_used; /* The last idl_seqno that this 'datapath' > * used in OVSDB. This number is used for > * garbage collection. */ > + int64_t ct_default_limit; /* Default limit for CT zones. */ > }; > > /* All bridges, indexed by name. */ > @@ -722,6 +724,11 @@ datapath_destroy(struct datapath *dp) > ct_zone_remove_and_destroy(dp, ct_zone); Missed updating zone limits here? > } > > + if (dp->ct_default_limit > -1) { > + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, > + NULL); > + } > + > hmap_remove(&all_datapaths, &dp->node); > hmap_destroy(&dp->ct_zones); > free(dp->type); > @@ -743,29 +750,60 @@ ct_zones_reconfigure(struct datapath *dp, struct ovsrec_datapath *dp_cfg) > struct ovsrec_ct_timeout_policy *tp_cfg = zone_cfg->timeout_policy; > > ct_zone = ct_zone_lookup(&dp->ct_zones, zone_id); > - if (ct_zone) { > - struct simap new_tp = SIMAP_INITIALIZER(&new_tp); > - get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); > - if (update_timeout_policy(&ct_zone->tp, &new_tp)) { > + if (!ct_zone) { > + ct_zone = ct_zone_alloc(zone_id, tp_cfg); > + hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); > + } > + > + struct simap new_tp = SIMAP_INITIALIZER(&new_tp); > + get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); > + > + if (update_timeout_policy(&ct_zone->tp, &new_tp)) { > + if (simap_count(&ct_zone->tp)) { Use simap_is_empty() instead. > ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, > &ct_zone->tp); > + } else { > + ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); > } > - } else { > - ct_zone = ct_zone_alloc(zone_id, tp_cfg); > - hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); > - ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, > - &ct_zone->tp); > } > + > + int64_t desired_limit = zone_cfg->limit ? *zone_cfg->limit : -1; > + if (ct_zone->limit != desired_limit) { The 'limit' is not initialiezd to -1 by ct_zone_alloc(). > + ofproto_ct_zone_limit_update(dp->type, zone_id, zone_cfg->limit); > + } > + > + ct_zone->limit = desired_limit; This can be moved into the 'if' statement. > ct_zone->last_used = idl_seqno; > } > > /* Purge 'ct_zone's no longer found in the database. */ > HMAP_FOR_EACH_SAFE (ct_zone, node, &dp->ct_zones) { > - if (ct_zone->last_used != idl_seqno) { > + if (ct_zone->last_used == idl_seqno) { > + continue; > + } > + > + if (simap_count(&ct_zone->tp)) { > ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); > - ct_zone_remove_and_destroy(dp, ct_zone); > } > + > + if (ct_zone->limit > -1) { > + ofproto_ct_zone_limit_update(dp->type, ct_zone->zone_id, NULL); > + } Can we move the checks above into ct_zone_remove_and_destroy() ? This will also help with the missed zone limit updates on datapath destruction. > + > + ct_zone_remove_and_destroy(dp, ct_zone); > + } > + > + /* Reconfigure default CT zone limit if needed. */ > + int64_t default_limit = dp_cfg->ct_zone_default_limit > + ? *dp_cfg->ct_zone_default_limit > + : -1; > + > + if (dp->ct_default_limit != default_limit) { 'ct_default_limit' is used uninitialized here? It is initialized with xzalloc, but it's not -1, i.e. we will issue an unnecessary update command. > + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, > + dp_cfg->ct_zone_default_limit); > } > + > + dp->ct_default_limit = default_limit; Can be moved into the 'if'. > } > > static void
On Mon, Oct 16, 2023 at 9:10 PM Ilya Maximets <i.maximets@ovn.org> wrote: > > On 10/10/23 16:12, Ales Musil wrote: > > Propagate the CT limit that is present in the DB into > > datapath. The limit is currently only propagated on change > > and can be overwritten by the dpctl commands. > > > > Signed-off-by: Ales Musil <amusil@redhat.com> > > --- > > v4: Rebase on top of current master. > > Make sure that the values from DB are propagated only if set. That applies to both limit and policies. > > --- > > ofproto/ofproto-dpif.c | 41 ++++++++++++++++++++++++++ > > ofproto/ofproto-dpif.h | 5 ++++ > > ofproto/ofproto-provider.h | 4 +++ > > ofproto/ofproto.c | 16 ++++++++-- > > ofproto/ofproto.h | 4 +++ > > tests/system-traffic.at | 54 ++++++++++++++++++++++++++++++++++ > > vswitchd/bridge.c | 60 +++++++++++++++++++++++++++++++------- > > 7 files changed, 171 insertions(+), 13 deletions(-) > > > > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > > index ba5706f6a..4fdbf0ef0 100644 > > --- a/ofproto/ofproto-dpif.c > > +++ b/ofproto/ofproto-dpif.c > > @@ -220,6 +220,7 @@ static void ofproto_unixctl_init(void); > > static void ct_zone_config_init(struct dpif_backer *backer); > > static void ct_zone_config_uninit(struct dpif_backer *backer); > > static void ct_zone_timeout_policy_sweep(struct dpif_backer *backer); > > +static void ct_zone_limits_commit(struct dpif_backer *backer); > > > > static inline struct ofproto_dpif * > > ofproto_dpif_cast(const struct ofproto *ofproto) > > @@ -513,6 +514,7 @@ type_run(const char *type) > > > > process_dpif_port_changes(backer); > > ct_zone_timeout_policy_sweep(backer); > > + ct_zone_limits_commit(backer); > > > > return 0; > > } > > @@ -5522,6 +5524,8 @@ ct_zone_config_init(struct dpif_backer *backer) > > cmap_init(&backer->ct_zones); > > hmap_init(&backer->ct_tps); > > ovs_list_init(&backer->ct_tp_kill_list); > > + ovs_list_init(&backer->ct_zone_limits_to_add); > > + ovs_list_init(&backer->ct_zone_limits_to_del); > > clear_existing_ct_timeout_policies(backer); > > } > > > > @@ -5545,6 +5549,8 @@ ct_zone_config_uninit(struct dpif_backer *backer) > > id_pool_destroy(backer->tp_ids); > > cmap_destroy(&backer->ct_zones); > > hmap_destroy(&backer->ct_tps); > > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); > > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); > > } > > > > static void > > @@ -5625,6 +5631,40 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) > > } > > } > > > > +BUILD_ASSERT_DECL(OFPROTO_CT_DEFAULT_ZONE_ID == CT_DPIF_DEFAULT_ZONE); > > Why this assertion added here? > > > + > > +static void > > +ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > > + int64_t *limit) > > +{ > > + struct dpif_backer *backer = shash_find_data(&all_dpif_backers, > > + datapath_type); > > + if (!backer) { > > + return; > > + } > > + > > + if (limit) { > > + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_add, zone_id, > > + *limit, 0); > > + } else { > > + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_del, zone_id, 0, 0); > > + } > > +} > > + > > +static void > > +ct_zone_limits_commit(struct dpif_backer *backer) > > +{ > > + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_add)) { > > + ct_dpif_set_limits(backer->dpif, &backer->ct_zone_limits_to_add); > > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); > > + } > > + > > + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_del)) { > > + ct_dpif_del_limits(backer->dpif, &backer->ct_zone_limits_to_del); > > + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); > > + } > > +} > > + > > static void > > get_datapath_cap(const char *datapath_type, struct smap *cap) > > { > > @@ -6914,4 +6954,5 @@ const struct ofproto_class ofproto_dpif_class = { > > ct_flush, /* ct_flush */ > > ct_set_zone_timeout_policy, > > ct_del_zone_timeout_policy, > > + ct_zone_limit_update, > > }; > > diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h > > index d8e0cd37a..b863dd6fc 100644 > > --- a/ofproto/ofproto-dpif.h > > +++ b/ofproto/ofproto-dpif.h > > @@ -284,6 +284,11 @@ struct dpif_backer { > > feature than 'bt_support'. */ > > > > struct atomic_count tnl_count; > > + > > + struct ovs_list ct_zone_limits_to_add; /* CT zone limits queued for > > + * addition into datapath. */ > > + struct ovs_list ct_zone_limits_to_del; /* CT zone limt queued for > > + * deletion from datapath. */ > > }; > > > > /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ > > diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h > > index 9f7b8b6e8..33fb99280 100644 > > --- a/ofproto/ofproto-provider.h > > +++ b/ofproto/ofproto-provider.h > > @@ -1921,6 +1921,10 @@ struct ofproto_class { > > /* Deletes the timeout policy associated with 'zone' in datapath type > > * 'dp_type'. */ > > void (*ct_del_zone_timeout_policy)(const char *dp_type, uint16_t zone); > > + > > + /* Updates the CT zone limit for specified zone. */ > > + void (*ct_zone_limit_update)(const char *dp_type, int32_t zone, > > + int64_t *limit); > > }; > > > > extern const struct ofproto_class ofproto_dpif_class; > > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > > index e78c80d11..6df3f1b27 100644 > > --- a/ofproto/ofproto.c > > +++ b/ofproto/ofproto.c > > @@ -1026,6 +1026,18 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) > > > > } > > > > +void > > +ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > > + int64_t *limit) > > +{ > > + datapath_type = ofproto_normalize_type(datapath_type); > > + const struct ofproto_class *class = ofproto_class_find__(datapath_type); > > + > > + if (class && class->ct_zone_limit_update) { > > + class->ct_zone_limit_update(datapath_type, zone_id, limit); > > + } > > +} > > + > > > > /* Spanning Tree Protocol (STP) configuration. */ > > > > @@ -6366,7 +6378,7 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm, > > error = ofproto_flow_mod_start(ofproto, &ofm); > > if (!error) { > > ofproto_bump_tables_version(ofproto); > > - error = ofproto_flow_mod_finish(ofproto, &ofm, req); > > + error = ofproto_flow_mod_finish(ofproto, &ofm, req); > > The whitespace thing again. > > > ofmonitor_flush(ofproto->connmgr); > > } > > ovs_mutex_unlock(&ofproto_mutex); > > @@ -8437,7 +8449,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) > > /* Send error referring to the original message. */ > > ofconn_send_error(ofconn, be->msg, error); > > error = OFPERR_OFPBFC_MSG_FAILED; > > - > > + > > And here. > > > /* 2. Revert. Undo all the changes made above. */ > > LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { > > if (be->type == OFPTYPE_FLOW_MOD) { > > diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h > > index 8efdb20a0..bba4a9e0e 100644 > > --- a/ofproto/ofproto.h > > +++ b/ofproto/ofproto.h > > @@ -53,6 +53,8 @@ struct lldp_status; > > struct aa_settings; > > struct aa_mapping_settings; > > > > +#define OFPROTO_CT_DEFAULT_ZONE_ID -1 > > + > > /* Needed for the lock annotations. */ > > extern struct ovs_mutex ofproto_mutex; > > > > @@ -384,6 +386,8 @@ void ofproto_ct_set_zone_timeout_policy(const char *datapath_type, > > struct simap *timeout_policy); > > void ofproto_ct_del_zone_timeout_policy(const char *datapath_type, > > uint16_t zone); > > +void ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, > > + int64_t *limit); > > void ofproto_get_datapath_cap(const char *datapath_type, > > struct smap *dp_cap); > > > > diff --git a/tests/system-traffic.at b/tests/system-traffic.at > > index f35cfaad9..d2897feb6 100644 > > --- a/tests/system-traffic.at > > +++ b/tests/system-traffic.at > > @@ -5220,6 +5220,60 @@ default limit=0 > > zone=4,limit=0,count=0 > > ]) > > > > +dnl Test limit set via database. > > +VSCTL_ADD_DATAPATH_TABLE() > > + > > +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=0]) > > +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=3]) > > + > > +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10]) > > +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=3]) > > +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl > > +default limit=10 > > +zone=0,limit=5,count=0 > > +]) > > + > > +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=0 limit=3]) > > +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=3 limit=3]) > > + > > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > > +default limit=10 > > +zone=0,limit=3,count=0 > > +zone=3,limit=3,count=0]) > > + > > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000200080000 actions=resubmit(,0)"]) > > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000300080000 actions=resubmit(,0)"]) > > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000400080000 actions=resubmit(,0)"]) > > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000500080000 actions=resubmit(,0)"]) > > +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000600080000 actions=resubmit(,0)"]) > > + > > +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl > > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3 > > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3 > > +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3 > > +]) > > + > > +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl > > +default limit=10 > > +zone=0,limit=3,count=0 > > +zone=3,limit=3,count=3 > > +]) > > + > > +AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE zone=3]) > > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > > +default limit=10 > > +zone=0,limit=3,count=0]) > > Are we waiting for all the ct entries to expire here? Might take > a lot of time unnecessarily. The 3 entries are in zone 3, we were removing the limit from zone 3, this just waits for this deletion to take effect. > > > + > > +AT_CHECK([ovs-vsctl set-zone-default-limit $DP_TYPE limit=5]) > > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > > +default limit=5 > > +zone=0,limit=3,count=0]) > > + > > +AT_CHECK([ovs-vsctl del-zone-default-limit $DP_TYPE]) > > +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl > > +default limit=0 > > +zone=0,limit=3,count=0]) > > + > > OVS_TRAFFIC_VSWITCHD_STOP(["dnl > > /could not create datapath/d > > /(Cannot allocate memory) on packet/d"]) > > diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c > > index e9110c1d8..1e02cc8df 100644 > > --- a/vswitchd/bridge.c > > +++ b/vswitchd/bridge.c > > @@ -157,6 +157,7 @@ struct aa_mapping { > > /* Internal representation of conntrack zone configuration table in OVSDB. */ > > struct ct_zone { > > uint16_t zone_id; > > + int64_t limit; /* Limit of allowed entries. */ > > struct simap tp; /* A map from timeout policy attribute to > > * timeout value. */ > > struct hmap_node node; /* Node in 'struct datapath' 'ct_zones' > > @@ -176,6 +177,7 @@ struct datapath { > > unsigned int last_used; /* The last idl_seqno that this 'datapath' > > * used in OVSDB. This number is used for > > * garbage collection. */ > > + int64_t ct_default_limit; /* Default limit for CT zones. */ > > }; > > > > /* All bridges, indexed by name. */ > > @@ -722,6 +724,11 @@ datapath_destroy(struct datapath *dp) > > ct_zone_remove_and_destroy(dp, ct_zone); > > Missed updating zone limits here? > > > } > > > > + if (dp->ct_default_limit > -1) { > > + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, > > + NULL); > > + } > > + > > hmap_remove(&all_datapaths, &dp->node); > > hmap_destroy(&dp->ct_zones); > > free(dp->type); > > @@ -743,29 +750,60 @@ ct_zones_reconfigure(struct datapath *dp, struct ovsrec_datapath *dp_cfg) > > struct ovsrec_ct_timeout_policy *tp_cfg = zone_cfg->timeout_policy; > > > > ct_zone = ct_zone_lookup(&dp->ct_zones, zone_id); > > - if (ct_zone) { > > - struct simap new_tp = SIMAP_INITIALIZER(&new_tp); > > - get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); > > - if (update_timeout_policy(&ct_zone->tp, &new_tp)) { > > + if (!ct_zone) { > > + ct_zone = ct_zone_alloc(zone_id, tp_cfg); > > + hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); > > + } > > + > > + struct simap new_tp = SIMAP_INITIALIZER(&new_tp); > > + get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); > > + > > + if (update_timeout_policy(&ct_zone->tp, &new_tp)) { > > + if (simap_count(&ct_zone->tp)) { > > Use simap_is_empty() instead. > > > ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, > > &ct_zone->tp); > > + } else { > > + ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); > > } > > - } else { > > - ct_zone = ct_zone_alloc(zone_id, tp_cfg); > > - hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); > > - ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, > > - &ct_zone->tp); > > } > > + > > + int64_t desired_limit = zone_cfg->limit ? *zone_cfg->limit : -1; > > + if (ct_zone->limit != desired_limit) { > > The 'limit' is not initialiezd to -1 by ct_zone_alloc(). > > > + ofproto_ct_zone_limit_update(dp->type, zone_id, zone_cfg->limit); > > + } > > + > > + ct_zone->limit = desired_limit; > > This can be moved into the 'if' statement. > > > ct_zone->last_used = idl_seqno; > > } > > > > /* Purge 'ct_zone's no longer found in the database. */ > > HMAP_FOR_EACH_SAFE (ct_zone, node, &dp->ct_zones) { > > - if (ct_zone->last_used != idl_seqno) { > > + if (ct_zone->last_used == idl_seqno) { > > + continue; > > + } > > + > > + if (simap_count(&ct_zone->tp)) { > > ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); > > - ct_zone_remove_and_destroy(dp, ct_zone); > > } > > + > > + if (ct_zone->limit > -1) { > > + ofproto_ct_zone_limit_update(dp->type, ct_zone->zone_id, NULL); > > + } > > Can we move the checks above into ct_zone_remove_and_destroy() ? > This will also help with the missed zone limit updates on datapath > destruction. > > > + > > + ct_zone_remove_and_destroy(dp, ct_zone); > > + } > > + > > + /* Reconfigure default CT zone limit if needed. */ > > + int64_t default_limit = dp_cfg->ct_zone_default_limit > > + ? *dp_cfg->ct_zone_default_limit > > + : -1; > > + > > + if (dp->ct_default_limit != default_limit) { > > 'ct_default_limit' is used uninitialized here? It is initialized > with xzalloc, but it's not -1, i.e. we will issue an unnecessary > update command. > > > + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, > > + dp_cfg->ct_zone_default_limit); > > } > > + > > + dp->ct_default_limit = default_limit; > > Can be moved into the 'if'. > > > } > > > > static void > Everything else will be addressed in v5. Thanks, Ales -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA amusil@redhat.com
On 10/18/23 09:56, Ales Musil wrote: > On Mon, Oct 16, 2023 at 9:10 PM Ilya Maximets <i.maximets@ovn.org> wrote: >> >> On 10/10/23 16:12, Ales Musil wrote: >>> Propagate the CT limit that is present in the DB into >>> datapath. The limit is currently only propagated on change >>> and can be overwritten by the dpctl commands. >>> >>> Signed-off-by: Ales Musil <amusil@redhat.com> >>> --- >>> v4: Rebase on top of current master. >>> Make sure that the values from DB are propagated only if set. That applies to both limit and policies. >>> --- >>> ofproto/ofproto-dpif.c | 41 ++++++++++++++++++++++++++ >>> ofproto/ofproto-dpif.h | 5 ++++ >>> ofproto/ofproto-provider.h | 4 +++ >>> ofproto/ofproto.c | 16 ++++++++-- >>> ofproto/ofproto.h | 4 +++ >>> tests/system-traffic.at | 54 ++++++++++++++++++++++++++++++++++ >>> vswitchd/bridge.c | 60 +++++++++++++++++++++++++++++++------- >>> 7 files changed, 171 insertions(+), 13 deletions(-) >>> >>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c >>> index ba5706f6a..4fdbf0ef0 100644 >>> --- a/ofproto/ofproto-dpif.c >>> +++ b/ofproto/ofproto-dpif.c >>> @@ -220,6 +220,7 @@ static void ofproto_unixctl_init(void); >>> static void ct_zone_config_init(struct dpif_backer *backer); >>> static void ct_zone_config_uninit(struct dpif_backer *backer); >>> static void ct_zone_timeout_policy_sweep(struct dpif_backer *backer); >>> +static void ct_zone_limits_commit(struct dpif_backer *backer); >>> >>> static inline struct ofproto_dpif * >>> ofproto_dpif_cast(const struct ofproto *ofproto) >>> @@ -513,6 +514,7 @@ type_run(const char *type) >>> >>> process_dpif_port_changes(backer); >>> ct_zone_timeout_policy_sweep(backer); >>> + ct_zone_limits_commit(backer); >>> >>> return 0; >>> } >>> @@ -5522,6 +5524,8 @@ ct_zone_config_init(struct dpif_backer *backer) >>> cmap_init(&backer->ct_zones); >>> hmap_init(&backer->ct_tps); >>> ovs_list_init(&backer->ct_tp_kill_list); >>> + ovs_list_init(&backer->ct_zone_limits_to_add); >>> + ovs_list_init(&backer->ct_zone_limits_to_del); >>> clear_existing_ct_timeout_policies(backer); >>> } >>> >>> @@ -5545,6 +5549,8 @@ ct_zone_config_uninit(struct dpif_backer *backer) >>> id_pool_destroy(backer->tp_ids); >>> cmap_destroy(&backer->ct_zones); >>> hmap_destroy(&backer->ct_tps); >>> + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); >>> + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); >>> } >>> >>> static void >>> @@ -5625,6 +5631,40 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) >>> } >>> } >>> >>> +BUILD_ASSERT_DECL(OFPROTO_CT_DEFAULT_ZONE_ID == CT_DPIF_DEFAULT_ZONE); >> >> Why this assertion added here? >> >>> + >>> +static void >>> +ct_zone_limit_update(const char *datapath_type, int32_t zone_id, >>> + int64_t *limit) >>> +{ >>> + struct dpif_backer *backer = shash_find_data(&all_dpif_backers, >>> + datapath_type); >>> + if (!backer) { >>> + return; >>> + } >>> + >>> + if (limit) { >>> + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_add, zone_id, >>> + *limit, 0); >>> + } else { >>> + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_del, zone_id, 0, 0); >>> + } >>> +} >>> + >>> +static void >>> +ct_zone_limits_commit(struct dpif_backer *backer) >>> +{ >>> + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_add)) { >>> + ct_dpif_set_limits(backer->dpif, &backer->ct_zone_limits_to_add); >>> + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); >>> + } >>> + >>> + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_del)) { >>> + ct_dpif_del_limits(backer->dpif, &backer->ct_zone_limits_to_del); >>> + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); >>> + } >>> +} >>> + >>> static void >>> get_datapath_cap(const char *datapath_type, struct smap *cap) >>> { >>> @@ -6914,4 +6954,5 @@ const struct ofproto_class ofproto_dpif_class = { >>> ct_flush, /* ct_flush */ >>> ct_set_zone_timeout_policy, >>> ct_del_zone_timeout_policy, >>> + ct_zone_limit_update, >>> }; >>> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h >>> index d8e0cd37a..b863dd6fc 100644 >>> --- a/ofproto/ofproto-dpif.h >>> +++ b/ofproto/ofproto-dpif.h >>> @@ -284,6 +284,11 @@ struct dpif_backer { >>> feature than 'bt_support'. */ >>> >>> struct atomic_count tnl_count; >>> + >>> + struct ovs_list ct_zone_limits_to_add; /* CT zone limits queued for >>> + * addition into datapath. */ >>> + struct ovs_list ct_zone_limits_to_del; /* CT zone limt queued for >>> + * deletion from datapath. */ >>> }; >>> >>> /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ >>> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h >>> index 9f7b8b6e8..33fb99280 100644 >>> --- a/ofproto/ofproto-provider.h >>> +++ b/ofproto/ofproto-provider.h >>> @@ -1921,6 +1921,10 @@ struct ofproto_class { >>> /* Deletes the timeout policy associated with 'zone' in datapath type >>> * 'dp_type'. */ >>> void (*ct_del_zone_timeout_policy)(const char *dp_type, uint16_t zone); >>> + >>> + /* Updates the CT zone limit for specified zone. */ >>> + void (*ct_zone_limit_update)(const char *dp_type, int32_t zone, >>> + int64_t *limit); >>> }; >>> >>> extern const struct ofproto_class ofproto_dpif_class; >>> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c >>> index e78c80d11..6df3f1b27 100644 >>> --- a/ofproto/ofproto.c >>> +++ b/ofproto/ofproto.c >>> @@ -1026,6 +1026,18 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) >>> >>> } >>> >>> +void >>> +ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, >>> + int64_t *limit) >>> +{ >>> + datapath_type = ofproto_normalize_type(datapath_type); >>> + const struct ofproto_class *class = ofproto_class_find__(datapath_type); >>> + >>> + if (class && class->ct_zone_limit_update) { >>> + class->ct_zone_limit_update(datapath_type, zone_id, limit); >>> + } >>> +} >>> + >>> >>> /* Spanning Tree Protocol (STP) configuration. */ >>> >>> @@ -6366,7 +6378,7 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm, >>> error = ofproto_flow_mod_start(ofproto, &ofm); >>> if (!error) { >>> ofproto_bump_tables_version(ofproto); >>> - error = ofproto_flow_mod_finish(ofproto, &ofm, req); >>> + error = ofproto_flow_mod_finish(ofproto, &ofm, req); >> >> The whitespace thing again. >> >>> ofmonitor_flush(ofproto->connmgr); >>> } >>> ovs_mutex_unlock(&ofproto_mutex); >>> @@ -8437,7 +8449,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) >>> /* Send error referring to the original message. */ >>> ofconn_send_error(ofconn, be->msg, error); >>> error = OFPERR_OFPBFC_MSG_FAILED; >>> - >>> + >> >> And here. >> >>> /* 2. Revert. Undo all the changes made above. */ >>> LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { >>> if (be->type == OFPTYPE_FLOW_MOD) { >>> diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h >>> index 8efdb20a0..bba4a9e0e 100644 >>> --- a/ofproto/ofproto.h >>> +++ b/ofproto/ofproto.h >>> @@ -53,6 +53,8 @@ struct lldp_status; >>> struct aa_settings; >>> struct aa_mapping_settings; >>> >>> +#define OFPROTO_CT_DEFAULT_ZONE_ID -1 >>> + >>> /* Needed for the lock annotations. */ >>> extern struct ovs_mutex ofproto_mutex; >>> >>> @@ -384,6 +386,8 @@ void ofproto_ct_set_zone_timeout_policy(const char *datapath_type, >>> struct simap *timeout_policy); >>> void ofproto_ct_del_zone_timeout_policy(const char *datapath_type, >>> uint16_t zone); >>> +void ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, >>> + int64_t *limit); >>> void ofproto_get_datapath_cap(const char *datapath_type, >>> struct smap *dp_cap); >>> >>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at >>> index f35cfaad9..d2897feb6 100644 >>> --- a/tests/system-traffic.at >>> +++ b/tests/system-traffic.at >>> @@ -5220,6 +5220,60 @@ default limit=0 >>> zone=4,limit=0,count=0 >>> ]) >>> >>> +dnl Test limit set via database. >>> +VSCTL_ADD_DATAPATH_TABLE() >>> + >>> +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=0]) >>> +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=3]) >>> + >>> +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10]) >>> +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=3]) >>> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl >>> +default limit=10 >>> +zone=0,limit=5,count=0 >>> +]) >>> + >>> +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=0 limit=3]) >>> +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=3 limit=3]) >>> + >>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl >>> +default limit=10 >>> +zone=0,limit=3,count=0 >>> +zone=3,limit=3,count=0]) >>> + >>> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000200080000 actions=resubmit(,0)"]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000300080000 actions=resubmit(,0)"]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000400080000 actions=resubmit(,0)"]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000500080000 actions=resubmit(,0)"]) >>> +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000600080000 actions=resubmit(,0)"]) >>> + >>> +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl >>> +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3 >>> +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3 >>> +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3 >>> +]) >>> + >>> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl >>> +default limit=10 >>> +zone=0,limit=3,count=0 >>> +zone=3,limit=3,count=3 >>> +]) >>> + >>> +AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE zone=3]) >>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl >>> +default limit=10 >>> +zone=0,limit=3,count=0]) >> >> Are we waiting for all the ct entries to expire here? Might take >> a lot of time unnecessarily. > > > The 3 entries are in zone 3, we were removing the limit from zone 3, > this just waits for this deletion to take effect. Oh, you're right. I looked at the wrong place. :) > >> >>> + >>> +AT_CHECK([ovs-vsctl set-zone-default-limit $DP_TYPE limit=5]) >>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl >>> +default limit=5 >>> +zone=0,limit=3,count=0]) >>> + >>> +AT_CHECK([ovs-vsctl del-zone-default-limit $DP_TYPE]) >>> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl >>> +default limit=0 >>> +zone=0,limit=3,count=0]) >>> + >>> OVS_TRAFFIC_VSWITCHD_STOP(["dnl >>> /could not create datapath/d >>> /(Cannot allocate memory) on packet/d"]) >>> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c >>> index e9110c1d8..1e02cc8df 100644 >>> --- a/vswitchd/bridge.c >>> +++ b/vswitchd/bridge.c >>> @@ -157,6 +157,7 @@ struct aa_mapping { >>> /* Internal representation of conntrack zone configuration table in OVSDB. */ >>> struct ct_zone { >>> uint16_t zone_id; >>> + int64_t limit; /* Limit of allowed entries. */ >>> struct simap tp; /* A map from timeout policy attribute to >>> * timeout value. */ >>> struct hmap_node node; /* Node in 'struct datapath' 'ct_zones' >>> @@ -176,6 +177,7 @@ struct datapath { >>> unsigned int last_used; /* The last idl_seqno that this 'datapath' >>> * used in OVSDB. This number is used for >>> * garbage collection. */ >>> + int64_t ct_default_limit; /* Default limit for CT zones. */ >>> }; >>> >>> /* All bridges, indexed by name. */ >>> @@ -722,6 +724,11 @@ datapath_destroy(struct datapath *dp) >>> ct_zone_remove_and_destroy(dp, ct_zone); >> >> Missed updating zone limits here? >> >>> } >>> >>> + if (dp->ct_default_limit > -1) { >>> + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, >>> + NULL); >>> + } >>> + >>> hmap_remove(&all_datapaths, &dp->node); >>> hmap_destroy(&dp->ct_zones); >>> free(dp->type); >>> @@ -743,29 +750,60 @@ ct_zones_reconfigure(struct datapath *dp, struct ovsrec_datapath *dp_cfg) >>> struct ovsrec_ct_timeout_policy *tp_cfg = zone_cfg->timeout_policy; >>> >>> ct_zone = ct_zone_lookup(&dp->ct_zones, zone_id); >>> - if (ct_zone) { >>> - struct simap new_tp = SIMAP_INITIALIZER(&new_tp); >>> - get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); >>> - if (update_timeout_policy(&ct_zone->tp, &new_tp)) { >>> + if (!ct_zone) { >>> + ct_zone = ct_zone_alloc(zone_id, tp_cfg); >>> + hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); >>> + } >>> + >>> + struct simap new_tp = SIMAP_INITIALIZER(&new_tp); >>> + get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); >>> + >>> + if (update_timeout_policy(&ct_zone->tp, &new_tp)) { >>> + if (simap_count(&ct_zone->tp)) { >> >> Use simap_is_empty() instead. >> >>> ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, >>> &ct_zone->tp); >>> + } else { >>> + ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); >>> } >>> - } else { >>> - ct_zone = ct_zone_alloc(zone_id, tp_cfg); >>> - hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); >>> - ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, >>> - &ct_zone->tp); >>> } >>> + >>> + int64_t desired_limit = zone_cfg->limit ? *zone_cfg->limit : -1; >>> + if (ct_zone->limit != desired_limit) { >> >> The 'limit' is not initialiezd to -1 by ct_zone_alloc(). >> >>> + ofproto_ct_zone_limit_update(dp->type, zone_id, zone_cfg->limit); >>> + } >>> + >>> + ct_zone->limit = desired_limit; >> >> This can be moved into the 'if' statement. >> >>> ct_zone->last_used = idl_seqno; >>> } >>> >>> /* Purge 'ct_zone's no longer found in the database. */ >>> HMAP_FOR_EACH_SAFE (ct_zone, node, &dp->ct_zones) { >>> - if (ct_zone->last_used != idl_seqno) { >>> + if (ct_zone->last_used == idl_seqno) { >>> + continue; >>> + } >>> + >>> + if (simap_count(&ct_zone->tp)) { >>> ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); >>> - ct_zone_remove_and_destroy(dp, ct_zone); >>> } >>> + >>> + if (ct_zone->limit > -1) { >>> + ofproto_ct_zone_limit_update(dp->type, ct_zone->zone_id, NULL); >>> + } >> >> Can we move the checks above into ct_zone_remove_and_destroy() ? >> This will also help with the missed zone limit updates on datapath >> destruction. >> >>> + >>> + ct_zone_remove_and_destroy(dp, ct_zone); >>> + } >>> + >>> + /* Reconfigure default CT zone limit if needed. */ >>> + int64_t default_limit = dp_cfg->ct_zone_default_limit >>> + ? *dp_cfg->ct_zone_default_limit >>> + : -1; >>> + >>> + if (dp->ct_default_limit != default_limit) { >> >> 'ct_default_limit' is used uninitialized here? It is initialized >> with xzalloc, but it's not -1, i.e. we will issue an unnecessary >> update command. >> >>> + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, >>> + dp_cfg->ct_zone_default_limit); >>> } >>> + >>> + dp->ct_default_limit = default_limit; >> >> Can be moved into the 'if'. >> >>> } >>> >>> static void >> > > Everything else will be addressed in v5. > > Thanks, > Ales > > > -- > > Ales Musil > > Senior Software Engineer - OVN Core > > Red Hat EMEA > > amusil@redhat.com >
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index ba5706f6a..4fdbf0ef0 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -220,6 +220,7 @@ static void ofproto_unixctl_init(void); static void ct_zone_config_init(struct dpif_backer *backer); static void ct_zone_config_uninit(struct dpif_backer *backer); static void ct_zone_timeout_policy_sweep(struct dpif_backer *backer); +static void ct_zone_limits_commit(struct dpif_backer *backer); static inline struct ofproto_dpif * ofproto_dpif_cast(const struct ofproto *ofproto) @@ -513,6 +514,7 @@ type_run(const char *type) process_dpif_port_changes(backer); ct_zone_timeout_policy_sweep(backer); + ct_zone_limits_commit(backer); return 0; } @@ -5522,6 +5524,8 @@ ct_zone_config_init(struct dpif_backer *backer) cmap_init(&backer->ct_zones); hmap_init(&backer->ct_tps); ovs_list_init(&backer->ct_tp_kill_list); + ovs_list_init(&backer->ct_zone_limits_to_add); + ovs_list_init(&backer->ct_zone_limits_to_del); clear_existing_ct_timeout_policies(backer); } @@ -5545,6 +5549,8 @@ ct_zone_config_uninit(struct dpif_backer *backer) id_pool_destroy(backer->tp_ids); cmap_destroy(&backer->ct_zones); hmap_destroy(&backer->ct_tps); + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); } static void @@ -5625,6 +5631,40 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) } } +BUILD_ASSERT_DECL(OFPROTO_CT_DEFAULT_ZONE_ID == CT_DPIF_DEFAULT_ZONE); + +static void +ct_zone_limit_update(const char *datapath_type, int32_t zone_id, + int64_t *limit) +{ + struct dpif_backer *backer = shash_find_data(&all_dpif_backers, + datapath_type); + if (!backer) { + return; + } + + if (limit) { + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_add, zone_id, + *limit, 0); + } else { + ct_dpif_push_zone_limit(&backer->ct_zone_limits_to_del, zone_id, 0, 0); + } +} + +static void +ct_zone_limits_commit(struct dpif_backer *backer) +{ + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_add)) { + ct_dpif_set_limits(backer->dpif, &backer->ct_zone_limits_to_add); + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_add); + } + + if (!ovs_list_is_empty(&backer->ct_zone_limits_to_del)) { + ct_dpif_del_limits(backer->dpif, &backer->ct_zone_limits_to_del); + ct_dpif_free_zone_limits(&backer->ct_zone_limits_to_del); + } +} + static void get_datapath_cap(const char *datapath_type, struct smap *cap) { @@ -6914,4 +6954,5 @@ const struct ofproto_class ofproto_dpif_class = { ct_flush, /* ct_flush */ ct_set_zone_timeout_policy, ct_del_zone_timeout_policy, + ct_zone_limit_update, }; diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index d8e0cd37a..b863dd6fc 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -284,6 +284,11 @@ struct dpif_backer { feature than 'bt_support'. */ struct atomic_count tnl_count; + + struct ovs_list ct_zone_limits_to_add; /* CT zone limits queued for + * addition into datapath. */ + struct ovs_list ct_zone_limits_to_del; /* CT zone limt queued for + * deletion from datapath. */ }; /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 9f7b8b6e8..33fb99280 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1921,6 +1921,10 @@ struct ofproto_class { /* Deletes the timeout policy associated with 'zone' in datapath type * 'dp_type'. */ void (*ct_del_zone_timeout_policy)(const char *dp_type, uint16_t zone); + + /* Updates the CT zone limit for specified zone. */ + void (*ct_zone_limit_update)(const char *dp_type, int32_t zone, + int64_t *limit); }; extern const struct ofproto_class ofproto_dpif_class; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index e78c80d11..6df3f1b27 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1026,6 +1026,18 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) } +void +ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, + int64_t *limit) +{ + datapath_type = ofproto_normalize_type(datapath_type); + const struct ofproto_class *class = ofproto_class_find__(datapath_type); + + if (class && class->ct_zone_limit_update) { + class->ct_zone_limit_update(datapath_type, zone_id, limit); + } +} + /* Spanning Tree Protocol (STP) configuration. */ @@ -6366,7 +6378,7 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm, error = ofproto_flow_mod_start(ofproto, &ofm); if (!error) { ofproto_bump_tables_version(ofproto); - error = ofproto_flow_mod_finish(ofproto, &ofm, req); + error = ofproto_flow_mod_finish(ofproto, &ofm, req); ofmonitor_flush(ofproto->connmgr); } ovs_mutex_unlock(&ofproto_mutex); @@ -8437,7 +8449,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) /* Send error referring to the original message. */ ofconn_send_error(ofconn, be->msg, error); error = OFPERR_OFPBFC_MSG_FAILED; - + /* 2. Revert. Undo all the changes made above. */ LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { if (be->type == OFPTYPE_FLOW_MOD) { diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 8efdb20a0..bba4a9e0e 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -53,6 +53,8 @@ struct lldp_status; struct aa_settings; struct aa_mapping_settings; +#define OFPROTO_CT_DEFAULT_ZONE_ID -1 + /* Needed for the lock annotations. */ extern struct ovs_mutex ofproto_mutex; @@ -384,6 +386,8 @@ void ofproto_ct_set_zone_timeout_policy(const char *datapath_type, struct simap *timeout_policy); void ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone); +void ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id, + int64_t *limit); void ofproto_get_datapath_cap(const char *datapath_type, struct smap *dp_cap); diff --git a/tests/system-traffic.at b/tests/system-traffic.at index f35cfaad9..d2897feb6 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -5220,6 +5220,60 @@ default limit=0 zone=4,limit=0,count=0 ]) +dnl Test limit set via database. +VSCTL_ADD_DATAPATH_TABLE() + +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=0]) +AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=3]) + +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10]) +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=3]) +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl +default limit=10 +zone=0,limit=5,count=0 +]) + +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=0 limit=3]) +AT_CHECK([ovs-vsctl add-zone-limit $DP_TYPE zone=3 limit=3]) + +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl +default limit=10 +zone=0,limit=3,count=0 +zone=3,limit=3,count=0]) + +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000200080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000300080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000400080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000500080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4c90a0101030a0101040001000600080000 actions=resubmit(,0)"]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3 +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3 +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3 +]) + +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl +default limit=10 +zone=0,limit=3,count=0 +zone=3,limit=3,count=3 +]) + +AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE zone=3]) +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl +default limit=10 +zone=0,limit=3,count=0]) + +AT_CHECK([ovs-vsctl set-zone-default-limit $DP_TYPE limit=5]) +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl +default limit=5 +zone=0,limit=3,count=0]) + +AT_CHECK([ovs-vsctl del-zone-default-limit $DP_TYPE]) +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], [dnl +default limit=0 +zone=0,limit=3,count=0]) + OVS_TRAFFIC_VSWITCHD_STOP(["dnl /could not create datapath/d /(Cannot allocate memory) on packet/d"]) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e9110c1d8..1e02cc8df 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -157,6 +157,7 @@ struct aa_mapping { /* Internal representation of conntrack zone configuration table in OVSDB. */ struct ct_zone { uint16_t zone_id; + int64_t limit; /* Limit of allowed entries. */ struct simap tp; /* A map from timeout policy attribute to * timeout value. */ struct hmap_node node; /* Node in 'struct datapath' 'ct_zones' @@ -176,6 +177,7 @@ struct datapath { unsigned int last_used; /* The last idl_seqno that this 'datapath' * used in OVSDB. This number is used for * garbage collection. */ + int64_t ct_default_limit; /* Default limit for CT zones. */ }; /* All bridges, indexed by name. */ @@ -722,6 +724,11 @@ datapath_destroy(struct datapath *dp) ct_zone_remove_and_destroy(dp, ct_zone); } + if (dp->ct_default_limit > -1) { + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, + NULL); + } + hmap_remove(&all_datapaths, &dp->node); hmap_destroy(&dp->ct_zones); free(dp->type); @@ -743,29 +750,60 @@ ct_zones_reconfigure(struct datapath *dp, struct ovsrec_datapath *dp_cfg) struct ovsrec_ct_timeout_policy *tp_cfg = zone_cfg->timeout_policy; ct_zone = ct_zone_lookup(&dp->ct_zones, zone_id); - if (ct_zone) { - struct simap new_tp = SIMAP_INITIALIZER(&new_tp); - get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); - if (update_timeout_policy(&ct_zone->tp, &new_tp)) { + if (!ct_zone) { + ct_zone = ct_zone_alloc(zone_id, tp_cfg); + hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); + } + + struct simap new_tp = SIMAP_INITIALIZER(&new_tp); + get_timeout_policy_from_ovsrec(&new_tp, tp_cfg); + + if (update_timeout_policy(&ct_zone->tp, &new_tp)) { + if (simap_count(&ct_zone->tp)) { ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, &ct_zone->tp); + } else { + ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); } - } else { - ct_zone = ct_zone_alloc(zone_id, tp_cfg); - hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0)); - ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id, - &ct_zone->tp); } + + int64_t desired_limit = zone_cfg->limit ? *zone_cfg->limit : -1; + if (ct_zone->limit != desired_limit) { + ofproto_ct_zone_limit_update(dp->type, zone_id, zone_cfg->limit); + } + + ct_zone->limit = desired_limit; ct_zone->last_used = idl_seqno; } /* Purge 'ct_zone's no longer found in the database. */ HMAP_FOR_EACH_SAFE (ct_zone, node, &dp->ct_zones) { - if (ct_zone->last_used != idl_seqno) { + if (ct_zone->last_used == idl_seqno) { + continue; + } + + if (simap_count(&ct_zone->tp)) { ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id); - ct_zone_remove_and_destroy(dp, ct_zone); } + + if (ct_zone->limit > -1) { + ofproto_ct_zone_limit_update(dp->type, ct_zone->zone_id, NULL); + } + + ct_zone_remove_and_destroy(dp, ct_zone); + } + + /* Reconfigure default CT zone limit if needed. */ + int64_t default_limit = dp_cfg->ct_zone_default_limit + ? *dp_cfg->ct_zone_default_limit + : -1; + + if (dp->ct_default_limit != default_limit) { + ofproto_ct_zone_limit_update(dp->type, OFPROTO_CT_DEFAULT_ZONE_ID, + dp_cfg->ct_zone_default_limit); } + + dp->ct_default_limit = default_limit; } static void
Propagate the CT limit that is present in the DB into datapath. The limit is currently only propagated on change and can be overwritten by the dpctl commands. Signed-off-by: Ales Musil <amusil@redhat.com> --- v4: Rebase on top of current master. Make sure that the values from DB are propagated only if set. That applies to both limit and policies. --- ofproto/ofproto-dpif.c | 41 ++++++++++++++++++++++++++ ofproto/ofproto-dpif.h | 5 ++++ ofproto/ofproto-provider.h | 4 +++ ofproto/ofproto.c | 16 ++++++++-- ofproto/ofproto.h | 4 +++ tests/system-traffic.at | 54 ++++++++++++++++++++++++++++++++++ vswitchd/bridge.c | 60 +++++++++++++++++++++++++++++++------- 7 files changed, 171 insertions(+), 13 deletions(-)