aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2015-07-21 04:43:47 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-21 13:39:03 -0400
commit571e722676fe386bb66f72a75b64a6ebf535c077 (patch)
tree80e374cf7f848408bad3be37237e4f43c9a9701b /net/ipv4/fib_semantics.c
parent499a24256862714539e902c0499b67da2bb3ab72 (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.c96
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)
452static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, 469static 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
525err_inval:
526 ret = -EINVAL;
527
528errout:
529 return ret;
484} 530}
485 531
486#endif 532#endif
487 533
534int 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
488int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) 555int 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);