@@ -113,6 +113,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
113
113
114
114
static struct rtnl_link_ops ipgre_link_ops __read_mostly ;
115
115
static int ipgre_tunnel_init (struct net_device * dev );
116
+ static void erspan_build_header (struct sk_buff * skb ,
117
+ __be32 id , u32 index , bool truncate );
116
118
117
119
static unsigned int ipgre_net_id __read_mostly ;
118
120
static unsigned int gre_tap_net_id __read_mostly ;
@@ -287,7 +289,33 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
287
289
false, false) < 0 )
288
290
goto drop ;
289
291
290
- tunnel -> index = ntohl (index );
292
+ if (tunnel -> collect_md ) {
293
+ struct ip_tunnel_info * info ;
294
+ struct erspan_metadata * md ;
295
+ __be64 tun_id ;
296
+ __be16 flags ;
297
+
298
+ tpi -> flags |= TUNNEL_KEY ;
299
+ flags = tpi -> flags ;
300
+ tun_id = key32_to_tunnel_id (tpi -> key );
301
+
302
+ tun_dst = ip_tun_rx_dst (skb , flags ,
303
+ tun_id , sizeof (* md ));
304
+ if (!tun_dst )
305
+ return PACKET_REJECT ;
306
+
307
+ md = ip_tunnel_info_opts (& tun_dst -> u .tun_info );
308
+ if (!md )
309
+ return PACKET_REJECT ;
310
+
311
+ md -> index = index ;
312
+ info = & tun_dst -> u .tun_info ;
313
+ info -> key .tun_flags |= TUNNEL_ERSPAN_OPT ;
314
+ info -> options_len = sizeof (* md );
315
+ } else {
316
+ tunnel -> index = ntohl (index );
317
+ }
318
+
291
319
skb_reset_mac_header (skb );
292
320
ip_tunnel_rcv (tunnel , skb , tpi , tun_dst , log_ecn_error );
293
321
return PACKET_RCVD ;
@@ -523,6 +551,64 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
523
551
dev -> stats .tx_dropped ++ ;
524
552
}
525
553
554
+ static void erspan_fb_xmit (struct sk_buff * skb , struct net_device * dev ,
555
+ __be16 proto )
556
+ {
557
+ struct ip_tunnel * tunnel = netdev_priv (dev );
558
+ struct ip_tunnel_info * tun_info ;
559
+ const struct ip_tunnel_key * key ;
560
+ struct erspan_metadata * md ;
561
+ struct rtable * rt = NULL ;
562
+ bool truncate = false;
563
+ struct flowi4 fl ;
564
+ int tunnel_hlen ;
565
+ __be16 df ;
566
+
567
+ tun_info = skb_tunnel_info (skb );
568
+ if (unlikely (!tun_info || !(tun_info -> mode & IP_TUNNEL_INFO_TX ) ||
569
+ ip_tunnel_info_af (tun_info ) != AF_INET ))
570
+ goto err_free_skb ;
571
+
572
+ key = & tun_info -> key ;
573
+
574
+ /* ERSPAN has fixed 8 byte GRE header */
575
+ tunnel_hlen = 8 + sizeof (struct erspanhdr );
576
+
577
+ rt = prepare_fb_xmit (skb , dev , & fl , tunnel_hlen );
578
+ if (!rt )
579
+ return ;
580
+
581
+ if (gre_handle_offloads (skb , false))
582
+ goto err_free_rt ;
583
+
584
+ if (skb -> len > dev -> mtu ) {
585
+ pskb_trim (skb , dev -> mtu );
586
+ truncate = true;
587
+ }
588
+
589
+ md = ip_tunnel_info_opts (tun_info );
590
+ if (!md )
591
+ goto err_free_rt ;
592
+
593
+ erspan_build_header (skb , tunnel_id_to_key32 (key -> tun_id ),
594
+ ntohl (md -> index ), truncate );
595
+
596
+ gre_build_header (skb , 8 , TUNNEL_SEQ ,
597
+ htons (ETH_P_ERSPAN ), 0 , htonl (tunnel -> o_seqno ++ ));
598
+
599
+ df = key -> tun_flags & TUNNEL_DONT_FRAGMENT ? htons (IP_DF ) : 0 ;
600
+
601
+ iptunnel_xmit (skb -> sk , rt , skb , fl .saddr , key -> u .ipv4 .dst , IPPROTO_GRE ,
602
+ key -> tos , key -> ttl , df , false);
603
+ return ;
604
+
605
+ err_free_rt :
606
+ ip_rt_put (rt );
607
+ err_free_skb :
608
+ kfree_skb (skb );
609
+ dev -> stats .tx_dropped ++ ;
610
+ }
611
+
526
612
static int gre_fill_metadata_dst (struct net_device * dev , struct sk_buff * skb )
527
613
{
528
614
struct ip_tunnel_info * info = skb_tunnel_info (skb );
@@ -636,6 +722,11 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
636
722
struct ip_tunnel * tunnel = netdev_priv (dev );
637
723
bool truncate = false;
638
724
725
+ if (tunnel -> collect_md ) {
726
+ erspan_fb_xmit (skb , dev , skb -> protocol );
727
+ return NETDEV_TX_OK ;
728
+ }
729
+
639
730
if (gre_handle_offloads (skb , false))
640
731
goto free_skb ;
641
732
@@ -998,9 +1089,12 @@ static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
998
1089
return ret ;
999
1090
1000
1091
/* ERSPAN should only have GRE sequence and key flag */
1001
- flags |= nla_get_be16 (data [IFLA_GRE_OFLAGS ]);
1002
- flags |= nla_get_be16 (data [IFLA_GRE_IFLAGS ]);
1003
- if (flags != (GRE_SEQ | GRE_KEY ))
1092
+ if (data [IFLA_GRE_OFLAGS ])
1093
+ flags |= nla_get_be16 (data [IFLA_GRE_OFLAGS ]);
1094
+ if (data [IFLA_GRE_IFLAGS ])
1095
+ flags |= nla_get_be16 (data [IFLA_GRE_IFLAGS ]);
1096
+ if (!data [IFLA_GRE_COLLECT_METADATA ] &&
1097
+ flags != (GRE_SEQ | GRE_KEY ))
1004
1098
return - EINVAL ;
1005
1099
1006
1100
/* ERSPAN Session ID only has 10-bit. Since we reuse
0 commit comments