vcl: ldp support SO_ORIGINAL_DST

Type: improvement

Support SO_ORIGINAL_DST socket option to get original dst_ip4 and dst_port if nat44 rule enabled.

Change-Id: If00e00d03e48f3b78a23a68f1b078954d79dd0f7
Signed-off-by: qinyang <qiny@yusur.tech>
diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c
index cfa9719..5998921 100644
--- a/src/vnet/session/application.c
+++ b/src/vnet/session/application.c
@@ -1529,6 +1529,12 @@
   return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
 }
 
+int
+application_original_dst_is_enabled (application_t *app)
+{
+  return app->flags & APP_OPTIONS_FLAGS_GET_ORIGINAL_DST;
+}
+
 static clib_error_t *
 application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
 					u8 transport_proto, u8 is_start)
diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h
index 09737a6..e100fe8 100644
--- a/src/vnet/session/application.h
+++ b/src/vnet/session/application.h
@@ -300,6 +300,7 @@
 void application_setup_proxy (application_t * app);
 void application_remove_proxy (application_t * app);
 void application_namespace_cleanup (app_namespace_t *app_ns);
+int application_original_dst_is_enabled (application_t *app);
 
 segment_manager_props_t *application_get_segment_manager_properties (u32
 								     app_index);
diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h
index 138953b..510068b 100644
--- a/src/vnet/session/application_interface.h
+++ b/src/vnet/session/application_interface.h
@@ -233,7 +233,8 @@
   _ (USE_LOCAL_SCOPE, "App can use local session scope")                      \
   _ (EVT_MQ_USE_EVENTFD, "Use eventfds for signaling")                        \
   _ (MEMFD_FOR_BUILTIN, "Use memfd for builtin app segs")                     \
-  _ (USE_HUGE_PAGE, "Use huge page for FIFO")
+  _ (USE_HUGE_PAGE, "Use huge page for FIFO")                                 \
+  _ (GET_ORIGINAL_DST, "Get original dst enabled")
 
 typedef enum _app_options
 {
@@ -299,15 +300,15 @@
   u8 is_ip4;			/**< set if uses ip4 networking */
 } app_session_transport_t;
 
-#define foreach_app_session_field					\
-  _(svm_fifo_t, *rx_fifo)		/**< rx fifo */			\
-  _(svm_fifo_t, *tx_fifo)		/**< tx fifo */			\
-  _(session_type_t, session_type)	/**< session type */		\
-  _(volatile u8, session_state)		/**< session state */		\
-  _(u32, session_index)			/**< index in owning pool */	\
-  _(app_session_transport_t, transport)	/**< transport info */		\
-  _(svm_msg_q_t, *vpp_evt_q)		/**< vpp event queue  */	\
-  _(u8, is_dgram)			/**< flag for dgram mode */	\
+#define foreach_app_session_field                                             \
+  _ (svm_fifo_t, *rx_fifo)		 /**< rx fifo */                      \
+  _ (svm_fifo_t, *tx_fifo)		 /**< tx fifo */                      \
+  _ (session_type_t, session_type)	 /**< session type */                 \
+  _ (volatile u8, session_state)	 /**< session state */                \
+  _ (u32, session_index)		 /**< index in owning pool */         \
+  _ (app_session_transport_t, transport) /**< transport info */               \
+  _ (svm_msg_q_t, *vpp_evt_q)		 /**< vpp event queue  */             \
+  _ (u8, is_dgram)			 /**< flag for dgram mode */
 
 typedef struct
 {
@@ -386,6 +387,8 @@
   transport_endpoint_t lcl;
   transport_endpoint_t rmt;
   u8 flags;
+  u32 original_dst_ip4;
+  u16 original_dst_port;
 } __clib_packed session_accepted_msg_t;
 
 typedef struct session_accepted_reply_msg_
diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c
index 5bb5776..228234c 100644
--- a/src/vnet/session/session.c
+++ b/src/vnet/session/session.c
@@ -17,6 +17,7 @@
  * @brief Session and session manager
  */
 
+#include <vnet/plugin/plugin.h>
 #include <vnet/session/session.h>
 #include <vnet/session/application.h>
 #include <vnet/dpo/load_balance.h>
@@ -1762,6 +1763,22 @@
 					      f->segment_index);
 }
 
+void
+session_get_original_dst (transport_endpoint_t *i2o_src,
+			  transport_endpoint_t *i2o_dst,
+			  transport_proto_t transport_proto, u32 *original_dst,
+			  u16 *original_dst_port)
+{
+  session_main_t *smm = vnet_get_session_main ();
+  ip_protocol_t proto =
+    (transport_proto == TRANSPORT_PROTO_TCP ? IPPROTO_TCP : IPPROTO_UDP);
+  if (!smm->original_dst_lookup || !i2o_dst->is_ip4)
+    return;
+  smm->original_dst_lookup (&i2o_src->ip.ip4, i2o_src->port, &i2o_dst->ip.ip4,
+			    i2o_dst->port, proto, original_dst,
+			    original_dst_port);
+}
+
 /* *INDENT-OFF* */
 static session_fifo_rx_fn *session_tx_fns[TRANSPORT_TX_N_FNS] = {
     session_tx_fifo_peek_and_snd,
@@ -2292,6 +2309,11 @@
 	smm->no_adaptive = 1;
       else if (unformat (input, "use-dma"))
 	smm->dma_enabled = 1;
+      else if (unformat (input, "nat44-original-dst-enable"))
+	{
+	  smm->original_dst_lookup = vlib_get_plugin_symbol (
+	    "nat_plugin.so", "nat44_original_dst_lookup");
+	}
       /*
        * Deprecated but maintained for compatibility
        */
diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h
index 10bae27..9c08f1a 100644
--- a/src/vnet/session/session.h
+++ b/src/vnet/session/session.h
@@ -193,6 +193,10 @@
 u8 session_node_lookup_fifo_event (svm_fifo_t * f, session_event_t * e);
 
 typedef void (*session_update_time_fn) (f64 time_now, u8 thread_index);
+typedef void (*nat44_original_dst_lookup_fn) (
+  ip4_address_t *i2o_src, u16 i2o_src_port, ip4_address_t *i2o_dst,
+  u16 i2o_dst_port, ip_protocol_t proto, u32 *original_dst,
+  u16 *original_dst_port);
 
 typedef struct session_main_
 {
@@ -281,6 +285,9 @@
   u32 preallocated_sessions;
 
   u16 msg_id_base;
+
+  /** Query nat44-ed session to get original dst ip4 & dst port. */
+  nat44_original_dst_lookup_fn original_dst_lookup;
 } session_main_t;
 
 extern session_main_t session_main;
@@ -812,6 +819,10 @@
 
 session_t *session_alloc_for_connection (transport_connection_t * tc);
 session_t *session_alloc_for_half_open (transport_connection_t *tc);
+void session_get_original_dst (transport_endpoint_t *i2o_src,
+			       transport_endpoint_t *i2o_dst,
+			       transport_proto_t transport_proto,
+			       u32 *original_dst, u16 *original_dst_port);
 
 typedef void (pool_safe_realloc_rpc_fn) (void *rpc_args);
 
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index 3e99938..3d70733 100644
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -136,6 +136,13 @@
       m.mq_index = s->thread_index;
     }
 
+  if (application_original_dst_is_enabled (app))
+    {
+      session_get_original_dst (&m.lcl, &m.rmt,
+				session_get_transport_proto (s),
+				&m.original_dst_ip4, &m.original_dst_port);
+    }
+
   app_wrk_send_ctrl_evt (app_wrk, SESSION_CTRL_EVT_ACCEPTED, &m, sizeof (m));
 
   return 0;