summaryrefslogtreecommitdiffstats
path: root/lib/libbpf/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libbpf/scripts')
-rwxr-xr-xlib/libbpf/scripts/build-fuzzers.sh81
-rwxr-xr-xlib/libbpf/scripts/coverity.sh105
-rwxr-xr-xlib/libbpf/scripts/sync-kernel.sh350
3 files changed, 536 insertions, 0 deletions
diff --git a/lib/libbpf/scripts/build-fuzzers.sh b/lib/libbpf/scripts/build-fuzzers.sh
new file mode 100755
index 0000000..75b3833
--- /dev/null
+++ b/lib/libbpf/scripts/build-fuzzers.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+set -eux
+
+SANITIZER=${SANITIZER:-address}
+flags="-O1 -fno-omit-frame-pointer -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER -fsanitize=fuzzer-no-link"
+
+export CC=${CC:-clang}
+export CFLAGS=${CFLAGS:-$flags}
+
+export CXX=${CXX:-clang++}
+export CXXFLAGS=${CXXFLAGS:-$flags}
+
+cd "$(dirname -- "$0")/.."
+
+export OUT=${OUT:-"$(pwd)/out"}
+mkdir -p "$OUT"
+
+export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer}
+
+# libelf is compiled with _FORTIFY_SOURCE by default and it
+# isn't compatible with MSan. It was borrowed
+# from https://github.com/google/oss-fuzz/pull/7422
+if [[ "$SANITIZER" == memory ]]; then
+ CFLAGS+=" -U_FORTIFY_SOURCE"
+ CXXFLAGS+=" -U_FORTIFY_SOURCE"
+fi
+
+# The alignment check is turned off by default on OSS-Fuzz/CFLite so it should be
+# turned on explicitly there. It was borrowed from
+# https://github.com/google/oss-fuzz/pull/7092
+if [[ "$SANITIZER" == undefined ]]; then
+ additional_ubsan_checks=alignment
+ UBSAN_FLAGS="-fsanitize=$additional_ubsan_checks -fno-sanitize-recover=$additional_ubsan_checks"
+ CFLAGS+=" $UBSAN_FLAGS"
+ CXXFLAGS+=" $UBSAN_FLAGS"
+fi
+
+# Ideally libbelf should be built using release tarballs available
+# at https://sourceware.org/elfutils/ftp/. Unfortunately sometimes they
+# fail to compile (for example, elfutils-0.185 fails to compile with LDFLAGS enabled
+# due to https://bugs.gentoo.org/794601) so let's just point the script to
+# commits referring to versions of libelf that actually can be built
+rm -rf elfutils
+git clone git://sourceware.org/git/elfutils.git
+(
+cd elfutils
+git checkout 83251d4091241acddbdcf16f814e3bc6ef3df49a
+git log --oneline -1
+
+# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
+find -name Makefile.am | xargs sed -i 's/,--no-undefined//'
+
+# ASan isn't compatible with -Wl,-z,defs either:
+# https://clang.llvm.org/docs/AddressSanitizer.html#usage
+sed -i 's/^\(ZDEFS_LDFLAGS=\).*/\1/' configure.ac
+
+if [[ "$SANITIZER" == undefined ]]; then
+ # That's basicaly what --enable-sanitize-undefined does to turn off unaligned access
+ # elfutils heavily relies on on i386/x86_64 but without changing compiler flags along the way
+ sed -i 's/\(check_undefined_val\)=[0-9]/\1=1/' configure.ac
+fi
+
+autoreconf -i -f
+if ! ./configure --enable-maintainer-mode --disable-debuginfod --disable-libdebuginfod \
+ CC="$CC" CFLAGS="-Wno-error $CFLAGS" CXX="$CXX" CXXFLAGS="-Wno-error $CXXFLAGS" LDFLAGS="$CFLAGS"; then
+ cat config.log
+ exit 1
+fi
+
+make -C config -j$(nproc) V=1
+make -C lib -j$(nproc) V=1
+make -C libelf -j$(nproc) V=1
+)
+
+make -C src BUILD_STATIC_ONLY=y V=1 clean
+make -C src -j$(nproc) CFLAGS="-I$(pwd)/elfutils/libelf $CFLAGS" BUILD_STATIC_ONLY=y V=1
+
+$CC $CFLAGS -Isrc -Iinclude -Iinclude/uapi -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -c fuzz/bpf-object-fuzzer.c -o bpf-object-fuzzer.o
+$CXX $CXXFLAGS $LIB_FUZZING_ENGINE bpf-object-fuzzer.o src/libbpf.a "$(pwd)/elfutils/libelf/libelf.a" -l:libz.a -o "$OUT/bpf-object-fuzzer"
+
+cp fuzz/bpf-object-fuzzer_seed_corpus.zip "$OUT"
diff --git a/lib/libbpf/scripts/coverity.sh b/lib/libbpf/scripts/coverity.sh
new file mode 100755
index 0000000..99e4809
--- /dev/null
+++ b/lib/libbpf/scripts/coverity.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+# Taken from: https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
+# Local changes are annotated with "#[local]"
+
+set -e
+
+# Environment check
+echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
+[ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
+[ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
+[ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
+[ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
+[ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1
+
+PLATFORM=`uname`
+#[local] Use /var/tmp for TOOL_ARCHIVE and TOOL_BASE, as on certain systems
+# /tmp is tmpfs and is sometimes too small to handle all necessary tooling
+TOOL_ARCHIVE=/var//tmp/cov-analysis-${PLATFORM}.tgz
+TOOL_URL=https://scan.coverity.com/download/${PLATFORM}
+TOOL_BASE=/var/tmp/coverity-scan-analysis
+UPLOAD_URL="https://scan.coverity.com/builds"
+SCAN_URL="https://scan.coverity.com"
+
+# Do not run on pull requests
+if [ "${TRAVIS_PULL_REQUEST}" = "true" ]; then
+ echo -e "\033[33;1mINFO: Skipping Coverity Analysis: branch is a pull request.\033[0m"
+ exit 0
+fi
+
+# Verify this branch should run
+IS_COVERITY_SCAN_BRANCH=`ruby -e "puts '${TRAVIS_BRANCH}' =~ /\\A$COVERITY_SCAN_BRANCH_PATTERN\\z/ ? 1 : 0"`
+if [ "$IS_COVERITY_SCAN_BRANCH" = "1" ]; then
+ echo -e "\033[33;1mCoverity Scan configured to run on branch ${TRAVIS_BRANCH}\033[0m"
+else
+ echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${TRAVIS_BRANCH}\033[0m"
+ exit 1
+fi
+
+# Verify upload is permitted
+AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
+if [ "$AUTH_RES" = "Access denied" ]; then
+ echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
+ exit 1
+else
+ AUTH=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['upload_permitted']"`
+ if [ "$AUTH" = "true" ]; then
+ echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
+ else
+ WHEN=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['next_upload_permitted_at']"`
+ echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
+ exit 0
+ fi
+fi
+
+if [ ! -d $TOOL_BASE ]; then
+ # Download Coverity Scan Analysis Tool
+ if [ ! -e $TOOL_ARCHIVE ]; then
+ echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
+ wget -nv -O $TOOL_ARCHIVE $TOOL_URL --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=$COVERITY_SCAN_TOKEN"
+ fi
+
+ # Extract Coverity Scan Analysis Tool
+ echo -e "\033[33;1mExtracting Coverity Scan Analysis Tool...\033[0m"
+ mkdir -p $TOOL_BASE
+ pushd $TOOL_BASE
+ tar xzf $TOOL_ARCHIVE
+ popd
+fi
+
+TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
+export PATH=$TOOL_DIR/bin:$PATH
+
+# Build
+echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
+COV_BUILD_OPTIONS=""
+#COV_BUILD_OPTIONS="--return-emit-failures 8 --parse-error-threshold 85"
+RESULTS_DIR="cov-int"
+eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
+COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $COV_BUILD_OPTIONS $COVERITY_SCAN_BUILD_COMMAND
+cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt 2>&1
+
+# Upload results
+echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
+RESULTS_ARCHIVE=analysis-results.tgz
+tar czf $RESULTS_ARCHIVE $RESULTS_DIR
+SHA=`git rev-parse --short HEAD`
+
+echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
+response=$(curl \
+ --silent --write-out "\n%{http_code}\n" \
+ --form project=$COVERITY_SCAN_PROJECT_NAME \
+ --form token=$COVERITY_SCAN_TOKEN \
+ --form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
+ --form file=@$RESULTS_ARCHIVE \
+ --form version=$SHA \
+ --form description="Travis CI build" \
+ $UPLOAD_URL)
+status_code=$(echo "$response" | sed -n '$p')
+#[local] Coverity used to return 201 on success, but it's 200 now
+# See https://github.com/systemd/systemd/blob/master/tools/coverity.sh#L145
+if [ "$status_code" != "200" ]; then
+ TEXT=$(echo "$response" | sed '$d')
+ echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
+ exit 1
+fi
diff --git a/lib/libbpf/scripts/sync-kernel.sh b/lib/libbpf/scripts/sync-kernel.sh
new file mode 100755
index 0000000..1653c2e
--- /dev/null
+++ b/lib/libbpf/scripts/sync-kernel.sh
@@ -0,0 +1,350 @@
+#!/bin/bash
+
+usage () {
+ echo "USAGE: ./sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>"
+ echo ""
+ echo "Set BPF_NEXT_BASELINE to override bpf-next tree commit, otherwise read from <libbpf-repo>/CHECKPOINT-COMMIT."
+ echo "Set BPF_BASELINE to override bpf tree commit, otherwise read from <libbpf-repo>/BPF-CHECKPOINT-COMMIT."
+ echo "Set MANUAL_MODE to 1 to manually control every cherry-picked commits."
+ exit 1
+}
+
+set -eu
+
+LIBBPF_REPO=${1-""}
+LINUX_REPO=${2-""}
+BPF_BRANCH=${3-""}
+BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
+BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
+
+if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ]; then
+ echo "Error: libbpf or linux repos are not specified"
+ usage
+fi
+if [ -z "${BPF_BRANCH}" ]; then
+ echo "Error: linux's bpf tree branch is not specified"
+ usage
+fi
+if [ -z "${BASELINE_COMMIT}" ] || [ -z "${BPF_BASELINE_COMMIT}" ]; then
+ echo "Error: bpf or bpf-next baseline commits are not provided"
+ usage
+fi
+
+SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
+WORKDIR=$(pwd)
+TMP_DIR=$(mktemp -d)
+
+trap "cd ${WORKDIR}; exit" INT TERM EXIT
+
+declare -A PATH_MAP
+PATH_MAP=( \
+ [tools/lib/bpf]=src \
+ [tools/include/uapi/linux/bpf_common.h]=include/uapi/linux/bpf_common.h \
+ [tools/include/uapi/linux/bpf.h]=include/uapi/linux/bpf.h \
+ [tools/include/uapi/linux/btf.h]=include/uapi/linux/btf.h \
+ [tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
+ [tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
+ [tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
+ [tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
+ [tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
+ [include/uapi/linux/perf_event.h]=include/uapi/linux/perf_event.h \
+ [Documentation/bpf/libbpf]=docs \
+)
+
+LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
+LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
+LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
+LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
+
+LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
+for p in "${!PATH_MAP[@]}"; do
+ LIBBPF_TREE_FILTER+="git mv -kf ${p} __libbpf/${PATH_MAP[${p}]} && "$'\\\n'
+done
+LIBBPF_TREE_FILTER+="git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.c,.gitignore} >/dev/null"
+
+cd_to()
+{
+ cd ${WORKDIR} && cd "$1"
+}
+
+# Output brief single-line commit description
+# $1 - commit ref
+commit_desc()
+{
+ git log -n1 --pretty='%h ("%s")' $1
+}
+
+# Create commit single-line signature, which consists of:
+# - full commit subject
+# - author date in ISO8601 format
+# - full commit body with newlines replaced with vertical bars (|)
+# - shortstat appended at the end
+# The idea is that this single-line signature is good enough to make final
+# decision about whether two commits are the same, across different repos.
+# $1 - commit ref
+# $2 - paths filter
+commit_signature()
+{
+ git show --pretty='("%s")|%aI|%b' --shortstat $1 -- ${2-.} | tr '\n' '|'
+}
+
+# Cherry-pick commits touching libbpf-related files
+# $1 - baseline_tag
+# $2 - tip_tag
+cherry_pick_commits()
+{
+ local manual_mode=${MANUAL_MODE:-0}
+ local baseline_tag=$1
+ local tip_tag=$2
+ local new_commits
+ local signature
+ local should_skip
+ local synced_cnt
+ local manual_check
+ local libbpf_conflict_cnt
+ local desc
+
+ new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
+ for new_commit in ${new_commits}; do
+ desc="$(commit_desc ${new_commit})"
+ signature="$(commit_signature ${new_commit} "${LIBBPF_PATHS[@]}")"
+ synced_cnt=$(grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | wc -l)
+ manual_check=0
+ if ((${synced_cnt} > 0)); then
+ # commit with the same subject is already in libbpf, but it's
+ # not 100% the same commit, so check with user
+ echo "Commit '${desc}' is synced into libbpf as:"
+ grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | \
+ cut -d'|' -f1 | sed -e 's/^/- /'
+ if ((${manual_mode} != 1 && ${synced_cnt} == 1)); then
+ echo "Skipping '${desc}' due to unique match..."
+ continue
+ fi
+ if ((${synced_cnt} > 1)); then
+ echo "'${desc} matches multiple commits, please, double-check!"
+ manual_check=1
+ fi
+ fi
+ if ((${manual_mode} == 1 || ${manual_check} == 1)); then
+ read -p "Do you want to skip '${desc}'? [y/N]: " should_skip
+ case "${should_skip}" in
+ "y" | "Y")
+ echo "Skipping '${desc}'..."
+ continue
+ ;;
+ esac
+ fi
+ # commit hasn't been synced into libbpf yet
+ echo "Picking '${desc}'..."
+ if ! git cherry-pick ${new_commit} &>/dev/null; then
+ echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
+ libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
+ conflict_cnt=$(git diff --name-only | wc -l)
+ prompt_resolution=1
+
+ if ((${libbpf_conflict_cnt} == 0)); then
+ echo "Looks like only non-libbpf files have conflicts, ignoring..."
+ if ((${conflict_cnt} == 0)); then
+ echo "Empty cherry-pick, skipping it..."
+ git cherry-pick --abort
+ continue
+ fi
+
+ git add .
+ # GIT_EDITOR=true to avoid editor popping up to edit commit message
+ if ! GIT_EDITOR=true git cherry-pick --continue &>/dev/null; then
+ echo "Error! That still failed! Please resolve manually."
+ else
+ echo "Success! All cherry-pick conflicts were resolved for '${desc}'!"
+ prompt_resolution=0
+ fi
+ fi
+
+ if ((${prompt_resolution} == 1)); then
+ read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
+ fi
+ fi
+ # Append signature of just cherry-picked commit to avoid
+ # potentially cherry-picking the same commit twice later when
+ # processing bpf tree commits. At this point we don't know yet
+ # the final commit sha in libbpf repo, so we record Linux SHA
+ # instead as LINUX_<sha>.
+ echo LINUX_$(git log --pretty='%h' -n1) "${signature}" >> ${TMP_DIR}/libbpf_commits.txt
+ done
+}
+
+cleanup()
+{
+ echo "Cleaning up..."
+ rm -r ${TMP_DIR}
+ cd_to ${LINUX_REPO}
+ git checkout ${TIP_SYM_REF}
+ git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
+ ${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG} || true
+
+ cd_to .
+ echo "DONE."
+}
+
+
+cd_to ${LIBBPF_REPO}
+GITHUB_ABS_DIR=$(pwd)
+echo "Dumping existing libbpf commit signatures..."
+for h in $(git log --pretty='%h' -n500); do
+ echo $h "$(commit_signature $h)" >> ${TMP_DIR}/libbpf_commits.txt
+done
+
+# Use current kernel repo HEAD as a source of patches
+cd_to ${LINUX_REPO}
+LINUX_ABS_DIR=$(pwd)
+TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
+TIP_COMMIT=$(git rev-parse HEAD)
+BPF_TIP_COMMIT=$(git rev-parse ${BPF_BRANCH})
+BASELINE_TAG=libbpf-baseline-${SUFFIX}
+TIP_TAG=libbpf-tip-${SUFFIX}
+BPF_BASELINE_TAG=libbpf-bpf-baseline-${SUFFIX}
+BPF_TIP_TAG=libbpf-bpf-tip-${SUFFIX}
+VIEW_TAG=libbpf-view-${SUFFIX}
+LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
+
+# Squash state of kernel repo at baseline into single commit
+SQUASH_BASE_TAG=libbpf-squash-base-${SUFFIX}
+SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
+SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
+
+echo "WORKDIR: ${WORKDIR}"
+echo "LINUX REPO: ${LINUX_REPO}"
+echo "LIBBPF REPO: ${LIBBPF_REPO}"
+echo "TEMP DIR: ${TMP_DIR}"
+echo "SUFFIX: ${SUFFIX}"
+echo "BASE COMMIT: '$(commit_desc ${BASELINE_COMMIT})'"
+echo "TIP COMMIT: '$(commit_desc ${TIP_COMMIT})'"
+echo "BPF BASE COMMIT: '$(commit_desc ${BPF_BASELINE_COMMIT})'"
+echo "BPF TIP COMMIT: '$(commit_desc ${BPF_TIP_COMMIT})'"
+echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
+echo "BASELINE TAG: ${BASELINE_TAG}"
+echo "TIP TAG: ${TIP_TAG}"
+echo "BPF BASELINE TAG: ${BPF_BASELINE_TAG}"
+echo "BPF TIP TAG: ${BPF_TIP_TAG}"
+echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
+echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
+echo "VIEW TAG: ${VIEW_TAG}"
+echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
+echo "PATCHES: ${TMP_DIR}/patches"
+
+git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
+git branch ${TIP_TAG} ${TIP_COMMIT}
+git branch ${BPF_BASELINE_TAG} ${BPF_BASELINE_COMMIT}
+git branch ${BPF_TIP_TAG} ${BPF_TIP_COMMIT}
+git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
+git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
+
+# Cherry-pick new commits onto squashed baseline commit
+cherry_pick_commits ${BASELINE_TAG} ${TIP_TAG}
+cherry_pick_commits ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
+
+# Move all libbpf files into __libbpf directory.
+FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
+# Make __libbpf a new root directory
+FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --prune-empty -f --subdirectory-filter __libbpf ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
+
+# If there are no new commits with libbpf-related changes, bail out
+COMMIT_CNT=$(git rev-list --count ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG})
+if ((${COMMIT_CNT} <= 0)); then
+ echo "No new changes to apply, we are done!"
+ cleanup
+ exit 2
+fi
+
+# Exclude baseline commit and generate nice cover letter with summary
+git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
+
+# Now is time to re-apply libbpf-related linux patches to libbpf repo
+cd_to ${LIBBPF_REPO}
+git checkout -b ${LIBBPF_SYNC_TAG}
+
+for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
+ if ! git am -3 --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
+ if ! patch -p1 --merge < "${TMP_DIR}/patches/${patch}"; then
+ read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
+ fi
+ git am --continue
+ fi
+done
+
+# Generate bpf_helper_defs.h and commit, if anything changed
+# restore Linux tip to use bpf_doc.py
+cd_to ${LINUX_REPO}
+git checkout ${TIP_TAG}
+# re-generate bpf_helper_defs.h
+cd_to ${LIBBPF_REPO}
+"${LINUX_ABS_DIR}/scripts/bpf_doc.py" --header \
+ --file include/uapi/linux/bpf.h > src/bpf_helper_defs.h
+# if anything changed, commit it
+helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
+if ((${helpers_changes} == 1)); then
+ git add src/bpf_helper_defs.h
+ git commit -m "sync: auto-generate latest BPF helpers
+
+Latest changes to BPF helper definitions.
+" -- src/bpf_helper_defs.h
+fi
+
+# Use generated cover-letter as a template for "sync commit" with
+# baseline and checkpoint commits from kernel repo (and leave summary
+# from cover letter intact, of course)
+echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
+echo ${BPF_TIP_COMMIT} > BPF-CHECKPOINT-COMMIT && \
+git add CHECKPOINT-COMMIT && \
+git add BPF-CHECKPOINT-COMMIT && \
+awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
+sed "s/\*\*\* BLURB HERE \*\*\*/\
+sync: latest libbpf changes from kernel\n\
+\n\
+Syncing latest libbpf commits from kernel repository.\n\
+Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
+Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
+Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
+Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
+git commit --file=-
+
+echo "SUCCESS! ${COMMIT_CNT} commits synced."
+
+echo "Verifying Linux's and Github's libbpf state"
+
+cd_to ${LINUX_REPO}
+git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
+FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
+FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
+git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
+
+cd_to ${LIBBPF_REPO}
+git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
+
+echo "Comparing list of files..."
+diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
+echo "Comparing file contents..."
+CONSISTENT=1
+for F in $(cat ${TMP_DIR}/linux-view.ls); do
+ if ! diff -u "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"; then
+ echo "${LINUX_ABS_DIR}/${F} and ${GITHUB_ABS_DIR}/${F} are different!"
+ CONSISTENT=0
+ fi
+done
+if ((${CONSISTENT} == 1)); then
+ echo "Great! Content is identical!"
+else
+ ignore_inconsistency=n
+ echo "Unfortunately, there are some inconsistencies, please double check."
+ read -p "Does everything look good? [y/N]: " ignore_inconsistency
+ case "${ignore_inconsistency}" in
+ "y" | "Y")
+ echo "Ok, proceeding..."
+ ;;
+ *)
+ echo "Oops, exiting with error..."
+ exit 4
+ esac
+fi
+
+cleanup