Skip to content

Commit ee1c279

Browse files
peterheisedavem330
authored andcommitted
net/hsr: Added support for HSR v1
This patch adds support for the newer version 1 of the HSR networking standard. Version 0 is still default and the new version has to be selected via iproute2. Main changes are in the supervision frame handling and its ethertype field. Signed-off-by: Peter Heise <peter.heise@airbus.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 125c8d1 commit ee1c279

File tree

10 files changed

+126
-63
lines changed

10 files changed

+126
-63
lines changed

include/uapi/linux/if_ether.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
#define ETH_P_TDLS 0x890D /* TDLS */
9393
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
9494
#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
95+
#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
9596
#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
9697
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
9798
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ enum {
773773
IFLA_HSR_SLAVE1,
774774
IFLA_HSR_SLAVE2,
775775
IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */
776+
IFLA_HSR_VERSION, /* HSR version */
776777
IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */
777778
IFLA_HSR_SEQ_NR,
778779
__IFLA_HSR_MAX,

net/hsr/Kconfig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ config HSR
1818
earlier.
1919

2020
This code is a "best effort" to comply with the HSR standard as
21-
described in IEC 62439-3:2010 (HSRv0), but no compliancy tests have
22-
been made.
21+
described in IEC 62439-3:2010 (HSRv0) and IEC 62439-3:2012 (HSRv1),
22+
but no compliancy tests have been made. Use iproute2 to select
23+
the version you desire.
2324

2425
You need to perform any and all necessary tests yourself before
2526
relying on this code in a safety critical system!

net/hsr/hsr_device.c

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ static void hsr_check_announce(struct net_device *hsr_dev,
9090

9191
hsr = netdev_priv(hsr_dev);
9292

93-
if ((hsr_dev->operstate == IF_OPER_UP) && (old_operstate != IF_OPER_UP)) {
93+
if ((hsr_dev->operstate == IF_OPER_UP)
94+
&& (old_operstate != IF_OPER_UP)) {
9495
/* Went up */
9596
hsr->announce_count = 0;
9697
hsr->announce_timer.expires = jiffies +
@@ -250,64 +251,71 @@ static const struct header_ops hsr_header_ops = {
250251
.parse = eth_header_parse,
251252
};
252253

253-
254-
/* HSR:2010 supervision frames should be padded so that the whole frame,
255-
* including headers and FCS, is 64 bytes (without VLAN).
256-
*/
257-
static int hsr_pad(int size)
258-
{
259-
const int min_size = ETH_ZLEN - HSR_HLEN - ETH_HLEN;
260-
261-
if (size >= min_size)
262-
return size;
263-
return min_size;
264-
}
265-
266-
static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
254+
static void send_hsr_supervision_frame(struct hsr_port *master,
255+
u8 type, u8 hsrVer)
267256
{
268257
struct sk_buff *skb;
269258
int hlen, tlen;
259+
struct hsr_tag *hsr_tag;
270260
struct hsr_sup_tag *hsr_stag;
271261
struct hsr_sup_payload *hsr_sp;
272262
unsigned long irqflags;
273263

274264
hlen = LL_RESERVED_SPACE(master->dev);
275265
tlen = master->dev->needed_tailroom;
276-
skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen,
277-
GFP_ATOMIC);
266+
skb = dev_alloc_skb(
267+
sizeof(struct hsr_tag) +
268+
sizeof(struct hsr_sup_tag) +
269+
sizeof(struct hsr_sup_payload) + hlen + tlen);
278270

279271
if (skb == NULL)
280272
return;
281273

282274
skb_reserve(skb, hlen);
283275

284276
skb->dev = master->dev;
285-
skb->protocol = htons(ETH_P_PRP);
277+
skb->protocol = htons(hsrVer ? ETH_P_HSR : ETH_P_PRP);
286278
skb->priority = TC_PRIO_CONTROL;
287279

288-
if (dev_hard_header(skb, skb->dev, ETH_P_PRP,
280+
if (dev_hard_header(skb, skb->dev, (hsrVer ? ETH_P_HSR : ETH_P_PRP),
289281
master->hsr->sup_multicast_addr,
290282
skb->dev->dev_addr, skb->len) <= 0)
291283
goto out;
292284
skb_reset_mac_header(skb);
293285

294-
hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(*hsr_stag));
286+
if (hsrVer > 0) {
287+
hsr_tag = (typeof(hsr_tag)) skb_put(skb, sizeof(struct hsr_tag));
288+
hsr_tag->encap_proto = htons(ETH_P_PRP);
289+
set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
290+
}
295291

296-
set_hsr_stag_path(hsr_stag, 0xf);
297-
set_hsr_stag_HSR_Ver(hsr_stag, 0);
292+
hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(struct hsr_sup_tag));
293+
set_hsr_stag_path(hsr_stag, (hsrVer ? 0x0 : 0xf));
294+
set_hsr_stag_HSR_Ver(hsr_stag, hsrVer);
298295

296+
/* From HSRv1 on we have separate supervision sequence numbers. */
299297
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
300-
hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
301-
master->hsr->sequence_nr++;
298+
if (hsrVer > 0) {
299+
hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
300+
hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
301+
master->hsr->sup_sequence_nr++;
302+
master->hsr->sequence_nr++;
303+
} else {
304+
hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
305+
master->hsr->sequence_nr++;
306+
}
302307
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
303308

304309
hsr_stag->HSR_TLV_Type = type;
305-
hsr_stag->HSR_TLV_Length = 12;
310+
/* TODO: Why 12 in HSRv0? */
311+
hsr_stag->HSR_TLV_Length = hsrVer ? sizeof(struct hsr_sup_payload) : 12;
306312

307313
/* Payload: MacAddressA */
308-
hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp));
314+
hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(struct hsr_sup_payload));
309315
ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr);
310316

317+
skb_put_padto(skb, ETH_ZLEN + HSR_HLEN);
318+
311319
hsr_forward_skb(skb, master);
312320
return;
313321

@@ -329,19 +337,20 @@ static void hsr_announce(unsigned long data)
329337
rcu_read_lock();
330338
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
331339

332-
if (hsr->announce_count < 3) {
333-
send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE);
340+
if (hsr->announce_count < 3 && hsr->protVersion == 0) {
341+
send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE,
342+
hsr->protVersion);
334343
hsr->announce_count++;
335-
} else {
336-
send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK);
337-
}
338344

339-
if (hsr->announce_count < 3)
340345
hsr->announce_timer.expires = jiffies +
341346
msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
342-
else
347+
} else {
348+
send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK,
349+
hsr->protVersion);
350+
343351
hsr->announce_timer.expires = jiffies +
344352
msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
353+
}
345354

346355
if (is_admin_up(master->dev))
347356
add_timer(&hsr->announce_timer);
@@ -428,7 +437,7 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
428437
};
429438

430439
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
431-
unsigned char multicast_spec)
440+
unsigned char multicast_spec, u8 protocol_version)
432441
{
433442
struct hsr_priv *hsr;
434443
struct hsr_port *port;
@@ -450,6 +459,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
450459
spin_lock_init(&hsr->seqnr_lock);
451460
/* Overflow soon to find bugs easier: */
452461
hsr->sequence_nr = HSR_SEQNR_START;
462+
hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
453463

454464
init_timer(&hsr->announce_timer);
455465
hsr->announce_timer.function = hsr_announce;
@@ -462,6 +472,8 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
462472
ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr);
463473
hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
464474

475+
hsr->protVersion = protocol_version;
476+
465477
/* FIXME: should I modify the value of these?
466478
*
467479
* - hsr_dev->flags - i.e.

net/hsr/hsr_device.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
void hsr_dev_setup(struct net_device *dev);
1919
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
20-
unsigned char multicast_spec);
20+
unsigned char multicast_spec, u8 protocol_version);
2121
void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
2222
bool is_hsr_master(struct net_device *dev);
2323
int hsr_get_max_mtu(struct hsr_priv *hsr);

net/hsr/hsr_forward.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,40 @@ struct hsr_frame_info {
5050
*/
5151
static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
5252
{
53-
struct hsr_ethhdr_sp *hdr;
53+
struct ethhdr *ethHdr;
54+
struct hsr_sup_tag *hsrSupTag;
55+
struct hsrv1_ethhdr_sp *hsrV1Hdr;
5456

5557
WARN_ON_ONCE(!skb_mac_header_was_set(skb));
56-
hdr = (struct hsr_ethhdr_sp *) skb_mac_header(skb);
58+
ethHdr = (struct ethhdr *) skb_mac_header(skb);
5759

58-
if (!ether_addr_equal(hdr->ethhdr.h_dest,
60+
/* Correct addr? */
61+
if (!ether_addr_equal(ethHdr->h_dest,
5962
hsr->sup_multicast_addr))
6063
return false;
6164

62-
if (get_hsr_stag_path(&hdr->hsr_sup) != 0x0f)
65+
/* Correct ether type?. */
66+
if (!(ethHdr->h_proto == htons(ETH_P_PRP)
67+
|| ethHdr->h_proto == htons(ETH_P_HSR)))
6368
return false;
64-
if ((hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_ANNOUNCE) &&
65-
(hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_LIFE_CHECK))
69+
70+
/* Get the supervision header from correct location. */
71+
if (ethHdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
72+
hsrV1Hdr = (struct hsrv1_ethhdr_sp *) skb_mac_header(skb);
73+
if (hsrV1Hdr->hsr.encap_proto != htons(ETH_P_PRP))
74+
return false;
75+
76+
hsrSupTag = &hsrV1Hdr->hsr_sup;
77+
} else {
78+
hsrSupTag = &((struct hsrv0_ethhdr_sp *) skb_mac_header(skb))->hsr_sup;
79+
}
80+
81+
if ((hsrSupTag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) &&
82+
(hsrSupTag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK))
6683
return false;
67-
if (hdr->hsr_sup.HSR_TLV_Length != 12)
84+
if ((hsrSupTag->HSR_TLV_Length != 12) &&
85+
(hsrSupTag->HSR_TLV_Length !=
86+
sizeof(struct hsr_sup_payload)))
6887
return false;
6988

7089
return true;
@@ -110,7 +129,7 @@ static struct sk_buff *frame_get_stripped_skb(struct hsr_frame_info *frame,
110129

111130

112131
static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
113-
struct hsr_port *port)
132+
struct hsr_port *port, u8 protoVersion)
114133
{
115134
struct hsr_ethhdr *hsr_ethhdr;
116135
int lane_id;
@@ -131,7 +150,8 @@ static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
131150
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
132151
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
133152
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
134-
hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP);
153+
hsr_ethhdr->ethhdr.h_proto = htons(protoVersion ?
154+
ETH_P_HSR : ETH_P_PRP);
135155
}
136156

137157
static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
@@ -160,7 +180,7 @@ static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
160180
memmove(dst, src, movelen);
161181
skb_reset_mac_header(skb);
162182

163-
hsr_fill_tag(skb, frame, port);
183+
hsr_fill_tag(skb, frame, port, port->hsr->protVersion);
164184

165185
return skb;
166186
}
@@ -320,7 +340,8 @@ static int hsr_fill_frame_info(struct hsr_frame_info *frame,
320340
/* FIXME: */
321341
WARN_ONCE(1, "HSR: VLAN not yet supported");
322342
}
323-
if (ethhdr->h_proto == htons(ETH_P_PRP)) {
343+
if (ethhdr->h_proto == htons(ETH_P_PRP)
344+
|| ethhdr->h_proto == htons(ETH_P_HSR)) {
324345
frame->skb_std = NULL;
325346
frame->skb_hsr = skb;
326347
frame->sequence_nr = hsr_get_skb_sequence_nr(skb);

net/hsr/hsr_framereg.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,17 @@ struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
177177
return node;
178178
}
179179

180-
if (!is_sup)
181-
return NULL; /* Only supervision frame may create node entry */
180+
/* Everyone may create a node entry, connected node to a HSR device. */
182181

183-
if (ethhdr->h_proto == htons(ETH_P_PRP)) {
182+
if (ethhdr->h_proto == htons(ETH_P_PRP)
183+
|| ethhdr->h_proto == htons(ETH_P_HSR)) {
184184
/* Use the existing sequence_nr from the tag as starting point
185185
* for filtering duplicate frames.
186186
*/
187187
seq_out = hsr_get_skb_sequence_nr(skb) - 1;
188188
} else {
189189
WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
190-
seq_out = 0;
190+
seq_out = HSR_SEQNR_START;
191191
}
192192

193193
return hsr_add_node(node_db, ethhdr->h_source, seq_out);
@@ -200,17 +200,25 @@ struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
200200
void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
201201
struct hsr_port *port_rcv)
202202
{
203+
struct ethhdr *ethhdr;
203204
struct hsr_node *node_real;
204205
struct hsr_sup_payload *hsr_sp;
205206
struct list_head *node_db;
206207
int i;
207208

208-
skb_pull(skb, sizeof(struct hsr_ethhdr_sp));
209-
hsr_sp = (struct hsr_sup_payload *) skb->data;
209+
ethhdr = (struct ethhdr *) skb_mac_header(skb);
210210

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;
211+
/* Leave the ethernet header. */
212+
skb_pull(skb, sizeof(struct ethhdr));
213+
214+
/* And leave the HSR tag. */
215+
if (ethhdr->h_proto == htons(ETH_P_HSR))
216+
skb_pull(skb, sizeof(struct hsr_tag));
217+
218+
/* And leave the HSR sup tag. */
219+
skb_pull(skb, sizeof(struct hsr_sup_tag));
220+
221+
hsr_sp = (struct hsr_sup_payload *) skb->data;
214222

215223
/* Merge node_curr (registered on MacAddressB) into node_real */
216224
node_db = &port_rcv->hsr->node_db;
@@ -225,7 +233,7 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
225233
/* Node has already been merged */
226234
goto done;
227235

228-
ether_addr_copy(node_real->MacAddressB, eth_hdr(skb)->h_source);
236+
ether_addr_copy(node_real->MacAddressB, ethhdr->h_source);
229237
for (i = 0; i < HSR_PT_PORTS; i++) {
230238
if (!node_curr->time_in_stale[i] &&
231239
time_after(node_curr->time_in[i], node_real->time_in[i])) {
@@ -241,7 +249,7 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
241249
kfree_rcu(node_curr, rcu_head);
242250

243251
done:
244-
skb_push(skb, sizeof(struct hsr_ethhdr_sp));
252+
skb_push(skb, sizeof(struct hsrv1_ethhdr_sp));
245253
}
246254

247255

net/hsr/hsr_main.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
*/
3131
#define MAX_SLAVE_DIFF 3000 /* ms */
3232
#define HSR_SEQNR_START (USHRT_MAX - 1024)
33+
#define HSR_SUP_SEQNR_START (HSR_SEQNR_START / 2)
3334

3435

3536
/* How often shall we check for broken ring and remove node entries older than
@@ -58,6 +59,8 @@ struct hsr_tag {
5859

5960
#define HSR_HLEN 6
6061

62+
#define HSR_V1_SUP_LSDUSIZE 52
63+
6164
/* The helper functions below assumes that 'path' occupies the 4 most
6265
* significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or
6366
* equivalently, the 4 most significant bits of HSR tag byte 14).
@@ -131,8 +134,14 @@ static inline void set_hsr_stag_HSR_Ver(struct hsr_sup_tag *hst, u16 HSR_Ver)
131134
set_hsr_tag_LSDU_size((struct hsr_tag *) hst, HSR_Ver);
132135
}
133136

134-
struct hsr_ethhdr_sp {
137+
struct hsrv0_ethhdr_sp {
138+
struct ethhdr ethhdr;
139+
struct hsr_sup_tag hsr_sup;
140+
} __packed;
141+
142+
struct hsrv1_ethhdr_sp {
135143
struct ethhdr ethhdr;
144+
struct hsr_tag hsr;
136145
struct hsr_sup_tag hsr_sup;
137146
} __packed;
138147

@@ -162,6 +171,8 @@ struct hsr_priv {
162171
struct timer_list prune_timer;
163172
int announce_count;
164173
u16 sequence_nr;
174+
u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
175+
u8 protVersion; /* Indicate if HSRv0 or HSRv1. */
165176
spinlock_t seqnr_lock; /* locking for sequence_nr */
166177
unsigned char sup_multicast_addr[ETH_ALEN];
167178
};

0 commit comments

Comments
 (0)