diff options
-rw-r--r-- | src/plugins/cnat/cnat_node.h | 41 | ||||
-rw-r--r-- | src/plugins/cnat/cnat_types.h | 11 | ||||
-rw-r--r-- | src/vppinfra/crc32.h | 20 |
3 files changed, 64 insertions, 8 deletions
diff --git a/src/plugins/cnat/cnat_node.h b/src/plugins/cnat/cnat_node.h index 80d803c4b61..c304c5c83e8 100644 --- a/src/plugins/cnat/cnat_node.h +++ b/src/plugins/cnat/cnat_node.h @@ -226,6 +226,29 @@ cnat_ip4_translate_l4 (ip4_header_t * ip4, udp_header_t * udp, } static_always_inline void +cnat_ip4_translate_sctp (ip4_header_t *ip4, sctp_header_t *sctp, + u16 new_port[VLIB_N_DIR]) +{ + /* Fastpath no checksum */ + if (PREDICT_TRUE (0 == sctp->checksum)) + { + sctp->dst_port = new_port[VLIB_TX]; + sctp->src_port = new_port[VLIB_RX]; + return; + } + + if (new_port[VLIB_TX]) + sctp->dst_port = new_port[VLIB_TX]; + if (new_port[VLIB_RX]) + sctp->src_port = new_port[VLIB_RX]; + + sctp->checksum = 0; + sctp->checksum = clib_host_to_little_u32 (~clib_crc32c_with_init ( + (u8 *) sctp, ntohs (ip4->length) - sizeof (ip4_header_t), + ~0 /* init value */)); +} + +static_always_inline void cnat_ip4_translate_l3 (ip4_header_t * ip4, ip4_address_t new_addr[VLIB_N_DIR]) { ip4_address_t old_addr[VLIB_N_DIR]; @@ -407,6 +430,12 @@ cnat_translation_ip4 (const cnat_session_t * session, udp->checksum = ip_csum_fold (sum); cnat_ip4_translate_l3 (ip4, new_addr); } + else if (ip4->protocol == IP_PROTOCOL_SCTP) + { + sctp_header_t *sctp = (sctp_header_t *) udp; + cnat_ip4_translate_sctp (ip4, sctp, new_port); + cnat_ip4_translate_l3 (ip4, new_addr); + } else if (ip4->protocol == IP_PROTOCOL_ICMP) { icmp46_header_t *icmp = (icmp46_header_t *) udp; @@ -743,6 +772,18 @@ cnat_session_make_key (vlib_buffer_t *b, ip_address_family_t af, session->key.cs_port[VLIB_RX] = udp->src_port; session->key.cs_port[VLIB_TX] = udp->dst_port; } + else if (ip4->protocol == IP_PROTOCOL_SCTP) + { + sctp_header_t *sctp; + sctp = (sctp_header_t *) (ip4 + 1); + ip46_address_set_ip4 (&session->key.cs_ip[VLIB_TX], + &ip4->dst_address); + ip46_address_set_ip4 (&session->key.cs_ip[VLIB_RX], + &ip4->src_address); + session->key.cs_proto = ip4->protocol; + session->key.cs_port[VLIB_RX] = sctp->src_port; + session->key.cs_port[VLIB_TX] = sctp->dst_port; + } else goto error; } diff --git a/src/plugins/cnat/cnat_types.h b/src/plugins/cnat/cnat_types.h index 7b779a66a4e..bf2726fa63a 100644 --- a/src/plugins/cnat/cnat_types.h +++ b/src/plugins/cnat/cnat_types.h @@ -55,6 +55,17 @@ #define MIN_SRC_PORT ((u16) 0xC000) +typedef struct +{ + /* Source and destination port. */ + u16 src_port, dst_port; + + /* Random value to distinguish connections. */ + u32 verification_tag; + + u32 checksum; +} sctp_header_t; + typedef enum cnat_trk_flag_t_ { /* Endpoint is active (static or dhcp resolved) */ diff --git a/src/vppinfra/crc32.h b/src/vppinfra/crc32.h index 3b81daf28ca..2b20fef9027 100644 --- a/src/vppinfra/crc32.h +++ b/src/vppinfra/crc32.h @@ -76,23 +76,27 @@ clib_crc32c_u64 (u32 last, u64 data) #ifdef clib_crc32c_uses_intrinsics static_always_inline u32 -clib_crc32c (u8 * s, int len) +clib_crc32c_with_init (u8 *s, int len, u32 last) { - u32 v = 0; - for (; len >= 8; len -= 8, s += 8) - v = clib_crc32c_u64 (v, *((u64u *) s)); + last = clib_crc32c_u64 (last, *((u64u *) s)); for (; len >= 4; len -= 4, s += 4) - v = clib_crc32c_u32 (v, *((u32u *) s)); + last = clib_crc32c_u32 (last, *((u32u *) s)); for (; len >= 2; len -= 2, s += 2) - v = clib_crc32c_u16 (v, *((u16u *) s)); + last = clib_crc32c_u16 (last, *((u16u *) s)); for (; len >= 1; len -= 1, s += 1) - v = clib_crc32c_u8 (v, *((u8 *) s)); + last = clib_crc32c_u8 (last, *((u8 *) s)); + + return last; +} - return v; +static_always_inline u32 +clib_crc32c (u8 *s, int len) +{ + return clib_crc32c_with_init (s, len, 0); } #endif |