Skip to contentSkip to conversation

net: UDP-Lite generic support

PATCH In review Gerrit Renker 4 participants 19 messages Jul 14, 2006 – Oct 13, 2006

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/3 net: UDP-Lite generic support

Generic support (header files, configuration, and documentation) for the UDP-Lite protocol (RFC 3828).

This has been tested successfully on AMD, i386/i686, and SMP architectures (compiles cleanly and works under different configurations).

With regard to the previously submitted patch set, no conceptual changes (it works), but a lot of tidying up and re-organisation:

* the number of changes to other files has been reduced to the bare minimum (would greatly value ideas for further reduction),
* ifdefs have been replaced by generic functions (whose implementation depends on CONFIG_IP_UDPLITE),
* much of the declarations and concepts shared between v4 and v6 UDP- Lite is now concentrated in the header file

I hope that this makes the code a lot more accessible. Both ipv4/udplite.c and ipv6/udplite.c derive from the respective udp.c variants.

There is documentation enclosed, as well as a few (v6-enabled) applications to test the kernel implementation. These should be easy to built - please give it a test run if you have a little time.

Previous comments have been a great help in improving the code: I would greatly value any further ideas, suggestions, and comments -- in particular ACKS & NAKS or application.

---

Documentation/networking/udplite.txt | 334 +++++++++++++++++++++++++++++++++++

 include/linux/in.h                   |    1
 include/linux/socket.h               |    1
 include/linux/udplite.h              |   96 ++++++++++
 include/net/udplite.h                |  196 ++++++++++++++++++++
 net/core/sock.c                      |    7
 net/ipv4/Kconfig                     |   21 ++
 7 files changed, 655 insertions(+), 1 deletion(-)
net/ipv4/Kconfig +21 -0
diff -Nurp  a/net/ipv4/Kconfig b/net/ipv4/Kconfig
@@ -581,3 +581,24 @@ config TCP_CONG_BIC
 
 source "net/ipv4/ipvs/Kconfig"
 
+config IP_UDPLITE
+	bool "The UDP-Lite Protocol (EXPERIMENTAL)"
+	depends on INET && EXPERIMENTAL
+        default n
+	---help---
+	  The UDP-Lite Protocol            <http://www.ietf.org/rfc/rfc3828.txt>
+
+	  UDP-Lite is  a Standards-Track IETF  transport protocol (RFC 3828). It
+	  features  a  variable-length checksum;  which allows partially damaged
+	  packets  to  be forwarded to media codecs, rather than being discarded
+	  due to invalid (UDP) checksum values. This can have advantages for the
+	  transport of multimedia (e.g. video/audio) over wireless networks.
+
+	  The protocol runs on both IPv4 and IPv6. The socket API resembles that
+	  of UDP. Applications must indicate their wish to utilise the partial
+	  checksum coverage feature by setting a socket option; UDP-Lite will
+	  otherwise run in (compatible) UDP mode.
+
+	  Detailed documentation in <file:Documentation/networking/udplite.txt>.
+
+	  If in doubt, say N.
include/linux/udplite.h +96 -0

96 lines not on this page · raw message

include/net/udplite.h +196 -0

196 lines not on this page · raw message

include/linux/socket.h +1 -0
diff -Nurp  a/include/linux/socket.h b/include/linux/socket.h
@@ -264,6 +264,7 @@ struct ucred {
 #define SOL_IPV6	41
 #define SOL_ICMPV6	58
 #define SOL_SCTP	132
+#define SOL_UDPLITE	136     /* UDP-Lite (RFC 3828) */
 #define SOL_RAW		255
 #define SOL_IPX		256
 #define SOL_AX25	257
include/linux/in.h +1 -0
diff -Nurp  a/include/linux/in.h b/include/linux/in.h
@@ -44,6 +44,7 @@ enum {
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+  IPPROTO_UDPLITE = 136,	/* UDP-Lite Protocol (RFC 3828)	        */
 
   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
net/core/sock.c +6 -1
diff -Nurp  a/net/core/sock.c b/net/core/sock.c
@@ -479,7 +479,12 @@ set_rcvbuf:
 			break;
 
 	 	case SO_NO_CHECK:
-			sk->sk_no_check = valbool;
+			/* UDP-Lite (RFC 3828) mandates checksumming,
+			 * hence user must not enable this option.   */
+			if (sk->sk_protocol == IPPROTO_UDPLITE)
+				ret = -EOPNOTSUPP;
+			else
+ 			    sk->sk_no_check = valbool;
 			break;
 
 		case SO_PRIORITY:
Documentation/networking/udplite.txt +334 -0

334 lines not on this page · raw message

maintainer
#1 lore raw
Quoted 5 lines · Gerrit Renker

diff -Nurp a/net/core/sock.c b/net/core/sock.c

net/core/sock.c 2006-07-14 10:17:50.000000000 +0100 set_rcvbuf: · line 487

Quoted 10 lines
net/core/sock.c 2006-07-14 10:17:50.000000000 +0100 renamed from net/core/sock.c 2006-07-06 09:08:24.000000000 +0100 +6 -1
@@ -479,7 +479,12 @@ set_rcvbuf:
                       break;
 
               case SO_NO_CHECK:
-                       sk->sk_no_check = valbool;
+                       /* UDP-Lite (RFC 3828) mandates checksumming,
+                        * hence user must not enable this option.   */
+                       if (sk->sk_protocol == IPPROTO_UDPLITE)
+                               ret = -EOPNOTSUPP;
+                       else
+                           sk->sk_no_check = valbool;

Please don't add protocol-specific stuff to generic functions. In this case why don't you just ignore sk_no_check for UDPLITE as we do for TCP?

Cheers,

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#2 lore raw

Quoting Herbert Xu:

|  >                case SO_NO_CHECK:
|  > -                       sk->sk_no_check = valbool;
|  > +                       /* UDP-Lite (RFC 3828) mandates checksumming,
|  > +                        * hence user must not enable this option.   */
|  > +                       if (sk->sk_protocol == IPPROTO_UDPLITE)
|  > +                               ret = -EOPNOTSUPP;
|  > +                       else
|  > +                           sk->sk_no_check = valbool;
|  
|  Please don't add protocol-specific stuff to generic functions.  In this
|  case why don't you just ignore sk_no_check for UDPLITE as we do for TCP?

Thank you for spotting this -- the UDP-Lite code indeed ignores sk_no_check and will (if no socket options are set) emulate UDP with sk_no_check = 0. Setting it to 1 will make no difference; so the above is more not strictly necessary. Will remove in next patch.
Any other comments or ideas, please do not hesitate to write.

-- Gerrit

maintainer
#3 lore raw
In reply to Gerrit Renker

From: Gerrit Renker <[email protected]>
Date: Fri, 14 Jul 2006 17:19:02 +0100

Quoted 2 lines

Generic support (header files, configuration, and documentation) for the UDP-Lite protocol (RFC 3828).

Gerrit, I tried to bring myself over the edge to accept this work and push it into my net-2.6.19 tree, but I simply can't The amount of code duplication is absolutely enormous and totally unnecessary.

With proper abstractions, you can easily add UDP-lite support to the existing UDP code. And I would really like it to be in that format before we put it into the tree.

Then all you need to do is something like add:

	__u16             pcslen;
	__u16             pcrlen;
/* checksum coverage set indicators used by pcflag */
#define UDPLITE_SEND_CC   0x1
#define UDPLITE_RECV_CC   0x2
	__u8              pcflag;

to struct udp_sock.

Add the seperate udp_port_rover and udlite_hash[] table to udp.c, make the latter sized by UDP_HTABLE_SIZE, with suitable exports, and share the udp_hash_lock for mutual exclusion. Finally, parameterize all the UDP hash table routines to take a hash table base and a port rover pointer so that they can operate on both UDP and UDP-Lite sockets transparently.

Next make 2 top-level routines for things like udp_err() etc. So that you can go:

/* Common code */
static void __udp_err(struct sock *sk, struct sk_buff *skb, int type, int code, u32 info)

{
	struct inet_sock *inet;
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	int harderr, err;

	if (sk == NULL) {
		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
    	  	return;	/* No socket for error */
	}

	err = 0;
	harderr = 0;
	inet = inet_sk(sk);

	switch (type) {
 ...
	}

	/*
	 *      RFC1122: OK.  Passes ICMP errors back to application, as per 
	 *	4.1.3.3.
	 */
	if (!inet->recverr) {
		if (!harderr || sk->sk_state != TCP_ESTABLISHED)
			goto out;
	} else {
		ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
	}
	sk->sk_err = err;
	sk->sk_error_report(sk);
out:
	sock_put(sk);
}

void udp_err(struct sk_buff *skb, u32 info)

{
	struct iphdr *iph = (struct iphdr*)skb->data;
	struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	struct sock *sk;

	sk = udp_v4_lookup(udp_hash,
			   iph->daddr, uh->dest, iph->saddr,
			   uh->source, skb->dev->ifindex);
	__udp_err(sk, skb, type, code, info);
}

void udplite_err(struct sk_buff *skb, u32 info)

{
	struct iphdr *iph = (struct iphdr*)skb->data;
	struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	struct sock *sk;

	sk = udp_v4_lookup(udplite_hash,
			   iph->daddr, uh->dest, iph->saddr,
			   uh->source, skb->dev->ifindex);
	__udp_err(sk, skb, type, code, info);
}

Make similar abstractions for the send and recive path processing, substituting in the specific UDP vs. UDP-Lite header and checksum semantic handling along the way.

It's mostly clerical work, but it will mean that we will have one copy of all this code and as a result we won't even need a config option for UDP-Lite.

Thanks.

#4 lore raw

Hi David,

thank you very much for taking time to revise the code and for the detailed comments.

|  The amount of code duplication is absolutely enormous and
|  totally unnecessary.

You are right.
So far I thought it better to keep UDP and UDP-Lite separate but an intelligent code integration does seem the better way.

<snip>

|  It's mostly clerical work, but it will mean that we will have one
|  copy of all this code and as a result we won't even need a config
|  option for UDP-Lite.

I will start with the v4-side and post a small RFC patch to see whether I got the concepts right. (Due to vacation, this will not before mid/end of August.)

Best regards
Gerrit

maintainer
#5 lore raw

From: Gerrit Renker <[email protected]>
Date: Fri, 28 Jul 2006 09:19:55 +0100

Quoted 3 lines

I will start with the v4-side and post a small RFC patch to see whether I got the concepts right. (Due to vacation, this will not before mid/end of August.)

Ok, I look forward to reviewing it.

#6 lore raw

RFC PATCH v3 1/4 net/ipv4: consolidated UDP / UDP-Lite code

In reply to David Miller

Hi David,

please find enclosed for review the proposed changes to integrate UDP-Lite code with UDP.

Please disregard all earlier patches, I have been putting in more hard work to consolidate the code further, also with regard to expanding to UDP(-Lite) v6. (Reductions are drastic: udplite.c is slimmed down to 186 lines.)

This is the v4-side and with a minimum of formatting diffs. Any suggestions for v4 will automatically be incorporated into the v6 side in the subsequent revision.

Enclosed patch applies on your 2.6.19 tree and on 2.6.18-rc6-mm2 and has been tested (UDPv4/v6 as well) for quite a while.

R e s o l v e d I s s u e s

a) Common Naming scheme:

--stuff that works for both UDPv4/6 and UDP-Litev4/6 is called udp_lib_xxx()
* restricted to v4: udp4_lib_xxx()
* restricted to v6: udp6_lib_xxx()
* when it should not be called directly: __udp_lib_xxx() [resp.__udp{4,6}_lib_xxx()]

--some old functions (e.g. udp_v4_mcast_next()) have retained their name
although they would need to be renamed (here udp4_lib_mcast_next()); this is left for later -- a `name-change-only' patch

b) Correct MIB-counting of de facto received datagrams (resolving
http://bugzilla.kernel.org/show_bug.cgi?id=6660 for this module; some follow-up
work may have to look at doing the same for sunrpc, nfs, and likewise)

c) udp_v{4,6}_get_port(): consolidated.

C h a n g e l o g

* inline functions which are shared between UDP and UDP-Lite and v4/v6 have been put into header files rather than duplicated in source files
* made net/ipv4/udplite.c self-contained unit (#included at the end of udp.c)
* consolidated v4/v6 checksumming code (generic now for UDP and UDP-Lite)
--new: udp_csum_outgoing()
--contrasts with udplite_csum_outgoing()
--removed support for disabling UDPv6 checksums (RFC 2460 says it's illegal)
* udp_v{4,6}_hash() and udp_v{4,6}_unhash() identical: inlined into header file
* basic xfrm/netfilter support (thanks to Patrick McHardy)
* updated the protocol registration in udplite4_register to not do /proc registration on error (thanks to comments by James Morris)
* detailed per-function breakdown as per earlier mail

Regards,
Gerrit
--

 include/linux/udp.h |   11 +
 include/net/udp.h   |   89 +++++++++
 net/ipv4/udp.c      |  485 ++++++++++++++++++++++++++++++++--------------------
 net/ipv6/udp.c      |   50 -----
 4 files changed, 406 insertions(+), 229 deletions(-)
include/linux/udp.h +11 -0
index 90223f0..1b7cf10 100644
@@ -50,12 +50,23 @@ struct udp_sock {
 	 * when the socket is uncorked.
 	 */
 	__u16		 len;		/* total length of pending frames */
+	/*
+	 * Fields specific to UDP-Lite.
+	 */
+	__u16		 pcslen;
+	__u16		 pcrlen;
+/* indicator bits used by pcflag: */
+#define UDPLITE_BIT      0x1  		/* set by udplite proto init function */
+#define UDPLITE_SEND_CC  0x2  		/* set via udplite setsockopt         */
+#define UDPLITE_RECV_CC  0x4		/* set via udplite setsocktopt        */
+	__u8		 pcflag;        /* marks socket as UDP-Lite if > 0    */
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
 {
 	return (struct udp_sock *)sk;
 }
+#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag)
 
 #endif
 
include/net/udp.h +86 -3

122 lines not on this page · raw message

net/ipv4/udp.c +302 -183

879 lines not on this page · raw message

net/ipv6/udp.c +7 -43

83 lines not on this page · raw message

#7 lore raw

RFC 1/1 net: consolidated UDP / UDP-Lite code

Hi David,

this is a maintenance update of the UDP-Lite code. It tracks recent changes to udp.c which make it difficult to apply earlier versions of the patch. For consistency, the code has now also been aligned to use __be32/16.

The patch addresses the suggestions made earlier by the following people on this list:
Patrick McHardy, Herbert Xu, James Morris, Arnaldo de Melo, Yoshifuji Hideaki, and David S. Miller.

Being small, I send it in one piece (but could dice it up); the code comprises:
* self-contained UDP-Lite extension (udplite.c and include/net/udplite.h)
* consolidated checksumming for UDPv4/6 and UDP-Litev4/6 --UDPv{4,6} checksumming therefore simpler
--enforces the mandatory UDPv6 checksums (RFC 2460, sec. 8.1)
* fixes the bug stated on http://bugzilla.kernel.org/show_bug.cgi?id=6660
( i.e. correct counting of delivered/erratic datagrams )
* concentrates some shared code which previously re-appeared in different files
* basic xfrm/netfilter support

I have left the v6-side sitting in the drawer. But it is easy to add, since it mirrors the structure of the v4-side - and asking whether this structure is ok with regard to the existing code is the whole point of this patch.

- Gerrit

--

 Documentation/networking/udplite.txt |  291 ++++++++++++++++++++
 include/linux/in.h                   |    1
 include/linux/socket.h               |    1
 include/linux/udp.h                  |   11
 include/net/snmp.h                   |    2
 include/net/udp.h                    |   95 ++++++
 include/net/udplite.h                |   86 ++++++
 include/net/xfrm.h                   |    2
 net/ipv4/af_inet.c                   |    9
 net/ipv4/netfilter/ipt_LOG.c         |   11
 net/ipv4/proc.c                      |   12
 net/ipv4/udp.c                       |  487 +++++++++++++++++++++--------------
 net/ipv4/udplite.c                   |  186 +++++++++++++
 net/ipv4/xfrm4_policy.c              |    1
 net/ipv6/netfilter/ip6t_LOG.c        |   10
 net/ipv6/udp.c                       |   60 ----
 net/ipv6/xfrm6_policy.c              |    1
 net/netfilter/xt_multiport.c         |    5
 net/netfilter/xt_tcpudp.c            |   20 +
 19 files changed, 1040 insertions(+), 251 deletions(-)
Documentation/networking/udplite.txt new file +291 -0
new file mode 100644
index 0000000..a899fa1
@@ -0,0 +1,291 @@
+  ===========================================================================
+                      The UDP-Lite protocol (RFC 3828)
+  ===========================================================================
+  last modified: 	Mon 18th September 2006
+
+
+  UDP-Lite is a Standards-Track IETF transport protocol whose characteristic
+  is a variable-length checksum. This has advantages for transport of multimedia
+  (video, VoIP) over wireless networks, as partly damaged packets can still be
+  fed into the codec instead of being discarded due to a failed checksum test.
+
+  This file briefly describes the existing kernel support and the socket API.
+  For in-depth information, you can consult:
+
+   o The UDP-Lite Homepage: http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/
+       Fom here you can always also download the latest patch for the stable
+       kernel tree and some example application source code.
+
+   o The UDP-Lite HOWTO on
+       http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/UDP-Lite-HOWTO.txt
+
+   o The Wireshark UDP-Lite WiKi (with capture files):
+       http://wiki.wireshark.org/Lightweight_User_Datagram_Protocol
+
+   o The Protocol Spec, RFC 3828, on  http://www.ietf.org/rfc/rfc3828.txt
+
+
+  I) APPLICATIONS
+
+  Several applications have been ported successfully to UDP-Lite. Ethereal
+  (now called wireshark) has UDP-Litev4/v6 support by default. The tarball on
+
+   http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/udplite_linux.tar.gz
+
+  has source code for several v4/v6 client-server and network testing examples.
+
+  Porting applications to UDP-Lite is straightforward: only socket level and
+  IPPROTO need to be changed; senders additionally set the checksum coverage
+  length (default = header length = 8). Details are in the next section.
+  UDP-Lite is not enabled per default: set CONFIG_IP_UDPLITE=y to support it.
+
+
+  II) PROGRAMMING API
+
+  UDP-Lite provides a connectionless, unreliable datagram service and hence
+  uses the same socket type as UDP. In fact, porting from UDP to UDP-Lite is
+  dead easy: simply add `IPPROTO_UDPLITE' as the last argument of the socket(2)
+  call so that the statement looks like:
+
+      s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);
+
+                      or, respectively,
+
+      s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE);
+
+  Since both UDP-Litev4 and UDP-Litev6 are supported, the porting process is the
+  same in both occasions. With just this change you are able to run UDP-Lite
+  services or connect to UDP-Lite servers. The kernel will assume that you are
+  not interested in using partial checksum coverage and so emulate UDP mode.
+
+  To make use of the partial checksum coverage facilities requires setting just
+  one socket option which takes an integer specifying the coverage length:
+
+    * Sender checksum coverage: UDPLITE_SEND_CSCOV
+
+      For example,
+
+        int val = 20;
+        setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int));
+
+      sets the checksum coverage length to 20 bytes (12b data + 8b header).
+      Of each packet only the first 20 bytes (plus the pseudo-header) will be
+      checksummed. This is useful for RTP applications which have a 12-byte
+      base header.
+
+
+    * Receiver checksum coverage: UDPLITE_RECV_CSCOV
+
+      This option is the receiver-side analogue. It is truly optional, i.e. not
+      required to enable traffic with partial checksum coverage. Its function is
+      that of a traffic filter: when enabled, it instructs the kernel to drop
+      all packets which have a coverage _less_ than this value. For example, if
+      RTP and UDP headers are to be protected, a receiver can enforce that only
+      packets with a minimum coverage of 20 are admitted:
+
+        int min = 20;
+        setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int));
+
+  The calls to getsockopt(2) are analogous. Being an extension and not a stand-
+  alone protocol, all socket options known from UDP can be used in exactly the
+  same manner as before, e.g. UDP_CORK or UDP_ENCAP.
+
+  A detailed discussion of UDP-Lite checksum coverage options is in section IV.
+
+
+
+  III) HEADER FILES
+
+  The socket API requires support through header files in /usr/include:
+
+    * /usr/include/netinet/in.h
+        to define IPPROTO_UDPLITE
+
+    * /usr/include/netinet/udplite.h
+        for UDP-Lite header fields and protocol constants
+
+  For testing purposes, the following can serve as a `mini' header file:
+
+    #define IPPROTO_UDPLITE       136
+    #define SOL_UDPLITE           136
+    #define UDPLITE_SEND_CSCOV     10
+    #define UDPLITE_RECV_CSCOV     11
+
+  Ready-made header files for various distros are in the UDP-Lite tarball.
+
+
+
+  IV) KERNEL BEHAVIOUR WITH REGARD TO THE VARIOUS SOCKET OPTIONS
+
+  To enable debugging messages, the log level must be set to 8, as most
+  messages use the KERN_DEBUG level (7).
+
+
+  1) Sender Socket Options
+
+  If the sender specifies a value of 0 as coverage length, the module
+  assumes full coverage, transmits a packet with coverage length of 0
+  and according checksum.  If the sender specifies a coverage < 8 and
+  different from 0, the kernel assumes 8 as default value.  Finally,
+  if the specified coverage length exceeds the packet length, the packet
+  length is used instead as coverage length.
+
+
+  2) Receiver Socket Options
+
+  The receiver specifies the minimum value of the coverage length it
+  is willing to accept.  A value of 0 here indicates that the receiver
+  always wants the whole of the packet covered. In this case, all
+  partially covered packets are dropped and an error is logged.
+
+  It is not possible to specify illegal values (<0 and <8); in these
+  cases the default of 8 is assumed.
+
+  All packets arriving with a coverage value less than the specified
+  threshold are discarded, these events are also logged.
+
+
+  3) Disabling the Checksum Computation
+
+  On both sender and receiver, checksumming will always be performed
+  and can not be disabled using SO_NO_CHECK. Thus
+
+        setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK,  ... );
+
+  will always will be ignored, while the value of
+
+        getsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, &value, ...);
+
+  is meaningless (as in TCP). Packets with a zero checksum field are
+  illegal (cf. RFC 3828, sec. 3.1) will be silently discarded.
+
+
+  4) Fragmentation
+
+  The checksum computation respects both buffersize and MTU. The size
+  of UDP-Lite packets is determined by the size of the send buffer. The
+  minimum size of the send buffer is 2048 (defined as SOCK_MIN_SNDBUF
+  in include/net/sock.h), the default value is configurable as
+  net.core.wmem_default or via setting the SO_SNDBUF socket(7)
+  option. The maximum upper bound for the send buffer is determined
+  by net.core.wmem_max.
+
+  Given a payload size larger than the send buffer size, UDP-Lite will
+  split the payload into several individual packets, filling up the
+  send buffer size in each case.
+
+  The precise value also depends on the interface MTU. The interface MTU,
+  in turn, may trigger IP fragmentation. In this case, the generated
+  UDP-Lite packet is split into several IP packets, of which only the
+  first one contains the L4 header.
+
+  The send buffer size has implications on the checksum coverage length.
+  Consider the following example:
+
+  Payload: 1536 bytes          Send Buffer:     1024 bytes
+  MTU:     1500 bytes          Coverage Length:  856 bytes
+
+  UDP-Lite will ship the 1536 bytes in two separate packets:
+
+  Packet 1: 1024 payload + 8 byte header + 20 byte IP header = 1052 bytes
+  Packet 2:  512 payload + 8 byte header + 20 byte IP header =  540 bytes
+
+  The coverage packet covers the UDP-Lite header and 848 bytes of the
+  payload in the first packet, the second packet is fully covered. Note
+  that for the second packet, the coverage length exceeds the packet
+  length. The kernel always re-adjusts the coverage length to the packet
+  length in such cases.
+
+  As an example of what happens when one UDP-Lite packet is split into
+  several tiny fragments, consider the following example.
+
+  Payload: 1024 bytes            Send buffer size: 1024 bytes
+  MTU:      300 bytes            Coverage length:   575 bytes
+
+  +-+-----------+--------------+--------------+--------------+
+  |8|    272    |      280     |     280      |     280      |
+  +-+-----------+--------------+--------------+--------------+
+               280            560            840           1032
+                                    ^
+  *****checksum coverage*************
+
+  The UDP-Lite module generates one 1032 byte packet (1024 + 8 byte
+  header). According to the interface MTU, these are split into 4 IP
+  packets (280 byte IP payload + 20 byte IP header). The kernel module
+  sums the contents of the entire first two packets, plus 15 bytes of
+  the last packet before releasing the fragments to the IP module.
+
+  To see the analogous case for IPv6 fragmentation, consider a link
+  MTU of 1280 bytes and a write buffer of 3356 bytes. If the checksum
+  coverage is less than 1232 bytes (MTU minus IPv6/fragment header
+  lengths), only the first fragment needs to be considered. When using
+  larger checksum coverage lengths, each eligible fragment needs to be
+  checksummed. Suppose we have a checksum coverage of 3062. The buffer
+  of 3356 bytes will be split into the following fragments:
+
+    Fragment 1: 1280 bytes carrying  1232 bytes of UDP-Lite data
+    Fragment 2: 1280 bytes carrying  1232 bytes of UDP-Lite data
+    Fragment 3:  948 bytes carrying   900 bytes of UDP-Lite data
+
+  The first two fragments have to be checksummed in full, of the last
+  fragment only 598 (= 3062 - 2*1232) bytes are checksummed.
+
+  While it is important that such cases are dealt with correctly, they
+  are (annoyingly) rare: UDP-Lite is designed for optimising multimedia
+  performance over wireless (or generally noisy) links and thus smaller
+  coverage lenghts are likely to be expected.
+
+
+  V) UDP-LITE RUNTIME STATISTICS AND THEIR MEANING
+
+  Exceptional and error conditions are logged to syslog at the KERN_DEBUG
+  level.  Live statistics about UDP-Lite are available in /proc/net/snmp
+  and can (with newer versions of netstat) be viewed using
+
+                            netstat -svu
+
+  This displays UDP-Lite statistics variables, whose meaning is as follows.
+
+   InDatagrams:     Total number of received datagrams.
+
+   NoPorts:         Number of packets received to an unknown port.
+                    These cases are counted separately (not as InErrors).
+
+   InErrors:        Number of erroneous UDP-Lite packets. Errors include:
+                      * internal socket queue receive errors
+                      * packet too short (less than 8 bytes or stated
+                        coverage length exceeds received length)
+                      * xfrm4_policy_check() returned with error
+                      * application has specified larger min. coverage
+                        length than that of incoming packet
+                      * checksum coverage violated
+                      * bad checksum
+
+   OutDatagrams:    Total number of sent datagrams.
+
+   These statistics derive from the UDP MIB (RFC 2013).
+
+
+  VI) IPTABLES
+
+  There is packet match support for UDP-Lite as well as support for the LOG target.
+  If you copy and paste the following line into /etc/protcols,
+
+  udplite 136     UDP-Lite        # UDP-Lite [RFC 3828]
+
+  then
+              iptables -A INPUT -p udplite -j LOG
+
+  will produce logging output to syslog. Dropping and rejecting packets also works.
+
+
+  VII) MAINTAINER ADDRESS
+
+  The UDP-Lite patch was developed at
+                    University of Aberdeen
+                    Electronics Research Group
+                    Department of Engineering
+                    Fraser Noble Building
+                    Aberdeen AB24 3UE; UK
+  The current maintainer is Gerrit Renker, <[email protected]>. Initial
+  code had been developed by William  Stanislaus, <[email protected]>.
include/linux/in.h +1 -0
index 2619859..1912e7c 100644
@@ -45,6 +45,7 @@ enum {
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+  IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/
 
   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
include/linux/socket.h +1 -0
index 3614090..592b666 100644
@@ -264,6 +264,7 @@ #define SOL_UDP		17
 #define SOL_IPV6	41
 #define SOL_ICMPV6	58
 #define SOL_SCTP	132
+#define SOL_UDPLITE	136     /* UDP-Lite (RFC 3828) */
 #define SOL_RAW		255
 #define SOL_IPX		256
 #define SOL_AX25	257
include/linux/udp.h +11 -0
index 014b41d..1248668 100644
@@ -50,12 +50,23 @@ struct udp_sock {
 	 * when the socket is uncorked.
 	 */
 	__u16		 len;		/* total length of pending frames */
+	/*
+	 * Fields specific to UDP-Lite.
+	 */
+	__u16		 pcslen;
+	__u16		 pcrlen;
+/* indicator bits used by pcflag: */
+#define UDPLITE_BIT      0x1  		/* set by udplite proto init function */
+#define UDPLITE_SEND_CC  0x2  		/* set via udplite setsockopt         */
+#define UDPLITE_RECV_CC  0x4		/* set via udplite setsocktopt        */
+	__u8		 pcflag;        /* marks socket as UDP-Lite if > 0    */
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
 {
 	return (struct udp_sock *)sk;
 }
+#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag)
 
 #endif
 
include/net/snmp.h +2 -0
index 464970e..34183aa 100644
@@ -131,6 +131,8 @@ #define SNMP_INC_STATS(mib, field) 	\
 	(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]++)
 #define SNMP_DEC_STATS(mib, field) 	\
 	(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]--)
+#define SNMP_DEC_STATS_BH(mib, field) 	\
+	(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]--)
 #define SNMP_ADD_STATS_BH(mib, field, addend) 	\
 	(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
 #define SNMP_ADD_STATS_USER(mib, field, addend) 	\
include/net/udp.h +92 -3

128 lines not on this page · raw message

include/net/udplite.h new file +86 -0

86 lines not on this page · raw message

include/net/xfrm.h +2 -0
index 1e2a4dd..2bd23cd 100644
@@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_sport;
 		break;
@@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_dport;
 		break;
net/ipv4/af_inet.c +8 -1
index edcf093..2b997b1 100644
@@ -1223,10 +1223,13 @@ static int __init init_ipv4_mibs(void)
 	tcp_statistics[1] = alloc_percpu(struct tcp_mib);
 	udp_statistics[0] = alloc_percpu(struct udp_mib);
 	udp_statistics[1] = alloc_percpu(struct udp_mib);
+	udplite_statistics[0] = alloc_percpu(struct udp_mib);
+	udplite_statistics[1] = alloc_percpu(struct udp_mib);
 	if (!
 	    (net_statistics[0] && net_statistics[1] && ip_statistics[0]
 	     && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
-	     && udp_statistics[0] && udp_statistics[1]))
+	     && udp_statistics[0] && udp_statistics[1]
+	     && udplite_statistics[0] && udplite_statistics[1]             ) )
 		return -ENOMEM;
 
 	(void) tcp_mib_init();
@@ -1313,6 +1316,10 @@ #endif
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
+	/*
+	 * 	Add UDP-Lite (RFC 3828)
+	 */
+	udplite4_register();
 
 	/*
 	 *	Set the ICMP layer up
net/ipv4/netfilter/ipt_LOG.c +8 -3
index 7dc820d..46eee64 100644
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (ih->protocol == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (ntohs(ih->frag_off) & IP_OFFSET)
 			break;
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_
 	/* IP:      40+46+6+11+127 = 230 */
 	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
 	/* UDP:     10+max(25,20) = 35 */
+	/* UDPLITE: 14+max(25,20) = 39 */
 	/* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
 	/* ESP:     10+max(25)+15 = 50 */
 	/* AH:      9+max(25)+15 = 49 */
net/ipv4/proc.c +12 -0
index 9c6cbe3..9b72fe4 100644
@@ -66,6 +66,7 @@ static int sockstat_seq_show(struct seq_
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
 	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
 		   atomic_read(&ip_frag_mem));
@@ -304,6 +305,17 @@ static int snmp_seq_show(struct seq_file
 			   fold_field((void **) udp_statistics, 
 				      snmp4_udp_list[i].entry));
 
+	/* the UDP and UDP-Lite MIBs are the same */
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %s", snmp4_udp_list[i].name);
+
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			   fold_field((void **) udplite_statistics,
+				      snmp4_udp_list[i].entry)     );
+
 	seq_putc(seq, '\n');
 	return 0;
 }
net/ipv4/udp.c +302 -185

898 lines not on this page · raw message

net/ipv4/udplite.c new file +186 -0

186 lines not on this page · raw message

net/ipv4/xfrm4_policy.c +1 -0
index 7a7a001..923a48b 100644
@@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, st
 	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
 		switch (iph->protocol) {
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/ipv6/netfilter/ip6t_LOG.c +7 -3
index 0cf537d..3cb6bb7 100644
@@ -270,11 +270,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (currenthdr == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (fragment)
 			break;
net/ipv6/udp.c +7 -53

99 lines not on this page · raw message

net/ipv6/xfrm6_policy.c +1 -0
index 6a252e2..cb352e3 100644
@@ -272,6 +272,7 @@ _decode_session6(struct sk_buff *skb, st
 			break;
 
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/netfilter/xt_multiport.c +3 -2
index d3aefd3..c3b4bc0 100644
@@ -1,5 +1,5 @@
-/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
-   the same place so we can treat them as equal. */
+/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
+   ports are in the same place so we can treat them as equal. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <[email protected]>
@@ -162,6 +162,7 @@ check(u_int16_t proto,
 {
 	/* Must specify supported protocol, no unknown flags or bad count */
 	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
+		|| proto == IPPROTO_UDPLITE
 		|| proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
 		&& !(ip_invflags & XT_INV_PROTO)
 		&& (match_flags == XT_MULTIPORT_SOURCE
net/netfilter/xt_tcpudp.c +19 -1
index e76a68e..46414b5 100644
@@ -10,7 +10,7 @@ #include <linux/netfilter/xt_tcpudp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("xt_tcp");
 MODULE_ALIAS("xt_udp");
@@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[]
 		.proto		= IPPROTO_UDP,
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET6,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
 };
 
 static int __init xt_tcpudp_init(void)
maintainer
#8 lore raw

Re: [PATCH-update][RFC] net: consolidated UDP / UDP-Lite code

From: Gerrit Renker <[email protected]>
Date: Mon, 9 Oct 2006 10:51:44 +0100

net/ipv4/udp.c out: · line 894

Quoted 4 lines

csum_copy_err:

net/ipv4/udp.c +2 -1
-	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
+	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
+	UDP_DEC_STATS_BH(UDP_MIB_INDATAGRAMS, is_udplite);

I'm not a big fan at all of these "statistic corrections" we're starting to place in various spots.

I really don't think it's the end of the world if we count as INDATAGRAMS a packet that we later discover has a bad checksum.

There are even some serious issues to consider because we might, for example, count the INDATAGRAMS on a particular cpu, and then find the checksum problem on another cpu and thus be subtracting a different one of the per-cpu instances of this counter. That could make it negative or similar.

#9 lore raw

Re: [PATCH-update][RFC] net: consolidated UDP / UDP-Lite code

|  >  csum_copy_err:
|  > -	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
|  > +	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
|  > +	UDP_DEC_STATS_BH(UDP_MIB_INDATAGRAMS, is_udplite);
|  
|  I'm not a big fan at all of these "statistic corrections"
|  we're starting to place in various spots.

I am not really fond of this solution either. It evolved via discussion, from a previous suggestion to place the increment of InDatagrams into udp_recvmsg(). The problem with that alternative was in dealing with applications which use the data_ready handler (such as sunrpc).

|  I really don't think it's the end of the world if we count as
|  INDATAGRAMS a packet that we later discover has a bad checksum.

It would have been nice to say "all these counters count correctly". Maybe that has been over-ambitious - in tcp_ipv4.c I found that tcp_v4_rcv also counts incoming segments even if they are bad.

I will restore the original state and remove the counter decrements in the next upcoming version of the patch.

Thank you,

-- Gerrit

#10 lore raw

Re: [PATCH-update][RFC] net: consolidated UDP / UDP-Lite code

In reply to Gerrit Renker

Hi David,

please find attached the updated UDP-Lite patch - I have removed the statistics corrections you pointed out to me.

Can you please indicate whether you are ok, by and large, with the changes performed by the patch? Even if it is some time ago, I have implemented in this patch the architectural suggestions you gave me a while earlier.

Since it takes more time to review both the v4 and the v6 side, I have still cut out the v6 side (it mirrors v4) - do you think it is better to send the whole thing?

My idea was to ask you for comments on the v4 side, incorporate these into both v4/v6 sides and then send the completed works without any further changes - so that the final reviewing will not take that long. Comments made by other people have been incorporated in the attached patch.

Many thanks,
Gerrit

---
 Documentation/networking/udplite.txt |  291 +++++++++++++++++++++
 include/linux/in.h                   |    1
 include/linux/socket.h               |    1
 include/linux/udp.h                  |   11
 include/net/udp.h                    |   92 ++++++
 include/net/udplite.h                |   86 ++++++
 include/net/xfrm.h                   |    2
 net/ipv4/af_inet.c                   |    9
 net/ipv4/netfilter/ipt_LOG.c         |   11
 net/ipv4/proc.c                      |   12
 net/ipv4/udp.c                       |  474 +++++++++++++++++++++--------------
 net/ipv4/udplite.c                   |  186 +++++++++++++
 net/ipv4/xfrm4_policy.c              |    1
 net/ipv6/netfilter/ip6t_LOG.c        |   10
 net/ipv6/udp.c                       |   60 ----
 net/ipv6/xfrm6_policy.c              |    1
 net/netfilter/xt_multiport.c         |    5
 net/netfilter/xt_tcpudp.c            |   20 +
 18 files changed, 1022 insertions(+), 251 deletions(-)
include/linux/in.h +1 -0
index 2619859..1912e7c 100644
@@ -45,6 +45,7 @@ enum {
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+  IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/
 
   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
include/linux/socket.h +1 -0
index 3614090..592b666 100644
@@ -264,6 +264,7 @@ #define SOL_UDP		17
 #define SOL_IPV6	41
 #define SOL_ICMPV6	58
 #define SOL_SCTP	132
+#define SOL_UDPLITE	136     /* UDP-Lite (RFC 3828) */
 #define SOL_RAW		255
 #define SOL_IPX		256
 #define SOL_AX25	257
include/linux/udp.h +11 -0
index 014b41d..1248668 100644
@@ -50,12 +50,23 @@ struct udp_sock {
 	 * when the socket is uncorked.
 	 */
 	__u16		 len;		/* total length of pending frames */
+	/*
+	 * Fields specific to UDP-Lite.
+	 */
+	__u16		 pcslen;
+	__u16		 pcrlen;
+/* indicator bits used by pcflag: */
+#define UDPLITE_BIT      0x1  		/* set by udplite proto init function */
+#define UDPLITE_SEND_CC  0x2  		/* set via udplite setsockopt         */
+#define UDPLITE_RECV_CC  0x4		/* set via udplite setsocktopt        */
+	__u8		 pcflag;        /* marks socket as UDP-Lite if > 0    */
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
 {
 	return (struct udp_sock *)sk;
 }
+#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag)
 
 #endif
 
include/net/udp.h +89 -3

125 lines not on this page · raw message

net/ipv4/udp.c +289 -185

885 lines not on this page · raw message

include/net/udplite.h new file +86 -0

86 lines not on this page · raw message

net/ipv4/udplite.c new file +186 -0

186 lines not on this page · raw message

net/ipv6/udp.c +7 -53

99 lines not on this page · raw message

net/ipv4/af_inet.c +8 -1
index edcf093..2b997b1 100644
@@ -1223,10 +1223,13 @@ static int __init init_ipv4_mibs(void)
 	tcp_statistics[1] = alloc_percpu(struct tcp_mib);
 	udp_statistics[0] = alloc_percpu(struct udp_mib);
 	udp_statistics[1] = alloc_percpu(struct udp_mib);
+	udplite_statistics[0] = alloc_percpu(struct udp_mib);
+	udplite_statistics[1] = alloc_percpu(struct udp_mib);
 	if (!
 	    (net_statistics[0] && net_statistics[1] && ip_statistics[0]
 	     && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
-	     && udp_statistics[0] && udp_statistics[1]))
+	     && udp_statistics[0] && udp_statistics[1]
+	     && udplite_statistics[0] && udplite_statistics[1]             ) )
 		return -ENOMEM;
 
 	(void) tcp_mib_init();
@@ -1313,6 +1316,10 @@ #endif
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
+	/*
+	 * 	Add UDP-Lite (RFC 3828)
+	 */
+	udplite4_register();
 
 	/*
 	 *	Set the ICMP layer up
net/ipv4/proc.c +12 -0
index 9c6cbe3..9b72fe4 100644
@@ -66,6 +66,7 @@ static int sockstat_seq_show(struct seq_
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
 	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
 		   atomic_read(&ip_frag_mem));
@@ -304,6 +305,17 @@ static int snmp_seq_show(struct seq_file
 			   fold_field((void **) udp_statistics, 
 				      snmp4_udp_list[i].entry));
 
+	/* the UDP and UDP-Lite MIBs are the same */
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %s", snmp4_udp_list[i].name);
+
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			   fold_field((void **) udplite_statistics,
+				      snmp4_udp_list[i].entry)     );
+
 	seq_putc(seq, '\n');
 	return 0;
 }
include/net/xfrm.h +2 -0
index 737fdb2..70a8d2d 100644
@@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_sport;
 		break;
@@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_dport;
 		break;
net/ipv4/xfrm4_policy.c +1 -0
index 1bed0cd..af6867f 100644
@@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, st
 	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
 		switch (iph->protocol) {
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/ipv6/xfrm6_policy.c +1 -0
index 73cee2e..8a25db1 100644
@@ -272,6 +272,7 @@ _decode_session6(struct sk_buff *skb, st
 			break;
 
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/netfilter/xt_multiport.c +3 -2
index d3aefd3..c3b4bc0 100644
@@ -1,5 +1,5 @@
-/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
-   the same place so we can treat them as equal. */
+/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
+   ports are in the same place so we can treat them as equal. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <[email protected]>
@@ -162,6 +162,7 @@ check(u_int16_t proto,
 {
 	/* Must specify supported protocol, no unknown flags or bad count */
 	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
+		|| proto == IPPROTO_UDPLITE
 		|| proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
 		&& !(ip_invflags & XT_INV_PROTO)
 		&& (match_flags == XT_MULTIPORT_SOURCE
net/netfilter/xt_tcpudp.c +19 -1
index e76a68e..46414b5 100644
@@ -10,7 +10,7 @@ #include <linux/netfilter/xt_tcpudp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("xt_tcp");
 MODULE_ALIAS("xt_udp");
@@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[]
 		.proto		= IPPROTO_UDP,
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET6,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
 };
 
 static int __init xt_tcpudp_init(void)
net/ipv4/netfilter/ipt_LOG.c +8 -3
index 7dc820d..46eee64 100644
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (ih->protocol == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (ntohs(ih->frag_off) & IP_OFFSET)
 			break;
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_
 	/* IP:      40+46+6+11+127 = 230 */
 	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
 	/* UDP:     10+max(25,20) = 35 */
+	/* UDPLITE: 14+max(25,20) = 39 */
 	/* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
 	/* ESP:     10+max(25)+15 = 50 */
 	/* AH:      9+max(25)+15 = 49 */
net/ipv6/netfilter/ip6t_LOG.c +7 -3
index 0cf537d..3cb6bb7 100644
@@ -270,11 +270,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (currenthdr == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (fragment)
 			break;
Documentation/networking/udplite.txt new file +291 -0

291 lines not on this page · raw message

maintainer
#11 lore raw

Re: [PATCH-update][RFC] net: consolidated UDP / UDP-Lite code

From: Gerrit Renker <[email protected]>
Date: Thu, 12 Oct 2006 08:49:19 +0100

Quoted 7 lines

please find attached the updated UDP-Lite patch - I have removed the statistics corrections you pointed out to me.

Can you please indicate whether you are ok, by and large, with the changes performed by the patch? Even if it is some time ago, I have implemented in this patch the architectural suggestions you gave me a while earlier.

The patch looks pretty good. I have no problems with how you implemented this at all.

I think we'll have no problem getting this into 2.6.20

#12 lore raw

PATCH v4 1/3 net/ipv4: UDP-Lite support (RFC 3828)

Hi David,

thank you for reviewing the code. This now is the full version, including both the v4 and the v6 side.

I would like to say `please consider for inclusion', but I think it would be good if the IPv6 developers could first have a look through and say whether they are ok with the changes.

The v4 side remains the same as before - apart from some re-shuffling to integrate it with v6.

Before submitting, I have checked compilation on a small bouquet of different architectures (worked ok, no compile or run problems).

Thanks again,
Gerrit

---
 include/linux/in.h     |    1
 include/linux/socket.h |    1
 include/linux/udp.h    |   12 +
 include/net/udp.h      |   91 +++++++++
 include/net/udplite.h  |  149 +++++++++++++++
 net/ipv4/af_inet.c     |   10 -
 net/ipv4/proc.c        |   13 +
 net/ipv4/udp.c         |  473 +++++++++++++++++++++++++++++--------------------
 net/ipv4/udplite.c     |  126 +++++++++++++
 9 files changed, 682 insertions(+), 194 deletions(-)
include/linux/in.h +1 -0
index 2619859..1912e7c 100644
@@ -45,6 +45,7 @@ enum {
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+  IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/
 
   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
include/linux/socket.h +1 -0
index 3614090..592b666 100644
@@ -264,6 +264,7 @@ #define SOL_UDP		17
 #define SOL_IPV6	41
 #define SOL_ICMPV6	58
 #define SOL_SCTP	132
+#define SOL_UDPLITE	136     /* UDP-Lite (RFC 3828) */
 #define SOL_RAW		255
 #define SOL_IPX		256
 #define SOL_AX25	257
include/linux/udp.h +12 -0
index 014b41d..564f3b0 100644
@@ -38,6 +38,7 @@ #ifdef __KERNEL__
 #include <linux/types.h>
 
 #include <net/inet_sock.h>
+#define UDP_HTABLE_SIZE		128
 
 struct udp_sock {
 	/* inet_sock has to be the first member */
@@ -50,12 +51,23 @@ struct udp_sock {
 	 * when the socket is uncorked.
 	 */
 	__u16		 len;		/* total length of pending frames */
+	/*
+	 * Fields specific to UDP-Lite.
+	 */
+	__u16		 pcslen;
+	__u16		 pcrlen;
+/* indicator bits used by pcflag: */
+#define UDPLITE_BIT      0x1  		/* set by udplite proto init function */
+#define UDPLITE_SEND_CC  0x2  		/* set via udplite setsockopt         */
+#define UDPLITE_RECV_CC  0x4		/* set via udplite setsocktopt        */
+	__u8		 pcflag;        /* marks socket as UDP-Lite if > 0    */
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
 {
 	return (struct udp_sock *)sk;
 }
+#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag)
 
 #endif
 
include/net/udp.h +87 -4

123 lines not on this page · raw message

net/ipv4/udp.c +284 -189

881 lines not on this page · raw message

include/net/udplite.h new file +149 -0

149 lines not on this page · raw message

net/ipv4/udplite.c new file +126 -0

126 lines not on this page · raw message

net/ipv4/af_inet.c +9 -1
index edcf093..05b2df2 100644
@@ -104,6 +104,7 @@ #include <net/ip_fib.h>
 #include <net/inet_connection_sock.h>
 #include <net/tcp.h>
 #include <net/udp.h>
+#include <net/udplite.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/raw.h>
@@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void)
 	tcp_statistics[1] = alloc_percpu(struct tcp_mib);
 	udp_statistics[0] = alloc_percpu(struct udp_mib);
 	udp_statistics[1] = alloc_percpu(struct udp_mib);
+	udplite_statistics[0] = alloc_percpu(struct udp_mib);
+	udplite_statistics[1] = alloc_percpu(struct udp_mib);
 	if (!
 	    (net_statistics[0] && net_statistics[1] && ip_statistics[0]
 	     && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
-	     && udp_statistics[0] && udp_statistics[1]))
+	     && udp_statistics[0] && udp_statistics[1]
+	     && udplite_statistics[0] && udplite_statistics[1]             ) )
 		return -ENOMEM;
 
 	(void) tcp_mib_init();
@@ -1313,6 +1317,10 @@ #endif
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
+	/*
+	 * 	Add UDP-Lite (RFC 3828)
+	 */
+	udplite4_register();
 
 	/*
 	 *	Set the ICMP layer up
net/ipv4/proc.c +13 -0
index 9c6cbe3..cd873da 100644
@@ -38,6 +38,7 @@ #include <net/icmp.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/udp.h>
+#include <net/udplite.h>
 #include <linux/inetdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
 	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
 		   atomic_read(&ip_frag_mem));
@@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file
 			   fold_field((void **) udp_statistics, 
 				      snmp4_udp_list[i].entry));
 
+	/* the UDP and UDP-Lite MIBs are the same */
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %s", snmp4_udp_list[i].name);
+
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			   fold_field((void **) udplite_statistics,
+				      snmp4_udp_list[i].entry)     );
+
 	seq_putc(seq, '\n');
 	return 0;
 }
#13 lore raw

PATCH v4 2/3 net/ipv6: v6-side of UDP-Lite

In reply to David Miller

This provides consolidated UDP-Lite support over IPv6. Changes to net/ipv6/udp.c reflect those in net/ipv4/udp.c.

---
 include/net/ipv6.h      |   10 +
 include/net/transp_v6.h |    3
 net/ipv6/af_inet6.c     |    3
 net/ipv6/proc.c         |   11 +
 net/ipv6/udp.c          |  333 ++++++++++++++++++++++++++++--------------------
 net/ipv6/udplite.c      |  131 ++++++++++++++++++
 6 files changed, 350 insertions(+), 141 deletions(-)
include/net/transp_v6.h +3 -0
index 61f724c..d5a337d 100644
@@ -11,6 +11,7 @@ #ifdef __KERNEL__
 
 extern struct proto rawv6_prot;
 extern struct proto udpv6_prot;
+extern struct proto udplitev6_prot;
 extern struct proto tcpv6_prot;
 
 struct flowi;
@@ -24,6 +25,8 @@ extern void				ipv6_destopt_init(void);
 /* transport protocols */
 extern void				rawv6_init(void);
 extern void				udpv6_init(void);
+extern void 				udplitev6_init(void);
+extern void 				udplitev6_cleanup(void);
 extern void				tcpv6_init(void);
 
 extern int				udpv6_connect(struct sock *sk,
net/ipv6/udp.c +195 -138

572 lines not on this page · raw message

net/ipv6/udplite.c new file +131 -0

131 lines not on this page · raw message

include/net/ipv6.h +7 -3
index 8223c44..60cbe35 100644
@@ -143,9 +143,13 @@ #define ICMP6_INC_STATS_OFFSET_BH(idev, 
 	SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset);    	\
 })
 DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6);
-#define UDP6_INC_STATS(field)		SNMP_INC_STATS(udp_stats_in6, field)
-#define UDP6_INC_STATS_BH(field)	SNMP_INC_STATS_BH(udp_stats_in6, field)
-#define UDP6_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(udp_stats_in6, field)
+DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
+#define UDP6_INC_STATS_BH(field, is_udplite) 			      do  {  \
+	if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field);         \
+	else		SNMP_INC_STATS_BH(udp_stats_in6, field);    } while(0)
+#define UDP6_INC_STATS_USER(field, is_udplite)			       do {    \
+	if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field);         \
+	else		SNMP_INC_STATS_USER(udp_stats_in6, field);    } while(0)
 
 int snmp6_register_dev(struct inet6_dev *idev);
 int snmp6_unregister_dev(struct inet6_dev *idev);
net/ipv6/proc.c +11 -0
index efee7a6..d72b36e 100644
@@ -49,6 +49,8 @@ static int sockstat6_seq_show(struct seq
 		       fold_prot_inuse(&tcpv6_prot));
 	seq_printf(seq, "UDP6: inuse %d\n",
 		       fold_prot_inuse(&udpv6_prot));
+	seq_printf(seq, "UDPLITE6: inuse %d\n",
+		        fold_prot_inuse(&udplitev6_prot));
 	seq_printf(seq, "RAW6: inuse %d\n",
 		       fold_prot_inuse(&rawv6_prot));
 	seq_printf(seq, "FRAG6: inuse %d memory %d\n",
@@ -133,6 +135,14 @@ static struct snmp_mib snmp6_udp6_list[]
 	SNMP_MIB_SENTINEL
 };
 
+static struct snmp_mib snmp6_udplite6_list[] = {
+	SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS),
+	SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS),
+	SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS),
+	SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
+	SNMP_MIB_SENTINEL
+};
+
 static unsigned long
 fold_field(void *mib[], int offt)
 {
@@ -166,6 +176,7 @@ static int snmp6_seq_show(struct seq_fil
 		snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list);
 		snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list);
 		snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list);
+		snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list);
 	}
 	return 0;
 }
net/ipv6/af_inet6.c +3 -0
index 858cae2..fdc7bef 100644
@@ -49,6 +49,7 @@ #include <linux/netfilter_ipv6.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/udp.h>
+#include <net/udplite.h>
 #include <net/tcp.h>
 #include <net/ipip.h>
 #include <net/protocol.h>
@@ -862,6 +863,7 @@ #endif
 
 	/* Init v6 transport protocols. */
 	udpv6_init();
+	udplitev6_init();
 	tcpv6_init();
 
 	ipv6_packet_init();
@@ -926,6 +928,7 @@ #ifdef CONFIG_IPV6_MIP6
 	mip6_fini();
 #endif
 	/* Cleanup code parts. */
+	udplitev6_cleanup();
 	ip6_flowlabel_cleanup();
 	addrconf_cleanup();
 	ip6_route_cleanup();
#14 lore raw

PATCH v4 3/3 net: UDP-Lite misc files

In reply to David Miller

Miscellaneous files to support UDP-Lite, including basic xfrm and netfilter support.

---
 Documentation/networking/udplite.txt |  291 +++++++++++++++++++++++++++++++++++
 include/net/xfrm.h                   |    2
 net/ipv4/netfilter/ipt_LOG.c         |   11 -
 net/ipv4/xfrm4_policy.c              |    1
 net/ipv6/netfilter/ip6t_LOG.c        |   10 -
 net/ipv6/xfrm6_policy.c              |    1
 net/netfilter/xt_multiport.c         |    5
 net/netfilter/xt_tcpudp.c            |   20 ++
 8 files changed, 332 insertions(+), 9 deletions(-)
include/net/xfrm.h +2 -0
index 737fdb2..70a8d2d 100644
@@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_sport;
 		break;
@@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_dport;
 		break;
net/ipv4/xfrm4_policy.c +1 -0
index 1bed0cd..af6867f 100644
@@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, st
 	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
 		switch (iph->protocol) {
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/ipv6/xfrm6_policy.c +1 -0
index 73cee2e..8a25db1 100644
@@ -272,6 +272,7 @@ _decode_session6(struct sk_buff *skb, st
 			break;
 
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/netfilter/xt_multiport.c +3 -2
index d3aefd3..c3b4bc0 100644
@@ -1,5 +1,5 @@
-/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
-   the same place so we can treat them as equal. */
+/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
+   ports are in the same place so we can treat them as equal. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <[email protected]>
@@ -162,6 +162,7 @@ check(u_int16_t proto,
 {
 	/* Must specify supported protocol, no unknown flags or bad count */
 	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
+		|| proto == IPPROTO_UDPLITE
 		|| proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
 		&& !(ip_invflags & XT_INV_PROTO)
 		&& (match_flags == XT_MULTIPORT_SOURCE
net/netfilter/xt_tcpudp.c +19 -1
index e76a68e..46414b5 100644
@@ -10,7 +10,7 @@ #include <linux/netfilter/xt_tcpudp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("xt_tcp");
 MODULE_ALIAS("xt_udp");
@@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[]
 		.proto		= IPPROTO_UDP,
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET6,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
 };
 
 static int __init xt_tcpudp_init(void)
net/ipv4/netfilter/ipt_LOG.c +8 -3
index 7dc820d..46eee64 100644
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (ih->protocol == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (ntohs(ih->frag_off) & IP_OFFSET)
 			break;
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_
 	/* IP:      40+46+6+11+127 = 230 */
 	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
 	/* UDP:     10+max(25,20) = 35 */
+	/* UDPLITE: 14+max(25,20) = 39 */
 	/* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
 	/* ESP:     10+max(25)+15 = 50 */
 	/* AH:      9+max(25)+15 = 49 */
net/ipv6/netfilter/ip6t_LOG.c +7 -3
index 0cf537d..3cb6bb7 100644
@@ -270,11 +270,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (currenthdr == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (fragment)
 			break;
Documentation/networking/udplite.txt new file +291 -0

291 lines not on this page · raw message

#15 lore raw

RFC PATCH v3 2/4 net/ipv4: self-contained UDP-Lite module

In reply to David Miller

The self-contained UDP-Litev4 module for v4; logically completely separate from ipv4/udp.c.

--
include/net/udplite.h | 86 +++++++++++++++++++++++

 net/ipv4/udplite.c    |  186 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 272 insertions(+)
include/net/udplite.h new file +86 -0
new file mode 100644
index 0000000..90d7aec
@@ -0,0 +1,86 @@
+/*
+ *	Definitions for the UDP-Lite (RFC 3828) code.
+ */
+#ifndef _UDPLITE_H
+#define _UDPLITE_H
+
+/* UDP-Lite socket options */
+#define UDPLITE_SEND_CSCOV   10 /* sender partial coverage (as sent)      */
+#define UDPLITE_RECV_CSCOV   11 /* receiver partial coverage (threshold ) */
+
+extern struct proto 		udplite_prot;
+extern struct hlist_head 	udplite_hash[UDP_HTABLE_SIZE];
+
+/* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */
+DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics);
+
+/*
+ *	Checksum computation is all in software, hence simpler getfrag.
+ */
+static __inline__ int udplite_getfrag(void *from, char *to, int  offset,
+				      int len, int odd, struct sk_buff *skb)
+{
+	return memcpy_fromiovecend(to, (struct iovec *) from, offset, len);
+}
+
+/*
+ * 	Functions used by UDP-Litev4 and UDP-Litev6
+ */
+/* calculate checksum coverage set for outgoing packets */
+static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh)
+{
+	int cscov = up->len;
+
+	/*
+	 * Sender has set `partial coverage' option on UDP-Lite socket
+	 */
+	if (up->pcflag & UDPLITE_SEND_CC)    {
+		if (up->pcslen < up->len) {
+		/* up->pcslen == 0 means that full coverage is required,
+		 * partial coverage only if  0 < up->pcslen < up->len */
+			if (0 < up->pcslen) {
+			       cscov = up->pcslen;
+			}
+			uh->len = htons(up->pcslen);
+		}
+	/*
+	 * NOTE: Causes for the error case  `up->pcslen > up->len':
+	 *        (i)  Application error (will not be penalized).
+	 *       (ii)  Payload too big for send buffer: data is split
+	 *             into several packets, each with its own header.
+	 *             In this case (e.g. last segment), coverage may
+	 *             exceed packet length.
+	 *       Since packets with coverage length > packet length are
+	 *       illegal, we fall back to the defaults here.
+	 */
+	}
+	return cscov;
+}
+
+static inline u32 udplite_csum_outgoing(struct sock *sk, int cscov)
+{
+	struct sk_buff *skb;
+	int off, len;
+	u32 csum = 0;
+
+	skb_queue_walk(&sk->sk_write_queue, skb) {
+		off = skb->h.raw - skb->data;
+		len = skb->len - off;
+
+		csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum);
+
+		if ((cscov -= len) <= 0)
+			break;
+	}
+	return csum;
+}
+
+/*
+ *  	net/ipv4/udplite.c
+ */
+extern void	udplite4_register(void);
+extern int 	udplite_get_port(struct sock *sk, unsigned short snum,
+			int (*scmp)(const struct sock *, const struct sock *));
+extern int	udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh,
+				      u16 len, u32 saddr, u32 daddr          );
+#endif	/* _UDPLITE_H */
net/ipv4/udplite.c new file +186 -0

186 lines not on this page · raw message

#16 lore raw

RFC PATCH v3 3/4 net: basic xfrm/netfilter support for UDP-Lite

In reply to David Miller

Basic xfrm and netfilter support for UDP-Lite:
* matching of UDP-Lite packets
* LOG support
* header file support

--

 include/net/xfrm.h            |    2 ++
 net/ipv4/netfilter/ipt_LOG.c  |   11 ++++++++---
 net/ipv4/xfrm4_policy.c       |    1 +
 net/ipv6/netfilter/ip6t_LOG.c |   10 +++++++---
 net/ipv6/xfrm6_policy.c       |    1 +
 net/netfilter/xt_multiport.c  |    9 +++++----
 net/netfilter/xt_tcpudp.c     |   20 +++++++++++++++++++-
 7 files changed, 43 insertions(+), 11 deletions(-)
include/net/xfrm.h +2 -0
index bf8e2df..e697862 100644
@@ -468,6 +468,7 @@ u16 xfrm_flowi_sport(struct flowi *fl)
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_sport;
 		break;
@@ -493,6 +494,7 @@ u16 xfrm_flowi_dport(struct flowi *fl)
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 		port = fl->fl_ip_dport;
 		break;
net/ipv4/xfrm4_policy.c +1 -0
index 4795985..22b53ea 100644
@@ -180,6 +180,7 @@ _decode_session4(struct sk_buff *skb, st
 	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
 		switch (iph->protocol) {
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/ipv6/xfrm6_policy.c +1 -0
index 9391c4c..ea94bd1 100644
@@ -252,6 +252,7 @@ _decode_session6(struct sk_buff *skb, st
 			break;
 
 		case IPPROTO_UDP:
+		case IPPROTO_UDPLITE:
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
net/netfilter/xt_tcpudp.c +19 -1
index e76a68e..46414b5 100644
@@ -10,7 +10,7 @@ #include <linux/netfilter/xt_tcpudp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("xt_tcp");
 MODULE_ALIAS("xt_udp");
@@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[]
 		.proto		= IPPROTO_UDP,
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "udplite",
+		.family		= AF_INET6,
+		.checkentry	= udp_checkentry,
+		.match		= udp_match,
+		.matchsize	= sizeof(struct xt_udp),
+		.proto		= IPPROTO_UDPLITE,
+		.me		= THIS_MODULE,
+	},
 };
 
 static int __init xt_tcpudp_init(void)
net/netfilter/xt_multiport.c +5 -4
index d3aefd3..9127f85 100644
@@ -1,5 +1,5 @@
-/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
-   the same place so we can treat them as equal. */
+/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
+ * ports are in the same place so we can treat them as equal. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <[email protected]>
@@ -161,8 +161,9 @@ check(u_int16_t proto,
       u_int8_t count)
 {
 	/* Must specify supported protocol, no unknown flags or bad count */
-	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
-		|| proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
+	return ( proto == IPPROTO_TCP  ||
+		 proto == IPPROTO_UDP  || proto == IPPROTO_UDPLITE ||
+		 proto == IPPROTO_SCTP || proto == IPPROTO_DCCP      )
 		&& !(ip_invflags & XT_INV_PROTO)
 		&& (match_flags == XT_MULTIPORT_SOURCE
 		    || match_flags == XT_MULTIPORT_DESTINATION
net/ipv6/netfilter/ip6t_LOG.c +7 -3
index 0cf537d..3cb6bb7 100644
@@ -270,11 +270,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (currenthdr == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (fragment)
 			break;
net/ipv4/netfilter/ipt_LOG.c +8 -3
index 7dc820d..46eee64 100644
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_
 		}
 		break;
 	}
-	case IPPROTO_UDP: {
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE: {
 		struct udphdr _udph, *uh;
 
-		/* Max length: 10 "PROTO=UDP " */
-		printk("PROTO=UDP ");
+		if (ih->protocol == IPPROTO_UDP)
+			/* Max length: 10 "PROTO=UDP "     */
+			printk("PROTO=UDP " );
+		else	/* Max length: 14 "PROTO=UDPLITE " */
+			printk("PROTO=UDPLITE ");
 
 		if (ntohs(ih->frag_off) & IP_OFFSET)
 			break;
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_
 	/* IP:      40+46+6+11+127 = 230 */
 	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
 	/* UDP:     10+max(25,20) = 35 */
+	/* UDPLITE: 14+max(25,20) = 39 */
 	/* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
 	/* ESP:     10+max(25)+15 = 50 */
 	/* AH:      9+max(25)+15 = 49 */
#17 lore raw

Re: [PATCHv3 3/4][RFC] net: basic xfrm/netfilter support for UDP-Lite

Quoted 10 lines · Gerrit Renker

Basic xfrm and netfilter support for UDP-Lite:
* matching of UDP-Lite packets
* LOG support
* header file support

--

net/netfilter/xt_multiport.c +0 -0
@@ -161,8 +161,9 @@ check(u_int16_t proto,
       u_int8_t count)

net/netfilter/xt_multiport.c check(u_int16_t proto, · line 169

Quoted 10 lines
net/netfilter/xt_multiport.c +3 -2
 {
 	/* Must specify supported protocol, no unknown flags or bad count */
-	return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
-		|| proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
+	return ( proto == IPPROTO_TCP  ||
+		 proto == IPPROTO_UDP  || proto == IPPROTO_UDPLITE ||
+		 proto == IPPROTO_SCTP || proto == IPPROTO_DCCP      )
 		&& !(ip_invflags & XT_INV_PROTO)
 		&& (match_flags == XT_MULTIPORT_SOURCE
 		    || match_flags == XT_MULTIPORT_DESTINATION

The patch looks good besides the fancy formating above. I'm not too much of a fan of the existing formating, but please keep it consistent.

#18 lore raw

RFC PATCH v3 4/4 net: misc. files to support UDP-Lite

In reply to David Miller

Miscellaneous files which complete the support for UDP-Litev4.

--

 Documentation/networking/udplite.txt |  291 +++++++++++++++++++++++++++++++++++
 include/linux/in.h                   |    1
 include/linux/socket.h               |    1
 include/net/snmp.h                   |    2
 net/ipv4/af_inet.c                   |    9 -
 net/ipv4/proc.c                      |   12 +
 6 files changed, 315 insertions(+), 1 deletion(-)
net/ipv4/af_inet.c +8 -1
index fdd89e3..8b2e66e 100644
@@ -1223,10 +1223,13 @@ static int __init init_ipv4_mibs(void)
 	tcp_statistics[1] = alloc_percpu(struct tcp_mib);
 	udp_statistics[0] = alloc_percpu(struct udp_mib);
 	udp_statistics[1] = alloc_percpu(struct udp_mib);
+	udplite_statistics[0] = alloc_percpu(struct udp_mib);
+	udplite_statistics[1] = alloc_percpu(struct udp_mib);
 	if (!
 	    (net_statistics[0] && net_statistics[1] && ip_statistics[0]
 	     && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
-	     && udp_statistics[0] && udp_statistics[1]))
+	     && udp_statistics[0] && udp_statistics[1]
+	     && udplite_statistics[0] && udplite_statistics[1]             ) )
 		return -ENOMEM;
 
 	(void) tcp_mib_init();
@@ -1313,6 +1316,10 @@ #endif
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
+	/*
+	 * 	Add UDP-Lite (RFC 3828)
+	 */
+	udplite4_register();
 
 	/*
 	 *	Set the ICMP layer up
net/ipv4/proc.c +12 -0
index 9c6cbe3..9b72fe4 100644
@@ -66,6 +66,7 @@ static int sockstat_seq_show(struct seq_
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
 	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
 		   atomic_read(&ip_frag_mem));
@@ -304,6 +305,17 @@ static int snmp_seq_show(struct seq_file
 			   fold_field((void **) udp_statistics, 
 				      snmp4_udp_list[i].entry));
 
+	/* the UDP and UDP-Lite MIBs are the same */
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %s", snmp4_udp_list[i].name);
+
+	seq_puts(seq, "\nUdpLite:");
+	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
+		seq_printf(seq, " %lu",
+			   fold_field((void **) udplite_statistics,
+				      snmp4_udp_list[i].entry)     );
+
 	seq_putc(seq, '\n');
 	return 0;
 }
include/net/snmp.h +2 -0
index 464970e..34183aa 100644
@@ -131,6 +131,8 @@ #define SNMP_INC_STATS(mib, field) 	\
 	(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]++)
 #define SNMP_DEC_STATS(mib, field) 	\
 	(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]--)
+#define SNMP_DEC_STATS_BH(mib, field) 	\
+	(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]--)
 #define SNMP_ADD_STATS_BH(mib, field, addend) 	\
 	(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
 #define SNMP_ADD_STATS_USER(mib, field, addend) 	\
include/linux/in.h +1 -0
index bcaca83..0903e5f 100644
@@ -44,6 +44,7 @@ enum {
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+  IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/
 
   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
include/linux/socket.h +1 -0
index 3614090..592b666 100644
@@ -264,6 +264,7 @@ #define SOL_UDP		17
 #define SOL_IPV6	41
 #define SOL_ICMPV6	58
 #define SOL_SCTP	132
+#define SOL_UDPLITE	136
 #define SOL_RAW		255
 #define SOL_IPX		256
 #define SOL_AX25	257
Documentation/networking/udplite.txt new file +291 -0

291 lines not on this page · raw message