Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: support driverkit multiarch driver builds #734

Merged
merged 10 commits into from
Jun 27, 2022
76 changes: 61 additions & 15 deletions driverkit/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,62 @@ ifeq ($(DRIVERKIT),)
DRIVERKIT := "/bin/driverkit"
endif

CONFIGS := $(wildcard config/*/*.yaml)
ALL_ARCHS := x86_64 aarch64

# Recursive wildcard
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))

# Equals function
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))

CONFIGS := $(call rwildcard,config/*,*.yaml)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find all configs under config and its subfolders (eventually, for supported $arch).

VERSIONS := $(patsubst config/%,%,$(sort $(dir $(wildcard config/*/))))
VERSIONS := $(VERSIONS:/=)
TARGET_VERSION ?= *
TARGET_DISTRO ?= *
TARGET_KERNEL ?= *
TARGET_ARCH ?= *
TARGET_ARCHS := $(if $(call eq,$(TARGET_ARCH),*),$(ALL_ARCHS),$(TARGET_ARCH))
TARGET_HEADERS ?=
S3_DRIVERS_BUCKET ?= "falco-distribution"
S3_DRIVERS_KEY_PREFIX ?= "driver"
SKIP_EXISTING ?= true

validate: $(patsubst config_%,validate/%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))
validate: validate_old validate_new
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split in 2 sub targets to correctly manage new and old driverkit config tree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it, even not elegant. When needed to cleanup it will be simple.

# old fmt had x86_64 only in root folder. Note: this breaks filtering for TARGET_ARCH
# because validate_old will always validate any old config.
# Not a big deal because we were not going to filter for TARGET_ARCH in any case.
# TODO: rm once old format support is dropped
validate_old: $(patsubst config_%,validate/%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))
# new fmt has $arch subfolders
validate_new: $(patsubst config_%,validate/%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_ARCH}/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))

all: $(patsubst config_%,%,$(subst /,_,$(CONFIGS)))

specific_target: $(patsubst config_%,%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))
specific_target: specific_target_old specific_target_new
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split in 2 sub targets to correctly manage new and old driverkit config tree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

# old fmt had x86_64 only in root folder. Note: this breaks filtering for TARGET_ARCH
# because specific_target_old will always build any old config.
# Not a big deal because we were not going to filter for TARGET_ARCH in any case.
# TODO: rm once old format support is dropped
specific_target_old: $(patsubst config_%,%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))
# new fmt has $arch subfolders
specific_target_new: $(patsubst config_%,%,$(subst /,_,$(wildcard config/${TARGET_VERSION}*/${TARGET_ARCH}/${TARGET_DISTRO}_${TARGET_KERNEL}-*)))

prepare: $(addprefix prepare_,$(VERSIONS))
publish: $(addprefix publish_,$(VERSIONS))
publish_s3: $(addprefix publish_s3_,$(VERSIONS))

generate:
$(foreach VERSION,$(VERSIONS),\
utils/generate -k ${TARGET_KERNEL} -d ${TARGET_DISTRO} -v ${VERSION}; \
$(foreach ARCH,$(TARGET_ARCHS),\
$(foreach VERSION,$(VERSIONS),\
utils/generate -a '$(ARCH)' -k '${TARGET_KERNEL}' -d '${TARGET_DISTRO}' -h '${TARGET_HEADERS}' -v '${VERSION}'; \
)\
)

generate/auto:
utils/scrape_and_generate
$(foreach ARCH,$(TARGET_ARCHS),\
utils/scrape_and_generate $(ARCH); \
)

cleanup:
utils/cleanup -p ${BINTRAY_SECRET} $(addprefix -v ,$(VERSIONS))
Expand All @@ -40,36 +69,53 @@ cleanup_s3:
S3_DRIVERS_BUCKET=${S3_DRIVERS_BUCKET} S3_DRIVERS_KEY_PREFIX=${S3_DRIVERS_KEY_PREFIX} utils/cleanup_s3 $(addprefix -v ,$(VERSIONS))

# $(1): pseudo-target name
# $(2): driver version
# $(3): config file path
# $(2): config file path
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped unused driver version param.

define gen_build_targets
validate/$(1): $(3)
utils/checkfiles $(3)
validate/$(1): $(2)
utils/checkfiles $(2)

$(1): validate/$(1) $(3)
DRIVERKIT=${DRIVERKIT} S3_DRIVERS_BUCKET=${S3_DRIVERS_BUCKET} S3_DRIVERS_KEY_PREFIX=${S3_DRIVERS_KEY_PREFIX} SKIP_EXISTING=${SKIP_EXISTING} utils/build $(3)
$(1): validate/$(1) $(2)
DRIVERKIT=${DRIVERKIT} S3_DRIVERS_BUCKET=${S3_DRIVERS_BUCKET} S3_DRIVERS_KEY_PREFIX=${S3_DRIVERS_KEY_PREFIX} SKIP_EXISTING=${SKIP_EXISTING} utils/build $(2)
endef

$(foreach CONFIG,$(CONFIGS),\
$(eval INNER := $(patsubst config/%,%,$(CONFIG)))\
$(eval VERSION := $(patsubst %/,%,$(dir $(INNER))))\
$(eval TARGET := $(patsubst config_%,%,$(subst /,_,$(CONFIG))))\
$(eval $(call gen_build_targets,$(TARGET),$(VERSION),$(CONFIG)))\
$(eval $(call gen_build_targets,$(TARGET),$(CONFIG)))\
)

# $(1): driver version
define gen_publish_targets
split_$(1)_kernelmodules:
# root is old x86_64
# TODO: rm once old format support is dropped
ifneq ("$(wildcard output/$(1)/*.ko)","")
@mkdir -p output/$(1)/kernel-module
@mv -f output/$(1)/*.ko output/$(1)/kernel-module
endif
ifneq ("$(wildcard output/$(1)/x86_64/*.ko)","")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, we now search in both root folder (old directory tree) and new $arch subfolders.

@mkdir -p output/$(1)/kernel-module/x86_64
@mv -f output/$(1)/x86_64/*.ko output/$(1)/kernel-module/x86_64
endif
ifneq ("$(wildcard output/$(1)/aarch64/*.ko)","")
@mkdir -p output/$(1)/kernel-module/aarch64
@mv -f output/$(1)/aarch64/*.ko output/$(1)/kernel-module/aarch64
endif

split_$(1)_ebpfprobes:
# root is old x86_64
# TODO: rm once old format support is dropped
ifneq ("$(wildcard output/$(1)/*.o)","")
@mkdir -p output/$(1)/ebpf-probe
@mv -f output/$(1)/*.o output/$(1)/ebpf-probe
endif
ifneq ("$(wildcard output/$(1)/x86_64/*.o)","")
@mkdir -p output/$(1)/ebpf-probe/x86_64
@mv -f output/$(1)/x86_64/*.o output/$(1)/ebpf-probe/x86_64
endif
ifneq ("$(wildcard output/$(1)/aarch64/*.o)","")
@mkdir -p output/$(1)/ebpf-probe/aarch64
@mv -f output/$(1)/aarch64/*.o output/$(1)/ebpf-probe/aarch64
endif

prepare_$(1): split_$(1)_kernelmodules split_$(1)_ebpfprobes
@echo "upserting falcosecurity/driver/kernel-module/$(1) version..."
Expand Down
7 changes: 4 additions & 3 deletions driverkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ make
### Available make targets

- `all`: build all the Falco drivers (all the versions), for every supported distro, and every supported kernel release
- `generate`: generate Driverkit config files for building drivers for specific kernel and target for all Falco lib versions
- `validate`: validate Driverkit config files for building drivers for specific kernel and target for all Falco lib versions
- `generate`: generate Driverkit config files for building drivers for specific arch, kernel and target for all Falco lib versions
- `validate`: validate Driverkit config files for building drivers for specific arch, kernel and target for all Falco lib versions
- `specific_target`: build the filtered driver versions
- `clean`: remove everything in the `output/` directory (except it, and its `.gitignore` file)
- `publish`: publish all the built Falco drivers (those existing in the `output/` directory) to bintray
Expand All @@ -37,14 +37,15 @@ make -e TARGET_DISTRO=amazonlinux2 specific_target

These are the available filters as environment variables:

- `TARGET_ARCH`: a specific arch between { "x86_64", "aarch64" }
- `TARGET_VERSION`: a specific Falco driver version
- `TARGET_DISTRO`: a spefific Linux distribution
- `TARGET_KERNEL`: a specific Linux version
- in <kernel_version>.<major_version>.<minor_version> format
- in <kernel_version>.<major_version>.* format
- in <kernel_version>.* format

Notice all the filters are optional (except `TARGET_DISTRO` and `TARGET_KERNEL` for `generate`).
Notice all the filters are optional (except for `generate` where they are mandatory).

You can also filter a specific distro with a specific kernel version:

Expand Down
15 changes: 12 additions & 3 deletions driverkit/utils/build
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ input="$1"
IFS=/ read -a input_parts <<< ${input}
driver_version="${input_parts[1]}"

# If there is an arch subdir -> use it!
# TODO: rm once old format support is dropped; just use arch="${input_parts[2]}"
if [[ ${#input_parts[@]} -eq 4 ]]; then
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workaround is needed to be able to check correct module path for old and new directory tree.

arch="${input_parts[2]}/"
else
# fallback at no arch (ie: x86_64, root folder on s3 bucket)
arch=""
fi

output_module=
output_probe=
create_variables "$input"
Expand All @@ -26,7 +35,7 @@ check_s3_existence() {

# Check whether the kernel module already exists on S3
if [[ -n "${output_module}" ]]; then
output_module_filename="${output_module##*/}"
output_module_filename="${arch}${output_module##*/}"
if [[ ${SKIP_EXISTING} == "true" ]] && check_s3_existence "${output_module_filename}"; then
>&2 echo "output module already esists inside S3 bucket - skipping (${S3_DRIVERS_KEY_PREFIX}/${driver_version}/${output_module_filename})"
else
Expand All @@ -36,7 +45,7 @@ fi

# Check whether the eBPF probe already exists on S3
if [[ -n "${output_probe}" ]]; then
output_probe_filename="${output_probe##*/}"
output_probe_filename="${arch}${output_probe##*/}"
if [[ ${SKIP_EXISTING} == "true" ]] && check_s3_existence "${output_probe_filename}"; then
>&2 echo "output probe already esists inside S3 bucket - skipping (${S3_DRIVERS_KEY_PREFIX}/${driver_version}/${output_probe_filename})"
else
Expand All @@ -46,6 +55,6 @@ fi

# Build
if [[ ${should_build} == "true" ]]; then
mkdir -p output/${driver_version}
mkdir -p output/${driver_version}/${arch}
${DRIVERKIT} docker -c ${input} --driverversion ${driver_version} --timeout 1000 || echo ${input} >> output/failing.log
fi
32 changes: 31 additions & 1 deletion driverkit/utils/checkfiles
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ source "${currentdir}/parseyaml"
input="$1"
filename="${input##*/}"

# TODO: rm once old format support is dropped; just use arch="${input_parts[2]}"
function get_arch_from_path() {
# Check if arch subdir exists
IFS=/ read -a input_parts <<< ${1}
if [[ ${#input_parts[@]} -eq 4 ]]; then
arch="${input_parts[2]}/"
else
arch=""
fi
echo -n "${arch}"
}

arch="$(get_arch_from_path ${input})"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetch arch from config file path (if any); it is later used to check that if config file is under a $arch subfolder, its output module and probe must be under same $arch subfolder.


target=
kernelrelease=
kernelversion=
Expand All @@ -34,6 +48,14 @@ if [ -n "${output_probe}" ]; then
>&2 echo "output probe filename is wrong (${1})"
exit 1
fi

# TODO: rm this external check once old format support is dropped (and we always have an arch)
if [[ -n "${arch}" ]]; then
if [ "$arch" != "$(get_arch_from_path ${output_probe})" ]; then
>&2 echo "output probe filename has wrong architecture in its config path (${1})"
exit 1
fi
fi
fi

# Check whether the kernel module filename follows the convention otherwise exit
Expand All @@ -43,4 +65,12 @@ if [ -n "${output_module}" ]; then
>&2 echo "output module filename is wrong (${1})"
exit 1
fi
fi

# TODO: rm this external check once old format support is dropped (and we always have an arch)
if [[ -n "${arch}" ]]; then
if [ "$arch" != "$(get_arch_from_path ${output_module})" ]; then
>&2 echo "output module filename has wrong architecture in its config path (${1})"
exit 1
fi
fi
fi
56 changes: 35 additions & 21 deletions driverkit/utils/driverstats
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ source "${currentdir}/parseyaml"
TARGET_VERSION=${TARGET_VERSION:-"*"}
TARGET_DISTRO=${TARGET_DISTRO:-"*"}
TARGET_KERNEL=${TARGET_KERNEL:-"*"}
TARGET_ARCH=${TARGET_ARCH:-"*"}

configs=(config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*.yaml)
# Only load old configs if x86_64 or * arch is requested
# TODO: rm this once old format support is dropped
if [ "${TARGET_ARCH}" = "*" ] || [ "${TARGET_ARCH}" = "x86_64" ]; then
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If users filter for TARGET_ARCH, only load old config if either "*" (any) or "x86_64" is requested.

configs_old=(config/${TARGET_VERSION}*/${TARGET_DISTRO}_${TARGET_KERNEL}-*.yaml)
fi
configs_new=(config/${TARGET_VERSION}*/${TARGET_ARCH}/${TARGET_DISTRO}_${TARGET_KERNEL}-*.yaml)

total_ebpf_drivers=0
total_kmod_drivers=0
Expand Down Expand Up @@ -47,26 +53,34 @@ cleanup() {
hdestroy kmod_drivers_by_version
}

for file in "${configs[@]}"
do
driver_version=${file%/*}
driver_version=${driver_version##config/}
output_module=
output_probe=
create_variables "$file"
if [ -n "${output_probe}" ]; then
((total_ebpf_drivers=total_ebpf_drivers+1))
current_num_ebpf_drivers=$(hget ebpf_drivers_by_version "${driver_version}") || current_num_ebpf_drivers=0
((current_num_ebpf_drivers=current_num_ebpf_drivers+1))
hput ebpf_drivers_by_version "${driver_version}" "${current_num_ebpf_drivers}"
fi
if [ -n "${output_module}" ]; then
((total_kmod_drivers=total_kmod_drivers+1))
current_num_kmod_drivers=$(hget kmod_drivers_by_version "${driver_version}") || current_num_kmod_drivers=0
((current_num_kmod_drivers=current_num_kmod_drivers+1))
hput kmod_drivers_by_version "${driver_version}" "${current_num_kmod_drivers}"
fi
done
loop() {
configs=("$@")
for file in "${configs[@]}"
do
driver_version=${file%/*}
driver_version=${driver_version##config/}
driver_version=$(echo "$driver_version" | tr '/' '_')
output_module=
output_probe=
create_variables "$file"
if [ -n "${output_probe}" ]; then
((total_ebpf_drivers=total_ebpf_drivers+1))
current_num_ebpf_drivers=$(hget ebpf_drivers_by_version "${driver_version}") || current_num_ebpf_drivers=0
((current_num_ebpf_drivers=current_num_ebpf_drivers+1))
hput ebpf_drivers_by_version "${driver_version}" "${current_num_ebpf_drivers}"
fi
if [ -n "${output_module}" ]; then
((total_kmod_drivers=total_kmod_drivers+1))
current_num_kmod_drivers=$(hget kmod_drivers_by_version "${driver_version}") || current_num_kmod_drivers=0
((current_num_kmod_drivers=current_num_kmod_drivers+1))
hput kmod_drivers_by_version "${driver_version}" "${current_num_kmod_drivers}"
fi
done
}

# TODO: rm this once old format support is dropped
loop "${configs_old[@]}"
loop "${configs_new[@]}"

for driver_version in $(hkeys kmod_drivers_by_version)
do
Expand Down
Loading