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: 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 419cb1d..391d008 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); @@ -2391,6 +2398,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 ca74df8..8fda2a9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -5689,6 +5689,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, @@ -5734,6 +5751,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://mail.openvswitch.org/mailman/listinfo/ovs-dev