X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;ds=sidebyside;f=net%2Fipv6%2Froute.c;h=19a77d0e03080cd3c185a4a7593fd5fefda2896e;hb=2bd93d7af1581d40e3c4b25242472661cb7c637a;hp=843406f14d7b2b37ac33b039f52fe80feb132cba;hpb=a8a44921383039bd5387020d035123d21660b309;p=cascardo%2Flinux.git diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 843406f14d7b..19a77d0e0308 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -89,12 +89,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_add_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex, unsigned pref); static struct rt6_info *rt6_get_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex); + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex); #endif static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) @@ -153,6 +153,12 @@ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } +static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst, + unsigned long old) +{ + return NULL; +} + static struct dst_ops ip6_dst_blackhole_ops = { .family = AF_INET6, .protocol = cpu_to_be16(ETH_P_IPV6), @@ -161,6 +167,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .default_mtu = ip6_blackhole_default_mtu, .default_advmss = ip6_default_advmss, .update_pmtu = ip6_rt_blackhole_update_pmtu, + .cow_metrics = ip6_rt_blackhole_cow_metrics, }; static const u32 ip6_template_metrics[RTAX_MAX] = { @@ -283,7 +290,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) time_after(jiffies, rt->rt6i_expires); } -static inline int rt6_need_strict(struct in6_addr *daddr) +static inline int rt6_need_strict(const struct in6_addr *daddr) { return ipv6_addr_type(daddr) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); @@ -295,7 +302,7 @@ static inline int rt6_need_strict(struct in6_addr *daddr) static inline struct rt6_info *rt6_device_match(struct net *net, struct rt6_info *rt, - struct in6_addr *saddr, + const struct in6_addr *saddr, int oif, int flags) { @@ -507,7 +514,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) #ifdef CONFIG_IPV6_ROUTE_INFO int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, - struct in6_addr *gwaddr) + const struct in6_addr *gwaddr) { struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; @@ -670,8 +677,8 @@ int ip6_ins_rt(struct rt6_info *rt) return __ip6_ins_rt(rt, &info); } -static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, - struct in6_addr *saddr) +static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, + const struct in6_addr *saddr) { struct rt6_info *rt; @@ -739,7 +746,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad return rt; } -static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) +static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) { struct rt6_info *rt = ip6_rt_copy(ort); if (rt) { @@ -830,7 +837,7 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table * void ip6_route_input(struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct net *net = dev_net(skb->dev); int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi6 fl6 = { @@ -1272,7 +1279,7 @@ int ip6_route_add(struct fib6_config *cfg) } if (cfg->fc_flags & RTF_GATEWAY) { - struct in6_addr *gw_addr; + const struct in6_addr *gw_addr; int gwa_type; gw_addr = &cfg->fc_gateway; @@ -1325,6 +1332,16 @@ int ip6_route_add(struct fib6_config *cfg) if (dev == NULL) goto out; + if (!ipv6_addr_any(&cfg->fc_prefsrc)) { + if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { + err = -EINVAL; + goto out; + } + ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc); + rt->rt6i_prefsrc.plen = 128; + } else + rt->rt6i_prefsrc.plen = 0; + if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); if (IS_ERR(rt->rt6i_nexthop)) { @@ -1502,9 +1519,9 @@ out: return rt; }; -static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, - struct in6_addr *src, - struct in6_addr *gateway, +static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, + const struct in6_addr *src, + const struct in6_addr *gateway, struct net_device *dev) { int flags = RT6_LOOKUP_F_HAS_SADDR; @@ -1526,8 +1543,8 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, flags, __ip6_route_redirect); } -void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, - struct in6_addr *saddr, +void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, + const struct in6_addr *saddr, struct neighbour *neigh, u8 *lladdr, int on_link) { struct rt6_info *rt, *nrt = NULL; @@ -1601,7 +1618,7 @@ out: * i.e. Path MTU discovery */ -static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, +static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr, struct net *net, u32 pmtu, int ifindex) { struct rt6_info *rt, *nrt; @@ -1686,7 +1703,7 @@ out: dst_release(&rt->dst); } -void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, +void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct net *net = dev_net(dev); @@ -1746,8 +1763,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_get_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex) + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex) { struct fib6_node *fn; struct rt6_info *rt = NULL; @@ -1778,8 +1795,8 @@ out: } static struct rt6_info *rt6_add_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex, unsigned pref) { struct fib6_config cfg = { @@ -1807,7 +1824,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, } #endif -struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) +struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) { struct rt6_info *rt; struct fib6_table *table; @@ -1829,7 +1846,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d return rt; } -struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, +struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref) { @@ -2012,7 +2029,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, rt->dst.output = ip6_output; rt->rt6i_dev = net->loopback_dev; rt->rt6i_idev = idev; - dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); rt->dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; @@ -2037,6 +2053,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, return rt; } +int ip6_route_get_saddr(struct net *net, + struct rt6_info *rt, + const struct in6_addr *daddr, + unsigned int prefs, + struct in6_addr *saddr) +{ + struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt); + int err = 0; + if (rt->rt6i_prefsrc.plen) + ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr); + else + err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, + daddr, prefs, saddr); + return err; +} + +/* remove deleted ip from prefsrc entries */ +struct arg_dev_net_ip { + struct net_device *dev; + struct net *net; + struct in6_addr *addr; +}; + +static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) +{ + struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev; + struct net *net = ((struct arg_dev_net_ip *)arg)->net; + struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; + + if (((void *)rt->rt6i_dev == dev || dev == NULL) && + rt != net->ipv6.ip6_null_entry && + ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { + /* remove prefsrc entry */ + rt->rt6i_prefsrc.plen = 0; + } + return 0; +} + +void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) +{ + struct net *net = dev_net(ifp->idev->dev); + struct arg_dev_net_ip adni = { + .dev = ifp->idev->dev, + .net = net, + .addr = &ifp->addr, + }; + fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); +} + struct arg_dev_net { struct net_device *dev; struct net *net; @@ -2183,6 +2248,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); } + if (tb[RTA_PREFSRC]) + nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16); + if (tb[RTA_OIF]) cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); @@ -2325,13 +2393,17 @@ static int rt6_fill_node(struct net *net, #endif NLA_PUT_U32(skb, RTA_IIF, iif); } else if (dst) { - struct inet6_dev *idev = ip6_dst_idev(&rt->dst); struct in6_addr saddr_buf; - if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, - dst, 0, &saddr_buf) == 0) + if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } + if (rt->rt6i_prefsrc.plen) { + struct in6_addr saddr_buf; + ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr); + NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); + } + if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) goto nla_put_failure;