Skip to contentSkip to conversation

Still using IPTOS_TOS() in kernel? Really???

DISCUSSION Philip A. Prindeville 2 participants 12 messages Dec 17, 2009 – Jan 11, 2010

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

[ Posted to linux-net a couple of days ago and didn't hear back... so reposting here since this might be more appropriate. ]

I'm looking at net/ipv4/ip_sockglue.c:

   512		case IP_TOS:	/* This sets both TOS and Precedence */
   513			if (sk->sk_type == SOCK_STREAM) {
   514				val &= ~3;
   515				val |= inet->tos & 3;
   516			}
   517			if (inet->tos != val) {
   518				inet->tos = val;
   519				sk->sk_priority = rt_tos2priority(val);
   520				sk_dst_reset(sk);
   521			}
   522			break;

and include/net/route.h:

   141	extern const __u8 ip_tos2prio[16];
   142	
   143	static inline char rt_tos2priority(u8 tos)
   144	{
   145		return ip_tos2prio[IPTOS_TOS(tos)>>1];
   146	}

and finally net/ipv4/route.c:

   165	#define ECN_OR_COST(class)	TC_PRIO_##class
   166	
   167	const __u8 ip_tos2prio[16] = {
   168		TC_PRIO_BESTEFFORT,
   169		ECN_OR_COST(FILLER),
   170		TC_PRIO_BESTEFFORT,
   171		ECN_OR_COST(BESTEFFORT),
   172		TC_PRIO_BULK,
   173		ECN_OR_COST(BULK),
   174		TC_PRIO_BULK,
   175		ECN_OR_COST(BULK),
   176		TC_PRIO_INTERACTIVE,
   177		ECN_OR_COST(INTERACTIVE),
   178		TC_PRIO_INTERACTIVE,
   179		ECN_OR_COST(INTERACTIVE),
   180		TC_PRIO_INTERACTIVE_BULK,
   181		ECN_OR_COST(INTERACTIVE_BULK),
   182		TC_PRIO_INTERACTIVE_BULK,
   183		ECN_OR_COST(INTERACTIVE_BULK)
   184	};

and it's slowly dawning on me that we're using an interpretation of the IP_TOS (and ip.ip_tos field) values that have been deprecated since 1998! Quoting RFC 2474:

3. Differentiated Services Field Definition

A replacement header field, called the DS field, is defined, which is intended to supersede the existing definitions of the IPv4 TOS octet [RFC791] and the IPv6 Traffic Class octet [IPv6].

Seems pretty clear, right? That DSCP is the new testament, here to replace the old testament... although if you look closely, the precedence values of IPTOS_PREC_ROUTINE looks a lot like IPTOS_CLASS_CS0, etc... so some backward compatibility was maintained. (See http://sourceware.org/bugzilla/show_bug.cgi?id=11027 and http://sourceware.org/bugzilla/show_bug.cgi?id=10789 if your glibc doesn't yet include the the IPTOS_CLASS_CSn and IPTOS_DSCP_AFxx values).

And indeed, only routers seem to pay attention to bits in the 0x1c space... I.e. between the upper 3 bits which still mean precedence, and the lower 2 bits which now signify experienced-congestion-notification (ECN).

Assuming that whatever the local host does to the output of the packet, that it's not going to sufficiently delay the packet enough because we're connected to some fast media (Fast ethernet, etc) then what we do locally shouldn't matter... unless of course we're using 802.1p tagging, in which case we can seriously mess up what happens next.

So how is it that no one noticed this issue yet, and given that Linux is used in a fair number of commercial embedded real-time boxes (like satellite and IPTV set-top boxes)... how are they not impacted by this?

Assuming my crusade to get various common apps and services (wget, TB, FF, Sendmail, Cyrus, ProFTPd, etc) to use DSCP/CS marking (very few apps currently use DSCP or precedence marking), then kernels with the proper default behavior will need to start shipping, right? I.e. out-of-the-box kernels should handle such apps without further configuration, such as needing to have the DSCP iptables module installed. They should "just work".

Thanks,

-Philip

#1 lore raw

Hi Philip,

interesting .. i am on the way to implement a DSCP/CS statistic to the kernel. We need this for network traffic accounting. The concept is the following:

We create a virtual file /pro/net/ipdscp , this includes several DSCP/CS counters. See http://www.iana.org/assignments/dscp-registry/. Every time ip_rcv_finish() is called, we take a look at the DSCP/CS (iph->tos) value and increment the related counter. If you're interested in, i will send you a patch ? ..

Maybe this is a good starting point for an DSCP/CS implementation. I was also shocked that the kernel do not really handle DiffServ thinks.

Quoted 7 lines

Assuming my crusade to get various common apps and services (wget, TB, FF,
Sendmail, Cyrus, ProFTPd, etc) to use DSCP/CS marking (very few apps currently use DSCP or precedence marking), then kernels with the proper default behavior will need to start shipping, right? I.e. out-of-the-box kernels should handle such apps without further configuration, such as needing to have the DSCP iptables module installed. They should "just work".

Right.

Best regards,
Torsten

#2 lore raw
Quoted 10 lines · Torsten Schmidt

Hi Philip,

interesting .. i am on the way to implement a DSCP/CS statistic to the kernel. We need this for network traffic accounting. The concept is the following:

We create a virtual file /pro/net/ipdscp , this includes several DSCP/CS counters. See http://www.iana.org/assignments/dscp-registry/. Every time ip_rcv_finish() is called, we take a look at the DSCP/CS (iph->tos) value and increment the related counter. If you're interested in, i will send you a patch ? ..

That would be great.

Quoted 2 lines

Maybe this is a good starting point for an DSCP/CS implementation. I was also shocked that the kernel do not really handle DiffServ thinks.

I think it would also be useful to rework the existing definition of rt_tos2priority() to have a DSCP/CS version that people could then select and build in their kernel via a simple CONFIG_DIFFSERV_COMPLIANT flag.

It could be selectable and default to off until a set cut-over point in the future, then it could become the default.

RFC-2474 is now 11 years old... Odd that we're still not compliant.

-Philip

Quoted 11 lines
Quoted 7 lines

Assuming my crusade to get various common apps and services (wget, TB, FF,
Sendmail, Cyrus, ProFTPd, etc) to use DSCP/CS marking (very few apps currently use DSCP or precedence marking), then kernels with the proper default behavior will need to start shipping, right? I.e. out-of-the-box kernels should handle such apps without further configuration, such as needing to have the DSCP iptables module installed. They should "just work".

Right.

Best regards,
Torsten

#3 lore raw
Quoted 7 lines · On Thursday 17 December 2009 20:45:32 you wrote:
Quoted 6 lines · Torsten Schmidt

Hi Philip,

interesting .. i am on the way to implement a DSCP/CS statistic to the kernel. We need this for network traffic accounting. The concept is the following:

Quoted 7 lines
Quoted 5 lines

We create a virtual file /pro/net/ipdscp , this includes several DSCP/CS counters. See http://www.iana.org/assignments/dscp-registry/. Every time ip_rcv_finish() is called, we take a look at the DSCP/CS (iph->tos) value and increment the related counter. If you're interested in, i will send you a patch ? ..

That would be great.

Here is a first PATCH, tested against 2.6.32. At the time we only support DSCP
class: CS0 and EF PHB. All other classes are shown in /proc/net/ipdscp, but always referenced with 0. Please take a look at ...

For debugging use:

  # ping -Q 0xAB localhost
  # cat /pro/net/ipdscp

in which 0xAB is:
0x00 for CS0, ore
0xB8 for EF PHB

Torsten

From aacc531f2c3f992f3acee65d8806c2c67df348b7 Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Fri, 18 Dec 2009 15:18:52 +0100
Subject: [PATCH] ipv4: add DSCP statistic

This adds IPv4 DSCP statistic to the kernel. See:
* /proc/net/ipdscp
* IANA dscp-registry
* RFC 2474

---
 include/linux/snmp.h    |   28 +++++++++++
 include/net/ipdscp.h    |   65 ++++++++++++++++++++++++++
 include/net/netns/mib.h |    4 ++
 include/net/snmp.h      |    6 +++
 net/ipv4/Kconfig        |   11 +++++
 net/ipv4/Makefile       |    2 +-
 net/ipv4/af_inet.c      |    3 +
 net/ipv4/ip_input.c     |    5 ++
 net/ipv4/ipdscp.c       |  116 +++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 239 insertions(+), 1 deletions(-)
 create mode 100644 include/net/ipdscp.h
 create mode 100644 net/ipv4/ipdscp.c
include/linux/snmp.h +28 -0
index 0f953fe..9cd2d8d 100644
@@ -260,4 +260,32 @@ enum
 	__LINUX_MIB_XFRMMAX
 };
 
+
+/* IPv4 DSCP */
+enum
+{
+	LINUX_MIB_IPDSCP_CS0,
+	LINUX_MIB_IPDSCP_CS1,
+	LINUX_MIB_IPDSCP_CS2,
+	LINUX_MIB_IPDSCP_CS3,
+	LINUX_MIB_IPDSCP_CS4,
+	LINUX_MIB_IPDSCP_CS5,
+	LINUX_MIB_IPDSCP_CS6,
+	LINUX_MIB_IPDSCP_CS7,
+	LINUX_MIB_IPDSCP_AF11,
+	LINUX_MIB_IPDSCP_AF12,
+	LINUX_MIB_IPDSCP_AF13,
+	LINUX_MIB_IPDSCP_AF21,
+	LINUX_MIB_IPDSCP_AF22,
+	LINUX_MIB_IPDSCP_AF23,
+	LINUX_MIB_IPDSCP_AF31,
+	LINUX_MIB_IPDSCP_AF32,
+	LINUX_MIB_IPDSCP_AF33,
+	LINUX_MIB_IPDSCP_AF41,
+	LINUX_MIB_IPDSCP_AF42,
+	LINUX_MIB_IPDSCP_AF43,
+	LINUX_MIB_IPDSCP_EF,
+	__IPDSCP_MIB_MAX
+};
+
 #endif	/* _LINUX_SNMP_H */
include/net/ipdscp.h new file +65 -0

65 lines not on this page · raw message

include/net/netns/mib.h +4 -0
index 0b44112..eccbc36 100644
@@ -23,6 +23,10 @@ struct netns_mib {
 #ifdef CONFIG_XFRM_STATISTICS
 	DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
 #endif
+#ifdef CONFIG_IP_DSCP_STAT
+	struct proc_dir_entry *proc_net_ipdscp;
+	DEFINE_SNMP_STAT(struct ipdscp_mib, ipdscp_statistics);
+#endif
 };
 
 #endif
include/net/snmp.h +6 -0
index 8c842e0..fcc567e 100644
@@ -122,6 +122,12 @@ struct linux_xfrm_mib {
 	unsigned long	mibs[LINUX_MIB_XFRMMAX];
 };
 
+/* Linux IPv4 DSCP */
+#define IPDSCP_MIB_MAX	__IPDSCP_MIB_MAX
+struct ipdscp_mib {
+	unsigned long	mibs[IPDSCP_MIB_MAX];
+};
+
 /* 
  * FIXME: On x86 and some other CPUs the split into user and softirq parts
  * is not needed because addl $1,memory is atomic against interrupts (but 
net/ipv4/Kconfig +11 -0
index 70491d9..b0d3cef 100644
@@ -272,6 +272,17 @@ config IP_PIMSM_V2
 	  gated-5). This routing protocol is not used widely, so say N unless
 	  you want to play with it.
 
+config IP_DSCP_STAT
+	bool "IP: DSCP statistic"
+	help
+	  This adds IPv4 DSCP statistic to the kernel.
+	  See:
+	    * /proc/net/ipdscp
+	    * IANA dscp-registry
+	    * RFC 2474	  
+
+	  If unsure, say N.
+
 config ARPD
 	bool "IP: ARP daemon support"
 	---help---
net/ipv4/Makefile +1 -1
index 80ff87c..adcb63c 100644
@@ -11,7 +11,7 @@ obj-y     := route.o inetpeer.o protocol.o \
 	     datagram.o raw.o udp.o udplite.o \
 	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
 	     fib_frontend.o fib_semantics.o \
-	     inet_fragment.o
+	     inet_fragment.o ipdscp.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
 obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
net/ipv4/af_inet.c +3 -0
index 57737b8..c633c6a 100644
@@ -112,6 +112,7 @@
 #include <net/inet_common.h>
 #include <net/xfrm.h>
 #include <net/net_namespace.h>
+#include <net/ipdscp.h>
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 #endif
@@ -1485,6 +1486,7 @@ static __net_init int ipv4_mib_init_net(struct net *net)
 		goto err_icmpmsg_mib;
 
 	tcp_mib_init(net);
+	ipdscp_stat_init(net);
 	return 0;
 
 err_icmpmsg_mib:
@@ -1512,6 +1514,7 @@ static __net_exit void ipv4_mib_exit_net(struct net *net)
 	snmp_mib_free((void **)net->mib.net_statistics);
 	snmp_mib_free((void **)net->mib.ip_statistics);
 	snmp_mib_free((void **)net->mib.tcp_statistics);
+	ipdscp_stat_fini(net);
 }
 
 static __net_initdata struct pernet_operations ipv4_mib_ops = {
net/ipv4/ip_input.c +5 -0
index 6c98b43..ba23624 100644
@@ -143,6 +143,7 @@
 #include <net/xfrm.h>
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#include <net/ipdscp.h>
 
 /*
  *	Process Router Attention IP option
@@ -365,6 +366,10 @@ static int ip_rcv_finish(struct sk_buff *skb)
 		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
 				skb->len);
 
+#ifdef CONFIG_IP_DSCP_STAT
+	ipv4_dscp_stat(dev_net(rt->u.dst.dev), iph->tos);
+#endif
+
 	return dst_input(skb);
 
 drop:
net/ipv4/ipdscp.c new file +116 -0

116 lines not on this page · raw message

Signature · 1 line
1.6.3.3
#4 lore raw
In reply to Philip A. Prindeville

Hi Philip,

here a second PATCH to add the missing DSCP classes to ipv4_dscp_stat(), also tested against 2.6.32.

Next step is to add IN / OUT statistic to DSCP. Maybe /proc/net/ipdscp will look like:
CS0 in out
CS1 in out
...
EF in out

any comments ?
Torsten

From 58a2a79f4083fa614637cab13fe7df99b92b6fcf Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Mon, 21 Dec 2009 21:30:44 +0100
Subject: [PATCH 2/2] ipv4: add missing DSCP classes

This patch adds the missing IANA DSCP registry entries to ipv4 DSCP statistic counter. See /proc/net/ipdscp

---
 include/net/ipdscp.h |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)
include/net/ipdscp.h +19 -1
index d5bce81..14cc8a6 100644
@@ -58,7 +58,25 @@ static inline void ipv4_dscp_stat(struct net *net, __u8 dsfield)
 	switch (dsfield >> 2) {
 	case IP_DSCP_CS0:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS0);break;
 	case IP_DSCP_EF:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_EF);break;
-	/* add new entrys here ... */
+	case IP_DSCP_CS1:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS1);break;
+	case IP_DSCP_CS2:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS2);break;
+	case IP_DSCP_CS3:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS3);break;
+	case IP_DSCP_CS4:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS4);break;
+	case IP_DSCP_CS5:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS5);break;
+	case IP_DSCP_CS6:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS6);break;
+	case IP_DSCP_CS7:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS7);break;
+	case IP_DSCP_AF11:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF11);break;
+	case IP_DSCP_AF12:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF12);break;
+	case IP_DSCP_AF13:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF13);break;
+	case IP_DSCP_AF21:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF21);break;
+	case IP_DSCP_AF22:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF22);break;
+	case IP_DSCP_AF23:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF23);break;
+	case IP_DSCP_AF31:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF31);break;
+	case IP_DSCP_AF32:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF32);break;
+	case IP_DSCP_AF33:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF33);break;
+	case IP_DSCP_AF41:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF41);break;
+	case IP_DSCP_AF42:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF42);break;
+	case IP_DSCP_AF43:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF43);break;
 	}
 }
 
Signature · 1 line
1.6.3.3
#5 lore raw
Quoted 13 lines · Torsten Schmidt

Hi Philip,

here a second PATCH to add the missing DSCP classes to ipv4_dscp_stat(), also tested against 2.6.32.

Next step is to add IN / OUT statistic to DSCP. Maybe /proc/net/ipdscp will look like:
CS0 in out
CS1 in out
...
EF in out

Quoted 2 lines

any comments ?
Torsten

Hi Torsten,

Yes, the MIB changes are certainly important... we are more focused though on actually updating the default queuing strategies.

I'll poke around and see if I can figure out how that works...

Looking at include/linux/pkt_sched.h:

#define TC_PRIO_BESTEFFORT              0
#define TC_PRIO_FILLER                  1
#define TC_PRIO_BULK                    2
#define TC_PRIO_INTERACTIVE_BULK        4
#define TC_PRIO_INTERACTIVE             6
#define TC_PRIO_CONTROL                 7

it seems that these TC priorities are just random, unrelated buckets and their ordinality has no relation to their priority. Is that correct?

If that's the case, then you *can't* just do:

static inline char rt_dscp2priority(u8 tos)

{
	return IPTOS_PREC(tos)>>5;
}

for instance. No, that would be too easy. :-)

-Philip

#6 lore raw
Quoted 11 lines

I'll poke around and see if I can figure out how that works...

Looking at include/linux/pkt_sched.h:

#define TC_PRIO_BESTEFFORT              0
#define TC_PRIO_FILLER                  1
#define TC_PRIO_BULK                    2
#define TC_PRIO_INTERACTIVE_BULK        4
#define TC_PRIO_INTERACTIVE             6
#define TC_PRIO_CONTROL                 7
Quoted 2 lines

it seems that these TC priorities are just random, unrelated buckets and
their ordinality has no relation to their priority. Is that correct?

No.

1.Type Of Service Field is defined in RFC 791:

Bits 0-2:  Precedence.
Bit    3:  0 = Normal Delay,      1 = Low Delay.
Bit    4:  0 = Normal Throughput, 1 = High Throughput.
Bit    5:  0 = Normal Reliability, 1 = High Reliability.
Bits 6-7:  ECN (RFC 3168). ECN-ECT, ECN-CE

2. include/net/route.h
static inline char rt_tos2priority(u8 tos)

{
	return ip_tos2prio[IPTOS_TOS(tos)>>1];
}

- IPTOS_TOS(tos), masks 0001.1110
(from left: Delay, Throughput, Reliability, ECN-ECT)
- IPTOS_TOS(tos)>>1, generates: 0000.1111 value range: 0 .. 15.
- ip_tos2prio [ IPTOS_TOS(tos)>>1 ],
lookup table:

3. net/ipv4/route.c

const __u8 ip_tos2prio[16] = {
	TC_PRIO_BESTEFFORT,
	ECN_OR_COST(FILLER),
	TC_PRIO_BESTEFFORT,
	ECN_OR_COST(BESTEFFORT),
	TC_PRIO_BULK,
	ECN_OR_COST(BULK),
	TC_PRIO_BULK,
	ECN_OR_COST(BULK),
	TC_PRIO_INTERACTIVE,
	ECN_OR_COST(INTERACTIVE),
	TC_PRIO_INTERACTIVE,
	ECN_OR_COST(INTERACTIVE),
	TC_PRIO_INTERACTIVE_BULK,
	ECN_OR_COST(INTERACTIVE_BULK),
	TC_PRIO_INTERACTIVE_BULK,
	ECN_OR_COST(INTERACTIVE_BULK)
};

with resolved defines it would look like:
const __u8 ip_tos2prio[16] = {0 1 0 0 2 2 2 2 6 6 6 6 4 4 4 4 };

So y = rt_tos2priority(x) maps:
- - - - - - - - - - -
x y bin(x)
0 0 0000
1 1 0001 -> ECN - ECT bit set
2 0 0010 -> High Reliability bit set
3 0 0011
4 2 0100 -> High Throughput bit set
5 2 0101
6 2 0110
7 2 0111
8 6 1000 -> Low Delay bit set
9 6 1001
10 6 1010
11 6 1011
12 4 1100
13 4 1101
14 4 1110
15 4 1111

4.
High Reliability gets priority 0.
High Throughput gets priority 2.
Low Delay gets highest priority 6.

priority:
-> Low Delay (6), High Throughput (2), High Reliability (0) !

5.

Quoted 7 lines

If that's the case, then you *can't* just do:
static inline char rt_dscp2priority(u8 tos)

{
	return IPTOS_PREC(tos)>>5;
}

for instance. No, that would be too easy. :-)

No, thats right. You map:

y = rt_dscp2priority(x)
y x
- - - - - - - -
0 CS0
1 CS1
2 CS2
3 CS3
4 CS4
5 CS5
6 CS6
7 CS7

This IMHO is compliant to RFC 2474.

6. So we simply need to do:
static inline char rt_tos2priority(u8 tos)
{

#ifdef CONFIG_IP_DIFFSERV_COMPLIANT
	return tos >> 5;
#else
	return ip_tos2prio[IPTOS_TOS(tos)>>1];

#endif
}

7. -> See [PATCH]: ipv4: add DiffServ priority based routing

Enables IPv4 Differentiated Services support for IP priority based routing. Notice that the IP TOS field was redefined 1998 to DiffServ (RFC 2474). Type Of Service is deprecated since 1998 !

This patch adds a compliant flag to net/ipv4/Kconfig, which allows the user to select DiffServ ore TOS priority based routing. Default answer is TOS.

Torsten

From e7539f1d3620286559d298b81dc5ca1672af4733 Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Tue, 22 Dec 2009 12:49:54 +0100
Subject: [PATCH] ipv4: add DiffServ priority based routing

Enables IPv4 Differentiated Services support for IP priority based routing. Notice that the IP TOS field was redefined 1998 to DiffServ (RFC 2474). Type Of Service is deprecated since 1998 !

This patch adds a compliant flag to net/ipv4/Kconfig, which allows the user to select DiffServ ore TOS priority based routing. Default answer is TOS.

---
 include/net/route.h |    4 ++++
 net/ipv4/Kconfig    |   15 +++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)
include/net/route.h +4 -0
index 40f6346..8bf43a5 100644
@@ -141,7 +141,11 @@ extern const __u8 ip_tos2prio[16];
 
 static inline char rt_tos2priority(u8 tos)
 {
+#ifdef CONFIG_IP_DIFFSERV_COMPLIANT
+	return tos >> 5;
+#else
 	return ip_tos2prio[IPTOS_TOS(tos)>>1];
+#endif
 }
 
 static inline int ip_route_connect(struct rtable **rp, __be32 dst,
net/ipv4/Kconfig +15 -0
index b0d3cef..b2a79e5 100644
@@ -272,6 +272,21 @@ config IP_PIMSM_V2
 	  gated-5). This routing protocol is not used widely, so say N unless
 	  you want to play with it.
 
+config IP_DIFFSERV_COMPLIANT
+	bool "IP: DiffServ priority routing"
+	default n
+	help
+	  Enables IPv4 Differentiated Services support for IP priority based
+	  routing. If you say YES here, TOS priority based routing is disabled.
+	  Notice that the IP TOS field was redefined 1998 to DiffServ (RFC 2474). 
+	  Type Of Service is deprecated since 1998 ! So in future default answer
+	  should be YES. 
+
+	    Y: DiffServ
+	    N: Type Of Service
+
+	  If unsure, say N.
+
 config IP_DSCP_STAT
 	bool "IP: DSCP statistic"
 	help
Signature · 1 line
1.6.3.3
#7 lore raw
Quoted 126 lines · Torsten Schmidt
Quoted 11 lines

I'll poke around and see if I can figure out how that works...

Looking at include/linux/pkt_sched.h:

#define TC_PRIO_BESTEFFORT              0
#define TC_PRIO_FILLER                  1
#define TC_PRIO_BULK                    2
#define TC_PRIO_INTERACTIVE_BULK        4
#define TC_PRIO_INTERACTIVE             6
#define TC_PRIO_CONTROL                 7
Quoted 2 lines

it seems that these TC priorities are just random, unrelated buckets and
their ordinality has no relation to their priority. Is that correct?

No.

1.Type Of Service Field is defined in RFC 791:

Bits 0-2:  Precedence.
Bit    3:  0 = Normal Delay,      1 = Low Delay.
Bit    4:  0 = Normal Throughput, 1 = High Throughput.
Bit    5:  0 = Normal Reliability, 1 = High Reliability.
Bits 6-7:  ECN (RFC 3168). ECN-ECT, ECN-CE

2. include/net/route.h
static inline char rt_tos2priority(u8 tos)

{
	return ip_tos2prio[IPTOS_TOS(tos)>>1];
}

- IPTOS_TOS(tos), masks 0001.1110
(from left: Delay, Throughput, Reliability, ECN-ECT)
- IPTOS_TOS(tos)>>1, generates: 0000.1111 value range: 0 .. 15.
- ip_tos2prio [ IPTOS_TOS(tos)>>1 ],
lookup table:

3. net/ipv4/route.c

const __u8 ip_tos2prio[16] = {
	TC_PRIO_BESTEFFORT,
	ECN_OR_COST(FILLER),
	TC_PRIO_BESTEFFORT,
	ECN_OR_COST(BESTEFFORT),
	TC_PRIO_BULK,
	ECN_OR_COST(BULK),
	TC_PRIO_BULK,
	ECN_OR_COST(BULK),
	TC_PRIO_INTERACTIVE,
	ECN_OR_COST(INTERACTIVE),
	TC_PRIO_INTERACTIVE,
	ECN_OR_COST(INTERACTIVE),
	TC_PRIO_INTERACTIVE_BULK,
	ECN_OR_COST(INTERACTIVE_BULK),
	TC_PRIO_INTERACTIVE_BULK,
	ECN_OR_COST(INTERACTIVE_BULK)
};

with resolved defines it would look like:
const __u8 ip_tos2prio[16] = {0 1 0 0 2 2 2 2 6 6 6 6 4 4 4 4 };

So y = rt_tos2priority(x) maps:
- - - - - - - - - - -
x y bin(x)
0 0 0000
1 1 0001 -> ECN - ECT bit set
2 0 0010 -> High Reliability bit set
3 0 0011
4 2 0100 -> High Throughput bit set
5 2 0101
6 2 0110
7 2 0111
8 6 1000 -> Low Delay bit set
9 6 1001
10 6 1010
11 6 1011
12 4 1100
13 4 1101
14 4 1110
15 4 1111

4.
High Reliability gets priority 0.
High Throughput gets priority 2.
Low Delay gets highest priority 6.

priority:
-> Low Delay (6), High Throughput (2), High Reliability (0) !

5.

Quoted 7 lines

If that's the case, then you *can't* just do:
static inline char rt_dscp2priority(u8 tos)

{
	return IPTOS_PREC(tos)>>5;
}

for instance. No, that would be too easy. :-)

No, thats right. You map:

y = rt_dscp2priority(x)
y x
- - - - - - - -
0 CS0
1 CS1
2 CS2
3 CS3
4 CS4
5 CS5
6 CS6
7 CS7

This IMHO is compliant to RFC 2474.

6. So we simply need to do:
static inline char rt_tos2priority(u8 tos)
{

#ifdef CONFIG_IP_DIFFSERV_COMPLIANT
	return tos >> 5;
#else
	return ip_tos2prio[IPTOS_TOS(tos)>>1];

#endif
}

7. -> See [PATCH]: ipv4: add DiffServ priority based routing

Enables IPv4 Differentiated Services support for IP priority based routing. Notice that the IP TOS field was redefined 1998 to DiffServ (RFC 2474). Type Of Service is deprecated since 1998 !

Quoted 10 lines

This patch adds a compliant flag to net/ipv4/Kconfig, which allows the user to select DiffServ ore TOS priority based routing. Default answer is TOS.

Torsten

Can you extend the patch to include classify_1d() in net/mac80211/wme.c?

I'm thinking:

         }

- if (dscp & 0x1c)
+#if !defined(CONFIG_IP_DIFFSERV_COMPLIANT)
+ if (IPTOS_TOS(dscp) & ~IPTOS_LOWCOST)

                 return 0;
+#endif
         return dscp >> 5;

}

should do it.

-Philip

#8 lore raw

Review

Quoted 13 lines

Can you extend the patch to include classify_1d() in net/mac80211/wme.c?

I'm thinking:

         }
(quoted diff) +3 -1
-        if (dscp & 0x1c)
+#if !defined(CONFIG_IP_DIFFSERV_COMPLIANT)
+        if (IPTOS_TOS(dscp) & ~IPTOS_LOWCOST)
                 return 0;
+#endif
         return dscp >> 5;
 }

This code segment seems to be older stuff. Its not in 2.6.32.

Torsten

#9 lore raw
Quoted 15 lines · Torsten Schmidt

Review

Quoted 13 lines

Can you extend the patch to include classify_1d() in net/mac80211/wme.c?

I'm thinking:

         }
(quoted diff) +3 -1
-        if (dscp & 0x1c)
+#if !defined(CONFIG_IP_DIFFSERV_COMPLIANT)
+        if (IPTOS_TOS(dscp) & ~IPTOS_LOWCOST)
                 return 0;
+#endif
         return dscp >> 5;
 }

This code segment seems to be older stuff. Its not in 2.6.32.

Quoted 1 line

Torsten

I'm running 2.6.27.42.

#10 lore raw

Hi Philip,

this patch series adds IP DiffServ OUT counters and renames /proc/net/ipdscp to /proc/net/ip_dscp to stay compatible.

See:
---
ipv4: prepare DSCP statistic for IN/OUT counters
ipv4: add DSCP OUT statistic
ipv4: change DSCP proc file name
---

Torsten

From 1e34debd128e09f22ffc00b4cb7cc5f1de52e2ff Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Tue, 5 Jan 2010 09:34:02 +0100
Subject: [PATCH 1/3] ipv4: prepare DSCP statistic for IN/OUT counters

some renames and cleanups.

---
 include/net/ipdscp.h    |   52 +++++++++++++++++++++-------------------------
 include/net/netns/mib.h |    2 +-
 net/ipv4/ip_input.c     |    2 +-
 net/ipv4/ipdscp.c       |    8 +++---
 4 files changed, 30 insertions(+), 34 deletions(-)
include/net/ipdscp.h +24 -28
index 14cc8a6..4236704 100644
@@ -39,13 +39,9 @@
 #define IP_DSCP_EF	(0x2E)
 
 #ifdef CONFIG_IP_DSCP_STAT
-#define IP_DSCP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.ipdscp_statistics, field)
-#define IP_DSCP_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.ipdscp_statistics, field)
-#define IP_DSCP_INC_STATS_USER(net, field)	SNMP_INC_STATS_USER((net)-mib.ipdscp_statistics, field)
+#define IP_DSCPIN_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.ipdscp_in_statistics, field)
 #else
-#define IP_DSCP_INC_STATS(net, field)	((void)(net))
-#define IP_DSCP_INC_STATS_BH(net, field)	((void)(net))
-#define IP_DSCP_INC_STATS_USER(net, field)	((void)(net))
+#define IP_DSCPIN_INC_STATS_BH(net, field)	((void)(net))
 #endif
 
 
@@ -53,30 +49,30 @@ int __net_init ipdscp_stat_init(struct net *net);
 void ipdscp_stat_fini(struct net *net);
 
 
-static inline void ipv4_dscp_stat(struct net *net, __u8 dsfield)
+static inline void ipv4_dscp_stat_in(struct net *net, __u8 dsfield)
 {
 	switch (dsfield >> 2) {
-	case IP_DSCP_CS0:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS0);break;
-	case IP_DSCP_EF:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_EF);break;
-	case IP_DSCP_CS1:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS1);break;
-	case IP_DSCP_CS2:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS2);break;
-	case IP_DSCP_CS3:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS3);break;
-	case IP_DSCP_CS4:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS4);break;
-	case IP_DSCP_CS5:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS5);break;
-	case IP_DSCP_CS6:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS6);break;
-	case IP_DSCP_CS7:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS7);break;
-	case IP_DSCP_AF11:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF11);break;
-	case IP_DSCP_AF12:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF12);break;
-	case IP_DSCP_AF13:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF13);break;
-	case IP_DSCP_AF21:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF21);break;
-	case IP_DSCP_AF22:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF22);break;
-	case IP_DSCP_AF23:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF23);break;
-	case IP_DSCP_AF31:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF31);break;
-	case IP_DSCP_AF32:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF32);break;
-	case IP_DSCP_AF33:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF33);break;
-	case IP_DSCP_AF41:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF41);break;
-	case IP_DSCP_AF42:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF42);break;
-	case IP_DSCP_AF43:	IP_DSCP_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF43);break;
+	case IP_DSCP_CS0:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS0);break;
+	case IP_DSCP_EF:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_EF);break;
+	case IP_DSCP_CS1:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS1);break;
+	case IP_DSCP_CS2:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS2);break;
+	case IP_DSCP_CS3:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS3);break;
+	case IP_DSCP_CS4:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS4);break;
+	case IP_DSCP_CS5:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS5);break;
+	case IP_DSCP_CS6:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS6);break;
+	case IP_DSCP_CS7:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_CS7);break;
+	case IP_DSCP_AF11:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF11);break;
+	case IP_DSCP_AF12:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF12);break;
+	case IP_DSCP_AF13:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF13);break;
+	case IP_DSCP_AF21:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF21);break;
+	case IP_DSCP_AF22:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF22);break;
+	case IP_DSCP_AF23:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF23);break;
+	case IP_DSCP_AF31:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF31);break;
+	case IP_DSCP_AF32:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF32);break;
+	case IP_DSCP_AF33:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF33);break;
+	case IP_DSCP_AF41:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF41);break;
+	case IP_DSCP_AF42:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF42);break;
+	case IP_DSCP_AF43:	IP_DSCPIN_INC_STATS_BH(net, LINUX_MIB_IPDSCP_AF43);break;
 	}
 }
 
include/net/netns/mib.h +1 -1
index eccbc36..a849e89 100644
@@ -25,7 +25,7 @@ struct netns_mib {
 #endif
 #ifdef CONFIG_IP_DSCP_STAT
 	struct proc_dir_entry *proc_net_ipdscp;
-	DEFINE_SNMP_STAT(struct ipdscp_mib, ipdscp_statistics);
+	DEFINE_SNMP_STAT(struct ipdscp_mib, ipdscp_in_statistics);
 #endif
 };
 
net/ipv4/ip_input.c +1 -1
index ba23624..ba8cd2c 100644
@@ -367,7 +367,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
 				skb->len);
 
 #ifdef CONFIG_IP_DSCP_STAT
-	ipv4_dscp_stat(dev_net(rt->u.dst.dev), iph->tos);
+	ipv4_dscp_stat_in(dev_net(rt->u.dst.dev), iph->tos);
 #endif
 
 	return dst_input(skb);
net/ipv4/ipdscp.c +4 -4
index 90f9fd1..fdbfb7b 100644
@@ -47,7 +47,7 @@ static int ipdscp_statistics_seq_show(struct seq_file *seq, void *v)
 	int i;
 	for (i=0; ipdscp_mib_list[i].name; i++)
 		seq_printf(seq, "%-24s\t%lu\n", ipdscp_mib_list[i].name,
-			   snmp_fold_field((void **)net->mib.ipdscp_statistics,
+			   snmp_fold_field((void **)net->mib.ipdscp_in_statistics,
 					   ipdscp_mib_list[i].entry));
 	return 0;
 }
@@ -87,19 +87,19 @@ int __net_init ipdscp_stat_init(struct net *net)
 {
 	int rv;
 
-	if (snmp_mib_init((void **)net->mib.ipdscp_statistics,
+	if (snmp_mib_init((void **)net->mib.ipdscp_in_statistics,
 			  sizeof(struct ipdscp_mib)) < 0)
 		return -ENOMEM;
 	rv = ipdscp_proc_init(net);
 	if (rv < 0)
-		snmp_mib_free((void **)net->mib.ipdscp_statistics);
+		snmp_mib_free((void **)net->mib.ipdscp_in_statistics);
 	return rv;
 }
 
 void ipdscp_stat_fini(struct net *net)
 {
 	ipdscp_proc_fini(net);
-	snmp_mib_free((void **)net->mib.ipdscp_statistics);
+	snmp_mib_free((void **)net->mib.ipdscp_in_statistics);
 }
 
 
Signature · 1 line
1.6.3.3

From 6ee7c2ef1260fd9b700893aa05c3d2a770d65e45 Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Tue, 5 Jan 2010 09:34:51 +0100
Subject: [PATCH 2/3] ipv4: add DSCP OUT statistic

---
 include/net/ipdscp.h    |   31 +++++++++++++++++++++++++++++++
 include/net/netns/mib.h |    1 +
 net/ipv4/ip_output.c    |    5 +++++
 net/ipv4/ipdscp.c       |   21 ++++++++++++++++-----
 4 files changed, 53 insertions(+), 5 deletions(-)
include/net/ipdscp.h +31 -0
index 4236704..c14f523 100644
@@ -38,10 +38,13 @@
 #define IP_DSCP_AF43	(0x26)
 #define IP_DSCP_EF	(0x2E)
 
+
 #ifdef CONFIG_IP_DSCP_STAT
 #define IP_DSCPIN_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.ipdscp_in_statistics, field)
+#define IP_DSCPOUT_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.ipdscp_out_statistics, field)
 #else
 #define IP_DSCPIN_INC_STATS_BH(net, field)	((void)(net))
+#define IP_DSCPOUT_INC_STATS(net, field)	((void)(net))
 #endif
 
 
@@ -76,4 +79,32 @@ static inline void ipv4_dscp_stat_in(struct net *net, __u8 dsfield)
 	}
 }
 
+
+static inline void ipv4_dscp_stat_out(struct net *net, __u8 dsfield)
+{
+	switch (dsfield >> 2) {
+	case IP_DSCP_CS0:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS0);break;
+	case IP_DSCP_EF:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_EF);break;
+	case IP_DSCP_CS1:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS1);break;
+	case IP_DSCP_CS2:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS2);break;
+	case IP_DSCP_CS3:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS3);break;
+	case IP_DSCP_CS4:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS4);break;
+	case IP_DSCP_CS5:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS5);break;
+	case IP_DSCP_CS6:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS6);break;
+	case IP_DSCP_CS7:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_CS7);break;
+	case IP_DSCP_AF11:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF11);break;
+	case IP_DSCP_AF12:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF12);break;
+	case IP_DSCP_AF13:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF13);break;
+	case IP_DSCP_AF21:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF21);break;
+	case IP_DSCP_AF22:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF22);break;
+	case IP_DSCP_AF23:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF23);break;
+	case IP_DSCP_AF31:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF31);break;
+	case IP_DSCP_AF32:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF32);break;
+	case IP_DSCP_AF33:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF33);break;
+	case IP_DSCP_AF41:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF41);break;
+	case IP_DSCP_AF42:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF42);break;
+	case IP_DSCP_AF43:	IP_DSCPOUT_INC_STATS(net, LINUX_MIB_IPDSCP_AF43);break;
+	}
+}
+
 #endif
include/net/netns/mib.h +1 -0
index a849e89..183f15b 100644
@@ -26,6 +26,7 @@ struct netns_mib {
 #ifdef CONFIG_IP_DSCP_STAT
 	struct proc_dir_entry *proc_net_ipdscp;
 	DEFINE_SNMP_STAT(struct ipdscp_mib, ipdscp_in_statistics);
+	DEFINE_SNMP_STAT(struct ipdscp_mib, ipdscp_out_statistics);
 #endif
 };
 
net/ipv4/ip_output.c +5 -0
index f989518..e14eca8 100644
@@ -79,6 +79,7 @@
 #include <linux/mroute.h>
 #include <linux/netlink.h>
 #include <linux/tcp.h>
+#include <net/ipdscp.h>
 
 int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
 
@@ -300,6 +301,10 @@ int ip_output(struct sk_buff *skb)
 
 	IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
 
+#ifdef CONFIG_IP_DSCP_STAT
+	ipv4_dscp_stat_out(dev_net(dev), ip_hdr(skb)->tos);
+#endif
+
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_IP);
 
net/ipv4/ipdscp.c +16 -5
index fdbfb7b..8988ccb 100644
@@ -46,8 +46,10 @@ static int ipdscp_statistics_seq_show(struct seq_file *seq, void *v)
 	struct net *net = seq->private;
 	int i;
 	for (i=0; ipdscp_mib_list[i].name; i++)
-		seq_printf(seq, "%-24s\t%lu\n", ipdscp_mib_list[i].name,
+		seq_printf(seq, "%-24s\t%lu\t%lu\n", ipdscp_mib_list[i].name,
 			   snmp_fold_field((void **)net->mib.ipdscp_in_statistics,
+					   ipdscp_mib_list[i].entry),
+			   snmp_fold_field((void **)net->mib.ipdscp_out_statistics,
 					   ipdscp_mib_list[i].entry));
 	return 0;
 }
@@ -89,11 +91,20 @@ int __net_init ipdscp_stat_init(struct net *net)
 
 	if (snmp_mib_init((void **)net->mib.ipdscp_in_statistics,
 			  sizeof(struct ipdscp_mib)) < 0)
-		return -ENOMEM;
+		goto err_ipdscp_in;
+	if (snmp_mib_init((void **)net->mib.ipdscp_out_statistics,
+			  sizeof(struct ipdscp_mib)) < 0)
+		goto err_ipdscp_out;
+
 	rv = ipdscp_proc_init(net);
-	if (rv < 0)
-		snmp_mib_free((void **)net->mib.ipdscp_in_statistics);
-	return rv;
+	if (rv >= 0) 
+		return 0;	
+
+err_ipdscp_out:
+	snmp_mib_free((void **)net->mib.ipdscp_out_statistics);
+err_ipdscp_in:
+	snmp_mib_free((void **)net->mib.ipdscp_in_statistics);	
+	return -ENOMEM;
 }
 
 void ipdscp_stat_fini(struct net *net)
Signature · 1 line
1.6.3.3

From 54f9a93d6476dc47c9ca87f3350187011039adf9 Mon Sep 17 00:00:00 2001
From: Torsten Schmidt <[email protected]>
Date: Mon, 11 Jan 2010 14:49:48 +0100
Subject: [PATCH 3/3] ipv4: change DSCP proc file name

---
 net/ipv4/ipdscp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/ipv4/ipdscp.c +1 -1
index 8988ccb..151623a 100644
@@ -72,7 +72,7 @@ static const struct file_operations ipdscp_statistics_seq_fops = {
 
 static int __net_init ipdscp_proc_init(struct net *net)
 {
-	if (!proc_net_fops_create(net, "ipdscp", S_IRUGO,
+	if (!proc_net_fops_create(net, "ip_dscp", S_IRUGO,
 				  &ipdscp_statistics_seq_fops))
 		return -ENOMEM;
 	return 0;
Signature · 1 line
1.6.3.3
#11 lore raw
In reply to Philip A. Prindeville

Digging some more (at least through the 2.6.27.38 source) I also find:

/* Given a data frame determine the 802.1p/1d tag to use. */ static unsigned int classify_1d(struct sk_buff *skb)

{
        unsigned int dscp;

        /* skb->priority values from 256->263 are magic values to
         * directly indicate a specific 802.1d priority.  This is used
         * to allow 802.1d priority to be passed directly in from VLAN
         * tags, etc.
         */
        if (skb->priority >= 256 && skb->priority <= 263)
                return skb->priority - 256;

        switch (skb->protocol) {
        case __constant_htons(ETH_P_IP):
                dscp = ip_hdr(skb)->tos & 0xfc;
                break;

        default:
                return 0;
        }

        if (dscp & 0x1c)
                return 0;
        return dscp >> 5;
}

in net/mac80211/wme.c

This won't work with DSCP values because they do set bits 0x10 and 0x80. In fact... looking at netinet/ip.h:

/*
* Definitions for IP type of service (ip_tos)
*/

#define IPTOS_TOS_MASK          0x1E
#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)
#define IPTOS_LOWDELAY          0x10
#define IPTOS_THROUGHPUT        0x08
#define IPTOS_RELIABILITY       0x04
#define IPTOS_LOWCOST           0x02
#define IPTOS_MINCOST           IPTOS_LOWCOST

I'm not even sure why the IPTOS_LOWCOST bit is left out of the check...

-Philip

Quoted 80 lines · Philip A. Prindeville

[ Posted to linux-net a couple of days ago and didn't hear back... so reposting here since this might be more appropriate. ]

I'm looking at net/ipv4/ip_sockglue.c:

   512		case IP_TOS:	/* This sets both TOS and Precedence */
   513			if (sk->sk_type == SOCK_STREAM) {
   514				val &= ~3;
   515				val |= inet->tos & 3;
   516			}
   517			if (inet->tos != val) {
   518				inet->tos = val;
   519				sk->sk_priority = rt_tos2priority(val);
   520				sk_dst_reset(sk);
   521			}
   522			break;

and include/net/route.h:

   141	extern const __u8 ip_tos2prio[16];
   142	
   143	static inline char rt_tos2priority(u8 tos)
   144	{
   145		return ip_tos2prio[IPTOS_TOS(tos)>>1];
   146	}

and finally net/ipv4/route.c:

   165	#define ECN_OR_COST(class)	TC_PRIO_##class
   166	
   167	const __u8 ip_tos2prio[16] = {
   168		TC_PRIO_BESTEFFORT,
   169		ECN_OR_COST(FILLER),
   170		TC_PRIO_BESTEFFORT,
   171		ECN_OR_COST(BESTEFFORT),
   172		TC_PRIO_BULK,
   173		ECN_OR_COST(BULK),
   174		TC_PRIO_BULK,
   175		ECN_OR_COST(BULK),
   176		TC_PRIO_INTERACTIVE,
   177		ECN_OR_COST(INTERACTIVE),
   178		TC_PRIO_INTERACTIVE,
   179		ECN_OR_COST(INTERACTIVE),
   180		TC_PRIO_INTERACTIVE_BULK,
   181		ECN_OR_COST(INTERACTIVE_BULK),
   182		TC_PRIO_INTERACTIVE_BULK,
   183		ECN_OR_COST(INTERACTIVE_BULK)
   184	};

and it's slowly dawning on me that we're using an interpretation of the IP_TOS (and ip.ip_tos field) values that have been deprecated since 1998! Quoting RFC 2474:

3. Differentiated Services Field Definition

A replacement header field, called the DS field, is defined, which is intended to supersede the existing definitions of the IPv4 TOS octet [RFC791] and the IPv6 Traffic Class octet [IPv6].

Seems pretty clear, right? That DSCP is the new testament, here to replace the old testament... although if you look closely, the precedence values of IPTOS_PREC_ROUTINE looks a lot like IPTOS_CLASS_CS0, etc... so some backward compatibility was maintained. (See http://sourceware.org/bugzilla/show_bug.cgi?id=11027 and http://sourceware.org/bugzilla/show_bug.cgi?id=10789 if your glibc doesn't yet include the the IPTOS_CLASS_CSn and IPTOS_DSCP_AFxx values).

And indeed, only routers seem to pay attention to bits in the 0x1c space... I.e. between the upper 3 bits which still mean precedence, and the lower 2 bits which now signify experienced-congestion-notification (ECN).

Assuming that whatever the local host does to the output of the packet, that it's not going to sufficiently delay the packet enough because we're connected to some fast media (Fast ethernet, etc) then what we do locally shouldn't matter... unless of course we're using 802.1p tagging, in which case we can seriously mess up what happens next.

So how is it that no one noticed this issue yet, and given that Linux is used in a fair number of commercial embedded real-time boxes (like satellite and IPTV set-top boxes)... how are they not impacted by this?

Assuming my crusade to get various common apps and services (wget, TB, FF, Sendmail, Cyrus, ProFTPd, etc) to use DSCP/CS marking (very few apps currently use DSCP or precedence marking), then kernels with the proper default behavior will need to start shipping, right? I.e. out-of-the-box kernels should handle such apps without further configuration, such as needing to have the DSCP iptables module installed. They should "just work".

Thanks,

-Philip

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html