linux/net/batman-adv/aggregation.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
   3 *
   4 * Marek Lindner, Simon Wunderlich
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of version 2 of the GNU General Public
   8 * License as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA
  19 *
  20 */
  21
  22#include "main.h"
  23#include "aggregation.h"
  24#include "send.h"
  25#include "routing.h"
  26#include "hard-interface.h"
  27
  28/* calculate the size of the tt information for a given packet */
  29static int tt_len(struct batman_packet *batman_packet)
  30{
  31        return batman_packet->num_tt * ETH_ALEN;
  32}
  33
  34/* return true if new_packet can be aggregated with forw_packet */
  35static bool can_aggregate_with(struct batman_packet *new_batman_packet,
  36                               int packet_len,
  37                               unsigned long send_time,
  38                               bool directlink,
  39                               struct hard_iface *if_incoming,
  40                               struct forw_packet *forw_packet)
  41{
  42        struct batman_packet *batman_packet =
  43                (struct batman_packet *)forw_packet->skb->data;
  44        int aggregated_bytes = forw_packet->packet_len + packet_len;
  45
  46        /**
  47         * we can aggregate the current packet to this aggregated packet
  48         * if:
  49         *
  50         * - the send time is within our MAX_AGGREGATION_MS time
  51         * - the resulting packet wont be bigger than
  52         *   MAX_AGGREGATION_BYTES
  53         */
  54
  55        if (time_before(send_time, forw_packet->send_time) &&
  56            time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
  57                                        forw_packet->send_time) &&
  58            (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
  59
  60                /**
  61                 * check aggregation compatibility
  62                 * -> direct link packets are broadcasted on
  63                 *    their interface only
  64                 * -> aggregate packet if the current packet is
  65                 *    a "global" packet as well as the base
  66                 *    packet
  67                 */
  68
  69                /* packets without direct link flag and high TTL
  70                 * are flooded through the net  */
  71                if ((!directlink) &&
  72                    (!(batman_packet->flags & DIRECTLINK)) &&
  73                    (batman_packet->ttl != 1) &&
  74
  75                    /* own packets originating non-primary
  76                     * interfaces leave only that interface */
  77                    ((!forw_packet->own) ||
  78                     (forw_packet->if_incoming->if_num == 0)))
  79                        return true;
  80
  81                /* if the incoming packet is sent via this one
  82                 * interface only - we still can aggregate */
  83                if ((directlink) &&
  84                    (new_batman_packet->ttl == 1) &&
  85                    (forw_packet->if_incoming == if_incoming) &&
  86
  87                    /* packets from direct neighbors or
  88                     * own secondary interface packets
  89                     * (= secondary interface packets in general) */
  90                    (batman_packet->flags & DIRECTLINK ||
  91                     (forw_packet->own &&
  92                      forw_packet->if_incoming->if_num != 0)))
  93                        return true;
  94        }
  95
  96        return false;
  97}
  98
  99/* create a new aggregated packet and add this packet to it */
 100static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
 101                                  unsigned long send_time, bool direct_link,
 102                                  struct hard_iface *if_incoming,
 103                                  int own_packet)
 104{
 105        struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 106        struct forw_packet *forw_packet_aggr;
 107        unsigned char *skb_buff;
 108
 109        if (!atomic_inc_not_zero(&if_incoming->refcount))
 110                return;
 111
 112        /* own packet should always be scheduled */
 113        if (!own_packet) {
 114                if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
 115                        bat_dbg(DBG_BATMAN, bat_priv,
 116                                "batman packet queue full\n");
 117                        goto out;
 118                }
 119        }
 120
 121        forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
 122        if (!forw_packet_aggr) {
 123                if (!own_packet)
 124                        atomic_inc(&bat_priv->batman_queue_left);
 125                goto out;
 126        }
 127
 128        if ((atomic_read(&bat_priv->aggregated_ogms)) &&
 129            (packet_len < MAX_AGGREGATION_BYTES))
 130                forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
 131                                                      sizeof(struct ethhdr));
 132        else
 133                forw_packet_aggr->skb = dev_alloc_skb(packet_len +
 134                                                      sizeof(struct ethhdr));
 135
 136        if (!forw_packet_aggr->skb) {
 137                if (!own_packet)
 138                        atomic_inc(&bat_priv->batman_queue_left);
 139                kfree(forw_packet_aggr);
 140                goto out;
 141        }
 142        skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
 143
 144        INIT_HLIST_NODE(&forw_packet_aggr->list);
 145
 146        skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
 147        forw_packet_aggr->packet_len = packet_len;
 148        memcpy(skb_buff, packet_buff, packet_len);
 149
 150        forw_packet_aggr->own = own_packet;
 151        forw_packet_aggr->if_incoming = if_incoming;
 152        forw_packet_aggr->num_packets = 0;
 153        forw_packet_aggr->direct_link_flags = 0;
 154        forw_packet_aggr->send_time = send_time;
 155
 156        /* save packet direct link flag status */
 157        if (direct_link)
 158                forw_packet_aggr->direct_link_flags |= 1;
 159
 160        /* add new packet to packet list */
 161        spin_lock_bh(&bat_priv->forw_bat_list_lock);
 162        hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
 163        spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 164
 165        /* start timer for this packet */
 166        INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
 167                          send_outstanding_bat_packet);
 168        queue_delayed_work(bat_event_workqueue,
 169                           &forw_packet_aggr->delayed_work,
 170                           send_time - jiffies);
 171
 172        return;
 173out:
 174        hardif_free_ref(if_incoming);
 175}
 176
 177/* aggregate a new packet into the existing aggregation */
 178static void aggregate(struct forw_packet *forw_packet_aggr,
 179                      unsigned char *packet_buff,
 180                      int packet_len,
 181                      bool direct_link)
 182{
 183        unsigned char *skb_buff;
 184
 185        skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
 186        memcpy(skb_buff, packet_buff, packet_len);
 187        forw_packet_aggr->packet_len += packet_len;
 188        forw_packet_aggr->num_packets++;
 189
 190        /* save packet direct link flag status */
 191        if (direct_link)
 192                forw_packet_aggr->direct_link_flags |=
 193                        (1 << forw_packet_aggr->num_packets);
 194}
 195
 196void add_bat_packet_to_list(struct bat_priv *bat_priv,
 197                            unsigned char *packet_buff, int packet_len,
 198                            struct hard_iface *if_incoming, char own_packet,
 199                            unsigned long send_time)
 200{
 201        /**
 202         * _aggr -> pointer to the packet we want to aggregate with
 203         * _pos -> pointer to the position in the queue
 204         */
 205        struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
 206        struct hlist_node *tmp_node;
 207        struct batman_packet *batman_packet =
 208                (struct batman_packet *)packet_buff;
 209        bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
 210
 211        /* find position for the packet in the forward queue */
 212        spin_lock_bh(&bat_priv->forw_bat_list_lock);
 213        /* own packets are not to be aggregated */
 214        if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
 215                hlist_for_each_entry(forw_packet_pos, tmp_node,
 216                                     &bat_priv->forw_bat_list, list) {
 217                        if (can_aggregate_with(batman_packet,
 218                                               packet_len,
 219                                               send_time,
 220                                               direct_link,
 221                                               if_incoming,
 222                                               forw_packet_pos)) {
 223                                forw_packet_aggr = forw_packet_pos;
 224                                break;
 225                        }
 226                }
 227        }
 228
 229        /* nothing to aggregate with - either aggregation disabled or no
 230         * suitable aggregation packet found */
 231        if (!forw_packet_aggr) {
 232                /* the following section can run without the lock */
 233                spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 234
 235                /**
 236                 * if we could not aggregate this packet with one of the others
 237                 * we hold it back for a while, so that it might be aggregated
 238                 * later on
 239                 */
 240                if ((!own_packet) &&
 241                    (atomic_read(&bat_priv->aggregated_ogms)))
 242                        send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
 243
 244                new_aggregated_packet(packet_buff, packet_len,
 245                                      send_time, direct_link,
 246                                      if_incoming, own_packet);
 247        } else {
 248                aggregate(forw_packet_aggr,
 249                          packet_buff, packet_len,
 250                          direct_link);
 251                spin_unlock_bh(&bat_priv->forw_bat_list_lock);
 252        }
 253}
 254
 255/* unpack the aggregated packets and process them one by one */
 256void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
 257                             int packet_len, struct hard_iface *if_incoming)
 258{
 259        struct batman_packet *batman_packet;
 260        int buff_pos = 0;
 261        unsigned char *tt_buff;
 262
 263        batman_packet = (struct batman_packet *)packet_buff;
 264
 265        do {
 266                /* network to host order for our 32bit seqno, and the
 267                   orig_interval. */
 268                batman_packet->seqno = ntohl(batman_packet->seqno);
 269
 270                tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
 271                receive_bat_packet(ethhdr, batman_packet,
 272                                   tt_buff, tt_len(batman_packet),
 273                                   if_incoming);
 274
 275                buff_pos += BAT_PACKET_LEN + tt_len(batman_packet);
 276                batman_packet = (struct batman_packet *)
 277                        (packet_buff + buff_pos);
 278        } while (aggregated_packet(buff_pos, packet_len,
 279                                   batman_packet->num_tt));
 280}
 281