net/ipv4: fib_trie: Avoid cryptic ternary expressions
[linux-2.6-microblaze.git] / net / ipv4 / fib_trie.c
index 868c747..90f0fc8 100644 (file)
@@ -338,12 +338,18 @@ static struct tnode *tnode_alloc(int bits)
 
 static inline void empty_child_inc(struct key_vector *n)
 {
-       ++tn_info(n)->empty_children ? : ++tn_info(n)->full_children;
+       tn_info(n)->empty_children++;
+
+       if (!tn_info(n)->empty_children)
+               tn_info(n)->full_children++;
 }
 
 static inline void empty_child_dec(struct key_vector *n)
 {
-       tn_info(n)->empty_children-- ? : tn_info(n)->full_children--;
+       if (!tn_info(n)->empty_children)
+               tn_info(n)->full_children--;
+
+       tn_info(n)->empty_children--;
 }
 
 static struct key_vector *leaf_new(t_key key, struct fib_alias *fa)
@@ -1449,6 +1455,7 @@ found:
                fib_alias_accessed(fa);
                err = fib_props[fa->fa_type].error;
                if (unlikely(err < 0)) {
+out_reject:
 #ifdef CONFIG_IP_FIB_TRIE_STATS
                        this_cpu_inc(stats->semantic_match_passed);
 #endif
@@ -1457,7 +1464,13 @@ found:
                }
                if (fi->fib_flags & RTNH_F_DEAD)
                        continue;
-               for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
+
+               if (unlikely(fi->nh && nexthop_is_blackhole(fi->nh))) {
+                       err = fib_props[RTN_BLACKHOLE].error;
+                       goto out_reject;
+               }
+
+               for (nhsel = 0; nhsel < fib_info_num_path(fi); nhsel++) {
                        struct fib_nh_common *nhc = fib_info_nhc(fi, nhsel);
 
                        if (nhc->nhc_flags & RTNH_F_DEAD)
@@ -1931,6 +1944,77 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
        return found;
 }
 
+/* derived from fib_trie_free */
+static void __fib_info_notify_update(struct net *net, struct fib_table *tb,
+                                    struct nl_info *info)
+{
+       struct trie *t = (struct trie *)tb->tb_data;
+       struct key_vector *pn = t->kv;
+       unsigned long cindex = 1;
+       struct fib_alias *fa;
+
+       for (;;) {
+               struct key_vector *n;
+
+               if (!(cindex--)) {
+                       t_key pkey = pn->key;
+
+                       if (IS_TRIE(pn))
+                               break;
+
+                       pn = node_parent(pn);
+                       cindex = get_index(pkey, pn);
+                       continue;
+               }
+
+               /* grab the next available node */
+               n = get_child(pn, cindex);
+               if (!n)
+                       continue;
+
+               if (IS_TNODE(n)) {
+                       /* record pn and cindex for leaf walking */
+                       pn = n;
+                       cindex = 1ul << n->bits;
+
+                       continue;
+               }
+
+               hlist_for_each_entry(fa, &n->leaf, fa_list) {
+                       struct fib_info *fi = fa->fa_info;
+
+                       if (!fi || !fi->nh_updated || fa->tb_id != tb->tb_id)
+                               continue;
+
+                       rtmsg_fib(RTM_NEWROUTE, htonl(n->key), fa,
+                                 KEYLENGTH - fa->fa_slen, tb->tb_id,
+                                 info, NLM_F_REPLACE);
+
+                       /* call_fib_entry_notifiers will be removed when
+                        * in-kernel notifier is implemented and supported
+                        * for nexthop objects
+                        */
+                       call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
+                                                n->key,
+                                                KEYLENGTH - fa->fa_slen, fa,
+                                                NULL);
+               }
+       }
+}
+
+void fib_info_notify_update(struct net *net, struct nl_info *info)
+{
+       unsigned int h;
+
+       for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               struct fib_table *tb;
+
+               hlist_for_each_entry_rcu(tb, head, tb_hlist)
+                       __fib_info_notify_update(net, tb, info);
+       }
+}
+
 static void fib_leaf_notify(struct net *net, struct key_vector *l,
                            struct fib_table *tb, struct notifier_block *nb)
 {
@@ -2634,14 +2718,18 @@ static void fib_route_seq_stop(struct seq_file *seq, void *v)
        rcu_read_unlock();
 }
 
-static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
+static unsigned int fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
 {
        unsigned int flags = 0;
 
        if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
                flags = RTF_REJECT;
-       if (fi && fi->fib_nh->fib_nh_gw4)
-               flags |= RTF_GATEWAY;
+       if (fi) {
+               const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
+
+               if (nhc->nhc_gw.ipv4)
+                       flags |= RTF_GATEWAY;
+       }
        if (mask == htonl(0xFFFFFFFF))
                flags |= RTF_HOST;
        flags |= RTF_UP;
@@ -2672,7 +2760,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
        prefix = htonl(l->key);
 
        hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
-               const struct fib_info *fi = fa->fa_info;
+               struct fib_info *fi = fa->fa_info;
                __be32 mask = inet_make_mask(KEYLENGTH - fa->fa_slen);
                unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
 
@@ -2685,26 +2773,31 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 
                seq_setwidth(seq, 127);
 
-               if (fi)
+               if (fi) {
+                       struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
+                       __be32 gw = 0;
+
+                       if (nhc->nhc_gw_family == AF_INET)
+                               gw = nhc->nhc_gw.ipv4;
+
                        seq_printf(seq,
                                   "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
                                   "%d\t%08X\t%d\t%u\t%u",
-                                  fi->fib_dev ? fi->fib_dev->name : "*",
-                                  prefix,
-                                  fi->fib_nh->fib_nh_gw4, flags, 0, 0,
+                                  nhc->nhc_dev ? nhc->nhc_dev->name : "*",
+                                  prefix, gw, flags, 0, 0,
                                   fi->fib_priority,
                                   mask,
                                   (fi->fib_advmss ?
                                    fi->fib_advmss + 40 : 0),
                                   fi->fib_window,
                                   fi->fib_rtt >> 3);
-               else
+               } else {
                        seq_printf(seq,
                                   "*\t%08X\t%08X\t%04X\t%d\t%u\t"
                                   "%d\t%08X\t%d\t%u\t%u",
                                   prefix, 0, flags, 0, 0, 0,
                                   mask, 0, 0, 0);
-
+               }
                seq_pad(seq, '\n');
        }