aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/cnat/cnat_node.h41
-rw-r--r--src/plugins/cnat/cnat_types.h11
-rw-r--r--src/vppinfra/crc32.h20
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