@@ -524,8 +524,37 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
524524 false, false) < 0 )
525525 return PACKET_REJECT ;
526526
527- tunnel -> parms .index = ntohl (index );
528- ip6_tnl_rcv (tunnel , skb , tpi , NULL , log_ecn_error );
527+ if (tunnel -> parms .collect_md ) {
528+ struct metadata_dst * tun_dst ;
529+ struct ip_tunnel_info * info ;
530+ struct erspan_metadata * md ;
531+ __be64 tun_id ;
532+ __be16 flags ;
533+
534+ tpi -> flags |= TUNNEL_KEY ;
535+ flags = tpi -> flags ;
536+ tun_id = key32_to_tunnel_id (tpi -> key );
537+
538+ tun_dst = ipv6_tun_rx_dst (skb , flags , tun_id ,
539+ sizeof (* md ));
540+ if (!tun_dst )
541+ return PACKET_REJECT ;
542+
543+ info = & tun_dst -> u .tun_info ;
544+ md = ip_tunnel_info_opts (info );
545+ if (!md )
546+ return PACKET_REJECT ;
547+
548+ md -> index = index ;
549+ info -> key .tun_flags |= TUNNEL_ERSPAN_OPT ;
550+ info -> options_len = sizeof (* md );
551+
552+ ip6_tnl_rcv (tunnel , skb , tpi , tun_dst , log_ecn_error );
553+
554+ } else {
555+ tunnel -> parms .index = ntohl (index );
556+ ip6_tnl_rcv (tunnel , skb , tpi , NULL , log_ecn_error );
557+ }
529558
530559 return PACKET_RCVD ;
531560 }
@@ -857,42 +886,73 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
857886 if (gre_handle_offloads (skb , false))
858887 goto tx_err ;
859888
860- switch (skb -> protocol ) {
861- case htons (ETH_P_IP ):
862- memset (& (IPCB (skb )-> opt ), 0 , sizeof (IPCB (skb )-> opt ));
863- prepare_ip6gre_xmit_ipv4 (skb , dev , & fl6 ,
864- & dsfield , & encap_limit );
865- break ;
866- case htons (ETH_P_IPV6 ):
867- if (ipv6_addr_equal (& t -> parms .raddr , & ipv6h -> saddr ))
868- goto tx_err ;
869- if (prepare_ip6gre_xmit_ipv6 (skb , dev , & fl6 ,
870- & dsfield , & encap_limit ))
871- goto tx_err ;
872- break ;
873- default :
874- memcpy (& fl6 , & t -> fl .u .ip6 , sizeof (fl6 ));
875- break ;
876- }
877-
878889 if (skb -> len > dev -> mtu + dev -> hard_header_len ) {
879890 pskb_trim (skb , dev -> mtu + dev -> hard_header_len );
880891 truncate = true;
881892 }
882893
883- erspan_build_header (skb , t -> parms .o_key , t -> parms .index ,
884- truncate , false);
885894 t -> parms .o_flags &= ~TUNNEL_KEY ;
886-
887895 IPCB (skb )-> flags = 0 ;
888- fl6 .daddr = t -> parms .raddr ;
896+
897+ /* For collect_md mode, derive fl6 from the tunnel key,
898+ * for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}.
899+ */
900+ if (t -> parms .collect_md ) {
901+ struct ip_tunnel_info * tun_info ;
902+ const struct ip_tunnel_key * key ;
903+ struct erspan_metadata * md ;
904+
905+ tun_info = skb_tunnel_info (skb );
906+ if (unlikely (!tun_info ||
907+ !(tun_info -> mode & IP_TUNNEL_INFO_TX ) ||
908+ ip_tunnel_info_af (tun_info ) != AF_INET6 ))
909+ return - EINVAL ;
910+
911+ key = & tun_info -> key ;
912+ memset (& fl6 , 0 , sizeof (fl6 ));
913+ fl6 .flowi6_proto = IPPROTO_GRE ;
914+ fl6 .daddr = key -> u .ipv6 .dst ;
915+ fl6 .flowlabel = key -> label ;
916+ fl6 .flowi6_uid = sock_net_uid (dev_net (dev ), NULL );
917+
918+ dsfield = key -> tos ;
919+ md = ip_tunnel_info_opts (tun_info );
920+ if (!md )
921+ goto tx_err ;
922+
923+ erspan_build_header (skb , tunnel_id_to_key32 (key -> tun_id ),
924+ ntohl (md -> index ), truncate , false);
925+
926+ } else {
927+ switch (skb -> protocol ) {
928+ case htons (ETH_P_IP ):
929+ memset (& (IPCB (skb )-> opt ), 0 , sizeof (IPCB (skb )-> opt ));
930+ prepare_ip6gre_xmit_ipv4 (skb , dev , & fl6 ,
931+ & dsfield , & encap_limit );
932+ break ;
933+ case htons (ETH_P_IPV6 ):
934+ if (ipv6_addr_equal (& t -> parms .raddr , & ipv6h -> saddr ))
935+ goto tx_err ;
936+ if (prepare_ip6gre_xmit_ipv6 (skb , dev , & fl6 ,
937+ & dsfield , & encap_limit ))
938+ goto tx_err ;
939+ break ;
940+ default :
941+ memcpy (& fl6 , & t -> fl .u .ip6 , sizeof (fl6 ));
942+ break ;
943+ }
944+
945+ erspan_build_header (skb , t -> parms .o_key , t -> parms .index ,
946+ truncate , false);
947+ fl6 .daddr = t -> parms .raddr ;
948+ }
889949
890950 /* Push GRE header. */
891951 gre_build_header (skb , 8 , TUNNEL_SEQ ,
892952 htons (ETH_P_ERSPAN ), 0 , htonl (t -> o_seqno ++ ));
893953
894954 /* TooBig packet may have updated dst->dev's mtu */
895- if (dst && dst_mtu (dst ) > dst -> dev -> mtu )
955+ if (! t -> parms . collect_md && dst && dst_mtu (dst ) > dst -> dev -> mtu )
896956 dst -> ops -> update_pmtu (dst , NULL , skb , dst -> dev -> mtu );
897957
898958 err = ip6_tnl_xmit (skb , dev , dsfield , & fl6 , encap_limit , & mtu ,
0 commit comments