Skip to content

Commit 2c9e534

Browse files
Add support for other container engines
With this change, quark k8s awareness works on non-docker runtimes. Spotted when running quark on GKE which uses containerd like most modern k8s deployments. We only support the systemd scheme, meaning foo-<id>.scope. Co-authored-by: Christiano Haesbaert <[email protected]>
1 parent 82b2d76 commit 2c9e534

File tree

3 files changed

+113
-19
lines changed

3 files changed

+113
-19
lines changed

quark-test.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,47 @@ t_dns(const struct test *t, struct quark_queue_attr *qa)
12201220
return (0);
12211221
}
12221222

1223+
static int
1224+
t_cgroup_parse(const struct test *t, struct quark_queue_attr *qa)
1225+
{
1226+
char cid[NAME_MAX];
1227+
int i, r;
1228+
1229+
struct {
1230+
const char *in;
1231+
const char *out;
1232+
int expected_ret; /* -1 fail, 0 found, any other fail */
1233+
} cases[] = {
1234+
{ "foo/docker-f6aa2e3fa923d32f4d7905727cf1011148e4da0fd101492e98a27e8c55c5c829.scope",
1235+
"docker://f6aa2e3fa923d32f4d7905727cf1011148e4da0fd101492e98a27e8c55c5c829",
1236+
0 },
1237+
{ "foo/cri-containerd-abc123def456.scope", "containerd://abc123def456", 0 },
1238+
{ "foo/containerd-abc123def456.scope", "containerd://abc123def456", 0 },
1239+
{ "foo/crio-0123456789abcdef.scope", "cri-o://0123456789abcdef", 0 },
1240+
/* negative cases */
1241+
{ "crio-0123456789abcdef.scope", "cri-o://0123456789abcdef", -1 },
1242+
{ "docker-.scope", NULL, -1 },
1243+
{ "containerd-.scope", NULL, -1 },
1244+
{ "crio-.scope", NULL, -1 },
1245+
{ "nothex", NULL, -1 },
1246+
{ "ABCDEF", NULL, -1 },
1247+
{ "something-abcdef.scope", NULL, -1 },
1248+
{ "docker-abcdef.scopeX", NULL, -1 },
1249+
{ NULL, NULL, -1 }
1250+
};
1251+
1252+
for (i = 0; cases[i].in != NULL; i++) {
1253+
bzero(cid, sizeof(cid));
1254+
1255+
r = parse_kube_cgroup(cases[i].in, cid, sizeof(cid));
1256+
assert(r == cases[i].expected_ret);
1257+
if (r == 0)
1258+
assert(!strcmp(cid, cases[i].out));
1259+
}
1260+
1261+
return (0);
1262+
}
1263+
12231264
/*
12241265
* Try to order by increasing order of complexity
12251266
*/
@@ -1239,6 +1280,7 @@ struct test all_tests[] = {
12391280
T_EBPF(t_tty),
12401281
T_EBPF(t_sock_conn),
12411282
T_EBPF(t_dns),
1283+
T_EBPF(t_cgroup_parse),
12421284
T(t_namespace),
12431285
T(t_cache_grace),
12441286
T(t_min_agg),

quark.c

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,36 +1227,86 @@ read_kube_events(struct quark_queue *qq)
12271227
}
12281228
}
12291229

1230+
/*
1231+
* Build the kubernetes container_id from a cgroup
1232+
* cgroup is what we get from the kernel, like docker-<id>.scope.
1233+
* container_id is how kubernetes sees it, like docker://<id>.
1234+
* Returns 0 if container_id is filled, -1 otherwise.
1235+
* Keep this function non static so we can test it.
1236+
*/
1237+
int
1238+
parse_kube_cgroup(const char *cgroup, char *container_id, size_t container_id_len)
1239+
{
1240+
char *name, *dot, *id;
1241+
const char *lookup_prefix;
1242+
int r, id_skip;
1243+
1244+
if ((name = strrchr(cgroup, '/')) == NULL)
1245+
return (-1);
1246+
name++;
1247+
1248+
/*
1249+
* Atm we only accept the systemd format, foo-<id>.scope
1250+
* docker-<id>.scope -> docker://<id>
1251+
* crio-<id>.scope|libpod-<id>.scope -> cri-o://<id>
1252+
* cri-containerd-<id>.scope -> containerd://<id>
1253+
* containerd-<id>.scope -> containerd://<id>
1254+
*/
1255+
id_skip = 0;
1256+
1257+
lookup_prefix = NULL;
1258+
if (!strncmp(name, "docker-", 7)) {
1259+
id_skip = 7;
1260+
lookup_prefix = "docker";
1261+
} else if (!strncmp(name, "crio-", 5)) {
1262+
id_skip = 5;
1263+
lookup_prefix = "cri-o";
1264+
} else if (!strncmp(name, "libpod-", 7)) {
1265+
id_skip = 7;
1266+
lookup_prefix = "cri-o";
1267+
} else if (!strncmp(name, "cri-containerd-", 15)) {
1268+
id_skip = 15;
1269+
lookup_prefix = "containerd";
1270+
} else if (!strncmp(name, "containerd-", 11)) {
1271+
id_skip = 11;
1272+
lookup_prefix = "containerd";
1273+
} else
1274+
return (-1);
1275+
1276+
/*
1277+
* id starts after the foo- prefix, we still need to chomp the trailing
1278+
* .scope
1279+
*/
1280+
id = name + id_skip;
1281+
1282+
/* copy the whole thing with the lookup_prefix, and then chomp .scope */
1283+
r = snprintf(container_id, container_id_len,
1284+
"%s://%s", lookup_prefix, id);
1285+
if (r < 0 || r >= (int)container_id_len)
1286+
return (-1);
1287+
dot = strrchr(container_id, '.');
1288+
if (dot == NULL)
1289+
return (-1);
1290+
*dot = 0;
1291+
1292+
return (0);
1293+
}
1294+
12301295
static void
12311296
link_kube_data(struct quark_queue *qq, struct quark_process *qp)
12321297
{
1233-
struct quark_container *container;
1234-
char *name, *dot;
1235-
char container_id[NAME_MAX];
1236-
int r;
1298+
struct quark_container *container;
1299+
char cid[NAME_MAX];
12371300

12381301
if (qp == NULL)
12391302
return;
12401303
if ((qp->flags & QUARK_F_CONTAINER) || qp->container != NULL)
12411304
return;
12421305
if (!(qp->flags & QUARK_F_CGROUP))
12431306
return;
1244-
if ((name = strrchr(qp->cgroup, '/')) == NULL)
1245-
return;
1246-
name++;
1247-
/* docker-f6aa2e3fa923d32f4d7905727cf1011148e4da0fd101492e98a27e8c55c5c829.scope */
1248-
/* "containerID": "docker://f6aa2e3fa923d32f4d7905727cf1011148e4da0fd101492e98a27e8c55c5c829", */
1249-
if (strncmp(name, "docker-", 7))
1250-
return;
1251-
name += 7;
1252-
r = snprintf(container_id, sizeof(container_id), "docker://%s", name);
1253-
if (r < 0 || r >= (int)(sizeof(container_id)))
1307+
if (parse_kube_cgroup(qp->cgroup, cid, sizeof(cid)) == -1)
12541308
return;
1255-
dot = strrchr(container_id, '.');
1256-
if (dot == NULL)
1257-
return;
1258-
*dot = 0;
1259-
if ((container = container_lookup(qq, container_id)) == NULL)
1309+
if ((container = container_lookup(qq, cid)) == NULL)
12601310
return;
12611311

12621312
qp->container = container;

quark.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ void quark_socket_iter_init(struct quark_socket_iter *, struct quark_queue *);
6161
const struct quark_socket *quark_socket_iter_next(struct quark_socket_iter *);
6262
const struct quark_socket *quark_socket_lookup(struct quark_queue *,
6363
struct quark_sockaddr *, struct quark_sockaddr *);
64+
/* quark.c: These are exported for testing only */
65+
int parse_kube_cgroup(const char *, char *, size_t);
6466

6567
/* btf.c */
6668
struct quark_btf_target {

0 commit comments

Comments
 (0)