BPF_MAP_UPDATE_BATCH,
        BPF_MAP_DELETE_BATCH,
        BPF_LINK_CREATE,
+       BPF_LINK_UPDATE,
 };
 
 enum bpf_map_type {
                __u32           attach_type;    /* attach type */
                __u32           flags;          /* extra flags */
        } link_create;
+
+       struct { /* struct used by BPF_LINK_UPDATE command */
+               __u32           link_fd;        /* link fd */
+               /* new program fd to update link with */
+               __u32           new_prog_fd;
+               __u32           flags;          /* extra flags */
+               /* expected link's program fd; is specified only if
+                * BPF_F_REPLACE flag is set in flags */
+               __u32           old_prog_fd;
+       } link_update;
+
 } __attribute__((aligned(8)));
 
 /* The description below is an attempt at providing documentation to eBPF
 
        return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
 }
 
+int bpf_link_create(int prog_fd, int target_fd,
+                   enum bpf_attach_type attach_type,
+                   const struct bpf_link_create_opts *opts)
+{
+       union bpf_attr attr;
+
+       if (!OPTS_VALID(opts, bpf_link_create_opts))
+               return -EINVAL;
+
+       memset(&attr, 0, sizeof(attr));
+       attr.link_create.prog_fd = prog_fd;
+       attr.link_create.target_fd = target_fd;
+       attr.link_create.attach_type = attach_type;
+
+       return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
+}
+
+int bpf_link_update(int link_fd, int new_prog_fd,
+                   const struct bpf_link_update_opts *opts)
+{
+       union bpf_attr attr;
+
+       if (!OPTS_VALID(opts, bpf_link_update_opts))
+               return -EINVAL;
+
+       memset(&attr, 0, sizeof(attr));
+       attr.link_update.link_fd = link_fd;
+       attr.link_update.new_prog_fd = new_prog_fd;
+       attr.link_update.flags = OPTS_GET(opts, flags, 0);
+       attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
+
+       return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
+}
+
 int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
                   __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt)
 {
 
 LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
                                enum bpf_attach_type type);
 
+struct bpf_link_create_opts {
+       size_t sz; /* size of this struct for forward/backward compatibility */
+};
+#define bpf_link_create_opts__last_field sz
+
+LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
+                              enum bpf_attach_type attach_type,
+                              const struct bpf_link_create_opts *opts);
+
+struct bpf_link_update_opts {
+       size_t sz; /* size of this struct for forward/backward compatibility */
+       __u32 flags;       /* extra flags */
+       __u32 old_prog_fd; /* expected old program FD */
+};
+#define bpf_link_update_opts__last_field old_prog_fd
+
+LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
+                              const struct bpf_link_update_opts *opts);
+
 struct bpf_prog_test_run_attr {
        int prog_fd;
        int repeat;
 
        bool disconnected;
 };
 
+/* Replace link's underlying BPF program with the new one */
+int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog)
+{
+       return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
+}
+
 /* Release "ownership" of underlying BPF resource (typically, BPF program
  * attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected
  * link, when destructed through bpf_link__destroy() call won't attempt to
        return bpf_program__attach_lsm(prog);
 }
 
+struct bpf_link *
+bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd)
+{
+       const struct bpf_sec_def *sec_def;
+       enum bpf_attach_type attach_type;
+       char errmsg[STRERR_BUFSIZE];
+       struct bpf_link *link;
+       int prog_fd, link_fd;
+
+       prog_fd = bpf_program__fd(prog);
+       if (prog_fd < 0) {
+               pr_warn("program '%s': can't attach before loaded\n",
+                       bpf_program__title(prog, false));
+               return ERR_PTR(-EINVAL);
+       }
+
+       link = calloc(1, sizeof(*link));
+       if (!link)
+               return ERR_PTR(-ENOMEM);
+       link->detach = &bpf_link__detach_fd;
+
+       attach_type = bpf_program__get_expected_attach_type(prog);
+       if (!attach_type) {
+               sec_def = find_sec_def(bpf_program__title(prog, false));
+               if (sec_def)
+                       attach_type = sec_def->attach_type;
+       }
+       link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL);
+       if (link_fd < 0) {
+               link_fd = -errno;
+               free(link);
+               pr_warn("program '%s': failed to attach to cgroup: %s\n",
+                       bpf_program__title(prog, false),
+                       libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
+               return ERR_PTR(link_fd);
+       }
+       link->fd = link_fd;
+       return link;
+}
+
 struct bpf_link *bpf_program__attach(struct bpf_program *prog)
 {
        const struct bpf_sec_def *sec_def;
 
 LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link);
 LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path);
 LIBBPF_API int bpf_link__unpin(struct bpf_link *link);
+LIBBPF_API int bpf_link__update_program(struct bpf_link *link,
+                                       struct bpf_program *prog);
 LIBBPF_API void bpf_link__disconnect(struct bpf_link *link);
 LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
 
 LIBBPF_API struct bpf_link *
 bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
                                   const char *tp_name);
-
 LIBBPF_API struct bpf_link *
 bpf_program__attach_trace(struct bpf_program *prog);
 LIBBPF_API struct bpf_link *
 bpf_program__attach_lsm(struct bpf_program *prog);
+LIBBPF_API struct bpf_link *
+bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);
+
 struct bpf_map;
+
 LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);
+
 struct bpf_insn;
 
 /*
 
                bpf_link__pin;
                bpf_link__pin_path;
                bpf_link__unpin;
+               bpf_link__update_program;
+               bpf_link_create;
+               bpf_link_update;
                bpf_map__set_initial_value;
+               bpf_program__attach_cgroup;
                bpf_program__attach_lsm;
                bpf_program__is_lsm;
                bpf_program__set_attach_target;