diff options
Diffstat (limited to 'tools')
63 files changed, 6922 insertions, 140 deletions
diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h index 4602464ebdfb..a4217c1a5d01 100644 --- a/tools/arch/arm/include/uapi/asm/kvm.h +++ b/tools/arch/arm/include/uapi/asm/kvm.h @@ -214,6 +214,18 @@ struct kvm_vcpu_events { #define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ KVM_REG_ARM_FW | ((r) & 0xffff)) #define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1) + /* Higher values mean better protection. */ +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2) + /* Higher values mean better protection. */ +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4) /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h index d819a3e8b552..9a507716ae2f 100644 --- a/tools/arch/arm64/include/uapi/asm/kvm.h +++ b/tools/arch/arm64/include/uapi/asm/kvm.h @@ -229,6 +229,16 @@ struct kvm_vcpu_events { #define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ KVM_REG_ARM_FW | ((r) & 0xffff)) #define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2) +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3 +#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4) /* SVE registers */ #define KVM_REG_ARM64_SVE (0x15 << KVM_REG_ARM_COPROC_SHIFT) diff --git a/tools/arch/powerpc/include/uapi/asm/mman.h b/tools/arch/powerpc/include/uapi/asm/mman.h index f33105bc5ca6..8601d824a9c6 100644 --- a/tools/arch/powerpc/include/uapi/asm/mman.h +++ b/tools/arch/powerpc/include/uapi/asm/mman.h @@ -4,12 +4,8 @@ #define MAP_DENYWRITE 0x0800 #define MAP_EXECUTABLE 0x1000 #define MAP_GROWSDOWN 0x0100 -#define MAP_HUGETLB 0x40000 #define MAP_LOCKED 0x80 -#define MAP_NONBLOCK 0x10000 #define MAP_NORESERVE 0x40 -#define MAP_POPULATE 0x8000 -#define MAP_STACK 0x20000 #include <uapi/asm-generic/mman-common.h> /* MAP_32BIT is undefined on powerpc, fix it for perf */ #define MAP_32BIT 0 diff --git a/tools/arch/sparc/include/uapi/asm/mman.h b/tools/arch/sparc/include/uapi/asm/mman.h index 38920eed8cbf..7b94dccc843d 100644 --- a/tools/arch/sparc/include/uapi/asm/mman.h +++ b/tools/arch/sparc/include/uapi/asm/mman.h @@ -4,12 +4,8 @@ #define MAP_DENYWRITE 0x0800 #define MAP_EXECUTABLE 0x1000 #define MAP_GROWSDOWN 0x0200 -#define MAP_HUGETLB 0x40000 #define MAP_LOCKED 0x100 -#define MAP_NONBLOCK 0x10000 #define MAP_NORESERVE 0x40 -#define MAP_POPULATE 0x8000 -#define MAP_STACK 0x20000 #include <uapi/asm-generic/mman-common.h> /* MAP_32BIT is undefined on sparc, fix it for perf */ #define MAP_32BIT 0 diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index d6ab5b4d15e5..503d3f42da16 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -378,10 +378,11 @@ struct kvm_sync_regs { struct kvm_vcpu_events events; }; -#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) -#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) -#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) -#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) +#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) +#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) +#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) +#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) +#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 /* unused */ @@ -432,4 +433,17 @@ struct kvm_nested_state { } data; }; +/* for KVM_CAP_PMU_EVENT_FILTER */ +struct kvm_pmu_event_filter { + __u32 action; + __u32 nevents; + __u32 fixed_counter_bitmap; + __u32 flags; + __u32 pad[4]; + __u64 events[0]; +}; + +#define KVM_PMU_EVENT_ALLOW 0 +#define KVM_PMU_EVENT_DENY 1 + #endif /* _ASM_X86_KVM_H */ diff --git a/tools/arch/x86/include/uapi/asm/vmx.h b/tools/arch/x86/include/uapi/asm/vmx.h index d213ec5c3766..f0b0c90dd398 100644 --- a/tools/arch/x86/include/uapi/asm/vmx.h +++ b/tools/arch/x86/include/uapi/asm/vmx.h @@ -146,7 +146,6 @@ #define VMX_ABORT_SAVE_GUEST_MSR_FAIL 1 #define VMX_ABORT_LOAD_HOST_PDPTE_FAIL 2 -#define VMX_ABORT_VMCS_CORRUPTED 3 #define VMX_ABORT_LOAD_HOST_MSR_FAIL 4 #endif /* _UAPIVMX_H */ diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index abd238d0f7a4..63b1f506ea67 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -19,15 +19,18 @@ #define MAP_TYPE 0x0f /* Mask for type of mapping */ #define MAP_FIXED 0x10 /* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20 /* don't use a file */ -#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED -# define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */ -#else -# define MAP_UNINITIALIZED 0x0 /* Don't support this flag */ -#endif -/* 0x0100 - 0x80000 flags are defined in asm-generic/mman.h */ +/* 0x0100 - 0x4000 flags are defined in asm-generic/mman.h */ +#define MAP_POPULATE 0x008000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x010000 /* do not block on IO */ +#define MAP_STACK 0x020000 /* give out an address that is best suited for process/thread stacks */ +#define MAP_HUGETLB 0x040000 /* create a huge page mapping */ +#define MAP_SYNC 0x080000 /* perform synchronous page faults for the mapping */ #define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED which doesn't unmap underlying mapping */ +#define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be + * uninitialized */ + /* * Flags for mlock */ diff --git a/tools/include/uapi/asm-generic/mman.h b/tools/include/uapi/asm-generic/mman.h index 36c197fc44a0..406f7718f9ad 100644 --- a/tools/include/uapi/asm-generic/mman.h +++ b/tools/include/uapi/asm-generic/mman.h @@ -9,13 +9,11 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ -#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ -#define MAP_NONBLOCK 0x10000 /* do not block on IO */ -#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ -#define MAP_HUGETLB 0x40000 /* create a huge page mapping */ -#define MAP_SYNC 0x80000 /* perform synchronous page faults for the mapping */ -/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */ +/* + * Bits [26:31] are reserved, see asm-generic/hugetlb_encode.h + * for MAP_HUGETLB usage + */ #define MCL_CURRENT 1 /* lock all current mappings */ #define MCL_FUTURE 2 /* lock all future mappings */ diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index a87904daf103..1be0e798e362 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -844,9 +844,15 @@ __SYSCALL(__NR_fsconfig, sys_fsconfig) __SYSCALL(__NR_fsmount, sys_fsmount) #define __NR_fspick 433 __SYSCALL(__NR_fspick, sys_fspick) +#define __NR_pidfd_open 434 +__SYSCALL(__NR_pidfd_open, sys_pidfd_open) +#ifdef __ARCH_WANT_SYS_CLONE3 +#define __NR_clone3 435 +__SYSCALL(__NR_clone3, sys_clone3) +#endif #undef __NR_syscalls -#define __NR_syscalls 434 +#define __NR_syscalls 436 /* * 32 bit systems traditionally used different diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 661d73f9a919..8a5b2f8f8eb9 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -50,6 +50,7 @@ typedef unsigned int drm_handle_t; #else /* One of the BSDs */ +#include <stdint.h> #include <sys/ioccom.h> #include <sys/types.h> typedef int8_t __s8; diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 3a73f5316766..328d05e77d9f 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -136,6 +136,8 @@ enum drm_i915_gem_engine_class { struct i915_engine_class_instance { __u16 engine_class; /* see enum drm_i915_gem_engine_class */ __u16 engine_instance; +#define I915_ENGINE_CLASS_INVALID_NONE -1 +#define I915_ENGINE_CLASS_INVALID_VIRTUAL -2 }; /** @@ -355,6 +357,8 @@ typedef struct _drm_i915_sarea { #define DRM_I915_PERF_ADD_CONFIG 0x37 #define DRM_I915_PERF_REMOVE_CONFIG 0x38 #define DRM_I915_QUERY 0x39 +#define DRM_I915_GEM_VM_CREATE 0x3a +#define DRM_I915_GEM_VM_DESTROY 0x3b /* Must be kept compact -- no holes */ #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) @@ -415,6 +419,8 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) #define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) +#define DRM_IOCTL_I915_GEM_VM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control) +#define DRM_IOCTL_I915_GEM_VM_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -598,6 +604,12 @@ typedef struct drm_i915_irq_wait { */ #define I915_PARAM_MMAP_GTT_COHERENT 52 +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports coordination of parallel + * execution through use of explicit fence support. + * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT. + */ +#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53 /* Must be kept compact -- no holes and well documented */ typedef struct drm_i915_getparam { @@ -1120,7 +1132,16 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_FENCE_ARRAY (1<<19) -#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1)) +/* + * Setting I915_EXEC_FENCE_SUBMIT implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_SUBMIT (1 << 20) + +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1)) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ @@ -1464,8 +1485,9 @@ struct drm_i915_gem_context_create_ext { __u32 ctx_id; /* output: id of new context*/ __u32 flags; #define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS (1u << 0) +#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE (1u << 1) #define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \ - (-(I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS << 1)) + (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1)) __u64 extensions; }; @@ -1507,6 +1529,41 @@ struct drm_i915_gem_context_param { * On creation, all new contexts are marked as recoverable. */ #define I915_CONTEXT_PARAM_RECOVERABLE 0x8 + + /* + * The id of the associated virtual memory address space (ppGTT) of + * this context. Can be retrieved and passed to another context + * (on the same fd) for both to use the same ppGTT and so share + * address layouts, and avoid reloading the page tables on context + * switches between themselves. + * + * See DRM_I915_GEM_VM_CREATE and DRM_I915_GEM_VM_DESTROY. + */ +#define I915_CONTEXT_PARAM_VM 0x9 + +/* + * I915_CONTEXT_PARAM_ENGINES: + * + * Bind this context to operate on this subset of available engines. Henceforth, + * the I915_EXEC_RING selector for DRM_IOCTL_I915_GEM_EXECBUFFER2 operates as + * an index into this array of engines; I915_EXEC_DEFAULT selecting engine[0] + * and upwards. Slots 0...N are filled in using the specified (class, instance). + * Use + * engine_class: I915_ENGINE_CLASS_INVALID, + * engine_instance: I915_ENGINE_CLASS_INVALID_NONE + * to specify a gap in the array that can be filled in later, e.g. by a + * virtual engine used for load balancing. + * + * Setting the number of engines bound to the context to 0, by passing a zero + * sized argument, will revert back to default settings. + * + * See struct i915_context_param_engines. + * + * Extensions: + * i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE) + * i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND) + */ +#define I915_CONTEXT_PARAM_ENGINES 0xa /* Must be kept compact -- no holes and well documented */ __u64 value; @@ -1540,9 +1597,10 @@ struct drm_i915_gem_context_param_sseu { struct i915_engine_class_instance engine; /* - * Unused for now. Must be cleared to zero. + * Unknown flags must be cleared to zero. */ __u32 flags; +#define I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX (1u << 0) /* * Mask of slices to enable for the context. Valid values are a subset @@ -1570,12 +1628,115 @@ struct drm_i915_gem_context_param_sseu { __u32 rsvd; }; +/* + * i915_context_engines_load_balance: + * + * Enable load balancing across this set of engines. + * + * Into the I915_EXEC_DEFAULT slot [0], a virtual engine is created that when + * used will proxy the execbuffer request onto one of the set of engines + * in such a way as to distribute the load evenly across the set. + * + * The set of engines must be compatible (e.g. the same HW class) as they + * will share the same logical GPU context and ring. + * + * To intermix rendering with the virtual engine and direct rendering onto + * the backing engines (bypassing the load balancing proxy), the context must + * be defined to use a single timeline for all engines. + */ +struct i915_context_engines_load_balance { + struct i915_user_extension base; + + __u16 engine_index; + __u16 num_siblings; + __u32 flags; /* all undefined flags must be zero */ + + __u64 mbz64; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 num_siblings; \ + __u32 flags; \ + __u64 mbz64; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/* + * i915_context_engines_bond: + * + * Constructed bonded pairs for execution within a virtual engine. + * + * All engines are equal, but some are more equal than others. Given + * the distribution of resources in the HW, it may be preferable to run + * a request on a given subset of engines in parallel to a request on a + * specific engine. We enable this selection of engines within a virtual + * engine by specifying bonding pairs, for any given master engine we will + * only execute on one of the corresponding siblings within the virtual engine. + * + * To execute a request in parallel on the master engine and a sibling requires + * coordination with a I915_EXEC_FENCE_SUBMIT. + */ +struct i915_context_engines_bond { + struct i915_user_extension base; + + struct i915_engine_class_instance master; + + __u16 virtual_index; /* index of virtual engine in ctx->engines[] */ + __u16 num_bonds; + + __u64 flags; /* all undefined flags must be zero */ + __u64 mbz64[4]; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \ + struct i915_user_extension base; \ + struct i915_engine_class_instance master; \ + __u16 virtual_index; \ + __u16 num_bonds; \ + __u64 flags; \ + __u64 mbz64[4]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +struct i915_context_param_engines { + __u64 extensions; /* linked chain of extension blocks, 0 terminates */ +#define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ +#define I915_CONTEXT_ENGINES_EXT_BOND 1 /* see i915_context_engines_bond */ + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_PARAM_ENGINES(name__, N__) struct { \ + __u64 extensions; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + struct drm_i915_gem_context_create_ext_setparam { #define I915_CONTEXT_CREATE_EXT_SETPARAM 0 struct i915_user_extension base; struct drm_i915_gem_context_param param; }; +struct drm_i915_gem_context_create_ext_clone { +#define I915_CONTEXT_CREATE_EXT_CLONE 1 + struct i915_user_extension base; + __u32 clone_id; + __u32 flags; +#define I915_CONTEXT_CLONE_ENGINES (1u << 0) +#define I915_CONTEXT_CLONE_FLAGS (1u << 1) +#define I915_CONTEXT_CLONE_SCHEDATTR (1u << 2) +#define I915_CONTEXT_CLONE_SSEU (1u << 3) +#define I915_CONTEXT_CLONE_TIMELINE (1u << 4) +#define I915_CONTEXT_CLONE_VM (1u << 5) +#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1) + __u64 rsvd; +}; + struct drm_i915_gem_context_destroy { __u32 ctx_id; __u32 pad; @@ -1821,6 +1982,7 @@ struct drm_i915_perf_oa_config { struct drm_i915_query_item { __u64 query_id; #define DRM_I915_QUERY_TOPOLOGY_INFO 1 +#define DRM_I915_QUERY_ENGINE_INFO 2 /* Must be kept compact -- no holes and well documented */ /* @@ -1919,6 +2081,47 @@ struct drm_i915_query_topology_info { __u8 data[]; }; +/** + * struct drm_i915_engine_info + * + * Describes one engine and it's capabilities as known to the driver. + */ +struct drm_i915_engine_info { + /** Engine class and instance. */ + struct i915_engine_class_instance engine; + + /** Reserved field. */ + __u32 rsvd0; + + /** Engine flags. */ + __u64 flags; + + /** Capabilities of this engine. */ + __u64 capabilities; +#define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) +#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) + + /** Reserved fields. */ + __u64 rsvd1[4]; +}; + +/** + * struct drm_i915_query_engine_info + * + * Engine info query enumerates all engines known to the driver by filling in + * an array of struct drm_i915_engine_info structures. + */ +struct drm_i915_query_engine_info { + /** Number of struct drm_i915_engine_info structs following. */ + __u32 num_engines; + + /** MBZ */ + __u32 rsvd[3]; + + /** Marker for drm_i915_engine_info structures. */ + struct drm_i915_engine_info engines[]; +}; + #if defined(__cplusplus) } #endif diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 7d113a9602f0..4a8c02cafa9a 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -695,6 +695,7 @@ enum { IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */ IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */ IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */ + IFLA_VF_BROADCAST, /* VF broadcast */ __IFLA_VF_MAX, }; @@ -705,6 +706,10 @@ struct ifla_vf_mac { __u8 mac[32]; /* MAX_ADDR_LEN */ }; +struct ifla_vf_broadcast { + __u8 broadcast[32]; +}; + struct ifla_vf_vlan { __u32 vf; __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index c2152f3dd02d..5e3f12d5359e 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -116,7 +116,7 @@ struct kvm_irq_level { * ACPI gsi notion of irq. * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. - * For ARM: See Documentation/virtual/kvm/api.txt + * For ARM: See Documentation/virt/kvm/api.txt */ union { __u32 irq; @@ -995,6 +995,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_SVE 170 #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171 #define KVM_CAP_ARM_PTRAUTH_GENERIC 172 +#define KVM_CAP_PMU_EVENT_FILTER 173 #ifdef KVM_CAP_IRQ_ROUTING @@ -1085,7 +1086,7 @@ struct kvm_xen_hvm_config { * * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies * the irqfd to operate in resampling mode for level triggered interrupt - * emulation. See Documentation/virtual/kvm/api.txt. + * emulation. See Documentation/virt/kvm/api.txt. */ #define KVM_IRQFD_FLAG_RESAMPLE (1 << 1) @@ -1329,6 +1330,8 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_RMMU_INFO _IOW(KVMIO, 0xb0, struct kvm_ppc_rmmu_info) /* Available with KVM_CAP_PPC_GET_CPU_CHAR */ #define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char) +/* Available with KVM_CAP_PMU_EVENT_FILTER */ +#define KVM_SET_PMU_EVENT_FILTER _IOW(KVMIO, 0xb2, struct kvm_pmu_event_filter) /* ioctl for vm fd */ #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) diff --git a/tools/include/uapi/linux/sched.h b/tools/include/uapi/linux/sched.h index ed4ee170bee2..b3105ac1381a 100644 --- a/tools/include/uapi/linux/sched.h +++ b/tools/include/uapi/linux/sched.h @@ -2,6 +2,8 @@ #ifndef _UAPI_LINUX_SCHED_H #define _UAPI_LINUX_SCHED_H +#include <linux/types.h> + /* * cloning flags: */ @@ -32,6 +34,20 @@ #define CLONE_IO 0x80000000 /* Clone io context */ /* + * Arguments for the clone3 syscall + */ +struct clone_args { + __aligned_u64 flags; + __aligned_u64 pidfd; + __aligned_u64 child_tid; + __aligned_u64 parent_tid; + __aligned_u64 exit_signal; + __aligned_u64 stack; + __aligned_u64 stack_size; + __aligned_u64 tls; +}; + +/* * Scheduling policies */ #define SCHED_NORMAL 0 @@ -51,9 +67,21 @@ #define SCHED_FLAG_RESET_ON_FORK 0x01 #define SCHED_FLAG_RECLAIM 0x02 #define SCHED_FLAG_DL_OVERRUN 0x04 +#define SCHED_FLAG_KEEP_POLICY 0x08 +#define SCHED_FLAG_KEEP_PARAMS 0x10 +#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20 +#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40 + +#define SCHED_FLAG_KEEP_ALL (SCHED_FLAG_KEEP_POLICY | \ + SCHED_FLAG_KEEP_PARAMS) + +#define SCHED_FLAG_UTIL_CLAMP (SCHED_FLAG_UTIL_CLAMP_MIN | \ + SCHED_FLAG_UTIL_CLAMP_MAX) #define SCHED_FLAG_ALL (SCHED_FLAG_RESET_ON_FORK | \ SCHED_FLAG_RECLAIM | \ - SCHED_FLAG_DL_OVERRUN) + SCHED_FLAG_DL_OVERRUN | \ + SCHED_FLAG_KEEP_ALL | \ + SCHED_FLAG_UTIL_CLAMP) #endif /* _UAPI_LINUX_SCHED_H */ diff --git a/tools/include/uapi/linux/usbdevice_fs.h b/tools/include/uapi/linux/usbdevice_fs.h index 964e87217be4..78efe870c2b7 100644 --- a/tools/include/uapi/linux/usbdevice_fs.h +++ b/tools/include/uapi/linux/usbdevice_fs.h @@ -76,6 +76,26 @@ struct usbdevfs_connectinfo { unsigned char slow; }; +struct usbdevfs_conninfo_ex { + __u32 size; /* Size of the structure from the kernel's */ + /* point of view. Can be used by userspace */ + /* to determine how much data can be */ + /* used/trusted. */ + __u32 busnum; /* USB bus number, as enumerated by the */ + /* kernel, the device is connected to. */ + __u32 devnum; /* Device address on the bus. */ + __u32 speed; /* USB_SPEED_* constants from ch9.h */ + __u8 num_ports; /* Number of ports the device is connected */ + /* to on the way to the root hub. It may */ + /* be bigger than size of 'ports' array so */ + /* userspace can detect overflows. */ + __u8 ports[7]; /* List of ports on the way from the root */ + /* hub to the device. Current limit in */ + /* USB specification is 7 tiers (root hub, */ + /* 5 intermediate hubs, device), which */ + /* gives at most 6 port entries. */ +}; + #define USBDEVFS_URB_SHORT_NOT_OK 0x01 #define USBDEVFS_URB_ISO_ASAP 0x02 #define USBDEVFS_URB_BULK_CONTINUATION 0x04 @@ -137,6 +157,7 @@ struct usbdevfs_hub_portinfo { #define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10 #define USBDEVFS_CAP_MMAP 0x20 #define USBDEVFS_CAP_DROP_PRIVILEGES 0x40 +#define USBDEVFS_CAP_CONNINFO_EX 0x80 /* USBDEVFS_DISCONNECT_CLAIM flags & struct */ @@ -197,5 +218,10 @@ struct usbdevfs_streams { #define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams) #define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32) #define USBDEVFS_GET_SPEED _IO('U', 31) +/* + * Returns struct usbdevfs_conninfo_ex; length is variable to allow + * extending size of the data returned. + */ +#define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) #endif /* _UAPI_LINUX_USBDEVICE_FS_H */ diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index aacb7608f02d..1aa189a9112a 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2018 Facebook */ +#include <endian.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -370,9 +371,9 @@ done: static bool btf_check_endianness(const GElf_Ehdr *ehdr) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if __BYTE_ORDER == __LITTLE_ENDIAN return ehdr->e_ident[EI_DATA] == ELFDATA2LSB; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#elif __BYTE_ORDER == __BIG_ENDIAN return ehdr->e_ident[EI_DATA] == ELFDATA2MSB; #else # error "Unrecognized __BYTE_ORDER__" diff --git a/tools/lib/bpf/hashmap.h b/tools/lib/bpf/hashmap.h index 03748a742146..bae8879cdf58 100644 --- a/tools/lib/bpf/hashmap.h +++ b/tools/lib/bpf/hashmap.h @@ -10,6 +10,11 @@ #include <stdbool.h> #include <stddef.h> +#ifdef __GLIBC__ +#include <bits/wordsize.h> +#else +#include <bits/reg.h> +#endif #include "libbpf_internal.h" static inline size_t hash_bits(size_t h, int bits) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 8462dab02812..2233f919dd88 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -20,6 +20,7 @@ #include <inttypes.h> #include <string.h> #include <unistd.h> +#include <endian.h> #include <fcntl.h> #include <errno.h> #include <asm/unistd.h> @@ -617,10 +618,10 @@ errout: static int bpf_object__check_endianness(struct bpf_object *obj) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if __BYTE_ORDER == __LITTLE_ENDIAN if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2LSB) return 0; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#elif __BYTE_ORDER == __BIG_ENDIAN if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2MSB) return 0; #else @@ -1378,8 +1379,13 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj) if (!has_datasec && btf_is_var(t)) { /* replace VAR with INT */ t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0); - t->size = sizeof(int); - *(int *)(t + 1) = BTF_INT_ENC(0, 0, 32); + /* + * using size = 1 is the safest choice, 4 will be too + * big and cause kernel BTF validation failure if + * original variable took less than 4 bytes + */ + t->size = 1; + *(int *)(t + 1) = BTF_INT_ENC(0, 0, 8); } else if (!has_datasec && btf_is_datasec(t)) { /* replace DATASEC with STRUCT */ const struct btf_var_secinfo *v = btf_var_secinfos(t); @@ -1501,6 +1507,12 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) BTF_ELF_SEC, err); btf__free(obj->btf); obj->btf = NULL; + /* btf_ext can't exist without btf, so free it as well */ + if (obj->btf_ext) { + btf_ext__free(obj->btf_ext); + obj->btf_ext = NULL; + } + if (bpf_object__is_btf_mandatory(obj)) return err; } @@ -5410,13 +5422,13 @@ struct perf_buffer *perf_buffer__new(int map_fd, size_t page_cnt, const struct perf_buffer_opts *opts) { struct perf_buffer_params p = {}; - struct perf_event_attr attr = { - .config = PERF_COUNT_SW_BPF_OUTPUT, - .type = PERF_TYPE_SOFTWARE, - .sample_type = PERF_SAMPLE_RAW, - .sample_period = 1, - .wakeup_events = 1, - }; + struct perf_event_attr attr = { 0, }; + + attr.config = PERF_COUNT_SW_BPF_OUTPUT, + attr.type = PERF_TYPE_SOFTWARE; + attr.sample_type = PERF_SAMPLE_RAW; + attr.sample_period = 1; + attr.wakeup_events = 1; p.attr = &attr; p.sample_cb = opts ? opts->sample_cb : NULL; diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index 5007b5d4fd2c..680e63066cf3 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -317,17 +317,16 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk) static int xsk_get_max_queues(struct xsk_socket *xsk) { - struct ethtool_channels channels; - struct ifreq ifr; + struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS }; + struct ifreq ifr = {}; int fd, err, ret; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return -errno; - channels.cmd = ETHTOOL_GCHANNELS; ifr.ifr_data = (void *)&channels; - strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1); + memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1); ifr.ifr_name[IFNAMSIZ - 1] = '\0'; err = ioctl(fd, SIOCETHTOOL, &ifr); if (err && errno != EOPNOTSUPP) { @@ -335,7 +334,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk) goto out; } - if (channels.max_combined == 0 || errno == EOPNOTSUPP) + if (err || channels.max_combined == 0) /* If the device says it has no channels, then all traffic * is sent to a single stream, so max queues = 1. */ @@ -517,7 +516,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, err = -errno; goto out_socket; } - strncpy(xsk->ifname, ifname, IFNAMSIZ - 1); + memcpy(xsk->ifname, ifname, IFNAMSIZ - 1); xsk->ifname[IFNAMSIZ - 1] = '\0'; err = xsk_set_xdp_socket_config(&xsk->config, usr_config); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 5f26620f13f5..176f2f084060 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1946,6 +1946,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, struct alternative *alt; struct instruction *insn, *next_insn; struct section *sec; + u8 visited; int ret; insn = first; @@ -1972,12 +1973,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, return 1; } + visited = 1 << state.uaccess; if (insn->visited) { if (!insn->hint && !insn_state_match(insn, &state)) return 1; - /* If we were here with AC=0, but now have AC=1, go again */ - if (insn->state.uaccess || !state.uaccess) + if (insn->visited & visited) return 0; } @@ -2024,7 +2025,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, } else insn->state = state; - insn->visited = true; + insn->visited |= visited; if (!insn->ignore_alts) { bool skip_orig = false; diff --git a/tools/objtool/check.h b/tools/objtool/check.h index b881fafcf55d..6d875ca6fce0 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -33,8 +33,9 @@ struct instruction { unsigned int len; enum insn_type type; unsigned long immediate; - bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; + bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts; bool retpoline_safe; + u8 visited; struct symbol *call_dest; struct instruction *jump_dest; struct instruction *first_jump_src; diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index d4e2e18a5881..caaab28f8400 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -228,11 +228,11 @@ OPTIONS With the metric option perf script can compute metrics for sampling periods, similar to perf stat. This requires - specifying a group with multiple metrics with the :S option + specifying a group with multiple events defining metrics with the :S option for perf record. perf will sample on the first event, and - compute metrics for all the events in the group. Please note + print computed metrics for all the events in the group. Please note that the metric computed is averaged over the whole sampling - period, not just for the sample point. + period (since the last sample), not just for the sample point. For sample events it's possible to display misc field with -F +misc option, following letters are displayed for each bit: @@ -384,7 +384,7 @@ include::itrace.txt[] perf script --time 0%-10%,30%-40% --max-blocks:: - Set the maximum number of program blocks to print with brstackasm for + Set the maximum number of program blocks to print with brstackinsn for each sample. --reltime:: diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index 5f54feb19977..d030c87ed9f5 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -126,7 +126,7 @@ vendor,family,model,stepping. For example: GenuineIntel,6,69,1 HEADER_TOTAL_MEM = 10, -An uint64_t with the total memory in bytes. +An uint64_t with the total memory in kilobytes. HEADER_CMDLINE = 11, diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index b4e6f9e6204a..c29976eca4a8 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -355,6 +355,8 @@ 431 common fsconfig __x64_sys_fsconfig 432 common fsmount __x64_sys_fsmount 433 common fspick __x64_sys_fspick +434 common pidfd_open __x64_sys_pidfd_open +435 common clone3 __x64_sys_clone3/ptregs # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 6418782951a4..3d0ffd41fb55 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -698,6 +698,16 @@ __cmd_probe(int argc, const char **argv) ret = perf_add_probe_events(params.events, params.nevents); if (ret < 0) { + + /* + * When perf_add_probe_events() fails it calls + * cleanup_perf_probe_events(pevs, npevs), i.e. + * cleanup_perf_probe_events(params.events, params.nevents), which + * will call clear_perf_probe_event(), so set nevents to zero + * to avoid cleanup_params() to call clear_perf_probe_event() again + * on the same pevs. + */ + params.nevents = 0; pr_err_with_code(" Error: Failed to add events.", ret); return ret; } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8f24865596af..0140ddb8dd0b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1059,7 +1059,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); if (ip == end) { - printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, + printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, ++insn, fp, &total_cycles); if (PRINT_FIELD(SRCCODE)) printed += print_srccode(thread, x.cpumode, ip); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index b55a534b4de0..352cf39d7c2f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -607,7 +607,13 @@ try_again: * group leaders. */ read_counters(&(struct timespec) { .tv_nsec = t1-t0 }); - perf_evlist__close(evsel_list); + + /* + * We need to keep evsel_list alive, because it's processed + * later the evsel_list will be closed after. + */ + if (!STAT_RECORD) + perf_evlist__close(evsel_list); return WEXITSTATUS(status); } @@ -1997,6 +2003,7 @@ int cmd_stat(int argc, const char **argv) perf_session__write_header(perf_stat.session, evsel_list, fd, true); } + perf_evlist__close(evsel_list); perf_session__delete(perf_stat.session); } diff --git a/tools/perf/trace/beauty/usbdevfs_ioctl.sh b/tools/perf/trace/beauty/usbdevfs_ioctl.sh index 930b80f422e8..aa597ae53747 100755 --- a/tools/perf/trace/beauty/usbdevfs_ioctl.sh +++ b/tools/perf/trace/beauty/usbdevfs_ioctl.sh @@ -3,10 +3,13 @@ [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +# also as: +# #define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) + printf "static const char *usbdevfs_ioctl_cmds[] = {\n" -regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" -egrep $regex ${header_dir}/usbdevice_fs.h | egrep -v 'USBDEVFS_\w+32[[:space:]]' | \ - sed -r "s/$regex/\2 \1/g" | \ +regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)(\(\w+\))?[[:space:]]+_IO[CWR]{0,2}\([[:space:]]*(_IOC_\w+,[[:space:]]*)?'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" +egrep "$regex" ${header_dir}/usbdevice_fs.h | egrep -v 'USBDEVFS_\w+32[[:space:]]' | \ + sed -r "s/$regex/\4 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n\n" printf "#if 0\n" diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ebb46da4dfe5..52459dd5ad0c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1291,6 +1291,7 @@ static void perf_evsel__free_id(struct perf_evsel *evsel) xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; zfree(&evsel->id); + evsel->ids = 0; } static void perf_evsel__free_config_terms(struct perf_evsel *evsel) @@ -2077,6 +2078,7 @@ void perf_evsel__close(struct perf_evsel *evsel) perf_evsel__close_fd(evsel); perf_evsel__free_fd(evsel); + perf_evsel__free_id(evsel); } int perf_evsel__open_per_cpu(struct perf_evsel *evsel, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index c24db7f4909c..1903d7ec9797 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -3559,6 +3559,13 @@ int perf_session__read_header(struct perf_session *session) data->file.path); } + if (f_header.attr_size == 0) { + pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n" + "Was the 'perf record' command properly terminated?\n", + data->file.path); + return -EINVAL; + } + nr_attrs = f_header.attrs.size / f_header.attr_size; lseek(fd, f_header.attrs.offset, SEEK_SET); @@ -3639,7 +3646,7 @@ int perf_event__synthesize_attr(struct perf_tool *tool, size += sizeof(struct perf_event_header); size += ids * sizeof(u64); - ev = malloc(size); + ev = zalloc(size); if (ev == NULL) return -ENOMEM; @@ -3747,7 +3754,7 @@ int perf_event__process_feature(struct perf_session *session, return 0; ff.buf = (void *)fe->data; - ff.size = event->header.size - sizeof(event->header); + ff.size = event->header.size - sizeof(*fe); ff.ph = &session->header; if (feat_ops[feat].process(&ff, NULL)) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cd1eb73cfe83..8394d48f8b32 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2230,6 +2230,7 @@ void clear_perf_probe_event(struct perf_probe_event *pev) field = next; } } + pev->nargs = 0; zfree(&pev->args); } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index d0fd6c614e68..37efa1f43d8b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -36,10 +36,16 @@ static int perf_session__process_compressed_event(struct perf_session *session, void *src; size_t decomp_size, src_size; u64 decomp_last_rem = 0; - size_t decomp_len = session->header.env.comp_mmap_len; + size_t mmap_len, decomp_len = session->header.env.comp_mmap_len; struct decomp *decomp, *decomp_last = session->decomp_last; - decomp = mmap(NULL, sizeof(struct decomp) + decomp_len, PROT_READ|PROT_WRITE, + if (decomp_last) { + decomp_last_rem = decomp_last->size - decomp_last->head; + decomp_len += decomp_last_rem; + } + + mmap_len = sizeof(struct decomp) + decomp_len; + decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); if (decomp == MAP_FAILED) { pr_err("Couldn't allocate memory for decompression\n"); @@ -47,10 +53,10 @@ static int perf_session__process_compressed_event(struct perf_session *session, } decomp->file_pos = file_offset; + decomp->mmap_len = mmap_len; decomp->head = 0; - if (decomp_last) { - decomp_last_rem = decomp_last->size - decomp_last->head; + if (decomp_last_rem) { memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem); decomp->size = decomp_last_rem; } @@ -61,7 +67,7 @@ static int perf_session__process_compressed_event(struct perf_session *session, decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size, &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); if (!decomp_size) { - munmap(decomp, sizeof(struct decomp) + decomp_len); + munmap(decomp, mmap_len); pr_err("Couldn't decompress data\n"); return -1; } @@ -255,15 +261,15 @@ static void perf_session__delete_threads(struct perf_session *session) static void perf_session__release_decomp_events(struct perf_session *session) { struct decomp *next, *decomp; - size_t decomp_len; + size_t mmap_len; next = session->decomp; - decomp_len = session->header.env.comp_mmap_len; do { decomp = next; if (decomp == NULL) break; next = decomp->next; - munmap(decomp, decomp_len + sizeof(struct decomp)); + mmap_len = decomp->mmap_len; + munmap(decomp, mmap_len); } while (1); } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index dd8920b745bc..863dbad87849 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -46,6 +46,7 @@ struct perf_session { struct decomp { struct decomp *next; u64 file_pos; + size_t mmap_len; u64 head; size_t size; char data[]; diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 656065af4971..accb1bf1cfd8 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -819,7 +819,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, "stalled cycles per insn", ratio); } else if (have_frontend_stalled) { - print_metric(config, ctxp, NULL, NULL, + out->new_line(config, ctxp); + print_metric(config, ctxp, NULL, "%7.2f ", "stalled cycles per insn", 0); } } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) { diff --git a/tools/perf/util/zstd.c b/tools/perf/util/zstd.c index 23bdb9884576..d2202392ffdb 100644 --- a/tools/perf/util/zstd.c +++ b/tools/perf/util/zstd.c @@ -99,8 +99,8 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size while (input.pos < input.size) { ret = ZSTD_decompressStream(data->dstream, &output, &input); if (ZSTD_isError(ret)) { - pr_err("failed to decompress (B): %ld -> %ld : %s\n", - src_size, output.size, ZSTD_getErrorName(ret)); + pr_err("failed to decompress (B): %ld -> %ld, dst_size %ld : %s\n", + src_size, output.size, dst_size, ZSTD_getErrorName(ret)); break; } output.dst = dst + output.pos; diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 495066bafbe3..ded7a950dc40 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -32,7 +32,6 @@ EXTRA_WARNINGS += -Wno-system-headers EXTRA_WARNINGS += -Wold-style-definition EXTRA_WARNINGS += -Wpacked EXTRA_WARNINGS += -Wredundant-decls -EXTRA_WARNINGS += -Wshadow EXTRA_WARNINGS += -Wstrict-prototypes EXTRA_WARNINGS += -Wswitch-default EXTRA_WARNINGS += -Wswitch-enum @@ -69,8 +68,16 @@ endif # will do for now and keep the above -Wstrict-aliasing=3 in place # in newer systems. # Needed for the __raw_cmpxchg in tools/arch/x86/include/asm/cmpxchg.h +# +# See https://lkml.org/lkml/2006/11/28/253 and https://gcc.gnu.org/gcc-4.8/changes.html, +# that takes into account Linus's comments (search for Wshadow) for the reasoning about +# -Wshadow not being interesting before gcc 4.8. + ifneq ($(filter 3.%,$(MAKE_VERSION)),) # make-3 EXTRA_WARNINGS += -fno-strict-aliasing +EXTRA_WARNINGS += -Wno-shadow +else +EXTRA_WARNINGS += -Wshadow endif ifneq ($(findstring $(MAKEFLAGS), w),w) diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl index 72525426654b..6fd864935319 100755 --- a/tools/testing/ktest/config-bisect.pl +++ b/tools/testing/ktest/config-bisect.pl @@ -663,7 +663,7 @@ while ($#ARGV >= 0) { } else { - die "Unknow option $opt\n"; + die "Unknown option $opt\n"; } } @@ -732,7 +732,7 @@ if ($start) { } } run_command "cp $good_start $good" or die "failed to copy to $good\n"; - run_command "cp $bad_start $bad" or die "faield to copy to $bad\n"; + run_command "cp $bad_start $bad" or die "failed to copy to $bad\n"; } else { if ( ! -f $good ) { die "Can not find file $good\n"; diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 3bd0f4a0336a..29001f944db7 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -57,7 +57,8 @@ TEST_PROGS := test_kmod.sh \ test_lirc_mode2.sh \ test_skb_cgroup_id.sh \ test_flow_dissector.sh \ - test_xdp_vlan.sh \ + test_xdp_vlan_mode_generic.sh \ + test_xdp_vlan_mode_native.sh \ test_lwt_ip_encap.sh \ test_tcp_check_syncookie.sh \ test_tc_tunnel.sh \ diff --git a/tools/testing/selftests/bpf/progs/sendmsg6_prog.c b/tools/testing/selftests/bpf/progs/sendmsg6_prog.c index 5aeaa284fc47..a68062820410 100644 --- a/tools/testing/selftests/bpf/progs/sendmsg6_prog.c +++ b/tools/testing/selftests/bpf/progs/sendmsg6_prog.c @@ -41,8 +41,7 @@ int sendmsg_v6_prog(struct bpf_sock_addr *ctx) } /* Rewrite destination. */ - if ((ctx->user_ip6[0] & 0xFFFF) == bpf_htons(0xFACE) && - ctx->user_ip6[0] >> 16 == bpf_htons(0xB00C)) { + if (ctx->user_ip6[0] == bpf_htonl(0xFACEB00C)) { ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.sh b/tools/testing/selftests/bpf/test_xdp_vlan.sh index 51a3a31d1aac..bb8b0da91686 100755 --- a/tools/testing/selftests/bpf/test_xdp_vlan.sh +++ b/tools/testing/selftests/bpf/test_xdp_vlan.sh @@ -1,6 +1,14 @@ #!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Author: Jesper Dangaard Brouer <hawk@kernel.org> -TESTNAME=xdp_vlan +# Allow wrapper scripts to name test +if [ -z "$TESTNAME" ]; then + TESTNAME=xdp_vlan +fi + +# Default XDP mode +XDP_MODE=xdpgeneric usage() { echo "Testing XDP + TC eBPF VLAN manipulations: $TESTNAME" @@ -9,9 +17,23 @@ usage() { echo " -v | --verbose : Verbose" echo " --flush : Flush before starting (e.g. after --interactive)" echo " --interactive : Keep netns setup running after test-run" + echo " --mode=XXX : Choose XDP mode (xdp | xdpgeneric | xdpdrv)" echo "" } +valid_xdp_mode() +{ + local mode=$1 + + case "$mode" in + xdpgeneric | xdpdrv | xdp) + return 0 + ;; + *) + return 1 + esac +} + cleanup() { local status=$? @@ -37,7 +59,7 @@ cleanup() # Using external program "getopt" to get --long-options OPTIONS=$(getopt -o hvfi: \ - --long verbose,flush,help,interactive,debug -- "$@") + --long verbose,flush,help,interactive,debug,mode: -- "$@") if (( $? != 0 )); then usage echo "selftests: $TESTNAME [FAILED] Error calling getopt, unknown option?" @@ -60,6 +82,11 @@ while true; do cleanup shift ;; + --mode ) + shift + XDP_MODE=$1 + shift + ;; -- ) shift break @@ -81,8 +108,14 @@ if [ "$EUID" -ne 0 ]; then exit 1 fi -ip link set dev lo xdp off 2>/dev/null > /dev/null -if [ $? -ne 0 ];then +valid_xdp_mode $XDP_MODE +if [ $? -ne 0 ]; then + echo "selftests: $TESTNAME [FAILED] unknown XDP mode ($XDP_MODE)" + exit 1 +fi + +ip link set dev lo xdpgeneric off 2>/dev/null > /dev/null +if [ $? -ne 0 ]; then echo "selftests: $TESTNAME [SKIP] need ip xdp support" exit 0 fi @@ -155,7 +188,7 @@ ip netns exec ns2 ip link set lo up # At this point, the hosts cannot reach each-other, # because ns2 are using VLAN tags on the packets. -ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Okay ping fails"' +ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Success: First ping must fail"' # Now we can use the test_xdp_vlan.c program to pop/push these VLAN tags @@ -166,7 +199,7 @@ export FILE=test_xdp_vlan.o # First test: Remove VLAN by setting VLAN ID 0, using "xdp_vlan_change" export XDP_PROG=xdp_vlan_change -ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG +ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG # In ns1: egress use TC to add back VLAN tag 4011 # (del cmd) @@ -177,8 +210,8 @@ ip netns exec ns1 tc filter add dev $DEVNS1 egress \ prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push # Now the namespaces can reach each-other, test with ping: -ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 -ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 +ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1 +ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2 # Second test: Replace xdp prog, that fully remove vlan header # @@ -187,9 +220,9 @@ ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 # ETH_P_8021Q indication, and this cause overwriting of our changes. # export XDP_PROG=xdp_vlan_remove_outer2 -ip netns exec ns1 ip link set $DEVNS1 xdp off -ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG +ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE off +ip netns exec ns1 ip link set $DEVNS1 $XDP_MODE object $FILE section $XDP_PROG # Now the namespaces should still be able reach each-other, test with ping: -ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 -ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 +ip netns exec ns2 ping -i 0.2 -W 2 -c 2 $IPADDR1 +ip netns exec ns1 ping -i 0.2 -W 2 -c 2 $IPADDR2 diff --git a/tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh b/tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh new file mode 100755 index 000000000000..c515326d6d59 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan_mode_generic.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Exit on failure +set -e + +# Wrapper script to test generic-XDP +export TESTNAME=xdp_vlan_mode_generic +./test_xdp_vlan.sh --mode=xdpgeneric diff --git a/tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh b/tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh new file mode 100755 index 000000000000..5cf7ce1f16c1 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan_mode_native.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Exit on failure +set -e + +# Wrapper script to test native-XDP +export TESTNAME=xdp_vlan_mode_native +./test_xdp_vlan.sh --mode=xdpdrv diff --git a/tools/testing/selftests/bpf/verifier/ctx_skb.c b/tools/testing/selftests/bpf/verifier/ctx_skb.c index b0fda2877119..d438193804b2 100644 --- a/tools/testing/selftests/bpf/verifier/ctx_skb.c +++ b/tools/testing/selftests/bpf/verifier/ctx_skb.c @@ -975,6 +975,17 @@ .prog_type = BPF_PROG_TYPE_CGROUP_SKB, }, { + "read gso_segs from CGROUP_SKB", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, gso_segs)), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, +}, +{ "write gso_segs from CGROUP_SKB", .insns = { BPF_MOV64_IMM(BPF_REG_0, 0), diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c index 4c223266299a..bdb69599c4bd 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.c +++ b/tools/testing/selftests/cgroup/cgroup_util.c @@ -191,8 +191,7 @@ int cg_find_unified_root(char *root, size_t len) strtok(NULL, delim); strtok(NULL, delim); - if (strcmp(fs, "cgroup") == 0 && - strcmp(type, "cgroup2") == 0) { + if (strcmp(type, "cgroup2") == 0) { strncpy(root, mount, len); return 0; } diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh index 40f16f2a3afd..5cbff8038f84 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh @@ -36,8 +36,6 @@ source $lib_dir/lib.sh h1_create() { - local dscp; - simple_if_init $h1 192.0.2.1/28 tc qdisc add dev $h1 clsact dscp_capture_install $h1 10 @@ -67,6 +65,7 @@ h2_destroy() dscp_map() { local base=$1; shift + local prio for prio in {0..7}; do echo app=$prio,5,$((base + prio)) @@ -138,6 +137,7 @@ dscp_ping_test() local prio=$1; shift local dev_10=$1; shift local dev_20=$1; shift + local key local dscp_10=$(((prio + 10) << 2)) local dscp_20=$(((prio + 20) << 2)) @@ -175,6 +175,8 @@ dscp_ping_test() test_dscp() { + local prio + for prio in {0..7}; do dscp_ping_test v$h1 192.0.2.1 192.0.2.2 $prio $h1 $h2 done diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh index 9faf02e32627..c745ce3befee 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh @@ -31,6 +31,7 @@ ALL_TESTS=" ping_ipv4 test_update test_no_update + test_dscp_leftover " lib_dir=$(dirname $0)/../../../net/forwarding @@ -50,10 +51,13 @@ reprioritize() echo ${reprio[$in]} } -h1_create() +zero() { - local dscp; + echo 0 +} +h1_create() +{ simple_if_init $h1 192.0.2.1/28 tc qdisc add dev $h1 clsact dscp_capture_install $h1 0 @@ -87,6 +91,7 @@ h2_destroy() dscp_map() { local base=$1; shift + local prio for prio in {0..7}; do echo app=$prio,5,$((base + prio)) @@ -156,6 +161,7 @@ dscp_ping_test() local reprio=$1; shift local dev1=$1; shift local dev2=$1; shift + local i local prio2=$($reprio $prio) # ICMP Request egress prio local prio3=$($reprio $prio2) # ICMP Response egress prio @@ -205,6 +211,7 @@ __test_update() { local update=$1; shift local reprio=$1; shift + local prio sysctl_restore net.ipv4.ip_forward_update_priority sysctl_set net.ipv4.ip_forward_update_priority $update @@ -224,6 +231,19 @@ test_no_update() __test_update 0 echo } +# Test that when the last APP rule is removed, the prio->DSCP map is properly +# set to zeroes, and that the last APP rule does not stay active in the ASIC. +test_dscp_leftover() +{ + lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null + lldpad_app_wait_del + + __test_update 0 zero + + lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null + lldpad_app_wait_set $swp2 +} + trap cleanup EXIT setup_prepare diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh index 71231ad2dbfb..47315fe48d5a 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh @@ -262,7 +262,7 @@ test_mc_aware() stop_traffic - log_test "UC performace under MC overload" + log_test "UC performance under MC overload" echo "UC-only throughput $(humanize $ucth1)" echo "UC+MC throughput $(humanize $ucth2)" @@ -316,7 +316,7 @@ test_uc_aware() stop_traffic - log_test "MC performace under UC overload" + log_test "MC performance under UC overload" echo " ingress UC throughput $(humanize ${uc_ir})" echo " egress UC throughput $(humanize ${uc_er})" echo " sent $attempts BC ARPs, got $passes responses" diff --git a/tools/testing/selftests/kmod/kmod.sh b/tools/testing/selftests/kmod/kmod.sh index 0a76314b4414..8b944cf042f6 100755 --- a/tools/testing/selftests/kmod/kmod.sh +++ b/tools/testing/selftests/kmod/kmod.sh @@ -28,7 +28,7 @@ # override by exporting to your environment prior running this script. # For instance this script assumes you do not have xfs loaded upon boot. # If this is false, export DEFAULT_KMOD_FS="ext4" prior to running this -# script if the filesyste module you don't have loaded upon bootup +# script if the filesystem module you don't have loaded upon bootup # is ext4 instead. Refer to allow_user_defaults() for a list of user # override variables possible. # @@ -263,7 +263,7 @@ config_get_test_result() config_reset() { if ! echo -n "1" >"$DIR"/reset; then - echo "$0: reset shuld have worked" >&2 + echo "$0: reset should have worked" >&2 exit 1 fi } @@ -488,7 +488,7 @@ usage() echo Example uses: echo echo "${TEST_NAME}.sh -- executes all tests" - echo "${TEST_NAME}.sh -t 0008 -- Executes test ID 0008 number of times is recomended" + echo "${TEST_NAME}.sh -t 0008 -- Executes test ID 0008 number of times is recommended" echo "${TEST_NAME}.sh -w 0008 -- Watch test ID 0008 run until an error occurs" echo "${TEST_NAME}.sh -s 0008 -- Run test ID 0008 once" echo "${TEST_NAME}.sh -c 0008 3 -- Run test ID 0008 three times" diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index ec15c4f6af55..0ac49d91a260 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -10,6 +10,7 @@ #ifndef __KSELFTEST_H #define __KSELFTEST_H +#include <errno.h> #include <stdlib.h> #include <unistd.h> #include <stdarg.h> @@ -81,58 +82,68 @@ static inline void ksft_print_cnts(void) static inline void ksft_print_msg(const char *msg, ...) { + int saved_errno = errno; va_list args; va_start(args, msg); printf("# "); + errno = saved_errno; vprintf(msg, args); va_end(args); } static inline void ksft_test_result_pass(const char *msg, ...) { + int saved_errno = errno; va_list args; ksft_cnt.ksft_pass++; va_start(args, msg); printf("ok %d ", ksft_test_num()); + errno = saved_errno; vprintf(msg, args); va_end(args); } static inline void ksft_test_result_fail(const char *msg, ...) { + int saved_errno = errno; va_list args; ksft_cnt.ksft_fail++; va_start(args, msg); printf("not ok %d ", ksft_test_num()); + errno = saved_errno; vprintf(msg, args); va_end(args); } static inline void ksft_test_result_skip(const char *msg, ...) { + int saved_errno = errno; va_list args; ksft_cnt.ksft_xskip++; va_start(args, msg); printf("not ok %d # SKIP ", ksft_test_num()); + errno = saved_errno; vprintf(msg, args); va_end(args); } static inline void ksft_test_result_error(const char *msg, ...) { + int saved_errno = errno; va_list args; ksft_cnt.ksft_error++; va_start(args, msg); printf("not ok %d # error ", ksft_test_num()); + errno = saved_errno; vprintf(msg, args); va_end(args); } @@ -152,10 +163,12 @@ static inline int ksft_exit_fail(void) static inline int ksft_exit_fail_msg(const char *msg, ...) { + int saved_errno = errno; va_list args; va_start(args, msg); printf("Bail out! "); + errno = saved_errno; vprintf(msg, args); va_end(args); @@ -178,10 +191,12 @@ static inline int ksft_exit_xpass(void) static inline int ksft_exit_skip(const char *msg, ...) { if (msg) { + int saved_errno = errno; va_list args; va_start(args, msg); printf("not ok %d # SKIP ", 1 + ksft_test_num()); + errno = saved_errno; vprintf(msg, args); va_end(args); } else { diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh index 30195449c63c..79b0affd21fb 100644 --- a/tools/testing/selftests/livepatch/functions.sh +++ b/tools/testing/selftests/livepatch/functions.sh @@ -13,6 +13,14 @@ function log() { echo "$1" > /dev/kmsg } +# skip(msg) - testing can't proceed +# msg - explanation +function skip() { + log "SKIP: $1" + echo "SKIP: $1" >&2 + exit 4 +} + # die(msg) - game over, man # msg - dying words function die() { @@ -21,13 +29,27 @@ function die() { exit 1 } -# set_dynamic_debug() - setup kernel dynamic debug -# TODO - push and pop this config? +function push_dynamic_debug() { + DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \ + awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}') +} + +function pop_dynamic_debug() { + if [[ -n "$DYNAMIC_DEBUG" ]]; then + echo -n "$DYNAMIC_DEBUG" > /sys/kernel/debug/dynamic_debug/control + fi +} + +# set_dynamic_debug() - save the current dynamic debug config and tweak +# it for the self-tests. Set a script exit trap +# that restores the original config. function set_dynamic_debug() { - cat << EOF > /sys/kernel/debug/dynamic_debug/control -file kernel/livepatch/* +p -func klp_try_switch_task -p -EOF + push_dynamic_debug + trap pop_dynamic_debug EXIT INT TERM HUP + cat <<-EOF > /sys/kernel/debug/dynamic_debug/control + file kernel/livepatch/* +p + func klp_try_switch_task -p + EOF } # loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES, @@ -43,6 +65,12 @@ function loop_until() { done } +function assert_mod() { + local mod="$1" + + modprobe --dry-run "$mod" &>/dev/null +} + function is_livepatch_mod() { local mod="$1" @@ -75,6 +103,9 @@ function __load_mod() { function load_mod() { local mod="$1"; shift + assert_mod "$mod" || + skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root" + is_livepatch_mod "$mod" && die "use load_lp() to load the livepatch module $mod" @@ -88,6 +119,9 @@ function load_mod() { function load_lp_nowait() { local mod="$1"; shift + assert_mod "$mod" || + skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root" + is_livepatch_mod "$mod" || die "module $mod is not a livepatch" diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 4ce0bc1612f5..c7cced739c34 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -17,7 +17,7 @@ tcp_inq tls txring_overwrite ip_defrag +ipv6_flowlabel +ipv6_flowlabel_mgr so_txtime -flowlabel -flowlabel_mgr tcp_fastopen_backup_key diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 1b24e36b4047..0bd6b23c97ef 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -10,9 +10,9 @@ TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh ip_defrag.sh TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh -TEST_PROGS += tcp_fastopen_backup_key.sh +TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh TEST_PROGS_EXTENDED := in_netns.sh -TEST_GEN_FILES = socket +TEST_GEN_FILES = socket nettest TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx ip_defrag diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh new file mode 100755 index 000000000000..9fd3a0b97f0d --- /dev/null +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -0,0 +1,3432 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved. +# +# IPv4 and IPv6 functional tests focusing on VRF and routing lookups +# for various permutations: +# 1. icmp, tcp, udp and netfilter +# 2. client, server, no-server +# 3. global address on interface +# 4. global address on 'lo' +# 5. remote and local traffic +# 6. VRF and non-VRF permutations +# +# Setup: +# ns-A | ns-B +# No VRF case: +# [ lo ] [ eth1 ]---|---[ eth1 ] [ lo ] +# remote address +# VRF case: +# [ red ]---[ eth1 ]---|---[ eth1 ] [ lo ] +# +# ns-A: +# eth1: 172.16.1.1/24, 2001:db8:1::1/64 +# lo: 127.0.0.1/8, ::1/128 +# 172.16.2.1/32, 2001:db8:2::1/128 +# red: 127.0.0.1/8, ::1/128 +# 172.16.3.1/32, 2001:db8:3::1/128 +# +# ns-B: +# eth1: 172.16.1.2/24, 2001:db8:1::2/64 +# lo2: 127.0.0.1/8, ::1/128 +# 172.16.2.2/32, 2001:db8:2::2/128 +# +# server / client nomenclature relative to ns-A + +VERBOSE=0 + +NSA_DEV=eth1 +NSB_DEV=eth1 +VRF=red +VRF_TABLE=1101 + +# IPv4 config +NSA_IP=172.16.1.1 +NSB_IP=172.16.1.2 +VRF_IP=172.16.3.1 + +# IPv6 config +NSA_IP6=2001:db8:1::1 +NSB_IP6=2001:db8:1::2 +VRF_IP6=2001:db8:3::1 + +NSA_LO_IP=172.16.2.1 +NSB_LO_IP=172.16.2.2 +NSA_LO_IP6=2001:db8:2::1 +NSB_LO_IP6=2001:db8:2::2 + +MCAST=ff02::1 +# set after namespace create +NSA_LINKIP6= +NSB_LINKIP6= + +NSA=ns-A +NSB=ns-B + +NSA_CMD="ip netns exec ${NSA}" +NSB_CMD="ip netns exec ${NSB}" + +which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) + +################################################################################ +# utilities + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + [ "${VERBOSE}" = "1" ] && echo + + if [ ${rc} -eq ${expected} ]; then + nsuccess=$((nsuccess+1)) + printf "TEST: %-70s [ OK ]\n" "${msg}" + else + nfail=$((nfail+1)) + printf "TEST: %-70s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi + + if [ "${PAUSE}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + + kill_procs +} + +log_test_addr() +{ + local addr=$1 + local rc=$2 + local expected=$3 + local msg="$4" + local astr + + astr=$(addr2str ${addr}) + log_test $rc $expected "$msg - ${astr}" +} + +log_section() +{ + echo + echo "###########################################################################" + echo "$*" + echo "###########################################################################" + echo +} + +log_subsection() +{ + echo + echo "#################################################################" + echo "$*" + echo +} + +log_start() +{ + # make sure we have no test instances running + kill_procs + + if [ "${VERBOSE}" = "1" ]; then + echo + echo "#######################################################" + fi +} + +log_debug() +{ + if [ "${VERBOSE}" = "1" ]; then + echo + echo "$*" + echo + fi +} + +show_hint() +{ + if [ "${VERBOSE}" = "1" ]; then + echo "HINT: $*" + echo + fi +} + +kill_procs() +{ + killall nettest ping ping6 >/dev/null 2>&1 + sleep 1 +} + +do_run_cmd() +{ + local cmd="$*" + local out + + if [ "$VERBOSE" = "1" ]; then + echo "COMMAND: ${cmd}" + fi + + out=$($cmd 2>&1) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo "$out" + fi + + return $rc +} + +run_cmd() +{ + do_run_cmd ${NSA_CMD} $* +} + +run_cmd_nsb() +{ + do_run_cmd ${NSB_CMD} $* +} + +setup_cmd() +{ + local cmd="$*" + local rc + + run_cmd ${cmd} + rc=$? + if [ $rc -ne 0 ]; then + # show user the command if not done so already + if [ "$VERBOSE" = "0" ]; then + echo "setup command: $cmd" + fi + echo "failed. stopping tests" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue" + read a + fi + exit $rc + fi +} + +setup_cmd_nsb() +{ + local cmd="$*" + local rc + + run_cmd_nsb ${cmd} + rc=$? + if [ $rc -ne 0 ]; then + # show user the command if not done so already + if [ "$VERBOSE" = "0" ]; then + echo "setup command: $cmd" + fi + echo "failed. stopping tests" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue" + read a + fi + exit $rc + fi +} + +# set sysctl values in NS-A +set_sysctl() +{ + echo "SYSCTL: $*" + echo + run_cmd sysctl -q -w $* +} + +################################################################################ +# Setup for tests + +addr2str() +{ + case "$1" in + 127.0.0.1) echo "loopback";; + ::1) echo "IPv6 loopback";; + + ${NSA_IP}) echo "ns-A IP";; + ${NSA_IP6}) echo "ns-A IPv6";; + ${NSA_LO_IP}) echo "ns-A loopback IP";; + ${NSA_LO_IP6}) echo "ns-A loopback IPv6";; + ${NSA_LINKIP6}|${NSA_LINKIP6}%*) echo "ns-A IPv6 LLA";; + + ${NSB_IP}) echo "ns-B IP";; + ${NSB_IP6}) echo "ns-B IPv6";; + ${NSB_LO_IP}) echo "ns-B loopback IP";; + ${NSB_LO_IP6}) echo "ns-B loopback IPv6";; + ${NSB_LINKIP6}|${NSB_LINKIP6}%*) echo "ns-B IPv6 LLA";; + + ${VRF_IP}) echo "VRF IP";; + ${VRF_IP6}) echo "VRF IPv6";; + + ${MCAST}%*) echo "multicast IP";; + + *) echo "unknown";; + esac +} + +get_linklocal() +{ + local ns=$1 + local dev=$2 + local addr + + addr=$(ip -netns ${ns} -6 -br addr show dev ${dev} | \ + awk '{ + for (i = 3; i <= NF; ++i) { + if ($i ~ /^fe80/) + print $i + } + }' + ) + addr=${addr/\/*} + + [ -z "$addr" ] && return 1 + + echo $addr + + return 0 +} + +################################################################################ +# create namespaces and vrf + +create_vrf() +{ + local ns=$1 + local vrf=$2 + local table=$3 + local addr=$4 + local addr6=$5 + + ip -netns ${ns} link add ${vrf} type vrf table ${table} + ip -netns ${ns} link set ${vrf} up + ip -netns ${ns} route add vrf ${vrf} unreachable default metric 8192 + ip -netns ${ns} -6 route add vrf ${vrf} unreachable default metric 8192 + + ip -netns ${ns} addr add 127.0.0.1/8 dev ${vrf} + ip -netns ${ns} -6 addr add ::1 dev ${vrf} nodad + if [ "${addr}" != "-" ]; then + ip -netns ${ns} addr add dev ${vrf} ${addr} + fi + if [ "${addr6}" != "-" ]; then + ip -netns ${ns} -6 addr add dev ${vrf} ${addr6} + fi + + ip -netns ${ns} ru del pref 0 + ip -netns ${ns} ru add pref 32765 from all lookup local + ip -netns ${ns} -6 ru del pref 0 + ip -netns ${ns} -6 ru add pref 32765 from all lookup local +} + +create_ns() +{ + local ns=$1 + local addr=$2 + local addr6=$3 + + ip netns add ${ns} + + ip -netns ${ns} link set lo up + if [ "${addr}" != "-" ]; then + ip -netns ${ns} addr add dev lo ${addr} + fi + if [ "${addr6}" != "-" ]; then + ip -netns ${ns} -6 addr add dev lo ${addr6} + fi + + ip -netns ${ns} ro add unreachable default metric 8192 + ip -netns ${ns} -6 ro add unreachable default metric 8192 + + ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1 +} + +# create veth pair to connect namespaces and apply addresses. +connect_ns() +{ + local ns1=$1 + local ns1_dev=$2 + local ns1_addr=$3 + local ns1_addr6=$4 + local ns2=$5 + local ns2_dev=$6 + local ns2_addr=$7 + local ns2_addr6=$8 + + ip -netns ${ns1} li add ${ns1_dev} type veth peer name tmp + ip -netns ${ns1} li set ${ns1_dev} up + ip -netns ${ns1} li set tmp netns ${ns2} name ${ns2_dev} + ip -netns ${ns2} li set ${ns2_dev} up + + if [ "${ns1_addr}" != "-" ]; then + ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr} + ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr} + fi + + if [ "${ns1_addr6}" != "-" ]; then + ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr6} + ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr6} + fi +} + +cleanup() +{ + # explicit cleanups to check those code paths + ip netns | grep -q ${NSA} + if [ $? -eq 0 ]; then + ip -netns ${NSA} link delete ${VRF} + ip -netns ${NSA} ro flush table ${VRF_TABLE} + + ip -netns ${NSA} addr flush dev ${NSA_DEV} + ip -netns ${NSA} -6 addr flush dev ${NSA_DEV} + ip -netns ${NSA} link set dev ${NSA_DEV} down + ip -netns ${NSA} link del dev ${NSA_DEV} + + ip netns del ${NSA} + fi + + ip netns del ${NSB} +} + +setup() +{ + local with_vrf=${1} + + # make sure we are starting with a clean slate + kill_procs + cleanup 2>/dev/null + + log_debug "Configuring network namespaces" + set -e + + create_ns ${NSA} ${NSA_LO_IP}/32 ${NSA_LO_IP6}/128 + create_ns ${NSB} ${NSB_LO_IP}/32 ${NSB_LO_IP6}/128 + connect_ns ${NSA} ${NSA_DEV} ${NSA_IP}/24 ${NSA_IP6}/64 \ + ${NSB} ${NSB_DEV} ${NSB_IP}/24 ${NSB_IP6}/64 + + NSA_LINKIP6=$(get_linklocal ${NSA} ${NSA_DEV}) + NSB_LINKIP6=$(get_linklocal ${NSB} ${NSB_DEV}) + + # tell ns-A how to get to remote addresses of ns-B + if [ "${with_vrf}" = "yes" ]; then + create_vrf ${NSA} ${VRF} ${VRF_TABLE} ${VRF_IP} ${VRF_IP6} + + ip -netns ${NSA} link set dev ${NSA_DEV} vrf ${VRF} + ip -netns ${NSA} ro add vrf ${VRF} ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV} + ip -netns ${NSA} -6 ro add vrf ${VRF} ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV} + + ip -netns ${NSB} ro add ${VRF_IP}/32 via ${NSA_IP} dev ${NSB_DEV} + ip -netns ${NSB} -6 ro add ${VRF_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV} + else + ip -netns ${NSA} ro add ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV} + ip -netns ${NSA} ro add ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV} + fi + + + # tell ns-B how to get to remote addresses of ns-A + ip -netns ${NSB} ro add ${NSA_LO_IP}/32 via ${NSA_IP} dev ${NSB_DEV} + ip -netns ${NSB} ro add ${NSA_LO_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV} + + set +e + + sleep 1 +} + +################################################################################ +# IPv4 + +ipv4_ping_novrf() +{ + local a + + # + # out + # + for a in ${NSB_IP} ${NSB_LO_IP} + do + log_start + run_cmd ping -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping out" + + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping out, device bind" + + log_start + run_cmd ping -c1 -w1 -I ${NSA_LO_IP} ${a} + log_test_addr ${a} $? 0 "ping out, address bind" + done + + # + # in + # + for a in ${NSA_IP} ${NSA_LO_IP} + do + log_start + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping in" + done + + # + # local traffic + # + for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1 + do + log_start + run_cmd ping -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping local" + done + + # + # local traffic, socket bound to device + # + # address on device + a=${NSA_IP} + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping local, device bind" + + # loopback addresses not reachable from device bind + # fails in a really weird way though because ipv4 special cases + # route lookups with oif set. + for a in ${NSA_LO_IP} 127.0.0.1 + do + log_start + show_hint "Fails since address on loopback device is out of device scope" + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 1 "ping local, device bind" + done + + # + # ip rule blocks reachability to remote address + # + log_start + setup_cmd ip rule add pref 32765 from all lookup local + setup_cmd ip rule del pref 0 from all lookup local + setup_cmd ip rule add pref 50 to ${NSB_LO_IP} prohibit + setup_cmd ip rule add pref 51 from ${NSB_IP} prohibit + + a=${NSB_LO_IP} + run_cmd ping -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, blocked by rule" + + # NOTE: ipv4 actually allows the lookup to fail and yet still create + # a viable rtable if the oif (e.g., bind to device) is set, so this + # case succeeds despite the rule + # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + + a=${NSA_LO_IP} + log_start + show_hint "Response generates ICMP (or arp request is ignored) due to ip rule" + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by rule" + + [ "$VERBOSE" = "1" ] && echo + setup_cmd ip rule del pref 32765 from all lookup local + setup_cmd ip rule add pref 0 from all lookup local + setup_cmd ip rule del pref 50 to ${NSB_LO_IP} prohibit + setup_cmd ip rule del pref 51 from ${NSB_IP} prohibit + + # + # route blocks reachability to remote address + # + log_start + setup_cmd ip route replace unreachable ${NSB_LO_IP} + setup_cmd ip route replace unreachable ${NSB_IP} + + a=${NSB_LO_IP} + run_cmd ping -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, blocked by route" + + # NOTE: ipv4 actually allows the lookup to fail and yet still create + # a viable rtable if the oif (e.g., bind to device) is set, so this + # case succeeds despite not having a route for the address + # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + + a=${NSA_LO_IP} + log_start + show_hint "Response is dropped (or arp request is ignored) due to ip route" + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by route" + + # + # remove 'remote' routes; fallback to default + # + log_start + setup_cmd ip ro del ${NSB_LO_IP} + + a=${NSB_LO_IP} + run_cmd ping -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, unreachable default route" + + # NOTE: ipv4 actually allows the lookup to fail and yet still create + # a viable rtable if the oif (e.g., bind to device) is set, so this + # case succeeds despite not having a route for the address + # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} +} + +ipv4_ping_vrf() +{ + local a + + # should default on; does not exist on older kernels + set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null + + # + # out + # + for a in ${NSB_IP} ${NSB_LO_IP} + do + log_start + run_cmd ping -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 0 "ping out, VRF bind" + + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping out, device bind" + + log_start + run_cmd ip vrf exec ${VRF} ping -c1 -w1 -I ${NSA_IP} ${a} + log_test_addr ${a} $? 0 "ping out, vrf device + dev address bind" + + log_start + run_cmd ip vrf exec ${VRF} ping -c1 -w1 -I ${VRF_IP} ${a} + log_test_addr ${a} $? 0 "ping out, vrf device + vrf address bind" + done + + # + # in + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping in" + done + + # + # local traffic, local address + # + for a in ${NSA_IP} ${VRF_IP} 127.0.0.1 + do + log_start + show_hint "Source address should be ${a}" + run_cmd ping -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 0 "ping local, VRF bind" + done + + # + # local traffic, socket bound to device + # + # address on device + a=${NSA_IP} + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping local, device bind" + + # vrf device is out of scope + for a in ${VRF_IP} 127.0.0.1 + do + log_start + show_hint "Fails since address on vrf device is out of device scope" + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 1 "ping local, device bind" + done + + # + # ip rule blocks address + # + log_start + setup_cmd ip rule add pref 50 to ${NSB_LO_IP} prohibit + setup_cmd ip rule add pref 51 from ${NSB_IP} prohibit + + a=${NSB_LO_IP} + run_cmd ping -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 2 "ping out, vrf bind, blocked by rule" + + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule" + + a=${NSA_LO_IP} + log_start + show_hint "Response lost due to ip rule" + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by rule" + + [ "$VERBOSE" = "1" ] && echo + setup_cmd ip rule del pref 50 to ${NSB_LO_IP} prohibit + setup_cmd ip rule del pref 51 from ${NSB_IP} prohibit + + # + # remove 'remote' routes; fallback to default + # + log_start + setup_cmd ip ro del vrf ${VRF} ${NSB_LO_IP} + + a=${NSB_LO_IP} + run_cmd ping -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 2 "ping out, vrf bind, unreachable route" + + log_start + run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, unreachable route" + + a=${NSA_LO_IP} + log_start + show_hint "Response lost by unreachable route" + run_cmd_nsb ping -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, unreachable route" +} + +ipv4_ping() +{ + log_section "IPv4 ping" + + log_subsection "No VRF" + setup + set_sysctl net.ipv4.raw_l3mdev_accept=0 2>/dev/null + ipv4_ping_novrf + setup + set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null + ipv4_ping_novrf + + log_subsection "With VRF" + setup "yes" + ipv4_ping_vrf +} + +################################################################################ +# IPv4 TCP + +ipv4_tcp_novrf() +{ + local a + + # + # server tests + # + for a in ${NSA_IP} ${NSA_LO_IP} + do + log_start + run_cmd nettest -s & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "Global server" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -d ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "Device server" + + # verify TCP reset sent and received + for a in ${NSA_IP} ${NSA_LO_IP} + do + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # client + # + for a in ${NSB_IP} ${NSB_LO_IP} + do + log_start + run_cmd_nsb nettest -s & + sleep 1 + run_cmd nettest -r ${a} -0 ${NSA_IP} + log_test_addr ${a} $? 0 "Client" + + log_start + run_cmd_nsb nettest -s & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 0 "Client, device bind" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -r ${a} + log_test_addr ${a} $? 1 "No server, unbound client" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + # + # local address tests + # + for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1 + do + log_start + run_cmd nettest -s & + sleep 1 + run_cmd nettest -r ${a} -0 ${a} -1 ${a} + log_test_addr ${a} $? 0 "Global server, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -d ${NSA_DEV} & + sleep 1 + run_cmd nettest -r ${a} -0 ${a} + log_test_addr ${a} $? 0 "Device server, unbound client, local connection" + + for a in ${NSA_LO_IP} 127.0.0.1 + do + log_start + show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope" + run_cmd nettest -s -d ${NSA_DEV} & + sleep 1 + run_cmd nettest -r ${a} + log_test_addr ${a} $? 1 "Device server, unbound client, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s & + sleep 1 + run_cmd nettest -r ${a} -0 ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 0 "Global server, device client, local connection" + + for a in ${NSA_LO_IP} 127.0.0.1 + do + log_start + show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope" + run_cmd nettest -s & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "Global server, device client, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -d ${NSA_DEV} -r ${a} -0 ${a} + log_test_addr ${a} $? 0 "Device server, device client, local connection" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 1 "No server, device client, local conn" +} + +ipv4_tcp_vrf() +{ + local a + + # disable global server + log_subsection "Global server disabled" + + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + + # + # server tests + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + show_hint "Should fail 'Connection refused' since global server with VRF is disabled" + run_cmd nettest -s & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 1 "Global server" + + log_start + run_cmd nettest -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + log_start + run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "Device server" + + # verify TCP reset received + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # local address tests + # (${VRF_IP} and 127.0.0.1 both timeout) + a=${NSA_IP} + log_start + show_hint "Should fail 'Connection refused' since global server with VRF is disabled" + run_cmd nettest -s & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "Global server, local connection" + + # + # enable VRF global server + # + log_subsection "VRF Global server enabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=1 + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + show_hint "client socket should be bound to VRF" + run_cmd nettest -s -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "Global server" + + log_start + show_hint "client socket should be bound to VRF" + run_cmd nettest -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + # verify TCP reset received + log_start + show_hint "Should fail 'Connection refused'" + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + a=${NSA_IP} + log_start + show_hint "client socket should be bound to device" + run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 0 "Device server" + + # local address tests + for a in ${NSA_IP} ${VRF_IP} + do + log_start + show_hint "Should fail 'No route to host' since client is not bound to VRF" + run_cmd nettest -s -2 ${VRF} & + sleep 1 + run_cmd nettest -r ${a} + log_test_addr ${a} $? 1 "Global server, local connection" + done + + # + # client + # + for a in ${NSB_IP} ${NSB_LO_IP} + do + log_start + run_cmd_nsb nettest -s & + sleep 1 + run_cmd nettest -r ${a} -d ${VRF} + log_test_addr ${a} $? 0 "Client, VRF bind" + + log_start + run_cmd_nsb nettest -s & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 0 "Client, device bind" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -r ${a} -d ${VRF} + log_test_addr ${a} $? 1 "No server, VRF client" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + for a in ${NSA_IP} ${VRF_IP} 127.0.0.1 + do + log_start + run_cmd nettest -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd nettest -r ${a} -d ${VRF} -0 ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} -0 ${a} + log_test_addr ${a} $? 0 "VRF server, device client, local connection" + + log_start + show_hint "Should fail 'No route to host' since client is out of VRF scope" + run_cmd nettest -s -d ${VRF} & + sleep 1 + run_cmd nettest -r ${a} + log_test_addr ${a} $? 1 "VRF server, unbound client, local connection" + + log_start + run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -r ${a} -d ${VRF} -0 ${a} + log_test_addr ${a} $? 0 "Device server, VRF client, local connection" + + log_start + run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -r ${a} -d ${NSA_DEV} -0 ${a} + log_test_addr ${a} $? 0 "Device server, device client, local connection" +} + +ipv4_tcp() +{ + log_section "IPv4/TCP" + log_subsection "No VRF" + setup + + # tcp_l3mdev_accept should have no affect without VRF; + # run tests with it enabled and disabled to verify + log_subsection "tcp_l3mdev_accept disabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + ipv4_tcp_novrf + log_subsection "tcp_l3mdev_accept enabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=1 + ipv4_tcp_novrf + + log_subsection "With VRF" + setup "yes" + ipv4_tcp_vrf +} + +################################################################################ +# IPv4 UDP + +ipv4_udp_novrf() +{ + local a + + # + # server tests + # + for a in ${NSA_IP} ${NSA_LO_IP} + do + log_start + run_cmd nettest -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "Global server" + + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + a=${NSA_IP} + log_start + run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "Device server" + + # + # client + # + for a in ${NSB_IP} ${NSB_LO_IP} + do + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -0 ${NSA_IP} + log_test_addr ${a} $? 0 "Client" + + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} -0 ${NSA_IP} + log_test_addr ${a} $? 0 "Client, device bind" + + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} -C -0 ${NSA_IP} + log_test_addr ${a} $? 0 "Client, device send via cmsg" + + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} -S -0 ${NSA_IP} + log_test_addr ${a} $? 0 "Client, device bind via IP_UNICAST_IF" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -D -r ${a} + log_test_addr ${a} $? 1 "No server, unbound client" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -D -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + # + # local address tests + # + for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1 + do + log_start + run_cmd nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -0 ${a} -1 ${a} + log_test_addr ${a} $? 0 "Global server, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -r ${a} + log_test_addr ${a} $? 0 "Device server, unbound client, local connection" + + for a in ${NSA_LO_IP} 127.0.0.1 + do + log_start + show_hint "Should fail 'Connection refused' since address is out of device scope" + run_cmd nettest -s -D -d ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -r ${a} + log_test_addr ${a} $? 1 "Device server, unbound client, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -D & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Global server, device client, local connection" + + log_start + run_cmd nettest -s -D & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -C -r ${a} + log_test_addr ${a} $? 0 "Global server, device send via cmsg, local connection" + + log_start + run_cmd nettest -s -D & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -S -r ${a} + log_test_addr ${a} $? 0 "Global server, device client via IP_UNICAST_IF, local connection" + + # IPv4 with device bind has really weird behavior - it overrides the + # fib lookup, generates an rtable and tries to send the packet. This + # causes failures for local traffic at different places + for a in ${NSA_LO_IP} 127.0.0.1 + do + log_start + show_hint "Should fail since addresses on loopback are out of device scope" + run_cmd nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 2 "Global server, device client, local connection" + + log_start + show_hint "Should fail since addresses on loopback are out of device scope" + run_cmd nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} -C + log_test_addr ${a} $? 1 "Global server, device send via cmsg, local connection" + + log_start + show_hint "Should fail since addresses on loopback are out of device scope" + run_cmd nettest -D -s & + sleep 1 + run_cmd nettest -D -r ${a} -d ${NSA_DEV} -S + log_test_addr ${a} $? 1 "Global server, device client via IP_UNICAST_IF, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -D -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} -0 ${a} + log_test_addr ${a} $? 0 "Device server, device client, local conn" + + log_start + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 2 "No server, device client, local conn" +} + +ipv4_udp_vrf() +{ + local a + + # disable global server + log_subsection "Global server disabled" + set_sysctl net.ipv4.udp_l3mdev_accept=0 + + # + # server tests + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + show_hint "Fails because ingress is in a VRF and global server is disabled" + run_cmd nettest -D -s & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 1 "Global server" + + log_start + run_cmd nettest -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + log_start + run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server" + + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 1 "No server" + + log_start + show_hint "Should fail 'Connection refused' since global server is out of scope" + run_cmd nettest -D -s & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 1 "Global server, VRF client, local connection" + done + + a=${NSA_IP} + log_start + run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + + log_start + run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "VRF server, enslaved device client, local connection" + + a=${NSA_IP} + log_start + run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn" + + log_start + run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn" + + # enable global server + log_subsection "Global server enabled" + set_sysctl net.ipv4.udp_l3mdev_accept=1 + + # + # server tests + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "Global server" + + log_start + run_cmd nettest -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + log_start + run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd_nsb nettest -D -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # client tests + # + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -d ${VRF} -D -r ${NSB_IP} -1 ${NSA_IP} + log_test $? 0 "VRF client" + + log_start + run_cmd_nsb nettest -D -s & + sleep 1 + run_cmd nettest -d ${NSA_DEV} -D -r ${NSB_IP} -1 ${NSA_IP} + log_test $? 0 "Enslaved device client" + + # negative test - should fail + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -D -d ${VRF} -r ${NSB_IP} + log_test $? 1 "No server, VRF client" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -D -d ${NSA_DEV} -r ${NSB_IP} + log_test $? 1 "No server, enslaved device client" + + # + # local address tests + # + a=${NSA_IP} + log_start + run_cmd nettest -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Global server, VRF client, local conn" + + log_start + run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + + log_start + run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "VRF server, device client, local conn" + + log_start + run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn" + + log_start + run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn" + + for a in ${VRF_IP} 127.0.0.1 + do + log_start + run_cmd nettest -D -s -2 ${VRF} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Global server, VRF client, local conn" + done + + for a in ${VRF_IP} 127.0.0.1 + do + log_start + run_cmd nettest -s -D -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + done + + # negative test - should fail + # verifies ECONNREFUSED + for a in ${NSA_IP} ${VRF_IP} 127.0.0.1 + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 1 "No server, VRF client, local conn" + done +} + +ipv4_udp() +{ + log_section "IPv4/UDP" + log_subsection "No VRF" + + setup + + # udp_l3mdev_accept should have no affect without VRF; + # run tests with it enabled and disabled to verify + log_subsection "udp_l3mdev_accept disabled" + set_sysctl net.ipv4.udp_l3mdev_accept=0 + ipv4_udp_novrf + log_subsection "udp_l3mdev_accept enabled" + set_sysctl net.ipv4.udp_l3mdev_accept=1 + ipv4_udp_novrf + + log_subsection "With VRF" + setup "yes" + ipv4_udp_vrf +} + +################################################################################ +# IPv4 address bind +# +# verifies ability or inability to bind to an address / device + +ipv4_addr_bind_novrf() +{ + # + # raw socket + # + for a in ${NSA_IP} ${NSA_LO_IP} + do + log_start + run_cmd nettest -s -R -P icmp -l ${a} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address" + + log_start + run_cmd nettest -s -R -P icmp -l ${a} -d ${NSA_DEV} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind" + done + + # + # tcp sockets + # + a=${NSA_IP} + log_start + run_cmd nettest -l ${a} -r ${NSB_IP} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address" + + log_start + run_cmd nettest -l ${a} -r ${NSB_IP} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind" + + # Sadly, the kernel allows binding a socket to a device and then + # binding to an address not on the device. The only restriction + # is that the address is valid in the L3 domain. So this test + # passes when it really should not + #a=${NSA_LO_IP} + #log_start + #show_hint "Should fail with 'Cannot assign requested address'" + #run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b + #log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address" +} + +ipv4_addr_bind_vrf() +{ + # + # raw socket + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest -s -R -P icmp -l ${a} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address" + + log_start + run_cmd nettest -s -R -P icmp -l ${a} -d ${NSA_DEV} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind" + log_start + run_cmd nettest -s -R -P icmp -l ${a} -d ${VRF} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after VRF bind" + done + + a=${NSA_LO_IP} + log_start + show_hint "Address on loopback is out of VRF scope" + run_cmd nettest -s -R -P icmp -l ${a} -d ${VRF} -b + log_test_addr ${a} $? 1 "Raw socket bind to out of scope address after VRF bind" + + # + # tcp sockets + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest -s -l ${a} -d ${VRF} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address" + + log_start + run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind" + done + + a=${NSA_LO_IP} + log_start + show_hint "Address on loopback out of scope for VRF" + run_cmd nettest -s -l ${a} -d ${VRF} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for VRF" + + log_start + show_hint "Address on loopback out of scope for device in VRF" + run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for device bind" +} + +ipv4_addr_bind() +{ + log_section "IPv4 address binds" + + log_subsection "No VRF" + setup + ipv4_addr_bind_novrf + + log_subsection "With VRF" + setup "yes" + ipv4_addr_bind_vrf +} + +################################################################################ +# IPv4 runtime tests + +ipv4_rt() +{ + local desc="$1" + local varg="$2" + local with_vrf="yes" + local a + + # + # server tests + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server" + + setup ${with_vrf} + done + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest ${varg} -s -d ${VRF} & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server" + + setup ${with_vrf} + done + + a=${NSA_IP} + log_start + run_cmd nettest ${varg} -s -d ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, enslaved device server" + + setup ${with_vrf} + + # + # client test + # + log_start + run_cmd_nsb nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${NSB_IP} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF client" + + setup ${with_vrf} + + log_start + run_cmd_nsb nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${NSB_IP} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, enslaved device client" + + setup ${with_vrf} + + # + # local address tests + # + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server, VRF client, local" + + setup ${with_vrf} + done + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest ${varg} -d ${VRF} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server and client, local" + + setup ${with_vrf} + done + + a=${NSA_IP} + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server, enslaved device client, local" + + setup ${with_vrf} + + log_start + run_cmd nettest ${varg} -d ${VRF} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server, enslaved device client, local" + + setup ${with_vrf} + + log_start + run_cmd nettest ${varg} -d ${NSA_DEV} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, enslaved device server and client, local" +} + +ipv4_ping_rt() +{ + local with_vrf="yes" + local a + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd_nsb ping -f ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "Device delete with active traffic - ping in" + + setup ${with_vrf} + done + + a=${NSB_IP} + log_start + run_cmd ping -f -I ${VRF} ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "Device delete with active traffic - ping out" +} + +ipv4_runtime() +{ + log_section "Run time tests - ipv4" + + setup "yes" + ipv4_ping_rt + + setup "yes" + ipv4_rt "TCP active socket" "-n -1" + + setup "yes" + ipv4_rt "TCP passive socket" "-i" +} + +################################################################################ +# IPv6 + +ipv6_ping_novrf() +{ + local a + + # should not have an impact, but make a known state + set_sysctl net.ipv4.raw_l3mdev_accept=0 2>/dev/null + + # + # out + # + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV} + do + log_start + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping out" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} + do + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping out, device bind" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_LO_IP6} ${a} + log_test_addr ${a} $? 0 "ping out, loopback address bind" + done + + # + # in + # + for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV} ${MCAST}%${NSB_DEV} + do + log_start + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping in" + done + + # + # local traffic, local address + # + for a in ${NSA_IP6} ${NSA_LO_IP6} ::1 ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV} + do + log_start + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping local, no bind" + done + + for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV} + do + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping local, device bind" + done + + for a in ${NSA_LO_IP6} ::1 + do + log_start + show_hint "Fails since address on loopback is out of device scope" + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping local, device bind" + done + + # + # ip rule blocks address + # + log_start + setup_cmd ip -6 rule add pref 32765 from all lookup local + setup_cmd ip -6 rule del pref 0 from all lookup local + setup_cmd ip -6 rule add pref 50 to ${NSB_LO_IP6} prohibit + setup_cmd ip -6 rule add pref 51 from ${NSB_IP6} prohibit + + a=${NSB_LO_IP6} + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, blocked by rule" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule" + + a=${NSA_LO_IP6} + log_start + show_hint "Response lost due to ip rule" + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by rule" + + setup_cmd ip -6 rule add pref 0 from all lookup local + setup_cmd ip -6 rule del pref 32765 from all lookup local + setup_cmd ip -6 rule del pref 50 to ${NSB_LO_IP6} prohibit + setup_cmd ip -6 rule del pref 51 from ${NSB_IP6} prohibit + + # + # route blocks reachability to remote address + # + log_start + setup_cmd ip -6 route del ${NSB_LO_IP6} + setup_cmd ip -6 route add unreachable ${NSB_LO_IP6} metric 10 + setup_cmd ip -6 route add unreachable ${NSB_IP6} metric 10 + + a=${NSB_LO_IP6} + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, blocked by route" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, blocked by route" + + a=${NSA_LO_IP6} + log_start + show_hint "Response lost due to ip route" + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by route" + + + # + # remove 'remote' routes; fallback to default + # + log_start + setup_cmd ip -6 ro del unreachable ${NSB_LO_IP6} + setup_cmd ip -6 ro del unreachable ${NSB_IP6} + + a=${NSB_LO_IP6} + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, unreachable route" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, unreachable route" +} + +ipv6_ping_vrf() +{ + local a + + # should default on; does not exist on older kernels + set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null + + # + # out + # + for a in ${NSB_IP6} ${NSB_LO_IP6} + do + log_start + run_cmd ${ping6} -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 0 "ping out, VRF bind" + done + + for a in ${NSB_LINKIP6}%${VRF} ${MCAST}%${VRF} + do + log_start + show_hint "Fails since VRF device does not support linklocal or multicast" + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, VRF bind" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV} + do + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping out, device bind" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} + do + log_start + run_cmd ip vrf exec ${VRF} ${ping6} -c1 -w1 -I ${VRF_IP6} ${a} + log_test_addr ${a} $? 0 "ping out, vrf device+address bind" + done + + # + # in + # + for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} ${MCAST}%${NSB_DEV} + do + log_start + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 0 "ping in" + done + + a=${NSA_LO_IP6} + log_start + show_hint "Fails since loopback address is out of VRF scope" + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in" + + # + # local traffic, local address + # + for a in ${NSA_IP6} ${VRF_IP6} ::1 + do + log_start + show_hint "Source address should be ${a}" + run_cmd ${ping6} -c1 -w1 -I ${VRF} ${a} + log_test_addr ${a} $? 0 "ping local, VRF bind" + done + + for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV} + do + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 0 "ping local, device bind" + done + + # LLA to GUA - remove ipv6 global addresses from ns-B + setup_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV} + setup_cmd_nsb ip -6 addr del ${NSB_LO_IP6}/128 dev lo + setup_cmd_nsb ip -6 ro add ${NSA_IP6}/128 via ${NSA_LINKIP6} dev ${NSB_DEV} + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6} + log_test_addr ${a} $? 0 "ping in, LLA to GUA" + done + + setup_cmd_nsb ip -6 ro del ${NSA_IP6}/128 via ${NSA_LINKIP6} dev ${NSB_DEV} + setup_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV} + setup_cmd_nsb ip -6 addr add ${NSB_LO_IP6}/128 dev lo + + # + # ip rule blocks address + # + log_start + setup_cmd ip -6 rule add pref 50 to ${NSB_LO_IP6} prohibit + setup_cmd ip -6 rule add pref 51 from ${NSB_IP6} prohibit + + a=${NSB_LO_IP6} + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, blocked by rule" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule" + + a=${NSA_LO_IP6} + log_start + show_hint "Response lost due to ip rule" + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 1 "ping in, blocked by rule" + + log_start + setup_cmd ip -6 rule del pref 50 to ${NSB_LO_IP6} prohibit + setup_cmd ip -6 rule del pref 51 from ${NSB_IP6} prohibit + + # + # remove 'remote' routes; fallback to default + # + log_start + setup_cmd ip -6 ro del ${NSB_LO_IP6} vrf ${VRF} + + a=${NSB_LO_IP6} + run_cmd ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping out, unreachable route" + + log_start + run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a} + log_test_addr ${a} $? 2 "ping out, device bind, unreachable route" + + ip -netns ${NSB} -6 ro del ${NSA_LO_IP6} + a=${NSA_LO_IP6} + log_start + run_cmd_nsb ${ping6} -c1 -w1 ${a} + log_test_addr ${a} $? 2 "ping in, unreachable route" +} + +ipv6_ping() +{ + log_section "IPv6 ping" + + log_subsection "No VRF" + setup + ipv6_ping_novrf + + log_subsection "With VRF" + setup "yes" + ipv6_ping_vrf +} + +################################################################################ +# IPv6 TCP + +ipv6_tcp_novrf() +{ + local a + + # + # server tests + # + for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + run_cmd nettest -6 -s & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Global server" + done + + # verify TCP reset received + for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # client + # + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} + do + log_start + run_cmd_nsb nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Client" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} + do + log_start + run_cmd_nsb nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 0 "Client, device bind" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + # + # local address tests + # + for a in ${NSA_IP6} ${NSA_LO_IP6} ::1 + do + log_start + run_cmd nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Global server, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -r ${a} -0 ${a} + log_test_addr ${a} $? 0 "Device server, unbound client, local connection" + + for a in ${NSA_LO_IP6} ::1 + do + log_start + show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope" + run_cmd nettest -6 -s -d ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -r ${a} + log_test_addr ${a} $? 1 "Device server, unbound client, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a} + log_test_addr ${a} $? 0 "Global server, device client, local connection" + + for a in ${NSA_LO_IP6} ::1 + do + log_start + show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope" + run_cmd nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "Global server, device client, local connection" + done + + for a in ${NSA_IP6} ${NSA_LINKIP6} + do + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Device server, device client, local conn" + done + + for a in ${NSA_IP6} ${NSA_LINKIP6} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 1 "No server, device client, local conn" + done +} + +ipv6_tcp_vrf() +{ + local a + + # disable global server + log_subsection "Global server disabled" + + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + + # + # server tests + # + for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + show_hint "Should fail 'Connection refused' since global server with VRF is disabled" + run_cmd nettest -6 -s & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 1 "Global server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "VRF server" + done + + # link local is always bound to ingress device + a=${NSA_LINKIP6}%${NSB_DEV} + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Device server" + done + + # verify TCP reset received + for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # local address tests + a=${NSA_IP6} + log_start + show_hint "Should fail 'Connection refused' since global server with VRF is disabled" + run_cmd nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "Global server, local connection" + + # + # enable VRF global server + # + log_subsection "VRF Global server enabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=1 + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Global server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "VRF server" + done + + # For LLA, child socket is bound to device + a=${NSA_LINKIP6}%${NSB_DEV} + log_start + run_cmd nettest -6 -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Global server" + + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "VRF server" + + for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 0 "Device server" + done + + # verify TCP reset received + for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # local address tests + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + show_hint "Fails 'No route to host' since client is not in VRF" + run_cmd nettest -6 -s -2 ${VRF} & + sleep 1 + run_cmd nettest -6 -r ${a} + log_test_addr ${a} $? 1 "Global server, local connection" + done + + + # + # client + # + for a in ${NSB_IP6} ${NSB_LO_IP6} + do + log_start + run_cmd_nsb nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${VRF} + log_test_addr ${a} $? 0 "Client, VRF bind" + done + + a=${NSB_LINKIP6} + log_start + show_hint "Fails since VRF device does not allow linklocal addresses" + run_cmd_nsb nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${VRF} + log_test_addr ${a} $? 1 "Client, VRF bind" + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6} + do + log_start + run_cmd_nsb nettest -6 -s & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 0 "Client, device bind" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -r ${a} -d ${VRF} + log_test_addr ${a} $? 1 "No server, VRF client" + done + + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6} + do + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + for a in ${NSA_IP6} ${VRF_IP6} ::1 + do + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${VRF} -0 ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a} + log_test_addr ${a} $? 0 "VRF server, device client, local connection" + + a=${NSA_IP6} + log_start + show_hint "Should fail since unbound client is out of VRF scope" + run_cmd nettest -6 -s -d ${VRF} & + sleep 1 + run_cmd nettest -6 -r ${a} + log_test_addr ${a} $? 1 "VRF server, unbound client, local connection" + + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${VRF} -0 ${a} + log_test_addr ${a} $? 0 "Device server, VRF client, local connection" + + for a in ${NSA_IP6} ${NSA_LINKIP6} + do + log_start + run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a} + log_test_addr ${a} $? 0 "Device server, device client, local connection" + done +} + +ipv6_tcp() +{ + log_section "IPv6/TCP" + log_subsection "No VRF" + setup + + # tcp_l3mdev_accept should have no affect without VRF; + # run tests with it enabled and disabled to verify + log_subsection "tcp_l3mdev_accept disabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + ipv6_tcp_novrf + log_subsection "tcp_l3mdev_accept enabled" + set_sysctl net.ipv4.tcp_l3mdev_accept=1 + ipv6_tcp_novrf + + log_subsection "With VRF" + setup "yes" + ipv6_tcp_vrf +} + +################################################################################ +# IPv6 UDP + +ipv6_udp_novrf() +{ + local a + + # + # server tests + # + for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + run_cmd nettest -6 -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Global server" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Device server" + done + + a=${NSA_LO_IP6} + log_start + run_cmd nettest -6 -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Global server" + + # should fail since loopback address is out of scope for a device + # bound server, but it does not - hence this is more documenting + # behavior. + #log_start + #show_hint "Should fail since loopback address is out of scope" + #run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + #sleep 1 + #run_cmd_nsb nettest -6 -D -r ${a} + #log_test_addr ${a} $? 1 "Device server" + + # negative test - should fail + for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV} + do + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # client + # + for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} + do + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -0 ${NSA_IP6} + log_test_addr ${a} $? 0 "Client" + + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -0 ${NSA_IP6} + log_test_addr ${a} $? 0 "Client, device bind" + + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -C -0 ${NSA_IP6} + log_test_addr ${a} $? 0 "Client, device send via cmsg" + + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -S -0 ${NSA_IP6} + log_test_addr ${a} $? 0 "Client, device bind via IPV6_UNICAST_IF" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "No server, unbound client" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "No server, device client" + done + + # + # local address tests + # + for a in ${NSA_IP6} ${NSA_LO_IP6} ::1 + do + log_start + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -0 ${a} -1 ${a} + log_test_addr ${a} $? 0 "Global server, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -D -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Device server, unbound client, local connection" + + for a in ${NSA_LO_IP6} ::1 + do + log_start + show_hint "Should fail 'Connection refused' since address is out of device scope" + run_cmd nettest -6 -s -D -d ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "Device server, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -D & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Global server, device client, local connection" + + log_start + run_cmd nettest -6 -s -D & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -C -r ${a} + log_test_addr ${a} $? 0 "Global server, device send via cmsg, local connection" + + log_start + run_cmd nettest -6 -s -D & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -S -r ${a} + log_test_addr ${a} $? 0 "Global server, device client via IPV6_UNICAST_IF, local connection" + + for a in ${NSA_LO_IP6} ::1 + do + log_start + show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} + log_test_addr ${a} $? 1 "Global server, device client, local connection" + + log_start + show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -C + log_test_addr ${a} $? 1 "Global server, device send via cmsg, local connection" + + log_start + show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -S + log_test_addr ${a} $? 1 "Global server, device client via IP_UNICAST_IF, local connection" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -D -s -d ${NSA_DEV} -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} -0 ${a} + log_test_addr ${a} $? 0 "Device server, device client, local conn" + + log_start + show_hint "Should fail 'Connection refused'" + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 1 "No server, device client, local conn" + + # LLA to GUA + run_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV} + run_cmd_nsb ip -6 ro add ${NSA_IP6}/128 dev ${NSB_DEV} + log_start + run_cmd nettest -6 -s -D & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${NSA_IP6} + log_test $? 0 "UDP in - LLA to GUA" + + run_cmd_nsb ip -6 ro del ${NSA_IP6}/128 dev ${NSB_DEV} + run_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV} nodad +} + +ipv6_udp_vrf() +{ + local a + + # disable global server + log_subsection "Global server disabled" + set_sysctl net.ipv4.udp_l3mdev_accept=0 + + # + # server tests + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + show_hint "Should fail 'Connection refused' since global server is disabled" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "Global server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "VRF server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server" + done + + # negative test - should fail + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + show_hint "Should fail 'Connection refused' since there is no server" + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # local address tests + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + show_hint "Should fail 'Connection refused' since global server is disabled" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 1 "Global server, VRF client, local conn" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${VRF} -s & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + done + + a=${NSA_IP6} + log_start + show_hint "Should fail 'Connection refused' since global server is disabled" + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 1 "Global server, device client, local conn" + + log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "VRF server, device client, local conn" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn" + + # disable global server + log_subsection "Global server enabled" + set_sysctl net.ipv4.udp_l3mdev_accept=1 + + # + # server tests + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Global server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "VRF server" + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 0 "Enslaved device server" + done + + # negative test - should fail + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd_nsb nettest -6 -D -r ${a} + log_test_addr ${a} $? 1 "No server" + done + + # + # client tests + # + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${NSB_IP6} + log_test $? 0 "VRF client" + + # negative test - should fail + log_start + run_cmd nettest -6 -D -d ${VRF} -r ${NSB_IP6} + log_test $? 1 "No server, VRF client" + + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_IP6} + log_test $? 0 "Enslaved device client" + + # negative test - should fail + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_IP6} + log_test $? 1 "No server, enslaved device client" + + # + # local address tests + # + a=${NSA_IP6} + log_start + run_cmd nettest -6 -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Global server, VRF client, local conn" + + #log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + + + a=${VRF_IP6} + log_start + run_cmd nettest -6 -D -s -2 ${VRF} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Global server, VRF client, local conn" + + log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${VRF} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "VRF server, VRF client, local conn" + + # negative test - should fail + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 1 "No server, VRF client, local conn" + done + + # device to global IP + a=${NSA_IP6} + log_start + run_cmd nettest -6 -D -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Global server, device client, local conn" + + log_start + run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "VRF server, device client, local conn" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${VRF} -r ${a} + log_test_addr ${a} $? 0 "Device server, VRF client, local conn" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 0 "Device server, device client, local conn" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} + log_test_addr ${a} $? 1 "No server, device client, local conn" + + + # link local addresses + log_start + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd_nsb nettest -6 -D -d ${NSB_DEV} -r ${NSA_LINKIP6} + log_test $? 0 "Global server, linklocal IP" + + log_start + run_cmd_nsb nettest -6 -D -d ${NSB_DEV} -r ${NSA_LINKIP6} + log_test $? 1 "No server, linklocal IP" + + + log_start + run_cmd_nsb nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_LINKIP6} + log_test $? 0 "Enslaved device client, linklocal IP" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_LINKIP6} + log_test $? 1 "No server, device client, peer linklocal IP" + + + log_start + run_cmd nettest -6 -D -s & + sleep 1 + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSA_LINKIP6} + log_test $? 0 "Enslaved device client, local conn - linklocal IP" + + log_start + run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSA_LINKIP6} + log_test $? 1 "No server, device client, local conn - linklocal IP" + + # LLA to GUA + run_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV} + run_cmd_nsb ip -6 ro add ${NSA_IP6}/128 dev ${NSB_DEV} + log_start + run_cmd nettest -6 -s -D & + sleep 1 + run_cmd_nsb nettest -6 -D -r ${NSA_IP6} + log_test $? 0 "UDP in - LLA to GUA" + + run_cmd_nsb ip -6 ro del ${NSA_IP6}/128 dev ${NSB_DEV} + run_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV} nodad +} + +ipv6_udp() +{ + # should not matter, but set to known state + set_sysctl net.ipv4.udp_early_demux=1 + + log_section "IPv6/UDP" + log_subsection "No VRF" + setup + + # udp_l3mdev_accept should have no affect without VRF; + # run tests with it enabled and disabled to verify + log_subsection "udp_l3mdev_accept disabled" + set_sysctl net.ipv4.udp_l3mdev_accept=0 + ipv6_udp_novrf + log_subsection "udp_l3mdev_accept enabled" + set_sysctl net.ipv4.udp_l3mdev_accept=1 + ipv6_udp_novrf + + log_subsection "With VRF" + setup "yes" + ipv6_udp_vrf +} + +################################################################################ +# IPv6 address bind + +ipv6_addr_bind_novrf() +{ + # + # raw socket + # + for a in ${NSA_IP6} ${NSA_LO_IP6} + do + log_start + run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address" + + log_start + run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${NSA_DEV} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind" + done + + # + # tcp sockets + # + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -l ${a} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address" + + log_start + run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind" + + a=${NSA_LO_IP6} + log_start + show_hint "Should fail with 'Cannot assign requested address'" + run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address" +} + +ipv6_addr_bind_vrf() +{ + # + # raw socket + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${VRF} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after vrf bind" + + log_start + run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${NSA_DEV} -b + log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind" + done + + a=${NSA_LO_IP6} + log_start + show_hint "Address on loopback is out of VRF scope" + run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${VRF} -b + log_test_addr ${a} $? 1 "Raw socket bind to invalid local address after vrf bind" + + # + # tcp sockets + # + # address on enslaved device is valid for the VRF or device in a VRF + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s -l ${a} -d ${VRF} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address with VRF bind" + done + + a=${NSA_IP6} + log_start + run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 0 "TCP socket bind to local address with device bind" + + a=${VRF_IP6} + log_start + run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to VRF address with device bind" + + a=${NSA_LO_IP6} + log_start + show_hint "Address on loopback out of scope for VRF" + run_cmd nettest -6 -s -l ${a} -d ${VRF} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for VRF" + + log_start + show_hint "Address on loopback out of scope for device in VRF" + run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b + log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for device bind" + +} + +ipv6_addr_bind() +{ + log_section "IPv6 address binds" + + log_subsection "No VRF" + setup + ipv6_addr_bind_novrf + + log_subsection "With VRF" + setup "yes" + ipv6_addr_bind_vrf +} + +################################################################################ +# IPv6 runtime tests + +ipv6_rt() +{ + local desc="$1" + local varg="-6 $2" + local with_vrf="yes" + local a + + # + # server tests + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server" + + setup ${with_vrf} + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest ${varg} -d ${VRF} -s & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server" + + setup ${with_vrf} + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest ${varg} -d ${NSA_DEV} -s & + sleep 1 + run_cmd_nsb nettest ${varg} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, enslaved device server" + + setup ${with_vrf} + done + + # + # client test + # + log_start + run_cmd_nsb nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${NSB_IP6} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test 0 0 "${desc}, VRF client" + + setup ${with_vrf} + + log_start + run_cmd_nsb nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${NSB_IP6} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test 0 0 "${desc}, enslaved device client" + + setup ${with_vrf} + + + # + # local address tests + # + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server, VRF client" + + setup ${with_vrf} + done + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest ${varg} -d ${VRF} -s & + sleep 1 + run_cmd nettest ${varg} -d ${VRF} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server and client" + + setup ${with_vrf} + done + + a=${NSA_IP6} + log_start + run_cmd nettest ${varg} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, global server, device client" + + setup ${with_vrf} + + log_start + run_cmd nettest ${varg} -d ${VRF} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, VRF server, device client" + + setup ${with_vrf} + + log_start + run_cmd nettest ${varg} -d ${NSA_DEV} -s & + sleep 1 + run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "${desc}, device server, device client" +} + +ipv6_ping_rt() +{ + local with_vrf="yes" + local a + + a=${NSA_IP6} + log_start + run_cmd_nsb ${ping6} -f ${a} & + sleep 3 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "Device delete with active traffic - ping in" + + setup ${with_vrf} + + log_start + run_cmd ${ping6} -f ${NSB_IP6} -I ${VRF} & + sleep 1 + run_cmd ip link del ${VRF} + sleep 1 + log_test_addr ${a} 0 0 "Device delete with active traffic - ping out" +} + +ipv6_runtime() +{ + log_section "Run time tests - ipv6" + + setup "yes" + ipv6_ping_rt + + setup "yes" + ipv6_rt "TCP active socket" "-n -1" + + setup "yes" + ipv6_rt "TCP passive socket" "-i" + + setup "yes" + ipv6_rt "UDP active socket" "-D -n -1" +} + +################################################################################ +# netfilter blocking connections + +netfilter_tcp_reset() +{ + local a + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest -s & + sleep 1 + run_cmd_nsb nettest -r ${a} + log_test_addr ${a} $? 1 "Global server, reject with TCP-reset on Rx" + done +} + +netfilter_icmp() +{ + local stype="$1" + local arg + local a + + [ "${stype}" = "UDP" ] && arg="-D" + + for a in ${NSA_IP} ${VRF_IP} + do + log_start + run_cmd nettest ${arg} -s & + sleep 1 + run_cmd_nsb nettest ${arg} -r ${a} + log_test_addr ${a} $? 1 "Global ${stype} server, Rx reject icmp-port-unreach" + done +} + +ipv4_netfilter() +{ + log_section "IPv4 Netfilter" + log_subsection "TCP reset" + + setup "yes" + run_cmd iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset + + netfilter_tcp_reset + + log_start + log_subsection "ICMP unreachable" + + log_start + run_cmd iptables -F + run_cmd iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-port-unreachable + run_cmd iptables -A INPUT -p udp --dport 12345 -j REJECT --reject-with icmp-port-unreachable + + netfilter_icmp "TCP" + netfilter_icmp "UDP" + + log_start + iptables -F +} + +netfilter_tcp6_reset() +{ + local a + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s & + sleep 1 + run_cmd_nsb nettest -6 -r ${a} + log_test_addr ${a} $? 1 "Global server, reject with TCP-reset on Rx" + done +} + +netfilter_icmp6() +{ + local stype="$1" + local arg + local a + + [ "${stype}" = "UDP" ] && arg="$arg -D" + + for a in ${NSA_IP6} ${VRF_IP6} + do + log_start + run_cmd nettest -6 -s ${arg} & + sleep 1 + run_cmd_nsb nettest -6 ${arg} -r ${a} + log_test_addr ${a} $? 1 "Global ${stype} server, Rx reject icmp-port-unreach" + done +} + +ipv6_netfilter() +{ + log_section "IPv6 Netfilter" + log_subsection "TCP reset" + + setup "yes" + run_cmd ip6tables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset + + netfilter_tcp6_reset + + log_subsection "ICMP unreachable" + + log_start + run_cmd ip6tables -F + run_cmd ip6tables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp6-port-unreachable + run_cmd ip6tables -A INPUT -p udp --dport 12345 -j REJECT --reject-with icmp6-port-unreachable + + netfilter_icmp6 "TCP" + netfilter_icmp6 "UDP" + + log_start + ip6tables -F +} + +################################################################################ +# specific use cases + +# VRF only. +# ns-A device enslaved to bridge. Verify traffic with and without +# br_netfilter module loaded. Repeat with SVI on bridge. +use_case_br() +{ + setup "yes" + + setup_cmd ip link set ${NSA_DEV} down + setup_cmd ip addr del dev ${NSA_DEV} ${NSA_IP}/24 + setup_cmd ip -6 addr del dev ${NSA_DEV} ${NSA_IP6}/64 + + setup_cmd ip link add br0 type bridge + setup_cmd ip addr add dev br0 ${NSA_IP}/24 + setup_cmd ip -6 addr add dev br0 ${NSA_IP6}/64 nodad + + setup_cmd ip li set ${NSA_DEV} master br0 + setup_cmd ip li set ${NSA_DEV} up + setup_cmd ip li set br0 up + setup_cmd ip li set br0 vrf ${VRF} + + rmmod br_netfilter 2>/dev/null + sleep 5 # DAD + + run_cmd ip neigh flush all + run_cmd ping -c1 -w1 -I br0 ${NSB_IP} + log_test $? 0 "Bridge into VRF - IPv4 ping out" + + run_cmd ip neigh flush all + run_cmd ${ping6} -c1 -w1 -I br0 ${NSB_IP6} + log_test $? 0 "Bridge into VRF - IPv6 ping out" + + run_cmd ip neigh flush all + run_cmd_nsb ping -c1 -w1 ${NSA_IP} + log_test $? 0 "Bridge into VRF - IPv4 ping in" + + run_cmd ip neigh flush all + run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6} + log_test $? 0 "Bridge into VRF - IPv6 ping in" + + modprobe br_netfilter + if [ $? -eq 0 ]; then + run_cmd ip neigh flush all + run_cmd ping -c1 -w1 -I br0 ${NSB_IP} + log_test $? 0 "Bridge into VRF with br_netfilter - IPv4 ping out" + + run_cmd ip neigh flush all + run_cmd ${ping6} -c1 -w1 -I br0 ${NSB_IP6} + log_test $? 0 "Bridge into VRF with br_netfilter - IPv6 ping out" + + run_cmd ip neigh flush all + run_cmd_nsb ping -c1 -w1 ${NSA_IP} + log_test $? 0 "Bridge into VRF with br_netfilter - IPv4 ping in" + + run_cmd ip neigh flush all + run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6} + log_test $? 0 "Bridge into VRF with br_netfilter - IPv6 ping in" + fi + + setup_cmd ip li set br0 nomaster + setup_cmd ip li add br0.100 link br0 type vlan id 100 + setup_cmd ip li set br0.100 vrf ${VRF} up + setup_cmd ip addr add dev br0.100 172.16.101.1/24 + setup_cmd ip -6 addr add dev br0.100 2001:db8:101::1/64 nodad + + setup_cmd_nsb ip li add vlan100 link ${NSB_DEV} type vlan id 100 + setup_cmd_nsb ip addr add dev vlan100 172.16.101.2/24 + setup_cmd_nsb ip -6 addr add dev vlan100 2001:db8:101::2/64 nodad + setup_cmd_nsb ip li set vlan100 up + sleep 1 + + rmmod br_netfilter 2>/dev/null + + run_cmd ip neigh flush all + run_cmd ping -c1 -w1 -I br0.100 172.16.101.2 + log_test $? 0 "Bridge vlan into VRF - IPv4 ping out" + + run_cmd ip neigh flush all + run_cmd ${ping6} -c1 -w1 -I br0.100 2001:db8:101::2 + log_test $? 0 "Bridge vlan into VRF - IPv6 ping out" + + run_cmd ip neigh flush all + run_cmd_nsb ping -c1 -w1 172.16.101.1 + log_test $? 0 "Bridge vlan into VRF - IPv4 ping in" + + run_cmd ip neigh flush all + run_cmd_nsb ${ping6} -c1 -w1 2001:db8:101::1 + log_test $? 0 "Bridge vlan into VRF - IPv6 ping in" + + modprobe br_netfilter + if [ $? -eq 0 ]; then + run_cmd ip neigh flush all + run_cmd ping -c1 -w1 -I br0.100 172.16.101.2 + log_test $? 0 "Bridge vlan into VRF with br_netfilter - IPv4 ping out" + + run_cmd ip neigh flush all + run_cmd ${ping6} -c1 -w1 -I br0.100 2001:db8:101::2 + log_test $? 0 "Bridge vlan into VRF with br_netfilter - IPv6 ping out" + + run_cmd ip neigh flush all + run_cmd_nsb ping -c1 -w1 172.16.101.1 + log_test $? 0 "Bridge vlan into VRF - IPv4 ping in" + + run_cmd ip neigh flush all + run_cmd_nsb ${ping6} -c1 -w1 2001:db8:101::1 + log_test $? 0 "Bridge vlan into VRF - IPv6 ping in" + fi + + setup_cmd ip li del br0 2>/dev/null + setup_cmd_nsb ip li del vlan100 2>/dev/null +} + +use_cases() +{ + log_section "Use cases" + use_case_br +} + +################################################################################ +# usage + +usage() +{ + cat <<EOF +usage: ${0##*/} OPTS + + -4 IPv4 tests only + -6 IPv6 tests only + -t <test> Test name/set to run + -p Pause on fail + -P Pause after each test + -v Be verbose +EOF +} + +################################################################################ +# main + +TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime ipv4_netfilter" +TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime ipv6_netfilter" +TESTS_OTHER="use_cases" + +PAUSE_ON_FAIL=no +PAUSE=no + +while getopts :46t:pPvh o +do + case $o in + 4) TESTS=ipv4;; + 6) TESTS=ipv6;; + t) TESTS=$OPTARG;; + p) PAUSE_ON_FAIL=yes;; + P) PAUSE=yes;; + v) VERBOSE=1;; + h) usage; exit 0;; + *) usage; exit 1;; + esac +done + +# make sure we don't pause twice +[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no + +# +# show user test config +# +if [ -z "$TESTS" ]; then + TESTS="$TESTS_IPV4 $TESTS_IPV6 $TESTS_OTHER" +elif [ "$TESTS" = "ipv4" ]; then + TESTS="$TESTS_IPV4" +elif [ "$TESTS" = "ipv6" ]; then + TESTS="$TESTS_IPV6" +fi + +which nettest >/dev/null +if [ $? -ne 0 ]; then + echo "'nettest' command not found; skipping tests" + exit 0 +fi + +declare -i nfail=0 +declare -i nsuccess=0 + +for t in $TESTS +do + case $t in + ipv4_ping|ping) ipv4_ping;; + ipv4_tcp|tcp) ipv4_tcp;; + ipv4_udp|udp) ipv4_udp;; + ipv4_bind|bind) ipv4_addr_bind;; + ipv4_runtime) ipv4_runtime;; + ipv4_netfilter) ipv4_netfilter;; + + ipv6_ping|ping6) ipv6_ping;; + ipv6_tcp|tcp6) ipv6_tcp;; + ipv6_udp|udp6) ipv6_udp;; + ipv6_bind|bind6) ipv6_addr_bind;; + ipv6_runtime) ipv6_runtime;; + ipv6_netfilter) ipv6_netfilter;; + + use_cases) use_cases;; + + # setup namespaces and config, but do not run any tests + setup) setup; exit 0;; + vrf_setup) setup "yes"; exit 0;; + + help) echo "Test names: $TESTS"; exit 0;; + esac +done + +cleanup 2>/dev/null + +printf "\nTests passed: %3d\n" ${nsuccess} +printf "Tests failed: %3d\n" ${nfail} diff --git a/tools/testing/selftests/net/forwarding/gre_multipath.sh b/tools/testing/selftests/net/forwarding/gre_multipath.sh index cca2baa03fb8..a8d8e8b3dc81 100755 --- a/tools/testing/selftests/net/forwarding/gre_multipath.sh +++ b/tools/testing/selftests/net/forwarding/gre_multipath.sh @@ -93,18 +93,10 @@ sw1_create() ip route add vrf v$ol1 192.0.2.16/28 \ nexthop dev g1a \ nexthop dev g1b - - tc qdisc add dev $ul1 clsact - tc filter add dev $ul1 egress pref 111 prot ipv4 \ - flower dst_ip 192.0.2.66 action pass - tc filter add dev $ul1 egress pref 222 prot ipv4 \ - flower dst_ip 192.0.2.82 action pass } sw1_destroy() { - tc qdisc del dev $ul1 clsact - ip route del vrf v$ol1 192.0.2.16/28 ip route del vrf v$ol1 192.0.2.82/32 via 192.0.2.146 @@ -139,10 +131,18 @@ sw2_create() ip route add vrf v$ol2 192.0.2.0/28 \ nexthop dev g2a \ nexthop dev g2b + + tc qdisc add dev $ul2 clsact + tc filter add dev $ul2 ingress pref 111 prot 802.1Q \ + flower vlan_id 111 action pass + tc filter add dev $ul2 ingress pref 222 prot 802.1Q \ + flower vlan_id 222 action pass } sw2_destroy() { + tc qdisc del dev $ul2 clsact + ip route del vrf v$ol2 192.0.2.0/28 ip route del vrf v$ol2 192.0.2.81/32 via 192.0.2.145 @@ -187,12 +187,16 @@ setup_prepare() sw1_create sw2_create h2_create + + forwarding_enable } cleanup() { pre_cleanup + forwarding_restore + h2_destroy sw2_destroy sw1_destroy @@ -211,15 +215,15 @@ multipath4_test() nexthop dev g1a weight $weight1 \ nexthop dev g1b weight $weight2 - local t0_111=$(tc_rule_stats_get $ul1 111 egress) - local t0_222=$(tc_rule_stats_get $ul1 222 egress) + local t0_111=$(tc_rule_stats_get $ul2 111 ingress) + local t0_222=$(tc_rule_stats_get $ul2 222 ingress) ip vrf exec v$h1 \ $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \ -d 1msec -t udp "sp=1024,dp=0-32768" - local t1_111=$(tc_rule_stats_get $ul1 111 egress) - local t1_222=$(tc_rule_stats_get $ul1 222 egress) + local t1_111=$(tc_rule_stats_get $ul2 111 ingress) + local t1_222=$(tc_rule_stats_get $ul2 222 ingress) local d111=$((t1_111 - t0_111)) local d222=$((t1_222 - t0_222)) diff --git a/tools/testing/selftests/net/l2tp.sh b/tools/testing/selftests/net/l2tp.sh new file mode 100644 index 000000000000..5782433886fc --- /dev/null +++ b/tools/testing/selftests/net/l2tp.sh @@ -0,0 +1,382 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# L2TPv3 tunnel between 2 hosts +# +# host-1 | router | host-2 +# | | +# lo l2tp | | l2tp lo +# 172.16.101.1 172.16.1.1 | | 172.16.1.2 172.16.101.2 +# fc00:101::1 fc00:1::1 | | fc00:1::2 fc00:101::2 +# | | +# eth0 | | eth0 +# 10.1.1.1 | | 10.1.2.1 +# 2001:db8:1::1 | | 2001:db8:2::1 + +VERBOSE=0 +PAUSE_ON_FAIL=no + +which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) + +################################################################################ +# +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + printf "TEST: %-60s [ OK ]\n" "${msg}" + nsuccess=$((nsuccess+1)) + else + ret=1 + nfail=$((nfail+1)) + printf "TEST: %-60s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi +} + +run_cmd() +{ + local ns + local cmd + local out + local rc + + ns="$1" + shift + cmd="$*" + + if [ "$VERBOSE" = "1" ]; then + printf " COMMAND: $cmd\n" + fi + + out=$(eval ip netns exec ${ns} ${cmd} 2>&1) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + + [ "$VERBOSE" = "1" ] && echo + + return $rc +} + +################################################################################ +# create namespaces and interconnects + +create_ns() +{ + local ns=$1 + local addr=$2 + local addr6=$3 + + [ -z "${addr}" ] && addr="-" + [ -z "${addr6}" ] && addr6="-" + + ip netns add ${ns} + + ip -netns ${ns} link set lo up + if [ "${addr}" != "-" ]; then + ip -netns ${ns} addr add dev lo ${addr} + fi + if [ "${addr6}" != "-" ]; then + ip -netns ${ns} -6 addr add dev lo ${addr6} + fi + + ip -netns ${ns} ro add unreachable default metric 8192 + ip -netns ${ns} -6 ro add unreachable default metric 8192 + + ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1 + ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.accept_dad=0 +} + +# create veth pair to connect namespaces and apply addresses. +connect_ns() +{ + local ns1=$1 + local ns1_dev=$2 + local ns1_addr=$3 + local ns1_addr6=$4 + local ns2=$5 + local ns2_dev=$6 + local ns2_addr=$7 + local ns2_addr6=$8 + + ip -netns ${ns1} li add ${ns1_dev} type veth peer name tmp + ip -netns ${ns1} li set ${ns1_dev} up + ip -netns ${ns1} li set tmp netns ${ns2} name ${ns2_dev} + ip -netns ${ns2} li set ${ns2_dev} up + + if [ "${ns1_addr}" != "-" ]; then + ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr} + ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr} + fi + + if [ "${ns1_addr6}" != "-" ]; then + ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr6} + ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr6} + fi +} + +################################################################################ +# test setup + +cleanup() +{ + local ns + + for ns in host-1 host-2 router + do + ip netns del ${ns} 2>/dev/null + done +} + +setup_l2tp_ipv4() +{ + # + # configure l2tpv3 tunnel on host-1 + # + ip -netns host-1 l2tp add tunnel tunnel_id 1041 peer_tunnel_id 1042 \ + encap ip local 10.1.1.1 remote 10.1.2.1 + ip -netns host-1 l2tp add session name l2tp4 tunnel_id 1041 \ + session_id 1041 peer_session_id 1042 + ip -netns host-1 link set dev l2tp4 up + ip -netns host-1 addr add dev l2tp4 172.16.1.1 peer 172.16.1.2 + + # + # configure l2tpv3 tunnel on host-2 + # + ip -netns host-2 l2tp add tunnel tunnel_id 1042 peer_tunnel_id 1041 \ + encap ip local 10.1.2.1 remote 10.1.1.1 + ip -netns host-2 l2tp add session name l2tp4 tunnel_id 1042 \ + session_id 1042 peer_session_id 1041 + ip -netns host-2 link set dev l2tp4 up + ip -netns host-2 addr add dev l2tp4 172.16.1.2 peer 172.16.1.1 + + # + # add routes to loopback addresses + # + ip -netns host-1 ro add 172.16.101.2/32 via 172.16.1.2 + ip -netns host-2 ro add 172.16.101.1/32 via 172.16.1.1 +} + +setup_l2tp_ipv6() +{ + # + # configure l2tpv3 tunnel on host-1 + # + ip -netns host-1 l2tp add tunnel tunnel_id 1061 peer_tunnel_id 1062 \ + encap ip local 2001:db8:1::1 remote 2001:db8:2::1 + ip -netns host-1 l2tp add session name l2tp6 tunnel_id 1061 \ + session_id 1061 peer_session_id 1062 + ip -netns host-1 link set dev l2tp6 up + ip -netns host-1 addr add dev l2tp6 fc00:1::1 peer fc00:1::2 + + # + # configure l2tpv3 tunnel on host-2 + # + ip -netns host-2 l2tp add tunnel tunnel_id 1062 peer_tunnel_id 1061 \ + encap ip local 2001:db8:2::1 remote 2001:db8:1::1 + ip -netns host-2 l2tp add session name l2tp6 tunnel_id 1062 \ + session_id 1062 peer_session_id 1061 + ip -netns host-2 link set dev l2tp6 up + ip -netns host-2 addr add dev l2tp6 fc00:1::2 peer fc00:1::1 + + # + # add routes to loopback addresses + # + ip -netns host-1 -6 ro add fc00:101::2/128 via fc00:1::2 + ip -netns host-2 -6 ro add fc00:101::1/128 via fc00:1::1 +} + +setup() +{ + # start clean + cleanup + + set -e + create_ns host-1 172.16.101.1/32 fc00:101::1/128 + create_ns host-2 172.16.101.2/32 fc00:101::2/128 + create_ns router + + connect_ns host-1 eth0 10.1.1.1/24 2001:db8:1::1/64 \ + router eth1 10.1.1.2/24 2001:db8:1::2/64 + + connect_ns host-2 eth0 10.1.2.1/24 2001:db8:2::1/64 \ + router eth2 10.1.2.2/24 2001:db8:2::2/64 + + ip -netns host-1 ro add 10.1.2.0/24 via 10.1.1.2 + ip -netns host-1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2 + + ip -netns host-2 ro add 10.1.1.0/24 via 10.1.2.2 + ip -netns host-2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2 + + setup_l2tp_ipv4 + setup_l2tp_ipv6 + set +e +} + +setup_ipsec() +{ + # + # IPv4 + # + run_cmd host-1 ip xfrm policy add \ + src 10.1.1.1 dst 10.1.2.1 dir out \ + tmpl proto esp mode transport + + run_cmd host-1 ip xfrm policy add \ + src 10.1.2.1 dst 10.1.1.1 dir in \ + tmpl proto esp mode transport + + run_cmd host-2 ip xfrm policy add \ + src 10.1.1.1 dst 10.1.2.1 dir in \ + tmpl proto esp mode transport + + run_cmd host-2 ip xfrm policy add \ + src 10.1.2.1 dst 10.1.1.1 dir out \ + tmpl proto esp mode transport + + ip -netns host-1 xfrm state add \ + src 10.1.1.1 dst 10.1.2.1 \ + spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-1 xfrm state add \ + src 10.1.2.1 dst 10.1.1.1 \ + spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-2 xfrm state add \ + src 10.1.1.1 dst 10.1.2.1 \ + spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-2 xfrm state add \ + src 10.1.2.1 dst 10.1.1.1 \ + spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + # + # IPV6 + # + run_cmd host-1 ip -6 xfrm policy add \ + src 2001:db8:1::1 dst 2001:db8:2::1 dir out \ + tmpl proto esp mode transport + + run_cmd host-1 ip -6 xfrm policy add \ + src 2001:db8:2::1 dst 2001:db8:1::1 dir in \ + tmpl proto esp mode transport + + run_cmd host-2 ip -6 xfrm policy add \ + src 2001:db8:1::1 dst 2001:db8:2::1 dir in \ + tmpl proto esp mode transport + + run_cmd host-2 ip -6 xfrm policy add \ + src 2001:db8:2::1 dst 2001:db8:1::1 dir out \ + tmpl proto esp mode transport + + ip -netns host-1 -6 xfrm state add \ + src 2001:db8:1::1 dst 2001:db8:2::1 \ + spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-1 -6 xfrm state add \ + src 2001:db8:2::1 dst 2001:db8:1::1 \ + spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-2 -6 xfrm state add \ + src 2001:db8:1::1 dst 2001:db8:2::1 \ + spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport + + ip -netns host-2 -6 xfrm state add \ + src 2001:db8:2::1 dst 2001:db8:1::1 \ + spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \ + 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport +} + +teardown_ipsec() +{ + run_cmd host-1 ip xfrm state flush + run_cmd host-1 ip xfrm policy flush + run_cmd host-2 ip xfrm state flush + run_cmd host-2 ip xfrm policy flush +} + +################################################################################ +# generate traffic through tunnel for various cases + +run_ping() +{ + local desc="$1" + + run_cmd host-1 ping -c1 -w1 172.16.1.2 + log_test $? 0 "IPv4 basic L2TP tunnel ${desc}" + + run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 + log_test $? 0 "IPv4 route through L2TP tunnel ${desc}" + + run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2 + log_test $? 0 "IPv6 basic L2TP tunnel ${desc}" + + run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 + log_test $? 0 "IPv6 route through L2TP tunnel ${desc}" +} + +run_tests() +{ + local desc + + setup + run_ping + + setup_ipsec + run_ping "- with IPsec" + run_cmd host-1 ping -c1 -w1 172.16.1.2 + log_test $? 0 "IPv4 basic L2TP tunnel ${desc}" + + run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2 + log_test $? 0 "IPv4 route through L2TP tunnel ${desc}" + + run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2 + log_test $? 0 "IPv6 basic L2TP tunnel - with IPsec" + + run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2 + log_test $? 0 "IPv6 route through L2TP tunnel - with IPsec" + + teardown_ipsec + run_ping "- after IPsec teardown" +} + +################################################################################ +# main + +declare -i nfail=0 +declare -i nsuccess=0 + +while getopts :pv o +do + case $o in + p) PAUSE_ON_FAIL=yes;; + v) VERBOSE=$(($VERBOSE + 1));; + *) exit 1;; + esac +done + +run_tests +cleanup + +printf "\nTests passed: %3d\n" ${nsuccess} +printf "Tests failed: %3d\n" ${nfail} diff --git a/tools/testing/selftests/net/nettest.c b/tools/testing/selftests/net/nettest.c new file mode 100644 index 000000000000..83515e5ea4dc --- /dev/null +++ b/tools/testing/selftests/net/nettest.c @@ -0,0 +1,1756 @@ +// SPDX-License-Identifier: GPL-2.0 +/* nettest - used for functional tests of networking APIs + * + * Copyright (c) 2013-2019 David Ahern <dsahern@gmail.com>. All rights reserved. + */ + +#define _GNU_SOURCE +#include <features.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <linux/tcp.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> + +#ifndef IPV6_UNICAST_IF +#define IPV6_UNICAST_IF 76 +#endif +#ifndef IPV6_MULTICAST_IF +#define IPV6_MULTICAST_IF 17 +#endif + +#define DEFAULT_PORT 12345 + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +struct sock_args { + /* local address */ + union { + struct in_addr in; + struct in6_addr in6; + } local_addr; + + /* remote address */ + union { + struct in_addr in; + struct in6_addr in6; + } remote_addr; + int scope_id; /* remote scope; v6 send only */ + + struct in_addr grp; /* multicast group */ + + unsigned int has_local_ip:1, + has_remote_ip:1, + has_grp:1, + has_expected_laddr:1, + has_expected_raddr:1, + bind_test_only:1; + + unsigned short port; + + int type; /* DGRAM, STREAM, RAW */ + int protocol; + int version; /* AF_INET/AF_INET6 */ + + int use_setsockopt; + int use_cmsg; + const char *dev; + int ifindex; + const char *password; + + /* expected addresses and device index for connection */ + int expected_ifindex; + + /* local address */ + union { + struct in_addr in; + struct in6_addr in6; + } expected_laddr; + + /* remote address */ + union { + struct in_addr in; + struct in6_addr in6; + } expected_raddr; +}; + +static int server_mode; +static unsigned int prog_timeout = 5; +static unsigned int interactive; +static int iter = 1; +static char *msg = "Hello world!"; +static int msglen; +static int quiet; +static int try_broadcast = 1; + +static char *timestamp(char *timebuf, int buflen) +{ + time_t now; + + now = time(NULL); + if (strftime(timebuf, buflen, "%T", localtime(&now)) == 0) { + memset(timebuf, 0, buflen); + strncpy(timebuf, "00:00:00", buflen-1); + } + + return timebuf; +} + +static void log_msg(const char *format, ...) +{ + char timebuf[64]; + va_list args; + + if (quiet) + return; + + fprintf(stdout, "%s %s:", + timestamp(timebuf, sizeof(timebuf)), + server_mode ? "server" : "client"); + va_start(args, format); + vfprintf(stdout, format, args); + va_end(args); + + fflush(stdout); +} + +static void log_error(const char *format, ...) +{ + char timebuf[64]; + va_list args; + + if (quiet) + return; + + fprintf(stderr, "%s %s:", + timestamp(timebuf, sizeof(timebuf)), + server_mode ? "server" : "client"); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + fflush(stderr); +} + +static void log_err_errno(const char *fmt, ...) +{ + char timebuf[64]; + va_list args; + + if (quiet) + return; + + fprintf(stderr, "%s %s: ", + timestamp(timebuf, sizeof(timebuf)), + server_mode ? "server" : "client"); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + fprintf(stderr, ": %d: %s\n", errno, strerror(errno)); + fflush(stderr); +} + +static void log_address(const char *desc, struct sockaddr *sa) +{ + char addrstr[64]; + + if (quiet) + return; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *) sa; + + log_msg("%s %s:%d", + desc, + inet_ntop(AF_INET, &s->sin_addr, addrstr, + sizeof(addrstr)), + ntohs(s->sin_port)); + + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; + + log_msg("%s [%s]:%d", + desc, + inet_ntop(AF_INET6, &s6->sin6_addr, addrstr, + sizeof(addrstr)), + ntohs(s6->sin6_port)); + } + + printf("\n"); + + fflush(stdout); +} + +static int tcp_md5sig(int sd, void *addr, socklen_t alen, const char *password) +{ + struct tcp_md5sig md5sig; + int keylen = password ? strlen(password) : 0; + int rc; + + memset(&md5sig, 0, sizeof(md5sig)); + memcpy(&md5sig.tcpm_addr, addr, alen); + md5sig.tcpm_keylen = keylen; + + if (keylen) + memcpy(md5sig.tcpm_key, password, keylen); + + rc = setsockopt(sd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)); + if (rc < 0) { + /* ENOENT is harmless. Returned when a password is cleared */ + if (errno == ENOENT) + rc = 0; + else + log_err_errno("setsockopt(TCP_MD5SIG)"); + } + + return rc; +} + +static int tcp_md5_remote(int sd, struct sock_args *args) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + }; + void *addr; + int alen; + + switch (args->version) { + case AF_INET: + sin.sin_port = htons(args->port); + sin.sin_addr = args->remote_addr.in; + addr = &sin; + alen = sizeof(sin); + break; + case AF_INET6: + sin6.sin6_port = htons(args->port); + sin6.sin6_addr = args->remote_addr.in6; + addr = &sin6; + alen = sizeof(sin6); + break; + default: + log_error("unknown address family\n"); + exit(1); + } + + if (tcp_md5sig(sd, addr, alen, args->password)) + return -1; + + return 0; +} + +static int get_ifidx(const char *ifname) +{ + struct ifreq ifdata; + int sd, rc; + + if (!ifname || *ifname == '\0') + return 0; + + memset(&ifdata, 0, sizeof(ifdata)); + + strcpy(ifdata.ifr_name, ifname); + + sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + log_err_errno("socket failed"); + return 0; + } + + rc = ioctl(sd, SIOCGIFINDEX, (char *)&ifdata); + close(sd); + if (rc != 0) { + log_err_errno("ioctl(SIOCGIFINDEX) failed"); + return 0; + } + + return ifdata.ifr_ifindex; +} + +static int bind_to_device(int sd, const char *name) +{ + int rc; + + rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1); + if (rc < 0) + log_err_errno("setsockopt(SO_BINDTODEVICE)"); + + return rc; +} + +static int get_bind_to_device(int sd, char *name, size_t len) +{ + int rc; + socklen_t optlen = len; + + name[0] = '\0'; + rc = getsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, &optlen); + if (rc < 0) + log_err_errno("setsockopt(SO_BINDTODEVICE)"); + + return rc; +} + +static int check_device(int sd, struct sock_args *args) +{ + int ifindex = 0; + char name[32]; + + if (get_bind_to_device(sd, name, sizeof(name))) + *name = '\0'; + else + ifindex = get_ifidx(name); + + log_msg(" bound to device %s/%d\n", + *name ? name : "<none>", ifindex); + + if (!args->expected_ifindex) + return 0; + + if (args->expected_ifindex != ifindex) { + log_error("Device index mismatch: expected %d have %d\n", + args->expected_ifindex, ifindex); + return 1; + } + + log_msg("Device index matches: expected %d have %d\n", + args->expected_ifindex, ifindex); + + return 0; +} + +static int set_pktinfo_v4(int sd) +{ + int one = 1; + int rc; + + rc = setsockopt(sd, SOL_IP, IP_PKTINFO, &one, sizeof(one)); + if (rc < 0 && rc != -ENOTSUP) + log_err_errno("setsockopt(IP_PKTINFO)"); + + return rc; +} + +static int set_recvpktinfo_v6(int sd) +{ + int one = 1; + int rc; + + rc = setsockopt(sd, SOL_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + if (rc < 0 && rc != -ENOTSUP) + log_err_errno("setsockopt(IPV6_RECVPKTINFO)"); + + return rc; +} + +static int set_recverr_v4(int sd) +{ + int one = 1; + int rc; + + rc = setsockopt(sd, SOL_IP, IP_RECVERR, &one, sizeof(one)); + if (rc < 0 && rc != -ENOTSUP) + log_err_errno("setsockopt(IP_RECVERR)"); + + return rc; +} + +static int set_recverr_v6(int sd) +{ + int one = 1; + int rc; + + rc = setsockopt(sd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)); + if (rc < 0 && rc != -ENOTSUP) + log_err_errno("setsockopt(IPV6_RECVERR)"); + + return rc; +} + +static int set_unicast_if(int sd, int ifindex, int version) +{ + int opt = IP_UNICAST_IF; + int level = SOL_IP; + int rc; + + ifindex = htonl(ifindex); + + if (version == AF_INET6) { + opt = IPV6_UNICAST_IF; + level = SOL_IPV6; + } + rc = setsockopt(sd, level, opt, &ifindex, sizeof(ifindex)); + if (rc < 0) + log_err_errno("setsockopt(IP_UNICAST_IF)"); + + return rc; +} + +static int set_multicast_if(int sd, int ifindex) +{ + struct ip_mreqn mreq = { .imr_ifindex = ifindex }; + int rc; + + rc = setsockopt(sd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)); + if (rc < 0) + log_err_errno("setsockopt(IP_MULTICAST_IF)"); + + return rc; +} + +static int set_membership(int sd, uint32_t grp, uint32_t addr, const char *dev) +{ + uint32_t if_addr = addr; + struct ip_mreqn mreq; + int rc; + + if (addr == htonl(INADDR_ANY) && !dev) { + log_error("Either local address or device needs to be given for multicast membership\n"); + return -1; + } + + mreq.imr_multiaddr.s_addr = grp; + mreq.imr_address.s_addr = if_addr; + mreq.imr_ifindex = dev ? get_ifidx(dev) : 0; + + rc = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (rc < 0) { + log_err_errno("setsockopt(IP_ADD_MEMBERSHIP)"); + return -1; + } + + return 0; +} + +static int set_broadcast(int sd) +{ + unsigned int one = 1; + int rc = 0; + + if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) != 0) { + log_err_errno("setsockopt(SO_BROADCAST)"); + rc = -1; + } + + return rc; +} + +static int set_reuseport(int sd) +{ + unsigned int one = 1; + int rc = 0; + + if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != 0) { + log_err_errno("setsockopt(SO_REUSEPORT)"); + rc = -1; + } + + return rc; +} + +static int set_reuseaddr(int sd) +{ + unsigned int one = 1; + int rc = 0; + + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) { + log_err_errno("setsockopt(SO_REUSEADDR)"); + rc = -1; + } + + return rc; +} + +static int str_to_uint(const char *str, int min, int max, unsigned int *value) +{ + int number; + char *end; + + errno = 0; + number = (unsigned int) strtoul(str, &end, 0); + + /* entire string should be consumed by conversion + * and value should be between min and max + */ + if (((*end == '\0') || (*end == '\n')) && (end != str) && + (errno != ERANGE) && (min <= number) && (number <= max)) { + *value = number; + return 0; + } + + return -1; +} + +static int expected_addr_match(struct sockaddr *sa, void *expected, + const char *desc) +{ + char addrstr[64]; + int rc = 0; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *) sa; + struct in_addr *exp_in = (struct in_addr *) expected; + + if (s->sin_addr.s_addr != exp_in->s_addr) { + log_error("%s address does not match expected %s", + desc, + inet_ntop(AF_INET, exp_in, + addrstr, sizeof(addrstr))); + rc = 1; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; + struct in6_addr *exp_in = (struct in6_addr *) expected; + + if (memcmp(&s6->sin6_addr, exp_in, sizeof(*exp_in))) { + log_error("%s address does not match expected %s", + desc, + inet_ntop(AF_INET6, exp_in, + addrstr, sizeof(addrstr))); + rc = 1; + } + } else { + log_error("%s address does not match expected - unknown family", + desc); + rc = 1; + } + + if (!rc) + log_msg("%s address matches expected\n", desc); + + return rc; +} + +static int show_sockstat(int sd, struct sock_args *args) +{ + struct sockaddr_in6 local_addr, remote_addr; + socklen_t alen = sizeof(local_addr); + struct sockaddr *sa; + const char *desc; + int rc = 0; + + desc = server_mode ? "server local:" : "client local:"; + sa = (struct sockaddr *) &local_addr; + if (getsockname(sd, sa, &alen) == 0) { + log_address(desc, sa); + + if (args->has_expected_laddr) { + rc = expected_addr_match(sa, &args->expected_laddr, + "local"); + } + } else { + log_err_errno("getsockname failed"); + } + + sa = (struct sockaddr *) &remote_addr; + desc = server_mode ? "server peer:" : "client peer:"; + if (getpeername(sd, sa, &alen) == 0) { + log_address(desc, sa); + + if (args->has_expected_raddr) { + rc |= expected_addr_match(sa, &args->expected_raddr, + "remote"); + } + } else { + log_err_errno("getpeername failed"); + } + + return rc; +} + +static int get_index_from_cmsg(struct msghdr *m) +{ + struct cmsghdr *cm; + int ifindex = 0; + char buf[64]; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(m); + m->msg_controllen != 0 && cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(m, cm)) { + + if (cm->cmsg_level == SOL_IP && + cm->cmsg_type == IP_PKTINFO) { + struct in_pktinfo *pi; + + pi = (struct in_pktinfo *)(CMSG_DATA(cm)); + inet_ntop(AF_INET, &pi->ipi_addr, buf, sizeof(buf)); + ifindex = pi->ipi_ifindex; + } else if (cm->cmsg_level == SOL_IPV6 && + cm->cmsg_type == IPV6_PKTINFO) { + struct in6_pktinfo *pi6; + + pi6 = (struct in6_pktinfo *)(CMSG_DATA(cm)); + inet_ntop(AF_INET6, &pi6->ipi6_addr, buf, sizeof(buf)); + ifindex = pi6->ipi6_ifindex; + } + } + + if (ifindex) { + log_msg(" pktinfo: ifindex %d dest addr %s\n", + ifindex, buf); + } + return ifindex; +} + +static int send_msg_no_cmsg(int sd, void *addr, socklen_t alen) +{ + int err; + +again: + err = sendto(sd, msg, msglen, 0, addr, alen); + if (err < 0) { + if (errno == EACCES && try_broadcast) { + try_broadcast = 0; + if (!set_broadcast(sd)) + goto again; + errno = EACCES; + } + + log_err_errno("sendto failed"); + return 1; + } + + return 0; +} + +static int send_msg_cmsg(int sd, void *addr, socklen_t alen, + int ifindex, int version) +{ + unsigned char cmsgbuf[64]; + struct iovec iov[2]; + struct cmsghdr *cm; + struct msghdr m; + int err; + + iov[0].iov_base = msg; + iov[0].iov_len = msglen; + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_name = (caddr_t)addr; + m.msg_namelen = alen; + + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + + if (version == AF_INET) { + struct in_pktinfo *pi; + + cm->cmsg_level = SOL_IP; + cm->cmsg_type = IP_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + pi = (struct in_pktinfo *)(CMSG_DATA(cm)); + pi->ipi_ifindex = ifindex; + + m.msg_controllen = cm->cmsg_len; + + } else if (version == AF_INET6) { + struct in6_pktinfo *pi6; + + cm->cmsg_level = SOL_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + pi6 = (struct in6_pktinfo *)(CMSG_DATA(cm)); + pi6->ipi6_ifindex = ifindex; + + m.msg_controllen = cm->cmsg_len; + } + +again: + err = sendmsg(sd, &m, 0); + if (err < 0) { + if (errno == EACCES && try_broadcast) { + try_broadcast = 0; + if (!set_broadcast(sd)) + goto again; + errno = EACCES; + } + + log_err_errno("sendmsg failed"); + return 1; + } + + return 0; +} + + +static int send_msg(int sd, void *addr, socklen_t alen, struct sock_args *args) +{ + if (args->type == SOCK_STREAM) { + if (write(sd, msg, msglen) < 0) { + log_err_errno("write failed sending msg to peer"); + return 1; + } + } else if (args->ifindex && args->use_cmsg) { + if (send_msg_cmsg(sd, addr, alen, args->ifindex, args->version)) + return 1; + } else { + if (send_msg_no_cmsg(sd, addr, alen)) + return 1; + } + + log_msg("Sent message:\n"); + log_msg(" %.24s%s\n", msg, msglen > 24 ? " ..." : ""); + + return 0; +} + +static int socket_read_dgram(int sd, struct sock_args *args) +{ + unsigned char addr[sizeof(struct sockaddr_in6)]; + struct sockaddr *sa = (struct sockaddr *) addr; + socklen_t alen = sizeof(addr); + struct iovec iov[2]; + struct msghdr m = { + .msg_name = (caddr_t)addr, + .msg_namelen = alen, + .msg_iov = iov, + .msg_iovlen = 1, + }; + unsigned char cmsgbuf[256]; + struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf; + char buf[16*1024]; + int ifindex; + int len; + + iov[0].iov_base = (caddr_t)buf; + iov[0].iov_len = sizeof(buf); + + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + m.msg_control = (caddr_t)cm; + m.msg_controllen = sizeof(cmsgbuf); + + len = recvmsg(sd, &m, 0); + if (len == 0) { + log_msg("peer closed connection.\n"); + return 0; + } else if (len < 0) { + log_msg("failed to read message: %d: %s\n", + errno, strerror(errno)); + return -1; + } + + buf[len] = '\0'; + + log_address("Message from:", sa); + log_msg(" %.24s%s\n", buf, len > 24 ? " ..." : ""); + + ifindex = get_index_from_cmsg(&m); + if (args->expected_ifindex) { + if (args->expected_ifindex != ifindex) { + log_error("Device index mismatch: expected %d have %d\n", + args->expected_ifindex, ifindex); + return -1; + } + log_msg("Device index matches: expected %d have %d\n", + args->expected_ifindex, ifindex); + } + + if (!interactive && server_mode) { + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; + struct in6_addr *in6 = &s6->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(in6)) { + const uint32_t *pa = (uint32_t *) &in6->s6_addr; + struct in_addr in4; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) addr; + pa += 3; + in4.s_addr = *pa; + sin->sin_addr = in4; + sin->sin_family = AF_INET; + if (send_msg_cmsg(sd, addr, alen, + ifindex, AF_INET) < 0) + goto out_err; + } + } +again: + iov[0].iov_len = len; + + if (args->version == AF_INET6) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; + + if (args->dev) { + /* avoid PKTINFO conflicts with bindtodev */ + if (sendto(sd, buf, len, 0, + (void *) addr, alen) < 0) + goto out_err; + } else { + /* kernel is allowing scope_id to be set to VRF + * index for LLA. for sends to global address + * reset scope id + */ + s6->sin6_scope_id = ifindex; + if (sendmsg(sd, &m, 0) < 0) + goto out_err; + } + } else { + int err; + + err = sendmsg(sd, &m, 0); + if (err < 0) { + if (errno == EACCES && try_broadcast) { + try_broadcast = 0; + if (!set_broadcast(sd)) + goto again; + errno = EACCES; + } + goto out_err; + } + } + log_msg("Sent message:\n"); + log_msg(" %.24s%s\n", buf, len > 24 ? " ..." : ""); + } + + return 1; +out_err: + log_err_errno("failed to send msg to peer"); + return -1; +} + +static int socket_read_stream(int sd) +{ + char buf[1024]; + int len; + + len = read(sd, buf, sizeof(buf)-1); + if (len == 0) { + log_msg("client closed connection.\n"); + return 0; + } else if (len < 0) { + log_msg("failed to read message\n"); + return -1; + } + + buf[len] = '\0'; + log_msg("Incoming message:\n"); + log_msg(" %.24s%s\n", buf, len > 24 ? " ..." : ""); + + if (!interactive && server_mode) { + if (write(sd, buf, len) < 0) { + log_err_errno("failed to send buf"); + return -1; + } + log_msg("Sent message:\n"); + log_msg(" %.24s%s\n", buf, len > 24 ? " ..." : ""); + } + + return 1; +} + +static int socket_read(int sd, struct sock_args *args) +{ + if (args->type == SOCK_STREAM) + return socket_read_stream(sd); + + return socket_read_dgram(sd, args); +} + +static int stdin_to_socket(int sd, int type, void *addr, socklen_t alen) +{ + char buf[1024]; + int len; + + if (fgets(buf, sizeof(buf), stdin) == NULL) + return 0; + + len = strlen(buf); + if (type == SOCK_STREAM) { + if (write(sd, buf, len) < 0) { + log_err_errno("failed to send buf"); + return -1; + } + } else { + int err; + +again: + err = sendto(sd, buf, len, 0, addr, alen); + if (err < 0) { + if (errno == EACCES && try_broadcast) { + try_broadcast = 0; + if (!set_broadcast(sd)) + goto again; + errno = EACCES; + } + log_err_errno("failed to send msg to peer"); + return -1; + } + } + log_msg("Sent message:\n"); + log_msg(" %.24s%s\n", buf, len > 24 ? " ..." : ""); + + return 1; +} + +static void set_recv_attr(int sd, int version) +{ + if (version == AF_INET6) { + set_recvpktinfo_v6(sd); + set_recverr_v6(sd); + } else { + set_pktinfo_v4(sd); + set_recverr_v4(sd); + } +} + +static int msg_loop(int client, int sd, void *addr, socklen_t alen, + struct sock_args *args) +{ + struct timeval timeout = { .tv_sec = prog_timeout }, *ptval = NULL; + fd_set rfds; + int nfds; + int rc; + + if (args->type != SOCK_STREAM) + set_recv_attr(sd, args->version); + + if (msg) { + msglen = strlen(msg); + + /* client sends first message */ + if (client) { + if (send_msg(sd, addr, alen, args)) + return 1; + } + if (!interactive) { + ptval = &timeout; + if (!prog_timeout) + timeout.tv_sec = 5; + } + } + + nfds = interactive ? MAX(fileno(stdin), sd) + 1 : sd + 1; + while (1) { + FD_ZERO(&rfds); + FD_SET(sd, &rfds); + if (interactive) + FD_SET(fileno(stdin), &rfds); + + rc = select(nfds, &rfds, NULL, NULL, ptval); + if (rc < 0) { + if (errno == EINTR) + continue; + + rc = 1; + log_err_errno("select failed"); + break; + } else if (rc == 0) { + log_error("Timed out waiting for response\n"); + rc = 2; + break; + } + + if (FD_ISSET(sd, &rfds)) { + rc = socket_read(sd, args); + if (rc < 0) { + rc = 1; + break; + } + if (rc == 0) + break; + } + + rc = 0; + + if (FD_ISSET(fileno(stdin), &rfds)) { + if (stdin_to_socket(sd, args->type, addr, alen) <= 0) + break; + } + + if (interactive) + continue; + + if (iter != -1) { + --iter; + if (iter == 0) + break; + } + + log_msg("Going into quiet mode\n"); + quiet = 1; + + if (client) { + if (send_msg(sd, addr, alen, args)) { + rc = 1; + break; + } + } + } + + return rc; +} + +static int msock_init(struct sock_args *args, int server) +{ + uint32_t if_addr = htonl(INADDR_ANY); + struct sockaddr_in laddr = { + .sin_family = AF_INET, + .sin_port = htons(args->port), + }; + int one = 1; + int sd; + + if (!server && args->has_local_ip) + if_addr = args->local_addr.in.s_addr; + + sd = socket(PF_INET, SOCK_DGRAM, 0); + if (sd < 0) { + log_err_errno("socket"); + return -1; + } + + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, + (char *)&one, sizeof(one)) < 0) { + log_err_errno("Setting SO_REUSEADDR error"); + goto out_err; + } + + if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, + (char *)&one, sizeof(one)) < 0) + log_err_errno("Setting SO_BROADCAST error"); + + if (args->dev && bind_to_device(sd, args->dev) != 0) + goto out_err; + else if (args->use_setsockopt && + set_multicast_if(sd, args->ifindex)) + goto out_err; + + laddr.sin_addr.s_addr = if_addr; + + if (bind(sd, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) { + log_err_errno("bind failed"); + goto out_err; + } + + if (server && + set_membership(sd, args->grp.s_addr, + args->local_addr.in.s_addr, args->dev)) + goto out_err; + + return sd; +out_err: + close(sd); + return -1; +} + +static int msock_server(struct sock_args *args) +{ + return msock_init(args, 1); +} + +static int msock_client(struct sock_args *args) +{ + return msock_init(args, 0); +} + +static int bind_socket(int sd, struct sock_args *args) +{ + struct sockaddr_in serv_addr = { + .sin_family = AF_INET, + }; + struct sockaddr_in6 serv6_addr = { + .sin6_family = AF_INET6, + }; + void *addr; + socklen_t alen; + + if (!args->has_local_ip && args->type == SOCK_RAW) + return 0; + + switch (args->version) { + case AF_INET: + serv_addr.sin_port = htons(args->port); + serv_addr.sin_addr = args->local_addr.in; + addr = &serv_addr; + alen = sizeof(serv_addr); + break; + + case AF_INET6: + serv6_addr.sin6_port = htons(args->port); + serv6_addr.sin6_addr = args->local_addr.in6; + addr = &serv6_addr; + alen = sizeof(serv6_addr); + break; + + default: + log_error("Invalid address family\n"); + return -1; + } + + if (bind(sd, addr, alen) < 0) { + log_err_errno("error binding socket"); + return -1; + } + + return 0; +} + +static int lsock_init(struct sock_args *args) +{ + long flags; + int sd; + + sd = socket(args->version, args->type, args->protocol); + if (sd < 0) { + log_err_errno("Error opening socket"); + return -1; + } + + if (set_reuseaddr(sd) != 0) + goto err; + + if (set_reuseport(sd) != 0) + goto err; + + if (args->dev && bind_to_device(sd, args->dev) != 0) + goto err; + else if (args->use_setsockopt && + set_unicast_if(sd, args->ifindex, args->version)) + goto err; + + if (bind_socket(sd, args)) + goto err; + + if (args->bind_test_only) + goto out; + + if (args->type == SOCK_STREAM && listen(sd, 1) < 0) { + log_err_errno("listen failed"); + goto err; + } + + flags = fcntl(sd, F_GETFL); + if ((flags < 0) || (fcntl(sd, F_SETFL, flags|O_NONBLOCK) < 0)) { + log_err_errno("Failed to set non-blocking option"); + goto err; + } + + if (fcntl(sd, F_SETFD, FD_CLOEXEC) < 0) + log_err_errno("Failed to set close-on-exec flag"); + +out: + return sd; + +err: + close(sd); + return -1; +} + +static int do_server(struct sock_args *args) +{ + struct timeval timeout = { .tv_sec = prog_timeout }, *ptval = NULL; + unsigned char addr[sizeof(struct sockaddr_in6)] = {}; + socklen_t alen = sizeof(addr); + int lsd, csd = -1; + + fd_set rfds; + int rc; + + if (prog_timeout) + ptval = &timeout; + + if (args->has_grp) + lsd = msock_server(args); + else + lsd = lsock_init(args); + + if (lsd < 0) + return 1; + + if (args->bind_test_only) { + close(lsd); + return 0; + } + + if (args->type != SOCK_STREAM) { + rc = msg_loop(0, lsd, (void *) addr, alen, args); + close(lsd); + return rc; + } + + if (args->password && tcp_md5_remote(lsd, args)) { + close(lsd); + return -1; + } + + while (1) { + log_msg("\n"); + log_msg("waiting for client connection.\n"); + FD_ZERO(&rfds); + FD_SET(lsd, &rfds); + + rc = select(lsd+1, &rfds, NULL, NULL, ptval); + if (rc == 0) { + rc = 2; + break; + } + + if (rc < 0) { + if (errno == EINTR) + continue; + + log_err_errno("select failed"); + break; + } + + if (FD_ISSET(lsd, &rfds)) { + + csd = accept(lsd, (void *) addr, &alen); + if (csd < 0) { + log_err_errno("accept failed"); + break; + } + + rc = show_sockstat(csd, args); + if (rc) + break; + + rc = check_device(csd, args); + if (rc) + break; + } + + rc = msg_loop(0, csd, (void *) addr, alen, args); + close(csd); + + if (!interactive) + break; + } + + close(lsd); + + return rc; +} + +static int wait_for_connect(int sd) +{ + struct timeval _tv = { .tv_sec = prog_timeout }, *tv = NULL; + fd_set wfd; + int val = 0, sz = sizeof(val); + int rc; + + FD_ZERO(&wfd); + FD_SET(sd, &wfd); + + if (prog_timeout) + tv = &_tv; + + rc = select(FD_SETSIZE, NULL, &wfd, NULL, tv); + if (rc == 0) { + log_error("connect timed out\n"); + return -2; + } else if (rc < 0) { + log_err_errno("select failed"); + return -3; + } + + if (getsockopt(sd, SOL_SOCKET, SO_ERROR, &val, (socklen_t *)&sz) < 0) { + log_err_errno("getsockopt(SO_ERROR) failed"); + return -4; + } + + if (val != 0) { + log_error("connect failed: %d: %s\n", val, strerror(val)); + return -1; + } + + return 0; +} + +static int connectsock(void *addr, socklen_t alen, struct sock_args *args) +{ + int sd, rc = -1; + long flags; + + sd = socket(args->version, args->type, args->protocol); + if (sd < 0) { + log_err_errno("Failed to create socket"); + return -1; + } + + flags = fcntl(sd, F_GETFL); + if ((flags < 0) || (fcntl(sd, F_SETFL, flags|O_NONBLOCK) < 0)) { + log_err_errno("Failed to set non-blocking option"); + goto err; + } + + if (set_reuseport(sd) != 0) + goto err; + + if (args->dev && bind_to_device(sd, args->dev) != 0) + goto err; + else if (args->use_setsockopt && + set_unicast_if(sd, args->ifindex, args->version)) + goto err; + + if (args->has_local_ip && bind_socket(sd, args)) + goto err; + + if (args->type != SOCK_STREAM) + goto out; + + if (args->password && tcp_md5sig(sd, addr, alen, args->password)) + goto err; + + if (args->bind_test_only) + goto out; + + if (connect(sd, addr, alen) < 0) { + if (errno != EINPROGRESS) { + log_err_errno("Failed to connect to remote host"); + rc = -1; + goto err; + } + rc = wait_for_connect(sd); + if (rc < 0) + goto err; + } +out: + return sd; + +err: + close(sd); + return rc; +} + +static int do_client(struct sock_args *args) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + }; + void *addr; + int alen; + int rc = 0; + int sd; + + if (!args->has_remote_ip && !args->has_grp) { + fprintf(stderr, "remote IP or multicast group not given\n"); + return 1; + } + + switch (args->version) { + case AF_INET: + sin.sin_port = htons(args->port); + if (args->has_grp) + sin.sin_addr = args->grp; + else + sin.sin_addr = args->remote_addr.in; + addr = &sin; + alen = sizeof(sin); + break; + case AF_INET6: + sin6.sin6_port = htons(args->port); + sin6.sin6_addr = args->remote_addr.in6; + sin6.sin6_scope_id = args->scope_id; + addr = &sin6; + alen = sizeof(sin6); + break; + } + + if (args->has_grp) + sd = msock_client(args); + else + sd = connectsock(addr, alen, args); + + if (sd < 0) + return -sd; + + if (args->bind_test_only) + goto out; + + if (args->type == SOCK_STREAM) { + rc = show_sockstat(sd, args); + if (rc != 0) + goto out; + } + + rc = msg_loop(1, sd, addr, alen, args); + +out: + close(sd); + + return rc; +} + +enum addr_type { + ADDR_TYPE_LOCAL, + ADDR_TYPE_REMOTE, + ADDR_TYPE_MCAST, + ADDR_TYPE_EXPECTED_LOCAL, + ADDR_TYPE_EXPECTED_REMOTE, +}; + +static int convert_addr(struct sock_args *args, const char *_str, + enum addr_type atype) +{ + int family = args->version; + struct in6_addr *in6; + struct in_addr *in; + const char *desc; + char *str, *dev; + void *addr; + int rc = 0; + + str = strdup(_str); + if (!str) + return -ENOMEM; + + switch (atype) { + case ADDR_TYPE_LOCAL: + desc = "local"; + addr = &args->local_addr; + break; + case ADDR_TYPE_REMOTE: + desc = "remote"; + addr = &args->remote_addr; + break; + case ADDR_TYPE_MCAST: + desc = "mcast grp"; + addr = &args->grp; + break; + case ADDR_TYPE_EXPECTED_LOCAL: + desc = "expected local"; + addr = &args->expected_laddr; + break; + case ADDR_TYPE_EXPECTED_REMOTE: + desc = "expected remote"; + addr = &args->expected_raddr; + break; + default: + log_error("unknown address type"); + exit(1); + } + + switch (family) { + case AF_INET: + in = (struct in_addr *) addr; + if (str) { + if (inet_pton(AF_INET, str, in) == 0) { + log_error("Invalid %s IP address\n", desc); + rc = -1; + goto out; + } + } else { + in->s_addr = htonl(INADDR_ANY); + } + break; + + case AF_INET6: + dev = strchr(str, '%'); + if (dev) { + *dev = '\0'; + dev++; + } + + in6 = (struct in6_addr *) addr; + if (str) { + if (inet_pton(AF_INET6, str, in6) == 0) { + log_error("Invalid %s IPv6 address\n", desc); + rc = -1; + goto out; + } + } else { + *in6 = in6addr_any; + } + if (dev) { + args->scope_id = get_ifidx(dev); + if (args->scope_id < 0) { + log_error("Invalid scope on %s IPv6 address\n", + desc); + rc = -1; + goto out; + } + } + break; + + default: + log_error("Invalid address family\n"); + } + +out: + free(str); + return rc; +} + +static char *random_msg(int len) +{ + int i, n = 0, olen = len + 1; + char *m; + + if (len <= 0) + return NULL; + + m = malloc(olen); + if (!m) + return NULL; + + while (len > 26) { + i = snprintf(m + n, olen - n, "%.26s", + "abcdefghijklmnopqrstuvwxyz"); + n += i; + len -= i; + } + i = snprintf(m + n, olen - n, "%.*s", len, + "abcdefghijklmnopqrstuvwxyz"); + return m; +} + +#define GETOPT_STR "sr:l:p:t:g:P:DRn:M:d:SCi6L:0:1:2:Fbq" + +static void print_usage(char *prog) +{ + printf( + "usage: %s OPTS\n" + "Required:\n" + " -r addr remote address to connect to (client mode only)\n" + " -p port port to connect to (client mode)/listen on (server mode)\n" + " (default: %d)\n" + " -s server mode (default: client mode)\n" + " -t timeout seconds (default: none)\n" + "\n" + "Optional:\n" + " -F Restart server loop\n" + " -6 IPv6 (default is IPv4)\n" + " -P proto protocol for socket: icmp, ospf (default: none)\n" + " -D|R datagram (D) / raw (R) socket (default stream)\n" + " -l addr local address to bind to\n" + "\n" + " -d dev bind socket to given device name\n" + " -S use setsockopt (IP_UNICAST_IF or IP_MULTICAST_IF)\n" + " to set device binding\n" + " -C use cmsg and IP_PKTINFO to specify device binding\n" + "\n" + " -L len send random message of given length\n" + " -n num number of times to send message\n" + "\n" + " -M password use MD5 sum protection\n" + " -g grp multicast group (e.g., 239.1.1.1)\n" + " -i interactive mode (default is echo and terminate)\n" + "\n" + " -0 addr Expected local address\n" + " -1 addr Expected remote address\n" + " -2 dev Expected device name (or index) to receive packet\n" + "\n" + " -b Bind test only.\n" + " -q Be quiet. Run test without printing anything.\n" + , prog, DEFAULT_PORT); +} + +int main(int argc, char *argv[]) +{ + struct sock_args args = { + .version = AF_INET, + .type = SOCK_STREAM, + .port = DEFAULT_PORT, + }; + struct protoent *pe; + unsigned int tmp; + int forever = 0; + + /* process inputs */ + extern char *optarg; + int rc = 0; + + /* + * process input args + */ + + while ((rc = getopt(argc, argv, GETOPT_STR)) != -1) { + switch (rc) { + case 's': + server_mode = 1; + break; + case 'F': + forever = 1; + break; + case 'l': + args.has_local_ip = 1; + if (convert_addr(&args, optarg, ADDR_TYPE_LOCAL) < 0) + return 1; + break; + case 'r': + args.has_remote_ip = 1; + if (convert_addr(&args, optarg, ADDR_TYPE_REMOTE) < 0) + return 1; + break; + case 'p': + if (str_to_uint(optarg, 1, 65535, &tmp) != 0) { + fprintf(stderr, "Invalid port\n"); + return 1; + } + args.port = (unsigned short) tmp; + break; + case 't': + if (str_to_uint(optarg, 0, INT_MAX, + &prog_timeout) != 0) { + fprintf(stderr, "Invalid timeout\n"); + return 1; + } + break; + case 'D': + args.type = SOCK_DGRAM; + break; + case 'R': + args.type = SOCK_RAW; + args.port = 0; + break; + case 'P': + pe = getprotobyname(optarg); + if (pe) { + args.protocol = pe->p_proto; + } else { + if (str_to_uint(optarg, 0, 0xffff, &tmp) != 0) { + fprintf(stderr, "Invalid protocol\n"); + return 1; + } + args.protocol = tmp; + } + break; + case 'n': + iter = atoi(optarg); + break; + case 'L': + msg = random_msg(atoi(optarg)); + break; + case 'M': + args.password = optarg; + break; + case 'S': + args.use_setsockopt = 1; + break; + case 'C': + args.use_cmsg = 1; + break; + case 'd': + args.dev = optarg; + args.ifindex = get_ifidx(optarg); + if (args.ifindex < 0) { + fprintf(stderr, "Invalid device name\n"); + return 1; + } + break; + case 'i': + interactive = 1; + break; + case 'g': + args.has_grp = 1; + if (convert_addr(&args, optarg, ADDR_TYPE_MCAST) < 0) + return 1; + args.type = SOCK_DGRAM; + break; + case '6': + args.version = AF_INET6; + break; + case 'b': + args.bind_test_only = 1; + break; + case '0': + args.has_expected_laddr = 1; + if (convert_addr(&args, optarg, + ADDR_TYPE_EXPECTED_LOCAL)) + return 1; + break; + case '1': + args.has_expected_raddr = 1; + if (convert_addr(&args, optarg, + ADDR_TYPE_EXPECTED_REMOTE)) + return 1; + + break; + case '2': + if (str_to_uint(optarg, 0, 0x7ffffff, &tmp) != 0) { + tmp = get_ifidx(optarg); + if (tmp < 0) { + fprintf(stderr, + "Invalid device index\n"); + return 1; + } + } + args.expected_ifindex = (int)tmp; + break; + case 'q': + quiet = 1; + break; + default: + print_usage(argv[0]); + return 1; + } + } + + if (args.password && + (!args.has_remote_ip || args.type != SOCK_STREAM)) { + log_error("MD5 passwords apply to TCP only and require a remote ip for the password\n"); + return 1; + } + + if ((args.use_setsockopt || args.use_cmsg) && !args.ifindex) { + fprintf(stderr, "Device binding not specified\n"); + return 1; + } + if (args.use_setsockopt || args.use_cmsg) + args.dev = NULL; + + if (iter == 0) { + fprintf(stderr, "Invalid number of messages to send\n"); + return 1; + } + + if (args.type == SOCK_STREAM && !args.protocol) + args.protocol = IPPROTO_TCP; + if (args.type == SOCK_DGRAM && !args.protocol) + args.protocol = IPPROTO_UDP; + + if ((args.type == SOCK_STREAM || args.type == SOCK_DGRAM) && + args.port == 0) { + fprintf(stderr, "Invalid port number\n"); + return 1; + } + + if (!server_mode && !args.has_grp && + !args.has_remote_ip && !args.has_local_ip) { + fprintf(stderr, + "Local (server mode) or remote IP (client IP) required\n"); + return 1; + } + + if (interactive) { + prog_timeout = 0; + msg = NULL; + } + + if (server_mode) { + do { + rc = do_server(&args); + } while (forever); + + return rc; + } + return do_client(&args); +} diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 090fff9dbc48..4c285b6e1db8 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -25,6 +25,80 @@ #define TLS_PAYLOAD_MAX_LEN 16384 #define SOL_TLS 282 +#ifndef ENOTSUPP +#define ENOTSUPP 524 +#endif + +FIXTURE(tls_basic) +{ + int fd, cfd; + bool notls; +}; + +FIXTURE_SETUP(tls_basic) +{ + struct sockaddr_in addr; + socklen_t len; + int sfd, ret; + + self->notls = false; + len = sizeof(addr); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + self->fd = socket(AF_INET, SOCK_STREAM, 0); + sfd = socket(AF_INET, SOCK_STREAM, 0); + + ret = bind(sfd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + ret = listen(sfd, 10); + ASSERT_EQ(ret, 0); + + ret = getsockname(sfd, &addr, &len); + ASSERT_EQ(ret, 0); + + ret = connect(self->fd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + + self->cfd = accept(sfd, &addr, &len); + ASSERT_GE(self->cfd, 0); + + close(sfd); + + ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + if (ret != 0) { + ASSERT_EQ(errno, ENOENT); + self->notls = true; + printf("Failure setting TCP_ULP, testing without tls\n"); + return; + } + + ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + ASSERT_EQ(ret, 0); +} + +FIXTURE_TEARDOWN(tls_basic) +{ + close(self->fd); + close(self->cfd); +} + +/* Send some data through with ULP but no keys */ +TEST_F(tls_basic, base_base) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10]; + + ASSERT_EQ(strlen(test_str) + 1, send_len); + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +}; + FIXTURE(tls) { int fd, cfd; @@ -165,6 +239,16 @@ TEST_F(tls, msg_more) EXPECT_EQ(memcmp(buf, test_str, send_len), 0); } +TEST_F(tls, msg_more_unsent) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10]; + + EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); +} + TEST_F(tls, sendmsg_single) { struct msghdr msg; @@ -610,6 +694,42 @@ TEST_F(tls, recv_lowat) EXPECT_EQ(memcmp(send_mem, recv_mem + 10, 5), 0); } +TEST_F(tls, bidir) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10]; + int ret; + + if (!self->notls) { + struct tls12_crypto_info_aes_gcm_128 tls12; + + memset(&tls12, 0, sizeof(tls12)); + tls12.info.version = TLS_1_3_VERSION; + tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128; + + ret = setsockopt(self->fd, SOL_TLS, TLS_RX, &tls12, + sizeof(tls12)); + ASSERT_EQ(ret, 0); + + ret = setsockopt(self->cfd, SOL_TLS, TLS_TX, &tls12, + sizeof(tls12)); + ASSERT_EQ(ret, 0); + } + + ASSERT_EQ(strlen(test_str) + 1, send_len); + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); + + memset(buf, 0, sizeof(buf)); + + EXPECT_EQ(send(self->cfd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->fd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +}; + TEST_F(tls, pollin) { char const *test_str = "test_poll"; @@ -837,6 +957,109 @@ TEST_F(tls, control_msg) EXPECT_EQ(memcmp(buf, test_str, send_len), 0); } +TEST_F(tls, shutdown) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10]; + + ASSERT_EQ(strlen(test_str) + 1, send_len); + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); + + shutdown(self->fd, SHUT_RDWR); + shutdown(self->cfd, SHUT_RDWR); +} + +TEST_F(tls, shutdown_unsent) +{ + char const *test_str = "test_read"; + int send_len = 10; + + EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); + + shutdown(self->fd, SHUT_RDWR); + shutdown(self->cfd, SHUT_RDWR); +} + +TEST_F(tls, shutdown_reuse) +{ + struct sockaddr_in addr; + int ret; + + shutdown(self->fd, SHUT_RDWR); + shutdown(self->cfd, SHUT_RDWR); + close(self->cfd); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + ret = bind(self->fd, &addr, sizeof(addr)); + EXPECT_EQ(ret, 0); + ret = listen(self->fd, 10); + EXPECT_EQ(ret, -1); + EXPECT_EQ(errno, EINVAL); + + ret = connect(self->fd, &addr, sizeof(addr)); + EXPECT_EQ(ret, -1); + EXPECT_EQ(errno, EISCONN); +} + +TEST(non_established) { + struct tls12_crypto_info_aes_gcm_256 tls12; + struct sockaddr_in addr; + int sfd, ret, fd; + socklen_t len; + + len = sizeof(addr); + + memset(&tls12, 0, sizeof(tls12)); + tls12.info.version = TLS_1_2_VERSION; + tls12.info.cipher_type = TLS_CIPHER_AES_GCM_256; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + fd = socket(AF_INET, SOCK_STREAM, 0); + sfd = socket(AF_INET, SOCK_STREAM, 0); + + ret = bind(sfd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + ret = listen(sfd, 10); + ASSERT_EQ(ret, 0); + + ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + EXPECT_EQ(ret, -1); + /* TLS ULP not supported */ + if (errno == ENOENT) + return; + EXPECT_EQ(errno, ENOTSUPP); + + ret = setsockopt(sfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + EXPECT_EQ(ret, -1); + EXPECT_EQ(errno, ENOTSUPP); + + ret = getsockname(sfd, &addr, &len); + ASSERT_EQ(ret, 0); + + ret = connect(fd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + + ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + ASSERT_EQ(ret, 0); + + ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + EXPECT_EQ(ret, -1); + EXPECT_EQ(errno, EEXIST); + + close(fd); + close(sfd); +} + TEST(keysizes) { struct tls12_crypto_info_aes_gcm_256 tls12; struct sockaddr_in addr; diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c index 7eaa8a3de262..b632965e60eb 100644 --- a/tools/testing/selftests/pidfd/pidfd_test.c +++ b/tools/testing/selftests/pidfd/pidfd_test.c @@ -339,13 +339,9 @@ static int test_pidfd_send_signal_syscall_support(void) ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); if (ret < 0) { - /* - * pidfd_send_signal() will currently return ENOSYS when - * CONFIG_PROC_FS is not set. - */ if (errno == ENOSYS) ksft_exit_skip( - "%s test: pidfd_send_signal() syscall not supported (Ensure that CONFIG_PROC_FS=y is set)\n", + "%s test: pidfd_send_signal() syscall not supported\n", test_name); ksft_exit_fail_msg("%s test: Failed to send signal\n", diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 22e5da9008fd..b0954c873e2f 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -128,7 +128,9 @@ optional arguments: -v, --verbose Show the commands that are being run -N, --notap Suppress tap results for command under test -d DEVICE, --device DEVICE - Execute the test case in flower category + Execute test cases that use a physical device, where + DEVICE is its name. (If not defined, tests that require + a physical device will be skipped) -P, --pause Pause execution just before post-suite stage selection: diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json index cc7c7d758008..6503b1ce091f 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json @@ -713,5 +713,99 @@ "teardown": [ "$TC actions flush action vlan" ] + }, + { + "id": "294e", + "name": "Add batch of 32 vlan push actions with cookie", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan push protocol 802.1q id 4094 priority 7 pipe index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "56f7", + "name": "Delete batch of 32 vlan push actions", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan push protocol 802.1q id 4094 priority 7 pipe index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\"" + ], + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "0", + "teardown": [] + }, + { + "id": "759f", + "name": "Add batch of 32 vlan pop actions with cookie", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan pop continue index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "c84a", + "name": "Delete batch of 32 vlan pop actions", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan pop index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\"" + ], + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action vlan index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "0", + "teardown": [] } ] diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json new file mode 100644 index 000000000000..5f24c0598624 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json @@ -0,0 +1,391 @@ +[ + { + "id": "f62b", + "name": "Add ingress matchall filter for protocol ipv4 and action PASS", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ip matchall action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip matchall", + "matchPattern": "^filter parent ffff: protocol ip pref 1 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "7f09", + "name": "Add egress matchall filter for protocol ipv4 and action PASS", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0x1 prio 1 protocol ip matchall action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 1 prio 1 protocol ip matchall", + "matchPattern": "^filter parent 1: protocol ip pref 1 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "0596", + "name": "Add ingress matchall filter for protocol ipv6 and action DROP", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall action drop", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ipv6 matchall", + "matchPattern": "^filter parent ffff: protocol ipv6 pref 1 matchall.*handle 0x1.*gact action drop.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "41df", + "name": "Add egress matchall filter for protocol ipv6 and action DROP", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0x1 prio 1 protocol ipv6 matchall action drop", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 1 prio 1 protocol ipv6 matchall", + "matchPattern": "^filter parent 1: protocol ipv6 pref 1 matchall.*handle 0x1.*gact action drop.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "e1da", + "name": "Add ingress matchall filter for protocol ipv4 and action PASS with priority at 16-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 65535 protocol ipv4 matchall action pass", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 65535 protocol ipv4 matchall", + "matchPattern": "^filter parent ffff: protocol ip pref 65535 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "3de5", + "name": "Add egress matchall filter for protocol ipv4 and action PASS with priority at 16-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0x1 prio 65535 protocol ipv4 matchall action pass", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 1 prio 65535 protocol ipv4 matchall", + "matchPattern": "^filter parent 1: protocol ip pref 65535 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "72d7", + "name": "Add ingress matchall filter for protocol ipv4 and action PASS with priority exceeding 16-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 655355 protocol ipv4 matchall action pass", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 655355 protocol ipv4 matchall", + "matchPattern": "^filter parent ffff: protocol ip pref 655355 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "41d3", + "name": "Add egress matchall filter for protocol ipv4 and action PASS with priority exceeding 16-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0x1 prio 655355 protocol ipv4 matchall action pass", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 1 prio 655355 protocol ipv4 matchall", + "matchPattern": "^filter parent 1: protocol ip pref 655355 matchall.*handle 0x1.*gact action pass.*ref 1 bind 1", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "f755", + "name": "Add ingress matchall filter for all protocols and action CONTINUE with handle at 32-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0xffffffff prio 1 protocol all matchall action continue", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xffffffff prio 1 protocol all matchall", + "matchPattern": "^filter parent ffff: protocol all pref 1 matchall.*handle 0xffffffff.*gact action continue.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "2c33", + "name": "Add egress matchall filter for all protocols and action CONTINUE with handle at 32-bit maximum", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0xffffffff prio 1 protocol all matchall action continue", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 0xffffffff prio 1 protocol all matchall", + "matchPattern": "^filter parent 1: protocol all pref 1 matchall.*handle 0xffffffff.*gact action continue.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "0e4a", + "name": "Add ingress matchall filter for all protocols and action RECLASSIFY with skip_hw flag", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol all matchall skip_hw action reclassify", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0x1 prio 1 protocol all matchall", + "matchPattern": "^filter parent ffff: protocol all pref 1 matchall.*handle 0x1.*skip_hw.*not_in_hw.*gact action reclassify.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "7f60", + "name": "Add egress matchall filter for all protocols and action RECLASSIFY with skip_hw flag", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 root handle 1: prio" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: handle 0x1 prio 1 protocol all matchall skip_hw action reclassify", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent 1: handle 0x1 prio 1 protocol all matchall", + "matchPattern": "^filter parent 1: protocol all pref 1 matchall.*handle 0x1.*skip_hw.*not_in_hw.*gact action reclassify.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 root handle 1: prio", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "8bd2", + "name": "Add ingress matchall filter for protocol ipv6 and action PASS with classid", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall classid 1:1 action pass", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall", + "matchPattern": "^filter parent ffff: protocol ipv6 pref 1 matchall.*handle 0x1.*flowid 1:1.*gact action pass.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "2a4a", + "name": "Add ingress matchall filter for protocol ipv6 and action PASS with invalid classid", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall classid 6789defg action pass", + "expExitCode": "1", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall", + "matchPattern": "^filter protocol ipv6 pref 1 matchall.*handle 0x1.*flowid 6789defg.*gact action pass.*ref 1 bind 1", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "eaf8", + "name": "Delete single ingress matchall filter", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall classid 1:2 action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv6 matchall", + "matchPattern": "^filter protocol ipv6 pref 1 matchall.*handle 0x1.*flowid 1:2.*gact action pass.*ref 1 bind 1", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "76ad", + "name": "Delete all ingress matchall filters", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol all matchall classid 1:2 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x2 prio 2 protocol all matchall classid 1:3 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x3 prio 3 protocol all matchall classid 1:4 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x4 prio 4 protocol all matchall classid 1:5 action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff:", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "^filter protocol all pref.*matchall.*handle.*flowid.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "1eb9", + "name": "Delete single ingress matchall filter out of multiple", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol all matchall classid 1:2 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x2 prio 2 protocol all matchall classid 1:3 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x3 prio 3 protocol all matchall classid 1:4 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x4 prio 4 protocol all matchall classid 1:5 action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: protocol all handle 0x2 prio 2 matchall", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "^filter protocol all pref 2 matchall.*handle 0x2 flowid 1:2.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + }, + { + "id": "6d63", + "name": "Delete ingress matchall filter by chain ID", + "category": [ + "filter", + "matchall" + ], + "setup": [ + "$IP link add dev $DEV1 type dummy || /bin/true", + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol all chain 1 matchall classid 1:1 action pass", + "$TC filter add dev $DEV1 parent ffff: handle 0x1 prio 1 protocol ipv4 chain 2 matchall classid 1:3 action continue" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: chain 2", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "^filter protocol all pref 1 matchall chain 1 handle 0x1 flowid 1:1.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress", + "$IP link del dev $DEV1 type dummy" + ] + } +] diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index f04321ace9fb..e566c70e64a1 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -356,12 +356,14 @@ def test_runner(pm, args, filtered_tests): time.sleep(2) for tidx in testlist: if "flower" in tidx["category"] and args.device == None: + errmsg = "Tests using the DEV2 variable must define the name of a " + errmsg += "physical NIC with the -d option when running tdc.\n" + errmsg += "Test has been skipped." if args.verbose > 1: - print('Not executing test {} {} because DEV2 not defined'. - format(tidx['id'], tidx['name'])) + print(errmsg) res = TestResult(tidx['id'], tidx['name']) res.set_result(ResultState.skip) - res.set_errormsg('Not executed because DEV2 is not defined') + res.set_errormsg(errmsg) tsr.add_resultdata(res) continue try: @@ -499,7 +501,9 @@ def set_args(parser): choices=['none', 'xunit', 'tap'], help='Specify the format for test results. (Default: TAP)') parser.add_argument('-d', '--device', - help='Execute the test case in flower category') + help='Execute test cases that use a physical device, ' + + 'where DEVICE is its name. (If not defined, tests ' + + 'that require a physical device will be skipped)') parser.add_argument( '-P', '--pause', action='store_true', help='Pause execution just before post-suite stage') diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c index 4602326b8f5b..a4f4d4cf22c3 100644 --- a/tools/testing/selftests/x86/test_vsyscall.c +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -451,7 +451,7 @@ static int test_vsys_x(void) printf("[OK]\tExecuting the vsyscall page failed: #PF(0x%lx)\n", segv_err); } else { - printf("[FAILT]\tExecution failed with the wrong error: #PF(0x%lx)\n", + printf("[FAIL]\tExecution failed with the wrong error: #PF(0x%lx)\n", segv_err); return 1; } |