@@ -952,13 +952,82 @@ static const struct net_dm_alert_ops *net_dm_alert_ops_arr[] = {
952
952
void net_dm_hw_report (struct sk_buff * skb ,
953
953
const struct net_dm_hw_metadata * hw_metadata )
954
954
{
955
+ rcu_read_lock ();
956
+
955
957
if (!monitor_hw )
956
- return ;
958
+ goto out ;
957
959
958
960
net_dm_alert_ops_arr [net_dm_alert_mode ]-> hw_probe (skb , hw_metadata );
961
+
962
+ out :
963
+ rcu_read_unlock ();
959
964
}
960
965
EXPORT_SYMBOL_GPL (net_dm_hw_report );
961
966
967
+ static int net_dm_hw_monitor_start (struct netlink_ext_ack * extack )
968
+ {
969
+ const struct net_dm_alert_ops * ops ;
970
+ int cpu ;
971
+
972
+ if (monitor_hw ) {
973
+ NL_SET_ERR_MSG_MOD (extack , "Hardware monitoring already enabled" );
974
+ return - EAGAIN ;
975
+ }
976
+
977
+ ops = net_dm_alert_ops_arr [net_dm_alert_mode ];
978
+
979
+ if (!try_module_get (THIS_MODULE )) {
980
+ NL_SET_ERR_MSG_MOD (extack , "Failed to take reference on module" );
981
+ return - ENODEV ;
982
+ }
983
+
984
+ for_each_possible_cpu (cpu ) {
985
+ struct per_cpu_dm_data * hw_data = & per_cpu (dm_hw_cpu_data , cpu );
986
+ struct net_dm_hw_entries * hw_entries ;
987
+
988
+ INIT_WORK (& hw_data -> dm_alert_work , ops -> hw_work_item_func );
989
+ timer_setup (& hw_data -> send_timer , sched_send_work , 0 );
990
+ hw_entries = net_dm_hw_reset_per_cpu_data (hw_data );
991
+ kfree (hw_entries );
992
+ }
993
+
994
+ monitor_hw = true;
995
+
996
+ return 0 ;
997
+ }
998
+
999
+ static void net_dm_hw_monitor_stop (struct netlink_ext_ack * extack )
1000
+ {
1001
+ int cpu ;
1002
+
1003
+ if (!monitor_hw )
1004
+ NL_SET_ERR_MSG_MOD (extack , "Hardware monitoring already disabled" );
1005
+
1006
+ monitor_hw = false;
1007
+
1008
+ /* After this call returns we are guaranteed that no CPU is processing
1009
+ * any hardware drops.
1010
+ */
1011
+ synchronize_rcu ();
1012
+
1013
+ for_each_possible_cpu (cpu ) {
1014
+ struct per_cpu_dm_data * hw_data = & per_cpu (dm_hw_cpu_data , cpu );
1015
+ struct sk_buff * skb ;
1016
+
1017
+ del_timer_sync (& hw_data -> send_timer );
1018
+ cancel_work_sync (& hw_data -> dm_alert_work );
1019
+ while ((skb = __skb_dequeue (& hw_data -> drop_queue ))) {
1020
+ struct net_dm_hw_metadata * hw_metadata ;
1021
+
1022
+ hw_metadata = NET_DM_SKB_CB (skb )-> hw_metadata ;
1023
+ net_dm_hw_metadata_free (hw_metadata );
1024
+ consume_skb (skb );
1025
+ }
1026
+ }
1027
+
1028
+ module_put (THIS_MODULE );
1029
+ }
1030
+
962
1031
static int net_dm_trace_on_set (struct netlink_ext_ack * extack )
963
1032
{
964
1033
const struct net_dm_alert_ops * ops ;
@@ -1153,14 +1222,61 @@ static int net_dm_cmd_config(struct sk_buff *skb,
1153
1222
return 0 ;
1154
1223
}
1155
1224
1225
+ static int net_dm_monitor_start (bool set_sw , bool set_hw ,
1226
+ struct netlink_ext_ack * extack )
1227
+ {
1228
+ bool sw_set = false;
1229
+ int rc ;
1230
+
1231
+ if (set_sw ) {
1232
+ rc = set_all_monitor_traces (TRACE_ON , extack );
1233
+ if (rc )
1234
+ return rc ;
1235
+ sw_set = true;
1236
+ }
1237
+
1238
+ if (set_hw ) {
1239
+ rc = net_dm_hw_monitor_start (extack );
1240
+ if (rc )
1241
+ goto err_monitor_hw ;
1242
+ }
1243
+
1244
+ return 0 ;
1245
+
1246
+ err_monitor_hw :
1247
+ if (sw_set )
1248
+ set_all_monitor_traces (TRACE_OFF , extack );
1249
+ return rc ;
1250
+ }
1251
+
1252
+ static void net_dm_monitor_stop (bool set_sw , bool set_hw ,
1253
+ struct netlink_ext_ack * extack )
1254
+ {
1255
+ if (set_hw )
1256
+ net_dm_hw_monitor_stop (extack );
1257
+ if (set_sw )
1258
+ set_all_monitor_traces (TRACE_OFF , extack );
1259
+ }
1260
+
1156
1261
static int net_dm_cmd_trace (struct sk_buff * skb ,
1157
1262
struct genl_info * info )
1158
1263
{
1264
+ bool set_sw = !!info -> attrs [NET_DM_ATTR_SW_DROPS ];
1265
+ bool set_hw = !!info -> attrs [NET_DM_ATTR_HW_DROPS ];
1266
+ struct netlink_ext_ack * extack = info -> extack ;
1267
+
1268
+ /* To maintain backward compatibility, we start / stop monitoring of
1269
+ * software drops if no flag is specified.
1270
+ */
1271
+ if (!set_sw && !set_hw )
1272
+ set_sw = true;
1273
+
1159
1274
switch (info -> genlhdr -> cmd ) {
1160
1275
case NET_DM_CMD_START :
1161
- return set_all_monitor_traces ( TRACE_ON , info -> extack );
1276
+ return net_dm_monitor_start ( set_sw , set_hw , extack );
1162
1277
case NET_DM_CMD_STOP :
1163
- return set_all_monitor_traces (TRACE_OFF , info -> extack );
1278
+ net_dm_monitor_stop (set_sw , set_hw , extack );
1279
+ return 0 ;
1164
1280
}
1165
1281
1166
1282
return - EOPNOTSUPP ;
@@ -1392,6 +1508,8 @@ static const struct nla_policy net_dm_nl_policy[NET_DM_ATTR_MAX + 1] = {
1392
1508
[NET_DM_ATTR_ALERT_MODE ] = { .type = NLA_U8 },
1393
1509
[NET_DM_ATTR_TRUNC_LEN ] = { .type = NLA_U32 },
1394
1510
[NET_DM_ATTR_QUEUE_LEN ] = { .type = NLA_U32 },
1511
+ [NET_DM_ATTR_SW_DROPS ] = {. type = NLA_FLAG },
1512
+ [NET_DM_ATTR_HW_DROPS ] = {. type = NLA_FLAG },
1395
1513
};
1396
1514
1397
1515
static const struct genl_ops dropmon_ops [] = {
0 commit comments