Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: hsr: generate supervision frame without HSR/PRP tag

For a switch to offload insertion of HSR/PRP tags, frames must not be
sent to the CPU facing switch port with a tag. Generate supervision frames
(eth type ETH_P_PRP) without HSR v1 (ETH_P_HSR)/PRP tag and rely on
create_tagged_frame which inserts it later. This will allow skipping the
tag insertion for all outgoing frames in the future which is required for
HSR v1/PRP tag insertions to be offloaded.

HSR v0 supervision frames always contain tag information so insertion of
the tag can't be offloaded. IEC 62439-3 Ed.2.0 (HSR v1) specifically
notes that this was changed since v0 to allow offloading.

Signed-off-by: George McCollister <george.mccollister@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Tested-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

George McCollister and committed by
David S. Miller
78be9217 f8a7e014

+14 -33
+7 -32
net/hsr/hsr_device.c
··· 230 230 .parse = eth_header_parse, 231 231 }; 232 232 233 - static struct sk_buff *hsr_init_skb(struct hsr_port *master, u16 proto) 233 + static struct sk_buff *hsr_init_skb(struct hsr_port *master) 234 234 { 235 235 struct hsr_priv *hsr = master->hsr; 236 236 struct sk_buff *skb; ··· 242 242 * being, for PRP it is a trailer and for HSR it is a 243 243 * header 244 244 */ 245 - skb = dev_alloc_skb(sizeof(struct hsr_tag) + 246 - sizeof(struct hsr_sup_tag) + 245 + skb = dev_alloc_skb(sizeof(struct hsr_sup_tag) + 247 246 sizeof(struct hsr_sup_payload) + hlen + tlen); 248 247 249 248 if (!skb) ··· 250 251 251 252 skb_reserve(skb, hlen); 252 253 skb->dev = master->dev; 253 - skb->protocol = htons(proto); 254 254 skb->priority = TC_PRIO_CONTROL; 255 255 256 - if (dev_hard_header(skb, skb->dev, proto, 256 + if (dev_hard_header(skb, skb->dev, ETH_P_PRP, 257 257 hsr->sup_multicast_addr, 258 258 skb->dev->dev_addr, skb->len) <= 0) 259 259 goto out; ··· 273 275 { 274 276 struct hsr_priv *hsr = master->hsr; 275 277 __u8 type = HSR_TLV_LIFE_CHECK; 276 - struct hsr_tag *hsr_tag = NULL; 277 278 struct hsr_sup_payload *hsr_sp; 278 279 struct hsr_sup_tag *hsr_stag; 279 280 unsigned long irqflags; 280 281 struct sk_buff *skb; 281 - u16 proto; 282 282 283 283 *interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); 284 284 if (hsr->announce_count < 3 && hsr->prot_version == 0) { ··· 285 289 hsr->announce_count++; 286 290 } 287 291 288 - if (!hsr->prot_version) 289 - proto = ETH_P_PRP; 290 - else 291 - proto = ETH_P_HSR; 292 - 293 - skb = hsr_init_skb(master, proto); 292 + skb = hsr_init_skb(master); 294 293 if (!skb) { 295 294 WARN_ONCE(1, "HSR: Could not send supervision frame\n"); 296 295 return; 297 - } 298 - 299 - if (hsr->prot_version > 0) { 300 - hsr_tag = skb_put(skb, sizeof(struct hsr_tag)); 301 - hsr_tag->encap_proto = htons(ETH_P_PRP); 302 - set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE); 303 296 } 304 297 305 298 hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag)); ··· 300 315 if (hsr->prot_version > 0) { 301 316 hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); 302 317 hsr->sup_sequence_nr++; 303 - hsr_tag->sequence_nr = htons(hsr->sequence_nr); 304 - hsr->sequence_nr++; 305 318 } else { 306 319 hsr_stag->sequence_nr = htons(hsr->sequence_nr); 307 320 hsr->sequence_nr++; ··· 315 332 hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); 316 333 ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); 317 334 318 - if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN)) 335 + if (skb_put_padto(skb, ETH_ZLEN)) 319 336 return; 320 337 321 338 hsr_forward_skb(skb, master); ··· 331 348 struct hsr_sup_tag *hsr_stag; 332 349 unsigned long irqflags; 333 350 struct sk_buff *skb; 334 - struct prp_rct *rct; 335 - u8 *tail; 336 351 337 - skb = hsr_init_skb(master, ETH_P_PRP); 352 + skb = hsr_init_skb(master); 338 353 if (!skb) { 339 354 WARN_ONCE(1, "PRP: Could not send supervision frame\n"); 340 355 return; ··· 354 373 hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); 355 374 ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); 356 375 357 - if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN)) { 376 + if (skb_put_padto(skb, ETH_ZLEN)) { 358 377 spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); 359 378 return; 360 379 } 361 380 362 - tail = skb_tail_pointer(skb) - HSR_HLEN; 363 - rct = (struct prp_rct *)tail; 364 - rct->PRP_suffix = htons(ETH_P_PRP); 365 - set_prp_LSDU_size(rct, HSR_V1_SUP_LSDUSIZE); 366 - rct->sequence_nr = htons(hsr->sequence_nr); 367 - hsr->sequence_nr++; 368 381 spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); 369 382 370 383 hsr_forward_skb(skb, master);
+7 -1
net/hsr/hsr_forward.c
··· 186 186 set_prp_LSDU_size(trailer, lsdu_size); 187 187 trailer->sequence_nr = htons(frame->sequence_nr); 188 188 trailer->PRP_suffix = htons(ETH_P_PRP); 189 + skb->protocol = eth_hdr(skb)->h_proto; 189 190 190 191 return skb; 191 192 } ··· 227 226 hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; 228 227 hsr_ethhdr->ethhdr.h_proto = htons(proto_version ? 229 228 ETH_P_HSR : ETH_P_PRP); 229 + skb->protocol = hsr_ethhdr->ethhdr.h_proto; 230 230 231 231 return skb; 232 232 } ··· 456 454 void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb, 457 455 struct hsr_frame_info *frame) 458 456 { 459 - if (proto == htons(ETH_P_PRP) || 457 + struct hsr_port *port = frame->port_rcv; 458 + struct hsr_priv *hsr = port->hsr; 459 + 460 + /* HSRv0 supervisory frames double as a tag so treat them as tagged. */ 461 + if ((!hsr->prot_version && proto == htons(ETH_P_PRP)) || 460 462 proto == htons(ETH_P_HSR)) { 461 463 /* HSR tagged frame :- Data or Supervision */ 462 464 frame->skb_std = NULL;