A lot of parsers will rely on doing the same things over and over, so
create a header with utility functions to aid in writing parsers.

Signed-off-by: Anatoly Burakov <[email protected]>
---
 drivers/net/intel/common/flow_util.h | 165 +++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
 create mode 100644 drivers/net/intel/common/flow_util.h

diff --git a/drivers/net/intel/common/flow_util.h 
b/drivers/net/intel/common/flow_util.h
new file mode 100644
index 0000000000..1337e6c55d
--- /dev/null
+++ b/drivers/net/intel/common/flow_util.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2025 Intel Corporation
+ */
+
+#ifndef _INTEL_COMMON_FLOW_UTIL_H_
+#define _INTEL_COMMON_FLOW_UTIL_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+/*
+ * Utility functions primarily intended for flow parsers.
+ */
+
+/**
+ * ci_is_all_byte - Check if memory region is filled with a specific byte 
value.
+ *
+ * @param ptr: Pointer to memory region
+ * @param len: Length in bytes
+ * @param val: Byte value to check (e.g., 0x00 or 0xFF)
+ *
+ * @return true if all bytes equal @val, false otherwise
+ */
+static inline bool
+ci_is_all_byte(const void *ptr, size_t len, uint8_t val)
+{
+       const uint8_t *bytes = ptr;
+       const uint32_t pattern32 = 0x01010101U * val;
+       size_t i = 0;
+
+       /* Process 4-byte chunks using memcpy */
+       for (; i + 4 <= len; i += 4) {
+               uint32_t chunk;
+               memcpy(&chunk, bytes + i, 4);
+               if (chunk != pattern32)
+                       return false;
+       }
+
+       /* Process remaining bytes */
+       for (; i < len; i++) {
+               if (bytes[i] != val)
+                       return false;
+       }
+
+       return true;
+}
+
+/**
+ * ci_is_all_zero_or_masked - Check if bytes are all 0x00 OR all 0xFF.
+ * @param ptr: Pointer to memory region
+ * @param len: Length in bytes
+ *
+ * @return true if all bytes are 0x00 OR all bytes are 0xFF, false otherwise
+ */
+static inline bool
+ci_is_all_zero_or_masked(const void *ptr, size_t len)
+{
+       const uint8_t *bytes = (const uint8_t *)ptr;
+       uint8_t first_val;
+
+       /* zero length cannot be valid */
+       if (len == 0)
+               return false;
+
+       first_val = bytes[0];
+
+       if (first_val != 0x00 && first_val != 0xFF)
+               return false;
+
+       return ci_is_all_byte(ptr, len, first_val);
+}
+
+/**
+ * ci_is_zero_or_masked - Check if a value is zero OR matches the mask exactly.
+ *
+ * @param value: Data value to check
+ * @param mask: Mask to compare against
+ *
+ * @return true if (value == 0) OR (value == mask), false otherwise
+ *
+ * Usage notes: this is intended for bitfields e.g. VLAN_TCI
+ * For byte-aligned fields, use CI_FIELD_IS_ZERO_OR_MASKED below.
+ */
+static inline bool
+ci_is_zero_or_masked(uint64_t value, uint64_t mask)
+{
+       uint64_t masked_val = value & mask;
+
+       return masked_val == 0 || masked_val == mask;
+}
+
+/**
+ * Check if a struct field is fully masked or unmasked.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_ZERO_OR_MASKED(field_ptr) \
+       ci_is_all_zero_or_masked((field_ptr), sizeof(*(field_ptr)))
+
+/**
+ * Check if a struct field is all 0x00.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_ZERO(field_ptr) \
+       ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0x00)
+
+/**
+ * Check if a struct field is all 0xFF.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_MASKED(field_ptr) \
+       ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0xFF)
+
+/**
+ * ci_be24_to_cpu - Convert 24-bit big-endian value to host byte order.
+ * @param val: Pointer to 3-byte big-endian value
+ *
+ * @return uint32_t value in host byte order
+ *
+ * Usage: extract 24-bit Big-Endian values (e.g. VXLAN VNI).
+ */
+static inline uint32_t
+ci_be24_to_cpu(const uint8_t val[3])
+{
+       return (val[0] << 16) | (val[1] << 8) | val[2];
+}
+
+/**
+ * ci_is_hex_char - Check if a character is a valid hexadecimal digit.
+ *
+ * @param c: Character to check
+ *
+ * @return true if c is in [0-9a-fA-F], false otherwise
+ */
+static inline bool
+ci_is_hex_char(unsigned char c)
+{
+       return ((c >= '0' && c <= '9') ||
+               (c >= 'a' && c <= 'f') ||
+               (c >= 'A' && c <= 'F'));
+}
+
+/**
+ * ci_hex_char_to_nibble - Convert hex character to 4-bit value.
+ *
+ * @param c: Hex character ('0'-'9', 'a'-'f', 'A'-'F')
+ *
+ * @return Value 0-15, or 0 if invalid
+ */
+static inline unsigned char
+ci_hex_char_to_nibble(unsigned char c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'a' && c <= 'f')
+               return c - 'a' + 10;
+       if (c >= 'A' && c <= 'F')
+               return c - 'A' + 10;
+       return 0;
+}
+
+#endif /* _INTEL_COMMON_FLOW_UTIL_H_ */
-- 
2.47.3

Reply via email to