Skip to content

Commit f266a68

Browse files
Arvid Brodindavem330
authored andcommitted
net/hsr: Better frame dispatch
This patch removes the separate paths for frames coming from the outside, and frames sent from the HSR device, and instead makes all frames go through hsr_forward_skb() in hsr_forward.c. This greatly improves code readability and also opens up the possibility for future support of the HSR Interlink device that is the basis for HSR RedBoxes and HSR QuadBoxes, as well as VLAN compatibility. Other improvements: * A reduction in the number of times an skb is copied on machines without HAVE_EFFICIENT_UNALIGNED_ACCESS, which improves throughput somewhat. * Headers are now created using the standard eth_header(), and using the standard hard_header_len. * Each HSR slave now gets its own private skb, so slave-specific fields can be correctly set. Signed-off-by: Arvid Brodin <arvid.brodin@alten.se> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 4c3477d commit f266a68

File tree

11 files changed

+656
-586
lines changed

11 files changed

+656
-586
lines changed

net/hsr/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
obj-$(CONFIG_HSR) += hsr.o
66

7-
hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o \
8-
hsr_slave.o
7+
hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \
8+
hsr_netlink.o hsr_slave.o hsr_forward.o

net/hsr/hsr_device.c

Lines changed: 23 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "hsr_slave.h"
2222
#include "hsr_framereg.h"
2323
#include "hsr_main.h"
24+
#include "hsr_forward.h"
2425

2526

2627
static bool is_admin_up(struct net_device *dev)
@@ -231,141 +232,21 @@ static netdev_features_t hsr_fix_features(struct net_device *dev,
231232
}
232233

233234

234-
static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr)
235-
{
236-
unsigned long irqflags;
237-
238-
/* IEC 62439-1:2010, p 48, says the 4-bit "path" field can take values
239-
* between 0001-1001 ("ring identifier", for regular HSR frames),
240-
* or 1111 ("HSR management", supervision frames). Unfortunately, the
241-
* spec writers forgot to explain what a "ring identifier" is, or
242-
* how it is used. So we just set this to 0001 for regular frames,
243-
* and 1111 for supervision frames.
244-
*/
245-
set_hsr_tag_path(&hsr_ethhdr->hsr_tag, 0x1);
246-
247-
/* IEC 62439-1:2010, p 12: "The link service data unit in an Ethernet
248-
* frame is the content of the frame located between the Length/Type
249-
* field and the Frame Check Sequence."
250-
*
251-
* IEC 62439-3, p 48, specifies the "original LPDU" to include the
252-
* original "LT" field (what "LT" means is not explained anywhere as
253-
* far as I can see - perhaps "Length/Type"?). So LSDU_size might
254-
* equal original length + 2.
255-
* Also, the fact that this field is not used anywhere (might be used
256-
* by a RedBox connecting HSR and PRP nets?) means I cannot test its
257-
* correctness. Instead of guessing, I set this to 0 here, to make any
258-
* problems immediately apparent. Anyone using this driver with PRP/HSR
259-
* RedBoxes might need to fix this...
260-
*/
261-
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, 0);
262-
263-
spin_lock_irqsave(&hsr->seqnr_lock, irqflags);
264-
hsr_ethhdr->hsr_tag.sequence_nr = htons(hsr->sequence_nr);
265-
hsr->sequence_nr++;
266-
spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags);
267-
268-
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
269-
270-
hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP);
271-
}
272-
273-
static int slave_xmit(struct hsr_priv *hsr, struct sk_buff *skb,
274-
enum hsr_port_type type)
275-
{
276-
struct hsr_port *port;
277-
struct hsr_ethhdr *hsr_ethhdr;
278-
279-
hsr_ethhdr = (struct hsr_ethhdr *) skb->data;
280-
281-
rcu_read_lock();
282-
port = hsr_port_get_hsr(hsr, type);
283-
if (!port) {
284-
rcu_read_unlock();
285-
return NET_XMIT_DROP;
286-
}
287-
skb->dev = port->dev;
288-
289-
hsr_addr_subst_dest(port->hsr, &hsr_ethhdr->ethhdr, port);
290-
rcu_read_unlock();
291-
292-
/* Address substitution (IEC62439-3 pp 26, 50): replace mac
293-
* address of outgoing frame with that of the outgoing slave's.
294-
*/
295-
ether_addr_copy(hsr_ethhdr->ethhdr.h_source, skb->dev->dev_addr);
296-
297-
return dev_queue_xmit(skb);
298-
}
299-
300235
static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
301236
{
302-
struct hsr_priv *hsr;
237+
struct hsr_priv *hsr = netdev_priv(dev);
303238
struct hsr_port *master;
304-
struct hsr_ethhdr *hsr_ethhdr;
305-
struct sk_buff *skb2;
306-
int res1, res2;
307-
308-
hsr = netdev_priv(dev);
309-
hsr_ethhdr = (struct hsr_ethhdr *) skb->data;
310-
311-
if ((skb->protocol != htons(ETH_P_PRP)) ||
312-
(hsr_ethhdr->ethhdr.h_proto != htons(ETH_P_PRP))) {
313-
hsr_fill_tag(hsr_ethhdr, hsr);
314-
skb->protocol = htons(ETH_P_PRP);
315-
}
316239

317-
skb2 = pskb_copy(skb, GFP_ATOMIC);
318-
319-
res1 = slave_xmit(hsr, skb, HSR_PT_SLAVE_A);
320-
if (skb2)
321-
res2 = slave_xmit(hsr, skb2, HSR_PT_SLAVE_B);
322-
else
323-
res2 = NET_XMIT_DROP;
324-
325-
rcu_read_lock();
326240
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
327-
if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN ||
328-
res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) {
329-
master->dev->stats.tx_packets++;
330-
master->dev->stats.tx_bytes += skb->len;
331-
} else {
332-
master->dev->stats.tx_dropped++;
333-
}
334-
rcu_read_unlock();
241+
skb->dev = master->dev;
242+
hsr_forward_skb(skb, master);
335243

336244
return NETDEV_TX_OK;
337245
}
338246

339247

340-
static int hsr_header_create(struct sk_buff *skb, struct net_device *dev,
341-
unsigned short type, const void *daddr,
342-
const void *saddr, unsigned int len)
343-
{
344-
int res;
345-
346-
/* Make room for the HSR tag now. We will fill it in later (in
347-
* hsr_dev_xmit)
348-
*/
349-
if (skb_headroom(skb) < HSR_HLEN + ETH_HLEN)
350-
return -ENOBUFS;
351-
skb_push(skb, HSR_HLEN);
352-
353-
/* To allow VLAN/HSR combos we should probably use
354-
* res = dev_hard_header(skb, dev, type, daddr, saddr, len + HSR_HLEN);
355-
* here instead. It would require other changes too, though - e.g.
356-
* separate headers for each slave etc...
357-
*/
358-
res = eth_header(skb, dev, type, daddr, saddr, len + HSR_HLEN);
359-
if (res <= 0)
360-
return res;
361-
skb_reset_mac_header(skb);
362-
363-
return res + HSR_HLEN;
364-
}
365-
366-
367248
static const struct header_ops hsr_header_ops = {
368-
.create = hsr_header_create,
249+
.create = eth_header,
369250
.parse = eth_header_parse,
370251
};
371252

@@ -382,19 +263,13 @@ static int hsr_pad(int size)
382263
return min_size;
383264
}
384265

385-
static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type)
266+
static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
386267
{
387-
struct hsr_priv *hsr;
388-
struct hsr_port *master;
389268
struct sk_buff *skb;
390269
int hlen, tlen;
391270
struct hsr_sup_tag *hsr_stag;
392271
struct hsr_sup_payload *hsr_sp;
393272
unsigned long irqflags;
394-
int res;
395-
396-
hsr = netdev_priv(hsr_dev);
397-
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
398273

399274
hlen = LL_RESERVED_SPACE(master->dev);
400275
tlen = master->dev->needed_tailroom;
@@ -410,33 +285,30 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type)
410285
skb->protocol = htons(ETH_P_PRP);
411286
skb->priority = TC_PRIO_CONTROL;
412287

413-
res = dev_hard_header(skb, skb->dev, ETH_P_PRP,
414-
hsr->sup_multicast_addr,
415-
skb->dev->dev_addr, skb->len);
416-
if (res <= 0)
288+
if (dev_hard_header(skb, skb->dev, ETH_P_PRP,
289+
master->hsr->sup_multicast_addr,
290+
skb->dev->dev_addr, skb->len) <= 0)
417291
goto out;
292+
skb_reset_mac_header(skb);
418293

419-
skb_pull(skb, sizeof(struct ethhdr));
420-
hsr_stag = (typeof(hsr_stag)) skb->data;
294+
hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(*hsr_stag));
421295

422296
set_hsr_stag_path(hsr_stag, 0xf);
423297
set_hsr_stag_HSR_Ver(hsr_stag, 0);
424298

425-
spin_lock_irqsave(&hsr->seqnr_lock, irqflags);
426-
hsr_stag->sequence_nr = htons(hsr->sequence_nr);
427-
hsr->sequence_nr++;
428-
spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags);
299+
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
300+
hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
301+
master->hsr->sequence_nr++;
302+
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
429303

430304
hsr_stag->HSR_TLV_Type = type;
431305
hsr_stag->HSR_TLV_Length = 12;
432306

433-
skb_push(skb, sizeof(struct ethhdr));
434-
435307
/* Payload: MacAddressA */
436308
hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp));
437309
ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr);
438310

439-
dev_queue_xmit(skb);
311+
hsr_forward_skb(skb, master);
440312
return;
441313

442314
out:
@@ -453,13 +325,15 @@ static void hsr_announce(unsigned long data)
453325
struct hsr_port *master;
454326

455327
hsr = (struct hsr_priv *) data;
328+
329+
rcu_read_lock();
456330
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
457331

458332
if (hsr->announce_count < 3) {
459-
send_hsr_supervision_frame(master->dev, HSR_TLV_ANNOUNCE);
333+
send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE);
460334
hsr->announce_count++;
461335
} else {
462-
send_hsr_supervision_frame(master->dev, HSR_TLV_LIFE_CHECK);
336+
send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK);
463337
}
464338

465339
if (hsr->announce_count < 3)
@@ -471,6 +345,8 @@ static void hsr_announce(unsigned long data)
471345

472346
if (is_admin_up(master->dev))
473347
add_timer(&hsr->announce_timer);
348+
349+
rcu_read_unlock();
474350
}
475351

476352

@@ -570,7 +446,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
570446

571447
spin_lock_init(&hsr->seqnr_lock);
572448
/* Overflow soon to find bugs easier: */
573-
hsr->sequence_nr = USHRT_MAX - 1024;
449+
hsr->sequence_nr = HSR_SEQNR_START;
574450

575451
init_timer(&hsr->announce_timer);
576452
hsr->announce_timer.function = hsr_announce;

0 commit comments

Comments
 (0)