These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / netfilter / ipvs / ip_vs_proto_tcp.c
index 8e92beb..d7024b2 100644 (file)
 #include <net/ip_vs.h>
 
 static int
-tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
+tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
+                 struct ip_vs_proto_data *pd,
                  int *verdict, struct ip_vs_conn **cpp,
                  struct ip_vs_iphdr *iph)
 {
-       struct net *net;
        struct ip_vs_service *svc;
        struct tcphdr _tcph, *th;
-       struct netns_ipvs *ipvs;
+       __be16 _ports[2], *ports = NULL;
 
-       th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
-       if (th == NULL) {
+       /* In the event of icmp, we're only guaranteed to have the first 8
+        * bytes of the transport header, so we only check the rest of the
+        * TCP packet for non-ICMP packets
+        */
+       if (likely(!ip_vs_iph_icmp(iph))) {
+               th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
+               if (th) {
+                       if (th->rst || !(sysctl_sloppy_tcp(ipvs) || th->syn))
+                               return 1;
+                       ports = &th->source;
+               }
+       } else {
+               ports = skb_header_pointer(
+                       skb, iph->len, sizeof(_ports), &_ports);
+       }
+
+       if (!ports) {
                *verdict = NF_DROP;
                return 0;
        }
-       net = skb_net(skb);
-       ipvs = net_ipvs(net);
+
        /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */
        rcu_read_lock();
-       if ((th->syn || sysctl_sloppy_tcp(ipvs)) && !th->rst &&
-           (svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
-                                     &iph->daddr, th->dest))) {
+
+       if (likely(!ip_vs_iph_inverse(iph)))
+               svc = ip_vs_service_find(ipvs, af, skb->mark, iph->protocol,
+                                        &iph->daddr, ports[1]);
+       else
+               svc = ip_vs_service_find(ipvs, af, skb->mark, iph->protocol,
+                                        &iph->saddr, ports[0]);
+
+       if (svc) {
                int ignored;
 
                if (ip_vs_todrop(ipvs)) {
@@ -571,14 +591,13 @@ static inline __u16 tcp_app_hashkey(__be16 port)
 }
 
 
-static int tcp_register_app(struct net *net, struct ip_vs_app *inc)
+static int tcp_register_app(struct netns_ipvs *ipvs, struct ip_vs_app *inc)
 {
        struct ip_vs_app *i;
        __u16 hash;
        __be16 port = inc->port;
        int ret = 0;
-       struct netns_ipvs *ipvs = net_ipvs(net);
-       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
+       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP);
 
        hash = tcp_app_hashkey(port);
 
@@ -597,9 +616,9 @@ static int tcp_register_app(struct net *net, struct ip_vs_app *inc)
 
 
 static void
-tcp_unregister_app(struct net *net, struct ip_vs_app *inc)
+tcp_unregister_app(struct netns_ipvs *ipvs, struct ip_vs_app *inc)
 {
-       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
+       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP);
 
        atomic_dec(&pd->appcnt);
        list_del_rcu(&inc->p_list);
@@ -609,7 +628,7 @@ tcp_unregister_app(struct net *net, struct ip_vs_app *inc)
 static int
 tcp_app_conn_bind(struct ip_vs_conn *cp)
 {
-       struct netns_ipvs *ipvs = net_ipvs(ip_vs_conn_net(cp));
+       struct netns_ipvs *ipvs = cp->ipvs;
        int hash;
        struct ip_vs_app *inc;
        int result = 0;
@@ -653,9 +672,9 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
 /*
  *     Set LISTEN timeout. (ip_vs_conn_put will setup timer)
  */
-void ip_vs_tcp_conn_listen(struct net *net, struct ip_vs_conn *cp)
+void ip_vs_tcp_conn_listen(struct ip_vs_conn *cp)
 {
-       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
+       struct ip_vs_proto_data *pd = ip_vs_proto_data_get(cp->ipvs, IPPROTO_TCP);
 
        spin_lock_bh(&cp->lock);
        cp->state = IP_VS_TCP_S_LISTEN;
@@ -668,10 +687,8 @@ void ip_vs_tcp_conn_listen(struct net *net, struct ip_vs_conn *cp)
  *   timeouts is netns related now.
  * ---------------------------------------------
  */
-static int __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
+static int __ip_vs_tcp_init(struct netns_ipvs *ipvs, struct ip_vs_proto_data *pd)
 {
-       struct netns_ipvs *ipvs = net_ipvs(net);
-
        ip_vs_init_hash_table(ipvs->tcp_apps, TCP_APP_TAB_SIZE);
        pd->timeout_table = ip_vs_create_timeout_table((int *)tcp_timeouts,
                                                        sizeof(tcp_timeouts));
@@ -681,7 +698,7 @@ static int __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
        return 0;
 }
 
-static void __ip_vs_tcp_exit(struct net *net, struct ip_vs_proto_data *pd)
+static void __ip_vs_tcp_exit(struct netns_ipvs *ipvs, struct ip_vs_proto_data *pd)
 {
        kfree(pd->timeout_table);
 }