1#ifndef  NAT_CHECK_H
2#define  NAT_CHECK_H
3/*
4 Hanoh Haim
5 Cisco Systems, Inc.
6*/
7
8/*
9Copyright (c) 2015-2015 Cisco Systems, Inc.
10
11Licensed under the Apache License, Version 2.0 (the "License");
12you may not use this file except in compliance with the License.
13You may obtain a copy of the License at
14
15    http://www.apache.org/licenses/LICENSE-2.0
16
17Unless required by applicable law or agreed to in writing, software
18distributed under the License is distributed on an "AS IS" BASIS,
19WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20See the License for the specific language governing permissions and
21limitations under the License.
22*/
23
24#include <map>
25#include "msg_manager.h"
26#include <common/Network/Packet/TcpHeader.h>
27#include <common/Network/Packet/UdpHeader.h>
28#include <common/Network/Packet/IPHeader.h>
29#include <common/Network/Packet/IPv6Header.h>
30#include <common/Network/Packet/EthernetHeader.h>
31#include "os_time.h"
32#include "nat_check_flow_table.h"
33
34// 2msec timeout
35#define MAX_TIME_MSG_IN_QUEUE_SEC  ( 0.002 )
36#define NAT_FLOW_ID_MASK_TCP_ACK 0x00ffffff
37#define NAT_FLOW_ID_MASK_IP_ID   0x000001ff
38
39class  CNatOption {
40public:
41    enum {
42        noIPV4_OPTION   = 0x10, /* dummy IPV4 option */
43        noOPTION_LEN    = 0x8,
44        noIPV4_MAGIC    = 0xEE,
45        noIPV4_MAGIC_RX    = 0xED,
46
47        noIPV6_OPTION_LEN    = (noOPTION_LEN/8)-1,
48        noIPV6_OPTION = 0x3C, /*IPv6-Opts	Destination Options for IPv6	RFC 2460*/
49    };
50
51    void set_option_type(uint8_t id) {
52        u.m_data[0 ] =id;
53    }
54
55    uint8_t get_option_type() {
56        return (u.m_data[0]);
57    }
58
59    void set_option_len(uint8_t len) {
60        u.m_data[1] = len;
61    }
62    uint8_t get_option_len(){
63        return ( u.m_data[1]);
64    }
65
66    void set_thread_id(uint8_t thread_id) {
67        u.m_data[3] = thread_id;
68    }
69
70    uint8_t get_thread_id() {
71        return (u.m_data[3]);
72    }
73
74    void set_magic(uint8_t magic){
75        u.m_data[2] = magic;
76    }
77
78    uint8_t get_magic(){
79        return (u.m_data[2]);
80    }
81
82    // Used when doing NAT using IP option
83    void set_fid(uint32_t fid) {
84        u.m_data_uint32[1] = fid & NAT_FLOW_ID_MASK_TCP_ACK;
85    }
86
87    uint32_t get_fid() {
88        return (u.m_data_uint32[1]);
89    }
90
91    bool is_valid_ipv4_magic_op0(void){
92        return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0xFFFFFF00 ) ==
93                 (CNatOption::noIPV4_OPTION <<24) +  (CNatOption::noOPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
94    }
95
96    bool is_valid_ipv4_magic(void) {
97        return (is_valid_ipv4_magic_op0());
98    }
99
100    bool is_valid_ipv6_magic(void) {
101        return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0x00FFFF00 ) ==
102                 (CNatOption::noIPV6_OPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
103
104    }
105
106    void set_init_ipv4_header() {
107        set_option_type(CNatOption::noIPV4_OPTION);
108        set_option_len(CNatOption::noOPTION_LEN);
109        set_magic(CNatOption::noIPV4_MAGIC);
110    }
111
112    void set_init_ipv6_header(void){
113        set_option_len(noIPV6_OPTION_LEN);
114        set_magic(CNatOption::noIPV4_MAGIC);
115    }
116
117    void dump(FILE *fd);
118
119private:
120    union u_ {
121        uint8_t  m_data[8];
122        uint32_t m_data_uint32[2];
123    } u;
124};
125
126struct CNatFlowInfo {
127    uint32_t m_external_ip;
128    uint32_t m_tcp_seq;
129    uint32_t m_fid;
130    uint16_t m_external_port;
131    uint16_t m_pad;
132};
133
134#if __x86_64__
135/* size of 64 bytes */
136    #define MAX_NAT_FLOW_INFO (7)
137    #define MAX_PKT_MSG_INFO  (26)
138#else
139    #define MAX_NAT_FLOW_INFO (8)
140    #define MAX_PKT_MSG_INFO  (30)
141#endif
142
143/*
144     !!!   WARNING  - CGenNodeNatInfo !!
145
146 this struct should be in the same size of CGenNode beacuse allocator is global .
147
148*/
149struct CGenNodeNatInfo : public CGenNodeMsgBase {
150    uint8_t       m_pad;
151    uint16_t      m_cnt;
152    //uint32_t      m_pad2;
153 #if __x86_64__
154    uint32_t      m_pad3;
155 #endif
156    CNatFlowInfo  m_data[MAX_NAT_FLOW_INFO];
157    uint64_t      m_pad4[8];
158
159public:
160      CNatFlowInfo * get_next_msg() {
161          CNatFlowInfo * lp=&m_data[m_cnt];
162          m_cnt++;
163          return (lp);
164      }
165
166      void init();
167
168      bool is_full(){
169          return (m_cnt==MAX_NAT_FLOW_INFO?true:false);
170      }
171      void dump(FILE *fd);
172};
173
174struct CGenNodeLatencyPktInfo : public CGenNodeMsgBase {
175    uint8_t       m_dir;
176    uint16_t      m_latency_offset;
177
178    uint8_t       m_update_ts;
179    uint8_t       m_pad3[3];
180
181    struct rte_mbuf *m_pkt;
182
183    uint32_t      m_pad4[MAX_PKT_MSG_INFO];
184    uint64_t      m_pad5[8];
185};
186
187
188/* per thread ring info for NAT messages
189   try to put as many messages  */
190class CNatPerThreadInfo {
191public:
192    CNatPerThreadInfo() {
193        m_last_time=0;
194        m_cur_nat_msg=0;
195        m_ring=0;
196    }
197public:
198    dsec_t            m_last_time;
199    CGenNodeNatInfo * m_cur_nat_msg;
200    CNodeRing       * m_ring;
201};
202
203
204class CNatStats {
205public:
206    uint64_t  m_total_rx;
207    uint64_t  m_total_msg;
208    /* errors */
209    uint64_t  m_err_no_valid_thread_id;
210    uint64_t  m_err_no_valid_proto;
211    uint64_t  m_err_queue_full;
212public:
213    void reset();
214    uint64_t get_errs(){
215        return  (m_err_no_valid_thread_id+m_err_no_valid_proto+m_err_queue_full);
216    }
217    void Dump(FILE *fd);
218};
219
220class CNatRxManager {
221
222public:
223    bool Create();
224    void Delete();
225    void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4, bool is_first);
226    void handle_aging();
227    void Dump(FILE *fd);
228    void DumpShort(FILE *fd);
229    static inline uint32_t calc_tcp_ack_val(uint32_t fid, uint8_t thread_id) {
230        return ((fid &  NAT_FLOW_ID_MASK_TCP_ACK) << 8) | thread_id;
231    }
232    static inline uint16_t calc_ip_id_val(uint32_t fid, uint8_t thread_id) {
233        // MSB bit == 1 signals this is latency packet
234        return ((fid &  NAT_FLOW_ID_MASK_IP_ID) << 6) | (thread_id & 0x3f) | 0x8000;
235    }
236    void get_info_from_tcp_ack(uint32_t tcp_ack, uint32_t &fid, uint8_t &thread_id);
237    void get_info_from_ip_id(uint16_t ip_id, uint32_t &fid, uint8_t &thread_id);
238private:
239    CNatPerThreadInfo * get_thread_info(uint8_t thread_id);
240    void flush_node(CNatPerThreadInfo * thread_info);
241
242private:
243    uint8_t               m_max_threads;
244    CNatPerThreadInfo   * m_per_thread;
245    CNatStats             m_stats;
246    CNatCheckFlowTable    m_ft;
247};
248
249
250#endif
251