summaryrefslogtreecommitdiffstats
path: root/sys/contrib/rdma/krping/krping_dev.c
blob: 7902ebfa8f4d443ac7bd22921b3dcb6129061a75 (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
/*
 * This code lifted from:
 * 	Simple `echo' pseudo-device KLD
 * 	Murray Stokely
 * 	Converted to 5.X by Søren (Xride) Straarup
 */

/*
 * /bin/echo "server,port=9999,addr=192.168.69.142,validate" > /dev/krping
 * /bin/echo "client,port=9999,addr=192.168.69.142,validate" > /dev/krping
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h>  /* uprintf */
#include <sys/errno.h>
#include <sys/param.h>  /* defines used in kernel.h */
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h>   /* cdevsw struct */
#include <sys/uio.h>    /* uio struct */
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <machine/stdarg.h>

#include "krping.h"

#define BUFFERSIZE 512

SYSCTL_NODE(_dev, OID_AUTO, krping, CTLFLAG_RW, 0, "kernel rping module");

int krping_debug = 0;
SYSCTL_INT(_dev_krping, OID_AUTO, debug, CTLFLAG_RW, &krping_debug, 0 , "");

/* Function prototypes */
static d_open_t      krping_open;
static d_close_t     krping_close;
static d_read_t      krping_read;
static d_write_t     krping_write;

/* Character device entry points */
static struct cdevsw krping_cdevsw = {
	.d_version = D_VERSION,
	.d_open = krping_open,
	.d_close = krping_close,
	.d_read = krping_read,
	.d_write = krping_write,
	.d_name = "krping",
};

typedef struct s_krping {
	char msg[BUFFERSIZE];
	int len;
} krping_t;

struct stats_list_entry {
	STAILQ_ENTRY(stats_list_entry) link;
	struct krping_stats *stats;
};
STAILQ_HEAD(stats_list, stats_list_entry);

/* vars */
static struct cdev *krping_dev;

static int
krping_loader(struct module *m, int what, void *arg)
{
	int err = 0;

	switch (what) {
	case MOD_LOAD:                /* kldload */
		krping_init();
		krping_dev = make_dev(&krping_cdevsw, 0, UID_ROOT, GID_WHEEL,
					0600, "krping");
		printf("Krping device loaded.\n");
		break;
	case MOD_UNLOAD:
		destroy_dev(krping_dev);
		printf("Krping device unloaded.\n");
		break;
	default:
		err = EOPNOTSUPP;
		break;
	}

	return (err);
}

static int
krping_open(struct cdev *dev, int oflags, int devtype, struct thread *p)
{

	return (0);
}

static int
krping_close(struct cdev *dev, int fflag, int devtype, struct thread *p)
{

	return 0;
}

static void
krping_copy_stats(struct krping_stats *stats, void *arg)
{
	struct stats_list_entry *s;
	struct stats_list *list = arg;

	s = malloc(sizeof(*s), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (s == NULL)
		return;
	if (stats != NULL) {
		s->stats = malloc(sizeof(*stats), M_DEVBUF, M_NOWAIT | M_ZERO);
		if (s->stats == NULL) {
			free(s, M_DEVBUF);
			return;
		}
		*s->stats = *stats;
	}
	STAILQ_INSERT_TAIL(list, s, link);
}

static int
krping_read(struct cdev *dev, struct uio *uio, int ioflag)
{
	int num = 1;
	struct stats_list list;
	struct stats_list_entry *e;

	STAILQ_INIT(&list);
	krping_walk_cb_list(krping_copy_stats, &list);

	if (STAILQ_EMPTY(&list))
		return (0);

	uprintf("krping: %4s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n",
	    "num", "device", "snd bytes", "snd msgs", "rcv bytes", "rcv msgs",
	    "wr bytes", "wr msgs", "rd bytes", "rd msgs");

	while (!STAILQ_EMPTY(&list)) {
		e = STAILQ_FIRST(&list);
		STAILQ_REMOVE_HEAD(&list, link);
		if (e->stats == NULL)
			uprintf("krping: %d listen\n", num);
		else {
			struct krping_stats *stats = e->stats;

			uprintf("krping: %4d %10s %10llu %10llu %10llu %10llu "
			    "%10llu %10llu %10llu %10llu\n", num, stats->name,
			    stats->send_bytes, stats->send_msgs,
			    stats->recv_bytes, stats->recv_msgs,
			    stats->write_bytes, stats->write_msgs,
			    stats->read_bytes, stats->read_msgs);
			free(stats, M_DEVBUF);
		}
		num++;
		free(e, M_DEVBUF);
	}

	return (0);
}

static int
krping_write(struct cdev *dev, struct uio *uio, int ioflag)
{
	int err = 0;
	int amt;
	int remain = BUFFERSIZE;
	char *cp;
	krping_t *krpingmsg;

	krpingmsg = malloc(sizeof *krpingmsg, M_DEVBUF, M_WAITOK|M_ZERO);
	if (!krpingmsg) {
		uprintf("Could not malloc mem!\n");
		return ENOMEM;
	}

	cp = krpingmsg->msg;
	while (uio->uio_resid) {
		amt = MIN(uio->uio_resid, remain);
		if (amt == 0)
			break;

		/* Copy the string in from user memory to kernel memory */
		err = uiomove(cp, amt, uio);
		if (err) {
			uprintf("Write failed: bad address!\n");
			return err;
		}
		cp += amt;
		remain -= amt;
	}

	if (uio->uio_resid != 0) {
		uprintf("Message too big. max size is %d!\n", BUFFERSIZE);
		return EMSGSIZE;
	}

	/* null terminate and remove the \n */
	cp--;
	*cp = 0;
	krpingmsg->len = (unsigned long)(cp - krpingmsg->msg);
	uprintf("krping: write string = |%s|\n", krpingmsg->msg);
	err = krping_doit(krpingmsg->msg, curproc);
	free(krpingmsg, M_DEVBUF);
	return(err);
}

int
krping_sigpending(void)
{

	return (SIGPENDING(curthread));
}

DEV_MODULE(krping, krping_loader, NULL);
MODULE_DEPEND(krping, ibcore, 1, 1, 1);
OpenPOWER on IntegriCloud