Initial commit of vpp code.
[vpp.git] / vnet / vnet / vcgn / cnat_v4_functions.c
1 /*
2  *---------------------------------------------------------------------------
3  * cnat_v4_funtions.c
4  *
5  * Copyright (c) 2008-2013 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *---------------------------------------------------------------------------
18  */
19 #include <vlib/vlib.h>
20 #include <vnet/vnet.h>
21 #include <vnet/pg/pg.h>
22 #include <vppinfra/error.h>
23
24
25 #include "tcp_header_definitions.h"
26 #include "cnat_db.h"
27 #include "cnat_config.h"
28 #include "cnat_v4_functions.h"
29 #include "dslite_defs.h"
30 #include "dslite_db.h"
31
32 static u32 tcp_logging_count;
33 static u32 tcp_logging_overflow;
34
35 static tcp_logging_struct_t tcp_logging_array[MAX_TCP_LOGGING_COUNT];
36
37 /*
38  * Function to log TCP pkts checksum changes..
39  */
40 void
41 tcp_debug_logging (
42     u32 seq_num,
43     u32 ack_num,
44     u32 old_ip,
45     u32 new_ip,
46     u16 old_port,
47     u16 new_port,
48     u16 old_ip_crc,
49     u16 new_ip_crc,
50     u16 old_tcp_crc,
51     u16 new_tcp_crc)
52 {
53     tcp_logging_array[tcp_logging_count].seq_num      = seq_num;
54     tcp_logging_array[tcp_logging_count].ack_num      = ack_num;
55     tcp_logging_array[tcp_logging_count].old_ip       = old_ip;
56     tcp_logging_array[tcp_logging_count].new_ip       = new_ip;
57     tcp_logging_array[tcp_logging_count].old_port     = old_port;
58     tcp_logging_array[tcp_logging_count].new_port     = new_port;
59     tcp_logging_array[tcp_logging_count].old_ip_crc   = old_ip_crc;
60     tcp_logging_array[tcp_logging_count].new_ip_crc   = new_ip_crc;
61     tcp_logging_array[tcp_logging_count].old_tcp_crc  = old_tcp_crc;
62     tcp_logging_array[tcp_logging_count].new_tcp_crc  = new_tcp_crc;
63
64     tcp_logging_count++;
65
66     if (tcp_logging_count >= MAX_TCP_LOGGING_COUNT) {
67         tcp_logging_overflow = 1;
68         tcp_logging_count    = 0;
69     }
70 }
71
72 /*
73  * Function to dmp TCP pkts logged..
74  */
75 void
76 tcp_debug_logging_dump (void)
77 {
78     u32 i, total_count, start_entry;
79
80     if (tcp_logging_overflow) {
81         total_count = MAX_TCP_LOGGING_COUNT;
82         start_entry = tcp_logging_count;
83         printf("Logging Entries Wrapped Around, displaying %d entries\n",
84                total_count);
85     } else {
86         total_count = tcp_logging_count;
87         start_entry = 0;
88         printf("Displaying %d entries\n", total_count);
89     }
90
91     printf("SEQ ACK IP_O IP_N PORT_O PORT_N L3_CRC_O L3_CRC_N L4_CRC_O L4_CRC_N\n");
92
93     for (i = 0; i < total_count; i++) {
94         u32 entry = (i + start_entry) % MAX_TCP_LOGGING_COUNT;
95
96         printf("%04d: 0x%08x 0x%08x 0x%08x 0x%08x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
97                entry, 
98                tcp_logging_array[entry].seq_num,
99                tcp_logging_array[entry].ack_num,
100                tcp_logging_array[entry].old_ip,
101                tcp_logging_array[entry].new_ip,
102                tcp_logging_array[entry].old_port,
103                tcp_logging_array[entry].new_port,
104                tcp_logging_array[entry].old_ip_crc,
105                tcp_logging_array[entry].new_ip_crc,
106                tcp_logging_array[entry].old_tcp_crc,
107                tcp_logging_array[entry].new_tcp_crc);
108     }
109 }
110
111 /*
112  * Function to enable TCP logging
113  */
114 void
115 tcp_debug_logging_enable_disable (u32 enable_flag)
116 {
117     switch (enable_flag) { 
118
119     case TCP_LOGGING_DISABLE:
120         if (tcp_logging_enable_flag == TCP_LOGGING_DISABLE) {
121             printf("\nTCP Logging ALREADY DISABLED\n");
122         } else {
123             printf("\nTCP Logging DISABLED\n");
124         }
125         tcp_logging_enable_flag = 0;
126         break;
127
128     case TCP_LOGGING_ENABLE:
129         if (tcp_logging_enable_flag == TCP_LOGGING_ENABLE) {
130             printf("\nTCP Logging ALREADY ENABLED\n");
131         } else {
132             tcp_logging_enable_flag = 1;
133             tcp_logging_count    = 0;
134             tcp_logging_overflow = 0;
135
136             printf("\nTCP Logging ENABLED\n");
137         }
138         break;
139
140     case TCP_LOGGING_PACKET_DUMP:
141         tcp_debug_logging_dump();
142         break;
143
144     case TCP_LOGGING_SUMMARY_DUMP:
145     default:
146         printf("\ntcp_logging_enable_flag %d, tcp_log_count %d\n",
147                tcp_logging_enable_flag, tcp_logging_count);
148         printf("To Enable TCP LOGGING provide a flag value of %d\n",
149                TCP_LOGGING_ENABLE);
150         break;
151     }
152 }
153
154 void hex_dump (u8 * p, int len) {
155     int i;
156     for (i=0;i<len;i++) {
157         if(i && (i & 0x3 ) == 0) printf(" ");
158         if(i && (i & 0xf ) == 0) printf("\n");
159         PLATFORM_DEBUG_PRINT("%02X ", p[i]);
160     }
161     PLATFORM_DEBUG_PRINT("\n");
162 }
163
164 void
165 print_icmp_pkt (ipv4_header *ip)
166 {
167     u32 i, total_len;
168
169     u8 *pkt = (u8 *) ip;
170
171     total_len = clib_net_to_host_u16(ip->total_len_bytes);
172
173     printf("\n======== PRINTING PKT START======\n");
174     printf("======== IP PACKET LEN %d ===========\n", total_len);
175     for (i=0; i < 20; i++) {
176        printf(" %02X ", *(pkt + i));
177     }
178
179     printf("\n======== ICMP HEADER =================\n");
180     for (i=20; i < 28; i++) {
181        printf(" %02X ", *(pkt + i));
182     }
183
184     printf("\n======== ICMP BODY ===================\n");
185     for (i=28; i < total_len; i++) {
186        printf(" %02X ", *(pkt + i));
187     }
188
189     printf("\n======== PRINTING PKT END =======\n");
190 }
191
192 void
193 print_udp_pkt (ipv4_header *ip)
194 {
195     u32 i, total_len, udp_len;
196
197     u8 *pkt = (u8 *) ip;
198
199     total_len = clib_net_to_host_u16(ip->total_len_bytes);
200     udp_len = total_len - 20;
201
202     printf("\n======== PRINTING PKT START======\n");
203     printf("======== IP PACKET LEN %d ===========\n", total_len);
204     for (i=0; i < 20; i++) {
205        printf(" %02X ", *(pkt + i));
206     }
207     printf("\n======== UDP PSEUDO HEADER ==========\n");
208     for (i=12; i < 20; i++) {
209        printf(" %02X ", *(pkt + i));
210     }
211     printf(" 00 11 %02X %02X ", udp_len >> 8, udp_len & 0xff);
212
213     printf("\n======== UDP HEADER =================\n");
214     for (i=20; i < 28; i++) {
215        printf(" %02X ", *(pkt + i));
216     }
217     printf("\n======== UDP BODY ===================\n");
218     for (i=28; i < total_len; i++) {
219        printf(" %02X ", *(pkt + i));
220     }
221
222     printf("\n======== PRINTING PKT END =======\n");
223 }
224
225 void
226 print_tcp_pkt (ipv4_header *ip)
227 {
228     u32 i, total_len, tcp_len;
229
230     u8 *pkt = (u8 *) ip;
231
232     total_len = clib_net_to_host_u16(ip->total_len_bytes);
233     tcp_len = total_len - 20;
234
235     printf("\n======== PRINTING PKT START======\n");
236     printf("======== IP PACKET LEN %d ===========\n", total_len);
237     for (i=0; i < 20; i++) {
238        printf(" %02X ", *(pkt + i));
239     }
240     printf("\n======== TCP PSEUDO HEADER ==========\n");
241     for (i=12; i < 20; i++) {
242        printf(" %02X ", *(pkt + i));
243     }
244     printf(" 00 06 %02X %02X ", tcp_len >> 8, tcp_len & 0xff);
245
246     printf("\n======== TCP HEADER =================\n");
247     for (i=20; i < 40; i++) {
248        printf(" %02X ", *(pkt + i));
249     }
250     printf("\n======== TCP BODY ===================\n");
251     for (i=40; i < total_len; i++) {
252        printf(" %02X ", *(pkt + i));
253     }
254
255     printf("\n======== PRINTING PKT END =======\n");
256 }
257
258 /* IN: ipv4 and tcp header pointer,
259  *     new ipv4 addr and port value
260  *     main db index for accessing per vrf mss value 
261  * DO:
262  *     NAT
263  *     mss adjust if needed
264  *     ip & tcp checksum update (incremental)
265  */ 
266
267 inline void tcp_in2out_nat_mss_n_checksum (ipv4_header * ip, 
268                                            tcp_hdr_type * tcp, 
269                                            u32 ipv4_addr, 
270                                            u16 port,
271                                            cnat_main_db_entry_t * db)
272 {
273     u8 *mss_ptr;
274     u8 check_mss = 0;
275     u16 mss_old, mss_new;
276     cnat_vrfmap_t * vrf_map_p;
277
278     cnat_v4_recalculate_tcp_checksum(ip,
279                                      tcp,
280                                      &(ip->src_addr),
281                                      &(tcp->src_port),
282                                      ipv4_addr,
283                                      port);
284     u16 frag_offset =
285         clib_net_to_host_u16(ip->frag_flags_offset);
286
287     if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
288         return; /* No TCP Header at all */
289     }
290
291     /*
292      * check SYN bit and if options field is present
293      * If yes, proceed to extract the options and get TCP MSS value
294      */
295     check_mss = ((tcp->flags & TCP_FLAG_SYN) && 
296                  (((tcp->hdr_len>>4) << 2) > sizeof(tcp_hdr_type)));
297
298     if (PREDICT_FALSE(check_mss)) {
299
300         /* get per VRF mss config */
301         if(PREDICT_FALSE(db->flags & (CNAT_DB_DSLITE_FLAG))) {
302             mss_new = dslite_table_db_ptr[db->dslite_nat44_inst_id].tcp_mss;
303         } else {
304             vrf_map_p = cnat_map_by_vrf + db->vrfmap_index;
305             mss_new = vrf_map_p->tcp_mss;
306         }
307         DSLITE_PRINTF(1, "Check MSS true..%u\n", mss_new);
308         /*
309          * If TCP MSS is not configured, skip the MSS checks
310          */
311         if (PREDICT_FALSE(mss_new != V4_TCP_MSS_NOT_CONFIGURED_VALUE)) {
312
313             /* if mss_ptr != NULL, then it points to MSS option */
314             mss_ptr = tcp_findoption(tcp, TCP_OPTION_MSS);
315
316             /* 
317              * TCP option field: | kind 1B | len 1B | value 2B|  
318              *    where kind != [0,1] 
319              */
320             if (PREDICT_TRUE(mss_ptr && (mss_ptr[1] == 4))) {
321
322                 u16 *ptr = (u16*)(mss_ptr + 2);
323
324                 mss_old = clib_net_to_host_u16(*ptr);
325
326                 if (PREDICT_FALSE(mss_old > mss_new)) {
327                     u32 sum32;
328                     u16 mss_old_r, old_tcp_checksum_r;
329
330                     *ptr = clib_host_to_net_u16(mss_new);
331
332                     mss_old_r = ~mss_old;
333
334                     old_tcp_checksum_r =
335                         ~clib_net_to_host_u16(tcp->tcp_checksum);
336
337                     /*
338                      * Revise the TCP checksum
339                      */
340                     sum32 = old_tcp_checksum_r + mss_old_r + mss_new;
341                     FILL_CHECKSUM(tcp->tcp_checksum, sum32)
342
343                     if (PREDICT_FALSE(tcp_logging_enable_flag)) {
344                         tcp_debug_logging(
345                             clib_net_to_host_u32(tcp->seq_num),
346                             clib_net_to_host_u32(tcp->ack_num),
347                             0,
348                             0,
349                             mss_old,
350                             mss_new,
351                             0,
352                             0,
353                             ~old_tcp_checksum_r,
354                             clib_net_to_host_u16(tcp->tcp_checksum));
355                     }
356                 }
357             }
358         }
359     }
360 }
361
362 u32 get_my_svi_intf_ip_addr() {
363     return 0x01010101;
364 }