aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet_ecn.h76
-rw-r--r--net/ipv4/ip_gre.c38
-rw-r--r--net/ipv4/ipip.c42
-rw-r--r--net/ipv6/ip6_gre.c54
4 files changed, 147 insertions, 63 deletions
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 2fa14691869c..aab73757bc4d 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -15,6 +15,8 @@ enum {
15 INET_ECN_MASK = 3, 15 INET_ECN_MASK = 3,
16}; 16};
17 17
18extern int sysctl_tunnel_ecn_log;
19
18static inline int INET_ECN_is_ce(__u8 dsfield) 20static inline int INET_ECN_is_ce(__u8 dsfield)
19{ 21{
20 return (dsfield & INET_ECN_MASK) == INET_ECN_CE; 22 return (dsfield & INET_ECN_MASK) == INET_ECN_CE;
@@ -145,4 +147,78 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb)
145 return 0; 147 return 0;
146} 148}
147 149
150/*
151 * RFC 6080 4.2
152 * To decapsulate the inner header at the tunnel egress, a compliant
153 * tunnel egress MUST set the outgoing ECN field to the codepoint at the
154 * intersection of the appropriate arriving inner header (row) and outer
155 * header (column) in Figure 4
156 *
157 * +---------+------------------------------------------------+
158 * |Arriving | Arriving Outer Header |
159 * | Inner +---------+------------+------------+------------+
160 * | Header | Not-ECT | ECT(0) | ECT(1) | CE |
161 * +---------+---------+------------+------------+------------+
162 * | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)|
163 * | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE |
164 * | ECT(1) | ECT(1) | ECT(1) (!) | ECT(1) | CE |
165 * | CE | CE | CE | CE(!!!)| CE |
166 * +---------+---------+------------+------------+------------+
167 *
168 * Figure 4: New IP in IP Decapsulation Behaviour
169 *
170 * returns 0 on success
171 * 1 if something is broken and should be logged (!!! above)
172 * 2 if packet should be dropped
173 */
174static inline int INET_ECN_decapsulate(struct sk_buff *skb,
175 __u8 outer, __u8 inner)
176{
177 if (INET_ECN_is_not_ect(inner)) {
178 switch (outer & INET_ECN_MASK) {
179 case INET_ECN_NOT_ECT:
180 return 0;
181 case INET_ECN_ECT_0:
182 case INET_ECN_ECT_1:
183 return 1;
184 case INET_ECN_CE:
185 return 2;
186 }
187 }
188
189 if (INET_ECN_is_ce(outer))
190 INET_ECN_set_ce(skb);
191
192 return 0;
193}
194
195static inline int IP_ECN_decapsulate(const struct iphdr *oiph,
196 struct sk_buff *skb)
197{
198 __u8 inner;
199
200 if (skb->protocol == htons(ETH_P_IP))
201 inner = ip_hdr(skb)->tos;
202 else if (skb->protocol == htons(ETH_P_IPV6))
203 inner = ipv6_get_dsfield(ipv6_hdr(skb));
204 else
205 return 0;
206
207 return INET_ECN_decapsulate(skb, oiph->tos, inner);
208}
209
210static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h,
211 struct sk_buff *skb)
212{
213 __u8 inner;
214
215 if (skb->protocol == htons(ETH_P_IP))
216 inner = ip_hdr(skb)->tos;
217 else if (skb->protocol == htons(ETH_P_IPV6))
218 inner = ipv6_get_dsfield(ipv6_hdr(skb));
219 else
220 return 0;
221
222 return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner);
223}
148#endif 224#endif
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 1c012cb2cb94..ef0b861ce044 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -120,6 +120,10 @@
120 Alexey Kuznetsov. 120 Alexey Kuznetsov.
121 */ 121 */
122 122
123static bool log_ecn_error = true;
124module_param(log_ecn_error, bool, 0644);
125MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
126
123static struct rtnl_link_ops ipgre_link_ops __read_mostly; 127static struct rtnl_link_ops ipgre_link_ops __read_mostly;
124static int ipgre_tunnel_init(struct net_device *dev); 128static int ipgre_tunnel_init(struct net_device *dev);
125static void ipgre_tunnel_setup(struct net_device *dev); 129static void ipgre_tunnel_setup(struct net_device *dev);
@@ -204,7 +208,9 @@ static struct rtnl_link_stats64 *ipgre_get_stats64(struct net_device *dev,
204 tot->rx_crc_errors = dev->stats.rx_crc_errors; 208 tot->rx_crc_errors = dev->stats.rx_crc_errors;
205 tot->rx_fifo_errors = dev->stats.rx_fifo_errors; 209 tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
206 tot->rx_length_errors = dev->stats.rx_length_errors; 210 tot->rx_length_errors = dev->stats.rx_length_errors;
211 tot->rx_frame_errors = dev->stats.rx_frame_errors;
207 tot->rx_errors = dev->stats.rx_errors; 212 tot->rx_errors = dev->stats.rx_errors;
213
208 tot->tx_fifo_errors = dev->stats.tx_fifo_errors; 214 tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
209 tot->tx_carrier_errors = dev->stats.tx_carrier_errors; 215 tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
210 tot->tx_dropped = dev->stats.tx_dropped; 216 tot->tx_dropped = dev->stats.tx_dropped;
@@ -587,17 +593,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
587 t->err_time = jiffies; 593 t->err_time = jiffies;
588} 594}
589 595
590static inline void ipgre_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
591{
592 if (INET_ECN_is_ce(iph->tos)) {
593 if (skb->protocol == htons(ETH_P_IP)) {
594 IP_ECN_set_ce(ip_hdr(skb));
595 } else if (skb->protocol == htons(ETH_P_IPV6)) {
596 IP6_ECN_set_ce(ipv6_hdr(skb));
597 }
598 }
599}
600
601static inline u8 596static inline u8
602ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb) 597ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb)
603{ 598{
@@ -620,6 +615,7 @@ static int ipgre_rcv(struct sk_buff *skb)
620 struct ip_tunnel *tunnel; 615 struct ip_tunnel *tunnel;
621 int offset = 4; 616 int offset = 4;
622 __be16 gre_proto; 617 __be16 gre_proto;
618 int err;
623 619
624 if (!pskb_may_pull(skb, 16)) 620 if (!pskb_may_pull(skb, 16))
625 goto drop; 621 goto drop;
@@ -723,17 +719,27 @@ static int ipgre_rcv(struct sk_buff *skb)
723 skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 719 skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
724 } 720 }
725 721
722 __skb_tunnel_rx(skb, tunnel->dev);
723
724 skb_reset_network_header(skb);
725 err = IP_ECN_decapsulate(iph, skb);
726 if (unlikely(err)) {
727 if (log_ecn_error)
728 net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
729 &iph->saddr, iph->tos);
730 if (err > 1) {
731 ++tunnel->dev->stats.rx_frame_errors;
732 ++tunnel->dev->stats.rx_errors;
733 goto drop;
734 }
735 }
736
726 tstats = this_cpu_ptr(tunnel->dev->tstats); 737 tstats = this_cpu_ptr(tunnel->dev->tstats);
727 u64_stats_update_begin(&tstats->syncp); 738 u64_stats_update_begin(&tstats->syncp);
728 tstats->rx_packets++; 739 tstats->rx_packets++;
729 tstats->rx_bytes += skb->len; 740 tstats->rx_bytes += skb->len;
730 u64_stats_update_end(&tstats->syncp); 741 u64_stats_update_end(&tstats->syncp);
731 742
732 __skb_tunnel_rx(skb, tunnel->dev);
733
734 skb_reset_network_header(skb);
735 ipgre_ecn_decapsulate(iph, skb);
736
737 netif_rx(skb); 743 netif_rx(skb);
738 744
739 return 0; 745 return 0;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 618bde867ac1..e15b45297c09 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -120,6 +120,10 @@
120#define HASH_SIZE 16 120#define HASH_SIZE 16
121#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) 121#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
122 122
123static bool log_ecn_error = true;
124module_param(log_ecn_error, bool, 0644);
125MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");