xref: /openbmc/linux/net/sched/em_cmp.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * net/sched/em_cmp.c	Simple packet data comparison ematch
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Authors:	Thomas Graf <tgraf@suug.ch>
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/skbuff.h>
121da177e4SLinus Torvalds #include <linux/tc_ematch/tc_em_cmp.h>
13d48abfecSHarvey Harrison #include <asm/unaligned.h>
141da177e4SLinus Torvalds #include <net/pkt_cls.h>
151da177e4SLinus Torvalds 
cmp_needs_transformation(struct tcf_em_cmp * cmp)161da177e4SLinus Torvalds static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
171da177e4SLinus Torvalds {
181da177e4SLinus Torvalds 	return unlikely(cmp->flags & TCF_EM_CMP_TRANS);
191da177e4SLinus Torvalds }
201da177e4SLinus Torvalds 
em_cmp_match(struct sk_buff * skb,struct tcf_ematch * em,struct tcf_pkt_info * info)211da177e4SLinus Torvalds static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
221da177e4SLinus Torvalds 			struct tcf_pkt_info *info)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds 	struct tcf_em_cmp *cmp = (struct tcf_em_cmp *) em->data;
251da177e4SLinus Torvalds 	unsigned char *ptr = tcf_get_base_ptr(skb, cmp->layer) + cmp->off;
261da177e4SLinus Torvalds 	u32 val = 0;
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds 	if (!tcf_valid_offset(skb, ptr, cmp->align))
291da177e4SLinus Torvalds 		return 0;
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 	switch (cmp->align) {
321da177e4SLinus Torvalds 	case TCF_EM_ALIGN_U8:
331da177e4SLinus Torvalds 		val = *ptr;
341da177e4SLinus Torvalds 		break;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds 	case TCF_EM_ALIGN_U16:
37d48abfecSHarvey Harrison 		val = get_unaligned_be16(ptr);
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 		if (cmp_needs_transformation(cmp))
401da177e4SLinus Torvalds 			val = be16_to_cpu(val);
411da177e4SLinus Torvalds 		break;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	case TCF_EM_ALIGN_U32:
44*e5a4b17dSMenglong Dong 		/* Worth checking boundaries? The branching seems
45cc7ec456SEric Dumazet 		 * to get worse. Visit again.
46cc7ec456SEric Dumazet 		 */
47d48abfecSHarvey Harrison 		val = get_unaligned_be32(ptr);
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 		if (cmp_needs_transformation(cmp))
501da177e4SLinus Torvalds 			val = be32_to_cpu(val);
511da177e4SLinus Torvalds 		break;
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	default:
541da177e4SLinus Torvalds 		return 0;
551da177e4SLinus Torvalds 	}
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	if (cmp->mask)
581da177e4SLinus Torvalds 		val &= cmp->mask;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	switch (cmp->opnd) {
611da177e4SLinus Torvalds 	case TCF_EM_OPND_EQ:
621da177e4SLinus Torvalds 		return val == cmp->val;
631da177e4SLinus Torvalds 	case TCF_EM_OPND_LT:
641da177e4SLinus Torvalds 		return val < cmp->val;
651da177e4SLinus Torvalds 	case TCF_EM_OPND_GT:
661da177e4SLinus Torvalds 		return val > cmp->val;
671da177e4SLinus Torvalds 	}
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static struct tcf_ematch_ops em_cmp_ops = {
731da177e4SLinus Torvalds 	.kind	  = TCF_EM_CMP,
741da177e4SLinus Torvalds 	.datalen  = sizeof(struct tcf_em_cmp),
751da177e4SLinus Torvalds 	.match	  = em_cmp_match,
761da177e4SLinus Torvalds 	.owner	  = THIS_MODULE,
771da177e4SLinus Torvalds 	.link	  = LIST_HEAD_INIT(em_cmp_ops.link)
781da177e4SLinus Torvalds };
791da177e4SLinus Torvalds 
init_em_cmp(void)801da177e4SLinus Torvalds static int __init init_em_cmp(void)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	return tcf_em_register(&em_cmp_ops);
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds 
exit_em_cmp(void)851da177e4SLinus Torvalds static void __exit exit_em_cmp(void)
861da177e4SLinus Torvalds {
871da177e4SLinus Torvalds 	tcf_em_unregister(&em_cmp_ops);
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds MODULE_LICENSE("GPL");
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds module_init(init_em_cmp);
931da177e4SLinus Torvalds module_exit(exit_em_cmp);
941da177e4SLinus Torvalds 
95db3d99c0SPatrick McHardy MODULE_ALIAS_TCF_EMATCH(TCF_EM_CMP);
96