root/trunk/batman-adv-kernelland/soft-interface.c @ 1551

Revision 1551, 8.9 kB (checked in by simon, 8 months ago)

batman-adv: Add bonding functionality

This patch introduces bonding functionality to batman-advanced, targeted
for the 0.3 release. As we are able to route the payload traffic as we
want, we may use multiple interfaces on multihomed hosts to transfer data
to achieve higher bandwidth. This can be considered as "light Multi Path
Routing" for single hop connections.

To detect which interfaces of a peer node belong to the same host, a
new flag PRIMARIES_FIRST_HOP is introduced. This flag is set on the first hop
of OGMs of the primary (first) interface, which is broadcasted on all
interfaces. When receiving such an OGM, we can learn which interfaces
belong to the same host (by assigning them to the primary originator).

Bonding works by sending packets in a round-robin fashion to the available
interfaces of a neighbor host, if multiple interfaces are available. The
neighbor interfaces should be almost equally good to reach.

To avoid interferences (i.e. sending on the same channel), only neighbor
interfaces with different mac addresses and different outgoing interfaces
are considered as candidates.

Bonding is deactivated by default, and can be activated by

echo 1 > /proc/net/batman-adv/bonding

for each individual node.

Signed-off-by: Simon Wunderlich <siwu@…>

Line 
1/*
2 * Copyright (C) 2007-2009 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 "soft-interface.h"
24#include "hard-interface.h"
25#include "routing.h"
26#include "send.h"
27#include "translation-table.h"
28#include "types.h"
29#include "hash.h"
30#include "gateway_client.h"
31#include <linux/ethtool.h>
32#include <linux/etherdevice.h>
33#include "compat.h"
34
35static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
36                                  * broadcast storms */
37static int32_t skb_packets;
38static int32_t skb_bad_packets;
39
40unsigned char mainIfAddr[ETH_ALEN];
41static unsigned char mainIfAddr_default[ETH_ALEN];
42static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
43static void bat_get_drvinfo(struct net_device *dev,
44                            struct ethtool_drvinfo *info);
45static u32 bat_get_msglevel(struct net_device *dev);
46static void bat_set_msglevel(struct net_device *dev, u32 value);
47static u32 bat_get_link(struct net_device *dev);
48static u32 bat_get_rx_csum(struct net_device *dev);
49static int bat_set_rx_csum(struct net_device *dev, u32 data);
50
51static const struct ethtool_ops bat_ethtool_ops = {
52        .get_settings = bat_get_settings,
53        .get_drvinfo = bat_get_drvinfo,
54        .get_msglevel = bat_get_msglevel,
55        .set_msglevel = bat_set_msglevel,
56        .get_link = bat_get_link,
57        .get_rx_csum = bat_get_rx_csum,
58        .set_rx_csum = bat_set_rx_csum
59};
60
61void set_main_if_addr(uint8_t *addr)
62{
63        memcpy(mainIfAddr, addr, ETH_ALEN);
64}
65
66int main_if_was_up(void)
67{
68        return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
69}
70
71int my_skb_push(struct sk_buff *skb, unsigned int len)
72{
73        int result = 0;
74
75        skb_packets++;
76        if (skb_headroom(skb) < len) {
77                skb_bad_packets++;
78                result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
79
80                if (result < 0)
81                        return result;
82        }
83
84        skb_push(skb, len);
85        return 0;
86}
87
88#ifdef HAVE_NET_DEVICE_OPS
89static const struct net_device_ops bat_netdev_ops = {
90        .ndo_open = interface_open,
91        .ndo_stop = interface_release,
92        .ndo_get_stats = interface_stats,
93        .ndo_set_mac_address = interface_set_mac_addr,
94        .ndo_change_mtu = interface_change_mtu,
95        .ndo_start_xmit = interface_tx,
96        .ndo_validate_addr = eth_validate_addr
97};
98#endif
99
100void interface_setup(struct net_device *dev)
101{
102        struct bat_priv *priv = netdev_priv(dev);
103        char dev_addr[ETH_ALEN];
104
105        ether_setup(dev);
106
107#ifdef HAVE_NET_DEVICE_OPS
108        dev->netdev_ops = &bat_netdev_ops;
109#else
110        dev->open = interface_open;
111        dev->stop = interface_release;
112        dev->get_stats = interface_stats;
113        dev->set_mac_address = interface_set_mac_addr;
114        dev->change_mtu = interface_change_mtu;
115        dev->hard_start_xmit = interface_tx;
116#endif
117        dev->destructor = free_netdev;
118
119        dev->mtu = hardif_min_mtu();
120        dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
121                                                * skbuff for our header */
122
123        /* generate random address */
124        random_ether_addr(dev_addr);
125        memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
126
127        SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
128
129        memset(priv, 0, sizeof(struct bat_priv));
130}
131
132int interface_open(struct net_device *dev)
133{
134        netif_start_queue(dev);
135        return 0;
136}
137
138int interface_release(struct net_device *dev)
139{
140        netif_stop_queue(dev);
141        return 0;
142}
143
144struct net_device_stats *interface_stats(struct net_device *dev)
145{
146        struct bat_priv *priv = netdev_priv(dev);
147        return &priv->stats;
148}
149
150int interface_set_mac_addr(struct net_device *dev, void *p)
151{
152        struct sockaddr *addr = p;
153
154        if (!is_valid_ether_addr(addr->sa_data))
155                return -EADDRNOTAVAIL;
156
157        hna_local_remove(dev->dev_addr, "mac address changed");
158        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
159        hna_local_add(dev->dev_addr);
160
161        return 0;
162}
163
164int interface_change_mtu(struct net_device *dev, int new_mtu)
165{
166        /* check ranges */
167        if ((new_mtu < 68) || (new_mtu > hardif_min_mtu()))
168                return -EINVAL;
169
170        dev->mtu = new_mtu;
171
172        return 0;
173}
174
175
176
177int interface_tx(struct sk_buff *skb, struct net_device *dev)
178{
179        struct unicast_packet *unicast_packet;
180        struct bcast_packet *bcast_packet;
181        struct orig_node *orig_node;
182        struct neigh_node *router;
183        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
184        struct bat_priv *priv = netdev_priv(dev);
185        struct batman_if *batman_if;
186        uint8_t dstaddr[6];
187        int data_len = skb->len;
188        unsigned long flags;
189        bool bcast_dst = false, do_bcast = true;
190
191        if (atomic_read(&module_state) != MODULE_ACTIVE)
192                goto dropped;
193
194        dev->trans_start = jiffies;
195        /* TODO: check this for locks */
196        hna_local_add(ethhdr->h_source);
197
198        if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest))
199                bcast_dst = true;
200
201        if ((bcast_dst) && gw_is_target(skb))
202                do_bcast = false;
203
204        /* ethernet packet should be broadcasted */
205        if (bcast_dst && do_bcast) {
206                if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0)
207                        goto dropped;
208
209                bcast_packet = (struct bcast_packet *)skb->data;
210                bcast_packet->version = COMPAT_VERSION;
211
212                /* batman packet type: broadcast */
213                bcast_packet->packet_type = BAT_BCAST;
214
215                /* hw address of first interface is the orig mac because only
216                 * this mac is known throughout the mesh */
217                memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
218
219                /* set broadcast sequence number */
220                bcast_packet->seqno = htons(bcast_seqno);
221
222                bcast_seqno++;
223
224                /* broadcast packet */
225                add_bcast_packet_to_list(skb);
226                /* a copy is stored in the bcast list, therefore removing
227                 * the original skb. */
228                kfree_skb(skb);
229
230        /* unicast packet */
231        } else {
232                spin_lock_irqsave(&orig_hash_lock, flags);
233
234                /* get routing information */
235                if (bcast_dst)
236                        orig_node = (struct orig_node *)gw_get_selected();
237                else
238                        orig_node = ((struct orig_node *)hash_find(orig_hash,
239                                                           ethhdr->h_dest));
240
241                /* check for hna host */
242                if (!orig_node)
243                        orig_node = transtable_search(ethhdr->h_dest);
244
245                router = find_router(orig_node);
246
247                if (!router)
248                        goto unlock;
249
250                /* don't lock while sending the packets ... we therefore
251                 * copy the required data before sending */
252
253                batman_if = router->if_incoming;
254                memcpy(dstaddr, router->addr, ETH_ALEN);
255
256                spin_unlock_irqrestore(&orig_hash_lock, flags);
257
258                if (batman_if->if_active != IF_ACTIVE)
259                        goto dropped;
260
261                if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
262                        goto dropped;
263
264                unicast_packet = (struct unicast_packet *)skb->data;
265
266                unicast_packet->version = COMPAT_VERSION;
267                /* batman packet type: unicast */
268                unicast_packet->packet_type = BAT_UNICAST;
269                /* set unicast ttl */
270                unicast_packet->ttl = TTL;
271                /* copy the destination for faster routing */
272                memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
273
274                send_skb_packet(skb, batman_if, dstaddr);
275        }
276
277        priv->stats.tx_packets++;
278        priv->stats.tx_bytes += data_len;
279        goto end;
280
281unlock:
282        spin_unlock_irqrestore(&orig_hash_lock, flags);
283dropped:
284        priv->stats.tx_dropped++;
285end:
286        return NETDEV_TX_OK;
287}
288
289void interface_rx(struct sk_buff *skb, int hdr_size)
290{
291        struct net_device *dev = soft_device;
292        struct bat_priv *priv = netdev_priv(dev);
293
294        /* check if enough space is available for pulling, and pull */
295        if (!pskb_may_pull(skb, hdr_size)) {
296                kfree_skb(skb);
297                return;
298        }
299        skb_pull_rcsum(skb, hdr_size);
300/*      skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
301
302        skb->dev = dev;
303        skb->protocol = eth_type_trans(skb, dev);
304
305        /* should not be neccesary anymore as we use skb_pull_rcsum()
306         * TODO: please verify this and remove this TODO
307         * -- Dec 21st 2009, Simon Wunderlich */
308
309/*      skb->ip_summed = CHECKSUM_UNNECESSARY;*/
310
311        /* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST,
312         * PACKET_OTHERHOST or PACKET_HOST */
313
314        priv->stats.rx_packets++;
315        priv->stats.rx_bytes += skb->len;
316
317        dev->last_rx = jiffies;
318
319        netif_rx(skb);
320}
321
322/* ethtool */
323static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
324{
325        cmd->supported = 0;
326        cmd->advertising = 0;
327        cmd->speed = SPEED_10;
328        cmd->duplex = DUPLEX_FULL;
329        cmd->port = PORT_TP;
330        cmd->phy_address = 0;
331        cmd->transceiver = XCVR_INTERNAL;
332        cmd->autoneg = AUTONEG_DISABLE;
333        cmd->maxtxpkt = 0;
334        cmd->maxrxpkt = 0;
335
336        return 0;
337}
338
339static void bat_get_drvinfo(struct net_device *dev,
340                            struct ethtool_drvinfo *info)
341{
342        strcpy(info->driver, "B.A.T.M.A.N. advanced");
343        strcpy(info->version, SOURCE_VERSION);
344        strcpy(info->fw_version, "N/A");
345        strcpy(info->bus_info, "batman");
346}
347
348static u32 bat_get_msglevel(struct net_device *dev)
349{
350        return -EOPNOTSUPP;
351}
352
353static void bat_set_msglevel(struct net_device *dev, u32 value)
354{
355}
356
357static u32 bat_get_link(struct net_device *dev)
358{
359        return 1;
360}
361
362static u32 bat_get_rx_csum(struct net_device *dev)
363{
364        return 0;
365}
366
367static int bat_set_rx_csum(struct net_device *dev, u32 data)
368{
369        return -EOPNOTSUPP;
370}
Note: See TracBrowser for help on using the browser.