linux/net/bridge/br_forward.c
<<
>>
Prefs
   1/*
   2 *      Forwarding decision
   3 *      Linux ethernet bridge
   4 *
   5 *      Authors:
   6 *      Lennert Buytenhek               <buytenh@gnu.org>
   7 *
   8 *      This program is free software; you can redistribute it and/or
   9 *      modify it under the terms of the GNU General Public License
  10 *      as published by the Free Software Foundation; either version
  11 *      2 of the License, or (at your option) any later version.
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/slab.h>
  16#include <linux/kernel.h>
  17#include <linux/netdevice.h>
  18#include <linux/netpoll.h>
  19#include <linux/skbuff.h>
  20#include <linux/if_vlan.h>
  21#include <linux/netfilter_bridge.h>
  22#include "br_private.h"
  23
  24static int deliver_clone(const struct net_bridge_port *prev,
  25                         struct sk_buff *skb,
  26                         void (*__packet_hook)(const struct net_bridge_port *p,
  27                                               struct sk_buff *skb));
  28
  29/* Don't forward packets to originating port or forwarding diasabled */
  30static inline int should_deliver(const struct net_bridge_port *p,
  31                                 const struct sk_buff *skb)
  32{
  33        return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
  34                p->state == BR_STATE_FORWARDING);
  35}
  36
  37static inline unsigned int packet_length(const struct sk_buff *skb)
  38{
  39        return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
  40}
  41
  42int br_dev_queue_push_xmit(struct sk_buff *skb)
  43{
  44        /* ip_fragment doesn't copy the MAC header */
  45        if (nf_bridge_maybe_copy_header(skb) ||
  46            (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))) {
  47                kfree_skb(skb);
  48        } else {
  49                skb_push(skb, ETH_HLEN);
  50                br_drop_fake_rtable(skb);
  51                dev_queue_xmit(skb);
  52        }
  53
  54        return 0;
  55}
  56
  57int br_forward_finish(struct sk_buff *skb)
  58{
  59        return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
  60                       br_dev_queue_push_xmit);
  61
  62}
  63
  64static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
  65{
  66        skb->dev = to->dev;
  67
  68        if (unlikely(netpoll_tx_running(to->br->dev))) {
  69                if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
  70                        kfree_skb(skb);
  71                else {
  72                        skb_push(skb, ETH_HLEN);
  73                        br_netpoll_send_skb(to, skb);
  74                }
  75                return;
  76        }
  77
  78        NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
  79                br_forward_finish);
  80}
  81
  82static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
  83{
  84        struct net_device *indev;
  85
  86        if (skb_warn_if_lro(skb)) {
  87                kfree_skb(skb);
  88                return;
  89        }
  90
  91        indev = skb->dev;
  92        skb->dev = to->dev;
  93        skb_forward_csum(skb);
  94
  95        NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
  96                br_forward_finish);
  97}
  98
  99/* called with rcu_read_lock */
 100void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 101{
 102        if (to && should_deliver(to, skb)) {
 103                __br_deliver(to, skb);
 104                return;
 105        }
 106
 107        kfree_skb(skb);
 108}
 109
 110/* called with rcu_read_lock */
 111void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
 112{
 113        if (should_deliver(to, skb)) {
 114                if (skb0)
 115                        deliver_clone(to, skb, __br_forward);
 116                else
 117                        __br_forward(to, skb);
 118                return;
 119        }
 120
 121        if (!skb0)
 122                kfree_skb(skb);
 123}
 124
 125static int deliver_clone(const struct net_bridge_port *prev,
 126                         struct sk_buff *skb,
 127                         void (*__packet_hook)(const struct net_bridge_port *p,
 128                                               struct sk_buff *skb))
 129{
 130        struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
 131
 132        skb = skb_clone(skb, GFP_ATOMIC);
 133        if (!skb) {
 134                dev->stats.tx_dropped++;
 135                return -ENOMEM;
 136        }
 137
 138        __packet_hook(prev, skb);
 139        return 0;
 140}
 141
 142static struct net_bridge_port *maybe_deliver(
 143        struct net_bridge_port *prev, struct net_bridge_port *p,
 144        struct sk_buff *skb,
 145        void (*__packet_hook)(const struct net_bridge_port *p,
 146                              struct sk_buff *skb))
 147{
 148        int err;
 149
 150        if (!should_deliver(p, skb))
 151                return prev;
 152
 153        if (!prev)
 154                goto out;
 155
 156        err = deliver_clone(prev, skb, __packet_hook);
 157        if (err)
 158                return ERR_PTR(err);
 159
 160out:
 161        return p;
 162}
 163
 164/* called under bridge lock */
 165static void br_flood(struct net_bridge *br, struct sk_buff *skb,
 166                     struct sk_buff *skb0,
 167                     void (*__packet_hook)(const struct net_bridge_port *p,
 168                                           struct sk_buff *skb))
 169{
 170        struct net_bridge_port *p;
 171        struct net_bridge_port *prev;
 172
 173        prev = NULL;
 174
 175        list_for_each_entry_rcu(p, &br->port_list, list) {
 176                prev = maybe_deliver(prev, p, skb, __packet_hook);
 177                if (IS_ERR(prev))
 178                        goto out;
 179        }
 180
 181        if (!prev)
 182                goto out;
 183
 184        if (skb0)
 185                deliver_clone(prev, skb, __packet_hook);
 186        else
 187                __packet_hook(prev, skb);
 188        return;
 189
 190out:
 191        if (!skb0)
 192                kfree_skb(skb);
 193}
 194
 195
 196/* called with rcu_read_lock */
 197void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
 198{
 199        br_flood(br, skb, NULL, __br_deliver);
 200}
 201
 202/* called under bridge lock */
 203void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
 204                      struct sk_buff *skb2)
 205{
 206        br_flood(br, skb, skb2, __br_forward);
 207}
 208
 209#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 210/* called with rcu_read_lock */
 211static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
 212                               struct sk_buff *skb, struct sk_buff *skb0,
 213                               void (*__packet_hook)(
 214                                        const struct net_bridge_port *p,
 215                                        struct sk_buff *skb))
 216{
 217        struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
 218        struct net_bridge *br = netdev_priv(dev);
 219        struct net_bridge_port *prev = NULL;
 220        struct net_bridge_port_group *p;
 221        struct hlist_node *rp;
 222
 223        rp = rcu_dereference(hlist_first_rcu(&br->router_list));
 224        p = mdst ? rcu_dereference(mdst->ports) : NULL;
 225        while (p || rp) {
 226                struct net_bridge_port *port, *lport, *rport;
 227
 228                lport = p ? p->port : NULL;
 229                rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
 230                             NULL;
 231
 232                port = (unsigned long)lport > (unsigned long)rport ?
 233                       lport : rport;
 234
 235                prev = maybe_deliver(prev, port, skb, __packet_hook);
 236                if (IS_ERR(prev))
 237                        goto out;
 238
 239                if ((unsigned long)lport >= (unsigned long)port)
 240                        p = rcu_dereference(p->next);
 241                if ((unsigned long)rport >= (unsigned long)port)
 242                        rp = rcu_dereference(hlist_next_rcu(rp));
 243        }
 244
 245        if (!prev)
 246                goto out;
 247
 248        if (skb0)
 249                deliver_clone(prev, skb, __packet_hook);
 250        else
 251                __packet_hook(prev, skb);
 252        return;
 253
 254out:
 255        if (!skb0)
 256                kfree_skb(skb);
 257}
 258
 259/* called with rcu_read_lock */
 260void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
 261                          struct sk_buff *skb)
 262{
 263        br_multicast_flood(mdst, skb, NULL, __br_deliver);
 264}
 265
 266/* called with rcu_read_lock */
 267void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
 268                          struct sk_buff *skb, struct sk_buff *skb2)
 269{
 270        br_multicast_flood(mdst, skb, skb2, __br_forward);
 271}
 272#endif
 273
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.