Kernel option setting failed

Hi!
Recently, I have been trying to use the Jetson Orin Nano as a node to build a K8s cluster, but the Calicol tool has been constantly failing. After checking the system requirements, I found that the following kernel options were not enabled:

root@nano:~# calicoctl node checksystem
Checking kernel version...
		5.15.148-tegra      					OK
Checking kernel modules...
		ipt_ipvs            					OK
		ipt_REJECT          					OK
		xt_addrtype         					OK
		xt_conntrack        					OK
		xt_icmp             					OK
		xt_icmp6            					OK
		xt_mark             					OK
		ip6_tables          					OK
		xt_multiport        					OK
		xt_bpf              					OK
WARNING: Unable to detect the ipt_rpfilter module as Loaded/Builtin module or lsmod
		ipt_rpfilter        					FAIL
WARNING: Unable to detect the xt_u32 module as Loaded/Builtin module or lsmod
		xt_u32              					FAIL
WARNING: Unable to detect the ip_set module as Loaded/Builtin module or lsmod
		ip_set              					FAIL
		nf_conntrack_netlink					OK
		vfio-pci            					OK
WARNING: Unable to detect the xt_rpfilter module as Loaded/Builtin module or lsmod
		xt_rpfilter         					FAIL
WARNING: Unable to detect the ipt_set module as Loaded/Builtin module or lsmod
		ipt_set             					FAIL
WARNING: Unable to detect the xt_set module as Loaded/Builtin module or lsmod
		xt_set              					FAIL
		ip_tables           					OK
System doesn't meet one or more minimum systems requirements to run Calico

So I tried to recompile the kernel to enable the relevant features, and I asked AI how to set the relevant kernel features, and the response was as follows:

CONFIG_NETFILTER_XT_MATCH_RPFILTER=m    # For xt_rpfilter
CONFIG_IP_SET=m                         # For ip_set
CONFIG_NETFILTER_XT_SET=m               # For xt_set
CONFIG_NETFILTER_XT_MATCH_U32=m         # For xt_u32
CONFIG_IP_NF_SET=m                      # For ipt_set

Unfortunately, after compilation, only xt_u32 and ip_set are enabled.
Here is my device information.

root@nano:~# apt-cache show nvidia-jetpack

Package: nvidia-jetpack
Source: nvidia-jetpack (6.2)
Version: 6.2+b77
Architecture: arm64
Maintainer: NVIDIA Corporation
Installed-Size: 194
Depends: nvidia-jetpack-runtime (= 6.2+b77), nvidia-jetpack-dev (= 6.2+b77)
Homepage: http://developer.nvidia.com/jetson
Priority: standard
Section: metapackages
Filename: pool/main/n/nvidia-jetpack/nvidia-jetpack_6.2+b77_arm64.deb
Size: 29298
SHA256: 70553d4b5a802057f9436677ef8ce255db386fd3b5d24ff2c0a8ec0e485c59cd
SHA1: 9deab64d12eef0e788471e05856c84bf2a0cf6e6
MD5sum: 4db65dc36434fe1f84176843384aee23
Description: NVIDIA Jetpack Meta Package
Description-md5: ad1462289bdbc54909ae109d1d32c0a8

Package: nvidia-jetpack
Source: nvidia-jetpack (6.1)
Version: 6.1+b123
Architecture: arm64
Maintainer: NVIDIA Corporation
Installed-Size: 194
Depends: nvidia-jetpack-runtime (= 6.1+b123), nvidia-jetpack-dev (= 6.1+b123)
Homepage: http://developer.nvidia.com/jetson
Priority: standard
Section: metapackages
Filename: pool/main/n/nvidia-jetpack/nvidia-jetpack_6.1+b123_arm64.deb
Size: 29312
SHA256: b6475a6108aeabc5b16af7c102162b7c46c36361239fef6293535d05ee2c2929
SHA1: f0984a6272c8f3a70ae14cb2ca6716b8c1a09543
MD5sum: a167745e1d88a8d7597454c8003fa9a4
Description: NVIDIA Jetpack Meta Package
Description-md5: ad1462289bdbc54909ae109d1d32c0a8

How should I configure the kernel to enable the features that are not enabled?
Is there a simpler way to enable these options besides compiling?
Thank you for your help!

You won’t be able to add this without compiling, but instructions can be simple and easy (at least in practical terms; they will sound complicated, and can be, but are not at all complicated after you do this once). The official documentation is good about compiling via cross-compile, which means on a Linux host PC. One can also natively compile on the Jetson if you have the disk space. Installation is where things can be either complicated or easy. The NVIDIA docs only show how to put the kernel content in the flash content and then flash, but if you only build a module, only a file copy is needed for installation.

Just a heads up before more details: The features which the running kernel has will be found in the compressed file “/proc/config.gz”. This is not a real file, it is the kernel telling you about its configuration in RAM. You could copy this file somewhere, and then “gunzip config.gz” to get the config file. There will be one configuration item not in that file, which is CONFIG_LOCALVERSION. If you run the command “uname -r”, then the suffix will be the CONFIG_LOCALVERSION (it is a string; the default is “-tegra”). If the old kernel is not running though, then that information is suspect. If you are running the original kernel, then I would suspect keeping a copy of that file safe and renaming it as “mv config "config-$(uname -r)"”. This is your starting point.

You could view that file with a text editor (it is human-readable). You will find some features are integrated…meaning they are not a module and are directly part of the kernel. Those features will show as “=y”. Features which are in the form of a module are “=m”. If you start with a kernel in which all configuration matches the running kernel, and then change only the module parts (the “=m”, such as adding a module), then all of your original modules will continue to work and the new module can be simply dropped in with a file copy and they will work with that kernel.

Some of this depends on what you’ve already done. If you’ve replaced something, then we need to know about it because the /proc/config.gz will probably no longer be a valid starting point. Before continuing, we need to know that information.

Do understand that simply hand editing the config is usually a “bad idea"™. Some features depend on others. There are build targets (“make <...something...target>”) which are dependency-aware editors. For example, when you use “make menuconfig” or “make nconfig” on a kernel this brings up an editor (I prefer nconfig which has a symbol search function, but is otherwise exactly like menuconfig”), and if you change a feature with this, then it also changes dependencies (if they exist).

Are you still using the original kernel? What do you see from “uname -r”? Are you interested in cross compile on your Linux host PC, or compiling natively on the Jetson? If on the Jetson, do you have sufficient disk space (use “df -H -T” and look for “Mounted on” of “/”)?

Do keep in mind that this is actually a lot simpler than it sounds if you’ve done this one time.

I am still using the original kernel without change. What I saw is as follows.

root@nano:~# uname -r
5.15.148-tegra
root@nano:~# uname -a
Linux nano 5.15.148-tegra #1 SMP PREEMPT Tue Jan 7 17:14:38 PST 2025 aarch64 aarch64 aarch64 GNU/Linux

I am currently cross-compiling on a Linux host PC because compiling on the Jetson device always results in inexplicable errors.
I just tried using ‘make menuconfig’ or ‘make nconfig’, but I couldn’t find the options I need. I have no idea about this manu.

For reference, if you want to just build the module(s), then they must be compatible with that currently running kernel. For that reason, write down this:
CONFIG_LOCALVERSION="-tegra"

This is what determines the suffix of “-tegra” when you run the command “uname -r”. If you copy the “/proc/config.gz” somewhere safe, then this is one of the few parameters you can safely hand edit (you could use something like menuconfig or nconfig). If you gunzip that file in some other location (you can’t edit in “/proc”), then you could directly search for CONFIG_LOCALVERSION, and then set it as I list above. The kernel source code of course has to also be an exact match.

Regarding source code version, there are a number of ways to get the correct version. However, if you know your L4T release and get the source code from NVIDIA at their download location for that L4T release, then this will always be valid. L4T is just what you call Ubuntu after it gets the NVIDIA content added to it. To find your L4T release see the output of “head -n 1 /etc/nv_tegra_release”. For Orin it would be either an L4T R35.x or R36.x (always state your L4T release version when asking questions on the forums). Go to your L4T release here:
https://developer.nvidia.com/linux-tegra

The public sources is a package which contains other packages. One of those other packages is the kernel (and some out of tree content; the out of tree content isn’t always important, but often is). If you need help with that, then just ask.

Before explaining all of the compile I will mention some things that make life easier. You will always want your kernel source to remain pristine and clean. This means all builds and all configuration should be in some temporary location which is separate from the source code. This is the “O=/some/where” option during build. If you don’t use that, build is in the source code tree itself. To make the source code tree completely clean and unconfigured you use this command:
make mrproper

Once that is done, then always use the “O=/some/where” to name an empty directory location (it won’t be empty once you’ve done anything with the build). You can set an environment variable to more easily work with this. For example:

# This is a new empty location. Name is arbitrary.
mkdir ~/kernel

# This terminal will see this value. The name "TEGRA_KERNEL_OUT" is arbitrary, but happens to be
# what NVIDIA uses in its examples.
export TEGRA_KERNEL_OUT=~/kernel

# This should verify the location.
echo $TEGRA_KERNEL_OUT

From that point forward (in that terminal) any build command (other than mrproper) would have this in it:
O=$TEGRA_KERNEL_OUT

For convenience, wherever the current kernel source is at, I will call that “TOP”. If you first cd to the location where you would normally compile kernel source from:

export TOP=`pwd`
echo $TOP

Most compile commands are from $TOP.

You also must start with a configuration which matches the existing kernel. The default config target for L4T R35.x and earlier would tegra_defconfig, but starting in L4T R36.x that default is “defconfig”. The L4T R35.x has a lot of out-of-tree content, whereas R36.x is now mainline. You could start with that (assuming you set up $TEGRA_KERNEL_OUT which is currently empty):

cd $TOP

# L4T R35.x:
make tegra_defconfig

# If L4T R36.x:
make defconfig

Remember that file you copied somewhere and appended “-tegra” to the “CONFIG_LOCALVERSION”? If the kernel was default, then this would be very similar, although it might order config lines differently. Just using defconfig or tegra_defconfig would also require you to add “-tegra” to the CONFIG_LOCALVERSION. To emphasize, the reason for this is to match the running kernel if and only if all of the “integrated” (“=y”, non-modular) features are an exact match. Once an integrated feature changes you do not want CONFIG_LOCALVERSION to match. We’re assuming everything you are editing will change only modules. That /proc/config.gz (after gunzip and after editing CONFIG_LOCALVERSION) will always match because it is the actual running kernel which produced this. defconfig and tegra_defconfig only match if your kernel has a default configuration.

When you copy the /proc/config.gz (after gunzip and with CONFIG_LOCALVERSION edited) to the new name “.config”, and place it at the “O=/some/where” ($TEGRA_KERNEL_OUT) this replaces using defconfig (or tegra_defconfig). In fact, this is what “make defconfig” (or tegra_defconfig) does: It creates a .config file in the output location of the kernel build. Regardless of whether you used a default target (such as make defconfig) you will have “$TEGRA_KERNEL_OUT/.config”.

Any editing software modifies “$TEGRA_KERNEL_OUT/.config”, and so you have to remember to use “O=$TEGRA_KERNEL_OUT” for everything you do. If ten people are using the same kernel source, but each person has their own $TEGRA_KERNEL_OUT, then nobody will collide with someone else’s configuration. Or a single person could use multiple different $TEGRA_KERNEL_OUT and different configurations, all using the same pristine and unmodified source code.


So here is a list of what you will probably actually do, assuming $TOP and $TEGRA_KERNEL_OUT are set (this does not mention the cross compile flags; I will add a version for cross compile later):

cp /proc/config.gz /some/safe/location/for/archive
cd /some/safe/location/for/archive
gunzip config.gz

# Now edit and set CONFIG_LOCALVERSION:
CONFIG_LOCALVERSION=-tegra

# You could also use quotes because it is a string:
CONFIG_LOCALVERSION="-tegra"

# We'll use the config.gz instead of a defconfig, but you could in a lot of cases also skip config.gz
# and instead use defconfig (L4T R36.x+) or tegra_defconfig (L4T R35.x or earlier).
cd $TEGRA_KERNEL_OUT
cp /some/safe/location/for/archive/config .config
cd $TOP

# Now we will configure your changes. Note that since there is a .config that what you start
# with is an unmodified exact match to your running kernel. The only differences will be from
# what you change. I use nconfig because it has a symbol search; every kernel feature has
# a symbol. CONFIG_LOCALVERSION is a symbol, and so is any change you make. Don't forget
# that if you fail to use O=/some/where, then your config will be missing.
make O=$TEGRA_KERNEL_OUT nconfig

# Use symbol search and find something you are interested in. Probably each of these, one at
# a time:
CONFIG_NETFILTER_XT_MATCH_RPFILTER
CONFIG_IP_SET
CONFIG_NETFILTER_XT_SET
CONFIG_NETFILTER_XT_MATCH_U32
CONFIG_IP_NF_SET

# At each of those use the 'm' key to enable as a module. Because this editor is dependency-aware
# any dependency will also be triggered. I don't know if CONFIG_IP_SET has dependencies, but if it
# does, then using 'm' to enable it will also set the other. This is rather important.

# Note that not all features can be integrated, nor can all features be a module. Most can be either.
# If you run into something which triggers an integration ("=y") instead of a module ("=m"), then you
# must change CONFIG_LOCALVERSION and you must reinstall everything. This includes modules and
# the kernel itself. Most likely you can just change modules.

# Then save and exit. This updates $TEGRA_KERNEL_OUT/.config. You could save that .config with
# an obvious name change in case you wish to start editing from that. You'd just copy it to a new
# $TEGRA_KERNEL_OUT with the name .config.

The above is only for configuration. That configuration is not yet propagated. If you build the main target, Image, then this automatically propagates configuration throughout the source code. You don’t need to build Image, although building it once as a test is advised. To manually propagate this configuration before building modules and skipping Image compile:
make O=$TEGRA_KERNEL_OUT modules_prepare

If you choose to build Image, which I advise as an “acid test” to see if all is in order:
make O=$TEGRA_KERNEL_OUT Image

To build modules:
make O=$TEGRA_KERNEL_OUT modules

There are steps to make finding what you want (after build) easier. Keep in mind that any kernel will look for its modules at:
/lib/modules/$(uname -r)/kernel/
(and half of uname -r comes from CONFIG_LOCALVERSION)

If you create another empty directory for modules to be output to, then there will be a temp location subdirectory named after the final module location. Let’s say you created this:

mkdir ~/modules
cd ~/modules
export INSTALL_MOD_PATH=`pwd`
echo $INSTALL_MOD_PATH

# You built modules, so put them in this new location:
cd $TOP
make O=$TEGRA_KERNEL_OUT modules_install INSTALL_MOD_PATH=$TEGRA_MODULES_OUT

If you now cd $TEGRA_MODULES_OUT you will find this subdirectory:
lib/modules/$(uname -r)/kernel/

Somewhere within that is your kernel module. You need a few modules, and each will be at a location which mirrors where it was in the source code. There might for example be one of your files near here:
$TEGRA_MODULES_OUT/lib/modules/5.15.148-tegra/kernel/net/some_feature_of_networks/abc.ko

If you are only adding modular features, then you simply copy those files in that same subdirectory to the Jetson’s “/lib/modules/$(uname -r)/kernel/...wherever...”. Then run “sudo depmod -a”. Or reboot, or both.


Note: For this example I’m assuming your host has 12 CPU cores. In cases where more than one core can be used (sometimes dependencies stop this) you can use the job server. This is the “-j #” option to make. To use 12 cores “-j 12”.

Here is a variation which is from cross compile; you will have to substitute the actual location of your cross tools (this is just my example and locations likely differ):

# Where is your actual cross tool chain?
export CROSS_COMPILE=/usr/bin/aarch64-linux-gnu-

# Only use ARCH when cross compiling. Do not set ARCH for native.
export ARCH=arm64
export TOP=/where/ever/kernel/source/is/at

mkdir ~/kernel
export TEGRA_KERNEL_OUT=~/kernel
echo $TEGRA_KERNEL_OUT

mkdir ~/modules
export TEGRA_MODULES_OUT=~modules
echo $TEGRA_MODULES_OUT

cp /saved/config/file/with/localversion/config $TEGRA_KERNEL_OUT/.config
cd $TOP

# You don't actually need to do this all the time, it is only if unsure of the source being pristine:
make mrproper

# This would be good even if you don't use 
make nconfig

# Edit, changing only modules. If for some reason a change cannot be in the form of a module,
# then you must start over with a new CONFIG_LOCALVERSION and build everything...modules
# and kernel. Assuming we only need modules (and building Image is done once to see if it
# finds any errors, but Image won't be installed).

# Building Image, needed only once as a test:
make -j 12 O=$TEGRA_KERNEL_OUT Image

# If you did not build Image, then propagate the config:
make O=$TEGRA_KERNEL_OUT modules_prepare

# Build modules:
make -j 12 O=$TEGRA_KERNEL_OUT modules

# Distribute modules in the empty location:
make O=$TEGRA_KERNEL_OUT modules_install INSTALL_MOD_PATH=$TEGRA_MODULES_OUT

# Copy only the modules which are new to the Jetson's "/lib/modules/$(uname -r)/kernel/...somewhere...

# On the Jetson:
sudo depmod -a

# Reboot of the Jetson is advised, but you could manually test with "modprobe <module name>"
# manually if you wish.

That’s it. As complicated as it sounds, there is no flash required for adding modules if they match the running kernel. All of those steps can be put in a script, or copy and pasted with a few edits.

Thank you very much for taking the time to help me. I know the process of compiling and updating kernel modules. My question is about that the following kernel features do not exist in the config: are these features named this way?or have they already been deprecated?

CONFIG_NETFILTER_XT_MATCH_RPFILTER
CONFIG_NETFILTER_XT_SET
CONFIG_IP_NF_SET

Thank you again.

Your kernel version depends on whether the L4T release is R35.x or R36.x. What do you see, on the running Jetson, from this?

zcat /proc/config.gz | egrep -i '(CONFIG_NETFILTER_XT_MATCH_RPFILTER|CONFIG_NETFILTER_XT_SET|CONFIG_IP_NF_SET)'

(you could copy and paste that)

The config.gz will show unused features as well as those which are used. If the features are not present, then probably the instructions for the particular symbols (which are just a token for the actual feature) are intended for a different kernel version (a major release version, e.g., you’re using a 5.x kernel, maybe this is from 4.x or 6.x).

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.