summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_fib.h3
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/route.c33
3 files changed, 35 insertions, 3 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 3b76849c190f..276328e3daa6 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -51,6 +51,8 @@ struct fib6_config {
51 struct nlattr *fc_mp; 51 struct nlattr *fc_mp;
52 52
53 struct nl_info fc_nlinfo; 53 struct nl_info fc_nlinfo;
54 struct nlattr *fc_encap;
55 u16 fc_encap_type;
54}; 56};
55 57
56struct fib6_node { 58struct fib6_node {
@@ -131,6 +133,7 @@ struct rt6_info {
131 /* more non-fragment space at head required */ 133 /* more non-fragment space at head required */
132 unsigned short rt6i_nfheader_len; 134 unsigned short rt6i_nfheader_len;
133 u8 rt6i_protocol; 135 u8 rt6i_protocol;
136 struct lwtunnel_state *rt6i_lwtstate;
134}; 137};
135 138
136static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) 139static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 55d19861ab20..d715f2e0c4e7 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -32,6 +32,7 @@
32#include <net/ipv6.h> 32#include <net/ipv6.h>
33#include <net/ndisc.h> 33#include <net/ndisc.h>
34#include <net/addrconf.h> 34#include <net/addrconf.h>
35#include <net/lwtunnel.h>
35 36
36#include <net/ip6_fib.h> 37#include <net/ip6_fib.h>
37#include <net/ip6_route.h> 38#include <net/ip6_route.h>
@@ -177,6 +178,7 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
177static void rt6_release(struct rt6_info *rt) 178static void rt6_release(struct rt6_info *rt)
178{ 179{
179 if (atomic_dec_and_test(&rt->rt6i_ref)) { 180 if (atomic_dec_and_test(&rt->rt6i_ref)) {
181 lwtunnel_state_put(rt->rt6i_lwtstate);
180 rt6_free_pcpu(rt); 182 rt6_free_pcpu(rt);
181 dst_free(&rt->dst); 183 dst_free(&rt->dst);
182 } 184 }
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6090969937f8..b3431b79dfb1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -58,6 +58,7 @@
58#include <net/netevent.h> 58#include <net/netevent.h>
59#include <net/netlink.h> 59#include <net/netlink.h>
60#include <net/nexthop.h> 60#include <net/nexthop.h>
61#include <net/lwtunnel.h>
61 62
62#include <asm/uaccess.h> 63#include <asm/uaccess.h>
63 64
@@ -1770,6 +1771,17 @@ int ip6_route_add(struct fib6_config *cfg)
1770 1771
1771 rt->dst.output = ip6_output; 1772 rt->dst.output = ip6_output;
1772 1773
1774 if (cfg->fc_encap) {
1775 struct lwtunnel_state *lwtstate;
1776
1777 err = lwtunnel_build_state(dev, cfg->fc_encap_type,
1778 cfg->fc_encap, &lwtstate);
1779 if (err)
1780 goto out;
1781 lwtunnel_state_get(lwtstate);
1782 rt->rt6i_lwtstate = lwtstate;
1783 }
1784
1773 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); 1785 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1774 rt->rt6i_dst.plen = cfg->fc_dst_len; 1786 rt->rt6i_dst.plen = cfg->fc_dst_len;
1775 if (rt->rt6i_dst.plen == 128) 1787 if (rt->rt6i_dst.plen == 128)
@@ -2595,6 +2607,8 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
2595 [RTA_METRICS] = { .type = NLA_NESTED }, 2607 [RTA_METRICS] = { .type = NLA_NESTED },
2596 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, 2608 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
2597 [RTA_PREF] = { .type = NLA_U8 }, 2609 [RTA_PREF] = { .type = NLA_U8 },
2610 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2611 [RTA_ENCAP] = { .type = NLA_NESTED },
2598}; 2612};
2599 2613
2600static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, 2614static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -2689,6 +2703,12 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2689 cfg->fc_flags |= RTF_PREF(pref); 2703 cfg->fc_flags |= RTF_PREF(pref);
2690 } 2704 }
2691 2705
2706 if (tb[RTA_ENCAP])
2707 cfg->fc_encap = tb[RTA_ENCAP];
2708
2709 if (tb[RTA_ENCAP_TYPE])
2710 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
2711
2692 err = 0; 2712 err = 0;
2693errout: 2713errout:
2694 return err; 2714 return err;
@@ -2721,6 +2741,10 @@ beginning:
2721 r_cfg.fc_gateway = nla_get_in6_addr(nla); 2741 r_cfg.fc_gateway = nla_get_in6_addr(nla);
2722 r_cfg.fc_flags |= RTF_GATEWAY; 2742 r_cfg.fc_flags |= RTF_GATEWAY;
2723 } 2743 }
2744 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
2745 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
2746 if (nla)
2747 r_cfg.fc_encap_type = nla_get_u16(nla);
2724 } 2748 }
2725 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); 2749 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2726 if (err) { 2750 if (err) {
@@ -2783,7 +2807,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
2783 return ip6_route_add(&cfg); 2807 return ip6_route_add(&cfg);
2784} 2808}
2785 2809
2786static inline size_t rt6_nlmsg_size(void) 2810static inline size_t rt6_nlmsg_size(struct rt6_info *rt)
2787{ 2811{
2788 return NLMSG_ALIGN(sizeof(struct rtmsg)) 2812 return NLMSG_ALIGN(sizeof(struct rtmsg))
2789 + nla_total_size(16) /* RTA_SRC */ 2813 + nla_total_size(16) /* RTA_SRC */
@@ -2797,7 +2821,8 @@ static inline size_t rt6_nlmsg_size(void)
2797 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ 2821 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
2798 + nla_total_size(sizeof(struct rta_cacheinfo)) 2822 + nla_total_size(sizeof(struct rta_cacheinfo))
2799 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ 2823 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2800 + nla_total_size(1); /* RTA_PREF */ 2824 + nla_total_size(1) /* RTA_PREF */
2825 + lwtunnel_get_encap_size(rt->rt6i_lwtstate);
2801} 2826}
2802 2827
2803static int rt6_fill_node(struct net *net, 2828static int rt6_fill_node(struct net *net,
@@ -2945,6 +2970,8 @@ static int rt6_fill_node(struct net *net,
2945 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) 2970 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2946 goto nla_put_failure; 2971 goto nla_put_failure;
2947 2972
2973 lwtunnel_fill_encap(skb, rt->rt6i_lwtstate);
2974
2948 nlmsg_end(skb, nlh); 2975 nlmsg_end(skb, nlh);
2949 return 0; 2976 return 0;
2950 2977
@@ -3071,7 +3098,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
3071 err = -ENOBUFS; 3098 err = -ENOBUFS;
3072 seq = info->nlh ? info->nlh->nlmsg_seq : 0; 3099 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3073 3100
3074 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); 3101 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3075 if (!skb) 3102 if (!skb)
3076 goto errout; 3103 goto errout;
3077 3104