summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/snat/in2out.c1
-rw-r--r--src/plugins/snat/out2in.c1
-rw-r--r--src/plugins/snat/snat.api66
-rw-r--r--src/plugins/snat/snat.c142
-rw-r--r--src/plugins/snat/snat.h1
-rw-r--r--src/plugins/snat/snat_test.c80
-rw-r--r--test/test_snat.py59
-rw-r--r--test/vpp_papi_provider.py23
8 files changed, 370 insertions, 3 deletions
diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c
index b4b7793dae0..c6dc7ca4e02 100644
--- a/src/plugins/snat/in2out.c
+++ b/src/plugins/snat/in2out.c
@@ -247,6 +247,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
pool_get (sm->per_thread_data[cpu_index].users, u);
memset (u, 0, sizeof (*u));
u->addr = ip0->src_address;
+ u->fib_index = rx_fib_index0;
pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt);
diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c
index 3bfc0aa31e0..7905436aab2 100644
--- a/src/plugins/snat/out2in.c
+++ b/src/plugins/snat/out2in.c
@@ -147,6 +147,7 @@ create_session_for_static_mapping (snat_main_t *sm,
pool_get (sm->per_thread_data[cpu_index].users, u);
memset (u, 0, sizeof (*u));
u->addr = in2out.addr;
+ u->fib_index = in2out.fib_index;
pool_get (sm->per_thread_data[cpu_index].list_pool,
per_user_list_head_elt);
diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api
index c429f05f14b..3462a8d2b6c 100644
--- a/src/plugins/snat/snat.api
+++ b/src/plugins/snat/snat.api
@@ -351,3 +351,69 @@ define snat_ipfix_enable_disable_reply {
u32 context;
i32 retval;
};
+
+/** \brief Dump S-NAT users
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define snat_user_dump {
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief S-NAT users response
+ @param context - sender context, to match reply w/ request
+ @vrf_id - VRF ID
+ @param is_ip4 - 1 if address type is IPv4
+ @param ip_adress - IP address
+ @param nsessions - number of dynamic sessions
+ @param nstaticsessions - number of static sessions
+*/
+define snat_user_details {
+ u32 context;
+ u32 vrf_id;
+ u8 is_ip4;
+ u8 ip_address[16];
+ u32 nsessions;
+ u32 nstaticsessions;
+};
+
+/** \brief S-NAT user's sessions
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param user_ip - IP address of the user to dump
+ @param vrf_id - VRF_ID
+*/
+define snat_user_session_dump {
+ u32 client_index;
+ u32 context;
+ u8 ip_address[16];
+ u32 vrf_id;
+};
+
+/** \brief S-NAT user's sessions response
+ @param context - sender context, to match reply w/ request
+ @param is_ip4 - 1 if address type is IPv4
+ @param outside_ip_address - outside IP address
+ @param outside_port - outside port
+ @param inside_ip_address - inside IP address
+ @param inside_port - inside port
+ @param protocol - protocol
+ @param is_static - 1 if session is static
+ @param last_heard - last heard timer
+ @param total_bytes - count of bytes sent through session
+ @param total_pkts - count of pakets sent through session
+*/
+define snat_user_session_details {
+ u32 context;
+ u8 is_ip4;
+ u8 outside_ip_address[16];
+ u16 outside_port;
+ u8 inside_ip_address[16];
+ u16 inside_port;
+ u16 protocol;
+ u8 is_static;
+ f64 last_heard;
+ u64 total_bytes;
+ u32 total_pkts;
+};
diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c
index 8c2bacdbed4..0ec20ef7909 100644
--- a/src/plugins/snat/snat.c
+++ b/src/plugins/snat/snat.c
@@ -1412,6 +1412,144 @@ static void *vl_api_snat_ipfix_enable_disable_t_print
FINISH;
}
+static void
+send_snat_user_details
+(snat_user_t * u, unix_shared_memory_queue_t * q, u32 context)
+{
+ vl_api_snat_user_details_t * rmp;
+ snat_main_t * sm = &snat_main;
+ ip4_fib_t * fib_table;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ memset (rmp, 0, sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_SNAT_USER_DETAILS+sm->msg_id_base);
+
+ fib_table = ip4_fib_get(u->fib_index);
+ rmp->vrf_id = ntohl (fib_table->table_id);
+
+ rmp->is_ip4 = 1;
+ clib_memcpy(rmp->ip_address, &(u->addr), 4);
+ rmp->nsessions = ntohl (u->nsessions);
+ rmp->nstaticsessions = ntohl (u->nstaticsessions);
+ rmp->context = context;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_snat_user_dump_t_handler
+(vl_api_snat_user_dump_t * mp)
+{
+ unix_shared_memory_queue_t *q;
+ snat_main_t * sm = &snat_main;
+ snat_main_per_thread_data_t * tsm;
+ snat_user_t * u;
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (q == 0)
+ return;
+
+ vec_foreach (tsm, sm->per_thread_data)
+ vec_foreach (u, tsm->users)
+ send_snat_user_details (u, q, mp->context);
+}
+
+static void *vl_api_snat_user_dump_t_print
+(vl_api_snat_user_dump_t *mp, void * handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: snat_user_dump ");
+
+ FINISH;
+}
+
+static void
+send_snat_user_session_details
+(snat_session_t * s, unix_shared_memory_queue_t * q, u32 context)
+{
+ vl_api_snat_user_session_details_t * rmp;
+ snat_main_t * sm = &snat_main;
+
+ rmp = vl_msg_api_alloc (sizeof(*rmp));
+ memset (rmp, 0, sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_SNAT_USER_SESSION_DETAILS+sm->msg_id_base);
+ rmp->is_ip4 = 1;
+ clib_memcpy(rmp->outside_ip_address, (&s->out2in.addr), 4);
+ rmp->outside_port = s->out2in.port;
+ clib_memcpy(rmp->inside_ip_address, (&s->in2out.addr), 4);
+ rmp->inside_port = s->in2out.port;
+ rmp->protocol = ntohs(snat_proto_to_ip_proto(s->in2out.protocol));
+ rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0;
+ rmp->last_heard = ntohl(s->last_heard);
+ rmp->total_bytes = ntohl(s->total_bytes);
+ rmp->total_pkts = ntohl(s->total_pkts);
+ rmp->context = context;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_snat_user_session_dump_t_handler
+(vl_api_snat_user_session_dump_t * mp)
+{
+ unix_shared_memory_queue_t *q;
+ snat_main_t * sm = &snat_main;
+ snat_main_per_thread_data_t *tsm;
+ snat_session_t * s;
+ clib_bihash_kv_8_8_t key, value;
+ snat_user_key_t ukey;
+ snat_user_t * u;
+ u32 session_index, head_index, elt_index;
+ dlist_elt_t * head, * elt;
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (q == 0)
+ return;
+
+ clib_memcpy (&ukey.addr, mp->ip_address, 4);
+ ukey.fib_index = ip4_fib_index_from_table_id (ntohl(mp->vrf_id));
+ key.key = ukey.as_u64;
+ if (!clib_bihash_search_8_8 (&sm->worker_by_in, &key, &value))
+ tsm = vec_elt_at_index (sm->per_thread_data, value.value);
+ else
+ tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+ if (clib_bihash_search_8_8 (&sm->user_hash, &key, &value))
+ return;
+ u = pool_elt_at_index (tsm->users, value.value);
+ if (!u->nsessions && !u->nstaticsessions)
+ return;
+
+ head_index = u->sessions_per_user_list_head_index;
+ head = pool_elt_at_index (tsm->list_pool, head_index);
+ elt_index = head->next;
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
+ session_index = elt->value;
+ while (session_index != ~0)
+ {
+ s = pool_elt_at_index (tsm->sessions, session_index);
+
+ send_snat_user_session_details (s, q, mp->context);
+
+ elt_index = elt->next;
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
+ session_index = elt->value;
+ }
+}
+
+static void *vl_api_snat_user_session_dump_t_print
+(vl_api_snat_user_session_dump_t *mp, void * handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: snat_user_session_dump ");
+ s = format (s, "ip_address %U vrf_id %d\n",
+ format_ip4_address, mp->ip_address,
+ clib_net_to_host_u32 (mp->vrf_id));
+
+ FINISH;
+}
+
/* List of message types that this plugin understands */
#define foreach_snat_plugin_api_msg \
_(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \
@@ -1426,7 +1564,9 @@ _(SNAT_SET_WORKERS, snat_set_workers) \
_(SNAT_WORKER_DUMP, snat_worker_dump) \
_(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr) \
_(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump) \
-_(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable)
+_(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable) \
+_(SNAT_USER_DUMP, snat_user_dump) \
+_(SNAT_USER_SESSION_DUMP, snat_user_session_dump)
/* Set up the API message handling tables */
static clib_error_t *
diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h
index 39cbd3f8e0f..47f2e6ee70f 100644
--- a/src/plugins/snat/snat.h
+++ b/src/plugins/snat/snat.h
@@ -110,6 +110,7 @@ typedef CLIB_PACKED(struct {
typedef struct {
ip4_address_t addr;
+ u32 fib_index;
u32 sessions_per_user_list_head_index;
u32 nsessions;
u32 nstaticsessions;
diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c
index a299e0ac68b..dae63a2369d 100644
--- a/src/plugins/snat/snat_test.c
+++ b/src/plugins/snat/snat_test.c
@@ -104,7 +104,9 @@ _(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY, \
snat_add_del_interface_addr_reply) \
_(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details) \
_(SNAT_IPFIX_ENABLE_DISABLE_REPLY, \
- snat_ipfix_enable_disable_reply)
+ snat_ipfix_enable_disable_reply) \
+_(SNAT_USER_DETAILS, snat_user_details) \
+_(SNAT_USER_SESSION_DETAILS, snat_user_session_details)
static int api_snat_add_address_range (vat_main_t * vam)
{
@@ -645,6 +647,78 @@ static int api_snat_ipfix_enable_disable (vat_main_t * vam)
return ret;
}
+static void vl_api_snat_user_session_details_t_handler
+ (vl_api_snat_user_session_details_t *mp)
+{
+ snat_test_main_t * sm = &snat_test_main;
+ vat_main_t *vam = sm->vat_main;
+
+ fformat(vam->ofp, "%s session %U:%d to %U:%d protocol id %d "
+ "total packets %d total bytes %d\n",
+ mp->is_static ? "static" : "dynamic",
+ format_ip4_address, mp->inside_ip_address, ntohl(mp->inside_port),
+ format_ip4_address, mp->outside_ip_address, ntohl(mp->outside_port),
+ ntohl(mp->protocol), ntohl(mp->total_pkts), ntohl(mp->total_bytes));
+}
+
+static int api_snat_user_session_dump(vat_main_t * vam)
+{
+ vl_api_snat_user_session_dump_t * mp;
+ vl_api_snat_control_ping_t *mp_ping;
+ int ret;
+
+ if (vam->json_output)
+ {
+ clib_warning ("JSON output not supported for snat_address_dump");
+ return -99;
+ }
+
+ M(SNAT_USER_SESSION_DUMP, mp);
+ S(mp);
+
+ /* Use a control ping for synchronization */
+ M(SNAT_CONTROL_PING, mp_ping);
+ S(mp_ping);
+
+ W (ret);
+ return ret;
+}
+
+static void vl_api_snat_user_details_t_handler
+ (vl_api_snat_user_details_t *mp)
+{
+ snat_test_main_t * sm = &snat_test_main;
+ vat_main_t *vam = sm->vat_main;
+
+ fformat(vam->ofp, "user with ip %U with vrf_id %d "
+ "with %d sessions and %d static sessions\n",
+ format_ip4_address, mp->ip_address, ntohl(mp->vrf_id),
+ ntohl(mp->nsessions), ntohl(mp->nstaticsessions));
+}
+
+static int api_snat_user_dump(vat_main_t * vam)
+{
+ vl_api_snat_user_dump_t * mp;
+ vl_api_snat_control_ping_t *mp_ping;
+ int ret;
+
+ if (vam->json_output)
+ {
+ clib_warning ("JSON output not supported for snat_address_dump");
+ return -99;
+ }
+
+ M(SNAT_USER_DUMP, mp);
+ S(mp);
+
+ /* Use a control ping for synchronization */
+ M(SNAT_CONTROL_PING, mp_ping);
+ S(mp_ping);
+
+ W (ret);
+ return ret;
+}
+
/*
* List of messages that the api test plugin sends,
* and that the data plane plugin processes
@@ -667,7 +741,9 @@ _(snat_add_del_interface_addr, \
"<intfc> | sw_if_index <id> [del]") \
_(snat_interface_addr_dump, "") \
_(snat_ipfix_enable_disable, "[domain <id>] [src_port <n>] " \
- "[disable]")
+ "[disable]") \
+_(snat_user_dump, "") \
+_(snat_user_session_dump, "ip_address <ip> vrf_id <table-id>")
static void
snat_vat_api_hookup (vat_main_t *vam)
diff --git a/test/test_snat.py b/test/test_snat.py
index 01bbe10aa3b..4cb51161353 100644
--- a/test/test_snat.py
+++ b/test/test_snat.py
@@ -870,6 +870,27 @@ class TestSNAT(VppTestCase):
capture = self.pg5.get_capture(len(pkts))
self.verify_capture_in(capture, self.pg5)
+ # pg5 session dump
+ addresses = self.vapi.snat_address_dump()
+ self.assertEqual(len(addresses), 1)
+ sessions = self.vapi.snat_user_session_dump(self.pg5.remote_ip4n, 10)
+ self.assertEqual(len(sessions), 3)
+ for session in sessions:
+ self.assertFalse(session.is_static)
+ self.assertEqual(session.inside_ip_address[0:4],
+ self.pg5.remote_ip4n)
+ self.assertEqual(session.outside_ip_address,
+ addresses[0].ip_address)
+ self.assertEqual(sessions[0].protocol, IP_PROTOS.tcp)
+ self.assertEqual(sessions[1].protocol, IP_PROTOS.udp)
+ self.assertEqual(sessions[2].protocol, IP_PROTOS.icmp)
+ self.assertEqual(sessions[0].inside_port, self.tcp_port_in)
+ self.assertEqual(sessions[1].inside_port, self.udp_port_in)
+ self.assertEqual(sessions[2].inside_port, self.icmp_id_in)
+ self.assertEqual(sessions[0].outside_port, self.tcp_port_out)
+ self.assertEqual(sessions[1].outside_port, self.udp_port_out)
+ self.assertEqual(sessions[2].outside_port, self.icmp_id_out)
+
# in2out 3rd interface
pkts = self.create_stream_in(self.pg6, self.pg3)
self.pg6.add_stream(pkts)
@@ -886,6 +907,44 @@ class TestSNAT(VppTestCase):
capture = self.pg6.get_capture(len(pkts))
self.verify_capture_in(capture, self.pg6)
+ # general user and session dump verifications
+ users = self.vapi.snat_user_dump()
+ self.assertTrue(len(users) >= 3)
+ addresses = self.vapi.snat_address_dump()
+ self.assertEqual(len(addresses), 1)
+ for user in users:
+ sessions = self.vapi.snat_user_session_dump(user.ip_address,
+ user.vrf_id)
+ for session in sessions:
+ self.assertEqual(user.ip_address, session.inside_ip_address)
+ self.assertTrue(session.total_bytes > session.total_pkts > 0)
+ self.assertTrue(session.protocol in
+ [IP_PROTOS.tcp, IP_PROTOS.udp,
+ IP_PROTOS.icmp])
+
+ # pg4 session dump
+ sessions = self.vapi.snat_user_session_dump(self.pg4.remote_ip4n, 10)
+ self.assertTrue(len(sessions) >= 4)
+ for session in sessions:
+ self.assertFalse(session.is_static)
+ self.assertEqual(session.inside_ip_address[0:4],
+ self.pg4.remote_ip4n)
+ self.assertEqual(session.outside_ip_address,
+ addresses[0].ip_address)
+
+ # pg6 session dump
+ sessions = self.vapi.snat_user_session_dump(self.pg6.remote_ip4n, 20)
+ self.assertTrue(len(sessions) >= 3)
+ for session in sessions:
+ self.assertTrue(session.is_static)
+ self.assertEqual(session.inside_ip_address[0:4],
+ self.pg6.remote_ip4n)
+ self.assertEqual(map(ord, session.outside_ip_address[0:4]),
+ map(int, static_nat_ip.split('.')))
+ self.assertTrue(session.inside_port in
+ [self.tcp_port_in, self.udp_port_in,
+ self.icmp_id_in])
+
def test_hairpinning(self):
""" SNAT hairpinning """
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index ea574b36493..de189c3eeaf 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1072,6 +1072,29 @@ class VppPapiProvider(object):
'src_port': src_port,
'enable': enable})
+ def snat_user_session_dump(
+ self,
+ ip_address,
+ vrf_id):
+ """Dump S-NAT user's sessions
+
+ :param ip_address: ip adress of the user to be dumped
+ :param cpu_index: cpu_index on which the user is
+ :param vrf_id: VRF ID
+ :return: Dictionary of S-NAT sessions
+ """
+ return self.api(
+ self.papi.snat_user_session_dump,
+ {'ip_address': ip_address,
+ 'vrf_id': vrf_id})
+
+ def snat_user_dump(self):
+ """Dump S-NAT users
+
+ :return: Dictionary of S-NAT users
+ """
+ return self.api(self.papi.snat_user_dump, {})
+
def control_ping(self):
self.api(self.papi.control_ping)