4141#include <net/addrconf.h>
4242#include <net/xfrm.h>
4343#include <net/net_namespace.h>
44+ #include <net/dst_metadata.h>
4445#include <net/netns/generic.h>
4546#include <linux/etherdevice.h>
4647
@@ -56,6 +57,7 @@ static const struct net_device_ops xfrmi_netdev_ops;
5657struct xfrmi_net {
5758 /* lists for storing interfaces in use */
5859 struct xfrm_if __rcu * xfrmi [XFRMI_HASH_SIZE ];
60+ struct xfrm_if __rcu * collect_md_xfrmi ;
5961};
6062
6163#define for_each_xfrmi_rcu (start , xi ) \
@@ -77,17 +79,23 @@ static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x)
7779 return xi ;
7880 }
7981
82+ xi = rcu_dereference (xfrmn -> collect_md_xfrmi );
83+ if (xi && (xi -> dev -> flags & IFF_UP ))
84+ return xi ;
85+
8086 return NULL ;
8187}
8288
83- static struct xfrm_if * xfrmi_decode_session (struct sk_buff * skb ,
84- unsigned short family )
89+ static bool xfrmi_decode_session (struct sk_buff * skb ,
90+ unsigned short family ,
91+ struct xfrm_if_decode_session_result * res )
8592{
8693 struct net_device * dev ;
94+ struct xfrm_if * xi ;
8795 int ifindex = 0 ;
8896
8997 if (!secpath_exists (skb ) || !skb -> dev )
90- return NULL ;
98+ return false ;
9199
92100 switch (family ) {
93101 case AF_INET6 :
@@ -107,11 +115,18 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
107115 }
108116
109117 if (!dev || !(dev -> flags & IFF_UP ))
110- return NULL ;
118+ return false ;
111119 if (dev -> netdev_ops != & xfrmi_netdev_ops )
112- return NULL ;
120+ return false ;
113121
114- return netdev_priv (dev );
122+ xi = netdev_priv (dev );
123+ res -> net = xi -> net ;
124+
125+ if (xi -> p .collect_md )
126+ res -> if_id = xfrm_input_state (skb )-> if_id ;
127+ else
128+ res -> if_id = xi -> p .if_id ;
129+ return true;
115130}
116131
117132static void xfrmi_link (struct xfrmi_net * xfrmn , struct xfrm_if * xi )
@@ -157,7 +172,10 @@ static int xfrmi_create(struct net_device *dev)
157172 if (err < 0 )
158173 goto out ;
159174
160- xfrmi_link (xfrmn , xi );
175+ if (xi -> p .collect_md )
176+ rcu_assign_pointer (xfrmn -> collect_md_xfrmi , xi );
177+ else
178+ xfrmi_link (xfrmn , xi );
161179
162180 return 0 ;
163181
@@ -185,7 +203,10 @@ static void xfrmi_dev_uninit(struct net_device *dev)
185203 struct xfrm_if * xi = netdev_priv (dev );
186204 struct xfrmi_net * xfrmn = net_generic (xi -> net , xfrmi_net_id );
187205
188- xfrmi_unlink (xfrmn , xi );
206+ if (xi -> p .collect_md )
207+ RCU_INIT_POINTER (xfrmn -> collect_md_xfrmi , NULL );
208+ else
209+ xfrmi_unlink (xfrmn , xi );
189210}
190211
191212static void xfrmi_scrub_packet (struct sk_buff * skb , bool xnet )
@@ -214,6 +235,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
214235 struct xfrm_state * x ;
215236 struct xfrm_if * xi ;
216237 bool xnet ;
238+ int link ;
217239
218240 if (err && !secpath_exists (skb ))
219241 return 0 ;
@@ -224,6 +246,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
224246 if (!xi )
225247 return 1 ;
226248
249+ link = skb -> dev -> ifindex ;
227250 dev = xi -> dev ;
228251 skb -> dev = dev ;
229252
@@ -254,6 +277,17 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
254277 }
255278
256279 xfrmi_scrub_packet (skb , xnet );
280+ if (xi -> p .collect_md ) {
281+ struct metadata_dst * md_dst ;
282+
283+ md_dst = metadata_dst_alloc (0 , METADATA_XFRM , GFP_ATOMIC );
284+ if (!md_dst )
285+ return - ENOMEM ;
286+
287+ md_dst -> u .xfrm_info .if_id = x -> if_id ;
288+ md_dst -> u .xfrm_info .link = link ;
289+ skb_dst_set (skb , (struct dst_entry * )md_dst );
290+ }
257291 dev_sw_netstats_rx_add (dev , skb -> len );
258292
259293 return 0 ;
@@ -269,10 +303,23 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
269303 struct net_device * tdev ;
270304 struct xfrm_state * x ;
271305 int err = -1 ;
306+ u32 if_id ;
272307 int mtu ;
273308
309+ if (xi -> p .collect_md ) {
310+ struct xfrm_md_info * md_info = skb_xfrm_md_info (skb );
311+
312+ if (unlikely (!md_info ))
313+ return - EINVAL ;
314+
315+ if_id = md_info -> if_id ;
316+ fl -> flowi_oif = md_info -> link ;
317+ } else {
318+ if_id = xi -> p .if_id ;
319+ }
320+
274321 dst_hold (dst );
275- dst = xfrm_lookup_with_ifid (xi -> net , dst , fl , NULL , 0 , xi -> p . if_id );
322+ dst = xfrm_lookup_with_ifid (xi -> net , dst , fl , NULL , 0 , if_id );
276323 if (IS_ERR (dst )) {
277324 err = PTR_ERR (dst );
278325 dst = NULL ;
@@ -283,7 +330,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
283330 if (!x )
284331 goto tx_err_link_failure ;
285332
286- if (x -> if_id != xi -> p . if_id )
333+ if (x -> if_id != if_id )
287334 goto tx_err_link_failure ;
288335
289336 tdev = dst -> dev ;
@@ -633,6 +680,9 @@ static void xfrmi_netlink_parms(struct nlattr *data[],
633680
634681 if (data [IFLA_XFRM_IF_ID ])
635682 parms -> if_id = nla_get_u32 (data [IFLA_XFRM_IF_ID ]);
683+
684+ if (data [IFLA_XFRM_COLLECT_METADATA ])
685+ parms -> collect_md = true;
636686}
637687
638688static int xfrmi_newlink (struct net * src_net , struct net_device * dev ,
@@ -645,14 +695,27 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
645695 int err ;
646696
647697 xfrmi_netlink_parms (data , & p );
648- if (!p .if_id ) {
649- NL_SET_ERR_MSG (extack , "if_id must be non zero" );
650- return - EINVAL ;
651- }
698+ if (p .collect_md ) {
699+ struct xfrmi_net * xfrmn = net_generic (net , xfrmi_net_id );
652700
653- xi = xfrmi_locate (net , & p );
654- if (xi )
655- return - EEXIST ;
701+ if (p .link || p .if_id ) {
702+ NL_SET_ERR_MSG (extack , "link and if_id must be zero" );
703+ return - EINVAL ;
704+ }
705+
706+ if (rtnl_dereference (xfrmn -> collect_md_xfrmi ))
707+ return - EEXIST ;
708+
709+ } else {
710+ if (!p .if_id ) {
711+ NL_SET_ERR_MSG (extack , "if_id must be non zero" );
712+ return - EINVAL ;
713+ }
714+
715+ xi = xfrmi_locate (net , & p );
716+ if (xi )
717+ return - EEXIST ;
718+ }
656719
657720 xi = netdev_priv (dev );
658721 xi -> p = p ;
@@ -682,12 +745,22 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
682745 return - EINVAL ;
683746 }
684747
748+ if (p .collect_md ) {
749+ NL_SET_ERR_MSG (extack , "collect_md can't be changed" );
750+ return - EINVAL ;
751+ }
752+
685753 xi = xfrmi_locate (net , & p );
686754 if (!xi ) {
687755 xi = netdev_priv (dev );
688756 } else {
689757 if (xi -> dev != dev )
690758 return - EEXIST ;
759+ if (xi -> p .collect_md ) {
760+ NL_SET_ERR_MSG (extack ,
761+ "device can't be changed to collect_md" );
762+ return - EINVAL ;
763+ }
691764 }
692765
693766 return xfrmi_update (xi , & p );
@@ -700,6 +773,8 @@ static size_t xfrmi_get_size(const struct net_device *dev)
700773 nla_total_size (4 ) +
701774 /* IFLA_XFRM_IF_ID */
702775 nla_total_size (4 ) +
776+ /* IFLA_XFRM_COLLECT_METADATA */
777+ nla_total_size (0 ) +
703778 0 ;
704779}
705780
@@ -709,7 +784,8 @@ static int xfrmi_fill_info(struct sk_buff *skb, const struct net_device *dev)
709784 struct xfrm_if_parms * parm = & xi -> p ;
710785
711786 if (nla_put_u32 (skb , IFLA_XFRM_LINK , parm -> link ) ||
712- nla_put_u32 (skb , IFLA_XFRM_IF_ID , parm -> if_id ))
787+ nla_put_u32 (skb , IFLA_XFRM_IF_ID , parm -> if_id ) ||
788+ (xi -> p .collect_md && nla_put_flag (skb , IFLA_XFRM_COLLECT_METADATA )))
713789 goto nla_put_failure ;
714790 return 0 ;
715791
@@ -725,8 +801,10 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev)
725801}
726802
727803static const struct nla_policy xfrmi_policy [IFLA_XFRM_MAX + 1 ] = {
728- [IFLA_XFRM_LINK ] = { .type = NLA_U32 },
729- [IFLA_XFRM_IF_ID ] = { .type = NLA_U32 },
804+ [IFLA_XFRM_UNSPEC ] = { .strict_start_type = IFLA_XFRM_COLLECT_METADATA },
805+ [IFLA_XFRM_LINK ] = { .type = NLA_U32 },
806+ [IFLA_XFRM_IF_ID ] = { .type = NLA_U32 },
807+ [IFLA_XFRM_COLLECT_METADATA ] = { .type = NLA_FLAG },
730808};
731809
732810static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
@@ -762,6 +840,9 @@ static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list)
762840 xip = & xi -> next )
763841 unregister_netdevice_queue (xi -> dev , & list );
764842 }
843+ xi = rtnl_dereference (xfrmn -> collect_md_xfrmi );
844+ if (xi )
845+ unregister_netdevice_queue (xi -> dev , & list );
765846 }
766847 unregister_netdevice_many (& list );
767848 rtnl_unlock ();
0 commit comments