diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/hsr/hsr_device.c | 242 | ||||
-rw-r--r-- | net/hsr/hsr_framereg.c | 142 | ||||
-rw-r--r-- | net/hsr/hsr_framereg.h | 12 | ||||
-rw-r--r-- | net/hsr/hsr_main.c | 128 | ||||
-rw-r--r-- | net/hsr/hsr_main.h | 31 | ||||
-rw-r--r-- | net/hsr/hsr_netlink.c | 57 | ||||
-rw-r--r-- | net/hsr/hsr_netlink.h | 3 | ||||
-rw-r--r-- | net/hsr/hsr_slave.c | 199 | ||||
-rw-r--r-- | net/hsr/hsr_slave.h | 29 |
9 files changed, 438 insertions, 405 deletions
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 1f8869cb70ae..1fc4ea20752e 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -45,29 +45,38 @@ static void __hsr_set_operstate(struct net_device *dev, int transition) } } -static void hsr_set_operstate(struct net_device *hsr_dev, bool has_carrier) +static void hsr_set_operstate(struct hsr_port *master, bool has_carrier) { - if (!is_admin_up(hsr_dev)) { - __hsr_set_operstate(hsr_dev, IF_OPER_DOWN); + if (!is_admin_up(master->dev)) { + __hsr_set_operstate(master->dev, IF_OPER_DOWN); return; } if (has_carrier) - __hsr_set_operstate(hsr_dev, IF_OPER_UP); + __hsr_set_operstate(master->dev, IF_OPER_UP); else - __hsr_set_operstate(hsr_dev, IF_OPER_LOWERLAYERDOWN); + __hsr_set_operstate(master->dev, IF_OPER_LOWERLAYERDOWN); } -static bool hsr_check_carrier(struct hsr_priv *hsr) +static bool hsr_check_carrier(struct hsr_port *master) { + struct hsr_port *port; bool has_carrier; - has_carrier = (is_slave_up(hsr->slave[0]) || is_slave_up(hsr->slave[1])); + has_carrier = false; + + rcu_read_lock(); + hsr_for_each_port(master->hsr, port) + if ((port->type != HSR_PT_MASTER) && is_slave_up(port->dev)) { + has_carrier = true; + break; + } + rcu_read_unlock(); if (has_carrier) - netif_carrier_on(hsr->dev); + netif_carrier_on(master->dev); else - netif_carrier_off(hsr->dev); + netif_carrier_off(master->dev); return has_carrier; } @@ -95,31 +104,30 @@ static void hsr_check_announce(struct net_device *hsr_dev, void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) { + struct hsr_port *master; unsigned char old_operstate; bool has_carrier; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); /* netif_stacked_transfer_operstate() cannot be used here since * it doesn't set IF_OPER_LOWERLAYERDOWN (?) */ - old_operstate = hsr->dev->operstate; - has_carrier = hsr_check_carrier(hsr); - hsr_set_operstate(hsr->dev, has_carrier); - hsr_check_announce(hsr->dev, old_operstate); + old_operstate = master->dev->operstate; + has_carrier = hsr_check_carrier(master); + hsr_set_operstate(master, has_carrier); + hsr_check_announce(master->dev, old_operstate); } int hsr_get_max_mtu(struct hsr_priv *hsr) { unsigned int mtu_max; - struct net_device *slave; + struct hsr_port *port; mtu_max = ETH_DATA_LEN; rcu_read_lock(); - slave = hsr->slave[0]; - if (slave) - mtu_max = min(slave->mtu, mtu_max); - slave = hsr->slave[1]; - if (slave) - mtu_max = min(slave->mtu, mtu_max); + hsr_for_each_port(hsr, port) + if (port->type != HSR_PT_MASTER) + mtu_max = min(port->dev->mtu, mtu_max); rcu_read_unlock(); if (mtu_max < HSR_HLEN) @@ -131,11 +139,13 @@ int hsr_get_max_mtu(struct hsr_priv *hsr) static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) { struct hsr_priv *hsr; + struct hsr_port *master; hsr = netdev_priv(dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (new_mtu > hsr_get_max_mtu(hsr)) { - netdev_info(hsr->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", + netdev_info(master->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", HSR_HLEN); return -EINVAL; } @@ -148,35 +158,42 @@ static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) static int hsr_dev_open(struct net_device *dev) { struct hsr_priv *hsr; - struct net_device *slave; - int i; - char *slave_name; + struct hsr_port *port; + char designation; hsr = netdev_priv(dev); + designation = '\0'; - for (i = 0; i < HSR_MAX_SLAVE; i++) { - slave = hsr->slave[i]; - if (slave) - slave_name = slave->name; - else - slave_name = "null"; - - if (!is_slave_up(slave)) - netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a working HSR network\n", - 'A' + i, slave_name); + rcu_read_lock(); + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + designation = 'A'; + break; + case HSR_PT_SLAVE_B: + designation = 'B'; + break; + default: + designation = '?'; + } + if (!is_slave_up(port->dev)) + netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a fully working HSR network\n", + designation, port->dev->name); } + rcu_read_unlock(); + + if (designation == '\0') + netdev_warn(dev, "No slave devices configured\n"); return 0; } + static int hsr_dev_close(struct net_device *dev) { - /* Nothing to do here. We could try to restore the state of the slaves - * to what they were before being changed by the hsr master dev's state, - * but they might have been changed manually in the mean time too, so - * taking them up or down here might be confusing and is probably not a - * good idea. - */ + /* Nothing to do here. */ return 0; } @@ -220,18 +237,24 @@ static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr) hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); } -static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, - enum hsr_dev_idx dev_idx) +static int slave_xmit(struct hsr_priv *hsr, struct sk_buff *skb, + enum hsr_port_type type) { + struct hsr_port *port; struct hsr_ethhdr *hsr_ethhdr; hsr_ethhdr = (struct hsr_ethhdr *) skb->data; - skb->dev = hsr->slave[dev_idx]; - if (unlikely(!skb->dev)) + rcu_read_lock(); + port = hsr_port_get_hsr(hsr, type); + if (!port) { + rcu_read_unlock(); return NET_XMIT_DROP; + } + skb->dev = port->dev; - hsr_addr_subst_dest(hsr, &hsr_ethhdr->ethhdr, dev_idx); + hsr_addr_subst_dest(port->hsr, &hsr_ethhdr->ethhdr, port); + rcu_read_unlock(); /* Address substitution (IEC62439-3 pp 26, 50): replace mac * address of outgoing frame with that of the outgoing slave's. @@ -241,10 +264,10 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, return dev_queue_xmit(skb); } - static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct hsr_priv *hsr; + struct hsr_port *master; struct hsr_ethhdr *hsr_ethhdr; struct sk_buff *skb2; int res1, res2; @@ -259,16 +282,23 @@ static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) } skb2 = pskb_copy(skb, GFP_ATOMIC); - res1 = slave_xmit(skb, hsr, HSR_DEV_SLAVE_A); - res2 = slave_xmit(skb2, hsr, HSR_DEV_SLAVE_B); + res1 = slave_xmit(hsr, skb, HSR_PT_SLAVE_A); + if (skb2) + res2 = slave_xmit(hsr, skb2, HSR_PT_SLAVE_B); + else + res2 = NET_XMIT_DROP; + + rcu_read_lock(); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { - hsr->dev->stats.tx_packets++; - hsr->dev->stats.tx_bytes += skb->len; + master->dev->stats.tx_packets++; + master->dev->stats.tx_bytes += skb->len; } else { - hsr->dev->stats.tx_dropped++; + master->dev->stats.tx_dropped++; } + rcu_read_unlock(); return NETDEV_TX_OK; } @@ -322,31 +352,35 @@ static int hsr_pad(int size) static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) { struct hsr_priv *hsr; + struct hsr_port *master; struct sk_buff *skb; int hlen, tlen; struct hsr_sup_tag *hsr_stag; struct hsr_sup_payload *hsr_sp; unsigned long irqflags; + int res; + + hsr = netdev_priv(hsr_dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); - hlen = LL_RESERVED_SPACE(hsr_dev); - tlen = hsr_dev->needed_tailroom; + hlen = LL_RESERVED_SPACE(master->dev); + tlen = master->dev->needed_tailroom; skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen, GFP_ATOMIC); if (skb == NULL) return; - hsr = netdev_priv(hsr_dev); - skb_reserve(skb, hlen); - skb->dev = hsr_dev; + skb->dev = master->dev; skb->protocol = htons(ETH_P_PRP); skb->priority = TC_PRIO_CONTROL; - if (dev_hard_header(skb, skb->dev, ETH_P_PRP, - hsr->sup_multicast_addr, - skb->dev->dev_addr, skb->len) < 0) + res = dev_hard_header(skb, skb->dev, ETH_P_PRP, + hsr->sup_multicast_addr, + skb->dev->dev_addr, skb->len); + if (res <= 0) goto out; skb_pull(skb, sizeof(struct ethhdr)); @@ -367,12 +401,13 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) /* Payload: MacAddressA */ hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp)); - ether_addr_copy(hsr_sp->MacAddressA, hsr_dev->dev_addr); + ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr); dev_queue_xmit(skb); return; out: + WARN_ON_ONCE("HSR: Could not send supervision frame\n"); kfree_skb(skb); } @@ -382,14 +417,16 @@ out: static void hsr_announce(unsigned long data) { struct hsr_priv *hsr; + struct hsr_port *master; hsr = (struct hsr_priv *) data; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (hsr->announce_count < 3) { - send_hsr_supervision_frame(hsr->dev, HSR_TLV_ANNOUNCE); + send_hsr_supervision_frame(master->dev, HSR_TLV_ANNOUNCE); hsr->announce_count++; } else { - send_hsr_supervision_frame(hsr->dev, HSR_TLV_LIFE_CHECK); + send_hsr_supervision_frame(master->dev, HSR_TLV_LIFE_CHECK); } if (hsr->announce_count < 3) @@ -399,43 +436,28 @@ static void hsr_announce(unsigned long data) hsr->announce_timer.expires = jiffies + msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); - if (is_admin_up(hsr->dev)) + if (is_admin_up(master->dev)) add_timer(&hsr->announce_timer); } -static void restore_slaves(struct net_device *hsr_dev) -{ - struct hsr_priv *hsr; - - hsr = netdev_priv(hsr_dev); - hsr_del_slave(hsr, 1); - hsr_del_slave(hsr, 0); -} - -static void reclaim_hsr_dev(struct rcu_head *rh) -{ - struct hsr_priv *hsr; - - hsr = container_of(rh, struct hsr_priv, rcu_head); - free_netdev(hsr->dev); -} - - /* According to comments in the declaration of struct net_device, this function * is "Called from unregister, can be used to call free_netdev". Ok then... */ static void hsr_dev_destroy(struct net_device *hsr_dev) { struct hsr_priv *hsr; + struct hsr_port *port; hsr = netdev_priv(hsr_dev); + hsr_for_each_port(hsr, port) + hsr_del_port(port); del_timer_sync(&hsr->prune_timer); del_timer_sync(&hsr->announce_timer); - unregister_hsr_master(hsr); /* calls list_del_rcu on hsr */ - restore_slaves(hsr_dev); - call_rcu(&hsr->rcu_head, reclaim_hsr_dev); /* reclaim hsr */ + + synchronize_rcu(); + free_netdev(hsr_dev); } static const struct net_device_ops hsr_device_ops = { @@ -461,12 +483,11 @@ void hsr_dev_setup(struct net_device *dev) /* Return true if dev is a HSR master; return false otherwise. */ -bool is_hsr_master(struct net_device *dev) +inline bool is_hsr_master(struct net_device *dev) { return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); } - /* Default multicast address for HSR Supervision frames */ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 @@ -476,12 +497,11 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], unsigned char multicast_spec) { struct hsr_priv *hsr; + struct hsr_port *port; int res; hsr = netdev_priv(hsr_dev); - hsr->dev = hsr_dev; - hsr->slave[0] = NULL; - hsr->slave[1] = NULL; + INIT_LIST_HEAD(&hsr->ports); INIT_LIST_HEAD(&hsr->node_db); INIT_LIST_HEAD(&hsr->self_node_db); @@ -516,36 +536,42 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; -/* FIXME: should I modify the value of these? - * - * - hsr_dev->flags - i.e. - * IFF_MASTER/SLAVE? - * - hsr_dev->priv_flags - i.e. - * IFF_EBRIDGE? - * IFF_TX_SKB_SHARING? - * IFF_HSR_MASTER/SLAVE? - */ + /* FIXME: should I modify the value of these? + * + * - hsr_dev->flags - i.e. + * IFF_MASTER/SLAVE? + * - hsr_dev->priv_flags - i.e. + * IFF_EBRIDGE? + * IFF_TX_SKB_SHARING? + * IFF_HSR_MASTER/SLAVE? + */ /* Make sure the 1st call to netif_carrier_on() gets through */ netif_carrier_off(hsr_dev); - res = register_netdevice(hsr_dev); + res = hsr_add_port(hsr, hsr_dev, HSR_PT_MASTER); if (res) return res; - res = hsr_add_slave(hsr, slave[0], 0); + res = register_netdevice(hsr_dev); if (res) - return res; - res = hsr_add_slave(hsr, slave[1], 1); - if (res) { - hsr_del_slave(hsr, 0); - return res; - } + goto fail; + + res = hsr_add_port(hsr, slave[0], HSR_PT_SLAVE_A); + if (res) + goto fail; + res = hsr_add_port(hsr, slave[1], HSR_PT_SLAVE_B); + if (res) + goto fail; hsr->prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); add_timer(&hsr->prune_timer); - register_hsr_master(hsr); - return 0; + +fail: + hsr_for_each_port(hsr, port) + hsr_del_port(port); + + return res; } diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 3666f94c526f..c9b78c52c75b 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -27,12 +27,11 @@ struct hsr_node { struct list_head mac_list; unsigned char MacAddressA[ETH_ALEN]; unsigned char MacAddressB[ETH_ALEN]; - enum hsr_dev_idx AddrB_if;/* The local slave through which AddrB - * frames are received from this node - */ - unsigned long time_in[HSR_MAX_SLAVE]; - bool time_in_stale[HSR_MAX_SLAVE]; - u16 seq_out[HSR_MAX_DEV]; + /* Local slave through which AddrB frames are received from this node */ + enum hsr_port_type AddrB_port; + unsigned long time_in[HSR_PT_PORTS]; + bool time_in_stale[HSR_PT_PORTS]; + u16 seq_out[HSR_PT_PORTS]; struct rcu_head rcu_head; }; @@ -154,11 +153,10 @@ int hsr_create_self_node(struct list_head *self_node_db, * We also need to detect if the sender's SlaveA and SlaveB cables have been * swapped. */ -struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, - struct hsr_node *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx) +struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, + struct hsr_port *port) { + struct hsr_priv *hsr; struct hsr_sup_payload *hsr_sp; struct hsr_ethhdr_sp *hsr_ethsup; int i; @@ -166,6 +164,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb); hsr_sp = (struct hsr_sup_payload *) skb->data; + hsr = port->hsr; if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { /* Node has changed its AddrA, frame was received from SlaveB */ @@ -174,7 +173,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, node = NULL; } - if (node && (dev_idx == node->AddrB_if) && + if (node && (port->type == node->AddrB_port) && !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { /* Cables have been swapped */ list_del_rcu(&node->mac_list); @@ -182,8 +181,8 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, node = NULL; } - if (node && (dev_idx != node->AddrB_if) && - (node->AddrB_if != HSR_DEV_NONE) && + if (node && (port->type != node->AddrB_port) && + (node->AddrB_port != HSR_PT_NONE) && !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { /* Cables have been swapped */ list_del_rcu(&node->mac_list); @@ -200,7 +199,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, * address. Node is PICS_SUBS capable; merge its AddrB. */ ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); - node->AddrB_if = dev_idx; + node->AddrB_port = port->type; return node; } @@ -211,17 +210,15 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA); ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source)) - node->AddrB_if = dev_idx; - else - node->AddrB_if = HSR_DEV_NONE; + node->AddrB_port = port->type; /* We are only interested in time diffs here, so use current jiffies * as initialization. (0 could trigger an spurious ring error warning). */ now = jiffies; - for (i = 0; i < HSR_MAX_SLAVE; i++) + for (i = 0; i < HSR_PT_PORTS; i++) node->time_in[i] = now; - for (i = 0; i < HSR_MAX_DEV; i++) + for (i = 0; i < HSR_PT_PORTS; i++) node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1; list_add_tail_rcu(&node->mac_list, &hsr->node_db); @@ -265,13 +262,13 @@ void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb) * which "side" the different interfaces are. */ void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, - enum hsr_dev_idx dev_idx) + struct hsr_port *port) { struct hsr_node *node; rcu_read_lock(); node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest); - if (node && (node->AddrB_if == dev_idx)) + if (node && (node->AddrB_port == port->type)) ether_addr_copy(ethhdr->h_dest, node->MacAddressB); rcu_read_unlock(); } @@ -295,14 +292,10 @@ static bool seq_nr_after(u16 a, u16 b) #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) -void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx) +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port) { - if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) { - WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); - return; - } - node->time_in[dev_idx] = jiffies; - node->time_in_stale[dev_idx] = false; + node->time_in[port->type] = jiffies; + node->time_in_stale[port->type] = false; } @@ -314,16 +307,12 @@ void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx) * 0 otherwise, or * negative error code on error */ -int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, struct sk_buff *skb) { struct hsr_ethhdr *hsr_ethhdr; u16 sequence_nr; - if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) { - WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); - return -EINVAL; - } if (!skb_mac_header_was_set(skb)) { WARN_ONCE(1, "%s: Mac header not set\n", __func__); return -EINVAL; @@ -331,35 +320,32 @@ int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr); - if (seq_nr_before_or_eq(sequence_nr, node->seq_out[dev_idx])) + if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type])) return 1; - node->seq_out[dev_idx] = sequence_nr; + node->seq_out[port->type] = sequence_nr; return 0; } - -static bool is_late(struct hsr_node *node, enum hsr_dev_idx dev_idx) +static struct hsr_port *get_late_port(struct hsr_priv *hsr, + struct hsr_node *node) { - enum hsr_dev_idx other; - - if (node->time_in_stale[dev_idx]) - return true; - - if (dev_idx == HSR_DEV_SLAVE_A) - other = HSR_DEV_SLAVE_B; - else - other = HSR_DEV_SLAVE_A; - - if (node->time_in_stale[other]) - return false; + if (node->time_in_stale[HSR_PT_SLAVE_A]) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (node->time_in_stale[HSR_PT_SLAVE_B]) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + + if (time_after(node->time_in[HSR_PT_SLAVE_B], + node->time_in[HSR_PT_SLAVE_A] + + msecs_to_jiffies(MAX_SLAVE_DIFF))) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (time_after(node->time_in[HSR_PT_SLAVE_A], + node->time_in[HSR_PT_SLAVE_B] + + msecs_to_jiffies(MAX_SLAVE_DIFF))) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); - if (time_after(node->time_in[other], node->time_in[dev_idx] + - msecs_to_jiffies(MAX_SLAVE_DIFF))) - return true; - - return false; + return NULL; } @@ -370,6 +356,7 @@ void hsr_prune_nodes(unsigned long data) { struct hsr_priv *hsr; struct hsr_node *node; + struct hsr_port *port; unsigned long timestamp; unsigned long time_a, time_b; @@ -378,35 +365,33 @@ void hsr_prune_nodes(unsigned long data) rcu_read_lock(); list_for_each_entry_rcu(node, &hsr->node_db, mac_list) { /* Shorthand */ - time_a = node->time_in[HSR_DEV_SLAVE_A]; - time_b = node->time_in[HSR_DEV_SLAVE_B]; + time_a = node->time_in[HSR_PT_SLAVE_A]; + time_b = node->time_in[HSR_PT_SLAVE_B]; /* Check for timestamps old enough to risk wrap-around */ if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET/2)) - node->time_in_stale[HSR_DEV_SLAVE_A] = true; + node->time_in_stale[HSR_PT_SLAVE_A] = true; if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET/2)) - node->time_in_stale[HSR_DEV_SLAVE_B] = true; + node->time_in_stale[HSR_PT_SLAVE_B] = true; /* Get age of newest frame from node. * At least one time_in is OK here; nodes get pruned long * before both time_ins can get stale */ timestamp = time_a; - if (node->time_in_stale[HSR_DEV_SLAVE_A] || - (!node->time_in_stale[HSR_DEV_SLAVE_B] && + if (node->time_in_stale[HSR_PT_SLAVE_A] || + (!node->time_in_stale[HSR_PT_SLAVE_B] && time_after(time_b, time_a))) timestamp = time_b; /* Warn of ring error only as long as we get frames at all */ if (time_is_after_jiffies(timestamp + msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) { - - if (is_late(node, HSR_DEV_SLAVE_A)) - hsr_nl_ringerror(hsr, node->MacAddressA, - HSR_DEV_SLAVE_A); - else if (is_late(node, HSR_DEV_SLAVE_B)) - hsr_nl_ringerror(hsr, node->MacAddressA, - HSR_DEV_SLAVE_B); + rcu_read_lock(); + port = get_late_port(hsr, node); + if (port != NULL) + hsr_nl_ringerror(hsr, node->MacAddressA, port); + rcu_read_unlock(); } /* Prune old entries */ @@ -455,7 +440,7 @@ int hsr_get_node_data(struct hsr_priv *hsr, u16 *if2_seq) { struct hsr_node *node; - struct net_device *slave; + struct hsr_port *port; unsigned long tdiff; @@ -468,8 +453,8 @@ int hsr_get_node_data(struct hsr_priv *hsr, ether_addr_copy(addr_b, node->MacAddressB); - tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_A]; - if (node->time_in_stale[HSR_DEV_SLAVE_A]) + tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A]; + if (node->time_in_stale[HSR_PT_SLAVE_A]) *if1_age = INT_MAX; #if HZ <= MSEC_PER_SEC else if (tdiff > msecs_to_jiffies(INT_MAX)) @@ -478,8 +463,8 @@ int hsr_get_node_data(struct hsr_priv *hsr, else *if1_age = jiffies_to_msecs(tdiff); - tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_B]; - if (node->time_in_stale[HSR_DEV_SLAVE_B]) + tdiff = jiffies - node->time_in[HSR_PT_SLAVE_B]; + if (node->time_in_stale[HSR_PT_SLAVE_B]) *if2_age = INT_MAX; #if HZ <= MSEC_PER_SEC else if (tdiff > msecs_to_jiffies(INT_MAX)) @@ -489,14 +474,15 @@ int hsr_get_node_data(struct hsr_priv *hsr, *if2_age = jiffies_to_msecs(tdiff); /* Present sequence numbers as if they were incoming on interface */ - *if1_seq = node->seq_out[HSR_DEV_SLAVE_B]; - *if2_seq = node->seq_out[HSR_DEV_SLAVE_A]; + *if1_seq = node->seq_out[HSR_PT_SLAVE_B]; + *if2_seq = node->seq_out[HSR_PT_SLAVE_A]; - slave = hsr->slave[node->AddrB_if]; - if ((node->AddrB_if != HSR_DEV_NONE) && slave) - *addr_b_ifindex = slave->ifindex; - else + if (node->AddrB_port != HSR_PT_NONE) { + port = hsr_port_get_hsr(hsr, node->AddrB_port); + *addr_b_ifindex = port->dev->ifindex; + } else { *addr_b_ifindex = -1; + } rcu_read_unlock(); diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index ccb09cf4ec5b..c87f36fc154c 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -18,18 +18,16 @@ struct hsr_node; struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); -struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, - struct hsr_node *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx); +struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, + struct hsr_port *port); void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb); void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, - enum hsr_dev_idx dev_idx); + struct hsr_port *port); -void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx); +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port); -int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, struct sk_buff *skb); void hsr_prune_nodes(unsigned long data); diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index b5abe26f7b4c..a06cab57ab68 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -39,76 +39,25 @@ void unregister_hsr_master(struct hsr_priv *hsr) } } -bool is_hsr_slave(struct net_device *dev) -{ - struct hsr_priv *hsr_it; - - list_for_each_entry_rcu(hsr_it, &hsr_list, hsr_list) { - if (dev == hsr_it->slave[0]) - return true; - if (dev == hsr_it->slave[1]) - return true; - } - - return false; -} - -/* If dev is a HSR slave device, return the virtual master device. Return NULL - * otherwise. - */ -struct hsr_priv *get_hsr_master(struct net_device *dev) -{ - struct hsr_priv *hsr; - - rcu_read_lock(); - list_for_each_entry_rcu(hsr, &hsr_list, hsr_list) - if ((dev == hsr->slave[0]) || - (dev == hsr->slave[1])) { - rcu_read_unlock(); - return hsr; - } - - rcu_read_unlock(); - return NULL; -} - -/* If dev is a HSR slave device, return the other slave device. Return NULL - * otherwise. - */ -struct net_device *get_other_slave(struct hsr_priv *hsr, - struct net_device *dev) -{ - if (dev == hsr->slave[0]) - return hsr->slave[1]; - if (dev == hsr->slave[1]) - return hsr->slave[0]; - - return NULL; -} - static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, void *ptr) { - struct net_device *slave, *other_slave; + struct net_device *dev; + struct hsr_port *port, *master; struct hsr_priv *hsr; int mtu_max; int res; - struct net_device *dev; dev = netdev_notifier_info_to_dev(ptr); - - hsr = get_hsr_master(dev); - if (hsr) { - /* dev is a slave device */ - slave = dev; - other_slave = get_other_slave(hsr, slave); - } else { + port = hsr_port_get_rtnl(dev); + if (port == NULL) { if (!is_hsr_master(dev)) - return NOTIFY_DONE; + return NOTIFY_DONE; /* Not an HSR device */ hsr = netdev_priv(dev); - slave = hsr->slave[0]; - other_slave = hsr->slave[1]; + port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + } else { + hsr = port->hsr; } switch (event) { @@ -118,48 +67,41 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, hsr_check_carrier_and_operstate(hsr); break; case NETDEV_CHANGEADDR: - - /* This should not happen since there's no ndo_set_mac_address() - * for HSR devices - i.e. not supported. - */ - if (dev == hsr->dev) + if (port->type == HSR_PT_MASTER) { + /* This should not happen since there's no + * ndo_set_mac_address() for HSR devices - i.e. not + * supported. + */ break; + } - if (dev == hsr->slave[0]) { - ether_addr_copy(hsr->dev->dev_addr, dev->dev_addr); - call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr->dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + + if (port->type == HSR_PT_SLAVE_A) { + ether_addr_copy(master->dev->dev_addr, dev->dev_addr); + call_netdevice_notifiers(NETDEV_CHANGEADDR, master->dev); } /* Make sure we recognize frames from ourselves in hsr_rcv() */ - other_slave = hsr->slave[1]; + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); res = hsr_create_self_node(&hsr->self_node_db, - hsr->dev->dev_addr, - other_slave ? - other_slave->dev_addr : - hsr->dev->dev_addr); + master->dev->dev_addr, + port ? + port->dev->dev_addr : + master->dev->dev_addr); if (res) - netdev_warn(hsr->dev, + netdev_warn(master->dev, "Could not update HSR node address.\n"); break; case NETDEV_CHANGEMTU: - if (dev == hsr->dev) + if (port->type == HSR_PT_MASTER) break; /* Handled in ndo_change_mtu() */ - mtu_max = hsr_get_max_mtu(hsr); - if (hsr->dev->mtu > mtu_max) - dev_set_mtu(hsr->dev, mtu_max); + mtu_max = hsr_get_max_mtu(port->hsr); + master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); + master->dev->mtu = mtu_max; break; case NETDEV_UNREGISTER: - if (dev == hsr->slave[0]) { - hsr->slave[0] = NULL; - hsr_del_slave(hsr, 0); - } - if (dev == hsr->slave[1]) { - hsr->slave[1] = NULL; - hsr_del_slave(hsr, 1); - } - - /* There should really be a way to set a new slave device... */ - + hsr_del_port(port); break; case NETDEV_PRE_TYPE_CHANGE: /* HSR works only on Ethernet devices. Refuse slave to change @@ -172,6 +114,16 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, } +struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) +{ + struct hsr_port *port; + + hsr_for_each_port(hsr, port) + if (port->type == pt) + return port; + return NULL; +} + static struct notifier_block hsr_nb = { .notifier_call = hsr_netdev_notify, /* Slave event notifications */ }; diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 43689a6d731f..e31c3069fdf8 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -136,20 +136,26 @@ struct hsr_ethhdr_sp { } __packed; -enum hsr_dev_idx { - HSR_DEV_NONE = -1, - HSR_DEV_SLAVE_A = 0, - HSR_DEV_SLAVE_B, - HSR_DEV_MASTER, +enum hsr_port_type { + HSR_PT_NONE = 0, /* Must be 0, used by framereg */ + HSR_PT_SLAVE_A, + HSR_PT_SLAVE_B, + HSR_PT_INTERLINK, + HSR_PT_MASTER, + HSR_PT_PORTS, /* This must be the last item in the enum */ +}; + +struct hsr_port { + struct list_head port_list; + struct net_device *dev; + struct hsr_priv *hsr; + enum hsr_port_type type; }; -#define HSR_MAX_SLAVE (HSR_DEV_SLAVE_B + 1) -#define HSR_MAX_DEV (HSR_DEV_MASTER + 1) struct hsr_priv { struct list_head hsr_list; /* List of hsr devices */ struct rcu_head rcu_head; - struct net_device *dev; - struct net_device *slave[HSR_MAX_SLAVE]; + struct list_head ports; struct list_head node_db; /* Other HSR nodes */ struct list_head self_node_db; /* MACs of slaves */ struct timer_list announce_timer; /* Supervision frame dispatch */ @@ -160,11 +166,6 @@ struct hsr_priv { unsigned char sup_multicast_addr[ETH_ALEN]; }; -void register_hsr_master(struct hsr_priv *hsr); -void unregister_hsr_master(struct hsr_priv *hsr); -bool is_hsr_slave(struct net_device *dev); -struct hsr_priv *get_hsr_master(struct net_device *dev); -struct net_device *get_other_slave(struct hsr_priv *hsr, - struct net_device *dev); +struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt); #endif /* __HSR_PRIVATE_H */ diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index a2ce359774f3..67082453928c 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -64,7 +64,7 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct hsr_priv *hsr; - struct net_device *slave; + struct hsr_port *port; int res; hsr = netdev_priv(dev); @@ -72,17 +72,17 @@ static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) res = 0; rcu_read_lock(); - slave = hsr->slave[0]; - if (slave) - res = nla_put_u32(skb, IFLA_HSR_SLAVE1, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (port) + res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex); rcu_read_unlock(); if (res) goto nla_put_failure; rcu_read_lock(); - slave = hsr->slave[1]; - if (slave) - res = nla_put_u32(skb, IFLA_HSR_SLAVE2, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + if (port) + res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex); rcu_read_unlock(); if (res) goto nla_put_failure; @@ -141,13 +141,12 @@ static const struct genl_multicast_group hsr_mcgrps[] = { * (i.e. a link has failed somewhere). */ v |