linux/tools/testing/selftests/bpf/test_align.c
<<
>>
Prefs
   1#include <asm/types.h>
   2#include <linux/types.h>
   3#include <stdint.h>
   4#include <stdio.h>
   5#include <stdlib.h>
   6#include <unistd.h>
   7#include <errno.h>
   8#include <string.h>
   9#include <stddef.h>
  10#include <stdbool.h>
  11
  12#include <sys/resource.h>
  13
  14#include <linux/unistd.h>
  15#include <linux/filter.h>
  16#include <linux/bpf_perf_event.h>
  17#include <linux/bpf.h>
  18
  19#include <bpf/bpf.h>
  20
  21#include "../../../include/linux/filter.h"
  22
  23#ifndef ARRAY_SIZE
  24# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  25#endif
  26
  27#define MAX_INSNS       512
  28#define MAX_MATCHES     16
  29
  30struct bpf_align_test {
  31        const char *descr;
  32        struct bpf_insn insns[MAX_INSNS];
  33        enum {
  34                UNDEF,
  35                ACCEPT,
  36                REJECT
  37        } result;
  38        enum bpf_prog_type prog_type;
  39        const char *matches[MAX_MATCHES];
  40};
  41
  42static struct bpf_align_test tests[] = {
  43        {
  44                .descr = "mov",
  45                .insns = {
  46                        BPF_MOV64_IMM(BPF_REG_3, 2),
  47                        BPF_MOV64_IMM(BPF_REG_3, 4),
  48                        BPF_MOV64_IMM(BPF_REG_3, 8),
  49                        BPF_MOV64_IMM(BPF_REG_3, 16),
  50                        BPF_MOV64_IMM(BPF_REG_3, 32),
  51                        BPF_MOV64_IMM(BPF_REG_0, 0),
  52                        BPF_EXIT_INSN(),
  53                },
  54                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  55                .matches = {
  56                        "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  57                        "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  58                        "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  59                        "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  60                        "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
  61                },
  62        },
  63        {
  64                .descr = "shift",
  65                .insns = {
  66                        BPF_MOV64_IMM(BPF_REG_3, 1),
  67                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  68                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  69                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  70                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
  71                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
  72                        BPF_MOV64_IMM(BPF_REG_4, 32),
  73                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  74                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  75                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  76                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
  77                        BPF_MOV64_IMM(BPF_REG_0, 0),
  78                        BPF_EXIT_INSN(),
  79                },
  80                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
  81                .matches = {
  82                        "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
  83                        "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  84                        "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  85                        "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  86                        "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  87                        "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
  88                        "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
  89                        "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
  90                        "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
  91                        "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
  92                        "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
  93                },
  94        },
  95        {
  96                .descr = "addsub",
  97                .insns = {
  98                        BPF_MOV64_IMM(BPF_REG_3, 4),
  99                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
 100                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
 101                        BPF_MOV64_IMM(BPF_REG_4, 8),
 102                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
 103                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
 104                        BPF_MOV64_IMM(BPF_REG_0, 0),
 105                        BPF_EXIT_INSN(),
 106                },
 107                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 108                .matches = {
 109                        "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
 110                        "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
 111                        "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
 112                        "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
 113                        "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
 114                        "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
 115                },
 116        },
 117        {
 118                .descr = "mul",
 119                .insns = {
 120                        BPF_MOV64_IMM(BPF_REG_3, 7),
 121                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
 122                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
 123                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
 124                        BPF_MOV64_IMM(BPF_REG_0, 0),
 125                        BPF_EXIT_INSN(),
 126                },
 127                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 128                .matches = {
 129                        "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
 130                        "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
 131                        "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
 132                        "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
 133                },
 134        },
 135
 136#define PREP_PKT_POINTERS \
 137        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
 138                    offsetof(struct __sk_buff, data)), \
 139        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
 140                    offsetof(struct __sk_buff, data_end))
 141
 142#define LOAD_UNKNOWN(DST_REG) \
 143        PREP_PKT_POINTERS, \
 144        BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
 145        BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
 146        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
 147        BPF_EXIT_INSN(), \
 148        BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
 149
 150        {
 151                .descr = "unknown shift",
 152                .insns = {
 153                        LOAD_UNKNOWN(BPF_REG_3),
 154                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
 155                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
 156                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
 157                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
 158                        LOAD_UNKNOWN(BPF_REG_4),
 159                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
 160                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
 161                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
 162                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
 163                        BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
 164                        BPF_MOV64_IMM(BPF_REG_0, 0),
 165                        BPF_EXIT_INSN(),
 166                },
 167                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 168                .matches = {
 169                        "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
 170                        "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
 171                        "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
 172                        "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
 173                        "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
 174                        "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
 175                        "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
 176                        "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
 177                        "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
 178                        "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
 179                        "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
 180                },
 181        },
 182        {
 183                .descr = "unknown mul",
 184                .insns = {
 185                        LOAD_UNKNOWN(BPF_REG_3),
 186                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
 187                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
 188                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
 189                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
 190                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
 191                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
 192                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
 193                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
 194                        BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
 195                        BPF_MOV64_IMM(BPF_REG_0, 0),
 196                        BPF_EXIT_INSN(),
 197                },
 198                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 199                .matches = {
 200                        "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
 201                        "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
 202                        "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
 203                        "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
 204                        "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
 205                        "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
 206                        "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
 207                        "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
 208                        "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
 209                        "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
 210                },
 211        },
 212        {
 213                .descr = "packet const offset",
 214                .insns = {
 215                        PREP_PKT_POINTERS,
 216                        BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
 217
 218                        BPF_MOV64_IMM(BPF_REG_0, 0),
 219
 220                        /* Skip over ethernet header.  */
 221                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
 222                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
 223                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
 224                        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
 225                        BPF_EXIT_INSN(),
 226
 227                        BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
 228                        BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
 229                        BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
 230                        BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
 231                        BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
 232                        BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
 233                        BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
 234
 235                        BPF_MOV64_IMM(BPF_REG_0, 0),
 236                        BPF_EXIT_INSN(),
 237                },
 238                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 239                .matches = {
 240                        "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
 241                        "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
 242                        "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
 243                        "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
 244                        "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
 245                        "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
 246                },
 247        },
 248        {
 249                .descr = "packet variable offset",
 250                .insns = {
 251                        LOAD_UNKNOWN(BPF_REG_6),
 252                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
 253
 254                        /* First, add a constant to the R5 packet pointer,
 255                         * then a variable with a known alignment.
 256                         */
 257                        BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
 258                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
 259                        BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
 260                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
 261                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
 262                        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
 263                        BPF_EXIT_INSN(),
 264                        BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
 265
 266                        /* Now, test in the other direction.  Adding first
 267                         * the variable offset to R5, then the constant.
 268                         */
 269                        BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
 270                        BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
 271                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
 272                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
 273                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
 274                        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
 275                        BPF_EXIT_INSN(),
 276                        BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
 277
 278                        /* Test multiple accumulations of unknown values
 279                         * into a packet pointer.
 280                         */
 281                        BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
 282                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
 283                        BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
 284                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
 285                        BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
 286                        BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
 287                        BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
 288                        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
 289                        BPF_EXIT_INSN(),
 290                        BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
 291
 292                        BPF_MOV64_IMM(BPF_REG_0, 0),
 293                        BPF_EXIT_INSN(),
 294                },
 295                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 296                .matches = {
 297                        /* Calculated offset in R6 has unknown value, but known
 298                         * alignment of 4.
 299                         */
 300                        "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
 301
 302                        /* Offset is added to packet pointer R5, resulting in known
 303                         * auxiliary alignment and offset.
 304                         */
 305                        "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 306
 307                        /* At the time the word size load is performed from R5,
 308                         * it's total offset is NET_IP_ALIGN + reg->off (0) +
 309                         * reg->aux_off (14) which is 16.  Then the variable
 310                         * offset is considered using reg->aux_off_align which
 311                         * is 4 and meets the load's requirements.
 312                         */
 313                        "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 314
 315
 316                        /* Variable offset is added to R5 packet pointer,
 317                         * resulting in auxiliary alignment of 4.
 318                         */
 319                        "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 320
 321                        /* Constant offset is added to R5, resulting in
 322                         * reg->off of 14.
 323                         */
 324                        "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 325
 326                        /* At the time the word size load is performed from R5,
 327                         * it's total offset is NET_IP_ALIGN + reg->off (14) which
 328                         * is 16.  Then the variable offset is considered using
 329                         * reg->aux_off_align which is 4 and meets the load's
 330                         * requirements.
 331                         */
 332                        "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 333
 334                        /* Constant offset is added to R5 packet pointer,
 335                         * resulting in reg->off value of 14.
 336                         */
 337                        "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
 338                        /* Variable offset is added to R5, resulting in an
 339                         * auxiliary offset of 14, and an auxiliary alignment of 4.
 340                         */
 341                        "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 342                        /* Constant is added to R5 again, setting reg->off to 4. */
 343                        "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 344                        /* And once more we add a variable, which causes an accumulation
 345                         * of reg->off into reg->aux_off_align, with resulting value of
 346                         * 18.  The auxiliary alignment stays at 4.
 347                         */
 348                        "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 349                        /* At the time the word size load is performed from R5,
 350                         * it's total offset is NET_IP_ALIGN + reg->off (0) +
 351                         * reg->aux_off (18) which is 20.  Then the variable offset
 352                         * is considered using reg->aux_off_align which is 4 and meets
 353                         * the load's requirements.
 354                         */
 355                        "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
 356                },
 357        },
 358};
 359
 360static int probe_filter_length(const struct bpf_insn *fp)
 361{
 362        int len;
 363
 364        for (len = MAX_INSNS - 1; len > 0; --len)
 365                if (fp[len].code != 0 || fp[len].imm != 0)
 366                        break;
 367        return len + 1;
 368}
 369
 370static char bpf_vlog[32768];
 371
 372static int do_test_single(struct bpf_align_test *test)
 373{
 374        struct bpf_insn *prog = test->insns;
 375        int prog_type = test->prog_type;
 376        int prog_len, i;
 377        int fd_prog;
 378        int ret;
 379
 380        prog_len = probe_filter_length(prog);
 381        fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
 382                                     prog, prog_len, 1, "GPL", 0,
 383                                     bpf_vlog, sizeof(bpf_vlog), 2);
 384        if (fd_prog < 0) {
 385                printf("Failed to load program.\n");
 386                printf("%s", bpf_vlog);
 387                ret = 1;
 388        } else {
 389                ret = 0;
 390                for (i = 0; i < MAX_MATCHES; i++) {
 391                        const char *t, *m = test->matches[i];
 392
 393                        if (!m)
 394                                break;
 395                        t = strstr(bpf_vlog, m);
 396                        if (!t) {
 397                                printf("Failed to find match: %s\n", m);
 398                                ret = 1;
 399                                printf("%s", bpf_vlog);
 400                                break;
 401                        }
 402                }
 403                close(fd_prog);
 404        }
 405        return ret;
 406}
 407
 408static int do_test(unsigned int from, unsigned int to)
 409{
 410        int all_pass = 0;
 411        int all_fail = 0;
 412        unsigned int i;
 413
 414        for (i = from; i < to; i++) {
 415                struct bpf_align_test *test = &tests[i];
 416                int fail;
 417
 418                printf("Test %3d: %s ... ",
 419                       i, test->descr);
 420                fail = do_test_single(test);
 421                if (fail) {
 422                        all_fail++;
 423                        printf("FAIL\n");
 424                } else {
 425                        all_pass++;
 426                        printf("PASS\n");
 427                }
 428        }
 429        printf("Results: %d pass %d fail\n",
 430               all_pass, all_fail);
 431        return all_fail ? EXIT_FAILURE : EXIT_SUCCESS;
 432}
 433
 434int main(int argc, char **argv)
 435{
 436        unsigned int from = 0, to = ARRAY_SIZE(tests);
 437        struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
 438
 439        setrlimit(RLIMIT_MEMLOCK, &rinf);
 440
 441        if (argc == 3) {
 442                unsigned int l = atoi(argv[argc - 2]);
 443                unsigned int u = atoi(argv[argc - 1]);
 444
 445                if (l < to && u < to) {
 446                        from = l;
 447                        to   = u + 1;
 448                }
 449        } else if (argc == 2) {
 450                unsigned int t = atoi(argv[argc - 1]);
 451
 452                if (t < to) {
 453                        from = t;
 454                        to   = t + 1;
 455                }
 456        }
 457        return do_test(from, to);
 458}
 459