Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ CINCLUDES := \
-I. \
-I.. \
$(KERN_INCLUDES) \
-include $(KDIR)/include/linux/kconfig.h
-include $(KDIR)/include/linux/kconfig.h \
-include mock.h
CCINCLUDES := \
-I. \
-I.. \
Expand All @@ -36,11 +37,12 @@ DEFS += -D__STRIP__
endif

WARNS := -Wall -Wundef -Wno-trigraphs -Wno-sign-compare -Wuninitialized \
-Wno-strict-aliasing -Wunused-but-set-variable -Werror
CFLAGS := $(WARNS) -Wstrict-prototypes -MD -no-pie -g $(CINCLUDES) $(DEFS) \
-fsanitize=address -fno-omit-frame-pointer
CCFLAGS := -std=c++11 $(WARNS) -MD -g $(CCINCLUDES) $(DEFS) \
-fsanitize=address -fno-omit-frame-pointer
-Wno-strict-aliasing -Wunused-but-set-variable -Wno-unused-variable \
-Wno-pointer-sign -Werror
CFLAGS := $(WARNS) -Wstrict-prototypes -MD -no-pie -g -fcf-protection \
-fsanitize=address -fno-omit-frame-pointer $(CINCLUDES) $(DEFS)
CCFLAGS := -std=c++11 $(WARNS) -MD -g -fcf-protection \
-fsanitize=address -fno-omit-frame-pointer $(CCINCLUDES) $(DEFS)

TEST_SRCS := unit_homa_incoming.c \
unit_homa_interest.c \
Expand Down Expand Up @@ -126,7 +128,7 @@ rhashtable.o: rhashtable.c
$(CC) -c $(CFLAGS) -O2 -fno-sanitize=address $< -o $@

unit: $(OBJS)
$(CXX) $(CFLAGS) $^ -o $@
$(CXX) $(CFLAGS) $^ -o $@ -lasan

test: unit
./unit
Expand Down
55 changes: 27 additions & 28 deletions test/mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES];
#endif
int __preempt_count;
int cpu_number = 1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
/* Storage for the kernel's per-cpu "hot" fields (task, preempt count,
* cpu number, etc.); real per-cpu semantics don't matter for unit tests,
* which are single-threaded, but the symbol must exist to satisfy the
* linker for inline kernel functions that reference it directly.
*/
struct pcpu_hot pcpu_hot;
#endif
char sock_flow_table[RPS_SOCK_FLOW_TABLE_SIZE(1024)];
struct net_hotdata net_hotdata = {
.rps_cpu_mask = 0x1f,
Expand Down Expand Up @@ -1129,27 +1137,17 @@ int kthread_stop(struct task_struct *k)
return 0;
}

#ifdef CONFIG_DEBUG_LIST
bool __list_add_valid(struct list_head *new, struct list_head *prev,
struct list_head *next)
{
return true;
}
#endif

/* __list_add_valid/__list_del_entry_valid are now provided by the
* kernel's own linux/list.h (unconditionally, regardless of
* CONFIG_DEBUG_LIST) - only the _or_report reporting hooks still need
* a definition here.
*/
bool __list_add_valid_or_report(struct list_head *new, struct list_head *prev,
struct list_head *next)
{
return true;
}

#ifdef CONFIG_DEBUG_LIST
bool __list_del_entry_valid(struct list_head *entry)
{
return true;
}
#endif

bool __list_del_entry_valid_or_report(struct list_head *entry)
{
return true;
Expand Down Expand Up @@ -1183,7 +1181,7 @@ void lock_sock_nested(struct sock *sk, int subclass)
sk->sk_lock.owned = 1;
}

ssize_t __modver_version_show(const struct module_attribute *a,
ssize_t __modver_version_show(struct module_attribute *a,
struct module_kobject *b, char *c)
{
return 0;
Expand Down Expand Up @@ -1226,20 +1224,21 @@ int netif_receive_skb(struct sk_buff *skb)
void __netif_schedule(struct Qdisc *q)
{}

void preempt_count_add(int val)
void mock_preempt_count_add(int val)
{
int i;

for (i = 0; i < val; i++)
preempt_disable();
/* Just adjust the mock backing-store counter directly; don't
* route through mock_preempt_disable(), since preempt_count_add()
* is used by callers (e.g. local_bh_disable()) that don't pair up
* 1-for-1 with preempt_disable()/preempt_enable(), so looping
* through the disable/enable leak-detector here would produce
* false "preempt_disables still active" failures.
*/
__preempt_count += val;
}

void preempt_count_sub(int val)
void mock_preempt_count_sub(int val)
{
int i;

for (i = 0; i < val; i++)
preempt_enable();
__preempt_count -= val;
}

long prepare_to_wait_event(struct wait_queue_head *wq_head,
Expand Down Expand Up @@ -1452,9 +1451,9 @@ bool rcuref_get_slowpath(rcuref_t *ref)
return true;
}

bool rcuref_put_slowpath(rcuref_t *ref, unsigned int cnt)
bool rcuref_put_slowpath(rcuref_t *ref)
{
return cnt == RCUREF_NOREF;
return true;
}

void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t) {}
Expand Down
97 changes: 94 additions & 3 deletions test/mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,89 @@
#ifndef _HOMA_MOCK_H
#define _HOMA_MOCK_H

/* This file must be the very first #include for every compiled .c file
* (forced via -include mock.h in the test Makefile, before homa_impl.h and
* before any real kernel header). <linux/mm.h> -> <linux/bit_spinlock.h>
* and <linux/lockdep.h> -> <linux/smp.h>, dragged in transitively by many
* kernel headers homa_impl.h includes (skbuff.h, kthread.h, completion.h,
* sched/signal.h, proc_fs.h, etc.), use preempt_disable()/preempt_enable()/
* smp_processor_id()/raw_smp_processor_id()/WARN_ON_ONCE() in inline
* functions; those inline functions bake in whichever macro definition is
* active when the header is first parsed. Getting the mocked versions
* active before any of that runs requires mock.h itself to be included
* first, standalone. homa_impl.h's own later #include "mock.h" is then a
* no-op (include guard), but these overrides are already in effect.
*/
#include <linux/bug.h>

#undef WARN
#define WARN(...)

#undef WARN_ON
#define WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
unlikely(__ret_warn_on); \
})

#undef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) WARN_ON(condition)

#undef WARN_ONCE
#define WARN_ONCE(cond, ...) ({ bool __c = (cond); (void)__c; __c; })

/* Pulling in the real <linux/preempt.h>/<linux/smp.h> here first (before
* the undef/define below) sets their include guards so later transitive
* re-inclusion is a no-op and can't clobber these overrides. This must
* come after the WARN overrides above, since preempt.h drags in
* <linux/thread_info.h> (via linkage.h), whose inline functions use
* WARN_ON_ONCE() and must see the mocked (no-op) version.
*/
#include <linux/preempt.h>
#include <linux/smp.h>

/* Forward declarations needed because the overrides below are used by
* headers included further down in this file, before mock.c's own
* declarations (later in this file) would otherwise be visible.
*/
void mock_preempt_disable(void);
void mock_preempt_enable(void);
int mock_processor_id(void);

#undef preempt_disable
#define preempt_disable() mock_preempt_disable()

#undef preempt_enable
#define preempt_enable() mock_preempt_enable()

#undef smp_processor_id
#define smp_processor_id() mock_processor_id()

#undef raw_smp_processor_id
#define raw_smp_processor_id() mock_processor_id()

/* <net/tcp.h> (tcp_v4_check/tcp_v6_check), <linux/filter.h> (this_cpu_ptr,
* via <linux/bpf.h>), <net/icmp.h> (icmp_send), <net/ip6_route.h>
* (rt6_get_cookie, via <net/ip6_fib.h>) and <net/netns/generic.h>
* (net_generic) all declare real inline functions/objects whose names this
* file redirects below via object-style macros; those macros corrupt the
* real declarations if the real headers are parsed afterward (their
* include guards would otherwise make a later re-inclusion elsewhere a
* silent no-op with the corrupted macro baked in). Pulling them in here
* first, before any of the redirects below, avoids that. homa.h is
* included here too so the HOMA_BPAGE_SIZE/HOMA_MIN_DEFAULT_PORT/etc.
* overrides below apply after the real values are already defined, instead
* of being silently clobbered by a later #include of homa.h from
* homa_impl.h.
*/
#include <net/tcp.h>
#include <net/ip6_checksum.h>
#include <linux/filter.h>
#include <net/icmp.h>
#include <net/ip6_route.h>
#include <net/netns/generic.h>
#include "homa.h"
#include "homa_wire.h"

#include <linux/ethtool.h>

/* Replace various Linux variables and functions with mocked ones. */
Expand Down Expand Up @@ -104,6 +187,12 @@
#undef preempt_enable
#define preempt_enable() mock_preempt_enable()

#undef preempt_count_add
#define preempt_count_add(val) mock_preempt_count_add(val)

#undef preempt_count_sub
#define preempt_count_sub(val) mock_preempt_count_sub(val)

#define put_page mock_put_page

#define rcu_read_lock mock_rcu_read_lock
Expand All @@ -119,6 +208,8 @@
#undef register_net_sysctl
#define register_net_sysctl mock_register_net_sysctl

#define rt6_get_cookie(...) 999

#define signal_pending(...) mock_signal_pending

/* Must redefine skb_frag_foreach_page because page pointers are different
Expand All @@ -135,9 +226,6 @@
copied += p_len, p++, p_off = 0, \
p_len = f_len - copied) \

#undef smp_processor_id
#define smp_processor_id() mock_processor_id()

#define sock_hold(sock) mock_sock_hold(sock)

#define sock_put(sock) mock_sock_put(sock)
Expand Down Expand Up @@ -182,6 +270,7 @@ extern int mock_copy_to_frags_errors;
extern int mock_copy_to_user_dont_copy;
extern int mock_copy_to_user_errors;
extern int mock_cpu_idle;
extern int cpu_number;
extern struct net_device
mock_devices[];
extern enum skb_drop_reason
Expand Down Expand Up @@ -275,6 +364,8 @@ int mock_page_refs(struct page *page);
int mock_page_to_nid(struct page *page);
void mock_preempt_disable(void);
void mock_preempt_enable(void);
void mock_preempt_count_add(int val);
void mock_preempt_count_sub(int val);
int mock_processor_id(void);
void mock_put_page(struct page *page);
struct sk_buff *
Expand Down