Merge branch 'master' of git://1984.lsi.us.es/net-next-2.6
authorPatrick McHardy <kaber@trash.net>
Fri, 14 Jan 2011 13:12:37 +0000 (14:12 +0100)
committerPatrick McHardy <kaber@trash.net>
Fri, 14 Jan 2011 13:12:37 +0000 (14:12 +0100)
Conflicts:
net/ipv4/route.c

Signed-off-by: Patrick McHardy <kaber@trash.net>
1  2 
include/net/dst.h
net/ipv4/fib_semantics.c
net/ipv4/route.c

diff --combined include/net/dst.h
index 6baba836ad8b89f5af324427aac0dc577d7f7341,93b0310317bed44f54350aeecc9abf80141ca592..be5a0d4c491d98eb1c2123364a137c5c954a4152
@@@ -70,9 -70,9 +70,9 @@@ struct dst_entry 
  
        struct  dst_ops         *ops;
  
-       u32                     metrics[RTAX_MAX];
+       u32                     _metrics[RTAX_MAX];
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        __u32                   tclassid;
  #else
        __u32                   __pad2;
  #ifdef __KERNEL__
  
  static inline u32
- dst_metric(const struct dst_entry *dst, int metric)
+ dst_metric_raw(const struct dst_entry *dst, const int metric)
  {
-       return dst->metrics[metric-1];
+       return dst->_metrics[metric-1];
+ }
+ static inline u32
+ dst_metric(const struct dst_entry *dst, const int metric)
+ {
+       WARN_ON_ONCE(metric == RTAX_HOPLIMIT ||
+                    metric == RTAX_ADVMSS ||
+                    metric == RTAX_MTU);
+       return dst_metric_raw(dst, metric);
+ }
+ static inline u32
+ dst_metric_advmss(const struct dst_entry *dst)
+ {
+       u32 advmss = dst_metric_raw(dst, RTAX_ADVMSS);
+       if (!advmss)
+               advmss = dst->ops->default_advmss(dst);
+       return advmss;
+ }
+ static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val)
+ {
+       dst->_metrics[metric-1] = val;
+ }
+ static inline void dst_import_metrics(struct dst_entry *dst, const u32 *src_metrics)
+ {
+       memcpy(dst->_metrics, src_metrics, RTAX_MAX * sizeof(u32));
+ }
+ static inline void dst_copy_metrics(struct dst_entry *dest, const struct dst_entry *src)
+ {
+       dst_import_metrics(dest, src->_metrics);
+ }
+ static inline u32 *dst_metrics_ptr(struct dst_entry *dst)
+ {
+       return dst->_metrics;
  }
  
  static inline u32
@@@ -117,11 -157,11 +157,11 @@@ dst_feature(const struct dst_entry *dst
  
  static inline u32 dst_mtu(const struct dst_entry *dst)
  {
-       u32 mtu = dst_metric(dst, RTAX_MTU);
-       /*
-        * Alexey put it here, so ask him about it :)
-        */
-       barrier();
+       u32 mtu = dst_metric_raw(dst, RTAX_MTU);
+       if (!mtu)
+               mtu = dst->ops->default_mtu(dst);
        return mtu;
  }
  
@@@ -134,7 -174,7 +174,7 @@@ static inline unsigned long dst_metric_
  static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric,
                                      unsigned long rtt)
  {
-       dst->metrics[metric-1] = jiffies_to_msecs(rtt);
+       dst_metric_set(dst, metric, jiffies_to_msecs(rtt));
  }
  
  static inline u32
@@@ -147,7 -187,7 +187,7 @@@ dst_allfrag(const struct dst_entry *dst
  }
  
  static inline int
- dst_metric_locked(struct dst_entry *dst, int metric)
+ dst_metric_locked(const struct dst_entry *dst, int metric)
  {
        return dst_metric(dst, RTAX_LOCK) & (1<<metric);
  }
diff --combined net/ipv4/fib_semantics.c
index a72c62d03106c5ad3d89ff59fc41fd6abcb39a64,12d3dc3df1b7d683e94cbf42140a9ac40b35029d..9aff11d7278f5bf31305b4582ee5e0eff75ffd4a
@@@ -200,7 -200,7 +200,7 @@@ static inline int nh_comp(const struct 
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
                    nh->nh_weight != onh->nh_weight ||
  #endif
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                    nh->nh_tclassid != onh->nh_tclassid ||
  #endif
                    ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_F_DEAD))
@@@ -422,7 -422,7 +422,7 @@@ static int fib_get_nhs(struct fib_info 
  
                        nla = nla_find(attrs, attrlen, RTA_GATEWAY);
                        nexthop_nh->nh_gw = nla ? nla_get_be32(nla) : 0;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                        nla = nla_find(attrs, attrlen, RTA_FLOW);
                        nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
  #endif
@@@ -476,7 -476,7 +476,7 @@@ int fib_nh_match(struct fib_config *cfg
                        nla = nla_find(attrs, attrlen, RTA_GATEWAY);
                        if (nla && nla_get_be32(nla) != nh->nh_gw)
                                return 1;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                        nla = nla_find(attrs, attrlen, RTA_FLOW);
                        if (nla && nla_get_u32(nla) != nh->nh_tclassid)
                                return 1;
@@@ -563,12 -563,8 +563,8 @@@ static int fib_check_nh(struct fib_conf
                rcu_read_lock();
                {
                        struct flowi fl = {
-                               .nl_u = {
-                                       .ip4_u = {
-                                               .daddr = nh->nh_gw,
-                                               .scope = cfg->fc_scope + 1,
-                                       },
-                               },
+                               .fl4_dst = nh->nh_gw,
+                               .fl4_scope = cfg->fc_scope + 1,
                                .oif = nh->nh_oif,
                        };
  
@@@ -783,7 -779,7 +779,7 @@@ struct fib_info *fib_create_info(struc
                        goto err_inval;
                if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw)
                        goto err_inval;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow)
                        goto err_inval;
  #endif
                nh->nh_oif = cfg->fc_oif;
                nh->nh_gw = cfg->fc_gw;
                nh->nh_flags = cfg->fc_flags;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                nh->nh_tclassid = cfg->fc_flow;
  #endif
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
@@@ -1006,7 -1002,7 +1002,7 @@@ int fib_dump_info(struct sk_buff *skb, 
  
                if (fi->fib_nh->nh_oif)
                        NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif);
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                if (fi->fib_nh[0].nh_tclassid)
                        NLA_PUT_U32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid);
  #endif
  
                        if (nh->nh_gw)
                                NLA_PUT_BE32(skb, RTA_GATEWAY, nh->nh_gw);
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
                        if (nh->nh_tclassid)
                                NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid);
  #endif
diff --combined net/ipv4/route.c
index f70ae1bccb8a0938048ea8f64a859e5f1c72667e,351dc4e8524231ee907298ecc2a1cd6f3cf04e3d..3e5b7cc2db4fefbbfd682856588c8eb2fcc4ddc6
@@@ -139,6 -139,8 +139,8 @@@ static unsigned long expires_ljiffies
   */
  
  static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie);
+ static unsigned int    ipv4_default_advmss(const struct dst_entry *dst);
+ static unsigned int    ipv4_default_mtu(const struct dst_entry *dst);
  static void            ipv4_dst_destroy(struct dst_entry *dst);
  static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
  static void            ipv4_link_failure(struct sk_buff *skb);
@@@ -155,6 -157,8 +157,8 @@@ static struct dst_ops ipv4_dst_ops = 
        .protocol =             cpu_to_be16(ETH_P_IP),
        .gc =                   rt_garbage_collect,
        .check =                ipv4_dst_check,
+       .default_advmss =       ipv4_default_advmss,
+       .default_mtu =          ipv4_default_mtu,
        .destroy =              ipv4_dst_destroy,
        .ifdown =               ipv4_dst_ifdown,
        .negative_advice =      ipv4_negative_advice,
@@@ -383,8 -387,7 +387,7 @@@ static int rt_cache_seq_show(struct seq
                        (__force u32)r->rt_gateway,
                        r->rt_flags, atomic_read(&r->dst.__refcnt),
                        r->dst.__use, 0, (__force u32)r->rt_src,
-                       (dst_metric(&r->dst, RTAX_ADVMSS) ?
-                            (int)dst_metric(&r->dst, RTAX_ADVMSS) + 40 : 0),
+                       dst_metric_advmss(&r->dst) + 40,
                        dst_metric(&r->dst, RTAX_WINDOW),
                        (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +
                              dst_metric(&r->dst, RTAX_RTTVAR)),
@@@ -511,7 -514,7 +514,7 @@@ static const struct file_operations rt_
        .release = seq_release,
  };
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
  static int rt_acct_proc_show(struct seq_file *m, void *v)
  {
        struct ip_rt_acct *dst, *src;
@@@ -564,14 -567,14 +567,14 @@@ static int __net_init ip_rt_do_proc_ini
        if (!pde)
                goto err2;
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        pde = proc_create("rt_acct", 0, net->proc_net, &rt_acct_proc_fops);
        if (!pde)
                goto err3;
  #endif
        return 0;
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
  err3:
        remove_proc_entry("rt_cache", net->proc_net_stat);
  #endif
@@@ -585,7 -588,7 +588,7 @@@ static void __net_exit ip_rt_do_proc_ex
  {
        remove_proc_entry("rt_cache", net->proc_net_stat);
        remove_proc_entry("rt_cache", net->proc_net);
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        remove_proc_entry("rt_acct", net->proc_net);
  #endif
  }
@@@ -684,17 -687,17 +687,17 @@@ static inline bool rt_caching(const str
  static inline bool compare_hash_inputs(const struct flowi *fl1,
                                        const struct flowi *fl2)
  {
-       return ((((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
-               ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
+       return ((((__force u32)fl1->fl4_dst ^ (__force u32)fl2->fl4_dst) |
+               ((__force u32)fl1->fl4_src ^ (__force u32)fl2->fl4_src) |
                (fl1->iif ^ fl2->iif)) == 0);
  }
  
  static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
  {
-       return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
-               ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
+       return (((__force u32)fl1->fl4_dst ^ (__force u32)fl2->fl4_dst) |
+               ((__force u32)fl1->fl4_src ^ (__force u32)fl2->fl4_src) |
                (fl1->mark ^ fl2->mark) |
-               (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) |
+               (*(u16 *)&fl1->fl4_tos ^ *(u16 *)&fl2->fl4_tos) |
                (fl1->oif ^ fl2->oif) |
                (fl1->iif ^ fl2->iif)) == 0;
  }
@@@ -714,13 -717,15 +717,15 @@@ static inline int rt_is_expired(struct 
   * Can be called by a softirq or a process.
   * In the later case, we want to be reschedule if necessary
   */
- static void rt_do_flush(int process_context)
+ static void rt_do_flush(struct net *net, int process_context)
  {
        unsigned int i;
        struct rtable *rth, *next;
-       struct rtable * tail;
  
        for (i = 0; i <= rt_hash_mask; i++) {
+               struct rtable __rcu **pprev;
+               struct rtable *list;
                if (process_context && need_resched())
                        cond_resched();
                rth = rcu_dereference_raw(rt_hash_table[i].chain);
                        continue;
  
                spin_lock_bh(rt_hash_lock_addr(i));
- #ifdef CONFIG_NET_NS
-               {
-               struct rtable __rcu **prev;
-               struct rtable *p;
  
-               rth = rcu_dereference_protected(rt_hash_table[i].chain,
+               list = NULL;
+               pprev = &rt_hash_table[i].chain;
+               rth = rcu_dereference_protected(*pprev,
                        lockdep_is_held(rt_hash_lock_addr(i)));
  
-               /* defer releasing the head of the list after spin_unlock */
-               for (tail = rth; tail;
-                    tail = rcu_dereference_protected(tail->dst.rt_next,
-                               lockdep_is_held(rt_hash_lock_addr(i))))
-                       if (!rt_is_expired(tail))
-                               break;
-               if (rth != tail)
-                       rt_hash_table[i].chain = tail;
-               /* call rt_free on entries after the tail requiring flush */
-               prev = &rt_hash_table[i].chain;
-               for (p = rcu_dereference_protected(*prev,
+               while (rth) {
+                       next = rcu_dereference_protected(rth->dst.rt_next,
                                lockdep_is_held(rt_hash_lock_addr(i)));
-                    p != NULL;
-                    p = next) {
-                       next = rcu_dereference_protected(p->dst.rt_next,
-                               lockdep_is_held(rt_hash_lock_addr(i)));
-                       if (!rt_is_expired(p)) {
-                               prev = &p->dst.rt_next;
+                       if (!net ||
+                           net_eq(dev_net(rth->dst.dev), net)) {
+                               rcu_assign_pointer(*pprev, next);
+                               rcu_assign_pointer(rth->dst.rt_next, list);
+                               list = rth;
                        } else {
-                               *prev = next;
-                               rt_free(p);
+                               pprev = &rth->dst.rt_next;
                        }
+                       rth = next;
                }
-               }
- #else
-               rth = rcu_dereference_protected(rt_hash_table[i].chain,
-                       lockdep_is_held(rt_hash_lock_addr(i)));
-               rcu_assign_pointer(rt_hash_table[i].chain, NULL);
-               tail = NULL;
- #endif
                spin_unlock_bh(rt_hash_lock_addr(i));
  
-               for (; rth != tail; rth = next) {
-                       next = rcu_dereference_protected(rth->dst.rt_next, 1);
-                       rt_free(rth);
+               for (; list; list = next) {
+                       next = rcu_dereference_protected(list->dst.rt_next, 1);
+                       rt_free(list);
                }
        }
  }
@@@ -919,13 -906,13 +906,13 @@@ void rt_cache_flush(struct net *net, in
  {
        rt_cache_invalidate(net);
        if (delay >= 0)
-               rt_do_flush(!in_softirq());
+               rt_do_flush(net, !in_softirq());
  }
  
  /* Flush previous cache invalidated entries from the cache */
- void rt_cache_flush_batch(void)
+ void rt_cache_flush_batch(struct net *net)
  {
-       rt_do_flush(!in_softirq());
+       rt_do_flush(net, !in_softirq());
  }
  
  static void rt_emergency_hash_rebuild(struct net *net)
@@@ -1289,7 -1276,7 +1276,7 @@@ void rt_bind_peer(struct rtable *rt, in
  {
        struct inet_peer *peer;
  
-       peer = inet_getpeer(rt->rt_dst, create);
+       peer = inet_getpeer_v4(rt->rt_dst, create);
  
        if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
                inet_putpeer(peer);
@@@ -1686,11 -1673,14 +1673,14 @@@ unsigned short ip_rt_frag_needed(struc
                                        if (mtu < dst_mtu(&rth->dst)) {
                                                dst_confirm(&rth->dst);
                                                if (mtu < ip_rt_min_pmtu) {
+                                                       u32 lock = dst_metric(&rth->dst,
+                                                                             RTAX_LOCK);
                                                        mtu = ip_rt_min_pmtu;
-                                                       rth->dst.metrics[RTAX_LOCK-1] |=
-                                                               (1 << RTAX_MTU);
+                                                       lock |= (1 << RTAX_MTU);
+                                                       dst_metric_set(&rth->dst, RTAX_LOCK,
+                                                                      lock);
                                                }
-                                               rth->dst.metrics[RTAX_MTU-1] = mtu;
+                                               dst_metric_set(&rth->dst, RTAX_MTU, mtu);
                                                dst_set_expires(&rth->dst,
                                                        ip_rt_mtu_expires);
                                        }
@@@ -1708,10 -1698,11 +1698,11 @@@ static void ip_rt_update_pmtu(struct ds
        if (dst_mtu(dst) > mtu && mtu >= 68 &&
            !(dst_metric_locked(dst, RTAX_MTU))) {
                if (mtu < ip_rt_min_pmtu) {
+                       u32 lock = dst_metric(dst, RTAX_LOCK);
                        mtu = ip_rt_min_pmtu;
-                       dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU);
+                       dst_metric_set(dst, RTAX_LOCK, lock | (1 << RTAX_MTU));
                }
-               dst->metrics[RTAX_MTU-1] = mtu;
+               dst_metric_set(dst, RTAX_MTU, mtu);
                dst_set_expires(dst, ip_rt_mtu_expires);
                call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
        }
@@@ -1784,7 -1775,7 +1775,7 @@@ void ip_rt_get_source(u8 *addr, struct 
        memcpy(addr, &src, 4);
  }
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
  static void set_class_tag(struct rtable *rt, u32 tag)
  {
        if (!(rt->dst.tclassid & 0xFFFF))
  }
  #endif
  
+ static unsigned int ipv4_default_advmss(const struct dst_entry *dst)
+ {
+       unsigned int advmss = dst_metric_raw(dst, RTAX_ADVMSS);
+       if (advmss == 0) {
+               advmss = max_t(unsigned int, dst->dev->mtu - 40,
+                              ip_rt_min_advmss);
+               if (advmss > 65535 - 40)
+                       advmss = 65535 - 40;
+       }
+       return advmss;
+ }
+ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
+ {
+       unsigned int mtu = dst->dev->mtu;
+       if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
+               const struct rtable *rt = (const struct rtable *) dst;
+               if (rt->rt_gateway != rt->rt_dst && mtu > 576)
+                       mtu = 576;
+       }
+       if (mtu > IP_MAX_MTU)
+               mtu = IP_MAX_MTU;
+       return mtu;
+ }
  static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
  {
+       struct dst_entry *dst = &rt->dst;
        struct fib_info *fi = res->fi;
  
        if (fi) {
                if (FIB_RES_GW(*res) &&
                    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
                        rt->rt_gateway = FIB_RES_GW(*res);
-               memcpy(rt->dst.metrics, fi->fib_metrics,
-                      sizeof(rt->dst.metrics));
-               if (fi->fib_mtu == 0) {
-                       rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
-                       if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
-                           rt->rt_gateway != rt->rt_dst &&
-                           rt->dst.dev->mtu > 576)
-                               rt->dst.metrics[RTAX_MTU-1] = 576;
-               }
+               dst_import_metrics(dst, fi->fib_metrics);
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
-               rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
+               dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
  #endif
-       } else
-               rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;
-       if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
-               rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
-       if (dst_mtu(&rt->dst) > IP_MAX_MTU)
-               rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
-       if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
-               rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
-                                      ip_rt_min_advmss);
-       if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
-               rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
+       }
+       if (dst_mtu(dst) > IP_MAX_MTU)
+               dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
+       if (dst_metric_raw(dst, RTAX_ADVMSS) > 65535 - 40)
+               dst_metric_set(dst, RTAX_ADVMSS, 65535 - 40);
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
  #ifdef CONFIG_IP_MULTIPLE_TABLES
        set_class_tag(rt, fib_rules_tclass(res));
  #endif
@@@ -1883,7 -1891,7 +1891,7 @@@ static int ip_route_input_mc(struct sk_
        rth->fl.mark    = skb->mark;
        rth->fl.fl4_src = saddr;
        rth->rt_src     = saddr;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        rth->dst.tclassid = itag;
  #endif
        rth->rt_iif     =
@@@ -2089,12 -2097,10 +2097,10 @@@ static int ip_route_input_slow(struct s
  {
        struct fib_result res;
        struct in_device *in_dev = __in_dev_get_rcu(dev);
-       struct flowi fl = { .nl_u = { .ip4_u =
-                                     { .daddr = daddr,
-                                       .saddr = saddr,
-                                       .tos = tos,
-                                       .scope = RT_SCOPE_UNIVERSE,
-                                     } },
+       struct flowi fl = { .fl4_dst    = daddr,
+                           .fl4_src    = saddr,
+                           .fl4_tos    = tos,
+                           .fl4_scope  = RT_SCOPE_UNIVERSE,
                            .mark = skb->mark,
                            .iif = dev->ifindex };
        unsigned        flags = 0;
@@@ -2202,7 -2208,7 +2208,7 @@@ local_input
        rth->fl.mark    = skb->mark;
        rth->fl.fl4_src = saddr;
        rth->rt_src     = saddr;
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        rth->dst.tclassid = itag;
  #endif
        rth->rt_iif     =
@@@ -2480,14 -2486,11 +2486,11 @@@ static int ip_route_output_slow(struct 
                                const struct flowi *oldflp)
  {
        u32 tos = RT_FL_TOS(oldflp);
-       struct flowi fl = { .nl_u = { .ip4_u =
-                                     { .daddr = oldflp->fl4_dst,
-                                       .saddr = oldflp->fl4_src,
-                                       .tos = tos & IPTOS_RT_MASK,
-                                       .scope = ((tos & RTO_ONLINK) ?
-                                                 RT_SCOPE_LINK :
-                                                 RT_SCOPE_UNIVERSE),
-                                     } },
+       struct flowi fl = { .fl4_dst = oldflp->fl4_dst,
+                           .fl4_src = oldflp->fl4_src,
+                           .fl4_tos = tos & IPTOS_RT_MASK,
+                           .fl4_scope = ((tos & RTO_ONLINK) ?
+                                         RT_SCOPE_LINK : RT_SCOPE_UNIVERSE),
                            .mark = oldflp->mark,
                            .iif = net->loopback_dev->ifindex,
                            .oif = oldflp->oif };
                        goto out;
  
                /* RACE: Check return value of inet_select_addr instead. */
-               if (rcu_dereference(dev_out->ip_ptr) == NULL)
-                       goto out;       /* Wrong error code */
+               if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) {
+                       err = -ENETUNREACH;
+                       goto out;
+               }
                if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
                    ipv4_is_lbcast(oldflp->fl4_dst)) {
                        if (!fl.fl4_src)
        }
  
        if (res.type == RTN_LOCAL) {
-               if (!fl.fl4_src)
-                       fl.fl4_src = fl.fl4_dst;
+               if (!fl.fl4_src) {
+                       if (res.fi->fib_prefsrc)
+                               fl.fl4_src = res.fi->fib_prefsrc;
+                       else
+                               fl.fl4_src = fl.fl4_dst;
+               }
                dev_out = net->loopback_dev;
                fl.oif = dev_out->ifindex;
                res.fi = NULL;
@@@ -2725,7 -2733,7 +2733,7 @@@ static int ipv4_dst_blackhole(struct ne
                new->__use = 1;
                new->input = dst_discard;
                new->output = dst_discard;
-               memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+               dst_copy_metrics(new, &ort->dst);
  
                new->dev = ort->dst.dev;
                if (new->dev)
@@@ -2820,7 -2828,7 +2828,7 @@@ static int rt_fill_info(struct net *net
        }
        if (rt->dst.dev)
                NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        if (rt->dst.tclassid)
                NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid);
  #endif
        if (rt->rt_dst != rt->rt_gateway)
                NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
  
-       if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
+       if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto nla_put_failure;
  
        if (rt->fl.mark)
@@@ -2944,13 -2952,9 +2952,9 @@@ static int inet_rtm_getroute(struct sk_
                        err = -rt->dst.error;
        } else {
                struct flowi fl = {
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = dst,
-                                       .saddr = src,
-                                       .tos = rtm->rtm_tos,
-                               },
-                       },
+                       .fl4_dst = dst,
+                       .fl4_src = src,
+                       .fl4_tos = rtm->rtm_tos,
                        .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
                        .mark = mark,
                };
@@@ -3245,9 -3249,9 +3249,9 @@@ static __net_initdata struct pernet_ope
  };
  
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
  struct ip_rt_acct __percpu *ip_rt_acct __read_mostly;
 -#endif /* CONFIG_NET_CLS_ROUTE */
 +#endif /* CONFIG_IP_ROUTE_CLASSID */
  
  static __initdata unsigned long rhash_entries;
  static int __init set_rhash_entries(char *str)
@@@ -3263,7 -3267,7 +3267,7 @@@ int __init ip_rt_init(void
  {
        int rc = 0;
  
 -#ifdef CONFIG_NET_CLS_ROUTE
 +#ifdef CONFIG_IP_ROUTE_CLASSID
        ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct));
        if (!ip_rt_acct)
                panic("IP: failed to allocate ip_rt_acct\n");