new file mode 100644
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_COMPILER_HELPERS_H__
+#define __PANDA_COMPILER_HELPERS_H__
+
+/* Various helper defintions and functions that are compiler specific
+ * (e.g. they use __attribute__
+ */
+
+/* Define the __defaligned macro if it's not already defined */
+#ifndef __defaligned
+#define __defaligned() __attribute__ ((__aligned__))
+#endif
+
+/* Define the __aligned macro if it's not already defined */
+#ifndef __aligned
+#define __aligned(size) __attribute__((__aligned__(size)))
+#endif
+
+/* Define the __unused macro if it's not already defined */
+#ifndef __unused
+#define __unused() __attribute__((unused))
+#endif
+
+/* Define the __always_inline macro if it's not already defined */
+#ifndef __always_inline
+#define __always_inline __attribute__((always_inline)) inline
+#endif
+
+/* Utilities for dynamic arrays in sections */
+
+#define PANDA_DEFINE_SECTION(NAME, TYPE) \
+extern TYPE __start_##NAME[]; \
+extern TYPE __stop_##NAME[]; \
+static inline unsigned int panda_section_array_size_##NAME(void) \
+{ \
+ return (unsigned int)(__stop_##NAME - __start_##NAME); \
+} \
+static inline TYPE *panda_section_base_##NAME(void) \
+{ \
+ return __start_##NAME; \
+}
+
+#ifndef __bpf__
+#define PANDA_SECTION_ATTR(NAME) __attribute__((__used__, __section__(#NAME)))
+#else
+#define PANDA_SECTION_ATTR(NAME)
+#endif
+
+/* Assume cache line size of 64 for purposes of section alignment */
+#ifndef PANDA_ALIGN_SECTION
+#define PANDA_ALIGN_SECTION __aligned(64)
+#endif
+
+#endif /* __PANDA_COMPILER_HELPERS_H__ */
new file mode 100644
@@ -0,0 +1,369 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_FLAG_FIELDS_H__
+#define __PANDA_FLAG_FIELDS_H__
+
+/* Definitions and functions for processing and parsing flag-fields */
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <linux/types.h>
+
+#include "net/panda/parser_types.h"
+
+/* Definitions for parsing flag-fields
+ *
+ * Flag-fields is a common networking protocol construct that encodes optional
+ * data in a set of flags and data fields. The flags indicate whether or not a
+ * corresponding data field is present. The data fields are fixed length per
+ * each flag-field definition and ordered by the ordering of the flags
+ * indicating the presence of the fields (e.g. GRE and GUE employ flag-fields)
+ */
+
+/* Flag-fields descriptors and tables
+ *
+ * A set of flag-fields is defined in a table of type struct panda_flag_fields.
+ * Each entry in the table is a descriptor for one flag-field in a protocol and
+ * includes a flag value, mask (for the case of a multi-bit flag), and size of
+ * the cooresponding field. A flag is matched if "(flags & mask) == flag"
+ */
+
+/* One descriptor for a flag
+ *
+ * flag: protocol value
+ * mask: mask to apply to field
+ * size: size for associated field data
+ */
+struct panda_flag_field {
+ __u32 flag;
+ __u32 mask;
+ size_t size;
+};
+
+/* Descriptor for a protocol field with flag fields
+ *
+ * Defines the flags and their data fields for one instance a flag field in
+ * in a protocol header (e.g. GRE v0 flags):
+ *
+ * num_idx: Number of flag_field structures
+ * fields: List of defined flag fields
+ */
+struct panda_flag_fields {
+ size_t num_idx;
+ struct panda_flag_field fields[];
+};
+
+/* Compute the length of optional fields present in a flags field */
+static inline size_t panda_flag_fields_length(__u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ size_t len = 0;
+ __u32 mask;
+ int i;
+
+ for (i = 0; i < flag_fields->num_idx; i++) {
+ mask = flag_fields->fields[i].mask ? :
+ flag_fields->fields[i].flag;
+
+ if ((flags & mask) == flag_fields->fields[i].flag)
+ len += flag_fields->fields[i].size;
+ }
+
+ return len;
+}
+
+static inline ssize_t __panda_flag_fields_offset(__u32 targ_idx, __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ size_t offset = 0;
+ __u32 mask;
+ int i;
+
+ for (i = 0; i < targ_idx; i++) {
+ mask = flag_fields->fields[i].mask ? :
+ flag_fields->fields[i].flag;
+
+ if ((flags & mask) == flag_fields->fields[i].flag)
+ offset += flag_fields->fields[i].size;
+ }
+
+ return offset;
+}
+
+/* Determine offset of a field given a set of flags */
+static inline ssize_t panda_flag_fields_offset(__u32 targ_idx, __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ __u32 mask;
+
+ mask = flag_fields->fields[targ_idx].mask ? :
+ flag_fields->fields[targ_idx].flag;
+ if ((flags & mask) != flag_fields->fields[targ_idx].flag) {
+ /* Flag not set */
+ return -1;
+ }
+
+ return __panda_flag_fields_offset(targ_idx, flags, flag_fields);
+}
+
+/* Check flags are legal */
+static inline bool panda_flag_fields_check_invalid(__u32 flags, __u32 mask)
+{
+ return !!(flags & ~mask);
+}
+
+/* Retrieve a byte value from a flag field */
+static inline __u8 panda_flag_fields_get8(const __u8 *fields, __u32 targ_idx,
+ __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ ssize_t offset = panda_flag_fields_offset(targ_idx, flags, flag_fields);
+
+ if (offset < 0)
+ return 0;
+
+ return *(__u8 *)&fields[offset];
+}
+
+/* Retrieve a short value from a flag field */
+static inline __u16 panda_flag_fields_get16(const __u8 *fields,
+ __u32 targ_idx,
+ __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ ssize_t offset = panda_flag_fields_offset(targ_idx, flags, flag_fields);
+
+ if (offset < 0)
+ return 0;
+
+ return *(__u16 *)&fields[offset];
+}
+
+/* Retrieve a 32 bit value from a flag field */
+static inline __u32 panda_get_flag_field32(const __u8 *fields, __u32 targ_idx,
+ __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ ssize_t offset = panda_flag_fields_offset(targ_idx, flags, flag_fields);
+
+ if (offset < 0)
+ return 0;
+
+ return *(__u32 *)&fields[offset];
+}
+
+/* Retrieve a 64 bit value from a flag field */
+static inline __u64 panda_get_flag_field64(const __u8 *fields, __u32 targ_idx,
+ __u32 flags,
+ const struct panda_flag_fields
+ *flag_fields)
+{
+ ssize_t offset = panda_flag_fields_offset(targ_idx, flags, flag_fields);
+
+ if (offset < 0)
+ return 0;
+
+ return *(__u64 *)&fields[offset];
+}
+
+
+/* Structure or parsing operations for flag-fields
+ *
+ * flags_offset: Offset of flags in the protocol header
+ * start_fields_offset: Return the offset in the header of the start of the
+ * flag fields data
+ */
+struct panda_proto_flag_fields_ops {
+ __u32 (*get_flags)(const void *hdr);
+ size_t (*start_fields_offset)(const void *hdr);
+};
+
+/* Flag-field parse node operations
+ *
+ * Operations to process a single flag-field
+ *
+ * extract_metadata: Extract metadata for the node. Input is the meta
+ * data frame which points to a parser defined metadata structure.
+ * If the value is NULL then no metadata is extracted
+ * handle_flag_field: Per flag-field handler which allows arbitrary processing
+ * of a flag-field. Input is the flag-field data and a parser defined
+ * metadata structure for the current frame. Return value is a parser
+ * return code: PANDA_OKAY indicates no errors, PANDA_STOP* return
+ * values indicate to stop parsing
+ */
+struct panda_parse_flag_field_node_ops {
+ void (*extract_metadata)(const void *hdr, void *frame,
+ struct panda_ctrl_data ctrl);
+ int (*handle_flag_field)(const void *hdr, void *frame,
+ struct panda_ctrl_data ctrl);
+};
+
+/* A parse node for a single flag field */
+struct panda_parse_flag_field_node {
+ const struct panda_parse_flag_field_node_ops ops;
+ const char *name;
+};
+
+/* One entry in a flag-fields protocol table:
+ * index: flag-field index (index in a flag-fields table)
+ * node: associated TLV parse structure for the type
+ */
+struct panda_proto_flag_fields_table_entry {
+ int index;
+ const struct panda_parse_flag_field_node *node;
+};
+
+/* Flag-fields table
+ *
+ * Contains a table that maps a flag-field index to a flag-field parse node.
+ * Note that the index correlates to an entry in a flag-fields table that
+ * describes the flag-fields of a protocol
+ */
+struct panda_proto_flag_fields_table {
+ int num_ents;
+ const struct panda_proto_flag_fields_table_entry *entries;
+};
+
+/* A flag-fields parse node. Note this is a super structure for a PANDA parse
+ * node and tyoe is PANDA_NODE_TYPE_FLAG_FIELDS
+ */
+struct panda_parse_flag_fields_node {
+ const struct panda_parse_node parse_node;
+ const struct panda_proto_flag_fields_table *flag_fields_proto_table;
+};
+
+/* A flag-fields protocol node. Note this is a super structure for a PANDA
+ * protocol node and tyoe is PANDA_NODE_TYPE_FLAG_FIELDS
+ */
+struct panda_proto_flag_fields_node {
+ struct panda_proto_node proto_node;
+ struct panda_proto_flag_fields_ops ops;
+ const struct panda_flag_fields *flag_fields;
+};
+
+/* Helper to create a flag-fields protocol table */
+#define PANDA_MAKE_FLAG_FIELDS_TABLE(NAME, ...) \
+ static const struct panda_proto_flag_fields_table_entry \
+ __##NAME[] = { __VA_ARGS__ }; \
+ static const struct panda_proto_flag_fields_table NAME = { \
+ .num_ents = sizeof(__##NAME) / \
+ sizeof(struct \
+ panda_proto_flag_fields_table_entry), \
+ .entries = __##NAME, \
+ }
+
+/* Forward declarations for flag-fields parse nodes */
+#define PANDA_DECL_FLAG_FIELDS_PARSE_NODE(FLAG_FIELDS_PARSE_NODE) \
+ static const struct panda_parse_flag_fields_node \
+ FLAG_FIELDS_PARSE_NODE
+
+/* Forward declarations for flag-field proto tables */
+#define PANDA_DECL_FLAG_FIELDS_TABLE(FLAG_FIELDS_TABLE) \
+ static const struct panda_proto_flag_fields_table \
+ FLAG_FIELDS_TABLE
+
+
+/* Helper to create a parse node with a next protocol table */
+#define __PANDA_MAKE_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ WILDCARD_NODE, \
+ PROTO_TABLE, \
+ FLAG_FIELDS_TABLE) \
+ static const struct panda_parse_flag_fields_node \
+ PARSE_FLAG_FIELDS_NODE = { \
+ .flag_fields_proto_table = FLAG_FIELDS_TABLE, \
+ .parse_node.node_type = PANDA_NODE_TYPE_FLAG_FIELDS, \
+ .parse_node.proto_node = \
+ &PROTO_FLAG_FIELDS_NODE.proto_node, \
+ .parse_node.ops.extract_metadata = EXTRACT_METADATA, \
+ .parse_node.ops.handle_proto = HANDLER, \
+ .parse_node.wildcard_node = WILDCARD_NODE, \
+ .parse_node.proto_table = PROTO_TABLE, \
+ }
+
+/* Helper to create a flag-fields parse node */
+#define PANDA_MAKE_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PROTO_TABLE, \
+ FLAG_FIELDS_TABLE) \
+ PANDA_DECL_FLAG_FIELDS_TABLE(FLAG_FIELDS_TABLE); \
+ PANDA_DECL_PROTO_TABLE(PROTO_TABLE); \
+ __PANDA_MAKE_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ NULL, &PROTO_TABLE, \
+ &FLAG_FIELDS_TABLE)
+
+/* Helper to create an overlay flag-fields parse node */
+#define PANDA_MAKE_FLAG_FIELDS_OVERLAY_PARSE_NODE( \
+ PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ OVERLAY_NODE, \
+ FLAG_FIELDS_TABLE) \
+ PANDA_DECL_FLAG_FIELDS_TABLE(FLAG_FIELDS_TABLE); \
+ __PANDA_MAKE_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ OVERLAY_NODE, NULL, \
+ &FLAG_FIELDS_TABLE) \
+
+/* Helper to create a leaf flag-fields parse node */
+#define PANDA_MAKE_LEAF_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, \
+ HANDLER, \
+ FLAG_FIELDS_TABLE) \
+ PANDA_DECL_FLAG_FIELDS_TABLE(FLAG_FIELDS_TABLE); \
+ __PANDA_MAKE_FLAG_FIELDS_PARSE_NODE(PARSE_FLAG_FIELDS_NODE, \
+ PROTO_FLAG_FIELDS_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ NULL, NULL, \
+ &FLAG_FIELDS_TABLE)
+
+/* Helper to create a parse node for a single flag-field */
+#define PANDA_MAKE_FLAG_FIELD_PARSE_NODE(NODE_NAME, METADATA_FUNC, \
+ HANDLER_FUNC) \
+ static const struct panda_parse_flag_field_node NODE_NAME = { \
+ .ops.extract_metadata = METADATA_FUNC, \
+ .ops.handle_flag_field = HANDLER_FUNC, \
+ .name = #NODE_NAME, \
+ }
+
+/* Null flag-field node for filling out flag-fields table */
+PANDA_MAKE_FLAG_FIELD_PARSE_NODE(PANDA_FLAG_NODE_NULL, NULL, NULL);
+
+#endif /* __PANDA_FLAG_FIELDS_H__ */
new file mode 100644
@@ -0,0 +1,394 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PARSER_H__
+#define __PANDA_PARSER_H__
+
+/* Parser interface for PANDA
+ *
+ * Definitions and functions for PANDA parser.
+ */
+
+#include <linux/types.h>
+
+#include "net/panda/compiler_helpers.h"
+#include "net/panda/flag_fields.h"
+#include "net/panda/parser_types.h"
+#include "net/panda/tlvs.h"
+
+/* Panda parser return codes */
+enum {
+ PANDA_OKAY = 0, /* Okay and continue */
+ PANDA_STOP_OKAY = -1, /* Okay and stop parsing */
+
+ /* Parser failure */
+ PANDA_STOP_FAIL = -2,
+ PANDA_STOP_LENGTH = -3,
+ PANDA_STOP_UNKNOWN_PROTO = -4,
+ PANDA_STOP_ENCAP_DEPTH = -5,
+ PANDA_STOP_UNKNOWN_TLV = -6,
+ PANDA_STOP_TLV_LENGTH = -7,
+ PANDA_STOP_BAD_FLAG = -8,
+};
+
+/* Helper to create a parser */
+#define __PANDA_PARSER(PARSER, NAME, ROOT_NODE) \
+static const struct panda_parser __##PARSER = { \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_GENERIC, \
+ .parser_entry_point = NULL \
+}; \
+
+#define PANDA_PARSER(PARSER, NAME, ROOT_NODE) \
+ __PANDA_PARSER(PARSER, NAME, ROOT_NODE) \
+ static const struct panda_parser *PARSER __unused() = \
+ &__##PARSER;
+
+#define PANDA_PARSER_EXT(PARSER, NAME, ROOT_NODE) \
+ __PANDA_PARSER(PARSER, NAME, ROOT_NODE) \
+ const struct panda_parser *PARSER __unused() = &__##PARSER;
+
+/* Helper to create an optimized parservairant */
+#define __PANDA_PARSER_OPT(PARSER, NAME, ROOT_NODE, FUNC) \
+static const struct panda_parser __##PARSER = { \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_OPTIMIZED, \
+ .parser_entry_point = FUNC \
+};
+
+/* Helpers to create and use Kmod parser vairant */
+#define __PANDA_PARSER_KMOD(PARSER, NAME, ROOT_NODE, FUNC) \
+const struct panda_parser __##PARSER##_kmod = { \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_KMOD, \
+ .parser_entry_point = FUNC \
+};
+
+#define PANDA_PARSER_KMOD(PARSER, NAME, ROOT_NODE, FUNC) \
+ __PANDA_PARSER_KMOD(PARSER, NAME, ROOT_NODE, FUNC) \
+ const struct panda_parser *PARSER##_kmod = &__##PARSER##_kmod;
+
+#define PANDA_PARSER_KMOD_EXTERN(NAME) \
+ extern const struct panda_parser *NAME##_kmod
+
+#define PANDA_PARSER_KMOD_NAME(NAME) NAME##_kmod
+
+#define PANDA_PARSER_OPT(PARSER, NAME, ROOT_NODE, FUNC) \
+ __PANDA_PARSER_OPT(PARSER, NAME, ROOT_NODE, FUNC) \
+ static const struct panda_parser *PARSER __unused() = \
+ &__##PARSER;
+
+#define PANDA_PARSER_OPT_EXT(PARSER, NAME, ROOT_NODE, FUNC) \
+ __PANDA_PARSER_OPT(PARSER, NAME, ROOT_NODE, FUNC) \
+ const struct panda_parser *PARSER __unused() = &__##PARSER;
+
+/* Helper to create an XDP parser vairant */
+#define __PANDA_PARSER_XDP(PARSER, NAME, ROOT_NODE, FUNC) \
+static const struct panda_parser __##PARSER = { \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_XDP, \
+ .parser_xdp_entry_point = FUNC \
+};
+
+#define PANDA_PARSER_XDP(PARSER, NAME, ROOT_NODE, FUNC) \
+ __PANDA_PARSER_XDP(PARSER, NAME, ROOT_NODE, FUNC) \
+ static const struct panda_parser *__##PARSER##_ext = \
+ &__##PARSER;
+
+#define PANDA_PARSER_XDP_EXT(PARSER, NAME, ROOT_NODE, FUNC) \
+ __PANDA_PARSER_XDP(PARSER, NAME, ROOT_NODE, FUNC) \
+ const struct panda_parser *__##PARSER##_ext = &__##PARSER;
+
+/* Helper to create a parser table */
+#define PANDA_MAKE_PARSER_TABLE(NAME, ...) \
+ static const struct panda_parser_table_entry __##NAME[] = \
+ { __VA_ARGS__ }; \
+ static const struct panda_parser_table NAME = { \
+ .num_ents = sizeof(__##NAME) / \
+ sizeof(struct panda_parser_table_entry), \
+ .entries = __##NAME, \
+ }
+
+/* Helper to create a protocol table */
+#define PANDA_MAKE_PROTO_TABLE(NAME, ...) \
+ static const struct panda_proto_table_entry __##NAME[] = \
+ { __VA_ARGS__ }; \
+ static const struct panda_proto_table NAME = { \
+ .num_ents = sizeof(__##NAME) / \
+ sizeof(struct panda_proto_table_entry), \
+ .entries = __##NAME, \
+ }
+
+/* Forward declarations for parse nodes */
+#define PANDA_DECL_PARSE_NODE(PARSE_NODE) \
+ static const struct panda_parse_node PARSE_NODE
+
+/* Forward declarations for protocol tables */
+#define PANDA_DECL_PROTO_TABLE(PROTO_TABLE) \
+ static const struct panda_proto_table PROTO_TABLE
+
+/* Helper to create a parse node with a next protocol table */
+#define __PANDA_MAKE_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ UNKNOWN_RET, WILDCARD_NODE, \
+ PROTO_TABLE) \
+ static const struct panda_parse_node PARSE_NODE = { \
+ .proto_node = &PROTO_NODE, \
+ .ops.extract_metadata = EXTRACT_METADATA, \
+ .ops.handle_proto = HANDLER, \
+ .unknown_ret = UNKNOWN_RET, \
+ .wildcard_node = WILDCARD_NODE, \
+ .proto_table = PROTO_TABLE, \
+ }
+
+/* Helper to create a parse node with default unknown next proto function
+ * that returns parser failure code
+ */
+#define PANDA_MAKE_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, PROTO_TABLE) \
+ PANDA_DECL_PROTO_TABLE(PROTO_TABLE); \
+ __PANDA_MAKE_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, NULL, \
+ &PROTO_TABLE)
+
+/* Helper to create a parse node single overlay node */
+#define PANDA_MAKE_OVERLAY_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, OVERLAY_NODE) \
+ __PANDA_MAKE_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, OVERLAY_NODE, \
+ NULL)
+
+/* Helper to create a leaf parse node with no next protocol table */
+#define PANDA_MAKE_LEAF_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER) \
+ __PANDA_MAKE_PARSE_NODE(PARSE_NODE, PROTO_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, NULL, \
+ NULL)
+
+/* Parsing functions */
+
+/* Flags to Panda parser functions */
+#define PANDA_F_DEBUG (1 << 0)
+
+#ifndef __KERNEL__
+/* Parse starting at the provided root node */
+int __panda_parse(const struct panda_parser *parser, const void *hdr,
+ size_t len, struct panda_metadata *metadata,
+ unsigned int flags, unsigned int max_encaps);
+#else
+static inline int __panda_parse(const struct panda_parser *parser,
+ const void *hdr, size_t len, struct panda_metadata *metadata,
+ unsigned int flags, unsigned int max_encaps)
+{
+ return 0;
+}
+#endif
+
+/* Parse packet starting from a parser node
+ *
+ * Arguments:
+ * - parser: Parser being invoked
+ * - hdr: pointer to start of packet
+ * - len: length of packet
+ * - metadata: metadata structure
+ * - flags: allowed parameterized parsing
+ * - max_encaps: maximum layers of encapsulation to parse
+ *
+ * Returns PANDA return code value.
+ */
+static inline int panda_parse(const struct panda_parser *parser,
+ const void *hdr, size_t len,
+ struct panda_metadata *metadata,
+ unsigned int flags, unsigned int max_encaps)
+{
+ switch (parser->parser_type) {
+ case PANDA_GENERIC:
+ return __panda_parse(parser, hdr, len, metadata, flags,
+ max_encaps);
+ case PANDA_KMOD:
+ case PANDA_OPTIMIZED:
+ return (parser->parser_entry_point)(parser, hdr, len, metadata,
+ flags, max_encaps);
+ default:
+ return PANDA_STOP_FAIL;
+ }
+}
+
+extern int panda_parse_ethernet(const void *hdr, size_t len,
+ struct panda_metadata *metadata,
+ unsigned int flags, unsigned int max_encaps);
+
+static inline const struct panda_parser *panda_lookup_parser_table(
+ const struct panda_parser_table *table,
+ int key)
+{
+ int i;
+
+ for (i = 0; i < table->num_ents; i++)
+ if (table->entries[i].value == key)
+ return *table->entries[i].parser;
+
+ return NULL;
+}
+
+static inline int panda_parse_from_table(const struct panda_parser_table *table,
+ int key, const void *hdr, size_t len,
+ struct panda_metadata *metadata,
+ unsigned int flags,
+ unsigned int max_encaps)
+{
+ const struct panda_parser *parser;
+
+ if (!(parser = panda_lookup_parser_table(table, key)))
+ return PANDA_STOP_FAIL;
+
+ return panda_parse(parser, hdr, len, metadata, flags, max_encaps);
+}
+
+
+static inline int panda_parse_xdp(const struct panda_parser *parser,
+ struct panda_ctx *ctx, const void **hdr,
+ const void *hdr_end, bool tailcall)
+{
+ if (parser->parser_type != PANDA_XDP)
+ return PANDA_STOP_FAIL;
+
+ return (parser->parser_xdp_entry_point)(ctx, hdr, hdr_end, tailcall);
+}
+
+#define PANDA_PARSE_XDP(PARSER, CTX, HDR, HDR_END, TAILCALL) \
+ panda_xdp_parser_##PARSER(CTX, HDR, HDR_END, TAILCALL)
+
+/* Helper to make an extern for a parser */
+#define PANDA_PARSER_EXTERN(NAME) \
+ extern struct panda_parser *NAME
+
+/* Helper to make forward declaration for a const parser */
+#define PANDA_PARSER_DECL(NAME) \
+ static const struct panda_parser *NAME
+
+#define PANDA_PARSER_EXT_DECL(NAME) \
+ extern const struct panda_parser *NAME
+
+struct panda_parser_def {
+ struct panda_parser **parser;
+ const char *name;
+ const struct panda_parse_node *root_node;
+ enum panda_parser_type parser_type;
+ panda_parser_opt_entry_point parser_entry_point;
+} PANDA_ALIGN_SECTION;
+
+PANDA_DEFINE_SECTION(panda_parsers, struct panda_parser_def)
+
+/* Helper to add parser to list of parser at initialization */
+#define PANDA_PARSER_ADD(PARSER, NAME, ROOT_NODE) \
+struct panda_parser *PARSER; \
+static const struct panda_parser_def PANDA_SECTION_ATTR(panda_parsers) \
+ PANDA_UNIQUE_NAME(__panda_parsers_,) = { \
+ .parser = &PARSER, \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_GENERIC, \
+}
+
+/* Helper to add parser to list of parser at initialization */
+#define PANDA_PARSER_OPT_ADD(PARSER, NAME, ROOT_NODE, FUNC) \
+struct panda_parser *PARSER; \
+static const struct panda_parser_def PANDA_SECTION_ATTR(panda_parsers) \
+ PANDA_UNIQUE_NAME(__panda_parsers_,) = { \
+ .parser = &PARSER, \
+ .name = NAME, \
+ .root_node = ROOT_NODE, \
+ .parser_type = PANDA_OPTIMIZED, \
+ .parser_entry_point = FUNC \
+}
+
+
+struct panda_parser *panda_parser_create(const char *name,
+ const struct panda_parse_node
+ *root_node);
+void panda_parser_destroy(struct panda_parser *parser);
+int panda_parser_init(void);
+
+#ifndef __KERNEL__
+
+extern siphash_key_t __panda_hash_key;
+
+/* Helper functions to compute the siphash from start pointer
+ * through len bytes. Note that siphash library expects start to
+ * be aligned to 64 bits
+ */
+static inline __u32 panda_compute_hash(const void *start, size_t len)
+{
+ __u32 hash;
+
+ hash = siphash(start, len, &__panda_hash_key);
+ if (!hash)
+ hash = 1;
+
+ return hash;
+}
+
+/* Helper macro to compute a hash from a metadata structure. METADATA
+ * is a pointer to a metadata structure and HASH_START_FIELD is the offset
+ * within the structure to start the hash. This macro requires that the
+ * common metadata for IP addresses is defined in the metadata structure,
+ * that is there is an addrs field of type PANDA_METADATA_addrs in the
+ * metadata structure. The end offset of the hash area is the last byte
+ * of the addrs structure which can be different depending on the type
+ * of address (for instance, IPv6 addresses have more bytes than IPv4
+ * addresses so the length of the bytes hashed area will be greater).
+ */
+#define PANDA_COMMON_COMPUTE_HASH(METADATA, HASH_START_FIELD) ({ \
+ __u32 hash; \
+ const void *start = PANDA_HASH_START(METADATA, \
+ HASH_START_FIELD); \
+ size_t olen = PANDA_HASH_LENGTH(METADATA, \
+ offsetof(typeof(*METADATA), \
+ HASH_START_FIELD)); \
+ \
+ hash = panda_compute_hash(start, olen); \
+ hash; \
+})
+
+/* Initialization function for hash key. If the argument is NULL the
+ * hash key is randomly set
+ */
+void panda_hash_secret_init(siphash_key_t *init_key);
+
+/* Function to print the raw bytesused in a hash */
+void panda_print_hash_input(const void *start, size_t len);
+
+#endif /* __KERNEL__ */
+
+#endif /* __PANDA_PARSER_H__ */
new file mode 100644
@@ -0,0 +1,873 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PARSER_METADATA_H__
+#define __PANDA_PARSER_METADATA_H__
+
+/* Helper definitions for PANDA parser metadata handling
+ *
+ * This defines a set of macros, constants, and functions that can be
+ * optionally used in constructing parse nodes and to assist in meta
+ * data handling as well as packet hashing.
+ */
+
+#ifndef __KERNEL__
+#include <string.h>
+#endif
+
+#include <linux/if_ether.h>
+#include <linux/mpls.h>
+
+#include "net/panda/parser.h"
+
+/* The PANDA helpers defines a common set of fields that may be used in
+ * parser specific metadata structures. This is done at the granularity of
+ * field names. When the common names and their types are used in meta
+ * data structure then helper marcos can be used to create functions
+ * that take the parser specific data structure as an argument but
+ * operate on the common fields. In this way we can essentially have
+ * the same functions operate on different input structures, in particular
+ * we can define per protocol macros that extract common fields into
+ * different metadata structures. The type of the structure is an argument
+ * to the macro, and then from that a function definition can be ommited that
+ * uses the type. Here is an example to extract common metadata for IPv4
+ * into a user defined metadata structure.
+ *
+ * #define PANDA_METADATA_ipv4_addrs(NAME, STRUCT) \
+ * static void NAME(const void *viph, void *iframe) \
+ * { \
+ * struct STRUCT *frame = iframe; \
+ * const struct iphdr *iph = viph; \
+ * \
+ * frame->addr_type = PANDA_ADDR_TYPE_IPV4; \
+ * frame->ip_proto = iph->protocol; \
+ * memcpy(frame->addrs.v4_addrs, &iph->saddr, \
+ * sizeof(frame->addrs.v4_addrs)); \
+ * }
+ *
+ * In this example the common metadata field names used are addr_type,
+ * addrs.v4, and ip_proto.
+ *
+ * #defines for metadata names and their types are below. Note the macros
+ * can be used to define the common metadata fields in a data structure,
+ * however this is not required. As long as the types and names are
+ * maintained differnt definitions may be used. This is particulary relevant
+ * when common names are in data structures and the user may wish to add
+ * other elements in the structure
+ */
+
+/* Common metadata names and macro definitions. Add new common meta
+ * data names to this list
+ */
+
+#define PANDA_METADATA_eth_proto __be16 eth_proto
+#define PANDA_METADATA_eth_addrs __u8 eth_addrs[2 * ETH_ALEN]
+#define PANDA_TCP_MAX_SACKS 4
+
+enum panda_addr_types {
+ PANDA_ADDR_TYPE_INVALID = 0, /* Invalid addr type */
+ PANDA_ADDR_TYPE_IPV4,
+ PANDA_ADDR_TYPE_IPV6,
+ PANDA_ADDR_TYPE_TIPC,
+};
+
+#define PANDA_METADATA_addr_type __u8 addr_type
+#define PANDA_METADATA_addrs \
+ union { \
+ union { \
+ __be32 v4_addrs[2]; \
+ struct { \
+ __be32 saddr; \
+ __be32 daddr; \
+ } v4; \
+ }; \
+ union { \
+ struct in6_addr v6_addrs[2]; \
+ struct { \
+ struct in6_addr saddr; \
+ struct in6_addr daddr; \
+ } v6; \
+ }; \
+ __be32 tipckey; \
+ } addrs
+
+#define PANDA_METADATA_ip_proto __u8 ip_proto
+#define PANDA_METADATA_is_fragment __u8 is_fragment: 1
+#define PANDA_METADATA_first_frag __u8 first_frag: 1
+
+#define PANDA_METADATA_flow_label __u32 flow_label
+
+#define PANDA_METADATA_l2_off __u16 l2_off
+#define PANDA_METADATA_l3_off __u16 l3_off
+#define PANDA_METADATA_l4_off __u16 l4_off
+
+#define PANDA_METADATA_ports \
+ union { \
+ __be32 ports; \
+ __be16 port16[2]; \
+ struct { \
+ __be16 src_port; \
+ __be16 dst_port; \
+ }; \
+ struct { \
+ __be16 sport; \
+ __be16 dport; \
+ } port_pair; \
+ }
+
+#define PANDA_METADATA_tcp_options \
+ struct { \
+ __u16 mss; \
+ __u8 window_scaling; \
+ struct { \
+ __u32 value; \
+ __u32 echo; \
+ } timestamp; \
+ struct { \
+ __u32 left_edge; \
+ __u32 right_edge; \
+ } sack[PANDA_TCP_MAX_SACKS]; \
+ } tcp_options
+
+#define PANDA_METADATA_keyid __be32 keyid
+
+#define PANDA_MAX_VLAN_CNT 2
+#define PANDA_METADATA_vlan_count __u8 vlan_count : 2
+#define PANDA_METADATA_vlan \
+ struct { \
+ union { \
+ struct { \
+ __u16 id:12, \
+ dei:1, \
+ priority:3; \
+ }; \
+ __be16 tci; \
+ }; \
+ __be16 tpid; \
+ } vlan[PANDA_MAX_VLAN_CNT]
+
+#define PANDA_METADATA_icmp \
+ struct { \
+ __u8 type; \
+ __u8 code; \
+ __u16 id; \
+ } icmp
+
+#define PANDA_METADATA_mpls \
+ struct { \
+ __u32 ttl: 8; \
+ __u32 bos: 1; \
+ __u32 tc: 3; \
+ __u32 label: 20; \
+ } mpls
+
+#define PANDA_METADATA_arp \
+ struct { \
+ __u32 sip; \
+ __u32 tip; \
+ __u8 op; \
+ __u8 sha[ETH_ALEN]; \
+ __u8 tha[ETH_ALEN]; \
+ } arp
+
+#define PANDA_METADATA_gre \
+ struct { \
+ __u32 flags; \
+ __be16 csum; \
+ __be32 keyid; \
+ __be32 seq; \
+ __be32 routing; \
+ } gre
+
+#define PANDA_METADATA_gre_pptp \
+ struct { \
+ __u32 flags; \
+ __be16 length; \
+ __be16 callid; \
+ __be32 seq; \
+ __be32 ack; \
+ } gre_pptp
+
+/* Meta data structure containing all common metadata in canonical field
+ * order. eth_proto is declared as the hash start field for the common
+ * metadata structure. addrs is last field for canonical hashing.
+ */
+struct panda_metadata_all {
+ PANDA_METADATA_addr_type;
+ PANDA_METADATA_is_fragment;
+ PANDA_METADATA_first_frag;
+ PANDA_METADATA_vlan_count;
+ PANDA_METADATA_eth_addrs;
+ PANDA_METADATA_tcp_options;
+ PANDA_METADATA_mpls;
+ PANDA_METADATA_arp;
+ PANDA_METADATA_gre;
+ PANDA_METADATA_gre_pptp;
+ PANDA_METADATA_l2_off;
+ PANDA_METADATA_l3_off;
+ PANDA_METADATA_l4_off;
+
+
+#define PANDA_HASH_START_FIELD_ALL eth_proto
+ PANDA_METADATA_eth_proto __aligned(8);
+ PANDA_METADATA_ip_proto;
+ PANDA_METADATA_flow_label;
+ PANDA_METADATA_vlan;
+ PANDA_METADATA_keyid;
+ PANDA_METADATA_ports;
+ PANDA_METADATA_icmp;
+
+ PANDA_METADATA_addrs; /* Must be last */
+};
+
+#define PANDA_HASH_OFFSET_ALL \
+ offsetof(struct panda_metadata_all, \
+ PANDA_HASH_START_FIELD_ALL)
+
+/* Template for hash consistentify. Sort the source and destination IP (and the
+ * ports if the IP address are the same) to have consistent hash within the two
+ * directions.
+ */
+#define PANDA_HASH_CONSISTENTIFY(FRAME) do { \
+ int addr_diff, i; \
+ \
+ switch ((FRAME)->addr_type) { \
+ case PANDA_ADDR_TYPE_IPV4: \
+ addr_diff = (FRAME)->addrs.v4_addrs[1] - \
+ (FRAME)->addrs.v4_addrs[0]; \
+ if ((addr_diff < 0) || \
+ (addr_diff == 0 && ((FRAME)->port16[1] < \
+ (FRAME)->port16[0]))) { \
+ PANDA_SWAP((FRAME)->addrs.v4_addrs[0], \
+ (FRAME)->addrs.v4_addrs[1]); \
+ PANDA_SWAP((FRAME)->port16[0], \
+ (FRAME)->port16[1]); \
+ } \
+ break; \
+ case PANDA_ADDR_TYPE_IPV6: \
+ addr_diff = memcmp(&(FRAME)->addrs.v6_addrs[1], \
+ &(FRAME)->addrs.v6_addrs[0], \
+ sizeof((FRAME)->addrs.v6_addrs[1])); \
+ if ((addr_diff < 0) || \
+ (addr_diff == 0 && ((FRAME)->port16[1] < \
+ (FRAME)->port16[0]))) { \
+ for (i = 0; i < 4; i++) \
+ PANDA_SWAP((FRAME)->addrs.v6_addrs[0]. \
+ s6_addr32[i], \
+ (FRAME)->addrs.v6_addrs[1]. \
+ s6_addr32[i]); \
+ PANDA_SWAP((FRAME)->port16[0], \
+ (FRAME)->port16[1]); \
+ } \
+ break; \
+ } \
+} while (0)
+
+/* Helper to get starting address for hash start. This is just the
+ * address of the field name in HASH_START_FIELD of a metadata
+ * structure instance (indicated by pointer in FRAME)
+ */
+#define PANDA_HASH_START(FRAME, HASH_START_FIELD) \
+ (&(FRAME)->HASH_START_FIELD)
+
+/* Helper that returns the hash length for a metadata structure. This
+ * returns the end of the address fields for the given type (the
+ * address fields are assumed to be the common metadata fields in a nion
+ * in the last fields in the metadata structure). The macro returns the
+ * offset of the last byte of address minus the offset of the field
+ * where the hash starts as indicated by the HASH_OFFSET argument.
+ */
+#define PANDA_HASH_LENGTH(FRAME, HASH_OFFSET) ({ \
+ size_t diff = HASH_OFFSET + sizeof((FRAME)->addrs); \
+ \
+ switch ((FRAME)->addr_type) { \
+ case PANDA_ADDR_TYPE_IPV4: \
+ diff -= sizeof((FRAME)->addrs.v4_addrs); \
+ break; \
+ case PANDA_ADDR_TYPE_IPV6: \
+ diff -= sizeof((FRAME)->addrs.v6_addrs); \
+ break; \
+ } \
+ sizeof(*(FRAME)) - diff; \
+})
+
+/* Helpers to extract common metadata */
+
+/* Meta data helper for Ethernet.
+ * Uses common metadata fields: eth_proto, eth_addrs
+ */
+#define PANDA_METADATA_TEMP_ether(NAME, STRUCT) \
+static void NAME(const void *veth, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->eth_proto = ((struct ethhdr *)veth)->h_proto; \
+ memcpy(frame->eth_addrs, &((struct ethhdr *)veth)->h_dest, \
+ sizeof(frame->eth_addrs)); \
+}
+
+/* Meta data helper for Ethernet with setting L2 offset.
+ * Uses common metadata fields: eth_proto, eth_addrs, l2_off
+ */
+#define PANDA_METADATA_TEMP_ether_off(NAME, STRUCT) \
+static void NAME(const void *veth, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->l2_off = ctrl.hdr_offset; \
+ frame->eth_proto = ((struct ethhdr *)veth)->h_proto; \
+ memcpy(frame->eth_addrs, &((struct ethhdr *)veth)->h_dest, \
+ sizeof(frame->eth_addrs)); \
+}
+
+/* Meta data helper for Ethernet without extracting addresses.
+ * Uses common metadata fields: eth_proto
+ */
+#define PANDA_METADATA_TEMP_ether_noaddrs(NAME, STRUCT) \
+static void NAME(const void *veth, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->eth_proto = ((struct ethhdr *)veth)->h_proto; \
+}
+
+/* Meta data helper for IPv4.
+ * Uses common metadata fields: is_fragment, first_frag, ip_proto,
+ * addr_type, addrs.v4_addrs, l3_off
+ */
+#define PANDA_METADATA_TEMP_ipv4(NAME, STRUCT) \
+static void NAME(const void *viph, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct iphdr *iph = viph; \
+ \
+ if (ip_is_fragment(iph)) { \
+ frame->is_fragment = 1; \
+ frame->first_frag = \
+ !(iph->frag_off & htons(IP_OFFSET)); \
+ } \
+ \
+ frame->l3_off = ctrl.hdr_offset; \
+ frame->addr_type = PANDA_ADDR_TYPE_IPV4; \
+ frame->ip_proto = iph->protocol; \
+ memcpy(frame->addrs.v4_addrs, &iph->saddr, \
+ sizeof(frame->addrs.v4_addrs)); \
+}
+
+/* Meta data helper for IPv4 to only extract IP address.
+ * Uses common meta * data fields: ip_proto, addr_type, addrs.v4_addrs
+ */
+#define PANDA_METADATA_TEMP_ipv4_addrs(NAME, STRUCT) \
+static void NAME(const void *viph, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct iphdr *iph = viph; \
+ \
+ frame->addr_type = PANDA_ADDR_TYPE_IPV4; \
+ frame->ip_proto = iph->protocol; \
+ memcpy(frame->addrs.v4_addrs, &iph->saddr, \
+ sizeof(frame->addrs.v4_addrs)); \
+}
+
+/* Meta data helper for IPv6.
+ * Uses common metadata fields: ip_proto, addr_type, flow_label,
+ * addrs.v6_addrs, l3_off
+ */
+#define PANDA_METADATA_TEMP_ipv6(NAME, STRUCT) \
+static void NAME(const void *viph, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct ipv6hdr *iph = viph; \
+ \
+ frame->l3_off = ctrl.hdr_offset; \
+ frame->ip_proto = iph->nexthdr; \
+ frame->addr_type = PANDA_ADDR_TYPE_IPV6; \
+ frame->flow_label = ntohl(ip6_flowlabel(iph)); \
+ memcpy(frame->addrs.v6_addrs, &iph->saddr, \
+ sizeof(frame->addrs.v6_addrs)); \
+}
+
+/* Meta data helper for IPv6 to only extract IP address.
+ * Uses common metadata fields: ip_proto, addr_type, addrs.v6_addrs
+ */
+#define PANDA_METADATA_TEMP_ipv6_addrs(NAME, STRUCT) \
+static void NAME(const void *viph, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct ipv6hdr *iph = viph; \
+ \
+ frame->ip_proto = iph->nexthdr; \
+ frame->addr_type = PANDA_ADDR_TYPE_IPV6; \
+ memcpy(frame->addrs.v6_addrs, &iph->saddr, \
+ sizeof(frame->addrs.v6_addrs)); \
+}
+
+/* Meta data helper for transport ports.
+ * Uses common metadata fields: ports
+ */
+#define PANDA_METADATA_TEMP_ports(NAME, STRUCT) \
+static void NAME(const void *vphdr, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->ports = ((struct port_hdr *)vphdr)->ports; \
+}
+
+/* Meta data helper for transport with ports and offset
+ * Uses common metadata fields: ports, l4_off
+ */
+#define PANDA_METADATA_TEMP_ports_off(NAME, STRUCT) \
+static void NAME(const void *vphdr, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->ports = ((struct port_hdr *)vphdr)->ports; \
+ frame->l4_off = ctrl.hdr_offset; \
+}
+
+/* Meta data helpers for TCP options */
+
+/* Meta data helper for TCP MSS option
+ * Uses common metadata field: tcp_options
+ */
+#define PANDA_METADATA_TEMP_tcp_option_mss(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ const struct tcp_opt_union *opt = vopt; \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->tcp_options.mss = ntohs(opt->mss); \
+}
+
+/* Meta data helper for TCP window scaling option
+ * Uses common metadata field: tcp_options
+ */
+#define PANDA_METADATA_TEMP_tcp_option_window_scaling(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ const struct tcp_opt_union *opt = vopt; \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->tcp_options.window_scaling = opt->window_scaling; \
+}
+
+/* Meta data helper for TCP timestamps option
+ * Uses common metadata field: tcp_options
+ */
+#define PANDA_METADATA_TEMP_tcp_option_timestamp(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ const struct tcp_opt_union *opt = vopt; \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->tcp_options.timestamp.value = \
+ ntohl(opt->timestamp.value); \
+ frame->tcp_options.timestamp.echo = \
+ ntohl(opt->timestamp.echo); \
+}
+
+/* Common macro to set one metadata entry for sack. N indicates which
+ * entry (per protocol specification that is 0, 1, 2, or 3)
+ */
+#define PANDA_METADATA_SET_TCP_SACK(N, VOPT, IFRAME, STRUCT) do { \
+ const struct tcp_opt_union *opt = vopt; \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->tcp_options.sack[N].left_edge = \
+ ntohl(opt->sack[N].left_edge); \
+ frame->tcp_options.sack[N].right_edge = \
+ ntohl(opt->sack[N].right_edge); \
+} while (0)
+
+/* Meta data helper for setting one TCP sack option
+ * Uses common metadata field: tcp_options.sack[0]
+ */
+#define PANDA_METADATA_TEMP_tcp_option_sack_1(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ PANDA_METADATA_SET_TCP_SACK(0, vopt, iframe, STRUCT); \
+}
+
+/* Meta data helper for setting two TCP sack options
+ * Uses common metadata field: tcp_options.sack[0], tcp_options.sack[1]
+ */
+#define PANDA_METADATA_TEMP_tcp_option_sack_2(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ PANDA_METADATA_SET_TCP_SACK(0, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(1, vopt, iframe, STRUCT); \
+}
+
+/* Meta data helper for setting three TCP sack options
+ * Uses common metadata field: tcp_options.sack[0], tcp_options.sack[1],
+ * tcp_options.sack[2]
+ */
+#define PANDA_METADATA_TEMP_tcp_option_sack_3(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ PANDA_METADATA_SET_TCP_SACK(0, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(1, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(2, vopt, iframe, STRUCT); \
+}
+
+/* Meta data helper for setting four TCP sack options
+ * Uses common metadata field: tcp_options.sack[0], tcp_options.sack[1],
+ * tcp_options.sack[2], tcp_options.sack[3]
+ */
+#define PANDA_METADATA_TEMP_tcp_option_sack_4(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ PANDA_METADATA_SET_TCP_SACK(0, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(1, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(2, vopt, iframe, STRUCT); \
+ PANDA_METADATA_SET_TCP_SACK(3, vopt, iframe, STRUCT); \
+}
+
+/* Meta data helper for IP overlay (differentiate based on version number).
+ * Uses common metadata fields: eth_proto
+ */
+#define PANDA_METADATA_TEMP_ip_overlay(NAME, STRUCT) \
+static void NAME(const void *viph, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ switch (((struct ip_hdr_byte *)viph)->version) { \
+ case 4: \
+ frame->eth_proto = __cpu_to_be16(ETH_P_IP); \
+ break; \
+ case 6: \
+ frame->eth_proto = __cpu_to_be16(ETH_P_IPV6); \
+ break; \
+ } \
+}
+
+/* Meta data helper for Routing, DestOpt, and Hop-by-Hop extension headers.
+ * Uses common metadata fields: ip_proto
+ */
+#define PANDA_METADATA_TEMP_ipv6_eh(NAME, STRUCT) \
+static void NAME(const void *vopt, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ ((struct STRUCT *)iframe)->ip_proto = \
+ ((struct ipv6_opt_hdr *)vopt)->nexthdr; \
+}
+
+/* Meta data helper for Fragmentation extension header.
+ * Uses common metadata fields: ip_proto, is_fragment, first_frag
+ */
+#define PANDA_METADATA_TEMP_ipv6_frag(NAME, STRUCT) \
+static void NAME(const void *vfrag, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct ipv6_frag_hdr *frag = vfrag; \
+ \
+ frame->ip_proto = frag->nexthdr; \
+ frame->is_fragment = 1; \
+ frame->first_frag = !(frag->frag_off & htons(IP6_OFFSET)); \
+}
+
+/* Meta data helper for Fragmentation extension header without info.
+ * Uses common metadata fields: ip_proto
+ */
+#define PANDA_METADATA_TEMP_ipv6_frag_noinfo(NAME, STRUCT) \
+static void NAME(const void *vfrag, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ ((struct STRUCT *)iframe)->ip_proto = \
+ ((struct ipv6_frag_hdr *)vfrag)->nexthdr; \
+}
+
+#define PANDA_METADATA_TEMP_arp_rarp(NAME, STRUCT) \
+static void NAME(const void *vearp, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct earphdr *earp = vearp; \
+ \
+ frame->arp.op = ntohs(earp->arp.ar_op) & 0xff; \
+ \
+ /* Record Ethernet addresses */ \
+ memcpy(frame->arp.sha, earp->ar_sha, ETH_ALEN); \
+ memcpy(frame->arp.tha, earp->ar_tha, ETH_ALEN); \
+ \
+ /* Record IP addresses */ \
+ memcpy(&frame->arp.sip, &earp->ar_sip, sizeof(frame->arp.sip)); \
+ memcpy(&frame->arp.tip, &earp->ar_tip, sizeof(frame->arp.tip)); \
+}
+
+/* Meta data helper for VLAN.
+ * Uses common metadata fields: vlan_count, vlan[0].id, vlan[0].priority,
+ * vlan[0].tci, vlan[0].tpid, vlan[1].id, vlan[1].priority, vlan[1].tci,
+ * vlan[1].tpid
+ */
+#define PANDA_METADATA_TEMP_vlan_set_tpid(NAME, STRUCT, TPID) \
+static void NAME(const void *vvlan, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct vlan_hdr *vlan = vvlan; \
+ int index = (frame->vlan_count < PANDA_MAX_VLAN_CNT) ? \
+ frame->vlan_count++ : PANDA_MAX_VLAN_CNT - 1; \
+ \
+ frame->vlan[index].id = ntohs(vlan->h_vlan_TCI) & \
+ VLAN_VID_MASK; \
+ frame->vlan[index].priority = (ntohs(vlan->h_vlan_TCI) & \
+ VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; \
+ frame->vlan[index].tpid = TPID; \
+}
+
+#define PANDA_METADATA_TEMP_vlan_8021AD(NAME, STRUCT) \
+ PANDA_METADATA_TEMP_vlan_set_tpid(NAME, STRUCT, ETH_P_8021AD)
+
+#define PANDA_METADATA_TEMP_vlan_8021Q(NAME, STRUCT) \
+ PANDA_METADATA_TEMP_vlan_set_tpid(NAME, STRUCT, ETH_P_8021Q)
+
+/* Meta data helper for ICMP (ICMPv4 or ICMPv6).
+ * Uses common metadata fields: icmp.type, icmp.code, icmp.id
+ */
+#define PANDA_METADATA_TEMP_icmp(NAME, STRUCT) \
+static void NAME(const void *vicmp, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct icmphdr *icmp = vicmp; \
+ \
+ frame->icmp.type = icmp->type; \
+ frame->icmp.code = icmp->code; \
+ if (icmp_has_id(icmp->type)) \
+ frame->icmp.id = icmp->un.echo.id ? : 1; \
+ else \
+ frame->icmp.id = 0; \
+}
+
+/* Meta data helper for MPLS.
+ * Uses common metadata fields: mpls.label, mpls.ttl, mpls.tc, mpls.bos, keyid
+ */
+#define PANDA_METADATA_TEMP_mpls(NAME, STRUCT) \
+static void NAME(const void *vmpls, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct mpls_label *mpls = vmpls; \
+ __u32 entry, label; \
+ \
+ entry = ntohl(mpls[0].entry); \
+ label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; \
+ \
+ frame->mpls.label = label; \
+ frame->mpls.ttl = \
+ (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT; \
+ frame->mpls.tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT; \
+ frame->mpls.bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT; \
+ \
+ if (label == MPLS_LABEL_ENTROPY) \
+ frame->keyid = \
+ mpls[1].entry & htonl(MPLS_LS_LABEL_MASK); \
+}
+
+/* Meta data helper for tipc.
+ * Uses common metadata fields: addr_type, tipckwy
+ *
+ * For non keepalive message set source node identity in tipc addresses.
+ * For keepalive messages set the tipc address to a random number fo
+ * spread PROBE/PROBE_REPLY messages across cores.
+ */
+#define PANDA_METADATA_TEMP_tipc(NAME, STRUCT) \
+static void NAME(const void *vtipc, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ const struct tipc_basic_hdr *tipc = vtipc; \
+ \
+ __u32 w0 = ntohl(tipc->w[0]); \
+ bool keepalive_msg; \
+ \
+ keepalive_msg = (w0 & TIPC_KEEPALIVE_MSG_MASK) == \
+ TIPC_KEEPALIVE_MSG_MASK; \
+ frame->addrs.tipckey = keepalive_msg ? 0 : tipc->w[3]; \
+ frame->addr_type = PANDA_ADDR_TYPE_TIPC; \
+}
+
+/* Meta data helper for GRE (v0)
+ * Uses common metadata field: gre.flags
+ */
+#define PANDA_METADATA_TEMP_gre(NAME, STRUCT) \
+static void NAME(const void *vhdr, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre.flags = gre_get_flags(vhdr); \
+}
+
+/* Meta data helper for GRE-PPTP (GRE v1)
+ * Uses common metadata field: gre_pptp.flags
+ */
+#define PANDA_METADATA_TEMP_gre_pptp(NAME, STRUCT) \
+static void NAME(const void *vhdr, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre_pptp.flags = gre_get_flags(vhdr); \
+}
+
+/* Meta data helper for GRE checksum
+ * Uses common metadata field: gre.checksum
+ */
+#define PANDA_METADATA_TEMP_gre_checksum(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre.csum = *(__u16 *)vdata; \
+}
+
+/* Meta data helper for GRE keyid
+ * Uses common metadata field: gre.keyid and keyid
+ */
+#define PANDA_METADATA_TEMP_gre_keyid(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ __u32 v = *(__u32 *)vdata; \
+ \
+ frame->gre.keyid = v; \
+ frame->keyid = v; \
+}
+
+/* Meta data helper for GRE sequence number
+ * Uses common metadata field: gre.seq
+ */
+#define PANDA_METADATA_TEMP_gre_seq(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre.seq = *(__u32 *)vdata; \
+}
+
+/* Meta data helper for GRE routing
+ * Uses common metadata field: gre.routing
+ */
+#define PANDA_METADATA_TEMP_gre_routing(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre.routing = *(__u32 *)vdata; \
+}
+
+
+/* Meta data helper for GRE keyid
+ * Uses common metadata field: pptp.length, pptp.call_id, and keyid
+ */
+#define PANDA_METADATA_TEMP_gre_pptp_key(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ struct panda_pptp_id *key = (struct panda_pptp_id *)vdata; \
+ \
+ frame->keyid = key->val32; \
+ frame->gre_pptp.length = key->payload_len; \
+ frame->gre_pptp.callid = key->call_id; \
+}
+
+/* Meta data helper for GRE-pptp sequence number
+ * Uses common metadata field: pptp.seq
+ */
+#define PANDA_METADATA_TEMP_gre_pptp_seq(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre_pptp.seq = *(__u32 *)vdata; \
+}
+
+/* Meta data helper for GRE-pptp ACK
+ * Uses common metadata field: pptp.ack
+ */
+#define PANDA_METADATA_TEMP_gre_pptp_ack(NAME, STRUCT) \
+static void NAME(const void *vdata, void *iframe, \
+ struct panda_ctrl_data ctrl) \
+{ \
+ struct STRUCT *frame = iframe; \
+ \
+ frame->gre_pptp.ack = *(__u32 *)vdata; \
+}
+
+/* Helper function to define a function to print common metadata */
+#define PANDA_PRINT_METADATA(FRAME) do { \
+ char a4buf[INET_ADDRSTRLEN]; \
+ char a6buf[INET6_ADDRSTRLEN]; \
+ \
+ switch ((FRAME)->addr_type) { \
+ case PANDA_ADDR_TYPE_IPV4: \
+ printf("IPv4 source address: %s\n", \
+ inet_ntop(AF_INET, &(FRAME)->addrs.v4_addrs[0], \
+ a4buf, sizeof(a4buf))); \
+ printf("IPv4 destination address: %s\n", \
+ inet_ntop(AF_INET, &(FRAME)->addrs.v4_addrs[1], \
+ a4buf, sizeof(a4buf))); \
+ break; \
+ case PANDA_ADDR_TYPE_IPV6: \
+ printf("IPv6 source address: %s\n", \
+ inet_ntop(AF_INET6, &(FRAME)->addrs.v6_addrs[0], \
+ a6buf, sizeof(a6buf))); \
+ printf("IPv6 destination address: %s\n", \
+ inet_ntop(AF_INET6, &(FRAME)->addrs.v6_addrs[1], \
+ a6buf, sizeof(a6buf))); \
+ break; \
+ } \
+ printf("Source port %04x\n", ntohs((FRAME)->port16[0])); \
+ printf("Destination port %04x\n", ntohs((FRAME)->port16[1])); \
+} while (0)
+
+#endif /* __PANDA_PARSER_METADATA_H__ */
new file mode 100644
@@ -0,0 +1,255 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_TYPES_H__
+#define __PANDA_TYPES_H__
+
+/* Type definitions for PANDA parser */
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <linux/types.h>
+
+#include "net/panda/compiler_helpers.h"
+
+/* Panda parser type codes */
+enum panda_parser_type {
+ /* Use non-optimized loop panda parser algorithm */
+ PANDA_GENERIC = 0,
+ /* Use optimized, generated, parser algorithm */
+ PANDA_OPTIMIZED = 1,
+ /* XDP parser */
+ PANDA_XDP = 2,
+ /* Kernel module parser */
+ PANDA_KMOD = 3,
+};
+
+/* Parse and protocol node types */
+enum panda_parser_node_type {
+ /* Plain node, no super structure */
+ PANDA_NODE_TYPE_PLAIN,
+ /* TLVs node with super structure for TLVs */
+ PANDA_NODE_TYPE_TLVS,
+ /* Flag-fields with super structure for flag-fields */
+ PANDA_NODE_TYPE_FLAG_FIELDS,
+};
+
+/* Protocol parsing operations:
+ *
+ * len: Return length of protocol header. If value is NULL then the length of
+ * the header is taken from the min_len in the protocol node. If the
+ * return value < 0 (a PANDA_STOP_* return code value) this indicates an
+ * error and parsing is stopped. A the return value greater than or equal
+ * to zero then gives the protocol length. If the returned length is less
+ * than the minimum protocol length, indicated in min_len by the protocol
+ * node, then this considered and error.
+ * next_proto: Return next protocol. If value is NULL then there is no
+ * next protocol. If return value is greater than or equal to zero
+ * this indicates a protocol number that is used in a table lookup
+ * to get the next layer protocol node.
+ */
+struct panda_parse_ops {
+ ssize_t (*len)(const void *hdr);
+ int (*next_proto)(const void *hdr);
+};
+
+/* Protocol node
+ *
+ * This structure contains the definitions to describe parsing of one type
+ * of protocol header. Fields are:
+ *
+ * node_type: The type of the node (plain, TLVs, flag-fields)
+ * encap: Indicates an encapsulation protocol (e.g. IPIP, GRE)
+ * overlay: Indicates an overlay protocol. This is used, for example, to
+ * switch on version number of a protocol header (e.g. IP version number
+ * or GRE version number)
+ * name: Text name of protocol node for debugging
+ * min_len: Minimum length of the protocol header
+ * ops: Operations to parse protocol header
+ */
+struct panda_proto_node {
+ enum panda_parser_node_type node_type;
+ __u8 encap;
+ __u8 overlay;
+ const char *name;
+ size_t min_len;
+ const struct panda_parse_ops ops;
+};
+
+/* Panda generic metadata
+ *
+ * Contains an array of parser specific (user defined) metadata structures.
+ * Meta data structures are defined specifically for each parser. An
+ * instance of this metadata is a frame. One frame is used for each
+ * level of encapulation. When the number of encapsulation layers exceeds
+ * max_num_frame then last frame is reused
+ * encaps: Number of encapsulation protocol encountered.
+ * max_frame_num: Maximum number of frames. One frame is used for each
+ * level of encapulation. When the number of encapsulation
+ * layers exceeds this value the last frame is reuse used
+ * frame_size: The size in bytes of each metadata frame
+ * frame_data: Contains max_frame_num metadata frames
+ */
+struct panda_metadata {
+ unsigned int encaps;
+ unsigned int max_frame_num;
+ size_t frame_size;
+
+ /* Application specific metadata frames */
+ __u8 frame_data[0] __aligned(8);
+};
+
+struct panda_ctx {
+ __u32 frame_num;
+ __u32 next;
+ __u32 offset;
+ struct panda_metadata metadata;
+};
+
+struct panda_ctrl_data {
+ size_t hdr_len;
+ size_t hdr_offset;
+};
+
+/* Parse node operations
+ *
+ * Operations to process a parsing node
+ *
+ * extract_metadata: Extract metadata for the node. Input is the meta
+ * data frame which points to a parser defined metadata structure.
+ * If the value is NULL then no metadata is extracted
+ * handle_proto: Per protocol handler which allows arbitrary processing
+ * of a protocol layer. Input is the header data and a parser defined
+ * metadata structure for the current frame. Return value is a parser
+ * return code: PANDA_OKAY indicates no errors, PANDA_STOP* return
+ * values indicate to stop parsing
+ */
+struct panda_parse_node_ops {
+ void (*extract_metadata)(const void *hdr, void *frame,
+ const struct panda_ctrl_data ctrl);
+ int (*handle_proto)(const void *hdr, void *frame,
+ const struct panda_ctrl_data ctrl);
+};
+
+/* Protocol node and parse node operations ordering. When processing a
+ * layer, operations are called in following order:
+ *
+ * protoop.len
+ * parseop.extract_metadata
+ * parseop.handle_proto
+ * protoop.next_proto
+ */
+
+struct panda_parse_node;
+
+/* One entry in a protocol table:
+ * value: protocol number
+ * node: associated parse node for the protocol number
+ */
+struct panda_proto_table_entry {
+ int value;
+ const struct panda_parse_node *node;
+};
+
+/* Protocol table
+ *
+ * Contains a protocol table that maps a protocol number to a parse
+ * node
+ */
+struct panda_proto_table {
+ int num_ents;
+ const struct panda_proto_table_entry *entries;
+};
+
+/* Parse node definition. Defines parsing and processing for one node in
+ * the parse graph of a parser. Contains:
+ *
+ * node_type: The type of the node (plain, TLVs, flag-fields)
+ * proto_node: Protocol node
+ * ops: Parse node operations
+ * proto_table: Protocol table for next protocol. This must be non-null if
+ * next_proto is not NULL
+ */
+struct panda_parse_node {
+ enum panda_parser_node_type node_type;
+ int unknown_ret;
+ const struct panda_proto_node *proto_node;
+ const struct panda_parse_node_ops ops;
+ const struct panda_proto_table *proto_table;
+ const struct panda_parse_node *wildcard_node;
+};
+
+/* Declaration of a PANDA parser */
+struct panda_parser;
+
+/* Panda entry-point for optimized parsers */
+typedef int (*panda_parser_opt_entry_point)(const struct panda_parser *parser,
+ const void *hdr, size_t len,
+ struct panda_metadata *metadata,
+ unsigned int flags,
+ unsigned int max_encaps);
+
+/* Panda entry-point for XDP parsers */
+typedef int (*panda_parser_xdp_entry_point)(struct panda_ctx *ctx,
+ const void **hdr,
+ const void *hdr_end,
+ bool tailcall);
+
+/* Definition of a PANDA parser. Fields are:
+ *
+ * name: Text name for the parser
+ * root_node: Root parse node of the parser. When the parser is invoked
+ * parsing commences at this parse node
+ */
+struct panda_parser {
+ const char *name;
+ const struct panda_parse_node *root_node;
+ enum panda_parser_type parser_type;
+ panda_parser_opt_entry_point parser_entry_point;
+ panda_parser_xdp_entry_point parser_xdp_entry_point;
+};
+
+/* One entry in a parser table:
+ * value: key vlaue
+ * parser: parser associated with the key value
+ */
+struct panda_parser_table_entry {
+ int value;
+ struct panda_parser **parser;
+};
+
+/* Parser table
+ *
+ * Contains a parser table that maps a key value, which could be a protocol
+ * number, to a parser
+ */
+struct panda_parser_table {
+ int num_ents;
+ const struct panda_parser_table_entry *entries;
+};
+
+#endif /* __PANDA_TYPES_H__ */
new file mode 100644
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Include for all defined proto nodes */
+
+#include "net/panda/proto_nodes/proto_ether.h"
+#include "net/panda/proto_nodes/proto_pppoe.h"
+#include "net/panda/proto_nodes/proto_ipv4.h"
+#include "net/panda/proto_nodes/proto_ipv6.h"
+#include "net/panda/proto_nodes/proto_ports.h"
+#include "net/panda/proto_nodes/proto_tcp.h"
+#include "net/panda/proto_nodes/proto_ip.h"
+#include "net/panda/proto_nodes/proto_ipv6_eh.h"
+#include "net/panda/proto_nodes/proto_ipv4ip.h"
+#include "net/panda/proto_nodes/proto_ipv6ip.h"
+#include "net/panda/proto_nodes/proto_gre.h"
+#include "net/panda/proto_nodes/proto_vlan.h"
+#include "net/panda/proto_nodes/proto_icmp.h"
+#include "net/panda/proto_nodes/proto_ppp.h"
+#include "net/panda/proto_nodes/proto_mpls.h"
+#include "net/panda/proto_nodes/proto_arp_rarp.h"
+#include "net/panda/proto_nodes/proto_tipc.h"
+#include "net/panda/proto_nodes/proto_batman.h"
+#include "net/panda/proto_nodes/proto_igmp.h"
+#include "net/panda/proto_nodes/proto_fcoe.h"
new file mode 100644
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_ARP_RARP_H__
+#define __PANDA_PROTO_ARP_RARP_H__
+
+#ifndef __KERNEL__
+#include <arpa/inet.h>
+#endif
+
+#include <linux/if_arp.h>
+
+#include "net/panda/parser.h"
+
+/* ARP and RARP node definitions */
+
+struct earphdr {
+ struct arphdr arp;
+ __u8 ar_sha[ETH_ALEN];
+ __u8 ar_sip[4];
+ __u8 ar_tha[ETH_ALEN];
+ __u8 ar_tip[4];
+};
+
+static inline ssize_t arp_len_check(const void *vearp)
+{
+ const struct earphdr *earp = vearp;
+ const struct arphdr *arp = &earp->arp;
+
+ if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
+ arp->ar_pro != htons(ETH_P_IP) ||
+ arp->ar_hln != ETH_ALEN ||
+ arp->ar_pln != 4 ||
+ (arp->ar_op != htons(ARPOP_REPLY) &&
+ arp->ar_op != htons(ARPOP_REQUEST)))
+ return PANDA_STOP_FAIL;
+
+ return sizeof(struct earphdr);
+}
+
+#endif /* __PANDA_PROTO_ARP_RARP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_arp protocol node
+ *
+ * Parse ARP header
+ */
+static const struct panda_proto_node panda_parse_arp __unused() = {
+ .name = "ARP",
+ .min_len = sizeof(struct earphdr),
+ .ops.len = arp_len_check,
+};
+
+/* panda_parse_rarp protocol node
+ *
+ * Parse RARP header
+ */
+static const struct panda_proto_node panda_parse_rarp __unused() = {
+ .name = "RARP",
+ .min_len = sizeof(struct earphdr),
+ .ops.len = arp_len_check,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_BATMAN_H__
+#define __PANDA_PROTO_BATMAN_H__
+
+#include <linux/if_ether.h>
+
+#include "net/panda/parser.h"
+
+/* ARP and RARP node definitions */
+
+#define BATADV_COMPAT_VERSION 15
+
+enum batadv_packettype {
+ /* 0x00 - 0x3f: local packets or special rules for handling */
+ BATADV_IV_OGM = 0x00,
+ BATADV_BCAST = 0x01,
+ BATADV_CODED = 0x02,
+ BATADV_ELP = 0x03,
+ BATADV_OGM2 = 0x04,
+ /* 0x40 - 0x7f: unicast */
+#define BATADV_UNICAST_MIN 0x40
+ BATADV_UNICAST = 0x40,
+ BATADV_UNICAST_FRAG = 0x41,
+ BATADV_UNICAST_4ADDR = 0x42,
+ BATADV_ICMP = 0x43,
+ BATADV_UNICAST_TVLV = 0x44,
+#define BATADV_UNICAST_MAX 0x7f
+ /* 0x80 - 0xff: reserved */
+};
+
+struct batadv_unicast_packet {
+ __u8 packet_type;
+ __u8 version;
+ __u8 ttl;
+ __u8 ttvn; /* destination translation table version number */
+ __u8 dest[ETH_ALEN];
+ /* "4 bytes boundary + 2 bytes" long to make the payload after the
+ * following ethernet header again 4 bytes boundary aligned
+ */
+};
+
+struct batadv_eth {
+ struct batadv_unicast_packet batadv_unicast;
+ struct ethhdr eth;
+};
+
+static inline ssize_t batman_len_check(const void *vbeth)
+{
+ const struct batadv_eth *beth = vbeth;
+
+ if (beth->batadv_unicast.version != BATADV_COMPAT_VERSION ||
+ beth->batadv_unicast.packet_type != BATADV_UNICAST)
+ return PANDA_STOP_FAIL;
+
+ return sizeof(struct batadv_eth);
+}
+
+static inline int batman_proto(const void *vbeth)
+{
+ return ((struct batadv_eth *)vbeth)->eth.h_proto;
+}
+
+#endif /* __PANDA_PROTO_BATMAN_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* parse_batman panda_protocol node
+ *
+ * Parse BATMAN header
+ *
+ * Next protocol operation returns Ethertype (e.g. ETH_P_IPV4)
+ */
+static const struct panda_proto_node panda_parse_batman __unused() = {
+ .name = "BATMAN",
+ .encap = 1,
+ .min_len = sizeof(struct batadv_eth),
+ .ops.len = batman_len_check,
+ .ops.next_proto = batman_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_ETHER_H__
+#define __PANDA_PROTO_ETHER_H__
+
+/* Ethernet node definitions */
+
+#include <linux/if_ether.h>
+
+#include "net/panda/parser.h"
+
+static inline int ether_proto(const void *veth)
+{
+ return ((struct ethhdr *)veth)->h_proto;
+}
+
+#endif /* __PANDA_PROTO_ETHER_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ether protocol node
+ *
+ * Parses Ethernet header
+ *
+ * Next protocol operation returns Ethertype (e.g. ETH_P_IPV4)
+ */
+
+static const struct panda_proto_node panda_parse_ether __unused() = {
+ .name = "Ethernet",
+ .min_len = sizeof(struct ethhdr),
+ .ops.next_proto = ether_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_FCOE_H__
+#define __PANDA_PROTO_FCOE_H__
+
+#include "net/panda/parser.h"
+
+/* Generic FCOE node definitions */
+
+#define FCOE_HEADER_LEN 38
+
+#endif /* __PANDA_PROTO_FCOE_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_fcoe protocol node
+ *
+ * Parse FCOE header
+ */
+static const struct panda_proto_node panda_parse_fcoe __unused() = {
+ .name = "FCOE",
+ .min_len = FCOE_HEADER_LEN,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_GRE_H__
+#define __PANDA_PROTO_GRE_H__
+
+/* GRE node definitions */
+
+#ifndef __KERNEL__
+#include <arpa/inet.h>
+#endif
+
+#include <linux/ip.h>
+
+#include "net/panda/parser.h"
+
+/* Define common GRE constants. These normally come from linux/if_tunnel.h,
+ * however that include file has a lot of other definitions beyond just GRE
+ * which can be a problem compiling especially with older kernel includes. So
+ * we define the GRE values here if they aren't already defined elsewhere.
+ */
+#ifndef GRE_CSUM
+#define GRE_CSUM __cpu_to_be16(0x8000)
+#endif
+
+#ifndef GRE_ROUTING
+#define GRE_ROUTING __cpu_to_be16(0x4000)
+#endif
+
+#ifndef GRE_KEY
+#define GRE_KEY __cpu_to_be16(0x2000)
+#endif
+
+#ifndef GRE_SEQ
+#define GRE_SEQ __cpu_to_be16(0x1000)
+#endif
+
+#ifndef GRE_ACK
+#define GRE_ACK __cpu_to_be16(0x0080)
+#endif
+
+#ifndef GRE_VERSION
+#define GRE_VERSION __cpu_to_be16(0x0007)
+#endif
+
+#ifndef GRE_VERSION_0
+#define GRE_VERSION_0 __cpu_to_be16(0x0000)
+#endif
+
+#ifndef GRE_VERSION_1
+#define GRE_VERSION_1 __cpu_to_be16(0x0001)
+#endif
+
+#ifndef GRE_PROTO_PPP
+#define GRE_PROTO_PPP __cpu_to_be16(0x880b)
+#endif
+
+#ifndef GRE_PPTP_KEY_MASK
+#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
+#endif
+
+/* GRE flag-field definitions */
+static const struct panda_flag_fields gre_flag_fields = {
+ .fields = {
+ {
+#define GRE_FLAGS_CSUM_IDX 0
+ .flag = GRE_CSUM,
+ .size = sizeof(__be32),
+ },
+ {
+#define GRE_FLAGS_KEY_IDX 1
+ .flag = GRE_KEY,
+ .size = sizeof(__be32),
+ },
+#define GRE_FLAGS_SEQ_IDX 2
+ {
+ .flag = GRE_SEQ,
+ .size = sizeof(__be32),
+ },
+#define GRE_FLAGS_NUM_IDX 3
+ },
+ .num_idx = GRE_FLAGS_NUM_IDX
+};
+
+#define GRE_FLAGS_V0_MASK (GRE_CSUM | GRE_KEY | GRE_SEQ | GRE_ROUTING)
+
+static const struct panda_flag_fields pptp_gre_flag_fields = {
+ .fields = {
+ {
+#define GRE_PPTP_FLAGS_CSUM_IDX 0
+ .flag = GRE_CSUM,
+ .size = sizeof(__be32),
+ },
+ {
+#define GRE_PPTP_FLAGS_KEY_IDX 1
+ .flag = GRE_KEY,
+ .size = sizeof(__be32),
+ },
+#define GRE_PPTP_FLAGS_SEQ_IDX 2
+ {
+ .flag = GRE_SEQ,
+ .size = sizeof(__be32),
+ },
+#define GRE_PPTP_FLAGS_ACK_IDX 3
+ {
+ .flag = GRE_ACK,
+ .size = sizeof(__be32),
+ },
+#define GRE_PPTP_FLAGS_NUM_IDX 4
+ },
+ .num_idx = GRE_PPTP_FLAGS_NUM_IDX
+};
+
+#define GRE_FLAGS_V1_MASK (GRE_CSUM | GRE_KEY | GRE_SEQ | \
+ GRE_ROUTING | GRE_ACK)
+
+#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
+
+struct gre_hdr {
+ __be16 flags;
+ __be16 protocol;
+ __u8 fields[0];
+};
+
+struct panda_pptp_id {
+ union {
+ struct {
+ __u16 payload_len;
+ __u16 call_id;
+ };
+ __u32 val32;
+ };
+};
+
+static inline int gre_proto_version(const void *vgre)
+{
+ return ntohs(((struct gre_hdr *)vgre)->flags & GRE_VERSION);
+}
+
+static inline size_t gre_v0_len_from_flags(unsigned int flags)
+{
+ return sizeof(struct gre_hdr) +
+ panda_flag_fields_length(flags, &gre_flag_fields);
+}
+
+static inline ssize_t gre_v0_len_check(const void *vgre)
+{
+ const struct gre_hdr *gre = vgre;
+
+ /* Check for valid set of flags */
+ if (panda_flag_fields_check_invalid(gre->flags, GRE_FLAGS_V0_MASK |
+ GRE_VERSION))
+ return PANDA_STOP_BAD_FLAG;
+
+ /* Only look inside GRE without routing */
+ if (((struct gre_hdr *)vgre)->flags & GRE_ROUTING)
+ return PANDA_STOP_OKAY;
+
+ return gre_v0_len_from_flags(gre->flags);
+}
+
+static inline int gre_v0_proto(const void *vgre)
+{
+ return ((struct gre_hdr *)vgre)->protocol;
+}
+
+static inline size_t gre_v1_len_from_flags(unsigned int flags)
+{
+ return sizeof(struct gre_hdr) +
+ panda_flag_fields_length(flags, &pptp_gre_flag_fields);
+}
+
+static inline ssize_t gre_v1_len_check(const void *vgre)
+{
+ const struct gre_hdr *gre = vgre;
+
+ /* Check for valid set of flags */
+ if (panda_flag_fields_check_invalid(gre->flags, GRE_FLAGS_V1_MASK |
+ GRE_VERSION))
+ return PANDA_STOP_BAD_FLAG;
+
+ /* Only look inside GRE without routing */
+ if (((struct gre_hdr *)vgre)->flags & GRE_ROUTING)
+ return PANDA_STOP_OKAY;
+
+ /* Version1 must be PPTP, and check that keyid id set */
+ if (!(gre->protocol == GRE_PROTO_PPP && (gre->flags & GRE_KEY)))
+ return PANDA_STOP_OKAY;
+
+ return gre_v1_len_from_flags(gre->flags);
+}
+
+static inline int gre_v1_proto(const void *vgre)
+{
+ /* Protocol already checked in gre_v1_len_check. Returning zero
+ * means PPP
+ */
+
+ return 0;
+}
+
+#endif /* __PANDA_PROTO_GRE_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_gre_base protocol node
+ *
+ * Parse base GRE header as an overlay to determine GRE version
+ *
+ * Next protocol operation returns GRE version number (i.e. 0 or 1).
+ */
+static const struct panda_proto_node panda_parse_gre_base __unused() = {
+ .name = "GRE base",
+ .overlay = 1,
+ .min_len = sizeof(struct gre_hdr),
+ .ops.next_proto = gre_proto_version,
+};
+
+static inline __u32 gre_get_flags(const void *hdr)
+{
+ return ((struct gre_hdr *)hdr)->flags;
+}
+
+static inline size_t gre_fields_offset(const void *hdr)
+{
+ return sizeof(struct gre_hdr);
+}
+
+/* panda_parse_gre_v0 protocol node
+ *
+ * Parse a version 0 GRE header
+ *
+ * Next protocol operation returns a GRE protocol (e.g. ETH_P_IPV4).
+ */
+static const struct panda_proto_flag_fields_node
+ panda_parse_gre_v0 __unused() = {
+ .proto_node.node_type = PANDA_NODE_TYPE_FLAG_FIELDS,
+ .proto_node.name = "GRE v0",
+ .proto_node.encap = 1,
+ .proto_node.min_len = sizeof(struct gre_hdr),
+ .proto_node.ops.next_proto = gre_v0_proto,
+ .proto_node.ops.len = gre_v0_len_check,
+ .ops.get_flags = gre_get_flags,
+ .ops.start_fields_offset = gre_fields_offset,
+ .flag_fields = &gre_flag_fields,
+};
+
+/* panda_parse_gre_v1 protocol node
+ *
+ * Parse a version 1 GRE header
+ *
+ * Next protocol operation returns GRE_PROTO_PPP.
+ */
+static const struct panda_proto_flag_fields_node
+ panda_parse_gre_v1 __unused() = {
+ .proto_node.node_type = PANDA_NODE_TYPE_FLAG_FIELDS,
+ .proto_node.name = "GRE v1 - pptp",
+ .proto_node.encap = 1,
+ .proto_node.min_len = sizeof(struct gre_hdr),
+ .proto_node.ops.next_proto = gre_v1_proto,
+ .proto_node.ops.len = gre_v1_len_check,
+ .ops.get_flags = gre_get_flags,
+ .ops.start_fields_offset = gre_fields_offset,
+ .flag_fields = &pptp_gre_flag_fields,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_ICMP_H__
+#define __PANDA_PROTO_ICMP_H__
+
+/* Generic ICMP node definitions */
+
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+
+#include "net/panda/parser.h"
+
+static inline bool icmp_has_id(__u8 type)
+{
+ switch (type) {
+ case ICMP_ECHO:
+ case ICMP_ECHOREPLY:
+ case ICMP_TIMESTAMP:
+ case ICMP_TIMESTAMPREPLY:
+ case ICMPV6_ECHO_REQUEST:
+ case ICMPV6_ECHO_REPLY:
+ return true;
+ }
+
+ return false;
+}
+
+#endif /* __PANDA_PROTO_ICMP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_icmpv4 protocol node
+ *
+ * Parse ICMPv4 header
+ */
+static const struct panda_proto_node panda_parse_icmpv4 __unused() = {
+ .name = "ICMPv4",
+ .min_len = sizeof(struct icmphdr),
+};
+
+/* panda_parse_icmpv6 protocol node
+ *
+ * Parse ICMPv6 header
+ */
+static const struct panda_proto_node panda_parse_icmpv6 __unused() = {
+ .name = "ICMPv6",
+ .min_len = sizeof(struct icmp6hdr),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IGMP_H__
+#define __PANDA_PROTO_IGMP_H__
+
+/* PANDA protocol node for IGMP */
+
+#include <linux/igmp.h>
+
+#include "net/panda/parser.h"
+
+#endif /* __PANDA_PROTO_IGMP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_igmp protocol node
+ *
+ * Parse IGMP header
+ */
+static const struct panda_proto_node panda_parse_igmp __unused() = {
+ .name = "IGMP",
+ .min_len = sizeof(struct igmphdr),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IP_H__
+#define __PANDA_PROTO_IP_H__
+
+#include "net/panda/parser.h"
+
+/* IP overlay node definitions */
+
+#include <asm/byteorder.h>
+
+struct ip_hdr_byte {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 rsvd:4,
+ version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ rsvd:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+};
+
+static inline int ip_proto(const void *viph)
+{
+ return ((struct ip_hdr_byte *)viph)->version;
+}
+
+static inline size_t ip_min_len(const void *viph)
+{
+ return sizeof(struct ip_hdr_byte);
+}
+
+#endif /* __PANDA_PROTO_IP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* parse_ip protocol node
+ *
+ * Parses first byte of IP header to distinguish IP version (i.e. IPv4
+ * and IPv6)
+ *
+ * Next protocol operation returns IP version number (e.g. 4 for IPv4,
+ * 6 for IPv6)
+ */
+static const struct panda_proto_node panda_parse_ip __unused() = {
+ .name = "IP overlay",
+ .overlay = 1,
+ .min_len = sizeof(struct ip_hdr_byte),
+ .ops.next_proto = ip_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PROTO_IPV4_H__
+#define __PROTO_IPV4_H__
+
+/* IPv4 node definitions */
+
+#ifndef __KERNEL__
+#include <arpa/inet.h>
+#endif
+
+#include <linux/ip.h>
+
+#include "net/panda/parser.h"
+
+#define IP_MF 0x2000 /* Flag: "More Fragments" */
+#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
+
+static inline size_t ipv4_len(const void *viph)
+{
+ return ((struct iphdr *)viph)->ihl * 4;
+}
+
+static inline bool ip_is_fragment(const struct iphdr *iph)
+{
+ return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
+}
+
+static inline int ipv4_proto(const void *viph)
+{
+ const struct iphdr *iph = viph;
+
+ if (ip_is_fragment(iph) && (iph->frag_off & htons(IP_OFFSET))) {
+ /* Stop at a non-first fragment */
+ return PANDA_STOP_OKAY;
+ }
+
+ return iph->protocol;
+}
+
+static inline int ipv4_proto_stop1stfrag(const void *viph)
+{
+ const struct iphdr *iph = viph;
+
+ if (ip_is_fragment(iph)) {
+ /* Stop at all fragments */
+ return PANDA_STOP_OKAY;
+ }
+
+ return iph->protocol;
+}
+
+static inline ssize_t ipv4_length(const void *viph)
+{
+ return ipv4_len(viph);
+}
+
+static inline ssize_t ipv4_length_check(const void *viph)
+{
+ const struct iphdr *iph = viph;
+
+ if (iph->version != 4)
+ return PANDA_STOP_UNKNOWN_PROTO;
+
+ return ipv4_len(viph);
+}
+
+#endif /* __PROTO_IPV4_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ipv4 protocol node
+ *
+ * Parse IPv4 header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv4 __unused() = {
+ .name = "IPv4",
+ .min_len = sizeof(struct iphdr),
+ .ops.len = ipv4_length,
+ .ops.next_proto = ipv4_proto,
+};
+
+/* panda_parse_ipv4_stop1stfrag protocol node
+ *
+ * Parse IPv4 header but don't parse into first fragment
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv4_stop1stfrag __unused() = {
+ .name = "IPv4 without parsing 1st fragment",
+ .min_len = sizeof(struct iphdr),
+ .ops.len = ipv4_length,
+ .ops.next_proto = ipv4_proto_stop1stfrag,
+};
+
+/* panda_parse_ipv4_check protocol node
+ *
+ * Check version is four and parse IPv4 header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv4_check __unused() = {
+ .name = "IPv4-check",
+ .min_len = sizeof(struct iphdr),
+ .ops.len = ipv4_length_check,
+ .ops.next_proto = ipv4_proto,
+};
+
+/* panda_parse_ipv4_stop1stfrag_check protocol node
+ *
+ * Check IP version is four an parse IPv4 header but don't parse into first
+ * fragment
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv4_stop1stfrag_check
+ __unused() = {
+ .name = "IPv4 without parsing 1st fragment",
+ .min_len = sizeof(struct iphdr),
+ .ops.len = ipv4_length,
+ .ops.next_proto = ipv4_proto_stop1stfrag,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IPV4IP_H__
+#define __PANDA_PROTO_IPV4IP_H__
+
+/* IPv4 in IP node definitions */
+
+#include <linux/ip.h>
+
+#include "net/panda/parser.h"
+
+static inline int ipv4_proto_default(const void *viph)
+{
+ return 0; /* Indicates IPv4 */
+}
+
+#endif /* __PANDA_PROTO_IPV4IP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* parse_ipv4ip protocol node
+ *
+ * Parses IPv4IP header
+ *
+ * Next protocol operation returns 0 indicating IPv4
+ */
+static const struct panda_proto_node panda_parse_ipv4ip __unused() = {
+ .name = "IPv4 in IP",
+ .encap = 1,
+ .overlay = 1,
+ .min_len = sizeof(struct iphdr),
+ .ops.next_proto = ipv4_proto_default,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IPV6_H__
+#define __PANDA_PROTO_IPV6_H__
+
+/* IPv6 node definitions */
+
+#ifndef __KERNEL__
+#include <arpa/inet.h>
+#endif
+
+#include <linux/ipv6.h>
+
+#include "net/panda/parser.h"
+
+#define ipv6_optlen(p) (((p)->hdrlen+1) << 3)
+
+#define IPV6_FLOWLABEL_MASK htonl(0x000FFFFF)
+static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
+{
+ return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
+}
+
+static inline int ipv6_proto(const void *viph)
+{
+ return ((struct ipv6hdr *)viph)->nexthdr;
+}
+
+static inline int ipv6_proto_stopflowlabel(const void *viph)
+{
+ const struct ipv6hdr *iph = viph;
+
+ if (ip6_flowlabel(iph)) {
+ /* Don't continue if flowlabel is non-zero */
+ return PANDA_STOP_OKAY;
+ }
+
+ return iph->nexthdr;
+}
+
+static inline ssize_t ipv6_length_check(const void *viph)
+{
+ const struct ipv6hdr *iph = viph;
+
+ if (iph->version != 6)
+ return PANDA_STOP_UNKNOWN_PROTO;
+
+ return sizeof(struct ipv6hdr);
+}
+
+#endif /* __PANDA_PROTO_IPV6_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ipv6 protocol node
+ *
+ * Parse IPv6 header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv6 __unused() = {
+ .name = "IPv6",
+ .min_len = sizeof(struct ipv6hdr),
+ .ops.next_proto = ipv6_proto,
+};
+
+/* parse_ipv6_stopflowlabel protocol node
+ *
+ * Parse IPv6 header and stop at a non-zero flow label
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node
+ panda_parse_ipv6_stopflowlabel __unused() = {
+ .name = "IPv6 stop at non-zero flow label",
+ .min_len = sizeof(struct ipv6hdr),
+ .ops.next_proto = ipv6_proto_stopflowlabel,
+};
+
+
+/* panda_parse_ipv6_check protocol node
+ *
+ * Check version is six and parse IPv6 header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv6_check __unused() = {
+ .name = "IPv6",
+ .min_len = sizeof(struct ipv6hdr),
+ .ops.len = ipv6_length_check,
+ .ops.next_proto = ipv6_proto,
+};
+
+/* parse_ipv6_stopflowlabel_check protocol node
+ *
+ * Check version is six, parse IPv6 header, and stop at a non-zero flow label
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node
+ panda_parse_ipv6_stopflowlabel_check
+ __unused() = {
+ .name = "IPv6 stop at non-zero flow label",
+ .min_len = sizeof(struct ipv6hdr),
+ .ops.len = ipv6_length_check,
+ .ops.next_proto = ipv6_proto_stopflowlabel,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IPV6_EH_H__
+#define __PANDA_PROTO_IPV6_EH_H__
+
+/* Generic definitions for IPv6 extension headers */
+
+#ifndef __KERNEL__
+#include <arpa/inet.h>
+#endif
+
+#include <linux/ipv6.h>
+
+#include "net/panda/parser.h"
+
+struct ipv6_frag_hdr {
+ __u8 nexthdr;
+ __u8 reserved;
+ __be16 frag_off;
+ __be32 identification;
+};
+
+#define IP6_MF 0x0001
+#define IP6_OFFSET 0xFFF8
+
+static inline int ipv6_eh_proto(const void *vopt)
+{
+ return ((struct ipv6_opt_hdr *)vopt)->nexthdr;
+}
+
+static inline ssize_t ipv6_eh_len(const void *vopt)
+{
+ return ipv6_optlen((struct ipv6_opt_hdr *)vopt);
+}
+
+static inline int ipv6_frag_proto(const void *vfraghdr)
+{
+ const struct ipv6_frag_hdr *fraghdr = vfraghdr;
+
+ if (fraghdr->frag_off & htons(IP6_OFFSET)) {
+ /* Stop at non-first fragment */
+ return PANDA_STOP_OKAY;
+ }
+
+ return fraghdr->nexthdr;
+}
+
+#endif /* __PANDA_PROTO_IPV6_EH_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+static const struct panda_proto_node panda_parse_ipv6_eh __unused() = {
+ .name = "IPv6 EH",
+ .min_len = sizeof(struct ipv6_opt_hdr),
+ .ops.next_proto = ipv6_eh_proto,
+ .ops.len = ipv6_eh_len,
+};
+
+/* panda_parse_ipv6_eh protocol node
+ *
+ * Parse IPv6 extension header (Destinaion Options, Hop-by-Hop Options,
+ * or Routing Header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv6_frag_eh __unused() = {
+ .name = "IPv6 EH",
+ .min_len = sizeof(struct ipv6_frag_hdr),
+ .ops.next_proto = ipv6_frag_proto,
+};
+
+/* panda_parse_ipv6_frag_eh protocol node
+ *
+ * Parse IPv6 fragmentation header, stop parsing at first fragment
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ipv6_frag_eh_stop1stfrag
+ __unused() = {
+ .name = "IPv6 EH",
+ .min_len = sizeof(struct ipv6_frag_hdr),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_IPV6IP_H__
+#define __PANDA_PROTO_IPV6IP_H__
+
+/* IPv6 in IP node definitions */
+
+#include <linux/ipv6.h>
+
+#include "net/panda/parser.h"
+
+static inline int ipv6_proto_default(const void *viph)
+{
+ return 0; /* Indicates IPv6 */
+}
+
+#endif /* __PANDA_PROTO_IPV6IP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ipv6ip protocol node
+ *
+ * Parses IPv6IP header
+ *
+ * Next protocol operation returns 0 indicating IPv4
+ */
+static const struct panda_proto_node panda_parse_ipv6ip __unused() = {
+ .name = "IPv6 in IP",
+ .encap = 1,
+ .overlay = 1,
+ .min_len = sizeof(struct ipv6hdr),
+ .ops.next_proto = ipv6_proto_default,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_MPLS_H__
+#define __PANDA_PROTO_MPLS_H__
+
+/* MPLS node definitions */
+
+#include <linux/mpls.h>
+
+#include "net/panda/parser.h"
+
+#endif /* __PANDA_PROTO_MPLS_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_mpls protocol node
+ *
+ * Parse MPLS header
+ */
+static const struct panda_proto_node panda_parse_mpls __unused() = {
+ .name = "MPLS",
+ .min_len = 2 * sizeof(struct mpls_label),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_PORTS_H__
+#define __PANDA_PROTO_PORTS_H__
+
+#include "net/panda/parser.h"
+
+/* Transport nodes with ports definitions */
+
+struct port_hdr {
+ union {
+ __be32 ports;
+ struct {
+ __be16 sport;
+ __be16 dport;
+ };
+ };
+};
+
+#endif /* __PANDA_PROTO_PORTS_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* Generic PANDA parse nodes for transport protocols that contain port
+ * numbers cnanonical location
+ *
+ * Transport header starts with sixteen bit source and destination port
+ * numbers. Applicable protocols include TCP, UDP, SCTP, etc.
+ */
+static const struct panda_proto_node panda_parse_ports __unused() = {
+ .name = "Transport with ports",
+ .min_len = sizeof(struct port_hdr),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_PPP_H__
+#define __PANDA_PROTO_PPP_H__
+
+#include <linux/ppp_defs.h>
+
+#include "net/panda/parser.h"
+
+/* PPP node definitions */
+
+struct ppp_hdr_proto8 {
+ __u8 address;
+ __u8 control;
+ __u8 protocol;
+};
+
+struct ppp_hdr_proto16 {
+ __u8 address;
+ __u8 control;
+ __be16 protocol;
+};
+
+static inline int ppp_proto(const void *vppp)
+{
+ /*
+ https://tools.ietf.org/html/rfc1661#section-2
+ if most significant byte is odd protcol length is 1 byte
+ */
+ return ((struct ppp_hdr_proto8*)vppp)->protocol % 2 ? __be16_to_cpu(((struct ppp_hdr_proto8*)vppp)->protocol) : ((struct ppp_hdr_proto16*)vppp)->protocol;
+}
+
+static inline ssize_t ppp_length(const void *vppp)
+{
+ return ((struct ppp_hdr_proto8*)vppp)->protocol % 2 ? sizeof(struct ppp_hdr_proto8) : sizeof(struct ppp_hdr_proto16);
+}
+
+#endif /* __PANDA_PROTO_PPP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ppp protocol node
+ *
+ * Parse PPP header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_ppp __unused() = {
+ .name = "PPP",
+ .min_len = sizeof(struct ppp_hdr_proto8),
+ .ops.len = ppp_length,
+ .ops.next_proto = ppp_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_PPPOE_H__
+#define __PANDA_PROTO_PPPOE_H__
+
+#include "net/panda/parser.h"
+
+struct pppoe_hdr_proto8 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 type : 4;
+ __u8 ver : 4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver : 4;
+ __u8 type : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 code;
+ __be16 sid;
+ __be16 length;
+ __u8 protocol;
+} __attribute__((packed));
+
+struct pppoe_hdr_proto16 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 type : 4;
+ __u8 ver : 4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver : 4;
+ __u8 type : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 code;
+ __be16 sid;
+ __be16 length;
+ __be16 protocol;
+} __attribute__((packed));
+
+//int static_assert_global_v[sizeof(struct pppoe_hdr) == 6 ? -1 : 1];
+
+/* PPP node definitions */
+static inline int pppoe_proto(const void *vppp)
+{
+ /*
+ https://tools.ietf.org/html/rfc1661#section-2
+ if most significant byte is odd protcol length is 1 byte
+ */
+ return ((struct pppoe_hdr_proto8*)vppp)->protocol % 2 ? __be16_to_cpu(((struct pppoe_hdr_proto8*)vppp)->protocol) : ((struct pppoe_hdr_proto16*)vppp)->protocol;
+}
+
+static inline ssize_t pppoe_length(const void *vppp)
+{
+ return ((struct pppoe_hdr_proto8*)vppp)->protocol % 2 ? sizeof(struct pppoe_hdr_proto8) : sizeof(struct pppoe_hdr_proto16);
+}
+
+#endif /* __PANDA_PROTO_PPP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_ppp protocol node
+ *
+ * Parse PPP header
+ *
+ * Next protocol operation returns IP proto number (e.g. IPPROTO_TCP)
+ */
+static const struct panda_proto_node panda_parse_pppoe __unused() = {
+ .name = "PPPoE",
+ .min_len = sizeof(struct pppoe_hdr_proto8),
+ .ops.len = pppoe_length,
+ .ops.next_proto = pppoe_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_TCP_H__
+#define __PANDA_PROTO_TCP_H__
+
+#include <linux/tcp.h>
+
+#include "net/panda/parser.h"
+
+/* TCP node definitions */
+
+#define TCPOPT_NOP 1 /* Padding */
+#define TCPOPT_EOL 0 /* End of options */
+#define TCPOPT_MSS 2 /* Segment size negotiating */
+#define TCPOPT_WINDOW 3 /* Window scaling */
+#define TCPOPT_SACK_PERM 4 /* SACK Permitted */
+#define TCPOPT_SACK 5 /* SACK Block */
+#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
+#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
+#define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */
+#define TCPOPT_EXP 254 /* Experimental */
+
+struct tcp_opt {
+ __u8 type;
+ __u8 len;
+ __u8 data[0];
+};
+
+struct tcp_timestamp_option_data {
+ __be32 value;
+ __be32 echo;
+};
+
+struct tcp_sack_option_data {
+ __be32 left_edge;
+ __be32 right_edge;
+};
+
+#define TCP_MAX_SACKS 4
+
+struct tcp_opt_union {
+ struct tcp_opt opt;
+ union {
+ __be16 mss;
+ __u8 window_scaling;
+ struct tcp_timestamp_option_data timestamp;
+ struct tcp_sack_option_data sack[TCP_MAX_SACKS];
+ } __attribute__((packed));
+} __attribute__((packed));
+
+static inline ssize_t tcp_len(const void *vtcp)
+{
+ return ((struct tcphdr *)vtcp)->doff * 4;
+}
+
+static inline ssize_t tcp_tlv_len(const void *hdr)
+{
+ return ((struct tcp_opt *)hdr)->len;
+}
+
+static inline int tcp_tlv_type(const void *hdr)
+{
+ return ((struct tcp_opt *)hdr)->type;
+}
+
+static inline size_t tcp_tlvs_start_offset(const void *hdr)
+{
+ return sizeof(struct tcphdr);
+}
+
+#endif /* __PANDA_PROTO_TCP_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* PANDA protocol node for TCP
+ *
+ * There are two variants:
+ * - Parse TCP header and TLVs
+ * - Just parse header without parsing TLVs
+ */
+
+/* panda_parse_tcp_tlvs protocol node
+ *
+ * Parse TCP header and any TLVs
+ */
+static const struct panda_proto_tlvs_node panda_parse_tcp_tlvs __unused() = {
+ .proto_node.node_type = PANDA_NODE_TYPE_TLVS,
+ .proto_node.name = "TCP with TLVs",
+ .proto_node.min_len = sizeof(struct tcphdr),
+ .proto_node.ops.len = tcp_len,
+ .ops.len = tcp_tlv_len,
+ .ops.type = tcp_tlv_type,
+ .ops.start_offset = tcp_tlvs_start_offset,
+ .pad1_val = TCPOPT_NOP,
+ .pad1_enable = 1,
+ .eol_val = TCPOPT_EOL,
+ .eol_enable = 1,
+ .min_len = sizeof(struct tcp_opt),
+};
+
+/* panda_parse_tcp_no_tlvs protocol node
+ *
+ * Parse TCP header without considering TLVs
+ */
+static const struct panda_proto_node panda_parse_tcp_notlvs __unused() = {
+ .name = "TCP without TLVs",
+ .min_len = sizeof(struct tcphdr),
+ .ops.len = tcp_len,
+};
+
+/* Protocol nodes for individual TLVs */
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_mss
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) + sizeof(__be16),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_window_scaling
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) + sizeof(__u8),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_timestamp
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) +
+ sizeof(struct tcp_timestamp_option_data),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_sack_1
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) +
+ sizeof(struct tcp_sack_option_data),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_sack_2
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) +
+ 2 * sizeof(struct tcp_sack_option_data),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_sack_3
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) +
+ 3 * sizeof(struct tcp_sack_option_data),
+};
+
+static const struct panda_proto_tlv_node panda_parse_tcp_option_sack_4
+ __unused() = {
+ .min_len = sizeof(struct tcp_opt) +
+ 4 * sizeof(struct tcp_sack_option_data),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_TIPC_H__
+#define __PANDA_PROTO_TIPC_H__
+
+/* TIPC node definitions */
+
+#include <linux/ppp_defs.h>
+
+#include "net/panda/parser.h"
+
+/* LINK_PROTOCOL + MSG_IS_KEEPALIVE */
+#define TIPC_KEEPALIVE_MSG_MASK 0x0e080000
+
+struct tipc_basic_hdr {
+ __be32 w[4];
+};
+
+#endif /* __PANDA_PROTO_TIPC_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_tipc protocol node
+ *
+ * Parse TIPC header
+ */
+static const struct panda_proto_node panda_parse_tipc __unused() = {
+ .name = "TIPC",
+ .min_len = sizeof(struct tipc_basic_hdr),
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_VLAN_H__
+#define __PANDA_PROTO_VLAN_H__
+
+#include "net/panda/parser.h"
+
+#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */
+#define VLAN_PRIO_SHIFT 13
+#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
+
+/* VLAN node definitions */
+
+#ifndef __KERNEL__
+struct vlan_hdr {
+ __be16 h_vlan_TCI;
+ __be16 h_vlan_encapsulated_proto;
+};
+#endif
+
+static inline int vlan_proto(const void *vvlan)
+{
+ return ((struct vlan_hdr *)vvlan)->h_vlan_encapsulated_proto;
+}
+
+#endif /* __PANDA_PROTO_VLAN_H__ */
+
+#ifdef PANDA_DEFINE_PARSE_NODE
+
+/* panda_parse_vlan protocol node
+ *
+ * Parse VLAN header
+ *
+ * Next protocol operation returns Ethertype (e.g. ETH_P_IPV4)
+ */
+static const struct panda_proto_node panda_parse_vlan __unused() = {
+ .name = "VLAN",
+ .min_len = sizeof(struct vlan_hdr),
+ .ops.next_proto = vlan_proto,
+};
+
+#endif /* PANDA_DEFINE_PARSE_NODE */
new file mode 100644
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_PROTO_NODES_DEF_H__
+#define __PANDA_PROTO_NODES_DEF_H__
+
+/* Include all proto nodes and define proto nodes */
+
+#define PANDA_DEFINE_PARSE_NODE_STATIC static
+#define PANDA_DEFINE_PARSE_NODE 1
+
+#include "net/panda/proto_nodes.h"
+
+#undef PANDA_DEFINE_PARSE_NODE
+#undef PANDA_DEFINE_PARSE_NODE_STATIC
+
+#endif /* __PANDA_PROTO_NODES_H__ */
new file mode 100644
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020,2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PANDA_TLV_H__
+#define __PANDA_TLV_H__
+
+/* Definitions and functions for processing and parsing TLVs */
+
+#ifndef __KERNEL__
+#include <stddef.h>
+#include <sys/types.h>
+#endif
+
+#include <linux/types.h>
+
+#include "net/panda/parser_types.h"
+
+/* Definitions for parsing TLVs
+ *
+ * TLVs are a common protocol header structure consisting of Type, Length,
+ * Value tuple (e.g. for handling TCP or IPv6 HBH options TLVs)
+ */
+
+/* Descriptor for parsing operations of one type of TLV. Fields are:
+ *
+ * len: Return length of a TLV. Must be set. If the return value < 0 (a
+ * PANDA_STOP_* return code value) this indicates an error and parsing
+ * is stopped. A the return value greater than or equal to zero then
+ * gives the protocol length. If the returned length is less than the
+ * minimum TLV option length, indicated by min_len by the TLV protocol
+ * node, then this considered and error.
+ * type: Return the type of the TLV. If the return value is less than zero
+ * (PANDA_STOP_* value) then this indicates and error and parsing stops
+ */
+struct panda_proto_tlvs_opts {
+ size_t (*start_offset)(const void *hdr);
+ ssize_t (*len)(const void *hdr);
+ int (*type)(const void *hdr);
+};
+
+/* TLV parse node operations
+ *
+ * Operations to process a sigle TLV parsenode
+ *
+ * extract_metadata: Extract metadata for the node. Input is the meta
+ * data frame which points to a parser defined metadata structure.
+ * If the value is NULL then no metadata is extracted
+ * handle_tlv: Per TLV type handler which allows arbitrary processing
+ * of a TLV. Input is the TLV data and a parser defined metadata
+ * structure for the current frame. Return value is a parser
+ * return code: PANDA_OKAY indicates no errors, PANDA_STOP* return
+ * values indicate to stop parsing
+ */
+struct panda_parse_tlv_node_ops {
+ void (*extract_metadata)(const void *hdr, void *frame,
+ const struct panda_ctrl_data ctrl);
+ int (*handle_tlv)(const void *hdr, void *frame,
+ const struct panda_ctrl_data ctrl);
+ int (*overlay_type)(const void *hdr);
+};
+
+/* Parse node for a single TLV. Use common parse node operations
+ * (extract_metadata and handle_proto)
+ */
+struct panda_parse_tlv_node {
+ const struct panda_proto_tlv_node *proto_tlv_node;
+ const struct panda_parse_tlv_node_ops tlv_ops;
+ const struct panda_proto_tlvs_table *overlay_table;
+ const struct panda_parse_tlv_node *overlay_wildcard_node;
+ int unknown_overlay_ret;
+ const char *name;
+};
+
+/* One entry in a TLV table:
+ * value: TLV type
+ * node: associated TLV parse structure for the type
+ */
+struct panda_proto_tlvs_table_entry {
+ int type;
+ const struct panda_parse_tlv_node *node;
+};
+
+/* TLV table
+ *
+ * Contains a table that maps a TLV type to a TLV parse node
+ */
+struct panda_proto_tlvs_table {
+ int num_ents;
+ const struct panda_proto_tlvs_table_entry *entries;
+};
+
+/* Parse node for parsing a protocol header that contains TLVs to be
+ * parser:
+ *
+ * parse_node: Node for main protocol header (e.g. IPv6 node in case of HBH
+ * options) Note that node_type is set in parse_node to
+ * PANDA_NODE_TYPE_TLVS and that the parse node can then be cast to a
+ * parse_tlv_node
+ * tlv_proto_table: Lookup table for TLV type
+ * max_tlvs: Maximum number of TLVs that are to be parseed in one list
+ * max_tlv_len: Maximum length allowed for any TLV in a list
+ * one type of TLVS.
+ */
+struct panda_parse_tlvs_node {
+ const struct panda_parse_node parse_node;
+ const struct panda_proto_tlvs_table *tlv_proto_table;
+ size_t max_tlvs;
+ size_t max_tlv_len;
+ int unknown_tlv_type_ret;
+ const struct panda_parse_tlv_node *tlv_wildcard_node;
+};
+
+/* A protocol node for parsing proto with TLVs
+ *
+ * proto_node: proto node
+ * ops: Operations for parsing TLVs
+ * pad1_val: Type value indicating one byte of TLV padding (e.g. would be
+ * for IPv6 HBH TLVs)
+ * pad1_enable: Pad1 value is used to detect single byte padding
+ * eol_val: Type value that indicates end of TLV list
+ * eol_enable: End of list value in eol_val is used
+ * start_offset: When there TLVs start relative the enapsulating protocol
+ * (e.g. would be twenty for TCP)
+ * min_len: Minimal length of a TLV option
+ */
+struct panda_proto_tlvs_node {
+ struct panda_proto_node proto_node;
+ struct panda_proto_tlvs_opts ops;
+ __u8 pad1_val;
+ __u8 eol_val;
+ __u8 pad1_enable;
+ __u8 eol_enable;
+ size_t min_len;
+};
+
+/* A protocol node for parsing proto with TLVs
+ *
+ * min_len: Minimal length of TLV
+ */
+struct panda_proto_tlv_node {
+ size_t min_len;
+};
+
+/* Look up a TLV parse node given
+ *
+ * Arguments:
+ * - node: A TLVs parse node containing lookup table
+ * - type: TLV type to lookup
+ *
+ * Returns pointer to parse node if the protocol is matched else returns
+ * NULL if the parse node isn't found
+ */
+const struct panda_parse_tlv_node *panda_parse_lookup_tlv(
+ const struct panda_parse_tlvs_node *node,
+ unsigned int type);
+
+/* Helper to create a TLV protocol table */
+#define PANDA_MAKE_TLV_TABLE(NAME, ...) \
+ static const struct panda_proto_tlvs_table_entry __##NAME[] = \
+ { __VA_ARGS__ }; \
+ static const struct panda_proto_tlvs_table NAME = { \
+ .num_ents = sizeof(__##NAME) / \
+ sizeof(struct panda_proto_tlvs_table_entry), \
+ .entries = __##NAME, \
+ }
+
+/* Forward declarations for TLV parser nodes */
+#define PANDA_DECL_TLVS_PARSE_NODE(TLVS_PARSE_NODE) \
+ static const struct panda_parse_tlvs_node TLVS_PARSE_NODE
+
+/* Forward declarations for TLV type tables */
+#define PANDA_DECL_TLVS_TABLE(TLVS_TABLE) \
+ static const struct panda_proto_tlvs_table TLVS_TABLE
+
+/* Helper to create a parse node with a next protocol table */
+#define __PANDA_MAKE_TLVS_PARSE_NODE(PARSE_TLV_NODE, PROTO_TLV_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ UNKNOWN_RET, WILDCARD_NODE, \
+ UNKNOWN_TLV_TYPE_RET, \
+ TLV_WILDCARD_NODE, \
+ PROTO_TABLE, TLV_TABLE) \
+ static const struct panda_parse_tlvs_node PARSE_TLV_NODE = { \
+ .parse_node.node_type = PANDA_NODE_TYPE_TLVS, \
+ .parse_node.proto_node = &PROTO_TLV_NODE.proto_node, \
+ .parse_node.ops.extract_metadata = EXTRACT_METADATA, \
+ .parse_node.ops.handle_proto = HANDLER, \
+ .parse_node.unknown_ret = UNKNOWN_RET, \
+ .parse_node.wildcard_node = WILDCARD_NODE, \
+ .parse_node.proto_table = PROTO_TABLE, \
+ .tlv_proto_table = TLV_TABLE, \
+ .unknown_tlv_type_ret = UNKNOWN_TLV_TYPE_RET, \
+ .tlv_wildcard_node = TLV_WILDCARD_NODE, \
+ }
+
+/* Helper to create a TLVs parse node with default unknown next proto
+ * function that returns parse failure code and default unknown TLV
+ * function that ignores unknown TLVs
+ */
+#define PANDA_MAKE_TLVS_PARSE_NODE(PARSE_TLV_NODE, PROTO_TLV_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PROTO_TABLE, TLV_TABLE) \
+ PANDA_DECL_TLVS_TABLE(TLV_TABLE); \
+ PANDA_DECL_PROTO_TABLE(PROTO_TABLE) \
+ __PANDA_MAKE_TLVS_PARSE_NODE(PARSE_TLV_NODE, \
+ (PROTO_NODE).pnode, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, NULL, \
+ PANDA_OKAY, NULL, \
+ &PROTO_TABLE, &TLV_TABLE)
+
+/* Helper to create a TLVs parse node with default unknown next proto
+ * function that returns parse failure code and default unknown TLV
+ * function that ignores unknown TLVs
+ */
+#define PANDA_MAKE_TLVS_OVERLAY_PARSE_NODE(PARSE_TLV_NODE, \
+ PROTO_TLV_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ OVERLAY_NODE, TLV_TABLE) \
+ PANDA_DECL_TLVS_TABLE(TLV_TABLE); \
+ __PANDA_MAKE_TLVS_PARSE_NODE(PARSE_TLV_NODE, \
+ (PROTO_NODE).pnode, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, \
+ OVERLAY_NODE, PANDA_OKAY, NULL, \
+ &PROTO_TABLE, &TLV_TABLE)
+
+/* Helper to create a leaf TLVs parse node with default unknown TLV
+ * function that ignores unknown TLVs
+ */
+#define PANDA_MAKE_LEAF_TLVS_PARSE_NODE(PARSE_TLV_NODE, PROTO_TLV_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ TLV_TABLE) \
+ PANDA_DECL_TLVS_TABLE(TLV_TABLE); \
+ __PANDA_MAKE_TLVS_PARSE_NODE(PARSE_TLV_NODE, PROTO_TLV_NODE, \
+ EXTRACT_METADATA, HANDLER, \
+ PANDA_STOP_UNKNOWN_PROTO, NULL, \
+ PANDA_OKAY, NULL, \
+ NULL, &TLV_TABLE)
+
+#define PANDA_MAKE_TLV_PARSE_NODE(NODE_NAME, PROTO_TLV_NODE, \
+ METADATA_FUNC, HANDLER_FUNC) \
+ static const struct panda_parse_tlv_node NODE_NAME = { \
+ .proto_tlv_node = &PROTO_TLV_NODE, \
+ .tlv_ops.extract_metadata = METADATA_FUNC, \
+ .tlv_ops.handle_tlv = HANDLER_FUNC, \
+ .name = #NODE_NAME, \
+ }
+
+#define PANDA_MAKE_TLV_OVERLAY_PARSE_NODE(NODE_NAME, \
+ METADATA_FUNC, HANDLER_FUNC, \
+ OVERLAY_TABLE, \
+ OVERLAY_TYPE_FUNC, \
+ UNKNOWN_OVERLAY_RET, \
+ OVERLAY_WILDCARD_NODE) \
+ PANDA_DECL_TLVS_TABLE(OVERLAY_TABLE); \
+ static const struct panda_parse_tlv_node NODE_NAME = { \
+ .tlv_ops.extract_metadata = METADATA_FUNC, \
+ .tlv_ops.handle_tlv = HANDLER_FUNC, \
+ .tlv_ops.overlay_type = OVERLAY_TYPE_FUNC, \
+ .unknown_overlay_ret = UNKNOWN_OVERLAY_RET, \
+ .overlay_wildcard_node = OVERLAY_WILDCARD_NODE, \
+ .overlay_table = &OVERLAY_TABLE, \
+ .name = #NODE_NAME, \
+ }
+
+#endif /* __PANDA_TLV_H__ */
@@ -455,4 +455,13 @@ config ETHTOOL_NETLINK
netlink. It provides better extensibility and some new features,
e.g. notification messages.
+config NET_PANDA
+ bool "PANDA parser"
+ help
+ If you say Y here, you will be able to classify packets based on
+ a configurable combination of packet keys and masks.
+
+ To compile this code as a module, choose M here: the module will
+ be called cls_flower.
+
endif # if NET
@@ -79,3 +79,4 @@ obj-$(CONFIG_NET_NCSI) += ncsi/
obj-$(CONFIG_XDP_SOCKETS) += xdp/
obj-$(CONFIG_MPTCP) += mptcp/
obj-$(CONFIG_MCTP) += mctp/
+obj-$(CONFIG_PANDA) += panda/
new file mode 100644
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Linux networking PANDA parser.
+#
+
+ifeq ($(CONFIG_NET_PANDA),y)
+obj-$(CONFIG_NET_PANDA) += panda_parser.o
+endif
new file mode 100644
@@ -0,0 +1,605 @@
+// SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+/*
+ * Copyright (c) 2020, 2021 SiPanda Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <net/panda/parser.h>
+
+/* Lookup a type in a node table*/
+static const struct panda_parse_node *lookup_node(int type,
+ const struct panda_proto_table *table)
+{
+ int i;
+
+ for (i = 0; i < table->num_ents; i++)
+ if (type == table->entries[i].value)
+ return table->entries[i].node;
+
+ return NULL;
+}
+
+/* Lookup a type in a node TLV table */
+static const struct panda_parse_tlv_node *lookup_tlv_node(int type,
+ const struct panda_proto_tlvs_table *table)
+{
+ int i;
+
+ for (i = 0; i < table->num_ents; i++)
+ if (type == table->entries[i].type)
+ return table->entries[i].node;
+
+ return NULL;
+}
+
+/* Lookup up a protocol for the table associated with a parse node */
+const struct panda_parse_tlv_node *panda_parse_lookup_tlv(
+ const struct panda_parse_tlvs_node *node,
+ unsigned int type)
+{
+ return lookup_tlv_node(type, node->tlv_proto_table);
+}
+
+/* Lookup a flag-fields index in a protocol node flag-fields table */
+static const struct panda_parse_flag_field_node *lookup_flag_field_node(int idx,
+ const struct panda_proto_flag_fields_table
+ *table)
+{
+ int i;
+
+ for (i = 0; i < table->num_ents; i++)
+ if (idx == table->entries[i].index)
+ return table->entries[i].node;
+
+ return NULL;
+}
+
+static int panda_parse_one_tlv(
+ const struct panda_parse_tlvs_node *parse_tlvs_node,
+ const struct panda_parse_tlv_node *parse_tlv_node,
+ const void *hdr, void *frame, int type,
+ struct panda_ctrl_data tlv_ctrl, unsigned int flags)
+{
+ const struct panda_proto_tlv_node *proto_tlv_node =
+ parse_tlv_node->proto_tlv_node;
+ const struct panda_parse_tlv_node_ops *ops;
+ int ret;
+
+parse_again:
+
+ if (flags & PANDA_F_DEBUG)
+ printf("PANDA parsing TLV %s\n", parse_tlv_node->name);
+
+ if (proto_tlv_node && (tlv_ctrl.hdr_len < proto_tlv_node->min_len)) {
+ /* Treat check length error as an unrecognized TLV */
+ parse_tlv_node = parse_tlvs_node->tlv_wildcard_node;
+ if (parse_tlv_node)
+ goto parse_again;
+ else
+ return parse_tlvs_node->unknown_tlv_type_ret;
+ }
+
+ ops = &parse_tlv_node->tlv_ops;
+
+ if (ops->extract_metadata)
+ ops->extract_metadata(hdr, frame, tlv_ctrl);
+
+ if (ops->handle_tlv) {
+ ret = ops->handle_tlv(hdr, frame, tlv_ctrl);
+ if (ret != PANDA_OKAY)
+ return ret;
+ }
+
+ if (!parse_tlv_node->overlay_table)
+ return PANDA_OKAY;
+
+ /* We have an TLV overlay node */
+
+ if (parse_tlv_node->tlv_ops.overlay_type)
+ type = parse_tlv_node->tlv_ops.overlay_type(hdr);
+ else
+ type = tlv_ctrl.hdr_len;
+
+ /* Get TLV node */
+ parse_tlv_node = lookup_tlv_node(type, parse_tlv_node->overlay_table);
+ if (parse_tlv_node)
+ goto parse_again;
+
+ /* Unknown TLV overlay node */
+ parse_tlv_node = parse_tlv_node->overlay_wildcard_node;
+ if (parse_tlv_node)
+ goto parse_again;
+
+ return parse_tlv_node->unknown_overlay_ret;
+}
+
+static int panda_parse_tlvs(const struct panda_parse_node *parse_node,
+ const void *hdr, void *frame,
+ const struct panda_ctrl_data ctrl,
+ unsigned int flags)
+{
+ const struct panda_parse_tlvs_node *parse_tlvs_node;
+ const struct panda_proto_tlvs_node *proto_tlvs_node;
+ const struct panda_parse_tlv_node *parse_tlv_node;
+ size_t off, len, offset = ctrl.hdr_offset;
+ struct panda_ctrl_data tlv_ctrl;
+ const __u8 *cp = hdr;
+ ssize_t tlv_len;
+ int type, ret;
+
+ parse_tlvs_node = (struct panda_parse_tlvs_node *)parse_node;
+ proto_tlvs_node = (struct panda_proto_tlvs_node *)
+ parse_node->proto_node;
+
+ /* Assume hlen marks end of TLVs */
+ off = proto_tlvs_node->ops.start_offset(hdr);
+
+ /* We assume start offset is less than or equal to minimal length */
+ len = ctrl.hdr_len - off;
+
+ cp += off;
+ offset += off;
+
+ while (len > 0) {
+ if (proto_tlvs_node->pad1_enable &&
+ *cp == proto_tlvs_node->pad1_val) {
+ /* One byte padding, just advance */
+ cp++;
+ offset++;
+ len--;
+ continue;
+ }
+
+ if (proto_tlvs_node->eol_enable &&
+ *cp == proto_tlvs_node->eol_val) {
+ cp++;
+ offset++;
+ len--;
+
+ /* Hit EOL, we're done */
+ break;
+ }
+
+ if (len < proto_tlvs_node->min_len) {
+ /* Length error */
+ return PANDA_STOP_TLV_LENGTH;
+ }
+
+ /* If the len function is not set this degenerates to an
+ * array of fixed sized values (which maybe be useful in
+ * itself now that I think about it)
+ */
+ if (proto_tlvs_node->ops.len) {
+ tlv_len = proto_tlvs_node->ops.len(cp);
+ if (!tlv_len || len < tlv_len)
+ return PANDA_STOP_TLV_LENGTH;
+
+ if (tlv_len < proto_tlvs_node->min_len)
+ return tlv_len < 0 ? tlv_len :
+ PANDA_STOP_TLV_LENGTH;
+ } else {
+ tlv_len = proto_tlvs_node->min_len;
+ }
+
+ tlv_ctrl.hdr_len = tlv_len;
+ tlv_ctrl.hdr_offset = offset;
+
+ type = proto_tlvs_node->ops.type(cp);
+
+ /* Get TLV node */
+ parse_tlv_node = lookup_tlv_node(type,
+ parse_tlvs_node->tlv_proto_table);
+ if (parse_tlv_node) {
+parse_one_tlv:
+ ret = panda_parse_one_tlv(parse_tlvs_node,
+ parse_tlv_node, cp, frame,
+ type, tlv_ctrl, flags);
+ if (ret != PANDA_OKAY)
+ return ret;
+ } else {
+ /* Unknown TLV */
+ parse_tlv_node = parse_tlvs_node->tlv_wildcard_node;
+ if (parse_tlv_node) {
+ /* If a wilcard node is present parse that
+ * node as an overlay to this one. The
+ * wild card node can perform error processing
+ */
+ goto parse_one_tlv;
+ } else {
+ /* Return default error code. Returning
+ * PANDA_OKAY means skip
+ */
+ if (parse_tlvs_node->unknown_tlv_type_ret !=
+ PANDA_OKAY)
+ return
+ parse_tlvs_node->unknown_tlv_type_ret;
+ }
+ }
+
+ /* Move over current header */
+ cp += tlv_len;
+ offset += tlv_len;
+ len -= tlv_len;
+ }
+
+ return PANDA_OKAY;
+}
+
+static int panda_parse_flag_fields(const struct panda_parse_node *parse_node,
+ const void *hdr, void *frame,
+ struct panda_ctrl_data ctrl,
+ unsigned int pflags)
+{
+ const struct panda_parse_flag_fields_node *parse_flag_fields_node;
+ const struct panda_proto_flag_fields_node *proto_flag_fields_node;
+ const struct panda_parse_flag_field_node *parse_flag_field_node;
+ const struct panda_flag_fields *flag_fields;
+ size_t offset = ctrl.hdr_offset, ioff;
+ ssize_t off;
+ __u32 flags;
+ int i;
+
+ parse_flag_fields_node =
+ (struct panda_parse_flag_fields_node *)parse_node;
+ proto_flag_fields_node =
+ (struct panda_proto_flag_fields_node *)
+ parse_node->proto_node;
+ flag_fields = proto_flag_fields_node->flag_fields;
+
+ flags = proto_flag_fields_node->ops.get_flags(hdr);
+
+ /* Position at start of field data */
+ ioff = proto_flag_fields_node->ops.start_fields_offset(hdr);
+ hdr += ioff;
+ offset += ioff;
+
+ for (i = 0; i < flag_fields->num_idx; i++) {
+ off = panda_flag_fields_offset(i, flags, flag_fields);
+ if (off < 0)
+ continue;
+
+ /* Flag field is present, try to find in the parse node
+ * table based on index in proto flag-fields
+ */
+ parse_flag_field_node = lookup_flag_field_node(i,
+ parse_flag_fields_node->flag_fields_proto_table);
+ if (parse_flag_field_node) {
+ const struct panda_parse_flag_field_node_ops
+ *ops = &parse_flag_field_node->ops;
+ struct panda_ctrl_data flag_ctrl;
+ const __u8 *cp = hdr + off;
+
+ flag_ctrl.hdr_len = flag_fields->fields[i].size;
+ flag_ctrl.hdr_offset = offset + off;
+
+ if (pflags & PANDA_F_DEBUG)
+ printf("PANDA parsing flag-field %s\n",
+ parse_flag_field_node->name);
+
+ if (ops->extract_metadata)
+ ops->extract_metadata(cp, frame, flag_ctrl);
+
+ if (ops->handle_flag_field)
+ ops->handle_flag_field(cp, frame, flag_ctrl);
+ }
+ }
+
+ return PANDA_OKAY;
+}
+
+/* Parse a packet
+ *
+ * Arguments:
+ * - parser: Parser being invoked
+ * - node: start root node (may be different than parser->root_node)
+ * - hdr: pointer to start of packet
+ * - len: length of packet
+ * - metadata: metadata structure
+ * - start_node: first node (typically node_ether)
+ * - flags: allowed parameterized parsing
+ */
+int __panda_parse(const struct panda_parser *parser, const void *hdr,
+ size_t len, struct panda_metadata *metadata,
+ unsigned int flags, unsigned int max_encaps)
+{
+ const struct panda_parse_node *parse_node = parser->root_node;
+ const struct panda_parse_node *next_parse_node;
+ void *frame = metadata->frame_data;
+ struct panda_ctrl_data ctrl;
+ unsigned int frame_num = 0;
+ const void *base_hdr = hdr;
+ int type, ret;
+
+ /* Main parsing loop. The loop normal teminates when we encounter a
+ * leaf protocol node, an error condition, hitting limit on layers of
+ * encapsulation, protocol condition to stop (i.e. flags that
+ * indicate to stop at flow label or hitting fragment), or
+ * unknown protocol result in table lookup for next node.
+ */
+
+ do {
+ const struct panda_proto_node *proto_node =
+ parse_node->proto_node;
+ ssize_t hlen = proto_node->min_len;
+
+ /* Protocol node length checks */
+
+ if (flags & PANDA_F_DEBUG)
+ printf("PANDA parsing %s\n", proto_node->name);
+
+ if (len < hlen)
+ return PANDA_STOP_LENGTH;
+
+ if (proto_node->ops.len) {
+ hlen = proto_node->ops.len(hdr);
+ if (len < hlen)
+ return PANDA_STOP_LENGTH;
+
+ if (hlen < proto_node->min_len)
+ return hlen < 0 ? hlen : PANDA_STOP_LENGTH;
+ } else {
+ hlen = proto_node->min_len;
+ }
+
+ ctrl.hdr_len = hlen;
+ ctrl.hdr_offset = hdr - base_hdr;
+
+ /* Callback processing order
+ * 1) Extract Metadata
+ * 2) Process TLVs
+ * 2.a) Extract metadata from TLVs
+ * 2.b) Process TLVs
+ * 3) Process protocol
+ */
+
+ /* Extract metadata, per node processing */
+
+ if (parse_node->ops.extract_metadata)
+ parse_node->ops.extract_metadata(hdr, frame, ctrl);
+
+ switch (parse_node->node_type) {
+ case PANDA_NODE_TYPE_PLAIN:
+ default:
+ break;
+ case PANDA_NODE_TYPE_TLVS:
+ /* Process TLV nodes */
+ if (parse_node->proto_node->node_type ==
+ PANDA_NODE_TYPE_TLVS) {
+ /* Need error in case parse_node is TLVs type
+ * but proto_node is not TLVs type
+ */
+ ret = panda_parse_tlvs(parse_node, hdr, frame,
+ ctrl, flags);
+ if (ret != PANDA_OKAY)
+ return ret;
+ }
+ break;
+ case PANDA_NODE_TYPE_FLAG_FIELDS:
+ /* Process flag-fields */
+ if (parse_node->proto_node->node_type ==
+ PANDA_NODE_TYPE_FLAG_FIELDS) {
+ /* Need error in case parse_node is flag-fields
+ * type but proto_node is not flag-fields type
+ */
+ ret = panda_parse_flag_fields(parse_node, hdr,
+ frame, ctrl,
+ flags);
+ if (ret != PANDA_OKAY)
+ return ret;
+ }
+ break;
+ }
+
+ /* Process protocol */
+ if (parse_node->ops.handle_proto)
+ parse_node->ops.handle_proto(hdr, frame, ctrl);
+
+ /* Proceed to next protocol layer */
+
+ if (!parse_node->proto_table && !parse_node->wildcard_node) {
+ /* Leaf parse node */
+
+ return PANDA_STOP_OKAY;
+ }
+
+ if (proto_node->encap) {
+ /* New encapsulation leyer. Check against
+ * number of encap layers allowed and also
+ * if we need a new metadata frame.
+ */
+ if (++metadata->encaps > max_encaps)
+ return PANDA_STOP_ENCAP_DEPTH;
+
+ if (metadata->max_frame_num > frame_num) {
+ frame += metadata->frame_size;
+ frame_num++;
+ }
+ }
+
+ if (proto_node->ops.next_proto && parse_node->proto_table) {
+ /* Lookup next proto */
+
+ type = proto_node->ops.next_proto(hdr);
+ if (type < 0)
+ return type;
+
+ /* Get next node */
+ next_parse_node = lookup_node(type,
+ parse_node->proto_table);
+
+ if (next_parse_node)
+ goto found_next;
+ }
+
+ /* Try wildcard node. Either table lookup failed to find a node
+ * or there is only a wildcard
+ */
+ if (parse_node->wildcard_node) {
+ /* Perform default processing in a wildcard node */
+
+ next_parse_node = parse_node->wildcard_node;
+ } else {
+ /* Return default code. Parsing will stop
+ * with the inidicated code
+ */
+
+ return parse_node->unknown_ret;
+ }
+
+found_next:
+ /* Found next protocol node, set up to process */
+
+ if (!proto_node->overlay) {
+ /* Move over current header */
+ hdr += hlen;
+ len -= hlen;
+ }
+
+ parse_node = next_parse_node;
+
+ } while (1);
+}
+
+struct panda_parser *panda_parser_create(const char *name,
+ const struct panda_parse_node
+ *root_node)
+{
+ struct panda_parser *parser;
+
+ parser = calloc(1, sizeof(*parser));
+ if (!parser)
+ return NULL;
+
+ parser->name = name;
+ parser->root_node = root_node;
+
+ return parser;
+}
+
+static
+struct panda_parser *panda_parser_opt_create(const char *name,
+ const struct panda_parse_node *root_node,
+ panda_parser_opt_entry_point parser_entry_point)
+{
+ struct panda_parser *parser;
+
+ parser = calloc(1, sizeof(*parser));
+ if (!parser)
+ return NULL;
+
+ parser->name = name;
+ parser->root_node = root_node;
+ parser->parser_type = PANDA_OPTIMIZED;
+ parser->parser_entry_point = parser_entry_point;
+
+ return parser;
+}
+
+void panda_parser_destroy(struct panda_parser *parser)
+{
+ free(parser);
+}
+
+siphash_key_t __panda_hash_key;
+void panda_hash_secret_init(siphash_key_t *init_key)
+{
+ if (init_key) {
+ __panda_hash_key = *init_key;
+ } else {
+ __u8 *bytes = (__u8 *)&__panda_hash_key;
+ int i;
+
+ for (i = 0; i < sizeof(__panda_hash_key); i++)
+ bytes[i] = rand();
+ }
+}
+
+void panda_print_hash_input(const void *start, size_t len)
+{
+ const __u8 *data = start;
+ int i;
+
+ printf("Hash input (size %lu): ", len);
+ for (i = 0; i < len; i++)
+ printf("%02x ", data[i]);
+ printf("\n");
+}
+
+/* Create a dummy parser to ensure that the section is defined */
+static struct panda_parser_def PANDA_SECTION_ATTR(panda_parsers) dummy_parser;
+
+int panda_parser_init(void)
+{
+ const struct panda_parser_def *def_base =
+ panda_section_base_panda_parsers();
+ int i, j;
+
+ for (i = 0; i < panda_section_array_size_panda_parsers(); i++) {
+ const struct panda_parser_def *def = &def_base[i];
+
+ if (!def->name && !def->root_node)
+ continue;
+
+ switch (def->parser_type) {
+ case PANDA_GENERIC:
+ *def->parser = panda_parser_create(def->name,
+ def->root_node);
+ if (!def->parser) {
+ fprintf(stderr, "Create parser \"%s\" failed\n",
+ def->name);
+ goto fail;
+ }
+ break;
+ case PANDA_OPTIMIZED:
+ *def->parser = panda_parser_opt_create(def->name,
+ def->root_node,
+ def->parser_entry_point);
+ if (!def->parser) {
+ fprintf(stderr, "Create parser \"%s\" failed\n",
+ def->name);
+ goto fail;
+ }
+ break;
+ default:
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ for (j = 0; j < i; j++) {
+ const struct panda_parser_def *def = &def_base[i];
+
+ panda_parser_destroy(*def->parser);
+ *def->parser = NULL;
+ }
+ return -1;
+}
+
+module_init(panda_parser_init);
+module_exit(panda_parser_exit);
+
+MODULE_AUTHOR("Tom Herbert <tom@expertise.dev>");
+MODULE_DESCRIPTION("PANDA parser");
+MODULE_LICENSE("GPL v2");