4242#include <net/ip_fib.h>
4343#include <net/netlink.h>
4444#include <net/nexthop.h>
45+ #include <net/lwtunnel.h>
4546
4647#include "fib_lookup.h"
4748
@@ -208,6 +209,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
208209 change_nexthops (fi ) {
209210 if (nexthop_nh -> nh_dev )
210211 dev_put (nexthop_nh -> nh_dev );
212+ lwtunnel_state_put (nexthop_nh -> nh_lwtstate );
211213 free_nh_exceptions (nexthop_nh );
212214 rt_fibinfo_free_cpus (nexthop_nh -> nh_pcpu_rth_output );
213215 rt_fibinfo_free (& nexthop_nh -> nh_rth_input );
@@ -266,6 +268,7 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
266268#ifdef CONFIG_IP_ROUTE_CLASSID
267269 nh -> nh_tclassid != onh -> nh_tclassid ||
268270#endif
271+ lwtunnel_cmp_encap (nh -> nh_lwtstate , onh -> nh_lwtstate ) ||
269272 ((nh -> nh_flags ^ onh -> nh_flags ) & ~RTNH_COMPARE_MASK ))
270273 return -1 ;
271274 onh ++ ;
@@ -366,6 +369,7 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
366369 payload += nla_total_size ((RTAX_MAX * nla_total_size (4 )));
367370
368371 if (fi -> fib_nhs ) {
372+ size_t nh_encapsize = 0 ;
369373 /* Also handles the special case fib_nhs == 1 */
370374
371375 /* each nexthop is packed in an attribute */
@@ -374,8 +378,21 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
374378 /* may contain flow and gateway attribute */
375379 nhsize += 2 * nla_total_size (4 );
376380
381+ /* grab encap info */
382+ for_nexthops (fi ) {
383+ if (nh -> nh_lwtstate ) {
384+ /* RTA_ENCAP_TYPE */
385+ nh_encapsize += lwtunnel_get_encap_size (
386+ nh -> nh_lwtstate );
387+ /* RTA_ENCAP */
388+ nh_encapsize += nla_total_size (2 );
389+ }
390+ } endfor_nexthops (fi );
391+
377392 /* all nexthops are packed in a nested attribute */
378- payload += nla_total_size (fi -> fib_nhs * nhsize );
393+ payload += nla_total_size ((fi -> fib_nhs * nhsize ) +
394+ nh_encapsize );
395+
379396 }
380397
381398 return payload ;
@@ -452,6 +469,9 @@ static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining)
452469static int fib_get_nhs (struct fib_info * fi , struct rtnexthop * rtnh ,
453470 int remaining , struct fib_config * cfg )
454471{
472+ struct net * net = cfg -> fc_nlinfo .nl_net ;
473+ int ret ;
474+
455475 change_nexthops (fi ) {
456476 int attrlen ;
457477
@@ -475,18 +495,66 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
475495 if (nexthop_nh -> nh_tclassid )
476496 fi -> fib_net -> ipv4 .fib_num_tclassid_users ++ ;
477497#endif
498+ nla = nla_find (attrs , attrlen , RTA_ENCAP );
499+ if (nla ) {
500+ struct lwtunnel_state * lwtstate ;
501+ struct net_device * dev = NULL ;
502+ struct nlattr * nla_entype ;
503+
504+ nla_entype = nla_find (attrs , attrlen ,
505+ RTA_ENCAP_TYPE );
506+ if (!nla_entype )
507+ goto err_inval ;
508+ if (cfg -> fc_oif )
509+ dev = __dev_get_by_index (net , cfg -> fc_oif );
510+ ret = lwtunnel_build_state (dev , nla_get_u16 (
511+ nla_entype ),
512+ nla , & lwtstate );
513+ if (ret )
514+ goto errout ;
515+ lwtunnel_state_get (lwtstate );
516+ nexthop_nh -> nh_lwtstate = lwtstate ;
517+ }
478518 }
479519
480520 rtnh = rtnh_next (rtnh , & remaining );
481521 } endfor_nexthops (fi );
482522
483523 return 0 ;
524+
525+ err_inval :
526+ ret = - EINVAL ;
527+
528+ errout :
529+ return ret ;
484530}
485531
486532#endif
487533
534+ int fib_encap_match (struct net * net , u16 encap_type ,
535+ struct nlattr * encap ,
536+ int oif , const struct fib_nh * nh )
537+ {
538+ struct lwtunnel_state * lwtstate ;
539+ struct net_device * dev = NULL ;
540+ int ret ;
541+
542+ if (encap_type == LWTUNNEL_ENCAP_NONE )
543+ return 0 ;
544+
545+ if (oif )
546+ dev = __dev_get_by_index (net , oif );
547+ ret = lwtunnel_build_state (dev , encap_type ,
548+ encap , & lwtstate );
549+ if (!ret )
550+ return lwtunnel_cmp_encap (lwtstate , nh -> nh_lwtstate );
551+
552+ return 0 ;
553+ }
554+
488555int fib_nh_match (struct fib_config * cfg , struct fib_info * fi )
489556{
557+ struct net * net = cfg -> fc_nlinfo .nl_net ;
490558#ifdef CONFIG_IP_ROUTE_MULTIPATH
491559 struct rtnexthop * rtnh ;
492560 int remaining ;
@@ -496,6 +564,12 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
496564 return 1 ;
497565
498566 if (cfg -> fc_oif || cfg -> fc_gw ) {
567+ if (cfg -> fc_encap ) {
568+ if (fib_encap_match (net , cfg -> fc_encap_type ,
569+ cfg -> fc_encap , cfg -> fc_oif ,
570+ fi -> fib_nh ))
571+ return 1 ;
572+ }
499573 if ((!cfg -> fc_oif || cfg -> fc_oif == fi -> fib_nh -> nh_oif ) &&
500574 (!cfg -> fc_gw || cfg -> fc_gw == fi -> fib_nh -> nh_gw ))
501575 return 0 ;
@@ -882,6 +956,22 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
882956 } else {
883957 struct fib_nh * nh = fi -> fib_nh ;
884958
959+ if (cfg -> fc_encap ) {
960+ struct lwtunnel_state * lwtstate ;
961+ struct net_device * dev = NULL ;
962+
963+ if (cfg -> fc_encap_type == LWTUNNEL_ENCAP_NONE )
964+ goto err_inval ;
965+ if (cfg -> fc_oif )
966+ dev = __dev_get_by_index (net , cfg -> fc_oif );
967+ err = lwtunnel_build_state (dev , cfg -> fc_encap_type ,
968+ cfg -> fc_encap , & lwtstate );
969+ if (err )
970+ goto failure ;
971+
972+ lwtunnel_state_get (lwtstate );
973+ nh -> nh_lwtstate = lwtstate ;
974+ }
885975 nh -> nh_oif = cfg -> fc_oif ;
886976 nh -> nh_gw = cfg -> fc_gw ;
887977 nh -> nh_flags = cfg -> fc_flags ;
@@ -1055,6 +1145,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
10551145 nla_put_u32 (skb , RTA_FLOW , fi -> fib_nh [0 ].nh_tclassid ))
10561146 goto nla_put_failure ;
10571147#endif
1148+ if (fi -> fib_nh -> nh_lwtstate )
1149+ lwtunnel_fill_encap (skb , fi -> fib_nh -> nh_lwtstate );
10581150 }
10591151#ifdef CONFIG_IP_ROUTE_MULTIPATH
10601152 if (fi -> fib_nhs > 1 ) {
@@ -1090,6 +1182,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
10901182 nla_put_u32 (skb , RTA_FLOW , nh -> nh_tclassid ))
10911183 goto nla_put_failure ;
10921184#endif
1185+ if (nh -> nh_lwtstate )
1186+ lwtunnel_fill_encap (skb , nh -> nh_lwtstate );
10931187 /* length of rtnetlink header + attributes */
10941188 rtnh -> rtnh_len = nlmsg_get_pos (skb ) - (void * ) rtnh ;
10951189 } endfor_nexthops (fi );
0 commit comments