All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH iproute2-next 0/2] Add devlink-metric support
@ 2020-08-17 12:55 Ido Schimmel
  2020-08-17 12:55 ` [RFC PATCH iproute2-next 1/2] Update kernel headers Ido Schimmel
  2020-08-17 12:55 ` [RFC PATCH iproute2-next 2/2] devlink: Add device metric set and show commands Ido Schimmel
  0 siblings, 2 replies; 3+ messages in thread
From: Ido Schimmel @ 2020-08-17 12:55 UTC (permalink / raw
  To: netdev
  Cc: davem, kuba, jiri, amcohen, danieller, mlxsw, roopa, dsahern,
	andrew, f.fainelli, vivien.didelot, saeedm, tariqt, ayal, eranbe,
	mkubecek, Ido Schimmel

From: Ido Schimmel <idosch@nvidia.com>

This patch set adds devlink-metric support in iproute2.

Patch #1 updates the kernel headers.

Patch #2 adds actual devlink-metric support including associated bash
completion support. See commit message for example usage and output.

Danielle Ratson (2):
  Update kernel headers
  devlink: Add device metric set and show commands

 bash-completion/devlink      |  67 ++++++++++++-
 devlink/devlink.c            | 185 ++++++++++++++++++++++++++++++++++-
 include/uapi/linux/devlink.h |  19 ++++
 3 files changed, 267 insertions(+), 4 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH iproute2-next 1/2] Update kernel headers
  2020-08-17 12:55 [RFC PATCH iproute2-next 0/2] Add devlink-metric support Ido Schimmel
@ 2020-08-17 12:55 ` Ido Schimmel
  2020-08-17 12:55 ` [RFC PATCH iproute2-next 2/2] devlink: Add device metric set and show commands Ido Schimmel
  1 sibling, 0 replies; 3+ messages in thread
From: Ido Schimmel @ 2020-08-17 12:55 UTC (permalink / raw
  To: netdev
  Cc: davem, kuba, jiri, amcohen, danieller, mlxsw, roopa, dsahern,
	andrew, f.fainelli, vivien.didelot, saeedm, tariqt, ayal, eranbe,
	mkubecek, Ido Schimmel

From: Danielle Ratson <danieller@nvidia.com>

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 include/uapi/linux/devlink.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index b7f23faae901..65563df8b0b6 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -122,6 +122,11 @@ enum devlink_command {
 	DEVLINK_CMD_TRAP_POLICER_NEW,
 	DEVLINK_CMD_TRAP_POLICER_DEL,
 
+	DEVLINK_CMD_METRIC_GET,		/* can dump */
+	DEVLINK_CMD_METRIC_SET,
+	DEVLINK_CMD_METRIC_NEW,
+	DEVLINK_CMD_METRIC_DEL,
+
 	/* add new commands above here */
 	__DEVLINK_CMD_MAX,
 	DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -272,6 +277,14 @@ enum {
 	DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE,
 };
 
+/**
+ * enum devlink_metric_type - Metric type.
+ * @DEVLINK_METRIC_TYPE_COUNTER: Counter. Monotonically increasing.
+ */
+enum devlink_metric_type {
+	DEVLINK_METRIC_TYPE_COUNTER,
+};
+
 enum devlink_attr {
 	/* don't change the order or add anything between, this is ABI! */
 	DEVLINK_ATTR_UNSPEC,
@@ -458,6 +471,12 @@ enum devlink_attr {
 	DEVLINK_ATTR_PORT_LANES,			/* u32 */
 	DEVLINK_ATTR_PORT_SPLITTABLE,			/* u8 */
 
+	DEVLINK_ATTR_METRIC_NAME,		/* string */
+	/* enum devlink_metric_type */
+	DEVLINK_ATTR_METRIC_TYPE,		/* u8 */
+	DEVLINK_ATTR_METRIC_COUNTER_VALUE,	/* u64 */
+	DEVLINK_ATTR_METRIC_GROUP,		/* u32 */
+
 	/* add new attributes above here, update the policy in devlink.c */
 
 	__DEVLINK_ATTR_MAX,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH iproute2-next 2/2] devlink: Add device metric set and show commands
  2020-08-17 12:55 [RFC PATCH iproute2-next 0/2] Add devlink-metric support Ido Schimmel
  2020-08-17 12:55 ` [RFC PATCH iproute2-next 1/2] Update kernel headers Ido Schimmel
@ 2020-08-17 12:55 ` Ido Schimmel
  1 sibling, 0 replies; 3+ messages in thread
From: Ido Schimmel @ 2020-08-17 12:55 UTC (permalink / raw
  To: netdev
  Cc: davem, kuba, jiri, amcohen, danieller, mlxsw, roopa, dsahern,
	andrew, f.fainelli, vivien.didelot, saeedm, tariqt, ayal, eranbe,
	mkubecek, Ido Schimmel

From: Danielle Ratson <danieller@nvidia.com>

Add support for devlink device metric set / show commands with
accompanying bash completion.

Examples:

Show a specific metric:

# devlink -sjp dev metric show netdevsim/netdevsim10 metric dummy_counter
{
    "metric": {
        "netdevsim/netdevsim10": [ {
                "metric": "dummy_counter",
                "type": "counter",
                "group": 0,
                "value": 11
            } ]
    }
}

Set multiple metrics to the same metric group:

# devlink dev metric set netdevsim/netdevsim10 metric dummy_counter group 5
# devlink dev metric set netdevsim/netdevsim20 metric dummy_counter group 5

Dump metrics from a specific group:

# devlink -sjp dev metric show group 5
{
    "metric": {
        "netdevsim/netdevsim10": [ {
                "metric": "dummy_counter",
                "type": "counter",
                "group": 5,
                "value": 12
            } ],
        "netdevsim/netdevsim20": [ {
                "metric": "dummy_counter",
                "type": "counter",
                "group": 5,
                "value": 13
            } ]
    }
}

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 bash-completion/devlink |  67 ++++++++++++++-
 devlink/devlink.c       | 185 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 248 insertions(+), 4 deletions(-)

diff --git a/bash-completion/devlink b/bash-completion/devlink
index f710c888652e..fd17e7ccf9c0 100644
--- a/bash-completion/devlink
+++ b/bash-completion/devlink
@@ -38,6 +38,15 @@ _devlink_direct_complete()
             value=$(devlink -j dev param show 2>/dev/null \
                     | jq ".param[\"$dev\"][].name")
             ;;
+        dev_metric)
+            value=$(devlink -j dev metric show 2>/dev/null \
+                    | jq '.metric' | jq 'keys[]')
+            ;;
+        metric)
+            dev=${words[4]}
+            value=$(devlink -j dev metric show 2>/dev/null \
+                    | jq ".metric[\"$dev\"][].metric")
+            ;;
         port)
             value=$(devlink -j port show 2>/dev/null \
                     | jq '.port as $ports | $ports | keys[] as $key
@@ -262,6 +271,62 @@ _devlink_dev_flash()
      esac
 }
 
+# Completion for devlink dev metric
+_devlink_dev_metric()
+{
+    if [[ $cword -eq 3 ]]; then
+            COMPREPLY=( $( compgen -W "show set" -- "$cur" ) )
+    fi
+
+    case "${words[3]}" in
+        show)
+            case $cword in
+                4)
+                    _devlink_direct_complete "dev_metric"
+                    COMPREPLY+=( $( compgen -W "group" -- "$cur" ) )
+                    return
+                    ;;
+                5)
+                    if [[ $prev != "group" ]]; then
+                        COMPREPLY=( $( compgen -W "metric" -- "$cur" ) )
+                    fi
+                    # else Integer argument
+                    return
+                    ;;
+                6)
+                    if [[ $prev == "metric" ]]; then
+                        _devlink_direct_complete "metric"
+                    fi
+                    return
+                    ;;
+            esac
+            ;;
+        set)
+            case $cword in
+                4)
+                    _devlink_direct_complete "dev_metric"
+                    return
+                    ;;
+                5)
+                    COMPREPLY=( $( compgen -W "metric" -- "$cur" ) )
+                    return
+                    ;;
+                6)
+                    _devlink_direct_complete "metric"
+                    return
+                    ;;
+                7)
+                    COMPREPLY=( $( compgen -W "group" -- "$cur" ) )
+                    return
+                    ;;
+                8)
+                    # Integer argument
+                    return
+                    ;;
+            esac
+    esac
+}
+
 # Completion for devlink dev
 _devlink_dev()
 {
@@ -274,7 +339,7 @@ _devlink_dev()
             fi
             return
             ;;
-        eswitch|param)
+        eswitch|param|metric)
             _devlink_dev_$command
             return
             ;;
diff --git a/devlink/devlink.c b/devlink/devlink.c
index 8ec96c01fbcf..00d4e9a31f7e 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -302,6 +302,8 @@ static void ifname_map_free(struct ifname_map *ifname_map)
 #define DL_OPT_TRAP_POLICER_BURST	BIT(36)
 #define DL_OPT_HEALTH_REPORTER_AUTO_DUMP     BIT(37)
 #define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
+#define DL_OPT_METRIC_NAME	BIT(39)
+#define DL_OPT_METRIC_GROUP	BIT(40)
 
 struct dl_opts {
 	uint64_t present; /* flags of present items */
@@ -349,6 +351,8 @@ struct dl_opts {
 	uint64_t trap_policer_burst;
 	char port_function_hw_addr[MAX_ADDR_LEN];
 	uint32_t port_function_hw_addr_len;
+	const char *metric_name;
+	uint32_t metric_group;
 };
 
 struct dl {
@@ -678,6 +682,10 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
 	[DEVLINK_ATTR_TRAP_POLICER_ID] = MNL_TYPE_U32,
 	[DEVLINK_ATTR_TRAP_POLICER_RATE] = MNL_TYPE_U64,
 	[DEVLINK_ATTR_TRAP_POLICER_BURST] = MNL_TYPE_U64,
+	[DEVLINK_ATTR_METRIC_NAME] = MNL_TYPE_STRING,
+	[DEVLINK_ATTR_METRIC_TYPE] = MNL_TYPE_U8,
+	[DEVLINK_ATTR_METRIC_COUNTER_VALUE] = MNL_TYPE_U64,
+	[DEVLINK_ATTR_METRIC_GROUP] = MNL_TYPE_U32,
 };
 
 static const enum mnl_attr_data_type
@@ -1359,6 +1367,8 @@ static const struct dl_args_metadata dl_args_required[] = {
 	{DL_OPT_TRAP_NAME,            "Trap's name is expected."},
 	{DL_OPT_TRAP_GROUP_NAME,      "Trap group's name is expected."},
 	{DL_OPT_PORT_FUNCTION_HW_ADDR, "Port function's hardware address is expected."},
+	{DL_OPT_METRIC_NAME,	       "Metric's name is expected."},
+	{DL_OPT_METRIC_GROUP,	       "Metric group's number is expected."}
 };
 
 static int dl_args_finding_required_validate(uint64_t o_required,
@@ -1738,7 +1748,20 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
 			if (err)
 				return err;
 			o_found |= DL_OPT_PORT_FUNCTION_HW_ADDR;
-
+		} else if (dl_argv_match(dl, "metric") &&
+			   (o_all & DL_OPT_METRIC_NAME)) {
+			dl_arg_inc(dl);
+			err = dl_argv_str(dl, &opts->metric_name);
+			if (err)
+				return err;
+			o_found |= DL_OPT_METRIC_NAME;
+		} else if (dl_argv_match(dl, "group") &&
+			   (o_all & DL_OPT_METRIC_GROUP)) {
+			dl_arg_inc(dl);
+			err = dl_argv_uint32_t(dl, &opts->metric_group);
+			if (err)
+				return err;
+			o_found |= DL_OPT_METRIC_GROUP;
 		} else {
 			pr_err("Unknown option \"%s\"\n", dl_argv(dl));
 			return -EINVAL;
@@ -1892,6 +1915,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
 				 opts->trap_policer_burst);
 	if (opts->present & DL_OPT_PORT_FUNCTION_HW_ADDR)
 		dl_function_attr_put(nlh, opts);
+	if (opts->present & DL_OPT_METRIC_NAME)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_METRIC_NAME,
+				  opts->metric_name);
+	if (opts->present & DL_OPT_METRIC_GROUP)
+		mnl_attr_put_u32(nlh, DEVLINK_ATTR_METRIC_GROUP,
+				 opts->metric_group);
 }
 
 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@@ -1955,6 +1984,8 @@ static void cmd_dev_help(void)
 	pr_err("       devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
 	pr_err("       devlink dev info [ DEV ]\n");
 	pr_err("       devlink dev flash DEV file PATH [ component NAME ]\n");
+	pr_err("       devlink dev metric show [ DEV metric METRIC | group GROUP ]\n");
+	pr_err("       devlink dev metric set DEV metric METRIC [ group GROUP ]\n");
 }
 
 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
@@ -3269,6 +3300,127 @@ out:
 	return err;
 }
 
+static const char *metric_type_name(uint8_t type)
+{
+	switch (type) {
+	case DEVLINK_METRIC_TYPE_COUNTER:
+		return "counter";
+	default:
+		return "<unknown type>";
+	}
+}
+
+static void pr_out_metric(struct dl *dl, struct nlattr **tb, bool array)
+{
+	uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_METRIC_TYPE]);
+
+	if (array)
+		pr_out_handle_start_arr(dl, tb);
+	else
+		__pr_out_handle_start(dl, tb, true, false);
+
+	check_indent_newline(dl);
+	print_string(PRINT_ANY, "metric", " metric %s",
+		     mnl_attr_get_str(tb[DEVLINK_ATTR_METRIC_NAME]));
+	print_string(PRINT_ANY, "type", " type %s", metric_type_name(type));
+	print_uint(PRINT_ANY, "group", " group %u",
+		   mnl_attr_get_u32(tb[DEVLINK_ATTR_METRIC_GROUP]));
+	if (dl->stats) {
+		if (tb[DEVLINK_ATTR_METRIC_COUNTER_VALUE]) {
+			enum devlink_attr attr;
+
+			attr = DEVLINK_ATTR_METRIC_COUNTER_VALUE;
+			pr_out_u64(dl, "value", mnl_attr_get_u64(tb[attr]));
+		}
+	}
+	pr_out_handle_end(dl);
+}
+
+static int cmd_dev_metric_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+	struct dl *dl = data;
+
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+	    !tb[DEVLINK_ATTR_METRIC_NAME] || !tb[DEVLINK_ATTR_METRIC_TYPE] ||
+	    !tb[DEVLINK_ATTR_METRIC_GROUP])
+		return MNL_CB_ERROR;
+	pr_out_metric(dl, tb, true);
+	return MNL_CB_OK;
+}
+
+static int cmd_dev_metric_set(struct dl *dl)
+{
+	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_METRIC_SET, flags);
+
+	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_METRIC_NAME,
+				DL_OPT_METRIC_GROUP);
+	if (err)
+		return err;
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int cmd_dev_metric_show(struct dl *dl)
+{
+	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+	struct nlmsghdr *nlh;
+	int err;
+
+	if (dl_argc(dl) == 0) {
+		flags |= NLM_F_DUMP;
+	} else if (dl_argv_match(dl, "group")) {
+		dl_arg_inc(dl);
+		err = dl_argv_uint32_t(dl, &dl->opts.metric_group);
+		if (err)
+			return err;
+		dl->opts.present |= DL_OPT_METRIC_GROUP;
+		flags |= NLM_F_DUMP;
+	}
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_METRIC_GET, flags);
+
+	if (dl_argc(dl) > 0) {
+		if (flags & NLM_F_DUMP) {
+			pr_err("Too many arguments\n");
+			return -EINVAL;
+		}
+
+		err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_METRIC_NAME, 0);
+		if (err)
+			return err;
+	}
+
+	dl_opts_put(nlh, dl);
+
+	pr_out_section_start(dl, "metric");
+	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_metric_show_cb, dl);
+	pr_out_section_end(dl);
+	return err;
+}
+
+static int cmd_dev_metric(struct dl *dl)
+{
+	if (dl_argv_match(dl, "help")) {
+		cmd_dev_help();
+		return 0;
+	} else if (dl_argv_match(dl, "show") || dl_no_arg(dl)) {
+		dl_arg_inc(dl);
+		return cmd_dev_metric_show(dl);
+	} else if (dl_argv_match(dl, "set")) {
+		dl_arg_inc(dl);
+		return cmd_dev_metric_set(dl);
+	}
+	pr_err("Command \"%s\" not found\n", dl_argv(dl));
+	return -ENOENT;
+}
+
 static int cmd_dev(struct dl *dl)
 {
 	if (dl_argv_match(dl, "help")) {
@@ -3293,6 +3445,9 @@ static int cmd_dev(struct dl *dl)
 	} else if (dl_argv_match(dl, "flash")) {
 		dl_arg_inc(dl);
 		return cmd_dev_flash(dl);
+	} else if (dl_argv_match(dl, "metric")) {
+		dl_arg_inc(dl);
+		return cmd_dev_metric(dl);
 	}
 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
 	return -ENOENT;
@@ -4413,6 +4568,10 @@ static const char *cmd_name(uint8_t cmd)
 	case DEVLINK_CMD_TRAP_POLICER_SET: return "set";
 	case DEVLINK_CMD_TRAP_POLICER_NEW: return "new";
 	case DEVLINK_CMD_TRAP_POLICER_DEL: return "del";
+	case DEVLINK_CMD_METRIC_GET: return "get";
+	case DEVLINK_CMD_METRIC_SET: return "set";
+	case DEVLINK_CMD_METRIC_NEW: return "new";
+	case DEVLINK_CMD_METRIC_DEL: return "del";
 	default: return "<unknown cmd>";
 	}
 }
@@ -4462,6 +4621,11 @@ static const char *cmd_obj(uint8_t cmd)
 	case DEVLINK_CMD_TRAP_POLICER_NEW:
 	case DEVLINK_CMD_TRAP_POLICER_DEL:
 		return "trap-policer";
+	case DEVLINK_CMD_METRIC_GET:
+	case DEVLINK_CMD_METRIC_SET:
+	case DEVLINK_CMD_METRIC_NEW:
+	case DEVLINK_CMD_METRIC_DEL:
+		return "metric";
 	default: return "<unknown obj>";
 	}
 }
@@ -4532,6 +4696,7 @@ static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
 static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
 static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
 static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array);
+static void pr_out_metric(struct dl *dl, struct nlattr **tb, bool array);
 
 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
 {
@@ -4653,6 +4818,19 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
 		pr_out_mon_header(genl->cmd);
 		pr_out_trap_policer(dl, tb, false);
 		break;
+	case DEVLINK_CMD_METRIC_GET: /* fall through */
+	case DEVLINK_CMD_METRIC_SET: /* fall through */
+	case DEVLINK_CMD_METRIC_NEW: /* fall through */
+	case DEVLINK_CMD_METRIC_DEL:
+		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+		    !tb[DEVLINK_ATTR_METRIC_NAME] ||
+		    !tb[DEVLINK_ATTR_METRIC_TYPE] ||
+		    !tb[DEVLINK_ATTR_METRIC_GROUP])
+			return MNL_CB_ERROR;
+		pr_out_mon_header(genl->cmd);
+		pr_out_metric(dl, tb, false);
+		break;
 	}
 	return MNL_CB_OK;
 }
@@ -4670,7 +4848,8 @@ static int cmd_mon_show(struct dl *dl)
 		    strcmp(cur_obj, "health") != 0 &&
 		    strcmp(cur_obj, "trap") != 0 &&
 		    strcmp(cur_obj, "trap-group") != 0 &&
-		    strcmp(cur_obj, "trap-policer") != 0) {
+		    strcmp(cur_obj, "trap-policer") != 0 &&
+		    strcmp(cur_obj, "metric") != 0) {
 			pr_err("Unknown object \"%s\"\n", cur_obj);
 			return -EINVAL;
 		}
@@ -4691,7 +4870,7 @@ static int cmd_mon_show(struct dl *dl)
 static void cmd_mon_help(void)
 {
 	pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
-	       "where  OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
+	       "where  OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer | metric }\n");
 }
 
 static int cmd_mon(struct dl *dl)
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-08-17 12:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-08-17 12:55 [RFC PATCH iproute2-next 0/2] Add devlink-metric support Ido Schimmel
2020-08-17 12:55 ` [RFC PATCH iproute2-next 1/2] Update kernel headers Ido Schimmel
2020-08-17 12:55 ` [RFC PATCH iproute2-next 2/2] devlink: Add device metric set and show commands Ido Schimmel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.