hsr_framereg.c (c5a7591172100269e426cf630da0f2dc8138a206) hsr_framereg.c (f266a683a4804dc499efc6c2206ef68efed029d0)
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):

--- 21 unchanged lines hidden (view full) ---

30 /* Local slave through which AddrB frames are received from this node */
31 enum hsr_port_type AddrB_port;
32 unsigned long time_in[HSR_PT_PORTS];
33 bool time_in_stale[HSR_PT_PORTS];
34 u16 seq_out[HSR_PT_PORTS];
35 struct rcu_head rcu_head;
36};
37
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):

--- 21 unchanged lines hidden (view full) ---

30 /* Local slave through which AddrB frames are received from this node */
31 enum hsr_port_type AddrB_port;
32 unsigned long time_in[HSR_PT_PORTS];
33 bool time_in_stale[HSR_PT_PORTS];
34 u16 seq_out[HSR_PT_PORTS];
35 struct rcu_head rcu_head;
36};
37
38
38/* TODO: use hash lists for mac addresses (linux/jhash.h)? */
39
40
39/* TODO: use hash lists for mac addresses (linux/jhash.h)? */
40
41
41
42/* Search for mac entry. Caller must hold rcu read lock.
42/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b,
43 * false otherwise.
43 */
44 */
44static struct hsr_node *find_node_by_AddrA(struct list_head *node_db,
45 const unsigned char addr[ETH_ALEN])
45static bool seq_nr_after(u16 a, u16 b)
46{
46{
47 struct hsr_node *node;
47 /* Remove inconsistency where
48 * seq_nr_after(a, b) == seq_nr_before(a, b)
49 */
50 if ((int) b - a == 32768)
51 return false;
48
52
49 list_for_each_entry_rcu(node, node_db, mac_list) {
50 if (ether_addr_equal(node->MacAddressA, addr))
51 return node;
52 }
53
54 return NULL;
53 return (((s16) (b - a)) < 0);
55}
54}
55#define seq_nr_before(a, b) seq_nr_after((b), (a))
56#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b)))
57#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))
56
57
58
59
58/* Search for mac entry. Caller must hold rcu read lock.
59 */
60static struct hsr_node *find_node_by_AddrB(struct list_head *node_db,
61 const unsigned char addr[ETH_ALEN])
60bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
62{
63 struct hsr_node *node;
64
61{
62 struct hsr_node *node;
63
65 list_for_each_entry_rcu(node, node_db, mac_list) {
66 if (ether_addr_equal(node->MacAddressB, addr))
67 return node;
64 node = list_first_or_null_rcu(&hsr->self_node_db, struct hsr_node,
65 mac_list);
66 if (!node) {
67 WARN_ONCE(1, "HSR: No self node\n");
68 return false;
68 }
69
69 }
70
70 return NULL;
71 if (ether_addr_equal(addr, node->MacAddressA))
72 return true;
73 if (ether_addr_equal(addr, node->MacAddressB))
74 return true;
75
76 return false;
71}
72
77}
78
73
74/* Search for mac entry. Caller must hold rcu read lock.
75 */
79/* Search for mac entry. Caller must hold rcu read lock.
80 */
76struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb)
81static struct hsr_node *find_node_by_AddrA(struct list_head *node_db,
82 const unsigned char addr[ETH_ALEN])
77{
78 struct hsr_node *node;
83{
84 struct hsr_node *node;
79 struct ethhdr *ethhdr;
80
85
81 if (!skb_mac_header_was_set(skb))
82 return NULL;
83
84 ethhdr = (struct ethhdr *) skb_mac_header(skb);
85
86 list_for_each_entry_rcu(node, node_db, mac_list) {
86 list_for_each_entry_rcu(node, node_db, mac_list) {
87 if (ether_addr_equal(node->MacAddressA, ethhdr->h_source))
87 if (ether_addr_equal(node->MacAddressA, addr))
88 return node;
88 return node;
89 if (ether_addr_equal(node->MacAddressB, ethhdr->h_source))
90 return node;
91 }
92
93 return NULL;
94}
95
96
97/* Helper for device init; the self_node_db is used in hsr_rcv() to recognize
98 * frames from self that's been looped over the HSR ring.

--- 23 unchanged lines hidden (view full) ---

122 rcu_read_unlock();
123 list_add_tail_rcu(&node->mac_list, self_node_db);
124 }
125
126 return 0;
127}
128
129
89 }
90
91 return NULL;
92}
93
94
95/* Helper for device init; the self_node_db is used in hsr_rcv() to recognize
96 * frames from self that's been looped over the HSR ring.

--- 23 unchanged lines hidden (view full) ---

120 rcu_read_unlock();
121 list_add_tail_rcu(&node->mac_list, self_node_db);
122 }
123
124 return 0;
125}
126
127
130/* Add/merge node to the database of nodes. 'skb' must contain an HSR
131 * supervision frame.
132 * - If the supervision header's MacAddressA field is not yet in the database,
133 * this frame is from an hitherto unknown node - add it to the database.
134 * - If the sender's MAC address is not the same as its MacAddressA address,
135 * the node is using PICS_SUBS (address substitution). Record the sender's
136 * address as the node's MacAddressB.
137 *
138 * This function needs to work even if the sender node has changed one of its
139 * slaves' MAC addresses. In this case, there are four different cases described
140 * by (Addr-changed, received-from) pairs as follows. Note that changing the
141 * SlaveA address is equal to changing the node's own address:
142 *
143 * - (AddrB, SlaveB): The new AddrB will be recorded by PICS_SUBS code since
144 * node == NULL.
145 * - (AddrB, SlaveA): Will work as usual (the AddrB change won't be detected
146 * from this frame).
147 *
148 * - (AddrA, SlaveB): The old node will be found. We need to detect this and
149 * remove the node.
150 * - (AddrA, SlaveA): A new node will be registered (non-PICS_SUBS at first).
151 * The old one will be pruned after HSR_NODE_FORGET_TIME.
152 *
153 * We also need to detect if the sender's SlaveA and SlaveB cables have been
154 * swapped.
128/* Allocate an hsr_node and add it to node_db. 'addr' is the node's AddressA;
129 * seq_out is used to initialize filtering of outgoing duplicate frames
130 * originating from the newly added node.
155 */
131 */
156struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb,
157 struct hsr_port *port)
132struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[],
133 u16 seq_out)
158{
134{
159 struct hsr_priv *hsr;
160 struct hsr_sup_payload *hsr_sp;
161 struct hsr_ethhdr_sp *hsr_ethsup;
162 int i;
135 struct hsr_node *node;
163 unsigned long now;
136 unsigned long now;
137 int i;
164
138
165 hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb);
166 hsr_sp = (struct hsr_sup_payload *) skb->data;
167 hsr = port->hsr;
168
169 if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) {
170 /* Node has changed its AddrA, frame was received from SlaveB */
171 list_del_rcu(&node->mac_list);
172 kfree_rcu(node, rcu_head);
173 node = NULL;
174 }
175
176 if (node && (port->type == node->AddrB_port) &&
177 !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) {
178 /* Cables have been swapped */
179 list_del_rcu(&node->mac_list);
180 kfree_rcu(node, rcu_head);
181 node = NULL;
182 }
183
184 if (node && (port->type != node->AddrB_port) &&
185 (node->AddrB_port != HSR_PT_NONE) &&
186 !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) {
187 /* Cables have been swapped */
188 list_del_rcu(&node->mac_list);
189 kfree_rcu(node, rcu_head);
190 node = NULL;
191 }
192
193 if (node)
194 return node;
195
196 node = find_node_by_AddrA(&hsr->node_db, hsr_sp->MacAddressA);
197 if (node) {
198 /* Node is known, but frame was received from an unknown
199 * address. Node is PICS_SUBS capable; merge its AddrB.
200 */
201 ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
202 node->AddrB_port = port->type;
203 return node;
204 }
205
206 node = kzalloc(sizeof(*node), GFP_ATOMIC);
207 if (!node)
208 return NULL;
209
139 node = kzalloc(sizeof(*node), GFP_ATOMIC);
140 if (!node)
141 return NULL;
142
210 ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA);
211 ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
212 if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source))
213 node->AddrB_port = port->type;
143 ether_addr_copy(node->MacAddressA, addr);
214
215 /* We are only interested in time diffs here, so use current jiffies
216 * as initialization. (0 could trigger an spurious ring error warning).
217 */
218 now = jiffies;
219 for (i = 0; i < HSR_PT_PORTS; i++)
220 node->time_in[i] = now;
221 for (i = 0; i < HSR_PT_PORTS; i++)
144
145 /* We are only interested in time diffs here, so use current jiffies
146 * as initialization. (0 could trigger an spurious ring error warning).
147 */
148 now = jiffies;
149 for (i = 0; i < HSR_PT_PORTS; i++)
150 node->time_in[i] = now;
151 for (i = 0; i < HSR_PT_PORTS; i++)
222 node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1;
152 node->seq_out[i] = seq_out;
223
153
224 list_add_tail_rcu(&node->mac_list, &hsr->node_db);
154 list_add_tail_rcu(&node->mac_list, node_db);
225
226 return node;
227}
228
155
156 return node;
157}
158
159/* Get the hsr_node from which 'skb' was sent.
160 */
161struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
162 bool is_sup)
163{
164 struct hsr_node *node;
165 struct ethhdr *ethhdr;
166 u16 seq_out;
229
167
168 if (!skb_mac_header_was_set(skb))
169 return NULL;
170
171 ethhdr = (struct ethhdr *) skb_mac_header(skb);
172
173 list_for_each_entry_rcu(node, node_db, mac_list) {
174 if (ether_addr_equal(node->MacAddressA, ethhdr->h_source))
175 return node;
176 if (ether_addr_equal(node->MacAddressB, ethhdr->h_source))
177 return node;
178 }
179
180 if (!is_sup)
181 return NULL; /* Only supervision frame may create node entry */
182
183 if (ethhdr->h_proto == htons(ETH_P_PRP)) {
184 /* Use the existing sequence_nr from the tag as starting point
185 * for filtering duplicate frames.
186 */
187 seq_out = hsr_get_skb_sequence_nr(skb) - 1;
188 } else {
189 WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
190 seq_out = 0;
191 }
192
193 return hsr_add_node(node_db, ethhdr->h_source, seq_out);
194}
195
196/* Use the Supervision frame's info about an eventual MacAddressB for merging
197 * nodes that has previously had their MacAddressB registered as a separate
198 * node.
199 */
200void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
201 struct hsr_port *port_rcv)
202{
203 struct hsr_node *node_real;
204 struct hsr_sup_payload *hsr_sp;
205 struct list_head *node_db;
206 int i;
207
208 skb_pull(skb, sizeof(struct hsr_ethhdr_sp));
209 hsr_sp = (struct hsr_sup_payload *) skb->data;
210
211 if (ether_addr_equal(eth_hdr(skb)->h_source, hsr_sp->MacAddressA))
212 /* Not sent from MacAddressB of a PICS_SUBS capable node */
213 goto done;
214
215 /* Merge node_curr (registered on MacAddressB) into node_real */
216 node_db = &port_rcv->hsr->node_db;
217 node_real = find_node_by_AddrA(node_db, hsr_sp->MacAddressA);
218 if (!node_real)
219 /* No frame received from AddrA of this node yet */
220 node_real = hsr_add_node(node_db, hsr_sp->MacAddressA,
221 HSR_SEQNR_START - 1);
222 if (!node_real)
223 goto done; /* No mem */
224 if (node_real == node_curr)
225 /* Node has already been merged */
226 goto done;
227
228 ether_addr_copy(node_real->MacAddressB, eth_hdr(skb)->h_source);
229 for (i = 0; i < HSR_PT_PORTS; i++) {
230 if (!node_curr->time_in_stale[i] &&
231 time_after(node_curr->time_in[i], node_real->time_in[i])) {
232 node_real->time_in[i] = node_curr->time_in[i];
233 node_real->time_in_stale[i] = node_curr->time_in_stale[i];
234 }
235 if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i]))
236 node_real->seq_out[i] = node_curr->seq_out[i];
237 }
238 node_real->AddrB_port = port_rcv->type;
239
240 list_del_rcu(&node_curr->mac_list);
241 kfree_rcu(node_curr, rcu_head);
242
243done:
244 skb_push(skb, sizeof(struct hsr_ethhdr_sp));
245}
246
247
230/* 'skb' is a frame meant for this host, that is to be passed to upper layers.
231 *
248/* 'skb' is a frame meant for this host, that is to be passed to upper layers.
249 *
232 * If the frame was sent by a node's B interface, replace the sender
250 * If the frame was sent by a node's B interface, replace the source
233 * address with that node's "official" address (MacAddressA) so that upper
234 * layers recognize where it came from.
235 */
251 * address with that node's "official" address (MacAddressA) so that upper
252 * layers recognize where it came from.
253 */
236void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb)
254void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb)
237{
255{
238 struct ethhdr *ethhdr;
239 struct hsr_node *node;
240
241 if (!skb_mac_header_was_set(skb)) {
242 WARN_ONCE(1, "%s: Mac header not set\n", __func__);
243 return;
244 }
256 if (!skb_mac_header_was_set(skb)) {
257 WARN_ONCE(1, "%s: Mac header not set\n", __func__);
258 return;
259 }
245 ethhdr = (struct ethhdr *) skb_mac_header(skb);
246
260
247 rcu_read_lock();
248 node = find_node_by_AddrB(&hsr->node_db, ethhdr->h_source);
249 if (node)
250 ether_addr_copy(ethhdr->h_source, node->MacAddressA);
251 rcu_read_unlock();
261 memcpy(&eth_hdr(skb)->h_source, node->MacAddressA, ETH_ALEN);
252}
253
262}
263
254
255/* 'skb' is a frame meant for another host.
264/* 'skb' is a frame meant for another host.
256 * 'hsr_dev_idx' is the HSR index of the outgoing device
265 * 'port' is the outgoing interface
257 *
258 * Substitute the target (dest) MAC address if necessary, so the it matches the
259 * recipient interface MAC address, regardless of whether that is the
260 * recipient's A or B interface.
261 * This is needed to keep the packets flowing through switches that learn on
262 * which "side" the different interfaces are.
263 */
266 *
267 * Substitute the target (dest) MAC address if necessary, so the it matches the
268 * recipient interface MAC address, regardless of whether that is the
269 * recipient's A or B interface.
270 * This is needed to keep the packets flowing through switches that learn on
271 * which "side" the different interfaces are.
272 */
264void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr,
273void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
265 struct hsr_port *port)
266{
274 struct hsr_port *port)
275{
267 struct hsr_node *node;
276 struct hsr_node *node_dst;
268
277
269 rcu_read_lock();
270 node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest);
271 if (node && (node->AddrB_port == port->type))
272 ether_addr_copy(ethhdr->h_dest, node->MacAddressB);
273 rcu_read_unlock();
274}
278 if (!skb_mac_header_was_set(skb)) {
279 WARN_ONCE(1, "%s: Mac header not set\n", __func__);
280 return;
281 }
275
282
283 if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest))
284 return;
276
285
277/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b,
278 * false otherwise.
279 */
280static bool seq_nr_after(u16 a, u16 b)
281{
282 /* Remove inconsistency where
283 * seq_nr_after(a, b) == seq_nr_before(a, b)
284 */
285 if ((int) b - a == 32768)
286 return false;
286 node_dst = find_node_by_AddrA(&port->hsr->node_db, eth_hdr(skb)->h_dest);
287 if (!node_dst) {
288 WARN_ONCE(1, "%s: Unknown node\n", __func__);
289 return;
290 }
291 if (port->type != node_dst->AddrB_port)
292 return;
293 if (!node_dst->MacAddressB) {
294 WARN_ONCE(1, "%s: No MacAddressB\n", __func__);
295 return;
296 }
287
297
288 return (((s16) (b - a)) < 0);
298 ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->MacAddressB);
289}
299}
290#define seq_nr_before(a, b) seq_nr_after((b), (a))
291#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b)))
292#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))
293
294
300
301
295void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port)
302void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
303 u16 sequence_nr)
296{
304{
305 /* Don't register incoming frames without a valid sequence number. This
306 * ensures entries of restarted nodes gets pruned so that they can
307 * re-register and resume communications.
308 */
309 if (seq_nr_before(sequence_nr, node->seq_out[port->type]))
310 return;
311
297 node->time_in[port->type] = jiffies;
298 node->time_in_stale[port->type] = false;
299}
300
312 node->time_in[port->type] = jiffies;
313 node->time_in_stale[port->type] = false;
314}
315
301
302/* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid
303 * ethhdr->h_source address and skb->mac_header set.
304 *
305 * Return:
306 * 1 if frame can be shown to have been sent recently on this interface,
307 * 0 otherwise, or
308 * negative error code on error
309 */
316/* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid
317 * ethhdr->h_source address and skb->mac_header set.
318 *
319 * Return:
320 * 1 if frame can be shown to have been sent recently on this interface,
321 * 0 otherwise, or
322 * negative error code on error
323 */
310int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port,
311 struct sk_buff *skb)
324int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
325 u16 sequence_nr)
312{
326{
313 struct hsr_ethhdr *hsr_ethhdr;
314 u16 sequence_nr;
315
316 if (!skb_mac_header_was_set(skb)) {
317 WARN_ONCE(1, "%s: Mac header not set\n", __func__);
318 return -EINVAL;
319 }
320 hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb);
321
322 sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
323 if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type]))
324 return 1;
325
326 node->seq_out[port->type] = sequence_nr;
327 return 0;
328}
329
330

--- 160 unchanged lines hidden ---
327 if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type]))
328 return 1;
329
330 node->seq_out[port->type] = sequence_nr;
331 return 0;
332}
333
334

--- 160 unchanged lines hidden ---