View | Details | Raw Unified | Return to bug 206186
Collapse All | Expand All

(-)sys/netgraph/ng_checksum.c (+729 lines)
Added Link Here
1
/*-
2
 * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#include <sys/cdefs.h>
29
__FBSDID("$FreeBSD$");
30
31
#include "opt_inet.h"
32
#include "opt_inet6.h"
33
34
#include <sys/param.h>
35
#include <sys/systm.h>
36
#include <sys/kernel.h>
37
#include <sys/endian.h>
38
#include <sys/malloc.h>
39
#include <sys/mbuf.h>
40
#include <sys/socket.h>
41
42
#include <net/bpf.h>
43
#include <net/ethernet.h>
44
#include <net/if.h>
45
#include <net/if_vlan_var.h>
46
47
#include <netinet/in.h>
48
#include <netinet/ip.h>
49
#include <netinet/ip6.h>
50
#include <netinet/tcp.h>
51
#include <netinet/udp.h>
52
#include <machine/in_cksum.h>
53
54
#include <netgraph/ng_message.h>
55
#include <netgraph/ng_parse.h>
56
#include <netgraph/netgraph.h>
57
58
#include <netgraph/ng_checksum.h>
59
60
/* private data */
61
struct ng_checksum_priv {
62
	hook_p in;
63
	hook_p out;
64
	uint8_t dlt;	/* DLT_XXX from bpf.h */
65
	struct ng_checksum_config *conf;
66
	struct ng_checksum_stats stats;
67
};
68
69
typedef struct ng_checksum_priv *priv_p;
70
71
/* Netgraph methods */
72
static ng_constructor_t	ng_checksum_constructor;
73
static ng_rcvmsg_t	ng_checksum_rcvmsg;
74
static ng_shutdown_t	ng_checksum_shutdown;
75
static ng_newhook_t	ng_checksum_newhook;
76
static ng_rcvdata_t	ng_checksum_rcvdata;
77
static ng_disconnect_t	ng_checksum_disconnect;
78
79
#define ERROUT(x) { error = (x); goto done; }
80
81
static const struct ng_parse_struct_field ng_checksum_config_type_fields[]
82
	= NG_CHECKSUM_CONFIG_TYPE;
83
static const struct ng_parse_type ng_checksum_config_type = {
84
	&ng_parse_struct_type,
85
	&ng_checksum_config_type_fields
86
};
87
88
static const struct ng_parse_struct_field ng_checksum_stats_fields[]
89
	= NG_CHECKSUM_STATS_TYPE;
90
static const struct ng_parse_type ng_checksum_stats_type = {
91
	&ng_parse_struct_type,
92
	&ng_checksum_stats_fields
93
};
94
95
static const struct ng_cmdlist ng_checksum_cmdlist[] = {
96
	{
97
		NGM_CHECKSUM_COOKIE,
98
		NGM_CHECKSUM_GETDLT,
99
		"getdlt",
100
		NULL,
101
		&ng_parse_uint8_type
102
	},
103
	{
104
		NGM_CHECKSUM_COOKIE,
105
		NGM_CHECKSUM_SETDLT,
106
		"setdlt",
107
		&ng_parse_uint8_type,
108
		NULL
109
	},
110
	{
111
		NGM_CHECKSUM_COOKIE,
112
		NGM_CHECKSUM_GETCONFIG,
113
		"getconfig",
114
		NULL,
115
		&ng_checksum_config_type
116
	},
117
	{
118
		NGM_CHECKSUM_COOKIE,
119
		NGM_CHECKSUM_SETCONFIG,
120
		"setconfig",
121
		&ng_checksum_config_type,
122
		NULL
123
	},
124
	{
125
		NGM_CHECKSUM_COOKIE,
126
		NGM_CHECKSUM_GET_STATS,
127
		"getstats",
128
		NULL,
129
		&ng_checksum_stats_type
130
	},
131
	{
132
		NGM_CHECKSUM_COOKIE,
133
		NGM_CHECKSUM_CLR_STATS,
134
		"clrstats",
135
		NULL,
136
		NULL
137
	},
138
	{
139
		NGM_CHECKSUM_COOKIE,
140
		NGM_CHECKSUM_GETCLR_STATS,
141
		"getclrstats",
142
		NULL,
143
		&ng_checksum_stats_type
144
	},
145
	{ 0 }
146
};
147
148
static struct ng_type typestruct = {
149
	.version =	NG_ABI_VERSION,
150
	.name =		NG_CHECKSUM_NODE_TYPE,
151
	.constructor =	ng_checksum_constructor,
152
	.rcvmsg =	ng_checksum_rcvmsg,
153
	.shutdown =	ng_checksum_shutdown,
154
	.newhook =	ng_checksum_newhook,
155
	.rcvdata =	ng_checksum_rcvdata,
156
	.disconnect =	ng_checksum_disconnect,
157
	.cmdlist =	ng_checksum_cmdlist,
158
};
159
160
NETGRAPH_INIT(checksum, &typestruct);
161
162
static int
163
ng_checksum_constructor(node_p node)
164
{
165
	priv_p priv;
166
167
	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK|M_ZERO);
168
	priv->dlt = DLT_RAW;
169
170
	NG_NODE_SET_PRIVATE(node, priv);
171
172
	return (0);
173
}
174
175
static int
176
ng_checksum_newhook(node_p node, hook_p hook, const char *name)
177
{
178
	const priv_p priv = NG_NODE_PRIVATE(node);
179
180
	if (strncmp(name, NG_CHECKSUM_HOOK_IN, strlen(NG_CHECKSUM_HOOK_IN)) == 0) {
181
		priv->in = hook;
182
	} else if (strncmp(name, NG_CHECKSUM_HOOK_OUT, strlen(NG_CHECKSUM_HOOK_OUT)) == 0) {
183
		priv->out = hook;
184
	} else
185
		return (EINVAL);
186
187
	return (0);
188
}
189
190
static int
191
ng_checksum_rcvmsg(node_p node, item_p item, hook_p lasthook)
192
{
193
	const priv_p priv = NG_NODE_PRIVATE(node);
194
	struct ng_checksum_config *conf, *newconf;
195
	struct ng_mesg *msg;
196
	struct ng_mesg *resp = NULL;
197
	int error = 0;
198
199
	NGI_GET_MSG(item, msg);
200
201
	if  (msg->header.typecookie != NGM_CHECKSUM_COOKIE)
202
		ERROUT(EINVAL);
203
204
	switch (msg->header.cmd)
205
	{
206
		case NGM_CHECKSUM_GETDLT:
207
			NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
208
209
			if (resp == NULL)
210
				ERROUT(ENOMEM);
211
212
			*((uint8_t *) resp->data) = priv->dlt;
213
214
			break;
215
216
		case NGM_CHECKSUM_SETDLT:
217
			if (msg->header.arglen != sizeof(uint8_t))
218
				ERROUT(EINVAL);
219
220
			switch (*(uint8_t *) msg->data)
221
			{
222
				case DLT_EN10MB:
223
				case DLT_RAW:
224
					priv->dlt = *(uint8_t *) msg->data;
225
					break;
226
227
				default:
228
					ERROUT(EINVAL);
229
			}
230
231
			break;
232
233
		case NGM_CHECKSUM_GETCONFIG:
234
			if (priv->conf == NULL)
235
				ERROUT(0);
236
237
			NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_config), M_WAITOK);
238
239
			if (resp == NULL)
240
				ERROUT(ENOMEM);
241
242
			bcopy(priv->conf, resp->data, sizeof(struct ng_checksum_config));
243
244
			break;
245
246
		case NGM_CHECKSUM_SETCONFIG:
247
			conf = (struct ng_checksum_config *) msg->data;
248
249
			if (msg->header.arglen != sizeof(struct ng_checksum_config))
250
				ERROUT(EINVAL);
251
252
			conf->csum_flags &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
253
			conf->csum_offload &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
254
255
			newconf = malloc(sizeof(struct ng_checksum_config), M_NETGRAPH, M_WAITOK|M_ZERO);
256
257
			bcopy(conf, newconf, sizeof(struct ng_checksum_config));
258
259
			if (priv->conf)
260
				free(priv->conf, M_NETGRAPH);
261
262
			priv->conf = newconf;
263
264
			break;
265
266
		case NGM_CHECKSUM_GET_STATS:
267
		case NGM_CHECKSUM_CLR_STATS:
268
		case NGM_CHECKSUM_GETCLR_STATS:
269
			if (msg->header.cmd != NGM_CHECKSUM_CLR_STATS) {
270
				NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_stats), M_WAITOK);
271
272
				if (resp == NULL)
273
					ERROUT(ENOMEM);
274
275
				bcopy(&(priv->stats), resp->data, sizeof(struct ng_checksum_stats));
276
			}
277
278
			if (msg->header.cmd != NGM_CHECKSUM_GET_STATS)
279
				bzero(&(priv->stats), sizeof(struct ng_checksum_stats));
280
281
			break;
282
283
		default:
284
			ERROUT(EINVAL);
285
	}
286
287
done:
288
	NG_RESPOND_MSG(error, node, item, resp);
289
	NG_FREE_MSG(msg);
290
291
	return (error);
292
}
293
294
#define	PULLUP_CHECK(mbuf, length) do {					\
295
	pullup_len += length;						\
296
	if (((mbuf)->m_pkthdr.len < pullup_len) ||			\
297
	    (pullup_len > MHLEN)) {					\
298
		return (EINVAL);					\
299
	}								\
300
	if ((mbuf)->m_len < pullup_len &&				\
301
	    (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {	\
302
		return (ENOBUFS);					\
303
	}								\
304
} while (0)
305
306
#ifdef INET
307
static int
308
checksum_ipv4(priv_p priv, struct mbuf *m, int l3_offset)
309
{
310
	struct ip *ip4;
311
	int pullup_len;
312
	int hlen, plen;
313
	int processed = 0;
314
315
	pullup_len = l3_offset;
316
317
	PULLUP_CHECK(m, sizeof(struct ip));
318
	ip4 = (struct ip *) mtodo(m, l3_offset);
319
320
	if (ip4->ip_v != IPVERSION)
321
		return (EOPNOTSUPP);
322
323
	hlen = ip4->ip_hl << 2;
324
	plen = ntohs(ip4->ip_len);
325
326
	if (hlen < sizeof(struct ip) || m->m_pkthdr.len < l3_offset + plen)
327
		return (EINVAL);
328
329
	if (m->m_pkthdr.csum_flags & CSUM_IP) {
330
		ip4->ip_sum = 0;
331
332
		if ((priv->conf->csum_offload & CSUM_IP) == 0) {
333
			if (hlen == sizeof(struct ip))
334
				ip4->ip_sum = in_cksum_hdr(ip4);
335
			else
336
				ip4->ip_sum = in_cksum_skip(m, l3_offset + hlen, l3_offset);
337
338
			m->m_pkthdr.csum_flags &= ~CSUM_IP;
339
		}
340
341
		processed = 1;
342
	}
343
344
	pullup_len = l3_offset + hlen;
345
346
	/* We can not calculate a checksum fragmented packets */
347
	if (ip4->ip_off & htons(IP_MF|IP_OFFMASK)) {
348
		m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
349
		return (0);
350
	}
351
352
	switch (ip4->ip_p)
353
	{
354
		case IPPROTO_TCP:
355
			if (m->m_pkthdr.csum_flags & CSUM_TCP) {
356
				struct tcphdr *th;
357
358
				PULLUP_CHECK(m, sizeof(struct tcphdr));
359
				th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
360
361
				th->th_sum = in_pseudo(ip4->ip_src.s_addr,
362
				    ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
363
364
				if ((priv->conf->csum_offload & CSUM_TCP) == 0) {
365
					th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
366
					m->m_pkthdr.csum_flags &= ~CSUM_TCP;
367
				}
368
369
				processed = 1;
370
			}
371
372
			m->m_pkthdr.csum_flags &= ~CSUM_UDP;
373
			break;
374
375
		case IPPROTO_UDP:
376
			if (m->m_pkthdr.csum_flags & CSUM_UDP) {
377
				struct udphdr *uh;
378
379
				PULLUP_CHECK(m, sizeof(struct udphdr));
380
				uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
381
382
				uh->uh_sum = in_pseudo(ip4->ip_src.s_addr,
383
				    ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
384
385
				if ((priv->conf->csum_offload & CSUM_UDP) == 0) {
386
					uh->uh_sum = in_cksum_skip(m,
387
					    l3_offset + plen, l3_offset + hlen);
388
389
					if (uh->uh_sum == 0)
390
						uh->uh_sum = 0xffff;
391
392
					m->m_pkthdr.csum_flags &= ~CSUM_UDP;
393
				}
394
395
				processed = 1;
396
			}
397
398
			m->m_pkthdr.csum_flags &= ~CSUM_TCP;
399
			break;
400
401
		default:
402
			m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
403
			break;
404
	}
405
406
	m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV6;
407
408
	if (processed)
409
		priv->stats.processed++;
410
411
	return (0);
412
}
413
#endif /* INET */
414
415
#ifdef INET6
416
static int
417
checksum_ipv6(priv_p priv, struct mbuf *m, int l3_offset)
418
{
419
	struct ip6_hdr *ip6;
420
	struct ip6_ext *ip6e = NULL;
421
	int pullup_len;
422
	int hlen, plen;
423
	int nxt;
424
	int processed = 0;
425
426
	pullup_len = l3_offset;
427
428
	PULLUP_CHECK(m, sizeof(struct ip6_hdr));
429
	ip6 = (struct ip6_hdr *) mtodo(m, l3_offset);
430
431
	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
432
		return (EOPNOTSUPP);
433
434
	hlen = sizeof(struct ip6_hdr);
435
	plen = ntohs(ip6->ip6_plen) + hlen;
436
437
	if (m->m_pkthdr.len < l3_offset + plen)
438
		return (EINVAL);
439
440
	nxt = ip6->ip6_nxt;
441
442
	for (;;) {
443
		switch (nxt)
444
		{
445
			case IPPROTO_DSTOPTS:
446
			case IPPROTO_HOPOPTS:
447
			case IPPROTO_ROUTING:
448
				PULLUP_CHECK(m, sizeof(struct ip6_ext));
449
				ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
450
				nxt = ip6e->ip6e_nxt;
451
				hlen += (ip6e->ip6e_len + 1) << 3;
452
				pullup_len = l3_offset + hlen;
453
				break;
454
455
			case IPPROTO_AH:
456
				PULLUP_CHECK(m, sizeof(struct ip6_ext));
457
				ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
458
				nxt = ip6e->ip6e_nxt;
459
				hlen += (ip6e->ip6e_len + 2) << 2;
460
				pullup_len = l3_offset + hlen;
461
				break;
462
463
			case IPPROTO_FRAGMENT:
464
				/* We can not calculate a checksum fragmented packets */
465
				m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
466
				return (0);
467
468
			default:
469
				goto loopend;
470
		}
471
472
		if (nxt == 0)
473
			return (EINVAL);
474
	}
475
476
loopend:
477
478
	switch (nxt)
479
	{
480
		case IPPROTO_TCP:
481
			if (m->m_pkthdr.csum_flags & CSUM_TCP_IPV6) {
482
				struct tcphdr *th;
483
484
				PULLUP_CHECK(m, sizeof(struct tcphdr));
485
				th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
486
487
				th->th_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
488
489
				if ((priv->conf->csum_offload & CSUM_TCP_IPV6) == 0) {
490
					th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
491
					m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
492
				}
493
494
				processed = 1;
495
			}
496
497
			m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
498
			break;
499
500
		case IPPROTO_UDP:
501
			if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6) {
502
				struct udphdr *uh;
503
504
				PULLUP_CHECK(m, sizeof(struct udphdr));
505
				uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
506
507
				uh->uh_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
508
509
				if ((priv->conf->csum_offload & CSUM_UDP_IPV6) == 0) {
510
					uh->uh_sum = in_cksum_skip(m,
511
					    l3_offset + plen, l3_offset + hlen);
512
513
					if (uh->uh_sum == 0)
514
						uh->uh_sum = 0xffff;
515
516
					m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
517
				}
518
519
				processed = 1;
520
			}
521
522
			m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
523
			break;
524
525
		default:
526
			m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
527
			break;
528
	}
529
530
	m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV4;
531
532
	if (processed)
533
		priv->stats.processed++;
534
535
	return (0);
536
}
537
#endif /* INET6 */
538
539
#undef	PULLUP_CHECK
540
541
static int
542
ng_checksum_rcvdata(hook_p hook, item_p item)
543
{
544
	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
545
	struct mbuf *m;
546
	hook_p out;
547
	int error = 0;
548
549
	priv->stats.received++;
550
551
	NGI_GET_M(item, m);
552
553
#define	PULLUP_CHECK(mbuf, length) do {					\
554
	pullup_len += length;						\
555
	if (((mbuf)->m_pkthdr.len < pullup_len) ||			\
556
	    (pullup_len > MHLEN)) {					\
557
		error = EINVAL;						\
558
		goto bypass;						\
559
	}								\
560
	if ((mbuf)->m_len < pullup_len &&				\
561
	    (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {	\
562
		error = ENOBUFS;					\
563
		goto drop;						\
564
	}								\
565
} while (0)
566
567
	if (!(priv->conf && hook == priv->in && m && (m->m_flags & M_PKTHDR)))
568
		goto bypass;
569
570
	m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
571
572
	if (m->m_pkthdr.csum_flags & (NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6))
573
	{
574
		struct ether_header *eh;
575
		struct ng_checksum_vlan_header *vh;
576
		int pullup_len = 0;
577
		uint16_t etype;
578
579
		m = m_unshare(m, M_NOWAIT);
580
581
		if (m == NULL)
582
			ERROUT(ENOMEM);
583
584
		switch (priv->dlt)
585
		{
586
			case DLT_EN10MB:
587
				PULLUP_CHECK(m, sizeof(struct ether_header));
588
				eh = mtod(m, struct ether_header *);
589
				etype = ntohs(eh->ether_type);
590
591
				for (;;) {	/* QinQ support */
592
					switch (etype)
593
					{
594
						case 0x8100:
595
						case 0x88A8:
596
						case 0x9100:
597
							PULLUP_CHECK(m, sizeof(struct ng_checksum_vlan_header));
598
							vh = (struct ng_checksum_vlan_header *) mtodo(m,
599
							    pullup_len - sizeof(struct ng_checksum_vlan_header));
600
							etype = ntohs(vh->etype);
601
							break;
602
603
						default:
604
							goto loopend;
605
					}
606
				}
607
loopend:
608
#ifdef INET
609
				if (etype == ETHERTYPE_IP &&
610
				    (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)) {
611
					error = checksum_ipv4(priv, m, pullup_len);
612
					if (error == ENOBUFS)
613
						goto drop;
614
				} else
615
#endif
616
#ifdef INET6
617
				if (etype == ETHERTYPE_IPV6 &&
618
				    (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)) {
619
					error = checksum_ipv6(priv, m, pullup_len);
620
					if (error == ENOBUFS)
621
						goto drop;
622
				} else
623
#endif
624
				{
625
					m->m_pkthdr.csum_flags &=
626
					    ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
627
				}
628
629
				break;
630
631
			case DLT_RAW:
632
#ifdef INET
633
				if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)
634
				{
635
					error = checksum_ipv4(priv, m, pullup_len);
636
637
					if (error == 0)
638
						goto bypass;
639
					else if (error == ENOBUFS)
640
						goto drop;
641
				}
642
#endif
643
#ifdef INET6
644
				if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)
645
				{
646
					error = checksum_ipv6(priv, m, pullup_len);
647
648
					if (error == 0)
649
						goto bypass;
650
					else if (error == ENOBUFS)
651
						goto drop;
652
				}
653
#endif
654
				if (error)
655
					m->m_pkthdr.csum_flags &=
656
					    ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
657
658
				break;
659
660
			default:
661
				ERROUT(EINVAL);
662
		}
663
	}
664
665
#undef	PULLUP_CHECK
666
667
bypass:
668
	out = NULL;
669
670
	if (hook == priv->in) {
671
		/* return frames on 'in' hook if 'out' not connected */
672
		out = priv->out ? priv->out : priv->in;
673
	} else if (hook == priv->out && priv->in) {
674
		/* pass frames on 'out' hook if 'in' connected */
675
		out = priv->in;
676
	}
677
678
	if (out == NULL)
679
		ERROUT(0);
680
681
	NG_FWD_NEW_DATA(error, item, out, m);
682
683
	return (error);
684
685
done:
686
drop:
687
	NG_FREE_ITEM(item);
688
	NG_FREE_M(m);
689
690
	priv->stats.dropped++;
691
692
	return (error);
693
}
694
695
static int
696
ng_checksum_shutdown(node_p node)
697
{
698
	const priv_p priv = NG_NODE_PRIVATE(node);
699
700
	NG_NODE_SET_PRIVATE(node, NULL);
701
	NG_NODE_UNREF(node);
702
703
	if (priv->conf)
704
		free(priv->conf, M_NETGRAPH);
705
706
	free(priv, M_NETGRAPH);
707
708
	return (0);
709
}
710
711
static int
712
ng_checksum_disconnect(hook_p hook)
713
{
714
	priv_p priv;
715
716
	priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
717
718
	if (hook == priv->in)
719
		priv->in = NULL;
720
721
	if (hook == priv->out)
722
		priv->out = NULL;
723
724
	if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
725
	    NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
726
		ng_rmnode_self(NG_HOOK_NODE(hook));
727
728
	return (0);
729
}
(-)sys/netgraph/ng_checksum.h (+88 lines)
Added Link Here
1
/*-
2
 * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 * $FreeBSD$
27
 */
28
29
#ifndef _NETGRAPH_NG_CHECKSUM_H_
30
#define _NETGRAPH_NG_CHECKSUM_H_
31
32
/* Node type name. */
33
#define	NG_CHECKSUM_NODE_TYPE	"checksum"
34
35
/* Node type cookie. */
36
#define	NGM_CHECKSUM_COOKIE	439419912
37
38
/* Hook names */
39
#define	NG_CHECKSUM_HOOK_IN	"in"
40
#define	NG_CHECKSUM_HOOK_OUT	"out"
41
42
/* Checksum flags */
43
#define NG_CHECKSUM_CSUM_IPV4	(CSUM_IP|CSUM_TCP|CSUM_UDP)
44
#define NG_CHECKSUM_CSUM_IPV6	(CSUM_TCP_IPV6|CSUM_UDP_IPV6)
45
46
/* Netgraph commands understood by this node type */
47
enum {
48
	NGM_CHECKSUM_GETDLT = 1,
49
	NGM_CHECKSUM_SETDLT,
50
	NGM_CHECKSUM_GETCONFIG,
51
	NGM_CHECKSUM_SETCONFIG,
52
	NGM_CHECKSUM_GETCLR_STATS,
53
	NGM_CHECKSUM_GET_STATS,
54
	NGM_CHECKSUM_CLR_STATS,
55
};
56
57
/* Parsing declarations */
58
59
#define	NG_CHECKSUM_CONFIG_TYPE {				\
60
	{ "csum_flags",		&ng_parse_uint64_type	},	\
61
	{ "csum_offload",	&ng_parse_uint64_type	},	\
62
	{ NULL }						\
63
}
64
65
#define	NG_CHECKSUM_STATS_TYPE {				\
66
	{ "Received",		&ng_parse_uint64_type	},	\
67
	{ "Processed",		&ng_parse_uint64_type	},	\
68
	{ "Dropped",		&ng_parse_uint64_type	},	\
69
	{ NULL }					\
70
}
71
72
struct ng_checksum_config {
73
	uint64_t	csum_flags;
74
	uint64_t	csum_offload;
75
};
76
77
struct ng_checksum_stats {
78
	uint64_t	received;
79
	uint64_t	processed;
80
	uint64_t	dropped;
81
};
82
83
struct ng_checksum_vlan_header {
84
	u_int16_t tag;
85
	u_int16_t etype;
86
};
87
88
#endif /* _NETGRAPH_NG_CHECKSUM_H_ */
(-)sys/modules/netgraph/checksum/Makefile (+20 lines)
Added Link Here
1
# $FreeBSD$
2
3
.include <bsd.own.mk>
4
5
KMOD=	ng_checksum
6
SRCS= 	ng_checksum.c opt_inet.h opt_inet6.h
7
8
.if !defined(KERNBUILDDIR)
9
10
.if ${MK_INET_SUPPORT} != "no"
11
opt_inet.h:
12
	echo "#define INET 1" > ${.TARGET}
13
.endif
14
.if ${MK_INET6_SUPPORT} != "no"
15
opt_inet6.h:
16
	echo "#define INET6 1" > ${.TARGET}
17
.endif
18
.endif
19
20
.include <bsd.kmod.mk>

Return to bug 206186