1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * net/sched/em_cmp.c Simple packet data comparison ematch
5 * Authors: Thomas Graf <tgraf@suug.ch>
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/skbuff.h>
12 #include <linux/tc_ematch/tc_em_cmp.h>
13 #include <asm/unaligned.h>
14 #include <net/pkt_cls.h>
16 static inline int cmp_needs_transformation(struct tcf_em_cmp
*cmp
)
18 return unlikely(cmp
->flags
& TCF_EM_CMP_TRANS
);
21 static int em_cmp_match(struct sk_buff
*skb
, struct tcf_ematch
*em
,
22 struct tcf_pkt_info
*info
)
24 struct tcf_em_cmp
*cmp
= (struct tcf_em_cmp
*) em
->data
;
25 unsigned char *ptr
= tcf_get_base_ptr(skb
, cmp
->layer
) + cmp
->off
;
28 if (!tcf_valid_offset(skb
, ptr
, cmp
->align
))
36 case TCF_EM_ALIGN_U16
:
37 val
= get_unaligned_be16(ptr
);
39 if (cmp_needs_transformation(cmp
))
40 val
= be16_to_cpu(val
);
43 case TCF_EM_ALIGN_U32
:
44 /* Worth checking boundries? The branching seems
45 * to get worse. Visit again.
47 val
= get_unaligned_be32(ptr
);
49 if (cmp_needs_transformation(cmp
))
50 val
= be32_to_cpu(val
);
62 return val
== cmp
->val
;
64 return val
< cmp
->val
;
66 return val
> cmp
->val
;
72 static struct tcf_ematch_ops em_cmp_ops
= {
74 .datalen
= sizeof(struct tcf_em_cmp
),
75 .match
= em_cmp_match
,
77 .link
= LIST_HEAD_INIT(em_cmp_ops
.link
)
80 static int __init
init_em_cmp(void)
82 return tcf_em_register(&em_cmp_ops
);
85 static void __exit
exit_em_cmp(void)
87 tcf_em_unregister(&em_cmp_ops
);
90 MODULE_LICENSE("GPL");
92 module_init(init_em_cmp
);
93 module_exit(exit_em_cmp
);
95 MODULE_ALIAS_TCF_EMATCH(TCF_EM_CMP
);