/* * sfe.h * Shortcut forwarding engine. * * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __SFE_H #define __SFE_H /* * Maximum number of accelerated IPv4 or IPv6 connections */ #if defined(SFE_MEM_PROFILE_LOW) #define SFE_MAX_CONNECTION_NUM 512 #elif defined(SFE_MEM_PROFILE_MEDIUM) #define SFE_MAX_CONNECTION_NUM 2048 #else #define SFE_MAX_CONNECTION_NUM 4096 #endif #define SFE_L2_PARSE_FLAGS_PPPOE_INGRESS 0x01 /* Indicates presence of a valid PPPoE header */ /** * SAWF_metadata information placement in mark field. */ #define SFE_SAWF_VALID_TAG 0xAA #define SFE_SAWF_TAG_SHIFT 0x18 #define SFE_SAWF_SERVICE_CLASS_SHIFT 0x10 #define SFE_SAWF_SERVICE_CLASS_MASK 0xff #define SFE_SAWF_MSDUQ_MASK 0xffff /** * SAWF_metadata extraction. */ #define SFE_GET_SAWF_TAG(x) (x>>SFE_SAWF_TAG_SHIFT) #define SFE_GET_SAWF_SERVICE_CLASS(x) ((x>>SFE_SAWF_SERVICE_CLASS_SHIFT) & SFE_SAWF_SERVICE_CLASS_MASK) #define SFE_GET_SAWF_MSDUQ(x) (x & SFE_SAWF_MSDUQ_MASK) #define SFE_SAWF_TAG_IS_VALID(x) ((x == SFE_SAWF_VALID_TAG) ? true : false) /* * IPv6 address structure */ struct sfe_ipv6_addr { __be32 addr[4]; }; typedef union { __be32 ip; struct sfe_ipv6_addr ip6[1]; } sfe_ip_addr_t; typedef enum sfe_sync_reason { SFE_SYNC_REASON_STATS, /* Sync is to synchronize stats */ SFE_SYNC_REASON_FLUSH, /* Sync is to flush a entry */ SFE_SYNC_REASON_DESTROY /* Sync is to destroy a entry(requested by connection manager) */ } sfe_sync_reason_t; /* * VLAN header (aka VLAN tag) */ struct sfe_vlan_hdr { u16 tpid; /* Tag Protocol Identifier */ u16 tci; /* Tag Control Information */ }; /* * Structure used to store L2 information */ struct sfe_l2_info { u16 parse_flags; /* Flags indicating L2.5 headers presence */ u16 pppoe_session_id; /* PPPOE header offset */ u16 protocol; /* L3 Protocol */ struct sfe_vlan_hdr vlan_hdr[SFE_MAX_VLAN_DEPTH]; /* VLAN tag(s) of ingress packet */ u8 vlan_hdr_cnt; /* Number of VLAN tags in the ingress packet */ }; /* * Structure used to sync connection stats/state back within the system. * * NOTE: The addresses here are NON-NAT addresses, i.e. the true endpoint addressing. * 'src' is the creator of the connection. */ struct sfe_connection_sync { struct net_device *src_dev; struct net_device *dest_dev; int is_v6; /* Is it for ipv6? */ int protocol; /* IP protocol number (IPPROTO_...) */ sfe_ip_addr_t src_ip; /* Non-NAT source address, i.e. the creator of the connection */ sfe_ip_addr_t src_ip_xlate; /* NATed source address */ __be16 src_port; /* Non-NAT source port */ __be16 src_port_xlate; /* NATed source port */ sfe_ip_addr_t dest_ip; /* Non-NAT destination address, i.e. to whom the connection was created */ sfe_ip_addr_t dest_ip_xlate; /* NATed destination address */ __be16 dest_port; /* Non-NAT destination port */ __be16 dest_port_xlate; /* NATed destination port */ u32 src_td_max_window; u32 src_td_end; u32 src_td_max_end; u64 src_packet_count; u64 src_byte_count; u32 src_new_packet_count; u32 src_new_byte_count; u32 dest_td_max_window; u32 dest_td_end; u32 dest_td_max_end; u64 dest_packet_count; u64 dest_byte_count; u32 dest_new_packet_count; u32 dest_new_byte_count; u32 reason; /* reason for stats sync message, i.e. destroy, flush, period sync */ u64 delta_jiffies; /* Time to be added to the current timeout to keep the connection alive */ }; /* * Expose the hook for the receive processing. */ extern int (*athrs_fast_nat_recv)(struct sk_buff *skb); /* * Expose what should be a static flag in the TCP connection tracker. */ extern int nf_ct_tcp_no_window_check; /* * Check the fast transmit feasibility. */ bool sfe_fast_xmit_check(struct sk_buff *skb, netdev_features_t features); /* * This callback will be called in a timer * at 100 times per second to sync stats back to * Linux connection track. * * A RCU lock is taken to prevent this callback * from unregistering. */ typedef void (*sfe_sync_rule_callback_t)(struct sfe_connection_sync *); typedef void (*sfe_ipv4_many_sync_callback_t)(struct sfe_ipv4_msg *msg); typedef void (*sfe_ipv6_many_sync_callback_t)(struct sfe_ipv6_msg *msg); /* * IPv4 APIs used by connection manager */ int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb, struct sfe_l2_info *l2_info, bool tun_outer); int sfe_ipv4_create_rule(struct sfe_ipv4_rule_create_msg *msg); void sfe_ipv4_destroy_rule(struct sfe_ipv4_rule_destroy_msg *msg); void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev); void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t callback); void sfe_ipv4_update_rule(struct sfe_ipv4_rule_create_msg *msg); bool sfe_dev_has_hw_csum(struct net_device *dev); bool sfe_ipv4_sync_invoke(uint16_t index); void sfe_ipv4_register_many_sync_callback(sfe_ipv4_many_sync_callback_t cb); void sfe_ipv4_stats_convert(struct sfe_ipv4_conn_sync *sync_msg, struct sfe_connection_sync *sis); #ifdef SFE_SUPPORT_IPV6 /* * IPv6 APIs used by connection manager */ int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb, struct sfe_l2_info *l2_info, bool tun_outer); int sfe_ipv6_create_rule(struct sfe_ipv6_rule_create_msg *msg); void sfe_ipv6_destroy_rule(struct sfe_ipv6_rule_destroy_msg *msg); void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev); void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback); void sfe_ipv6_update_rule(struct sfe_ipv6_rule_create_msg *msg); bool sfe_ipv6_sync_invoke(uint16_t index); void sfe_ipv6_register_many_sync_callback(sfe_ipv6_many_sync_callback_t cb); void sfe_ipv6_stats_convert(struct sfe_ipv6_conn_sync *sync_msg, struct sfe_connection_sync *sis); #else static inline int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb, struct sfe_l2_info *l2_info, bool tun_outer) { return 0; } static inline int sfe_ipv6_create_rule(struct sfe_ipv6_rule_create_msg *msg) { return 0; } static inline void sfe_ipv6_destroy_rule(struct sfe_ipv6_rule_destroy_msg *msg) { return; } static inline void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev) { return; } static inline void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback) { return; } static inline void sfe_ipv6_update_rule(struct sfe_ipv6_rule_create_msg *msg) { return; } static inline bool sfe_ipv6_sync_invoke(uint16_t index) { return false; } static inline void sfe_ipv6_register_many_sync_callback(sfe_ipv6_many_sync_callback_t cb) { return; } static inline void sfe_ipv6_stats_convert(struct sfe_ipv6_conn_sync *sync_msg, struct sfe_connection_sync *sis) { return; } #endif /* * sfe_ipv6_addr_equal() * compare ipv6 address * * return: 1, equal; 0, no equal */ static inline int sfe_ipv6_addr_equal(struct sfe_ipv6_addr *a, struct sfe_ipv6_addr *b) { return a->addr[0] == b->addr[0] && a->addr[1] == b->addr[1] && a->addr[2] == b->addr[2] && a->addr[3] == b->addr[3]; } /* * sfe_ipv4_addr_equal() * compare ipv4 address * * return: 1, equal; 0, no equal */ #define sfe_ipv4_addr_equal(a, b) ((u32)(a) == (u32)(b)) /* * sfe_addr_equal() * compare ipv4 or ipv6 address * * return: 1, equal; 0, no equal */ static inline int sfe_addr_equal(sfe_ip_addr_t *a, sfe_ip_addr_t *b, int is_v4) { return is_v4 ? sfe_ipv4_addr_equal(a->ip, b->ip) : sfe_ipv6_addr_equal(a->ip6, b->ip6); } /* * sfe_l2_parse_flag_set() * Set L2 parse flag */ static inline void sfe_l2_parse_flag_set(struct sfe_l2_info *l2_info, u16 flag) { l2_info->parse_flags |= flag; } /* * sfe_l2_parse_flag_get() * Get L2 parse flag */ static inline u16 sfe_l2_parse_flag_get(struct sfe_l2_info *l2_info) { return l2_info->parse_flags; } /* * sfe_l2_parse_flag_check() * Check L2 parse flag */ static inline bool sfe_l2_parse_flag_check(struct sfe_l2_info *l2_info, u16 flag) { return !!(l2_info->parse_flags & flag); } /* * sfe_l2_pppoe_session_id_get() * Get PPPPoE session ID from l2_info */ static inline u16 sfe_l2_pppoe_session_id_get(struct sfe_l2_info *l2_info) { return l2_info->pppoe_session_id; } /* * sfe_l2_pppoe_session_id_set() * Set PPPoE session ID to l2_info */ static inline void sfe_l2_pppoe_session_id_set(struct sfe_l2_info *l2_info, u16 session_id) { l2_info->pppoe_session_id = session_id; } /* * sfe_l2_protocol_get() * Get L2 protocol */ static inline u16 sfe_l2_protocol_get(struct sfe_l2_info *l2_info) { return l2_info->protocol; } /* * sfe_l2_protocol_set() * Set L2 protocol */ static inline void sfe_l2_protocol_set(struct sfe_l2_info *l2_info, u16 proto) { l2_info->protocol = proto; } int sfe_init_if(void); void sfe_exit_if(void); #endif /* __SFE_H */