42
42
#include <net/ip_fib.h>
43
43
#include <net/netlink.h>
44
44
#include <net/nexthop.h>
45
+ #include <net/lwtunnel.h>
45
46
46
47
#include "fib_lookup.h"
47
48
@@ -208,6 +209,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
208
209
change_nexthops (fi ) {
209
210
if (nexthop_nh -> nh_dev )
210
211
dev_put (nexthop_nh -> nh_dev );
212
+ lwtunnel_state_put (nexthop_nh -> nh_lwtstate );
211
213
free_nh_exceptions (nexthop_nh );
212
214
rt_fibinfo_free_cpus (nexthop_nh -> nh_pcpu_rth_output );
213
215
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)
266
268
#ifdef CONFIG_IP_ROUTE_CLASSID
267
269
nh -> nh_tclassid != onh -> nh_tclassid ||
268
270
#endif
271
+ lwtunnel_cmp_encap (nh -> nh_lwtstate , onh -> nh_lwtstate ) ||
269
272
((nh -> nh_flags ^ onh -> nh_flags ) & ~RTNH_COMPARE_MASK ))
270
273
return -1 ;
271
274
onh ++ ;
@@ -366,6 +369,7 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
366
369
payload += nla_total_size ((RTAX_MAX * nla_total_size (4 )));
367
370
368
371
if (fi -> fib_nhs ) {
372
+ size_t nh_encapsize = 0 ;
369
373
/* Also handles the special case fib_nhs == 1 */
370
374
371
375
/* each nexthop is packed in an attribute */
@@ -374,8 +378,21 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
374
378
/* may contain flow and gateway attribute */
375
379
nhsize += 2 * nla_total_size (4 );
376
380
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
+
377
392
/* 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
+
379
396
}
380
397
381
398
return payload ;
@@ -452,6 +469,9 @@ static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining)
452
469
static int fib_get_nhs (struct fib_info * fi , struct rtnexthop * rtnh ,
453
470
int remaining , struct fib_config * cfg )
454
471
{
472
+ struct net * net = cfg -> fc_nlinfo .nl_net ;
473
+ int ret ;
474
+
455
475
change_nexthops (fi ) {
456
476
int attrlen ;
457
477
@@ -475,18 +495,66 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
475
495
if (nexthop_nh -> nh_tclassid )
476
496
fi -> fib_net -> ipv4 .fib_num_tclassid_users ++ ;
477
497
#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
+ }
478
518
}
479
519
480
520
rtnh = rtnh_next (rtnh , & remaining );
481
521
} endfor_nexthops (fi );
482
522
483
523
return 0 ;
524
+
525
+ err_inval :
526
+ ret = - EINVAL ;
527
+
528
+ errout :
529
+ return ret ;
484
530
}
485
531
486
532
#endif
487
533
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
+
488
555
int fib_nh_match (struct fib_config * cfg , struct fib_info * fi )
489
556
{
557
+ struct net * net = cfg -> fc_nlinfo .nl_net ;
490
558
#ifdef CONFIG_IP_ROUTE_MULTIPATH
491
559
struct rtnexthop * rtnh ;
492
560
int remaining ;
@@ -496,6 +564,12 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
496
564
return 1 ;
497
565
498
566
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
+ }
499
573
if ((!cfg -> fc_oif || cfg -> fc_oif == fi -> fib_nh -> nh_oif ) &&
500
574
(!cfg -> fc_gw || cfg -> fc_gw == fi -> fib_nh -> nh_gw ))
501
575
return 0 ;
@@ -882,6 +956,22 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
882
956
} else {
883
957
struct fib_nh * nh = fi -> fib_nh ;
884
958
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
+ }
885
975
nh -> nh_oif = cfg -> fc_oif ;
886
976
nh -> nh_gw = cfg -> fc_gw ;
887
977
nh -> nh_flags = cfg -> fc_flags ;
@@ -1055,6 +1145,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
1055
1145
nla_put_u32 (skb , RTA_FLOW , fi -> fib_nh [0 ].nh_tclassid ))
1056
1146
goto nla_put_failure ;
1057
1147
#endif
1148
+ if (fi -> fib_nh -> nh_lwtstate )
1149
+ lwtunnel_fill_encap (skb , fi -> fib_nh -> nh_lwtstate );
1058
1150
}
1059
1151
#ifdef CONFIG_IP_ROUTE_MULTIPATH
1060
1152
if (fi -> fib_nhs > 1 ) {
@@ -1090,6 +1182,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
1090
1182
nla_put_u32 (skb , RTA_FLOW , nh -> nh_tclassid ))
1091
1183
goto nla_put_failure ;
1092
1184
#endif
1185
+ if (nh -> nh_lwtstate )
1186
+ lwtunnel_fill_encap (skb , nh -> nh_lwtstate );
1093
1187
/* length of rtnetlink header + attributes */
1094
1188
rtnh -> rtnh_len = nlmsg_get_pos (skb ) - (void * ) rtnh ;
1095
1189
} endfor_nexthops (fi );
0 commit comments