Thread (12 messages) 12 messages, 6 authors, 2017-09-02

[PATCH] Add TX limit for SocketCAN.

From: <hidden>
Date: 2017-09-01 02:13:03
Subsystem: can network layer, the rest · Maintainers: Oliver Hartkopp, Marc Kleine-Budde, Linus Torvalds

From: "Shi, Zhongjie" <redacted>

This will be used to prevent malicious or unintentional
flooding of messages via SocketCAN.

Change-Id: I6c2e122e12a594d9ad7dc4bdeebe15a1929eb893
Tracked-On: https://jira01.devtools.intel.com/browse/OAM-48496
Signed-off-by: Shi, Zhongjie <redacted>
---
 net/can/Kconfig  | 13 +++++++++++++
 net/can/af_can.c | 15 +++++++++++++++
 net/can/af_can.h |  5 +++++
 net/can/proc.c   | 13 +++++++++++++
 4 files changed, 46 insertions(+)
diff --git a/net/can/Kconfig b/net/can/Kconfig
index a15c0e0..aeba3d0 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -51,6 +51,19 @@ config CAN_GW
 	  They can be modified with AND/OR/XOR/SET operations as configured
 	  by the netlink configuration interface known e.g. from iptables.
 
+config CAN_TX_ATTEMPT_RATE_LIMIT
+	int "Tx attempt rate limit"
+	default "5"
+	---help---
+	  This TX attempt rate limit can be used to prevent flood of messages
+	  from user space. It's TX "attempt" rate here instead of the "actual"
+	  TX rate because we do the statistics for the TX attempt no matter if
+	  the message TX is actually sent successful or not. The current
+	  default value is "5" which means 5 messages per second that is proper
+	  for an in-vehicle infotainment (IVI) system. For the use cases other
+	  than IVI, this can be set to the value corresponding to the specific
+	  requirement.
+
 source "drivers/net/can/Kconfig"
 
 endif
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 88edac0..4981c15 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -83,6 +83,9 @@ static DEFINE_MUTEX(proto_tab_lock);
 
 static atomic_t skbcounter = ATOMIC_INIT(0);
 
+#define SOCK_TX_ATTEMPT_RATE_LIMIT    (CONFIG_CAN_TX_ATTEMPT_RATE_LIMIT)
+
+
 /*
  * af_can socket functions
  */
@@ -212,6 +215,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
  *  -EPERM when trying to send on a non-CAN interface
  *  -EMSGSIZE CAN frame size is bigger than CAN interface MTU
  *  -EINVAL when the skb->data does not contain a valid CAN frame
+ *  -EDQUOT when current tx rate reach its limit
  */
 int can_send(struct sk_buff *skb, int loop)
 {
@@ -251,6 +255,17 @@ int can_send(struct sk_buff *skb, int loop)
 		goto inval_skb;
 	}
 
+	/* update statistics */
+	can_stats->tx_attempt_frames++;
+	can_stats->tx_frames_attempt_delta++;
+
+	/* throttle if needed */
+	if (can_stats->current_tx_attempt_rate > SOCK_TX_ATTEMPT_RATE_LIMIT) {
+		printk_ratelimited(KERN_WARNING "can: inhibit tx due to "
+			"attempt rate: %lu\n", can_stats->current_tx_attempt_rate);
+		return EDQUOT;
+	}
+
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 
 	skb_reset_mac_header(skb);
diff --git a/net/can/af_can.h b/net/can/af_can.h
index d0ef45b..6f50e82 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -83,22 +83,27 @@ struct s_stats {
 
 	unsigned long rx_frames;
 	unsigned long tx_frames;
+	unsigned long tx_attempt_frames;
 	unsigned long matches;
 
 	unsigned long total_rx_rate;
 	unsigned long total_tx_rate;
+	unsigned long total_tx_attempt_rate;
 	unsigned long total_rx_match_ratio;
 
 	unsigned long current_rx_rate;
 	unsigned long current_tx_rate;
+	unsigned long current_tx_attempt_rate;
 	unsigned long current_rx_match_ratio;
 
 	unsigned long max_rx_rate;
 	unsigned long max_tx_rate;
+	unsigned long max_tx_attempt_rate;
 	unsigned long max_rx_match_ratio;
 
 	unsigned long rx_frames_delta;
 	unsigned long tx_frames_delta;
+	unsigned long tx_frames_attempt_delta;
 	unsigned long matches_delta;
 };
 
diff --git a/net/can/proc.c b/net/can/proc.c
index 83045f0..96eb745 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -148,6 +148,8 @@ void can_stat_update(unsigned long data)
 
 	can_stats->total_tx_rate = calc_rate(can_stats->jiffies_init, j,
 					    can_stats->tx_frames);
+	can_stats->total_tx_attempt_rate = calc_rate(can_stats->jiffies_init, j,
+					    can_stats->tx_attempt_frames);
 	can_stats->total_rx_rate = calc_rate(can_stats->jiffies_init, j,
 					    can_stats->rx_frames);
 
@@ -158,12 +160,16 @@ void can_stat_update(unsigned long data)
 			can_stats->rx_frames_delta;
 
 	can_stats->current_tx_rate = calc_rate(0, HZ, can_stats->tx_frames_delta);
+	can_stats->current_tx_attempt_rate = calc_rate(0, HZ, can_stats->tx_frames_attempt_delta);
 	can_stats->current_rx_rate = calc_rate(0, HZ, can_stats->rx_frames_delta);
 
 	/* check / update maximum values */
 	if (can_stats->max_tx_rate < can_stats->current_tx_rate)
 		can_stats->max_tx_rate = can_stats->current_tx_rate;
 
+	if (can_stats->max_tx_attempt_rate < can_stats->current_tx_attempt_rate)
+		can_stats->max_tx_attempt_rate = can_stats->current_tx_attempt_rate;
+
 	if (can_stats->max_rx_rate < can_stats->current_rx_rate)
 		can_stats->max_rx_rate = can_stats->current_rx_rate;
 
@@ -172,6 +178,7 @@ void can_stat_update(unsigned long data)
 
 	/* clear values for 'current rate' calculation */
 	can_stats->tx_frames_delta = 0;
+	can_stats->tx_frames_attempt_delta = 0;
 	can_stats->rx_frames_delta = 0;
 	can_stats->matches_delta   = 0;
 
@@ -227,6 +234,8 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
 
 		seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
 				can_stats->total_tx_rate);
+		seq_printf(m, " %8ld frames/s total attempt tx rate (ATXR)\n",
+				can_stats->total_tx_attempt_rate);
 		seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
 				can_stats->total_rx_rate);
 
@@ -237,6 +246,8 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
 
 		seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
 				can_stats->current_tx_rate);
+		seq_printf(m, " %8ld frames/s current attempt tx rate (CATXR)\n",
+				can_stats->current_tx_attempt_rate);
 		seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
 				can_stats->current_rx_rate);
 
@@ -247,6 +258,8 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
 
 		seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
 				can_stats->max_tx_rate);
+		seq_printf(m, " %8ld frames/s max attempt tx rate (MATXR)\n",
+				can_stats->max_tx_attempt_rate);
 		seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
 				can_stats->max_rx_rate);
 
-- 
2.7.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help