|      **bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes**}]
 |      **bpftool** **prog pin** *PROG* *FILE*
 |      **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
+|       **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP*
+|       **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP*
 |      **bpftool** **prog help**
 |
 |      *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
 |              **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
 |              **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
 |      }
+|       *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** }
 
 
 DESCRIPTION
 
                  Note: *FILE* must be located in *bpffs* mount.
 
+        **bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP*
+                  Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
+                  to the map *MAP*.
+
+        **bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP*
+                  Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
+                  from the map *MAP*.
+
        **bpftool prog help**
                  Print short help message.
 
 
        [BPF_PROG_TYPE_FLOW_DISSECTOR]  = "flow_dissector",
 };
 
+static const char * const attach_type_strings[] = {
+       [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
+       [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
+       [BPF_SK_MSG_VERDICT] = "msg_verdict",
+       [__MAX_BPF_ATTACH_TYPE] = NULL,
+};
+
+enum bpf_attach_type parse_attach_type(const char *str)
+{
+       enum bpf_attach_type type;
+
+       for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
+               if (attach_type_strings[type] &&
+                   is_prefix(str, attach_type_strings[type]))
+                       return type;
+       }
+
+       return __MAX_BPF_ATTACH_TYPE;
+}
+
 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
 {
        struct timespec real_time_ts, boot_time_ts;
        return a->idx - b->idx;
 }
 
+static int do_attach(int argc, char **argv)
+{
+       enum bpf_attach_type attach_type;
+       int err, mapfd, progfd;
+
+       if (!REQ_ARGS(5)) {
+               p_err("too few parameters for map attach");
+               return -EINVAL;
+       }
+
+       progfd = prog_parse_fd(&argc, &argv);
+       if (progfd < 0)
+               return progfd;
+
+       attach_type = parse_attach_type(*argv);
+       if (attach_type == __MAX_BPF_ATTACH_TYPE) {
+               p_err("invalid attach type");
+               return -EINVAL;
+       }
+       NEXT_ARG();
+
+       mapfd = map_parse_fd(&argc, &argv);
+       if (mapfd < 0)
+               return mapfd;
+
+       err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
+       if (err) {
+               p_err("failed prog attach to map");
+               return -EINVAL;
+       }
+
+       if (json_output)
+               jsonw_null(json_wtr);
+       return 0;
+}
+
+static int do_detach(int argc, char **argv)
+{
+       enum bpf_attach_type attach_type;
+       int err, mapfd, progfd;
+
+       if (!REQ_ARGS(5)) {
+               p_err("too few parameters for map detach");
+               return -EINVAL;
+       }
+
+       progfd = prog_parse_fd(&argc, &argv);
+       if (progfd < 0)
+               return progfd;
+
+       attach_type = parse_attach_type(*argv);
+       if (attach_type == __MAX_BPF_ATTACH_TYPE) {
+               p_err("invalid attach type");
+               return -EINVAL;
+       }
+       NEXT_ARG();
+
+       mapfd = map_parse_fd(&argc, &argv);
+       if (mapfd < 0)
+               return mapfd;
+
+       err = bpf_prog_detach2(progfd, mapfd, attach_type);
+       if (err) {
+               p_err("failed prog detach from map");
+               return -EINVAL;
+       }
+
+       if (json_output)
+               jsonw_null(json_wtr);
+       return 0;
+}
 static int do_load(int argc, char **argv)
 {
        enum bpf_attach_type expected_attach_type;
                "       %s %s pin   PROG FILE\n"
                "       %s %s load  OBJ  FILE [type TYPE] [dev NAME] \\\n"
                "                         [map { idx IDX | name NAME } MAP]\n"
+               "       %s %s attach PROG ATTACH_TYPE MAP\n"
+               "       %s %s detach PROG ATTACH_TYPE MAP\n"
                "       %s %s help\n"
                "\n"
                "       " HELP_SPEC_MAP "\n"
                "                 cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
                "                 cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
                "                 cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
+               "       ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n"
                "       " HELP_SPEC_OPTIONS "\n"
                "",
                bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
-               bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
+               bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
+               bin_name, argv[-2], bin_name, argv[-2]);
 
        return 0;
 }
        { "dump",       do_dump },
        { "pin",        do_pin },
        { "load",       do_load },
+       { "attach",     do_attach },
+       { "detach",     do_detach },
        { 0 }
 };