My struggles with C and libvirt

I recently completed a project for my Advanced Operating Systems course at Georgia Tech. I found that the project was hard not because of the problem itself. It’s hard because it must be done in C, using libvirt APIs which are poorly documented, using a test setup that is brittle.

This article will hopefully save others some pain.

I’ll be providing examples of how to call relevant libvirt APIs, and some other useful information

General Tips

Set up warnings

Before you do anything, enable every single warning that you can for the C compiler. The compiler can catch so many mistakes for you if you tell it to. This includes issues like implicit casting, incorrect printf calls, ineffectual assignments, and so much more.

Update your Makefile to enable some warnings, for example:

GCCFLAGS += -Wall -Wextra -Wpedantic \
          -Wformat=2 -Wno-unused-parameter -Wshadow \
          -Wwrite-strings -Wstrict-prototypes -Wold-style-definition \
          -Wredundant-decls -Wnested-externs -Wmissing-include-dirs \
		  -Wjump-misses-init -Wlogical-op -std=c11 \
		  -Wstrict-overflow -fno-strict-aliasing \
		  -Wconversion

compile:
    gcc -g vcpu_scheduler.c -o vcpu_scheduler -lvirt -lm $(GCCFLAGS)

Refresh on C

I hadn’t written C single my senior year of college. Like many, I’ve been spoiled by high-level languages that give you modern luxeries like lists and generics. I found that spending some time reading up on modern C and pointers both helped me out.

I found these resources useful:

Development Environment

The entire class will be scrambling to setup their development environment for the first week or so. I personally installed Linux on my desktop and used that to work with VS Code SSH Remote, but there are plenty of other valid ways to work.

C/libvirt patterns

Now, onto some useful patterns.

Counting Host CPUs

C heavily uses output variables. Methods will often return ints that represent either a status code (e.g. was there an error or not), or the number of records returned, or both.

This method returns 0 on success, and -1 on failure.

It’s always good to check return codes. Nothing nothing nothing is more frustrating than being confused about why straightforward code is failing — this is one way to prevent that from happening.

virNodeInfo node_info;
if (virNodeGetInfo(conn, &node_info) == -1) {
  exit(1);
}
unsigned int num_cpus = node_info.cpus;

Listing domains

This method takes a pointer. It will allocate a list of domains at the pointer, and the return value contains the number of items returned. You can iterate over the items using this information.

Also, this method requires a bit of cleanup. You didn’t dynamically allocate any memory, but the method you called did. Clean up so that you don’t leak memory.

virDomainPtr *domain_list;
int num_domains = virConnectListAllDomains(conn, &domain_list, 0);
// don't forget to cleanup!
for (int i_domain = 0; i_domain < num_domains; i_domain++) {
  virDomainFree(domain_list[i_domain]);
}
free(domain_list);

Pin a vCPU to a pCPU

This one is rough.

I think you can form the CPU map manually, but I just call libvirt and let it form it for me, then I pin CPUs as I like.

unsigned char *map;
if (virNodeGetCPUMap(conn, &map, NULL, 0) == -1) {
  exit(1);
}

// Use CPU 0
VIR_USE_CPU(map, 0);
// Don't use CPU 1
VIR_UNUSE_CPU(map, 1);

int maplen = VIR_CPU_MAPLEN(number_of_physical_cpus);

// apply these settings to vcpu #0 in the given domain
virDomainPinVcpu(domain, 0, map, maplen);
free(map);

Recent posts from blogs that I like

Advice to a beginning software engineer

In general, you should be suspicious of engineers who are trying to give you advice. Even during ordinary times, this industry is so wide and changes so quickly that nobody really knows anything for sure. And we are not in ordinary times. The advent of LLMs and AI agents is the largest change to sof...

via Sean Goedecke

U.S. Soldier Gets 70 Months in Prison for AT&T, Verizon Extortions

A U.S. Army soldier who pleaded guilty to hacking into multiple telecommunications companies and stealing mobile call and text metadata for more than 100 million AT&T customers in 2024 was sentenced to 70 months in federal prison today and ordered to pay nearly $300,000 in restitution to victims.

via Krebs on Security

American in Paris, the brief paintings of Susan Watkins

She started training at the age of 15 in New York, then in Paris, where for a decade she was one of the most successful American painters, but died soon after her return to the USA.

via The Eclectic Light Company