From 6d58572de91a10cc29c8087186ce66a006033f81 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 25 Jul 2016 14:26:44 -0600 Subject: [PATCH] net: rmnet_data: Define the skb recycle handler for transports rmnet_data currently frees incoming memory when de-aggregating large incoming aggregated packets. This may introduce additional overhead in the memory allocator. Add a handler as part of the rx_handler_data to recycle the skb's. This handler needs to defined within the specific transport driver. If the recycle handler is not implemented by the transport, rmnet_data will free the skb (default behavior). CRs-Fixed: 1048396 Change-Id: I14b929d78c87ced26cff3c32876d2eec5de33350 Signed-off-by: Subash Abhinov Kasiviswanathan --- include/net/rmnet_config.h | 27 +++++++++++++++++++++ net/rmnet_data/rmnet_data_config.c | 47 ++++++++++++++++++++++++------------ net/rmnet_data/rmnet_data_config.h | 6 ++++- net/rmnet_data/rmnet_data_handlers.c | 19 +++++++-------- net/rmnet_data/rmnet_data_stats.c | 15 +++++++++--- net/rmnet_data/rmnet_map.h | 9 ++++--- net/rmnet_data/rmnet_map_command.c | 7 +++--- net/rmnet_data/rmnet_map_data.c | 9 ++++--- 8 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 include/net/rmnet_config.h diff --git a/include/net/rmnet_config.h b/include/net/rmnet_config.h new file mode 100644 index 000000000000..0e6282b05483 --- /dev/null +++ b/include/net/rmnet_config.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data config definition + * + */ + +#ifndef _RMNET_CONFIG_H_ +#define _RMNET_CONFIG_H_ + +#include + +struct rmnet_phys_ep_conf_s { + void (*recycle)(struct sk_buff *); /* Destruct function */ + void *config; +}; + +#endif /* _RMNET_CONFIG_H_ */ diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c index c49393924e26..ebce455b645d 100644 --- a/net/rmnet_data/rmnet_data_config.c +++ b/net/rmnet_data/rmnet_data_config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #include #include #include +#include #include "rmnet_data_config.h" #include "rmnet_data_handlers.h" #include "rmnet_data_vnd.h" @@ -141,14 +142,22 @@ static inline int _rmnet_is_physical_endpoint_associated(struct net_device *dev) * - pointer to configuration if successful * - 0 (null) if device is not associated */ -static inline struct rmnet_phys_ep_conf_s *_rmnet_get_phys_ep_config - (struct net_device *dev) +struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config + (struct net_device *dev) { - if (_rmnet_is_physical_endpoint_associated(dev)) - return (struct rmnet_phys_ep_conf_s *) - rcu_dereference(dev->rx_handler_data); - else + struct rmnet_phys_ep_conf_s *_rmnet_phys_ep_config; + + if (_rmnet_is_physical_endpoint_associated(dev)) { + _rmnet_phys_ep_config = (struct rmnet_phys_ep_conf_s *) + rcu_dereference(dev->rx_handler_data); + if (_rmnet_phys_ep_config && _rmnet_phys_ep_config->config) + return (struct rmnet_phys_ep_config *) + _rmnet_phys_ep_config->config; + else + return 0; + } else { return 0; + } } /** @@ -165,7 +174,7 @@ static inline struct rmnet_phys_ep_conf_s *_rmnet_get_phys_ep_config struct rmnet_logical_ep_conf_s *_rmnet_get_logical_ep(struct net_device *dev, int config_id) { - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; struct rmnet_logical_ep_conf_s *epconfig_l; if (rmnet_vnd_is_vnd(dev)) @@ -400,7 +409,7 @@ static void _rmnet_netlink_get_link_egress_data_format struct rmnet_nl_msg_s *resp_rmnet) { struct net_device *dev; - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; _RMNET_NETLINK_NULL_CHECKS(); resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; @@ -432,7 +441,7 @@ static void _rmnet_netlink_get_link_ingress_data_format struct rmnet_nl_msg_s *resp_rmnet) { struct net_device *dev; - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; _RMNET_NETLINK_NULL_CHECKS(); resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; @@ -725,7 +734,7 @@ int rmnet_set_ingress_data_format(struct net_device *dev, uint32_t ingress_data_format, uint8_t tail_spacing) { - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; ASSERT_RTNL(); LOGL("(%s,0x%08X);", dev->name, ingress_data_format); @@ -762,7 +771,7 @@ int rmnet_set_egress_data_format(struct net_device *dev, uint16_t agg_size, uint16_t agg_count) { - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; ASSERT_RTNL(); LOGL("(%s,0x%08X, %d, %d);", @@ -800,7 +809,9 @@ int rmnet_set_egress_data_format(struct net_device *dev, int rmnet_associate_network_device(struct net_device *dev) { struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *conf; int rc; + ASSERT_RTNL(); LOGL("(%s);\n", dev->name); @@ -819,19 +830,25 @@ int rmnet_associate_network_device(struct net_device *dev) } config = kmalloc(sizeof(*config), GFP_ATOMIC); + conf = kmalloc(sizeof(*conf), GFP_ATOMIC); - if (!config) + if (!config || !conf) return RMNET_CONFIG_NOMEM; memset(config, 0, sizeof(struct rmnet_phys_ep_conf_s)); - config->dev = dev; - spin_lock_init(&config->agg_lock); + memset(conf, 0, sizeof(struct rmnet_phys_ep_config)); + + config->config = conf; + conf->dev = dev; + spin_lock_init(&conf->agg_lock); + config->recycle = kfree_skb; rc = netdev_rx_handler_register(dev, rmnet_rx_handler, config); if (rc) { LOGM("netdev_rx_handler_register returns %d", rc); kfree(config); + kfree(conf); return RMNET_CONFIG_DEVICE_IN_USE; } diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h index a76bcef79e6a..78329c38b364 100644 --- a/net/rmnet_data/rmnet_data_config.h +++ b/net/rmnet_data/rmnet_data_config.h @@ -17,6 +17,7 @@ #include #include #include +#include #ifndef _RMNET_DATA_CONFIG_H_ #define _RMNET_DATA_CONFIG_H_ @@ -62,7 +63,7 @@ struct rmnet_logical_ep_conf_s { * @agg_time: Wall clock time when aggregated frame was created * @agg_last: Last time the aggregation routing was invoked */ -struct rmnet_phys_ep_conf_s { +struct rmnet_phys_ep_config { struct net_device *dev; struct rmnet_logical_ep_conf_s local_ep; struct rmnet_logical_ep_conf_s muxed_ep[RMNET_DATA_MAX_LOGICAL_EP]; @@ -123,4 +124,7 @@ int rmnet_create_vnd(int id); int rmnet_create_vnd_prefix(int id, const char *name); int rmnet_free_vnd(int id); +struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config + (struct net_device *dev); + #endif /* _RMNET_DATA_CONFIG_H_ */ diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index 9d04b2f8ddd9..185b609e637f 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "rmnet_data_private.h" #include "rmnet_data_config.h" #include "rmnet_data_vnd.h" @@ -321,7 +322,7 @@ static rx_handler_result_t __rmnet_deliver_skb(struct sk_buff *skb, * - RX_HANDLER_PASS if packet should be passed up the stack by caller */ static rx_handler_result_t rmnet_ingress_deliver_packet(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { if (!config) { LOGD("%s", "NULL physical EP provided"); @@ -356,7 +357,7 @@ static rx_handler_result_t rmnet_ingress_deliver_packet(struct sk_buff *skb, * - result of __rmnet_deliver_skb() for all other cases */ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { struct rmnet_logical_ep_conf_s *ep; uint8_t mux_id; @@ -440,7 +441,7 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, * - result of _rmnet_map_ingress_handler() for all other cases */ static rx_handler_result_t rmnet_map_ingress_handler(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { struct sk_buff *skbn; int rc, co = 0; @@ -480,7 +481,7 @@ static rx_handler_result_t rmnet_map_ingress_handler(struct sk_buff *skb, * - 1 on failure */ static int rmnet_map_egress_handler(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config, + struct rmnet_phys_ep_config *config, struct rmnet_logical_ep_conf_s *ep, struct net_device *orig_dev) { @@ -563,7 +564,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, */ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) { - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; struct net_device *dev; int rc; @@ -574,8 +575,7 @@ rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) trace_rmnet_ingress_handler(skb); rmnet_print_packet(skb, dev->name, 'r'); - config = (struct rmnet_phys_ep_conf_s *) - rcu_dereference(skb->dev->rx_handler_data); + config = _rmnet_get_phys_ep_config(skb->dev); if (!config) { LOGD("%s is not associated with rmnet_data", skb->dev->name); @@ -654,14 +654,13 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) void rmnet_egress_handler(struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep) { - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; struct net_device *orig_dev; int rc; orig_dev = skb->dev; skb->dev = ep->egress_dev; - config = (struct rmnet_phys_ep_conf_s *) - rcu_dereference(skb->dev->rx_handler_data); + config = _rmnet_get_phys_ep_config(skb->dev); if (!config) { LOGD("%s is not associated with rmnet_data", skb->dev->name); diff --git a/net/rmnet_data/rmnet_data_stats.c b/net/rmnet_data/rmnet_data_stats.c index 5fefda55c72c..20f1628242c7 100644 --- a/net/rmnet_data/rmnet_data_stats.c +++ b/net/rmnet_data/rmnet_data_stats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #include #include #include +#include #include "rmnet_data_private.h" #include "rmnet_data_stats.h" #include "rmnet_data_config.h" @@ -73,8 +74,16 @@ void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason) skb_free[reason]++; spin_unlock_irqrestore(&rmnet_skb_free_lock, flags); - if (skb) - kfree_skb(skb); + if (likely(skb)) { + struct rmnet_phys_ep_conf_s *config; + + config = (struct rmnet_phys_ep_conf_s *)rcu_dereference + (skb->dev->rx_handler_data); + if (likely(config)) + config->recycle(skb); + else + kfree_skb(skb); + } } void rmnet_stats_queue_xmit(int rc, unsigned int reason) diff --git a/net/rmnet_data/rmnet_map.h b/net/rmnet_data/rmnet_map.h index 0a6ad908b827..71abca122dd6 100644 --- a/net/rmnet_data/rmnet_map.h +++ b/net/rmnet_data/rmnet_map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #include #include +#include #ifndef _RMNET_MAP_H_ #define _RMNET_MAP_H_ @@ -133,14 +134,14 @@ enum rmnet_map_agg_state_e { uint8_t rmnet_map_demultiplex(struct sk_buff *skb); struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config); + struct rmnet_phys_ep_config *config); struct rmnet_map_header_s *rmnet_map_add_map_header(struct sk_buff *skb, int hdrlen, int pad); rx_handler_result_t rmnet_map_command(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config); + struct rmnet_phys_ep_config *config); void rmnet_map_aggregate(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config); + struct rmnet_phys_ep_config *config); int rmnet_map_checksum_downlink_packet(struct sk_buff *skb); int rmnet_map_checksum_uplink_packet(struct sk_buff *skb, diff --git a/net/rmnet_data/rmnet_map_command.c b/net/rmnet_data/rmnet_map_command.c index 4bcfa10db486..055d5f402957 100644 --- a/net/rmnet_data/rmnet_map_command.c +++ b/net/rmnet_data/rmnet_map_command.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "rmnet_data_config.h" #include "rmnet_map.h" #include "rmnet_data_private.h" @@ -44,7 +45,7 @@ MODULE_PARM_DESC(rmnet_map_command_stats, "MAP command statistics"); * - RMNET_MAP_COMMAND_ACK on success */ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config, + struct rmnet_phys_ep_config *config, int enable) { struct rmnet_map_control_command_s *cmd; @@ -116,7 +117,7 @@ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, */ static void rmnet_map_send_ack(struct sk_buff *skb, unsigned char type, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { struct rmnet_map_control_command_s *cmd; int xmit_status; @@ -162,7 +163,7 @@ static void rmnet_map_send_ack(struct sk_buff *skb, * - RX_HANDLER_CONSUMED. Command frames are always consumed. */ rx_handler_result_t rmnet_map_command(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { struct rmnet_map_control_command_s *cmd; unsigned char command_name; diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c index 68caf44c1f92..beff8332c731 100644 --- a/net/rmnet_data/rmnet_map_data.c +++ b/net/rmnet_data/rmnet_map_data.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "rmnet_data_config.h" #include "rmnet_map.h" #include "rmnet_data_private.h" @@ -52,7 +53,7 @@ MODULE_PARM_DESC(agg_bypass_time, "Skip agg when apart spaced more than this"); struct agg_work { struct delayed_work work; - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; }; #define RMNET_MAP_DEAGGR_SPACING 64 @@ -131,7 +132,7 @@ done: * - 0 (null) if no more aggregated packets */ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) + struct rmnet_phys_ep_config *config) { struct sk_buff *skbn; struct rmnet_map_header_s *maph; @@ -185,7 +186,7 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, static void rmnet_map_flush_packet_queue(struct work_struct *work) { struct agg_work *real_work; - struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *config; unsigned long flags; struct sk_buff *skb; int rc, agg_count = 0; @@ -233,7 +234,7 @@ static void rmnet_map_flush_packet_queue(struct work_struct *work) * the argument SKB and should not be further processed by any other function. */ void rmnet_map_aggregate(struct sk_buff *skb, - struct rmnet_phys_ep_conf_s *config) { + struct rmnet_phys_ep_config *config) { uint8_t *dest_buff; struct agg_work *work; unsigned long flags; -- 2.11.0