Whamcloud - gitweb
4d7e09dcce371b3d8e90c1ac4f3de8c5860e9624
[fs/lustre-release.git] / libcfs / libcfs / ulinux / ulinux-kernelcomm.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2009 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * Author: Nathan Rutman <nathan.rutman@sun.com>
37  *
38  * Kernel - userspace communication routines.  We'll use a shorthand term
39  * "lnl" (Lustre NetLink) for the interface names for all arches (even though
40  * implemtation may not use NetLink).
41  * For Linux, we use Netlink sockets.
42  */
43
44 #define DEBUG_SUBSYSTEM S_CLASS
45
46 /* This is the userspace side.
47  * See libcfs/linux/linux-kernelcomm.c for the kernel side.
48  */
49
50 #ifdef HAVE_NETLINK
51
52 #include <libcfs/libcfs.h>
53 #include <sys/socket.h>
54 #include <linux/netlink.h>
55
56 /** Start the userspace side of a LNL pipe.
57  * @param link Private descriptor for pipe/socket.
58  * @param groups LNL broadcast group to listen to
59  *          (can be null for unicast to this pid)
60  */
61 int libcfs_ulnl_start(lustre_netlink *link, int groups)
62 {
63         struct sockaddr_nl src_addr;
64         int sock;
65         int rc = 0;
66
67         sock = socket(PF_NETLINK, SOCK_RAW, LNL_SOCKET);
68         if (sock < 0)
69                 return -errno;
70
71         memset(&src_addr, 0, sizeof(src_addr));
72         src_addr.nl_family = AF_NETLINK;
73         src_addr.nl_pid = getpid();  /* self pid */
74         src_addr.nl_groups = groups;
75         rc = bind(sock, (struct sockaddr*)&src_addr, sizeof(src_addr));
76         if (rc < 0) {
77                 close(sock);
78                 return -errno;
79         }
80         *link = sock;
81         return 0;
82 }
83
84 int libcfs_ulnl_stop(lustre_netlink *link)
85 {
86         return close(*link);
87 }
88
89 /** Read a message from the netlink layer.
90  * Allocates memory, returns handle
91  *
92  * @param link Private descriptor for pipe/socket.
93  * @param maxsize Maximum message size allowed
94  * @param transport Only listen to messages on this transport
95  *      (and the generic transport)
96  * @param lnlhh Handle to the new LNL message
97  */
98 int libcfs_ulnl_msg_get(lustre_netlink *link, int maxsize, int transport,
99                         struct lnl_hdr **lnlhh)
100 {
101         struct iovec iov;
102         struct sockaddr_nl dest_addr;
103         struct msghdr msg;
104         struct nlmsghdr *nlh = NULL;
105         struct lnl_hdr *lnlh;
106         int rc = 0;
107
108         nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(maxsize));
109         if (!nlh)
110                 return -ENOMEM;
111
112         memset(nlh, 0, NLMSG_SPACE(maxsize));
113         iov.iov_base = (void *)nlh;
114         iov.iov_len = NLMSG_SPACE(maxsize);
115
116         memset(&dest_addr, 0, sizeof(dest_addr));
117         msg.msg_name = (void *)&dest_addr;
118         msg.msg_namelen = sizeof(dest_addr);
119         msg.msg_iov = &iov;
120         msg.msg_iovlen = 1;
121
122         CDEBUG(0, "Waiting for message from kernel on pid %d\n", getpid());
123
124         while (1) {
125                 /* Read message from kernel */
126                 rc = recvmsg(*link, &msg, 0);
127                 if (rc <= 0) {
128                         rc = -errno;
129                         break;
130                 }
131                 lnlh = (struct lnl_hdr *)NLMSG_DATA(nlh);
132                 CDEBUG(0, " Received message mg=%x t=%d m=%d l=%d\n",
133                        lnlh->lnl_magic, lnlh->lnl_transport, lnlh->lnl_msgtype,
134                        lnlh->lnl_msglen);
135                 if (lnlh->lnl_magic != LNL_MAGIC) {
136                         CERROR("bad message magic %x != %x\n",
137                                lnlh->lnl_magic, LNL_MAGIC);
138                         rc = -EPROTO;
139                         break;
140                 }
141                 if (lnlh->lnl_transport == transport ||
142                     lnlh->lnl_transport == LNL_TRANSPORT_GENERIC) {
143                         *lnlhh = lnlh;
144                         return 0;
145                 }
146                 /* Ignore messages on other transports */
147         }
148         free(nlh);
149         return rc;
150 }
151
152 /* Free a message returned by the above fn */
153 int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh)
154 {
155         /* compute nlmsdghdr offset */
156         char *p = (char *)NLMSG_DATA(0);
157
158         free((void *)((char *)*lnlhh - p));
159         *lnlhh = NULL;
160         return 0;
161 }
162
163 #else /* HAVE_NETLINK */
164
165 #include <errno.h>
166
167 typedef int lustre_netlink;
168 int libcfs_ulnl_start(lustre_netlink *link, int groups) {
169         return -ENOSYS;
170 }
171 int libcfs_ulnl_stop(lustre_netlink *link) {
172         return 0;
173 }
174 struct lnl_hdr;
175 int libcfs_ulnl_msg_get(lustre_netlink *link, int maxsize, int transport,
176                         struct lnl_hdr **lnlhh) {
177         return -ENOSYS;
178 }
179 int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh) {
180         return -ENOSYS;
181 }
182 #endif /* HAVE_NETLINK */
183