def METHOD_NAME(
    cgrp: Object, bpf_attach_type: IntegerLike
) -> Iterator[Object]:
    """
    Iterate over all cgroup BPF programs of the given attach type attached to
    the given cgroup.
    :param cgrp: ``struct cgroup *``
    :param bpf_attach_type: ``enum bpf_attach_type``
    :return: Iterator of ``struct bpf_prog *`` objects.
    """
    # Before Linux kernel commit 3007098494be ("cgroup: add support for eBPF
    # programs") (in v4.10), struct cgroup::bpf didn't exist because cgroup BPF
    # programs didn't exist.
    try:
        cgrp_bpf = cgrp.bpf
    except AttributeError:
        return
    # Since Linux kernel commit 324bda9e6c5a ("bpf: multi program support for
    # cgroup+bpf") (in v4.15), the attached programs are stored in an array of
    # lists, struct cgroup_bpf::progs. Before that, only one program of each
    # attach type could be attached to a cgroup, so the attached programs are
    # stored in an array of struct bpf_prog *, struct cgroup_bpf::prog.
    try:
        progs = cgrp_bpf.progs
    except AttributeError:
        # If the kernel was not configured with CONFIG_CGROUP_BPF, then struct
        # cgroup_bpf is an empty structure.
        try:
            prog = cgrp_bpf.prog[bpf_attach_type]
        except AttributeError:
            return
        if prog:
            yield prog
    else:
        # Since Linux kernel commit 00442143a2ab ("bpf: convert
        # cgroup_bpf.progs to hlist") (in v6.0-rc1), the list of programs is an
        # hlist_head. Before that, it was a list_head.
        list = progs[bpf_attach_type].address_of_()
        if hasattr(list, "first"):
            iterator = hlist_for_each_entry
        else:
            iterator = list_for_each_entry
        for pl in iterator("struct bpf_prog_list", list, "node"):
            yield pl.prog