Whamcloud - gitweb
b=19856
[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 <sys/socket.h>
53 #include <linux/netlink.h>
54
55 #include <libcfs/libcfs.h>
56
57 /** Start the userspace side of a LNL pipe.
58  * @param link Private descriptor for pipe/socket.
59  * @param groups LNL broadcast group to listen to
60  *          (can be null for unicast to this pid)
61  */
62 int libcfs_ulnl_start(lustre_netlink *link, int groups)
63 {
64         struct sockaddr_nl src_addr;
65         int sock;
66         int rc = 0;
67
68         sock = socket(PF_NETLINK, SOCK_RAW, LNL_SOCKET);
69         if (sock < 0)
70                 return -errno;
71
72         memset(&src_addr, 0, sizeof(src_addr));
73         src_addr.nl_family = AF_NETLINK;
74         src_addr.nl_pid = getpid();  /* self pid */
75         src_addr.nl_groups = groups;
76         rc = bind(sock, (struct sockaddr*)&src_addr, sizeof(src_addr));
77         if (rc < 0) {
78                 close(sock);
79                 return -errno;
80         }
81         *link = sock;
82         return 0;
83 }
84
85 int libcfs_ulnl_stop(lustre_netlink *link)
86 {
87         return close(*link);
88 }
89
90 /** Read a message from the netlink layer.
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                         perror("recv");
129                         rc = -errno;
130                         break;
131                 }
132                 lnlh = (struct lnl_hdr *)NLMSG_DATA(nlh);
133                 CDEBUG(0, " Received message mg=%x t=%d m=%d l=%d\n",
134                        lnlh->lnl_magic, lnlh->lnl_transport, lnlh->lnl_msgtype,
135                        lnlh->lnl_msglen);
136                 if (lnlh->lnl_magic != LNL_MAGIC) {
137                         CERROR("bad message magic %x != %x\n",
138                                lnlh->lnl_magic, LNL_MAGIC);
139                         rc = -EPROTO;
140                         break;
141                 }
142                 if (lnlh->lnl_transport == transport ||
143                     lnlh->lnl_transport == LNL_TRANSPORT_GENERIC) {
144                         *lnlhh = lnlh;
145                         return 0;
146                 }
147                 /* Ignore messages on other transports */
148         }
149         free(nlh);
150         return rc;
151 }
152
153 /* Free a message returned by the above fn */
154 int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh)
155 {
156         /* compute nlmsdghdr offset */
157         char *p = (char *)NLMSG_DATA(0);
158
159         free((void *)((char *)*lnlhh - p));
160         *lnlhh = NULL;
161         return 0;
162 }
163
164 #else /* HAVE_NETLINK */
165 int libcfs_ulnl_start(lustre_netlink *link, int groups) {
166         return -ENOSYS;
167 }
168 int libcfs_ulnl_stop(lustre_netlink *link) {
169         return 0;
170 }
171
172 int libcfs_ulnl_msg_get(lustre_netlink *link, int maxsize, int transport,
173                         struct lnl_hdr **lnlhh) {
174         return -ENOSYS;
175 }
176 int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh) {
177         return -ENOSYS;
178 }
179 #endif /* HAVE_NETLINK */
180