2 *------------------------------------------------------------------
5 * Copyright (c) 2007-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:
10 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
20 #ifndef __CNAT_V4_FUNCTOINS__
21 #define __CNAT_V4_FUNCTOINS__
23 #include "tcp_header_definitions.h"
27 #include "platform_common.h"
30 * Defines and structures to enable TCP packet logging
32 #define TCP_LOGGING_DISABLE 0
33 #define TCP_LOGGING_ENABLE 1
34 #define TCP_LOGGING_PACKET_DUMP 2
35 #define TCP_LOGGING_SUMMARY_DUMP 3
37 #define MAX_TCP_LOGGING_COUNT 1024
39 typedef struct tcp_logging_struct {
50 } tcp_logging_struct_t;
52 void tcp_debug_logging_dump (void);
53 void tcp_debug_logging_enable_disable (u32 enable_flag);
68 #define JLI printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); fflush(stdout);
70 #define CNAT_ICMP_DEST_UNREACHABLE 100
71 #define INCREMENT_NODE_COUNTER(c) \
72 em->counters[node_counter_base_index + c] += 1;
74 #define V4_TCP_UPDATE_SESSION_FLAG(db, tcp) \
75 if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \
76 db->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \
78 if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \
79 db->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \
80 db->flags |= CNAT_DB_FLAG_TCP_CLOSING; \
83 #define V4_TCP_UPDATE_SESSION_DB_FLAG(sdb, tcp) \
84 if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \
85 sdb->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \
87 if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \
88 sdb->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \
89 sdb->flags |= CNAT_DB_FLAG_TCP_CLOSING; \
93 * Code to recalculate checksum after ACK/SEQ number changes
94 * This macro assumes, we have pointer to tcp structure
95 * referenced by the name "tcp"
97 #define CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(old_val32, new_val32) \
99 u16 old_val_lower, old_val_upper, old_tcp_cr; \
100 u16 new_val_lower, new_val_upper, new_tcp_cr; \
103 old_val_lower = ~((u16) old_val32); \
104 old_val_upper = ~((u16) (old_val32 >> 16)); \
105 old_tcp_cr = ~net2host16(&tcp->tcp_checksum); \
106 new_val_lower = (u16) new_val32; \
107 new_val_upper = (u16) (new_val32 >> 16); \
109 sum32 = old_val_lower + old_val_upper + old_tcp_cr + \
110 new_val_lower + new_val_upper; \
112 sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \
113 sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \
114 new_tcp_cr = ~((u16)sum32); \
116 tcp->tcp_checksum = host2net16(new_tcp_cr); \
120 * newchecksum = ~(~oldchecksum + ~old + new)
121 * old/new for l3 checksum: ip address
123 #define CNAT_UPDATE_L3_CHECKSUM_DECLARE \
124 u16 old_l3_1r, old_l3_2r; \
125 u16 old_l3_cr, new_l3_c; \
128 #define CNAT_UPDATE_L3_CHECKSUM(old_l3_1, old_l3_2, old_l3_c, \
129 new_l3_1, new_l3_2) \
130 old_l3_1r = ~(old_l3_1); \
131 old_l3_2r = ~(old_l3_2); \
132 old_l3_cr = ~(old_l3_c); \
133 new32 = old_l3_cr + old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
134 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
135 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
136 new_l3_c = ~((u16)new32);
140 * newchecksum = ~(~oldchecksum + ~old + new)
141 * old/new for l3 checksum: ip address
142 * old/new for l4 checksum: ip address and port
144 #define CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE \
145 u16 old_l3_1r, old_l3_2r, old_l4r; \
146 u16 old_l3_cr, old_l4_cr; \
147 u16 new_l3_c, new_l4_c; \
150 #define CNAT_UPDATE_L3_L4_CHECKSUM(old_l3_1, old_l3_2, old_l4, \
151 old_l3_c, old_l4_c, \
152 new_l3_1, new_l3_2, new_l4) \
153 old_l3_1r = ~(old_l3_1); \
154 old_l3_2r = ~(old_l3_2); \
155 old_l3_cr = ~(old_l3_c); \
156 sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
157 new32 = old_l3_cr + sum32; \
158 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
159 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
160 new_l3_c = ~((u16)new32); \
161 old_l4r = ~(old_l4); \
162 old_l4_cr = ~(old_l4_c); \
163 sum32 += old_l4r + new_l4; \
164 new32 = old_l4_cr + sum32; \
165 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
166 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
167 new_l4_c = ~((u16)new32);
170 * For ICMP checksums, we don't use the top IP header for checksum calculation
172 #define CNAT_UPDATE_L3_ICMP_CHECKSUM(old_l3_1, old_l3_2, old_l4, \
173 old_l3_c, old_l4_c, \
174 new_l3_1, new_l3_2, new_l4) \
175 old_l3_1r = ~(old_l3_1); \
176 old_l3_2r = ~(old_l3_2); \
177 old_l3_cr = ~(old_l3_c); \
178 sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
179 new32 = old_l3_cr + sum32; \
180 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
181 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
182 new_l3_c = ~((u16)new32); \
183 old_l4r = ~(old_l4); \
184 old_l4_cr = ~(old_l4_c); \
185 sum32 = old_l4r + new_l4; \
186 new32 = old_l4_cr + sum32; \
187 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
188 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
189 new_l4_c = ~((u16)new32);
193 * icmp error type message:
194 * newchecksum = ~(~oldchecksum + ~old + new)
195 * old/new for outlayer ip checksum: ip address
196 * old/new for outlayer icmp checksum:
197 * out-layer: ip address
198 * inner-layer: ip addr, port, l3 checksum, l4 checksum
200 #define CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE \
201 u16 old_ip_1r, old_ip_2r, old_ip_port_r, old_ip_cr, old_icmp_cr; \
206 #define CNAT_UPDATE_ICMP_ERR_CHECKSUM(old_ip_1, old_ip_2, old_ip_port, old_ip_c, old_icmp_c, \
207 new_ip_1, new_ip_2, new_ip_port, new_ip_c) \
208 old_ip_1r = ~(old_ip_1); \
209 old_ip_2r = ~(old_ip_2); \
210 old_ip_port_r = ~(old_ip_port); \
211 old_ip_cr = ~(old_ip_c); \
212 old_icmp_cr = ~(old_icmp_c); \
213 sum32 = old_ip_1r + old_ip_2r + new_ip_1 + new_ip_2 + \
214 old_ip_port_r + new_ip_port + old_ip_cr + new_ip_c; \
215 new32 = old_icmp_cr + sum32; \
216 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
217 new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
218 new_icmp_c = ~((u16)new32); \
221 * Add the two 16 bit parts of the 32 bit field
222 * Repeat it one more time to take care of any overflow
223 * Complement the u16 value and store it in network format
225 #define FILL_CHECKSUM(checksum_field, sum32) { \
226 sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \
227 sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \
228 checksum_field = clib_host_to_net_u16(~((u16) sum32)); \
232 cnat_v4_recalculate_tcp_checksum (ipv4_header *ip,
235 u16 *tcp_port_addr_ptr,
239 u32 old_ip_addr, old_ip32_r, new_ip32, sum32;
240 u16 old_port_r, old_ip_checksum_r, old_tcp_checksum_r;
244 p16 = (u16*) ip_addr_ptr;
246 old_ip_addr = *ip_addr_ptr;
247 old_ip32_r = (((u16) ~clib_net_to_host_u16(*p16)) +
248 ((u16) ~clib_net_to_host_u16(*(p16+1))));
250 old_port_r = ~clib_net_to_host_u16(*tcp_port_addr_ptr);
252 *ip_addr_ptr = clib_host_to_net_u32(new_ip);
254 new_ip32 = (new_ip & 0xffff) + ((new_ip >> 16) & 0xffff);
256 old_ip_checksum_r = ~clib_net_to_host_u16(ip->checksum);
259 * Recalculate the new IP checksum
261 sum32 = old_ip32_r + new_ip32 + old_ip_checksum_r;
263 FILL_CHECKSUM(ip->checksum, sum32);
266 clib_net_to_host_u16((ip->frag_flags_offset));
268 if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
269 return; /* No need to update TCP fields */
272 *tcp_port_addr_ptr = clib_host_to_net_u16(new_port);
273 old_tcp_checksum_r = ~clib_net_to_host_u16(tcp->tcp_checksum);
276 * Recalculate the new TCP checksum
278 sum32 = old_ip32_r + new_ip32 +
279 old_port_r + new_port + old_tcp_checksum_r;
281 FILL_CHECKSUM(tcp->tcp_checksum, sum32);
283 if (PREDICT_FALSE(tcp_logging_enable_flag)) {
285 clib_net_to_host_u32(tcp->seq_num),
286 clib_net_to_host_u32(tcp->ack_num),
287 clib_net_to_host_u32(old_ip_addr),
288 clib_net_to_host_u32(*ip_addr_ptr),
290 clib_net_to_host_u16(*tcp_port_addr_ptr),
292 clib_net_to_host_u16(ip->checksum),
294 clib_net_to_host_u16(tcp->tcp_checksum));
299 inline void tcp_in2out_nat_mss_n_checksum (ipv4_header *ip,
303 cnat_main_db_entry_t * db);
305 void hex_dump(u8 * p, int len);
307 u32 get_my_svi_intf_ip_addr();
310 * in cnat_v4_icmp_gen.c,
311 * return 1 if icmp msg allow to generate
315 u32 icmp_msg_gen_allowed ();
317 cnat_icmp_msg_t v6_icmp_msg_gen_allowed();
319 int v4_crc_zero_udp_allowed();
320 void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4);
321 int icmpv4_generate_with_throttling (spp_ctx_t *ctx, ipv4_header *ipv4,
324 int icmpv6_generate_with_throttling (spp_ctx_t *ctx, ipv6_header_t *ipv4,
327 void icmp_error_generate_v6(spp_ctx_t *ctx, u8 icmp_type,
328 u8 icmp_code, u16 uidb_index);
330 void calculate_window_scale(tcp_hdr_type *tcp_header, u8 *scale);
332 void cnat_log_nat44_tcp_seq_mismatch(
333 cnat_main_db_entry_t *db,
334 cnat_vrfmap_t *vrfmap);
335 void print_icmp_pkt (ipv4_header *ip);
336 void print_udp_pkt (ipv4_header *ip);
337 void print_tcp_pkt (ipv4_header *ip);
338 void print_ipv6_pkt (ipv6_header_t *ip);