diff --git a/cmd/core/display_utils.go b/cmd/core/display_utils.go index fa935cea..eb10f26e 100644 --- a/cmd/core/display_utils.go +++ b/cmd/core/display_utils.go @@ -267,6 +267,10 @@ func displayFar(sb *strings.Builder, far *ie.IE) { if err == nil { writeLineTabbed(sb, fmt.Sprintf("Header Enrichment: %s : %s ", headerEnrichment.HeaderFieldName, headerEnrichment.HeaderFieldValue), 3) } + forwardingPolicyIdentifier, err := forwardingParameter.ForwardingPolicyIdentifier() + if err == nil { + writeLineTabbed(sb, fmt.Sprintf("Fordward Policy Identifier: %s ", forwardingPolicyIdentifier), 3) + } } } if updateForwardingParameters, err := far.UpdateForwardingParameters(); err == nil { @@ -289,6 +293,10 @@ func displayFar(sb *strings.Builder, far *ie.IE) { if err == nil { writeLineTabbed(sb, fmt.Sprintf("Header Enrichment: %s : %s ", headerEnrichment.HeaderFieldName, headerEnrichment.HeaderFieldValue), 3) } + forwardingPolicyIdentifier, err := updateForwardingParameter.ForwardingPolicyIdentifier() + if err == nil { + writeLineTabbed(sb, fmt.Sprintf("Fordward Policy Identifier: %s ", forwardingPolicyIdentifier), 3) + } } } diff --git a/cmd/core/pfcp_session_handlers.go b/cmd/core/pfcp_session_handlers.go index 11fdd067..415793b3 100644 --- a/cmd/core/pfcp_session_handlers.go +++ b/cmd/core/pfcp_session_handlers.go @@ -1,9 +1,11 @@ package core import ( + "encoding/base64" "encoding/binary" "fmt" "net" + "strconv" "github.com/edgecomllc/eupf/cmd/ebpf" @@ -480,6 +482,21 @@ func composeFarInfo(far *ie.IE, localIp net.IP, farInfo ebpf.FarInfo) (ebpf.FarI return ebpf.FarInfo{}, fmt.Errorf("IPv6 not supported yet") } } + forwardingPolicyIndex := findIEindex(forward, 41) // IE Type Forwarding Policy + if forwardingPolicyIndex == -1 { + log.Info().Msg("WARN: No ForwardingPolicy") + } else { + forwardingPolicyIdentifier, _ := forward[forwardingPolicyIndex].ForwardingPolicyIdentifier() + + forwardingPolicyIdentifierDecode, err := base64.StdEncoding.DecodeString(forwardingPolicyIdentifier) + if err == nil { + uint32Value, err := strconv.ParseUint(string(forwardingPolicyIdentifierDecode), 10, 32) + if err == nil { + farInfo.ForwardingPolicyIdentifier = uint32(uint32Value) + } + } + // TODO support pre-defined policy if forwardingPolicyIdentifier is not base64 treat it as referring to a pre-defined policy + } } transportLevelMarking, err := GetTransportLevelMarking(far) if err == nil { diff --git a/cmd/ebpf/pdr.go b/cmd/ebpf/pdr.go index a1556dd6..9eb0fc64 100644 --- a/cmd/ebpf/pdr.go +++ b/cmd/ebpf/pdr.go @@ -149,12 +149,13 @@ func (bpfObjects *BpfObjects) DeleteDownlinkPdrIp6(ipv6 net.IP) error { } type FarInfo struct { - Action uint8 - OuterHeaderCreation uint8 - Teid uint32 - RemoteIP uint32 - LocalIP uint32 - TransportLevelMarking uint16 + Action uint8 + OuterHeaderCreation uint8 + Teid uint32 + RemoteIP uint32 + LocalIP uint32 + TransportLevelMarking uint16 + ForwardingPolicyIdentifier uint32 } func (f FarInfo) MarshalJSON() ([]byte, error) { @@ -163,12 +164,13 @@ func (f FarInfo) MarshalJSON() ([]byte, error) { binary.LittleEndian.PutUint32(remoteIP, f.RemoteIP) binary.LittleEndian.PutUint32(localIP, f.LocalIP) data := map[string]interface{}{ - "action": f.Action, - "outer_header_creation": f.OuterHeaderCreation, - "teid": f.Teid, - "remote_ip": remoteIP.String(), - "local_ip": localIP.String(), - "transport_level_marking": f.TransportLevelMarking, + "action": f.Action, + "outer_header_creation": f.OuterHeaderCreation, + "teid": f.Teid, + "remote_ip": remoteIP.String(), + "local_ip": localIP.String(), + "transport_level_marking": f.TransportLevelMarking, + "forwarding_policy_identifier": f.ForwardingPolicyIdentifier, } return json.Marshal(data) } diff --git a/cmd/ebpf/xdp/n3n6_entrypoint.c b/cmd/ebpf/xdp/n3n6_entrypoint.c index aaf7a81b..746ede2a 100644 --- a/cmd/ebpf/xdp/n3n6_entrypoint.c +++ b/cmd/ebpf/xdp/n3n6_entrypoint.c @@ -38,6 +38,7 @@ #include "xdp/utils/parsers.h" #include "xdp/utils/csum.h" #include "xdp/utils/gtp_utils.h" +#include "xdp/utils/nsh_utils.h" #include "xdp/utils/routing.h" #include "xdp/utils/icmp.h" @@ -313,6 +314,23 @@ static __always_inline enum xdp_action handle_gtp_packet(struct packet_context * } } + // Check for forwarding policy identifier + if (far->forwarding_policy_identifier) { + /* + * TODO: support predefined traffic steering policy. Should check + * first if the forwarding policy identifier refers to a pre-defined + * policy, if not we treat this as a SFC ID as below. + */ + // NOTE: The FIB tables need to have been populate prior. + // Traffic with forwarding_policy_identifier should'nt be the first traffic to be received + if (ctx->ip4) { + if (-1 == add_nsh_over_ip4_headers(ctx, far->forwarding_policy_identifier)) { + upf_printk("upf: failed to NSH encapsulate packet"); + return XDP_ABORTED; + } + } + } + /* * Decrement IP TTL and reply TTL exeeded message (debug purspose only) */ diff --git a/cmd/ebpf/xdp/pdr.h b/cmd/ebpf/xdp/pdr.h index fc11ac64..f83a0946 100644 --- a/cmd/ebpf/xdp/pdr.h +++ b/cmd/ebpf/xdp/pdr.h @@ -114,6 +114,7 @@ struct far_info { __u32 localip; /* first octet DSCP value in the Type-of-Service, second octet shall contain the ToS/Traffic Class mask field, which shall be set to "0xFC". */ __u16 transport_level_marking; + __u32 forwarding_policy_identifier; }; /* FAR ID -> FAR */ diff --git a/cmd/ebpf/xdp/utils/gtp_utils.h b/cmd/ebpf/xdp/utils/gtp_utils.h index e78d5baa..3e198f0e 100644 --- a/cmd/ebpf/xdp/utils/gtp_utils.h +++ b/cmd/ebpf/xdp/utils/gtp_utils.h @@ -242,7 +242,7 @@ static __always_inline __u32 add_gtp_over_ip4_headers(struct packet_context *ctx // udp->check = cs; /* Update packet pointers */ - context_set_ip4(ctx, (char *)(long)ctx->xdp_ctx->data, (const char *)(long)ctx->xdp_ctx->data_end, eth, ip, udp, gtp); + context_set_ip4(ctx, (char *)(long)ctx->xdp_ctx->data, (const char *)(long)ctx->xdp_ctx->data_end, eth, ip, udp, gtp, 0); return 0; } diff --git a/cmd/ebpf/xdp/utils/nsh.h b/cmd/ebpf/xdp/utils/nsh.h new file mode 100644 index 00000000..d91fb55b --- /dev/null +++ b/cmd/ebpf/xdp/utils/nsh.h @@ -0,0 +1,303 @@ +#ifndef __NET_NSH_H +#define __NET_NSH_H 1 + +// #include + +/* + * Network Service Header: + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Ver|O|U| TTL | Length |U|U|U|U|MD Type| Next Protocol | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Service Path Identifier (SPI) | Service Index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * ~ Mandatory/Optional Context Headers ~ + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Version: The version field is used to ensure backward compatibility + * going forward with future NSH specification updates. It MUST be set + * to 0x0 by the sender, in this first revision of NSH. Given the + * widespread implementation of existing hardware that uses the first + * nibble after an MPLS label stack for ECMP decision processing, this + * document reserves version 01b and this value MUST NOT be used in + * future versions of the protocol. Please see [RFC7325] for further + * discussion of MPLS-related forwarding requirements. + * + * O bit: Setting this bit indicates an Operations, Administration, and + * Maintenance (OAM) packet. The actual format and processing of SFC + * OAM packets is outside the scope of this specification (see for + * example [I-D.ietf-sfc-oam-framework] for one approach). + * + * The O bit MUST be set for OAM packets and MUST NOT be set for non-OAM + * packets. The O bit MUST NOT be modified along the SFP. + * + * SF/SFF/SFC Proxy/Classifier implementations that do not support SFC + * OAM procedures SHOULD discard packets with O bit set, but MAY support + * a configurable parameter to enable forwarding received SFC OAM + * packets unmodified to the next element in the chain. Forwarding OAM + * packets unmodified by SFC elements that do not support SFC OAM + * procedures may be acceptable for a subset of OAM functions, but can + * result in unexpected outcomes for others, thus it is recommended to + * analyze the impact of forwarding an OAM packet for all OAM functions + * prior to enabling this behavior. The configurable parameter MUST be + * disabled by default. + * + * TTL: Indicates the maximum SFF hops for an SFP. This field is used + * for service plane loop detection. The initial TTL value SHOULD be + * configurable via the control plane; the configured initial value can + * be specific to one or more SFPs. If no initial value is explicitly + * provided, the default initial TTL value of 63 MUST be used. Each SFF + * involved in forwarding an NSH packet MUST decrement the TTL value by + * 1 prior to NSH forwarding lookup. Decrementing by 1 from an incoming + * value of 0 shall result in a TTL value of 63. The packet MUST NOT be + * forwarded if TTL is, after decrement, 0. + * + * All other flag fields, marked U, are unassigned and available for + * future use, see Section 11.2.1. Unassigned bits MUST be set to zero + * upon origination, and MUST be ignored and preserved unmodified by + * other NSH supporting elements. Elements which do not understand the + * meaning of any of these bits MUST NOT modify their actions based on + * those unknown bits. + * + * Length: The total length, in 4-byte words, of NSH including the Base + * Header, the Service Path Header, the Fixed Length Context Header or + * Variable Length Context Header(s). The length MUST be 0x6 for MD + * Type equal to 0x1, and MUST be 0x2 or greater for MD Type equal to + * 0x2. The length of the NSH header MUST be an integer multiple of 4 + * bytes, thus variable length metadata is always padded out to a + * multiple of 4 bytes. + * + * MD Type: Indicates the format of NSH beyond the mandatory Base Header + * and the Service Path Header. MD Type defines the format of the + * metadata being carried. + * + * 0x0 - This is a reserved value. Implementations SHOULD silently + * discard packets with MD Type 0x0. + * + * 0x1 - This indicates that the format of the header includes a fixed + * length Context Header (see Figure 4 below). + * + * 0x2 - This does not mandate any headers beyond the Base Header and + * Service Path Header, but may contain optional variable length Context + * Header(s). The semantics of the variable length Context Header(s) + * are not defined in this document. The format of the optional + * variable length Context Headers is provided in Section 2.5.1. + * + * 0xF - This value is reserved for experimentation and testing, as per + * [RFC3692]. Implementations not explicitly configured to be part of + * an experiment SHOULD silently discard packets with MD Type 0xF. + * + * Next Protocol: indicates the protocol type of the encapsulated data. + * NSH does not alter the inner payload, and the semantics on the inner + * protocol remain unchanged due to NSH service function chaining. + * Please see the IANA Considerations section below, Section 11.2.5. + * + * This document defines the following Next Protocol values: + * + * 0x1: IPv4 + * 0x2: IPv6 + * 0x3: Ethernet + * 0x4: NSH + * 0x5: MPLS + * 0xFE: Experiment 1 + * 0xFF: Experiment 2 + * + * Packets with Next Protocol values not supported SHOULD be silently + * dropped by default, although an implementation MAY provide a + * configuration parameter to forward them. Additionally, an + * implementation not explicitly configured for a specific experiment + * [RFC3692] SHOULD silently drop packets with Next Protocol values 0xFE + * and 0xFF. + * + * Service Path Identifier (SPI): Identifies a service path. + * Participating nodes MUST use this identifier for Service Function + * Path selection. The initial classifier MUST set the appropriate SPI + * for a given classification result. + * + * Service Index (SI): Provides location within the SFP. The initial + * classifier for a given SFP SHOULD set the SI to 255, however the + * control plane MAY configure the initial value of SI as appropriate + * (i.e., taking into account the length of the service function path). + * The Service Index MUST be decremented by a value of 1 by Service + * Functions or by SFC Proxy nodes after performing required services + * and the new decremented SI value MUST be used in the egress packet's + * NSH. The initial Classifier MUST send the packet to the first SFF in + * the identified SFP for forwarding along an SFP. If re-classification + * occurs, and that re-classification results in a new SPI, the + * (re)classifier is, in effect, the initial classifier for the + * resultant SPI. + * + * The SI is used in conjunction the with Service Path Identifier for + * Service Function Path Selection and for determining the next SFF/SF + * in the path. The SI is also valuable when troubleshooting or + * reporting service paths. Additionally, while the TTL field is the + * main mechanism for service plane loop detection, the SI can also be + * used for detecting service plane loops. + * + * When the Base Header specifies MD Type = 0x1, a Fixed Length Context + * Header (16-bytes) MUST be present immediately following the Service + * Path Header. The value of a Fixed Length Context + * Header that carries no metadata MUST be set to zero. + * + * When the base header specifies MD Type = 0x2, zero or more Variable + * Length Context Headers MAY be added, immediately following the + * Service Path Header (see Figure 5). Therefore, Length = 0x2, + * indicates that only the Base Header followed by the Service Path + * Header are present. The optional Variable Length Context Headers + * MUST be of an integer number of 4-bytes. The base header Length + * field MUST be used to determine the offset to locate the original + * packet or frame for SFC nodes that require access to that + * information. + * + * The format of the optional variable length Context Headers + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Metadata Class | Type |U| Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Variable Metadata | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Metadata Class (MD Class): Defines the scope of the 'Type' field to + * provide a hierarchical namespace. The IANA Considerations + * Section 11.2.4 defines how the MD Class values can be allocated to + * standards bodies, vendors, and others. + * + * Type: Indicates the explicit type of metadata being carried. The + * definition of the Type is the responsibility of the MD Class owner. + * + * Unassigned bit: One unassigned bit is available for future use. This + * bit MUST NOT be set, and MUST be ignored on receipt. + * + * Length: Indicates the length of the variable metadata, in bytes. In + * case the metadata length is not an integer number of 4-byte words, + * the sender MUST add pad bytes immediately following the last metadata + * byte to extend the metadata to an integer number of 4-byte words. + * The receiver MUST round up the length field to the nearest 4-byte + * word boundary, to locate and process the next field in the packet. + * The receiver MUST access only those bytes in the metadata indicated + * by the length field (i.e., actual number of bytes) and MUST ignore + * the remaining bytes up to the nearest 4-byte word boundary. The + * Length may be 0 or greater. + * + * A value of 0 denotes a Context Header without a Variable Metadata + * field. + * + * [0] https://datatracker.ietf.org/doc/draft-ietf-sfc-nsh/ + */ + +/** + * struct nsh_md1_ctx - Keeps track of NSH context data + * @context: NSH Contexts. + */ +struct nsh_md1_ctx { + __be32 context[4]; +}; + +struct nsh_md2_tlv { + __be16 md_class; + __u8 type; + __u8 length; + __u8 md_value[]; +}; + +struct nshhdr { + __be16 ver_flags_ttl_len; + __u8 mdtype; + __u8 np; + __be32 path_hdr; + union { + struct nsh_md1_ctx md1; + struct nsh_md2_tlv md2; + }; +}; + +/* Masking NSH header fields. */ +#define NSH_VER_MASK 0xc000 +#define NSH_VER_SHIFT 14 +#define NSH_FLAGS_MASK 0x3000 +#define NSH_FLAGS_SHIFT 12 +#define NSH_TTL_MASK 0x0fc0 +#define NSH_TTL_SHIFT 6 +#define NSH_LEN_MASK 0x003f +#define NSH_LEN_SHIFT 0 + +#define NSH_MDTYPE_MASK 0x0f +#define NSH_MDTYPE_SHIFT 0 + +#define NSH_SPI_MASK 0xffffff00 +#define NSH_SPI_SHIFT 8 +#define NSH_SI_MASK 0x000000ff +#define NSH_SI_SHIFT 0 + +/* MD Type Registry. */ +#define NSH_M_TYPE1 0x01 +#define NSH_M_TYPE2 0x02 +#define NSH_M_EXP1 0xFE +#define NSH_M_EXP2 0xFF + +/* NSH Base Header Length */ +#define NSH_BASE_HDR_LEN 8 + +/* NSH MD Type 1 header Length. */ +#define NSH_M_TYPE1_LEN 24 + +/* NSH header maximum Length. */ +#define NSH_HDR_MAX_LEN 256 + +/* NSH context headers maximum Length. */ +#define NSH_CTX_HDRS_MAX_LEN 248 + +static inline __u16 nsh_hdr_len(const struct nshhdr *nsh) +{ + return ((bpf_ntohs(nsh->ver_flags_ttl_len) & NSH_LEN_MASK) + >> NSH_LEN_SHIFT) << 2; +} + +static inline __u8 nsh_get_ver(const struct nshhdr *nsh) +{ + return (bpf_ntohs(nsh->ver_flags_ttl_len) & NSH_VER_MASK) + >> NSH_VER_SHIFT; +} + +static inline __u8 nsh_get_flags(const struct nshhdr *nsh) +{ + return (bpf_ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK) + >> NSH_FLAGS_SHIFT; +} + +static inline __u8 nsh_get_ttl(const struct nshhdr *nsh) +{ + return (bpf_ntohs(nsh->ver_flags_ttl_len) & NSH_TTL_MASK) + >> NSH_TTL_SHIFT; +} + +static inline void __nsh_set_xflag(struct nshhdr *nsh, __u16 xflag, __u16 xmask) +{ + nsh->ver_flags_ttl_len + = (nsh->ver_flags_ttl_len & ~bpf_htons(xmask)) | bpf_htons(xflag); +} + +static inline void nsh_set_flags_and_ttl(struct nshhdr *nsh, __u8 flags, __u8 ttl) +{ + __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) | + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK), + NSH_FLAGS_MASK | NSH_TTL_MASK); +} + +static inline void nsh_set_flags_ttl_len(struct nshhdr *nsh, __u8 flags, + __u8 ttl, __u8 len) +{ + len = len >> 2; + __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) | + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK) | + ((len << NSH_LEN_SHIFT) & NSH_LEN_MASK), + NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK); +} + + +#endif /* __NET_NSH_H */ \ No newline at end of file diff --git a/cmd/ebpf/xdp/utils/nsh_utils.h b/cmd/ebpf/xdp/utils/nsh_utils.h new file mode 100644 index 00000000..0a778689 --- /dev/null +++ b/cmd/ebpf/xdp/utils/nsh_utils.h @@ -0,0 +1,59 @@ +#include +#include + +#include +#include + +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_NSH 0x894F /* Network Service Header */ + +#include "xdp/utils/nsh.h" +#include "xdp/utils/packet_context.h" +#include "xdp/utils/trace.h" + +// TODO: support metadata +static __always_inline __u32 add_nsh_over_ip4_headers(struct packet_context *ctx, __u32 path_hdr) { + + static const size_t nsh_encap_size = NSH_BASE_HDR_LEN; // Without metadata + + + int result = bpf_xdp_adjust_head(ctx->xdp_ctx, (__s32)-nsh_encap_size); + if (result) + return -1; + + char *data = (char *)(long)ctx->xdp_ctx->data; + char *data_end = (char *)(long)ctx->xdp_ctx->data_end; + + struct ethhdr *orig_eth = (struct ethhdr *)(data + nsh_encap_size); + if ((const char *)(orig_eth + 1) > data_end) + return -1; + + struct ethhdr *eth = (struct ethhdr *)data; + __builtin_memcpy(eth, orig_eth, sizeof(*eth)); + eth->h_proto = bpf_htons(ETH_P_NSH); + + // /* Add the NSH header */ + struct nshhdr *nsh = (struct nshhdr *)(eth + 1); + if ((const char *)(nsh + 1) > data_end) + return -1; + + nsh->ver_flags_ttl_len = 0; + nsh->mdtype = NSH_M_TYPE2; + nsh->np = 0x01; + nsh->path_hdr = bpf_htonl(path_hdr); + nsh_set_flags_ttl_len(nsh, 0x0, 0x3F, nsh_encap_size); + + upf_printk("upf: added nsh encap"); + + struct iphdr *ip = (struct iphdr *)((char *)nsh + nsh_encap_size); + if ((const char *)(ip + 1) > data_end) + return -1; + + context_set_ip4(ctx, (char *)(long)ctx->xdp_ctx->data, (const char *)(long)ctx->xdp_ctx->data_end, eth, ip, 0, 0, nsh); + return 0; +} + +static __always_inline long remove_nsh_header(struct packet_context *ctx) { + return 0; +} + diff --git a/cmd/ebpf/xdp/utils/packet_context.h b/cmd/ebpf/xdp/utils/packet_context.h index d9fe0b23..b622d77e 100644 --- a/cmd/ebpf/xdp/utils/packet_context.h +++ b/cmd/ebpf/xdp/utils/packet_context.h @@ -23,6 +23,7 @@ #include #include #include "xdp/utils/gtpu.h" +#include "xdp/utils/nsh.h" /* Header cursor to keep track of current parsing position */ struct packet_context { @@ -37,4 +38,5 @@ struct packet_context { struct udphdr *udp; struct tcphdr *tcp; struct gtpuhdr *gtp; + struct nshhdr *nsh; }; diff --git a/cmd/ebpf/xdp/utils/parsers.h b/cmd/ebpf/xdp/utils/parsers.h index 937a1bc4..d542e85c 100644 --- a/cmd/ebpf/xdp/utils/parsers.h +++ b/cmd/ebpf/xdp/utils/parsers.h @@ -132,7 +132,7 @@ static __always_inline void swap_ip(struct iphdr *iph) { // ip->check = ipv4_csum(ip, sizeof(*ip)); } -static __always_inline void context_set_ip4(struct packet_context *ctx, char *data, const char *data_end, struct ethhdr *eth, struct iphdr *ip4, struct udphdr *udp, struct gtpuhdr *gtp) { +static __always_inline void context_set_ip4(struct packet_context *ctx, char *data, const char *data_end, struct ethhdr *eth, struct iphdr *ip4, struct udphdr *udp, struct gtpuhdr *gtp, struct nshhdr *nsh) { ctx->data = data; ctx->data_end = data_end; ctx->eth = eth; @@ -140,6 +140,7 @@ static __always_inline void context_set_ip4(struct packet_context *ctx, char *da ctx->ip6 = 0; ctx->udp = udp; ctx->gtp = gtp; + ctx->nsh = nsh; } static __always_inline void context_reset(struct packet_context *ctx, char *data, const char *data_end) { @@ -150,6 +151,7 @@ static __always_inline void context_reset(struct packet_context *ctx, char *data ctx->ip6 = 0; ctx->udp = 0; ctx->gtp = 0; + ctx->nsh = 0; }