linux/net/hsr/hsr_slave.c
<<
>>
Prefs
   1/* Copyright 2011-2014 Autronica Fire and Security AS
   2 *
   3 * This program is free software; you can redistribute it and/or modify it
   4 * under the terms of the GNU General Public License as published by the Free
   5 * Software Foundation; either version 2 of the License, or (at your option)
   6 * any later version.
   7 *
   8 * Author(s):
   9 *      2011-2014 Arvid Brodin, arvid.brodin@alten.se
  10 */
  11
  12#include "hsr_slave.h"
  13#include <linux/etherdevice.h>
  14#include <linux/if_arp.h>
  15#include "hsr_main.h"
  16#include "hsr_device.h"
  17#include "hsr_forward.h"
  18#include "hsr_framereg.h"
  19
  20
  21static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
  22{
  23        struct sk_buff *skb = *pskb;
  24        struct hsr_port *port;
  25
  26        if (!skb_mac_header_was_set(skb)) {
  27                WARN_ONCE(1, "%s: skb invalid", __func__);
  28                return RX_HANDLER_PASS;
  29        }
  30
  31        rcu_read_lock(); /* hsr->node_db, hsr->ports */
  32        port = hsr_port_get_rcu(skb->dev);
  33
  34        if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) {
  35                /* Directly kill frames sent by ourselves */
  36                kfree_skb(skb);
  37                goto finish_consume;
  38        }
  39
  40        if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP))
  41                goto finish_pass;
  42
  43        skb_push(skb, ETH_HLEN);
  44
  45        hsr_forward_skb(skb, port);
  46
  47finish_consume:
  48        rcu_read_unlock(); /* hsr->node_db, hsr->ports */
  49        return RX_HANDLER_CONSUMED;
  50
  51finish_pass:
  52        rcu_read_unlock(); /* hsr->node_db, hsr->ports */
  53        return RX_HANDLER_PASS;
  54}
  55
  56bool hsr_port_exists(const struct net_device *dev)
  57{
  58        return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame;
  59}
  60
  61
  62static int hsr_check_dev_ok(struct net_device *dev)
  63{
  64        /* Don't allow HSR on non-ethernet like devices */
  65        if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) ||
  66            (dev->addr_len != ETH_ALEN)) {
  67                netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
  68                return -EINVAL;
  69        }
  70
  71        /* Don't allow enslaving hsr devices */
  72        if (is_hsr_master(dev)) {
  73                netdev_info(dev, "Cannot create trees of HSR devices.\n");
  74                return -EINVAL;
  75        }
  76
  77        if (hsr_port_exists(dev)) {
  78                netdev_info(dev, "This device is already a HSR slave.\n");
  79                return -EINVAL;
  80        }
  81
  82        if (dev->priv_flags & IFF_802_1Q_VLAN) {
  83                netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n");
  84                return -EINVAL;
  85        }
  86
  87        if (dev->priv_flags & IFF_DONT_BRIDGE) {
  88                netdev_info(dev, "This device does not support bridging.\n");
  89                return -EOPNOTSUPP;
  90        }
  91
  92        /* HSR over bonded devices has not been tested, but I'm not sure it
  93         * won't work...
  94         */
  95
  96        return 0;
  97}
  98
  99
 100/* Setup device to be added to the HSR bridge. */
 101static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port)
 102{
 103        int res;
 104
 105        dev_hold(dev);
 106        res = dev_set_promiscuity(dev, 1);
 107        if (res)
 108                goto fail_promiscuity;
 109
 110        /* FIXME:
 111         * What does net device "adjacency" mean? Should we do
 112         * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ?
 113         */
 114
 115        res = netdev_rx_handler_register(dev, hsr_handle_frame, port);
 116        if (res)
 117                goto fail_rx_handler;
 118        dev_disable_lro(dev);
 119
 120        return 0;
 121
 122fail_rx_handler:
 123        dev_set_promiscuity(dev, -1);
 124fail_promiscuity:
 125        dev_put(dev);
 126
 127        return res;
 128}
 129
 130int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
 131                 enum hsr_port_type type)
 132{
 133        struct hsr_port *port, *master;
 134        int res;
 135
 136        if (type != HSR_PT_MASTER) {
 137                res = hsr_check_dev_ok(dev);
 138                if (res)
 139                        return res;
 140        }
 141
 142        port = hsr_port_get_hsr(hsr, type);
 143        if (port != NULL)
 144                return -EBUSY;  /* This port already exists */
 145
 146        port = kzalloc(sizeof(*port), GFP_KERNEL);
 147        if (port == NULL)
 148                return -ENOMEM;
 149
 150        if (type != HSR_PT_MASTER) {
 151                res = hsr_portdev_setup(dev, port);
 152                if (res)
 153                        goto fail_dev_setup;
 154        }
 155
 156        port->hsr = hsr;
 157        port->dev = dev;
 158        port->type = type;
 159
 160        list_add_tail_rcu(&port->port_list, &hsr->ports);
 161        synchronize_rcu();
 162
 163        master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
 164        netdev_update_features(master->dev);
 165        dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
 166
 167        return 0;
 168
 169fail_dev_setup:
 170        kfree(port);
 171        return res;
 172}
 173
 174void hsr_del_port(struct hsr_port *port)
 175{
 176        struct hsr_priv *hsr;
 177        struct hsr_port *master;
 178
 179        hsr = port->hsr;
 180        master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
 181        list_del_rcu(&port->port_list);
 182
 183        if (port != master) {
 184                if (master != NULL) {
 185                        netdev_update_features(master->dev);
 186                        dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
 187                }
 188                netdev_rx_handler_unregister(port->dev);
 189                dev_set_promiscuity(port->dev, -1);
 190        }
 191
 192        /* FIXME?
 193         * netdev_upper_dev_unlink(port->dev, port->hsr->dev);
 194         */
 195
 196        synchronize_rcu();
 197
 198        if (port != master)
 199                dev_put(port->dev);
 200}
 201