linux/net/ipv4/ipmr_base.c
<<
>>
Prefs
   1/* Linux multicast routing support
   2 * Common logic shared by IPv4 [ipmr] and IPv6 [ip6mr] implementation
   3 */
   4
   5#include <linux/rhashtable.h>
   6#include <linux/mroute_base.h>
   7
   8/* Sets everything common except 'dev', since that is done under locking */
   9void vif_device_init(struct vif_device *v,
  10                     struct net_device *dev,
  11                     unsigned long rate_limit,
  12                     unsigned char threshold,
  13                     unsigned short flags,
  14                     unsigned short get_iflink_mask)
  15{
  16        v->dev = NULL;
  17        v->bytes_in = 0;
  18        v->bytes_out = 0;
  19        v->pkt_in = 0;
  20        v->pkt_out = 0;
  21        v->rate_limit = rate_limit;
  22        v->flags = flags;
  23        v->threshold = threshold;
  24        if (v->flags & get_iflink_mask)
  25                v->link = dev_get_iflink(dev);
  26        else
  27                v->link = dev->ifindex;
  28}
  29EXPORT_SYMBOL(vif_device_init);
  30
  31struct mr_table *
  32mr_table_alloc(struct net *net, u32 id,
  33               struct mr_table_ops *ops,
  34               void (*expire_func)(struct timer_list *t),
  35               void (*table_set)(struct mr_table *mrt,
  36                                 struct net *net))
  37{
  38        struct mr_table *mrt;
  39        int err;
  40
  41        mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
  42        if (!mrt)
  43                return ERR_PTR(-ENOMEM);
  44        mrt->id = id;
  45        write_pnet(&mrt->net, net);
  46
  47        mrt->ops = *ops;
  48        err = rhltable_init(&mrt->mfc_hash, mrt->ops.rht_params);
  49        if (err) {
  50                kfree(mrt);
  51                return ERR_PTR(err);
  52        }
  53        INIT_LIST_HEAD(&mrt->mfc_cache_list);
  54        INIT_LIST_HEAD(&mrt->mfc_unres_queue);
  55
  56        timer_setup(&mrt->ipmr_expire_timer, expire_func, 0);
  57
  58        mrt->mroute_reg_vif_num = -1;
  59        table_set(mrt, net);
  60        return mrt;
  61}
  62EXPORT_SYMBOL(mr_table_alloc);
  63
  64void *mr_mfc_find_parent(struct mr_table *mrt, void *hasharg, int parent)
  65{
  66        struct rhlist_head *tmp, *list;
  67        struct mr_mfc *c;
  68
  69        list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
  70        rhl_for_each_entry_rcu(c, tmp, list, mnode)
  71                if (parent == -1 || parent == c->mfc_parent)
  72                        return c;
  73
  74        return NULL;
  75}
  76EXPORT_SYMBOL(mr_mfc_find_parent);
  77
  78void *mr_mfc_find_any_parent(struct mr_table *mrt, int vifi)
  79{
  80        struct rhlist_head *tmp, *list;
  81        struct mr_mfc *c;
  82
  83        list = rhltable_lookup(&mrt->mfc_hash, mrt->ops.cmparg_any,
  84                               *mrt->ops.rht_params);
  85        rhl_for_each_entry_rcu(c, tmp, list, mnode)
  86                if (c->mfc_un.res.ttls[vifi] < 255)
  87                        return c;
  88
  89        return NULL;
  90}
  91EXPORT_SYMBOL(mr_mfc_find_any_parent);
  92
  93void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg)
  94{
  95        struct rhlist_head *tmp, *list;
  96        struct mr_mfc *c, *proxy;
  97
  98        list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
  99        rhl_for_each_entry_rcu(c, tmp, list, mnode) {
 100                if (c->mfc_un.res.ttls[vifi] < 255)
 101                        return c;
 102
 103                /* It's ok if the vifi is part of the static tree */
 104                proxy = mr_mfc_find_any_parent(mrt, c->mfc_parent);
 105                if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
 106                        return c;
 107        }
 108
 109        return mr_mfc_find_any_parent(mrt, vifi);
 110}
 111EXPORT_SYMBOL(mr_mfc_find_any);
 112
 113#ifdef CONFIG_PROC_FS
 114void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, loff_t pos)
 115{
 116        struct mr_table *mrt = iter->mrt;
 117
 118        for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
 119                if (!VIF_EXISTS(mrt, iter->ct))
 120                        continue;
 121                if (pos-- == 0)
 122                        return &mrt->vif_table[iter->ct];
 123        }
 124        return NULL;
 125}
 126EXPORT_SYMBOL(mr_vif_seq_idx);
 127
 128void *mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 129{
 130        struct mr_vif_iter *iter = seq->private;
 131        struct net *net = seq_file_net(seq);
 132        struct mr_table *mrt = iter->mrt;
 133
 134        ++*pos;
 135        if (v == SEQ_START_TOKEN)
 136                return mr_vif_seq_idx(net, iter, 0);
 137
 138        while (++iter->ct < mrt->maxvif) {
 139                if (!VIF_EXISTS(mrt, iter->ct))
 140                        continue;
 141                return &mrt->vif_table[iter->ct];
 142        }
 143        return NULL;
 144}
 145EXPORT_SYMBOL(mr_vif_seq_next);
 146
 147void *mr_mfc_seq_idx(struct net *net,
 148                     struct mr_mfc_iter *it, loff_t pos)
 149{
 150        struct mr_table *mrt = it->mrt;
 151        struct mr_mfc *mfc;
 152
 153        rcu_read_lock();
 154        it->cache = &mrt->mfc_cache_list;
 155        list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
 156                if (pos-- == 0)
 157                        return mfc;
 158        rcu_read_unlock();
 159
 160        spin_lock_bh(it->lock);
 161        it->cache = &mrt->mfc_unres_queue;
 162        list_for_each_entry(mfc, it->cache, list)
 163                if (pos-- == 0)
 164                        return mfc;
 165        spin_unlock_bh(it->lock);
 166
 167        it->cache = NULL;
 168        return NULL;
 169}
 170EXPORT_SYMBOL(mr_mfc_seq_idx);
 171
 172void *mr_mfc_seq_next(struct seq_file *seq, void *v,
 173                      loff_t *pos)
 174{
 175        struct mr_mfc_iter *it = seq->private;
 176        struct net *net = seq_file_net(seq);
 177        struct mr_table *mrt = it->mrt;
 178        struct mr_mfc *c = v;
 179
 180        ++*pos;
 181
 182        if (v == SEQ_START_TOKEN)
 183                return mr_mfc_seq_idx(net, seq->private, 0);
 184
 185        if (c->list.next != it->cache)
 186                return list_entry(c->list.next, struct mr_mfc, list);
 187
 188        if (it->cache == &mrt->mfc_unres_queue)
 189                goto end_of_list;
 190
 191        /* exhausted cache_array, show unresolved */
 192        rcu_read_unlock();
 193        it->cache = &mrt->mfc_unres_queue;
 194
 195        spin_lock_bh(it->lock);
 196        if (!list_empty(it->cache))
 197                return list_first_entry(it->cache, struct mr_mfc, list);
 198
 199end_of_list:
 200        spin_unlock_bh(it->lock);
 201        it->cache = NULL;
 202
 203        return NULL;
 204}
 205EXPORT_SYMBOL(mr_mfc_seq_next);
 206#endif
 207
 208int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
 209                   struct mr_mfc *c, struct rtmsg *rtm)
 210{
 211        struct rta_mfc_stats mfcs;
 212        struct nlattr *mp_attr;
 213        struct rtnexthop *nhp;
 214        unsigned long lastuse;
 215        int ct;
 216
 217        /* If cache is unresolved, don't try to parse IIF and OIF */
 218        if (c->mfc_parent >= MAXVIFS) {
 219                rtm->rtm_flags |= RTNH_F_UNRESOLVED;
 220                return -ENOENT;
 221        }
 222
 223        if (VIF_EXISTS(mrt, c->mfc_parent) &&
 224            nla_put_u32(skb, RTA_IIF,
 225                        mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
 226                return -EMSGSIZE;
 227
 228        if (c->mfc_flags & MFC_OFFLOAD)
 229                rtm->rtm_flags |= RTNH_F_OFFLOAD;
 230
 231        mp_attr = nla_nest_start_noflag(skb, RTA_MULTIPATH);
 232        if (!mp_attr)
 233                return -EMSGSIZE;
 234
 235        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
 236                if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
 237                        struct vif_device *vif;
 238
 239                        nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
 240                        if (!nhp) {
 241                                nla_nest_cancel(skb, mp_attr);
 242                                return -EMSGSIZE;
 243                        }
 244
 245                        nhp->rtnh_flags = 0;
 246                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
 247                        vif = &mrt->vif_table[ct];
 248                        nhp->rtnh_ifindex = vif->dev->ifindex;
 249                        nhp->rtnh_len = sizeof(*nhp);
 250                }
 251        }
 252
 253        nla_nest_end(skb, mp_attr);
 254
 255        lastuse = READ_ONCE(c->mfc_un.res.lastuse);
 256        lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
 257
 258        mfcs.mfcs_packets = c->mfc_un.res.pkt;
 259        mfcs.mfcs_bytes = c->mfc_un.res.bytes;
 260        mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
 261        if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
 262            nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
 263                              RTA_PAD))
 264                return -EMSGSIZE;
 265
 266        rtm->rtm_type = RTN_MULTICAST;
 267        return 1;
 268}
 269EXPORT_SYMBOL(mr_fill_mroute);
 270
 271static bool mr_mfc_uses_dev(const struct mr_table *mrt,
 272                            const struct mr_mfc *c,
 273                            const struct net_device *dev)
 274{
 275        int ct;
 276
 277        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
 278                if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
 279                        const struct vif_device *vif;
 280
 281                        vif = &mrt->vif_table[ct];
 282                        if (vif->dev == dev)
 283                                return true;
 284                }
 285        }
 286        return false;
 287}
 288
 289int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
 290                  struct netlink_callback *cb,
 291                  int (*fill)(struct mr_table *mrt, struct sk_buff *skb,
 292                              u32 portid, u32 seq, struct mr_mfc *c,
 293                              int cmd, int flags),
 294                  spinlock_t *lock, struct fib_dump_filter *filter)
 295{
 296        unsigned int e = 0, s_e = cb->args[1];
 297        unsigned int flags = NLM_F_MULTI;
 298        struct mr_mfc *mfc;
 299        int err;
 300
 301        if (filter->filter_set)
 302                flags |= NLM_F_DUMP_FILTERED;
 303
 304        list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
 305                if (e < s_e)
 306                        goto next_entry;
 307                if (filter->dev &&
 308                    !mr_mfc_uses_dev(mrt, mfc, filter->dev))
 309                        goto next_entry;
 310
 311                err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
 312                           cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
 313                if (err < 0)
 314                        goto out;
 315next_entry:
 316                e++;
 317        }
 318
 319        spin_lock_bh(lock);
 320        list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
 321                if (e < s_e)
 322                        goto next_entry2;
 323                if (filter->dev &&
 324                    !mr_mfc_uses_dev(mrt, mfc, filter->dev))
 325                        goto next_entry2;
 326
 327                err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
 328                           cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
 329                if (err < 0) {
 330                        spin_unlock_bh(lock);
 331                        goto out;
 332                }
 333next_entry2:
 334                e++;
 335        }
 336        spin_unlock_bh(lock);
 337        err = 0;
 338out:
 339        cb->args[1] = e;
 340        return err;
 341}
 342EXPORT_SYMBOL(mr_table_dump);
 343
 344int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
 345                     struct mr_table *(*iter)(struct net *net,
 346                                              struct mr_table *mrt),
 347                     int (*fill)(struct mr_table *mrt,
 348                                 struct sk_buff *skb,
 349                                 u32 portid, u32 seq, struct mr_mfc *c,
 350                                 int cmd, int flags),
 351                     spinlock_t *lock, struct fib_dump_filter *filter)
 352{
 353        unsigned int t = 0, s_t = cb->args[0];
 354        struct net *net = sock_net(skb->sk);
 355        struct mr_table *mrt;
 356        int err;
 357
 358        /* multicast does not track protocol or have route type other
 359         * than RTN_MULTICAST
 360         */
 361        if (filter->filter_set) {
 362                if (filter->protocol || filter->flags ||
 363                    (filter->rt_type && filter->rt_type != RTN_MULTICAST))
 364                        return skb->len;
 365        }
 366
 367        rcu_read_lock();
 368        for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
 369                if (t < s_t)
 370                        goto next_table;
 371
 372                err = mr_table_dump(mrt, skb, cb, fill, lock, filter);
 373                if (err < 0)
 374                        break;
 375                cb->args[1] = 0;
 376next_table:
 377                t++;
 378        }
 379        rcu_read_unlock();
 380
 381        cb->args[0] = t;
 382
 383        return skb->len;
 384}
 385EXPORT_SYMBOL(mr_rtm_dumproute);
 386
 387int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
 388            int (*rules_dump)(struct net *net,
 389                              struct notifier_block *nb),
 390            struct mr_table *(*mr_iter)(struct net *net,
 391                                        struct mr_table *mrt),
 392            rwlock_t *mrt_lock)
 393{
 394        struct mr_table *mrt;
 395        int err;
 396
 397        err = rules_dump(net, nb);
 398        if (err)
 399                return err;
 400
 401        for (mrt = mr_iter(net, NULL); mrt; mrt = mr_iter(net, mrt)) {
 402                struct vif_device *v = &mrt->vif_table[0];
 403                struct mr_mfc *mfc;
 404                int vifi;
 405
 406                /* Notifiy on table VIF entries */
 407                read_lock(mrt_lock);
 408                for (vifi = 0; vifi < mrt->maxvif; vifi++, v++) {
 409                        if (!v->dev)
 410                                continue;
 411
 412                        mr_call_vif_notifier(nb, net, family,
 413                                             FIB_EVENT_VIF_ADD,
 414                                             v, vifi, mrt->id);
 415                }
 416                read_unlock(mrt_lock);
 417
 418                /* Notify on table MFC entries */
 419                list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
 420                        mr_call_mfc_notifier(nb, net, family,
 421                                             FIB_EVENT_ENTRY_ADD,
 422                                             mfc, mrt->id);
 423        }
 424
 425        return 0;
 426}
 427EXPORT_SYMBOL(mr_dump);
 428