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);

Posts from blogs I like

Much ado about "nothing"

Author's note Originally, I was gonna wait a bit before writing this. I had intended this to be written and published in a few weeks after the NixOS foundation board had time to react and attempt to control the damage from whatever the fuck has been going on over there. I just don't care at this point. I need this out of my head and off of my chest. I would also like to have made this a video of some kind to make it more personal (mostly so you can hear my voice and intonation/emotio…

via Xe Iaso's blog April 27, 2024

Copyleft licenses are not “restrictive”

One may observe an axis, or a “spectrum”, along which free and open source software licenses can be organized, where one end is “permissive” and the other end is “copyleft”. It is important to acknowledge, however, that though copyleft can be found at the opposite end of an axis with respect to permissive, it is not synonymous with the linguistic antonym of permissive – that is, copyleft licenses are not “restrictive” by comparison with permissive licenses. Aside: Free software is not synonymous with copyle…

via Drew DeVault's blog April 19, 2024

How web bloat impacts users with slow devices

In 2017, we looked at how web bloat affects users with slow connections. Even in the U.S., many users didn't have broadband speeds, making much of the web difficult to use. It's still the case that many users don't have broadband speeds, both inside and outside of the U.S. and that much of the modern web isn't usable for people with slow internet, but the exponential increase in bandwidth (Nielsen suggests this is 50% per year for high-end connections) has outpaced web bloat for typical sites, making this l…

via danluu.com March 16, 2024