#endif
 
 #include <net/ip_vs.h>
+#include <linux/indirect_call_wrapper.h>
 
 
 EXPORT_SYMBOL(register_ip_vs_scheduler);
 #endif
 EXPORT_SYMBOL(ip_vs_new_conn_out);
 
+#ifdef CONFIG_IP_VS_PROTO_TCP
+INDIRECT_CALLABLE_DECLARE(int
+       tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
+                        struct ip_vs_conn *cp, struct ip_vs_iphdr *iph));
+#endif
+
+#ifdef CONFIG_IP_VS_PROTO_UDP
+INDIRECT_CALLABLE_DECLARE(int
+       udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
+                        struct ip_vs_conn *cp, struct ip_vs_iphdr *iph));
+#endif
+
+#if defined(CONFIG_IP_VS_PROTO_TCP) && defined(CONFIG_IP_VS_PROTO_UDP)
+#define SNAT_CALL(f, ...) \
+       INDIRECT_CALL_2(f, tcp_snat_handler, udp_snat_handler, __VA_ARGS__)
+#elif defined(CONFIG_IP_VS_PROTO_TCP)
+#define SNAT_CALL(f, ...) INDIRECT_CALL_1(f, tcp_snat_handler, __VA_ARGS__)
+#elif defined(CONFIG_IP_VS_PROTO_UDP)
+#define SNAT_CALL(f, ...) INDIRECT_CALL_1(f, udp_snat_handler, __VA_ARGS__)
+#else
+#define SNAT_CALL(f, ...) f(__VA_ARGS__)
+#endif
+
 static unsigned int ip_vs_net_id __read_mostly;
 /* netns cnt used for uniqueness */
 static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
         */
        if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK)) {
                iph->hdr_flags ^= IP_VS_HDR_INVERSE;
-               cp = pp->conn_in_get(svc->ipvs, svc->af, skb, iph);
+               cp = INDIRECT_CALL_1(pp->conn_in_get,
+                                    ip_vs_conn_in_get_proto, svc->ipvs,
+                                    svc->af, skb, iph);
                iph->hdr_flags ^= IP_VS_HDR_INVERSE;
 
                if (cp) {
        ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
 
        /* The embedded headers contain source and dest in reverse order */
-       cp = pp->conn_out_get(ipvs, AF_INET, skb, &ciph);
+       cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+                            ipvs, AF_INET, skb, &ciph);
        if (!cp)
                return NF_ACCEPT;
 
                return NF_ACCEPT;
 
        /* The embedded headers contain source and dest in reverse order */
-       cp = pp->conn_out_get(ipvs, AF_INET6, skb, &ciph);
+       cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+                            ipvs, AF_INET6, skb, &ciph);
        if (!cp)
                return NF_ACCEPT;
 
                goto drop;
 
        /* mangle the packet */
-       if (pp->snat_handler && !pp->snat_handler(skb, pp, cp, iph))
+       if (pp->snat_handler &&
+           !SNAT_CALL(pp->snat_handler, skb, pp, cp, iph))
                goto drop;
 
 #ifdef CONFIG_IP_VS_IPV6
        /*
         * Check if the packet belongs to an existing entry
         */
-       cp = pp->conn_out_get(ipvs, af, skb, &iph);
+       cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+                            ipvs, af, skb, &iph);
 
        if (likely(cp)) {
                if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
        /* The embedded headers contain source and dest in reverse order.
         * For IPIP this is error for request, not for reply.
         */
-       cp = pp->conn_in_get(ipvs, AF_INET, skb, &ciph);
+       cp = INDIRECT_CALL_1(pp->conn_in_get, ip_vs_conn_in_get_proto,
+                            ipvs, AF_INET, skb, &ciph);
 
        if (!cp) {
                int v;
        /* The embedded headers contain source and dest in reverse order
         * if not from localhost
         */
-       cp = pp->conn_in_get(ipvs, AF_INET6, skb, &ciph);
+       cp = INDIRECT_CALL_1(pp->conn_in_get, ip_vs_conn_in_get_proto,
+                            ipvs, AF_INET6, skb, &ciph);
 
        if (!cp) {
                int v;
        /*
         * Check if the packet belongs to an existing connection entry
         */
-       cp = pp->conn_in_get(ipvs, af, skb, &iph);
+       cp = INDIRECT_CALL_1(pp->conn_in_get, ip_vs_conn_in_get_proto,
+                            ipvs, af, skb, &iph);
 
        conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
        if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {