aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.h
blob: 34992da8dbc9ea8e5992552b9aa0d10ee03fb83f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server
 *
 * Copyright (C) 2010-2012 VMware, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#line 5

/**
 * @file
 *
 * @brief Linux Offload definitions.
 * This file is only meant to be included via pvtcp_off.h.
 */

#ifndef _PVTCP_OFF_LINUX_H_
#define _PVTCP_OFF_LINUX_H_

#include <linux/socket.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/tcp.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
#include <linux/random.h>
#include <linux/fs.h>
#include <linux/cred.h>


typedef struct PvtcpSock {
   struct sock *sk;
   PVTCP_SOCK_COMMON_FIELDS;
   PVTCP_OFF_SOCK_COMMON_FIELDS;
   void (*destruct)(struct sock *sk);
   void (*stateChange)(struct sock *sk);
   void (*dataReady)(struct sock *sk, int bytes);
   void (*writeSpace)(struct sock *sk);
   void (*errorReport)(struct sock *sk);
} PvtcpSock;


typedef enum PvtcpSockNamespace {
   PVTCP_SOCK_NAMESPACE_INITIAL,
   PVTCP_SOCK_NAMESPACE_CHANNEL
} PvtcpSockNamespace;


/* Number of large datagram allocations. */
extern unsigned long long pvtcpOffDgramAllocations;

/* Inet4 loopback addresses. */
extern unsigned int pvtcpLoopbackOffAddr;

/* Get the 'struct sock' from a PvtcpSock. */
#define SkFromPvsk(pvsk) ((pvsk)->sk)

/* Get the PvtcpSock from a 'struct sock'. */
#define PvskFromSk(sk) ((PvtcpSock *)(sk)->sk_user_data)

int
PvtcpTestAndBindLoopbackInet4(PvtcpSock *pvsk,
                              unsigned int *addr,
                              unsigned short port);
int
PvtcpTestAndBindLoopbackInet6(PvtcpSock *pvsk,
                              unsigned long long *addr0,
                              unsigned long long *addr1,
                              unsigned short port);

void PvtcpResetLoopbackInet4(PvtcpSock *pvsk, unsigned int *addr);
void PvtcpResetLoopbackInet6(PvtcpSock *pvsk, struct in6_addr *in6);

void PvtcpFlowAIO(PvtcpSock *pvsk, int eof);
void PvtcpOutputAIO(PvtcpSock *pvsk);
int PvtcpInputAIO(PvtcpSock *pvsk, void *perCpuBuf);


/**
 * @brief Switches a socket to the channel, or the initial name space.
 * @param pvsk socket to switch.
 * @param ns which namespace to switch to.
 */

static inline void
PvtcpSwitchSock(PvtcpSock *pvsk,
                PvtcpSockNamespace ns)
{
#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE)
   struct sock *sk;
   struct net *prevNet;

   if (!pvsk) {
      return;
   }
   sk = SkFromPvsk(pvsk);
   if (!sk) {
      /* If this is a phony, create fail reporting pvsk, just return. */

      return;
   }

   prevNet = sock_net(sk);
   switch (ns) {
   case PVTCP_SOCK_NAMESPACE_INITIAL:
      sock_net_set(sk, get_net(&init_net));
      break;
   case PVTCP_SOCK_NAMESPACE_CHANNEL:
      sock_net_set(sk, get_net(pvsk->state->namespace));
      break;
   }
   put_net(prevNet);
#endif
}


/**
 * @brief Tests whether a socket has an explicit namespace.
 * @param pvsk socket to test.
 * @return 1 if the socket has a namespace, 0 otherwise.
 */

static inline int
PvtcpHasSockNamespace(PvtcpSock *pvsk)
{
#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE)
   struct sock *sk;
   int rc = 0;

   if (!pvsk) {
      return rc;
   }
   sk = SkFromPvsk(pvsk);
   if (!sk) {
      /* If this is a phony, create fail reporting pvsk, just return 0. */

      return rc;
   }

   rc = (sock_net(sk) != &init_net);
   return rc;
#else
   return 0;
#endif
}


/**
 * @brief Retains the pvsock's underlying socket.
 * @param pvsk socket to retain.
 */

static inline void
PvtcpHoldSock(PvtcpSock *pvsk)
{
   struct sock *sk = SkFromPvsk(pvsk);

   if (likely(sk)) {
      sock_hold(sk);
   }
}


/**
 * @brief Releases a hold on the pvsock's underlying socket. If the underlying
 *   socket is NULL, this is an error socket and we deallocate it.
 * @param pvsk socket to release hold on.
 */

static inline void
PvtcpPutSock(PvtcpSock *pvsk)
{
   struct sock *sk = SkFromPvsk(pvsk);

   if (likely(sk)) {
      sock_put(sk);
   } else {
      /*
       * This is an error socket, which does _not_ have an underlying socket.
       * We simply need to free it.
       */

      CommOS_Kfree(pvsk);
   }
}


/**
 * @brief Schedules an offload socket for AIO.
 * @param pvsk socket to schedule.
 * @sideeffect the socket will be processed by AIO threads.
 */

static inline void
PvtcpSchedSock(PvtcpSock *pvsk)
{
   /*
    * We must hold the socket before we enqueue it for AIO, such that it may
    * not be released while in the workqueue. If CommSvc_ScheduleAIOWork()
    * returned non-zero, it means the socket had already been enqueued. In
    * that case, we release the hold. Otherwise, the hold is released by the
    * AIO function (PvtcpProcessAIO()).
    * Note that error pv sockets may only originate from synchronized RPCs,
    * or to be more precise, from PvtcpCreateOp(), and not from IO processing;
    * this means that they cannot be attempted to be enqueued more than once.
    */

   PvtcpHoldSock(pvsk);
   if (CommSvc_ScheduleAIOWork(&pvsk->work)) {
      PvtcpPutSock(pvsk);
   }
}

#endif // _PVTCP_OFF_LINUX_H_