diff options
author | Roopa Prabhu <roopa@cumulusnetworks.com> | 2015-07-21 04:43:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-21 13:39:03 -0400 |
commit | 571e722676fe386bb66f72a75b64a6ebf535c077 (patch) | |
tree | 80e374cf7f848408bad3be37237e4f43c9a9701b /net/ipv4/fib_semantics.c | |
parent | 499a24256862714539e902c0499b67da2bb3ab72 (diff) |
ipv4: support for fib route lwtunnel encap attributes
This patch adds support in ipv4 fib functions to parse user
provided encap attributes and attach encap state data to fib_nh
and rtable.
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 96 |
1 files changed, 95 insertions, 1 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index c7358ea4ae93..6754c64b2fe0 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <net/ip_fib.h> | 42 | #include <net/ip_fib.h> |
43 | #include <net/netlink.h> | 43 | #include <net/netlink.h> |
44 | #include <net/nexthop.h> | 44 | #include <net/nexthop.h> |
45 | #include <net/lwtunnel.h> | ||
45 | 46 | ||
46 | #include "fib_lookup.h" | 47 | #include "fib_lookup.h" |
47 | 48 | ||
@@ -208,6 +209,7 @@ static void free_fib_info_rcu(struct rcu_head *head) | |||
208 | change_nexthops(fi) { | 209 | change_nexthops(fi) { |
209 | if (nexthop_nh->nh_dev) | 210 | if (nexthop_nh->nh_dev) |
210 | dev_put(nexthop_nh->nh_dev); | 211 | dev_put(nexthop_nh->nh_dev); |
212 | lwtunnel_state_put(nexthop_nh->nh_lwtstate); | ||
211 | free_nh_exceptions(nexthop_nh); | 213 | free_nh_exceptions(nexthop_nh); |
212 | rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); | 214 | rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); |
213 | rt_fibinfo_free(&nexthop_nh->nh_rth_input); | 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 | #ifdef CONFIG_IP_ROUTE_CLASSID | 268 | #ifdef CONFIG_IP_ROUTE_CLASSID |
267 | nh->nh_tclassid != onh->nh_tclassid || | 269 | nh->nh_tclassid != onh->nh_tclassid || |
268 | #endif | 270 | #endif |
271 | lwtunnel_cmp_encap(nh->nh_lwtstate, onh->nh_lwtstate) || | ||
269 | ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK)) | 272 | ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK)) |
270 | return -1; | 273 | return -1; |
271 | onh++; | 274 | onh++; |
@@ -366,6 +369,7 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi) | |||
366 | payload += nla_total_size((RTAX_MAX * nla_total_size(4))); | 369 | payload += nla_total_size((RTAX_MAX * nla_total_size(4))); |
367 | 370 | ||
368 | if (fi->fib_nhs) { | 371 | if (fi->fib_nhs) { |
372 | size_t nh_encapsize = 0; | ||
369 | /* Also handles the special case fib_nhs == 1 */ | 373 | /* Also handles the special case fib_nhs == 1 */ |
370 | 374 | ||
371 | /* each nexthop is packed in an attribute */ | 375 | /* each nexthop is packed in an attribute */ |
@@ -374,8 +378,21 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi) | |||
374 | /* may contain flow and gateway attribute */ | 378 | /* may contain flow and gateway attribute */ |
375 | nhsize += 2 * nla_total_size(4); | 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 | /* all nexthops are packed in a nested attribute */ | 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 | return payload; | 398 | return payload; |
@@ -452,6 +469,9 @@ static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining) | |||
452 | static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, | 469 | static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, |
453 | int remaining, struct fib_config *cfg) | 470 | int remaining, struct fib_config *cfg) |
454 | { | 471 | { |
472 | struct net *net = cfg->fc_nlinfo.nl_net; | ||
473 | int ret; | ||
474 | |||
455 | change_nexthops(fi) { | 475 | change_nexthops(fi) { |
456 | int attrlen; | 476 | int attrlen; |
457 | 477 | ||
@@ -475,18 +495,66 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, | |||
475 | if (nexthop_nh->nh_tclassid) | 495 | if (nexthop_nh->nh_tclassid) |
476 | fi->fib_net->ipv4.fib_num_tclassid_users++; | 496 | fi->fib_net->ipv4.fib_num_tclassid_users++; |
477 | #endif | 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 | rtnh = rtnh_next(rtnh, &remaining); | 520 | rtnh = rtnh_next(rtnh, &remaining); |
481 | } endfor_nexthops(fi); | 521 | } endfor_nexthops(fi); |
482 | 522 | ||
483 | return 0; | 523 | return 0; |
524 | |||
525 | err_inval: | ||
526 | ret = -EINVAL; | ||
527 | |||
528 | errout: | ||
529 | return ret; | ||
484 | } | 530 | } |
485 | 531 | ||
486 | #endif | 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 | int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) | 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 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 558 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
491 | struct rtnexthop *rtnh; | 559 | struct rtnexthop *rtnh; |
492 | int remaining; | 560 | int remaining; |
@@ -496,6 +564,12 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) | |||
496 | return 1; | 564 | return 1; |
497 | 565 | ||
498 | if (cfg->fc_oif || cfg->fc_gw) { | 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 | if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && | 573 | if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && |
500 | (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) | 574 | (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) |
501 | return 0; | 575 | return 0; |
@@ -882,6 +956,22 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
882 | } else { | 956 | } else { |
883 | struct fib_nh *nh = fi->fib_nh; | 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 | nh->nh_oif = cfg->fc_oif; | 975 | nh->nh_oif = cfg->fc_oif; |
886 | nh->nh_gw = cfg->fc_gw; | 976 | nh->nh_gw = cfg->fc_gw; |
887 | nh->nh_flags = cfg->fc_flags; | 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 | nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) | 1145 | nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) |
1056 | goto nla_put_failure; | 1146 | goto nla_put_failure; |
1057 | #endif | 1147 | #endif |
1148 | if (fi->fib_nh->nh_lwtstate) | ||
1149 | lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate); | ||
1058 | } | 1150 | } |
1059 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1151 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
1060 | if (fi->fib_nhs > 1) { | 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 | nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) | 1182 | nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) |
1091 | goto nla_put_failure; | 1183 | goto nla_put_failure; |
1092 | #endif | 1184 | #endif |
1185 | if (nh->nh_lwtstate) | ||
1186 | lwtunnel_fill_encap(skb, nh->nh_lwtstate); | ||
1093 | /* length of rtnetlink header + attributes */ | 1187 | /* length of rtnetlink header + attributes */ |
1094 | rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; | 1188 | rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; |
1095 | } endfor_nexthops(fi); | 1189 | } endfor_nexthops(fi); |