]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
dpll: add client-side filtering for device show
authorPetr Oros <poros@redhat.com>
Tue, 24 Feb 2026 09:12:41 +0000 (10:12 +0100)
committerDavid Ahern <dsahern@kernel.org>
Mon, 2 Mar 2026 15:44:13 +0000 (08:44 -0700)
Add client-side filtering support for dpll device show command.
Users can filter devices by module-name, clock-id, type, mode,
and lock-status. Multiple filters use AND semantics. Filters
work with both dump (all devices) and single GET (by id) operations.

Signed-off-by: Petr Oros <poros@redhat.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
bash-completion/dpll
dpll/dpll.c
man/man8/dpll.8

index caf86a36f2adf37920d212ef15848ec83cc9c923..a614b3eb6ab3551f7dac0d32a58809228a6e8fdb 100644 (file)
@@ -60,8 +60,31 @@ _dpll_device()
                         "$(_dpll_direct_complete device_id)" -- "$cur" ) )
                     return 0
                     ;;
+                module-name)
+                    COMPREPLY=( $( compgen -W \
+                        "$(_dpll_direct_complete module_name)" -- "$cur" ) )
+                    return 0
+                    ;;
+                clock-id)
+                    # numeric value, no completion
+                    return 0
+                    ;;
+                type)
+                    COMPREPLY=( $( compgen -W "pps eec" -- "$cur" ) )
+                    return 0
+                    ;;
+                mode)
+                    COMPREPLY=( $( compgen -W "manual automatic" -- "$cur" ) )
+                    return 0
+                    ;;
+                lock-status)
+                    COMPREPLY=( $( compgen -W \
+                        "unlocked locked locked-ho-acq holdover" -- "$cur" ) )
+                    return 0
+                    ;;
                 *)
-                    COMPREPLY=( $( compgen -W "id" -- "$cur" ) )
+                    COMPREPLY=( $( compgen -W "id module-name clock-id \
+                        type mode lock-status" -- "$cur" ) )
                     return 0
                     ;;
             esac
index 624567c2a826fd511bd383a638a59f8ad9c62dd2..d3c964e211319daf0f057bcbad00af58db65a55e 100644 (file)
@@ -616,6 +616,9 @@ dpll_free:
 static void cmd_device_help(void)
 {
        pr_err("Usage: dpll device show [ id DEVICE_ID ]\n");
+       pr_err("                        [ module-name NAME ] [ clock-id ID ]\n");
+       pr_err("                        [ type TYPE ] [ mode MODE ]\n");
+       pr_err("                        [ lock-status STATUS ]\n");
        pr_err("       dpll device set id DEVICE_ID [ mode { automatic | manual } ]\n");
        pr_err("                                    [ phase-offset-monitor { enable | disable } ]\n");
        pr_err("                                    [ phase-offset-avg-factor NUM ]\n");
@@ -669,6 +672,21 @@ static int str_to_dpll_type(const char *s, __u32 *type)
        return 0;
 }
 
+static int str_to_dpll_lock_status(const char *s, __u32 *status)
+{
+       if (!strcmp(s, "unlocked"))
+               *status = DPLL_LOCK_STATUS_UNLOCKED;
+       else if (!strcmp(s, "locked"))
+               *status = DPLL_LOCK_STATUS_LOCKED;
+       else if (!strcmp(s, "locked-ho-acq"))
+               *status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ;
+       else if (!strcmp(s, "holdover"))
+               *status = DPLL_LOCK_STATUS_HOLDOVER;
+       else
+               return -EINVAL;
+       return 0;
+}
+
 static const char *dpll_lock_status_error_name(__u32 error)
 {
        switch (error) {
@@ -735,6 +753,118 @@ static int attr_pin_cb(const struct nlattr *attr, void *data)
        return MNL_CB_OK;
 }
 
+/*
+ * Dump filter helpers - client-side filtering of dump results.
+ * AND semantics: all specified filters must match.
+ */
+
+static inline bool filter_match_str(struct nlattr *attr, const char *expected)
+{
+       return attr && strcmp(mnl_attr_get_str(attr), expected) == 0;
+}
+
+static inline bool filter_match_u32(struct nlattr *attr, __u32 expected)
+{
+       return attr && mnl_attr_get_u32(attr) == expected;
+}
+
+static inline bool filter_match_u64(struct nlattr *attr, __u64 expected)
+{
+       return attr && mnl_attr_get_u64(attr) == expected;
+}
+
+static int dpll_filter_parse_str(struct dpll *dpll, const char *name,
+                                const char **dst, uint64_t *present,
+                                uint64_t flag)
+{
+       const char *str = dpll_argv_next(dpll);
+
+       if (!str) {
+               pr_err("%s requires an argument\n", name);
+               return -EINVAL;
+       }
+       *dst = str;
+       *present |= flag;
+       return 0;
+}
+
+static int dpll_filter_parse_u64(struct dpll *dpll, const char *name,
+                                __u64 *dst, uint64_t *present,
+                                uint64_t flag)
+{
+       const char *str = dpll_argv_next(dpll);
+
+       if (!str) {
+               pr_err("%s requires an argument\n", name);
+               return -EINVAL;
+       }
+       if (get_u64(dst, str, 0)) {
+               pr_err("invalid %s: %s\n", name, str);
+               return -EINVAL;
+       }
+       *present |= flag;
+       return 0;
+}
+
+static int dpll_filter_parse_enum(struct dpll *dpll, const char *name,
+                                 __u32 *dst, uint64_t *present,
+                                 uint64_t flag,
+                                 int (*convert)(const char *, __u32 *),
+                                 const char *valid_values)
+{
+       const char *str = dpll_argv_next(dpll);
+
+       if (!str) {
+               pr_err("%s requires an argument\n", name);
+               return -EINVAL;
+       }
+       if (convert(str, dst)) {
+               pr_err("invalid %s: %s (use %s)\n", name, str, valid_values);
+               return -EINVAL;
+       }
+       *present |= flag;
+       return 0;
+}
+
+#define DPLL_FILTER_DEV_MODULE_NAME    BIT(0)
+#define DPLL_FILTER_DEV_CLOCK_ID       BIT(1)
+#define DPLL_FILTER_DEV_TYPE           BIT(2)
+#define DPLL_FILTER_DEV_MODE           BIT(3)
+#define DPLL_FILTER_DEV_LOCK_STATUS    BIT(4)
+
+struct dpll_device_filter {
+       uint64_t present;
+       const char *module_name;
+       __u64 clock_id;
+       __u32 type;
+       __u32 mode;
+       __u32 lock_status;
+};
+
+static bool dpll_device_dump_filter(struct dpll_device_filter *filter,
+                                   struct nlattr **tb)
+{
+       if (!filter || !filter->present)
+               return true;
+
+       if ((filter->present & DPLL_FILTER_DEV_MODULE_NAME) &&
+           !filter_match_str(tb[DPLL_A_MODULE_NAME], filter->module_name))
+               return false;
+       if ((filter->present & DPLL_FILTER_DEV_CLOCK_ID) &&
+           !filter_match_u64(tb[DPLL_A_CLOCK_ID], filter->clock_id))
+               return false;
+       if ((filter->present & DPLL_FILTER_DEV_TYPE) &&
+           !filter_match_u32(tb[DPLL_A_TYPE], filter->type))
+               return false;
+       if ((filter->present & DPLL_FILTER_DEV_MODE) &&
+           !filter_match_u32(tb[DPLL_A_MODE], filter->mode))
+               return false;
+       if ((filter->present & DPLL_FILTER_DEV_LOCK_STATUS) &&
+           !filter_match_u32(tb[DPLL_A_LOCK_STATUS], filter->lock_status))
+               return false;
+       return true;
+}
+
 /* Print device attributes */
 static void dpll_device_print_attrs(const struct nlmsghdr *nlh,
                                    struct nlattr **tb)
@@ -765,9 +895,14 @@ static void dpll_device_print_attrs(const struct nlmsghdr *nlh,
 /* Netlink callback - device get (single device) */
 static int cmd_device_show_cb(const struct nlmsghdr *nlh, void *data)
 {
+       struct dpll_device_filter *filter = data;
        struct nlattr *tb[DPLL_A_MAX + 1] = {};
 
        mnl_attr_parse(nlh, sizeof(struct genlmsghdr), attr_cb, tb);
+
+       if (!dpll_device_dump_filter(filter, tb))
+               return MNL_CB_OK;
+
        dpll_device_print_attrs(nlh, tb);
 
        return MNL_CB_OK;
@@ -776,10 +911,14 @@ static int cmd_device_show_cb(const struct nlmsghdr *nlh, void *data)
 /* Netlink callback - device dump (multiple devices) */
 static int cmd_device_show_dump_cb(const struct nlmsghdr *nlh, void *data)
 {
+       struct dpll_device_filter *filter = data;
        struct nlattr *tb[DPLL_A_MAX + 1] = {};
 
        mnl_attr_parse(nlh, sizeof(struct genlmsghdr), attr_cb, tb);
 
+       if (!dpll_device_dump_filter(filter, tb))
+               return MNL_CB_OK;
+
        open_json_object(NULL);
        dpll_device_print_attrs(nlh, tb);
        close_json_object();
@@ -787,7 +926,8 @@ static int cmd_device_show_dump_cb(const struct nlmsghdr *nlh, void *data)
        return MNL_CB_OK;
 }
 
-static int cmd_device_show_id(struct dpll *dpll, __u32 id)
+static int cmd_device_show_id(struct dpll *dpll, __u32 id,
+                             struct dpll_device_filter *filter)
 {
        struct nlmsghdr *nlh;
        int err;
@@ -796,7 +936,8 @@ static int cmd_device_show_id(struct dpll *dpll, __u32 id)
                                          NLM_F_REQUEST | NLM_F_ACK);
        mnl_attr_put_u32(nlh, DPLL_A_ID, id);
 
-       err = mnlu_gen_socket_sndrcv(&dpll->nlg, nlh, cmd_device_show_cb, NULL);
+       err = mnlu_gen_socket_sndrcv(&dpll->nlg, nlh, cmd_device_show_cb,
+                                    filter);
        if (err < 0) {
                pr_err("Failed to get device %u\n", id);
                return -1;
@@ -805,7 +946,8 @@ static int cmd_device_show_id(struct dpll *dpll, __u32 id)
        return 0;
 }
 
-static int cmd_device_show_dump(struct dpll *dpll)
+static int cmd_device_show_dump(struct dpll *dpll,
+                               struct dpll_device_filter *filter)
 {
        struct nlmsghdr *nlh;
        int err;
@@ -817,7 +959,7 @@ static int cmd_device_show_dump(struct dpll *dpll)
        open_json_array(PRINT_JSON, "device");
 
        err = mnlu_gen_socket_sndrcv(&dpll->nlg, nlh, cmd_device_show_dump_cb,
-                                    NULL);
+                                    filter);
        if (err < 0) {
                pr_err("Failed to dump devices\n");
                close_json_array(PRINT_JSON, NULL);
@@ -831,6 +973,7 @@ static int cmd_device_show_dump(struct dpll *dpll)
 
 static int cmd_device_show(struct dpll *dpll)
 {
+       struct dpll_device_filter filter = {};
        bool has_id = false;
        __u32 id = 0;
 
@@ -839,6 +982,42 @@ static int cmd_device_show(struct dpll *dpll)
                        if (dpll_parse_u32(dpll, "id", &id))
                                return -EINVAL;
                        has_id = true;
+               } else if (dpll_argv_match(dpll, "module-name")) {
+                       if (dpll_filter_parse_str(dpll, "module-name",
+                                                 &filter.module_name,
+                                                 &filter.present,
+                                                 DPLL_FILTER_DEV_MODULE_NAME))
+                               return -EINVAL;
+               } else if (dpll_argv_match(dpll, "clock-id")) {
+                       if (dpll_filter_parse_u64(dpll, "clock-id",
+                                                 &filter.clock_id,
+                                                 &filter.present,
+                                                 DPLL_FILTER_DEV_CLOCK_ID))
+                               return -EINVAL;
+               } else if (dpll_argv_match(dpll, "type")) {
+                       if (dpll_filter_parse_enum(dpll, "type",
+                                                  &filter.type,
+                                                  &filter.present,
+                                                  DPLL_FILTER_DEV_TYPE,
+                                                  str_to_dpll_type,
+                                                  "pps/eec"))
+                               return -EINVAL;
+               } else if (dpll_argv_match(dpll, "mode")) {
+                       if (dpll_filter_parse_enum(dpll, "mode",
+                                                  &filter.mode,
+                                                  &filter.present,
+                                                  DPLL_FILTER_DEV_MODE,
+                                                  str_to_dpll_mode,
+                                                  "manual/automatic"))
+                               return -EINVAL;
+               } else if (dpll_argv_match(dpll, "lock-status")) {
+                       if (dpll_filter_parse_enum(dpll, "lock-status",
+                                                  &filter.lock_status,
+                                                  &filter.present,
+                                                  DPLL_FILTER_DEV_LOCK_STATUS,
+                                                  str_to_dpll_lock_status,
+                                                  "unlocked/locked/locked-ho-acq/holdover"))
+                               return -EINVAL;
                } else {
                        pr_err("unknown option: %s\n", dpll_argv(dpll));
                        return -EINVAL;
@@ -846,9 +1025,9 @@ static int cmd_device_show(struct dpll *dpll)
        }
 
        if (has_id)
-               return cmd_device_show_id(dpll, id);
+               return cmd_device_show_id(dpll, id, &filter);
 
-       return cmd_device_show_dump(dpll);
+       return cmd_device_show_dump(dpll, &filter);
 }
 
 static int cmd_device_set(struct dpll *dpll)
index e82f083feac64b986cb5e0f8140ae174c6fec875..1407ca9793c96ce209341f73167411b07cb0f4f1 100644 (file)
@@ -60,7 +60,7 @@ and newlines for better human readability.
 
 .SH DEVICE COMMANDS
 
-.SS dpll device show [ id ID ]
+.SS dpll device show [ id ID ] [ module-name NAME ] [ clock-id ID ] [ type TYPE ] [ mode MODE ] [ lock-status STATUS ]
 
 Display information about DPLL devices. If no arguments are specified,
 shows all devices in the system.
@@ -69,6 +69,29 @@ shows all devices in the system.
 .BI id " ID"
 Show only the device with the specified numeric identifier.
 
+.TP
+.BI module-name " NAME"
+Show only devices provided by the specified kernel module.
+
+.TP
+.BI clock-id " ID"
+Show only devices with the specified 64-bit clock identifier.
+
+.TP
+.BI type " TYPE"
+Show only devices of the specified type:
+.BR pps " or " eec .
+
+.TP
+.BI mode " MODE"
+Show only devices in the specified operating mode:
+.BR manual " or " automatic .
+
+.TP
+.BI lock-status " STATUS"
+Show only devices with the specified lock status:
+.BR unlocked ", " locked ", " locked-ho-acq ", " holdover .
+
 .PP
 Output includes:
 .RS
@@ -304,6 +327,16 @@ Press Ctrl+C to stop monitoring.
 .B dpll device set id 0 phase-offset-monitor enable
 .fi
 
+.SS Show all EEC devices
+.nf
+.B dpll device show type eec
+.fi
+
+.SS Show devices from specific module in JSON
+.nf
+.B dpll -jp device show module-name ice
+.fi
+
 .SS Show all pins
 .nf
 .B dpll pin show