Sure, that's perfect. Thanks, Antonio
> -----Original Message----- > From: Darrell Ball [mailto:db...@vmware.com] > Sent: Friday, December 15, 2017 7:23 PM > To: Fischetti, Antonio <antonio.fische...@intel.com>; > d...@openvswitch.org > Subject: Re: [ovs-dev] [PATCH v3 2/5] conntrack: add commands to r/w CT > parameters. > > Hi Antonio > > Alternatively, given that most of code is rewritten, I was planning on > just submitting the patches, which are in process, and adding you as co- > author. > Will that work for you? > > Thanks Darrell > > > > On 12/15/17, 11:05 AM, "Fischetti, Antonio" > <antonio.fische...@intel.com> wrote: > > Thanks Darrell for your review. > I agree with your comments, if we have to consider R/W commands with > more than one parameter is much better to have specific functions > as you explained and showed. > > I'll rework accordingly and post a v4. > > Regards, > -Antonio > > > -----Original Message----- > > From: Darrell Ball [mailto:db...@vmware.com] > > Sent: Monday, December 11, 2017 6:44 PM > > To: Fischetti, Antonio <antonio.fische...@intel.com>; > > d...@openvswitch.org > > Subject: Re: [ovs-dev] [PATCH v3 2/5] conntrack: add commands to > r/w CT > > parameters. > > > > One extra note inline > > > > Thanks Darrell > > > > On 12/11/17, 8:35 AM, "Darrell Ball" <db...@vmware.com> wrote: > > > > Thanks Antonio for doing all this and pushing it forward. > > > > Regarding patches 2-4: > > > > I understand you want to save some code for various possible > set and > > get operations. > > The prior art for these commands is however not generic set > and get > > commands. > > Sometimes, we have specific commands that can take different > numbers > > of arguments but > > those are specific and the context is clear. > > If we take some examples, we might see there is an issue with > the > > approach here. > > Take per zone limits as one example, which is an internal > > requirement that we are working on > > across datapaths. > > This is a set operation with 2 arguments plus the datapath = 3 > > arguments. > > This won’t work with the generic set functions here. > > The corresponding get will not work either. > > Trying to make this work generically will get pretty messy and > the > > parameter validation error prone. > > > > I would like to propose an alternative (a simple one; also > with code > > consolidation and more error checking) below: > > Please let me know what you think. > > > > Thanks Darrell > > > > > /////////////////////////////////////////////////////////////// > > > > diff --git a/lib/conntrack.c b/lib/conntrack.c > > index f5a3aa9..c8ad548 100644 > > --- a/lib/conntrack.c > > +++ b/lib/conntrack.c > > @@ -2485,6 +2485,27 @@ conntrack_flush(struct conntrack *ct, > const > > uint16_t *zone) > > return 0; > > } > > > > +int > > +conntrack_set_maxconns(struct conntrack *ct, uint32_t > maxconns) > > +{ > > + atomic_init(&ct->n_conn_limit, maxconns); > > + return 0; > > +} > > + > > +int > > +conntrack_get_maxconns(struct conntrack *ct, uint32_t > *maxconns) > > +{ > > + atomic_read_relaxed(&ct->n_conn_limit, maxconns); > > + return 0; > > +} > > + > > +int > > +conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns) > > +{ > > + *nconns = atomic_count_get(&ct->n_conn); > > + return 0; > > +} > > + > > /* This function must be called with the ct->resources read > lock > > taken. */ > > static struct alg_exp_node * > > expectation_lookup(struct hmap *alg_expectations, > > diff --git a/lib/conntrack.h b/lib/conntrack.h > > index fbeef1c..8652724 100644 > > --- a/lib/conntrack.h > > +++ b/lib/conntrack.h > > @@ -114,6 +114,9 @@ int conntrack_dump_next(struct > conntrack_dump *, > > struct ct_dpif_entry *); > > int conntrack_dump_done(struct conntrack_dump *); > > > > int conntrack_flush(struct conntrack *, const uint16_t > *zone); > > +int conntrack_set_maxconns(struct conntrack *ct, uint32_t > > maxconns); > > +int conntrack_get_maxconns(struct conntrack *ct, uint32_t > > *maxconns); > > +int conntrack_get_nconns(struct conntrack *ct, uint32_t > *nconns); > > ^L > > /* 'struct ct_lock' is a wrapper for an adaptive mutex. It's > > useful to try > > * different types of locks (e.g. spinlocks) */ > > diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c > > index 239c848..5fa3a97 100644 > > --- a/lib/ct-dpif.c > > +++ b/lib/ct-dpif.c > > @@ -140,6 +140,30 @@ ct_dpif_flush(struct dpif *dpif, const > uint16_t > > *zone, > > : EOPNOTSUPP); > > } > > > > +int > > +ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns) > > +{ > > + return (dpif->dpif_class->ct_set_maxconns > > + ? dpif->dpif_class->ct_set_maxconns(dpif, > maxconns) > > + : EOPNOTSUPP); > > +} > > + > > +int > > +ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns) > > +{ > > + return (dpif->dpif_class->ct_get_maxconns > > + ? dpif->dpif_class->ct_get_maxconns(dpif, > maxconns) > > + : EOPNOTSUPP); > > +} > > + > > +int > > +ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns) > > +{ > > + return (dpif->dpif_class->ct_get_nconns > > + ? dpif->dpif_class->ct_get_nconns(dpif, nconns) > > + : EOPNOTSUPP); > > +} > > + > > void > > ct_dpif_entry_uninit(struct ct_dpif_entry *entry) > > { > > diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h > > index 5e2de53..09e7698 100644 > > --- a/lib/ct-dpif.h > > +++ b/lib/ct-dpif.h > > @@ -197,6 +197,9 @@ int ct_dpif_dump_next(struct > ct_dpif_dump_state > > *, struct ct_dpif_entry *); > > int ct_dpif_dump_done(struct ct_dpif_dump_state *); > > int ct_dpif_flush(struct dpif *, const uint16_t *zone, > > const struct ct_dpif_tuple *); > > +int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t > maxconns); > > +int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t > *maxconns); > > +int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); > > void ct_dpif_entry_uninit(struct ct_dpif_entry *); > > void ct_dpif_format_entry(const struct ct_dpif_entry *, > struct ds > > *, > > bool verbose, bool print_stats); > > diff --git a/lib/dpctl.c b/lib/dpctl.c > > index a28ded9..215d1c3 100644 > > --- a/lib/dpctl.c > > +++ b/lib/dpctl.c > > @@ -1654,6 +1654,96 @@ dpctl_ct_bkts(int argc, const char > *argv[], > > return error; > > } > > ^L > > +static int > > +dpctl_ct_open_dp(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p, struct dpif > **dpif) > > +{ > > + int error = 0; > > + /* The datapath name is not a mandatory parameter for > this > > command. > > + * If it is not specified - so argc < 3 - we retrieve it > from > > the > > + * current setup, assuming only one exists. */ > > + char *dpname = argc == 3 ? xstrdup(argv[1]) : > > get_one_dp(dpctl_p); > > > > > > [Darrell] The ‘3’ here would be replaced with a parameter > representing > > the number > > of parameters expected when the dp is included in > the > > parameter list. > > > > > > + if (!dpname) { > > + error = EINVAL; > > + dpctl_error(dpctl_p, error, "datapath not found"); > > + } else { > > + error = parsed_dpif_open(dpname, false, dpif); > > + free(dpname); > > + if (error) { > > + dpctl_error(dpctl_p, error, "opening datapath"); > > + } > > + } > > + return error; > > +} > > + > > +static int > > +dpctl_ct_set_maxconns(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p) > > +{ > > + struct dpif *dpif; > > + int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif); > > + if (!error) { > > + uint32_t maxconns; > > + if (ovs_scan(argv[argc - 1], "%"SCNu32, &maxconns)) { > > + error = ct_dpif_set_maxconns(dpif, maxconns); > > + dpif_close(dpif); > > + > > + if (!error) { > > + dpctl_print(dpctl_p, "Ok"); > > + } else { > > + dpctl_error(dpctl_p, error, "ct set maxconns > > failed"); > > + } > > + } else { > > + error = EINVAL; > > + dpctl_error(dpctl_p, error, "maxconns missing or > > malformed"); > > + } > > + } > > + > > + return error; > > +} > > + > > +static int > > +dpctl_ct_get_maxconns(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p) > > +{ > > + struct dpif *dpif; > > + int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif); > > + if (!error) { > > + uint32_t maxconns; > > + error = ct_dpif_get_maxconns(dpif, &maxconns); > > + dpif_close(dpif); > > + > > + if (!error) { > > + dpctl_print(dpctl_p, "%u\n", maxconns); > > + } else { > > + dpctl_error(dpctl_p, error, "maxconns could not > be > > retrieved"); > > + } > > + } > > + > > + return error; > > +} > > + > > +static int > > +dpctl_ct_get_nconns(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p) > > +{ > > + struct dpif *dpif; > > + int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif); > > + if (!error) { > > + uint32_t nconns; > > + error = ct_dpif_get_nconns(dpif, &nconns); > > + dpif_close(dpif); > > + > > + if (!error) { > > + dpctl_print(dpctl_p, "%u\n", nconns); > > + } else { > > + dpctl_error(dpctl_p, error, "nconns could not be > > retrieved"); > > + } > > + } > > + > > + return error; > > +} > > + > > /* Undocumented commands for unit testing. */ > > > > static int > > @@ -1950,6 +2040,9 @@ static const struct dpctl_command > > all_commands[] = { > > { "ct-stats-show", "[dp] [zone=N] [verbose]", > > 0, 3, dpctl_ct_stats_show, DP_RO }, > > { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO }, > > + { "ct-set-maxconns", "[dp] maxconns", 1, 2, > > dpctl_ct_set_maxconns, DP_RW }, > > + { "ct-get-maxconns", "[dp] maxconns", 1, 2, > > dpctl_ct_get_maxconns, DP_RO }, > > + { "ct-get-nconns", "[dp] nconns", 1, 2, > dpctl_ct_get_nconns, > > DP_RO }, > > { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, > > { "list-commands", "", 0, INT_MAX, dpctl_list_commands, > DP_RO > > }, > > > > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > > index b1ef9a6..9432859 100644 > > --- a/lib/dpif-netdev.c > > +++ b/lib/dpif-netdev.c > > @@ -5745,6 +5745,30 @@ dpif_netdev_ct_flush(struct dpif *dpif, > const > > uint16_t *zone, > > return conntrack_flush(&dp->conntrack, zone); > > } > > > > +static int > > +dpif_netdev_ct_set_maxconns(struct dpif *dpif, uint32_t > maxconns) > > +{ > > + struct dp_netdev *dp = get_dp_netdev(dpif); > > + > > + return conntrack_set_maxconns(&dp->conntrack, maxconns); > > +} > > + > > +static int > > +dpif_netdev_ct_get_maxconns(struct dpif *dpif, uint32_t > *maxconns) > > +{ > > + struct dp_netdev *dp = get_dp_netdev(dpif); > > + > > + return conntrack_get_nconns(&dp->conntrack, maxconns); > > +} > > + > > +static int > > +dpif_netdev_ct_get_nconns(struct dpif *dpif, uint32_t > *nconns) > > +{ > > + struct dp_netdev *dp = get_dp_netdev(dpif); > > + > > + return conntrack_get_nconns(&dp->conntrack, nconns); > > +} > > + > > const struct dpif_class dpif_netdev_class = { > > "netdev", > > dpif_netdev_init, > > @@ -5790,6 +5814,9 @@ const struct dpif_class > dpif_netdev_class = { > > dpif_netdev_ct_dump_next, > > dpif_netdev_ct_dump_done, > > dpif_netdev_ct_flush, > > + dpif_netdev_ct_set_maxconns, > > + dpif_netdev_ct_get_maxconns, > > + dpif_netdev_ct_get_nconns, > > dpif_netdev_meter_get_features, > > dpif_netdev_meter_set, > > dpif_netdev_meter_get, > > diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > > index 3f76128..f8d75eb 100644 > > --- a/lib/dpif-netlink.c > > +++ b/lib/dpif-netlink.c > > @@ -2989,6 +2989,9 @@ const struct dpif_class > dpif_netlink_class = { > > dpif_netlink_ct_dump_next, > > dpif_netlink_ct_dump_done, > > dpif_netlink_ct_flush, > > + NULL, /* ct_set_maxconns */ > > + NULL, /* ct_get_maxconns */ > > + NULL, /* ct_get_nconns */ > > dpif_netlink_meter_get_features, > > dpif_netlink_meter_set, > > dpif_netlink_meter_get, > > diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h > > index 947bf5e..62b3598 100644 > > --- a/lib/dpif-provider.h > > +++ b/lib/dpif-provider.h > > @@ -437,6 +437,12 @@ struct dpif_class { > > * (zone 0). */ > > int (*ct_flush)(struct dpif *, const uint16_t *zone, > > const struct ct_dpif_tuple *tuple); > > + /* Set max connections allowed. */ > > + int (*ct_set_maxconns)(struct dpif *, uint32_t maxconns); > > + /* Get max connections allowed. */ > > + int (*ct_get_maxconns)(struct dpif *, uint32_t > *maxconns); > > + /* Get number of connections tracked. */ > > + int (*ct_get_nconns)(struct dpif *, uint32_t *nconns); > > > > /* Meters */ > > > > > > > /////////////////////////////////////////////////////////////// > > > > > > > > On 10/13/17, 1:27 AM, "ovs-dev-boun...@openvswitch.org on > behalf of > > antonio.fische...@intel.com" <ovs-dev-boun...@openvswitch.org on > behalf > > of antonio.fische...@intel.com> wrote: > > > > Add infrastructure to implement: > > - dpctl/ct-get-glbl-cfg to read a current value of > available > > conntrack parameters. > > - dpctl/ct-set-glbl-cfg to set a value to the available > > conntrack > > parameters. > > > > CC: Darrell Ball <dlu...@gmail.com> > > CC: Kevin Traynor <ktray...@redhat.com> > > Signed-off-by: Antonio Fischetti > <antonio.fische...@intel.com> > > --- > > lib/conntrack.c | 60 > > ++++++++++++++++++++++++++++++++++++++++++ > > lib/conntrack.h | 3 +++ > > lib/ct-dpif.c | 28 ++++++++++++++++++++ > > lib/ct-dpif.h | 2 ++ > > lib/dpctl.c | 76 > > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > > lib/dpif-netdev.c | 19 ++++++++++++++ > > lib/dpif-netlink.c | 2 ++ > > lib/dpif-provider.h | 4 +++ > > 8 files changed, 194 insertions(+) > > > > diff --git a/lib/conntrack.c b/lib/conntrack.c > > index e555b55..29889c9 100644 > > --- a/lib/conntrack.c > > +++ b/lib/conntrack.c > > @@ -67,6 +67,13 @@ enum ct_alg_mode { > > CT_TFTP_MODE, > > }; > > > > +/* Variable to manage read/write on CT parameters. */ > > +struct ct_cfg_params { > > + char *cli; /* Parameter name in human format. */ > > + int (*wr)(struct conntrack *, uint32_t); > > + int (*rd)(struct conntrack *, uint32_t *); > > +}; > > + > > static bool conn_key_extract(struct conntrack *, struct > > dp_packet *, > > ovs_be16 dl_type, struct > > conn_lookup_ctx *, > > uint16_t zone); > > @@ -2485,6 +2492,59 @@ conntrack_flush(struct conntrack > *ct, > > const uint16_t *zone) > > return 0; > > } > > > > +/* List of parameters that can be read/written at run- > time. */ > > +struct ct_cfg_params cfg_params[] = {}; > > + > > +int > > +conntrack_set_param(struct conntrack *ct, > > + const char *set_param) > > +{ > > + uint32_t max_conn; > > + char buf[16] = ""; > > + > > + /* Check if the specified param can be managed. */ > > + for (int i = 0; i < sizeof(cfg_params) / > sizeof(struct > > ct_cfg_params); > > + i++) { > > + if (!strncmp(set_param, cfg_params[i].cli, > > + strlen(cfg_params[i].cli))) { > > + ovs_strzcpy(buf, cfg_params[i].cli, > sizeof(buf) - > > 1); > > + strncat(buf, "=%"SCNu32, sizeof(buf) - 1 - > > strlen(buf)); > > + if (ovs_scan(set_param, buf, &max_conn)) { > > + return (cfg_params[i].wr > > + ? cfg_params[i].wr(ct, max_conn) > > + : EOPNOTSUPP); > > + } else { > > + return EINVAL; > > + } > > + } > > + } > > + /* The entered param didn't match any in the list. */ > > + VLOG_WARN("%s parameter is not managed by this > command.", > > set_param); > > + > > + return EINVAL; > > +} > > + > > +int > > +conntrack_get_param(struct conntrack *ct, > > + const char *get_param, uint32_t *val) > > +{ > > + /* Check if the specified param can be managed. */ > > + for (int i = 0; i < sizeof(cfg_params) / > sizeof(struct > > ct_cfg_params); > > + i++) { > > + if (!strncmp(get_param, cfg_params[i].cli, > > + strlen(cfg_params[i].cli))) { > > + > > + return (cfg_params[i].rd > > + ? cfg_params[i].rd(ct, val) > > + : EOPNOTSUPP); > > + } > > + } > > + /* The entered param didn't match any in the list. */ > > + VLOG_WARN("%s parameter is not managed by this > command.", > > get_param); > > + > > + return EINVAL; > > +} > > + > > /* This function must be called with the ct->resources > read > > lock taken. */ > > static struct alg_exp_node * > > expectation_lookup(struct hmap *alg_expectations, > > diff --git a/lib/conntrack.h b/lib/conntrack.h > > index fbeef1c..4eb9a9a 100644 > > --- a/lib/conntrack.h > > +++ b/lib/conntrack.h > > @@ -114,6 +114,9 @@ int conntrack_dump_next(struct > > conntrack_dump *, struct ct_dpif_entry *); > > int conntrack_dump_done(struct conntrack_dump *); > > > > int conntrack_flush(struct conntrack *, const uint16_t > *zone); > > +int conntrack_set_param(struct conntrack *, const char > > *set_param); > > +int conntrack_get_param(struct conntrack *, const char > > *get_param, > > + uint32_t *val); > > ? > > /* 'struct ct_lock' is a wrapper for an adaptive mutex. > It's > > useful to try > > * different types of locks (e.g. spinlocks) */ > > diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c > > index c79e69e..599bc57 100644 > > --- a/lib/ct-dpif.c > > +++ b/lib/ct-dpif.c > > @@ -127,6 +127,34 @@ ct_dpif_flush(struct dpif *dpif, > const > > uint16_t *zone) > > : EOPNOTSUPP); > > } > > > > +int > > +ct_dpif_set_param(struct dpif *dpif, const char > *set_param) > > +{ > > + if (!set_param) { > > + VLOG_DBG("%s: ct_set_param: no input param", > > dpif_name(dpif)); > > + return EINVAL; > > + } > > + VLOG_DBG("%s: ct_set_param: %s", dpif_name(dpif), > > set_param); > > + > > + return (dpif->dpif_class->ct_set_param > > + ? dpif->dpif_class->ct_set_param(dpif, > set_param) > > + : EOPNOTSUPP); > > +} > > + > > +int > > +ct_dpif_get_param(struct dpif *dpif, const char > *get_param, > > uint32_t *val) > > +{ > > + if (!get_param) { > > + VLOG_DBG("%s: ct_get_param: no input param", > > dpif_name(dpif)); > > + return EINVAL; > > + } > > + VLOG_DBG("%s: ct_get_param: %s", dpif_name(dpif), > > get_param); > > + > > + return (dpif->dpif_class->ct_get_param > > + ? dpif->dpif_class->ct_get_param(dpif, > get_param, > > val) > > + : EOPNOTSUPP); > > +} > > + > > void > > ct_dpif_entry_uninit(struct ct_dpif_entry *entry) > > { > > diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h > > index d5f9661..92ce3e9 100644 > > --- a/lib/ct-dpif.h > > +++ b/lib/ct-dpif.h > > @@ -196,6 +196,8 @@ int ct_dpif_dump_start(struct dpif *, > struct > > ct_dpif_dump_state **, > > int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct > > ct_dpif_entry *); > > int ct_dpif_dump_done(struct ct_dpif_dump_state *); > > int ct_dpif_flush(struct dpif *, const uint16_t *zone); > > +int ct_dpif_set_param(struct dpif *dpif, const char > > *set_param); > > +int ct_dpif_get_param(struct dpif *dpif, const char > *get_param, > > uint32_t *val); > > void ct_dpif_entry_uninit(struct ct_dpif_entry *); > > void ct_dpif_format_entry(const struct ct_dpif_entry *, > struct > > ds *, > > bool verbose, bool > print_stats); > > diff --git a/lib/dpctl.c b/lib/dpctl.c > > index b6eecf0..5b02951 100644 > > --- a/lib/dpctl.c > > +++ b/lib/dpctl.c > > @@ -1589,6 +1589,80 @@ dpctl_ct_bkts(int argc, const char > > *argv[], > > free(conn_per_bkts); > > return error; > > } > > + > > +static int > > +dpctl_ct_set_param(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p) > > +{ > > + struct dpif *dpif; > > + char *name; > > + int error; > > + > > + /* The datapath name is not a mandatory parameter for > this > > command. > > + * If it is not specified - so argc < 3 - we retrieve > it > > from the > > + * current setup, assuming only one exists. */ > > + name = argc == 3 ? xstrdup(argv[1]) : > get_one_dp(dpctl_p); > > + if (!name) { > > + return EINVAL; > > + } > > + error = parsed_dpif_open(name, false, &dpif); > > + free(name); > > + if (error) { > > + dpctl_error(dpctl_p, error, "opening datapath"); > > + return error; > > + } > > + > > + error = ct_dpif_set_param(dpif, argv[argc - 1]); > > + > > + if (!error) { > > + dpctl_print(dpctl_p, "Ok"); > > + } else { > > + dpctl_print(dpctl_p, "CT set global cfg failed > (%s)", > > + ovs_strerror(error)); > > + } > > + > > + dpif_close(dpif); > > + > > + return error; > > +} > > + > > +static int > > +dpctl_ct_get_param(int argc, const char *argv[], > > + struct dpctl_params *dpctl_p) > > +{ > > + struct dpif *dpif; > > + uint32_t param_val; > > + char *name; > > + int error; > > + > > + /* The datapath name is not a mandatory parameter for > this > > command. > > + * If it is not specified - so argc < 3 - we retrieve > it > > from the > > + * current setup, assuming only one exists. */ > > + name = argc == 3 ? xstrdup(argv[1]) : > get_one_dp(dpctl_p); > > + if (!name) { > > + return EINVAL; > > + } > > + error = parsed_dpif_open(name, false, &dpif); > > + free(name); > > + if (error) { > > + dpctl_error(dpctl_p, error, "opening datapath"); > > + return error; > > + } > > + > > + error = ct_dpif_get_param(dpif, argv[argc - 1], > > ¶m_val); > > + > > + if (!error) { > > + dpctl_print(dpctl_p, "Current value: %d", > param_val); > > + } else { > > + dpctl_print(dpctl_p, "CT get global cfg failed > (%s)", > > + ovs_strerror(error)); > > + } > > + > > + dpif_close(dpif); > > + > > + return error; > > +} > > + > > ? > > /* Undocumented commands for unit testing. */ > > > > @@ -1885,6 +1959,8 @@ static const struct dpctl_command > > all_commands[] = { > > { "ct-stats-show", "[dp] [zone=N] [verbose]", > > 0, 3, dpctl_ct_stats_show, DP_RO }, > > { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, > DP_RO }, > > + { "ct-set-glbl-cfg", "[dp] param=..", 1, 2, > > dpctl_ct_set_param, DP_RW }, > > + { "ct-get-glbl-cfg", "[dp] param", 1, 2, > > dpctl_ct_get_param, DP_RO }, > > { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, > > { "list-commands", "", 0, INT_MAX, > dpctl_list_commands, > > DP_RO }, > > > > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > > index d5eb830..4c0e7cf 100644 > > --- a/lib/dpif-netdev.c > > +++ b/lib/dpif-netdev.c > > @@ -5721,6 +5721,23 @@ dpif_netdev_ct_flush(struct dpif > *dpif, > > const uint16_t *zone) > > return conntrack_flush(&dp->conntrack, zone); > > } > > > > +static int > > +dpif_netdev_ct_set_param(struct dpif *dpif, const char > > *set_param) > > +{ > > + struct dp_netdev *dp = get_dp_netdev(dpif); > > + > > + return conntrack_set_param(&dp->conntrack, > set_param); > > +} > > + > > +static int > > +dpif_netdev_ct_get_param(struct dpif *dpif, const char > > *get_param, > > + uint32_t *val) > > +{ > > + struct dp_netdev *dp = get_dp_netdev(dpif); > > + > > + return conntrack_get_param(&dp->conntrack, get_param, > val); > > +} > > + > > const struct dpif_class dpif_netdev_class = { > > "netdev", > > dpif_netdev_init, > > @@ -5766,6 +5783,8 @@ const struct dpif_class > dpif_netdev_class > > = { > > dpif_netdev_ct_dump_next, > > dpif_netdev_ct_dump_done, > > dpif_netdev_ct_flush, > > + dpif_netdev_ct_set_param, > > + dpif_netdev_ct_get_param, > > dpif_netdev_meter_get_features, > > dpif_netdev_meter_set, > > dpif_netdev_meter_get, > > diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > > index 29001fb..0945fad 100644 > > --- a/lib/dpif-netlink.c > > +++ b/lib/dpif-netlink.c > > @@ -2986,6 +2986,8 @@ const struct dpif_class > dpif_netlink_class > > = { > > dpif_netlink_ct_dump_next, > > dpif_netlink_ct_dump_done, > > dpif_netlink_ct_flush, > > + NULL, /* ct_set_param */ > > + NULL, /* ct_get_param */ > > dpif_netlink_meter_get_features, > > dpif_netlink_meter_set, > > dpif_netlink_meter_get, > > diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h > > index 1d82a09..262b2e0 100644 > > --- a/lib/dpif-provider.h > > +++ b/lib/dpif-provider.h > > @@ -427,6 +427,10 @@ struct dpif_class { > > /* Flushes the connection tracking tables. If 'zone' > is not > > NULL, > > * only deletes connections in '*zone'. */ > > int (*ct_flush)(struct dpif *, const uint16_t *zone); > > + /* Set a value to a connection tracking working > parameter. > > */ > > + int (*ct_set_param)(struct dpif *, const char > *set_param); > > + /* Read the current value of a connection tracking > working > > parameter. */ > > + int (*ct_get_param)(struct dpif *, const char > *get_param, > > uint32_t *val); > > > > /* Meters */ > > > > -- > > 2.4.11 > > > > _______________________________________________ > > dev mailing list > > d...@openvswitch.org > > https://urldefense.proofpoint.com/v2/url?u=https- > > 3A__mail.openvswitch.org_mailman_listinfo_ovs- > > 2Ddev&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=BVhFA09CGX7JQ5Ih- > > uZnsw&m=m6PHM-SNZk7M88zlL6EQWY-S5kl3XTbB-YNfA- > yk7xE&s=u0Gt2hVhSfd4NYQ0- > > mRy8r1P_U_vFyUqgE_Xd6rC9Qk&e= > > > > > > > > > > > > > > > > > > > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev