History

libbpf: Add support for bpf_link-based cgroup attachment

Add bpf_program__attach_cgroup(), which uses BPF_LINK_CREATE subcommand to create an FD-based kernel bpf_link. Also add low-level bpf_link_create() API. If expected_attach_type is not specified explicitly with bpf_program__set_expected_attach_type(), libbpf will try to determine proper attach type from BPF program's section definition. Also add support for bpf_link's underlying BPF program replacement: - unconditional through high-level bpf_link__update_program() API; - cmpxchg-like with specifying expected current BPF program through low-level bpf_link_update() API.

Andrii Nakryiko committed 6 years ago

Commit cc4f8641 parent 0c991eb6 files · +122 −1Browse files

Unified · Split

6 files
  1. tools/include/uapi/linux/bpf.h +12 −0
  2. tools/lib/bpf/bpf.c +34 −0
  3. tools/lib/bpf/bpf.h +19 −0
  4. tools/lib/bpf/libbpf.c +46 −0
  5. tools/lib/bpf/libbpf.h +7 −1
  6. tools/lib/bpf/libbpf.map +4 −0
tools/include/uapi/linux/bpf.h+12−0
@@ -112,6 +112,7 @@ enum bpf_cmd { · 111 unmodified lines
112112 BPF_MAP_UPDATE_BATCH,
113113 BPF_MAP_DELETE_BATCH,
114114 BPF_LINK_CREATE,
115+ BPF_LINK_UPDATE,
115116 };
116117
117118 enum bpf_map_type {
@@ -577,6 +578,17 @@ union bpf_attr { · 459 unmodified lines
577578 __u32 attach_type; /* attach type */
578579 __u32 flags; /* extra flags */
579580 } link_create;
581+
582+ struct { /* struct used by BPF_LINK_UPDATE command */
583+ __u32 link_fd; /* link fd */
584+ /* new program fd to update link with */
585+ __u32 new_prog_fd;
586+ __u32 flags; /* extra flags */
587+ /* expected link's program fd; is specified only if
588+ * BPF_F_REPLACE flag is set in flags */
589+ __u32 old_prog_fd;
590+ } link_update;
591+
580592 } __attribute__((aligned(8)));
581593
582594 /* The description below is an attempt at providing documentation to eBPF
tools/lib/bpf/bpf.c+34−0
@@ -585,6 +585,40 @@ int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type) · 584 unmodified lines
585585 return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
586586 }
587587
588+int bpf_link_create(int prog_fd, int target_fd,
589+ enum bpf_attach_type attach_type,
590+ const struct bpf_link_create_opts *opts)
591+{
592+ union bpf_attr attr;
593+
594+ if (!OPTS_VALID(opts, bpf_link_create_opts))
595+ return -EINVAL;
596+
597+ memset(&attr, 0, sizeof(attr));
598+ attr.link_create.prog_fd = prog_fd;
599+ attr.link_create.target_fd = target_fd;
600+ attr.link_create.attach_type = attach_type;
601+
602+ return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
603+}
604+
605+int bpf_link_update(int link_fd, int new_prog_fd,
606+ const struct bpf_link_update_opts *opts)
607+{
608+ union bpf_attr attr;
609+
610+ if (!OPTS_VALID(opts, bpf_link_update_opts))
611+ return -EINVAL;
612+
613+ memset(&attr, 0, sizeof(attr));
614+ attr.link_update.link_fd = link_fd;
615+ attr.link_update.new_prog_fd = new_prog_fd;
616+ attr.link_update.flags = OPTS_GET(opts, flags, 0);
617+ attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
618+
619+ return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
620+}
621+
588622 int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
589623 __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt)
590624 {
tools/lib/bpf/bpf.h+19−0
@@ -168,6 +168,25 @@ LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); · 167 unmodified lines
168168 LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
169169 enum bpf_attach_type type);
170170
171+struct bpf_link_create_opts {
172+ size_t sz; /* size of this struct for forward/backward compatibility */
173+};
174+#define bpf_link_create_opts__last_field sz
175+
176+LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
177+ enum bpf_attach_type attach_type,
178+ const struct bpf_link_create_opts *opts);
179+
180+struct bpf_link_update_opts {
181+ size_t sz; /* size of this struct for forward/backward compatibility */
182+ __u32 flags; /* extra flags */
183+ __u32 old_prog_fd; /* expected old program FD */
184+};
185+#define bpf_link_update_opts__last_field old_prog_fd
186+
187+LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
188+ const struct bpf_link_update_opts *opts);
189+
171190 struct bpf_prog_test_run_attr {
172191 int prog_fd;
173192 int repeat;
tools/lib/bpf/libbpf.c+46−0
@@ -6978,6 +6978,12 @@ struct bpf_link { · 6977 unmodified lines
69786978 bool disconnected;
69796979 };
69806980
6981+/* Replace link's underlying BPF program with the new one */
6982+int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog)
6983+{
6984+ return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
6985+}
6986+
69816987 /* Release "ownership" of underlying BPF resource (typically, BPF program
69826988 * attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected
69836989 * link, when destructed through bpf_link__destroy() call won't attempt to
@@ -7533,6 +7539,46 @@ static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec, · 549 unmodified lines
75337539 return bpf_program__attach_lsm(prog);
75347540 }
75357541
7542+struct bpf_link *
7543+bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd)
7544+{
7545+ const struct bpf_sec_def *sec_def;
7546+ enum bpf_attach_type attach_type;
7547+ char errmsg[STRERR_BUFSIZE];
7548+ struct bpf_link *link;
7549+ int prog_fd, link_fd;
7550+
7551+ prog_fd = bpf_program__fd(prog);
7552+ if (prog_fd < 0) {
7553+ pr_warn("program '%s': can't attach before loaded\n",
7554+ bpf_program__title(prog, false));
7555+ return ERR_PTR(-EINVAL);
7556+ }
7557+
7558+ link = calloc(1, sizeof(*link));
7559+ if (!link)
7560+ return ERR_PTR(-ENOMEM);
7561+ link->detach = &bpf_link__detach_fd;
7562+
7563+ attach_type = bpf_program__get_expected_attach_type(prog);
7564+ if (!attach_type) {
7565+ sec_def = find_sec_def(bpf_program__title(prog, false));
7566+ if (sec_def)
7567+ attach_type = sec_def->attach_type;
7568+ }
7569+ link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL);
7570+ if (link_fd < 0) {
7571+ link_fd = -errno;
7572+ free(link);
7573+ pr_warn("program '%s': failed to attach to cgroup: %s\n",
7574+ bpf_program__title(prog, false),
7575+ libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
7576+ return ERR_PTR(link_fd);
7577+ }
7578+ link->fd = link_fd;
7579+ return link;
7580+}
7581+
75367582 struct bpf_link *bpf_program__attach(struct bpf_program *prog)
75377583 {
75387584 const struct bpf_sec_def *sec_def;
tools/lib/bpf/libbpf.h+7−1
@@ -224,6 +224,8 @@ LIBBPF_API int bpf_link__fd(const struct bpf_link *link); · 223 unmodified lines
224224 LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link);
225225 LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path);
226226 LIBBPF_API int bpf_link__unpin(struct bpf_link *link);
227+LIBBPF_API int bpf_link__update_program(struct bpf_link *link,
228+ struct bpf_program *prog);
227229 LIBBPF_API void bpf_link__disconnect(struct bpf_link *link);
228230 LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
229231
@@ -245,13 +247,17 @@ bpf_program__attach_tracepoint(struct bpf_program *prog, · 15 unmodified lines
245247 LIBBPF_API struct bpf_link *
246248 bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
247249 const char *tp_name);
248−
249250 LIBBPF_API struct bpf_link *
250251 bpf_program__attach_trace(struct bpf_program *prog);
251252 LIBBPF_API struct bpf_link *
252253 bpf_program__attach_lsm(struct bpf_program *prog);
254+LIBBPF_API struct bpf_link *
255+bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);
256+
253257 struct bpf_map;
258+
254259 LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);
260+
255261 struct bpf_insn;
256262
257263 /*
tools/lib/bpf/libbpf.map+4−0
@@ -243,7 +243,11 @@ LIBBPF_0.0.8 { · 242 unmodified lines
243243 bpf_link__pin;
244244 bpf_link__pin_path;
245245 bpf_link__unpin;
246+ bpf_link__update_program;
247+ bpf_link_create;
248+ bpf_link_update;
246249 bpf_map__set_initial_value;
250+ bpf_program__attach_cgroup;
247251 bpf_program__attach_lsm;
248252 bpf_program__is_lsm;
249253 bpf_program__set_attach_target;