summaryrefslogtreecommitdiffstats
path: root/include/net
diff options
context:
space:
mode:
Diffstat (limited to 'include/net')
-rw-r--r--include/net/inet_ecn.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 2fa14691869..aab73757bc4 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -15,6 +15,8 @@ enum {
INET_ECN_MASK = 3,
};
+extern int sysctl_tunnel_ecn_log;
+
static inline int INET_ECN_is_ce(__u8 dsfield)
{
return (dsfield & INET_ECN_MASK) == INET_ECN_CE;
@@ -145,4 +147,78 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb)
return 0;
}
+/*
+ * RFC 6080 4.2
+ * To decapsulate the inner header at the tunnel egress, a compliant
+ * tunnel egress MUST set the outgoing ECN field to the codepoint at the
+ * intersection of the appropriate arriving inner header (row) and outer
+ * header (column) in Figure 4
+ *
+ * +---------+------------------------------------------------+
+ * |Arriving | Arriving Outer Header |
+ * | Inner +---------+------------+------------+------------+
+ * | Header | Not-ECT | ECT(0) | ECT(1) | CE |
+ * +---------+---------+------------+------------+------------+
+ * | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)|
+ * | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE |
+ * | ECT(1) | ECT(1) | ECT(1) (!) | ECT(1) | CE |
+ * | CE | CE | CE | CE(!!!)| CE |
+ * +---------+---------+------------+------------+------------+
+ *
+ * Figure 4: New IP in IP Decapsulation Behaviour
+ *
+ * returns 0 on success
+ * 1 if something is broken and should be logged (!!! above)
+ * 2 if packet should be dropped
+ */
+static inline int INET_ECN_decapsulate(struct sk_buff *skb,
+ __u8 outer, __u8 inner)
+{
+ if (INET_ECN_is_not_ect(inner)) {
+ switch (outer & INET_ECN_MASK) {
+ case INET_ECN_NOT_ECT:
+ return 0;
+ case INET_ECN_ECT_0:
+ case INET_ECN_ECT_1:
+ return 1;
+ case INET_ECN_CE:
+ return 2;
+ }
+ }
+
+ if (INET_ECN_is_ce(outer))
+ INET_ECN_set_ce(skb);
+
+ return 0;
+}
+
+static inline int IP_ECN_decapsulate(const struct iphdr *oiph,
+ struct sk_buff *skb)
+{
+ __u8 inner;
+
+ if (skb->protocol == htons(ETH_P_IP))
+ inner = ip_hdr(skb)->tos;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ inner = ipv6_get_dsfield(ipv6_hdr(skb));
+ else
+ return 0;
+
+ return INET_ECN_decapsulate(skb, oiph->tos, inner);
+}
+
+static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h,
+ struct sk_buff *skb)
+{
+ __u8 inner;
+
+ if (skb->protocol == htons(ETH_P_IP))
+ inner = ip_hdr(skb)->tos;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ inner = ipv6_get_dsfield(ipv6_hdr(skb));
+ else
+ return 0;
+
+ return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner);
+}
#endif