linux/net/tipc/monitor.c
<<
>>
Prefs
   1/*
   2 * net/tipc/monitor.c
   3 *
   4 * Copyright (c) 2016, Ericsson AB
   5 * All rights reserved.
   6 *
   7 * Redistribution and use in source and binary forms, with or without
   8 * modification, are permitted provided that the following conditions are met:
   9 *
  10 * 1. Redistributions of source code must retain the above copyright
  11 *    notice, this list of conditions and the following disclaimer.
  12 * 2. Redistributions in binary form must reproduce the above copyright
  13 *    notice, this list of conditions and the following disclaimer in the
  14 *    documentation and/or other materials provided with the distribution.
  15 * 3. Neither the names of the copyright holders nor the names of its
  16 *    contributors may be used to endorse or promote products derived from
  17 *    this software without specific prior written permission.
  18 *
  19 * Alternatively, this software may be distributed under the terms of the
  20 * GNU General Public License ("GPL") version 2 as published by the Free
  21 * Software Foundation.
  22 *
  23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33 * POSSIBILITY OF SUCH DAMAGE.
  34 */
  35
  36#include <net/genetlink.h>
  37#include "core.h"
  38#include "addr.h"
  39#include "monitor.h"
  40#include "bearer.h"
  41
  42#define MAX_MON_DOMAIN       64
  43#define MON_TIMEOUT          120000
  44#define MAX_PEER_DOWN_EVENTS 4
  45
  46/* struct tipc_mon_domain: domain record to be transferred between peers
  47 * @len: actual size of domain record
  48 * @gen: current generation of sender's domain
  49 * @ack_gen: most recent generation of self's domain acked by peer
  50 * @member_cnt: number of domain member nodes described in this record
  51 * @up_map: bit map indicating which of the members the sender considers up
  52 * @members: identity of the domain members
  53 */
  54struct tipc_mon_domain {
  55        u16 len;
  56        u16 gen;
  57        u16 ack_gen;
  58        u16 member_cnt;
  59        u64 up_map;
  60        u32 members[MAX_MON_DOMAIN];
  61};
  62
  63/* struct tipc_peer: state of a peer node and its domain
  64 * @addr: tipc node identity of peer
  65 * @head_map: shows which other nodes currently consider peer 'up'
  66 * @domain: most recent domain record from peer
  67 * @hash: position in hashed lookup list
  68 * @list: position in linked list, in circular ascending order by 'addr'
  69 * @applied: number of reported domain members applied on this monitor list
  70 * @is_up: peer is up as seen from this node
  71 * @is_head: peer is assigned domain head as seen from this node
  72 * @is_local: peer is in local domain and should be continuously monitored
  73 * @down_cnt: - numbers of other peers which have reported this on lost
  74 */
  75struct tipc_peer {
  76        u32 addr;
  77        struct tipc_mon_domain *domain;
  78        struct hlist_node hash;
  79        struct list_head list;
  80        u8 applied;
  81        u8 down_cnt;
  82        bool is_up;
  83        bool is_head;
  84        bool is_local;
  85};
  86
  87struct tipc_monitor {
  88        struct hlist_head peers[NODE_HTABLE_SIZE];
  89        int peer_cnt;
  90        struct tipc_peer *self;
  91        rwlock_t lock;
  92        struct tipc_mon_domain cache;
  93        u16 list_gen;
  94        u16 dom_gen;
  95        struct net *net;
  96        struct timer_list timer;
  97        unsigned long timer_intv;
  98};
  99
 100static struct tipc_monitor *tipc_monitor(struct net *net, int bearer_id)
 101{
 102        return tipc_net(net)->monitors[bearer_id];
 103}
 104
 105const int tipc_max_domain_size = sizeof(struct tipc_mon_domain);
 106
 107static inline u16 mon_cpu_to_le16(u16 val)
 108{
 109        return (__force __u16)htons(val);
 110}
 111
 112static inline u32 mon_cpu_to_le32(u32 val)
 113{
 114        return (__force __u32)htonl(val);
 115}
 116
 117static inline u64 mon_cpu_to_le64(u64 val)
 118{
 119        return (__force __u64)cpu_to_be64(val);
 120}
 121
 122static inline u16 mon_le16_to_cpu(u16 val)
 123{
 124        return ntohs((__force __be16)val);
 125}
 126
 127static inline u32 mon_le32_to_cpu(u32 val)
 128{
 129        return ntohl((__force __be32)val);
 130}
 131
 132static inline u64 mon_le64_to_cpu(u64 val)
 133{
 134        return be64_to_cpu((__force __be64)val);
 135}
 136
 137/* dom_rec_len(): actual length of domain record for transport
 138 */
 139static int dom_rec_len(struct tipc_mon_domain *dom, u16 mcnt)
 140{
 141        return (offsetof(struct tipc_mon_domain, members)) + (mcnt * sizeof(u32));
 142}
 143
 144/* dom_size() : calculate size of own domain based on number of peers
 145 */
 146static int dom_size(int peers)
 147{
 148        int i = 0;
 149
 150        while ((i * i) < peers)
 151                i++;
 152        return i < MAX_MON_DOMAIN ? i : MAX_MON_DOMAIN;
 153}
 154
 155static void map_set(u64 *up_map, int i, unsigned int v)
 156{
 157        *up_map &= ~(1ULL << i);
 158        *up_map |= ((u64)v << i);
 159}
 160
 161static int map_get(u64 up_map, int i)
 162{
 163        return (up_map & (1 << i)) >> i;
 164}
 165
 166static struct tipc_peer *peer_prev(struct tipc_peer *peer)
 167{
 168        return list_last_entry(&peer->list, struct tipc_peer, list);
 169}
 170
 171static struct tipc_peer *peer_nxt(struct tipc_peer *peer)
 172{
 173        return list_first_entry(&peer->list, struct tipc_peer, list);
 174}
 175
 176static struct tipc_peer *peer_head(struct tipc_peer *peer)
 177{
 178        while (!peer->is_head)
 179                peer = peer_prev(peer);
 180        return peer;
 181}
 182
 183static struct tipc_peer *get_peer(struct tipc_monitor *mon, u32 addr)
 184{
 185        struct tipc_peer *peer;
 186        unsigned int thash = tipc_hashfn(addr);
 187
 188        hlist_for_each_entry(peer, &mon->peers[thash], hash) {
 189                if (peer->addr == addr)
 190                        return peer;
 191        }
 192        return NULL;
 193}
 194
 195static struct tipc_peer *get_self(struct net *net, int bearer_id)
 196{
 197        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 198
 199        return mon->self;
 200}
 201
 202static inline bool tipc_mon_is_active(struct net *net, struct tipc_monitor *mon)
 203{
 204        struct tipc_net *tn = tipc_net(net);
 205
 206        return mon->peer_cnt > tn->mon_threshold;
 207}
 208
 209/* mon_identify_lost_members() : - identify amd mark potentially lost members
 210 */
 211static void mon_identify_lost_members(struct tipc_peer *peer,
 212                                      struct tipc_mon_domain *dom_bef,
 213                                      int applied_bef)
 214{
 215        struct tipc_peer *member = peer;
 216        struct tipc_mon_domain *dom_aft = peer->domain;
 217        int applied_aft = peer->applied;
 218        int i;
 219
 220        for (i = 0; i < applied_bef; i++) {
 221                member = peer_nxt(member);
 222
 223                /* Do nothing if self or peer already see member as down */
 224                if (!member->is_up || !map_get(dom_bef->up_map, i))
 225                        continue;
 226
 227                /* Loss of local node must be detected by active probing */
 228                if (member->is_local)
 229                        continue;
 230
 231                /* Start probing if member was removed from applied domain */
 232                if (!applied_aft || (applied_aft < i)) {
 233                        member->down_cnt = 1;
 234                        continue;
 235                }
 236
 237                /* Member loss is confirmed if it is still in applied domain */
 238                if (!map_get(dom_aft->up_map, i))
 239                        member->down_cnt++;
 240        }
 241}
 242
 243/* mon_apply_domain() : match a peer's domain record against monitor list
 244 */
 245static void mon_apply_domain(struct tipc_monitor *mon,
 246                             struct tipc_peer *peer)
 247{
 248        struct tipc_mon_domain *dom = peer->domain;
 249        struct tipc_peer *member;
 250        u32 addr;
 251        int i;
 252
 253        if (!dom || !peer->is_up)
 254                return;
 255
 256        /* Scan across domain members and match against monitor list */
 257        peer->applied = 0;
 258        member = peer_nxt(peer);
 259        for (i = 0; i < dom->member_cnt; i++) {
 260                addr = dom->members[i];
 261                if (addr != member->addr)
 262                        return;
 263                peer->applied++;
 264                member = peer_nxt(member);
 265        }
 266}
 267
 268/* mon_update_local_domain() : update after peer addition/removal/up/down
 269 */
 270static void mon_update_local_domain(struct tipc_monitor *mon)
 271{
 272        struct tipc_peer *self = mon->self;
 273        struct tipc_mon_domain *cache = &mon->cache;
 274        struct tipc_mon_domain *dom = self->domain;
 275        struct tipc_peer *peer = self;
 276        u64 prev_up_map = dom->up_map;
 277        u16 member_cnt, i;
 278        bool diff;
 279
 280        /* Update local domain size based on current size of cluster */
 281        member_cnt = dom_size(mon->peer_cnt) - 1;
 282        self->applied = member_cnt;
 283
 284        /* Update native and cached outgoing local domain records */
 285        dom->len = dom_rec_len(dom, member_cnt);
 286        diff = dom->member_cnt != member_cnt;
 287        dom->member_cnt = member_cnt;
 288        for (i = 0; i < member_cnt; i++) {
 289                peer = peer_nxt(peer);
 290                diff |= dom->members[i] != peer->addr;
 291                dom->members[i] = peer->addr;
 292                map_set(&dom->up_map, i, peer->is_up);
 293                cache->members[i] = mon_cpu_to_le32(peer->addr);
 294        }
 295        diff |= dom->up_map != prev_up_map;
 296        if (!diff)
 297                return;
 298        dom->gen = ++mon->dom_gen;
 299        cache->len = mon_cpu_to_le16(dom->len);
 300        cache->gen = mon_cpu_to_le16(dom->gen);
 301        cache->member_cnt = mon_cpu_to_le16(member_cnt);
 302        cache->up_map = mon_cpu_to_le64(dom->up_map);
 303        mon_apply_domain(mon, self);
 304}
 305
 306/* mon_update_neighbors() : update preceding neighbors of added/removed peer
 307 */
 308static void mon_update_neighbors(struct tipc_monitor *mon,
 309                                 struct tipc_peer *peer)
 310{
 311        int dz, i;
 312
 313        dz = dom_size(mon->peer_cnt);
 314        for (i = 0; i < dz; i++) {
 315                mon_apply_domain(mon, peer);
 316                peer = peer_prev(peer);
 317        }
 318}
 319
 320/* mon_assign_roles() : reassign peer roles after a network change
 321 * The monitor list is consistent at this stage; i.e., each peer is monitoring
 322 * a set of domain members as matched between domain record and the monitor list
 323 */
 324static void mon_assign_roles(struct tipc_monitor *mon, struct tipc_peer *head)
 325{
 326        struct tipc_peer *peer = peer_nxt(head);
 327        struct tipc_peer *self = mon->self;
 328        int i = 0;
 329
 330        for (; peer != self; peer = peer_nxt(peer)) {
 331                peer->is_local = false;
 332
 333                /* Update domain member */
 334                if (i++ < head->applied) {
 335                        peer->is_head = false;
 336                        if (head == self)
 337                                peer->is_local = true;
 338                        continue;
 339                }
 340                /* Assign next domain head */
 341                if (!peer->is_up)
 342                        continue;
 343                if (peer->is_head)
 344                        break;
 345                head = peer;
 346                head->is_head = true;
 347                i = 0;
 348        }
 349        mon->list_gen++;
 350}
 351
 352void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id)
 353{
 354        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 355        struct tipc_peer *self;
 356        struct tipc_peer *peer, *prev, *head;
 357
 358        if (!mon)
 359                return;
 360
 361        self = get_self(net, bearer_id);
 362        write_lock_bh(&mon->lock);
 363        peer = get_peer(mon, addr);
 364        if (!peer)
 365                goto exit;
 366        prev = peer_prev(peer);
 367        list_del(&peer->list);
 368        hlist_del(&peer->hash);
 369        kfree(peer->domain);
 370        kfree(peer);
 371        mon->peer_cnt--;
 372        head = peer_head(prev);
 373        if (head == self)
 374                mon_update_local_domain(mon);
 375        mon_update_neighbors(mon, prev);
 376
 377        /* Revert to full-mesh monitoring if we reach threshold */
 378        if (!tipc_mon_is_active(net, mon)) {
 379                list_for_each_entry(peer, &self->list, list) {
 380                        kfree(peer->domain);
 381                        peer->domain = NULL;
 382                        peer->applied = 0;
 383                }
 384        }
 385        mon_assign_roles(mon, head);
 386exit:
 387        write_unlock_bh(&mon->lock);
 388}
 389
 390static bool tipc_mon_add_peer(struct tipc_monitor *mon, u32 addr,
 391                              struct tipc_peer **peer)
 392{
 393        struct tipc_peer *self = mon->self;
 394        struct tipc_peer *cur, *prev, *p;
 395
 396        p = kzalloc(sizeof(*p), GFP_ATOMIC);
 397        *peer = p;
 398        if (!p)
 399                return false;
 400        p->addr = addr;
 401
 402        /* Add new peer to lookup list */
 403        INIT_LIST_HEAD(&p->list);
 404        hlist_add_head(&p->hash, &mon->peers[tipc_hashfn(addr)]);
 405
 406        /* Sort new peer into iterator list, in ascending circular order */
 407        prev = self;
 408        list_for_each_entry(cur, &self->list, list) {
 409                if ((addr > prev->addr) && (addr < cur->addr))
 410                        break;
 411                if (((addr < cur->addr) || (addr > prev->addr)) &&
 412                    (prev->addr > cur->addr))
 413                        break;
 414                prev = cur;
 415        }
 416        list_add_tail(&p->list, &cur->list);
 417        mon->peer_cnt++;
 418        mon_update_neighbors(mon, p);
 419        return true;
 420}
 421
 422void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id)
 423{
 424        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 425        struct tipc_peer *self = get_self(net, bearer_id);
 426        struct tipc_peer *peer, *head;
 427
 428        write_lock_bh(&mon->lock);
 429        peer = get_peer(mon, addr);
 430        if (!peer && !tipc_mon_add_peer(mon, addr, &peer))
 431                goto exit;
 432        peer->is_up = true;
 433        head = peer_head(peer);
 434        if (head == self)
 435                mon_update_local_domain(mon);
 436        mon_assign_roles(mon, head);
 437exit:
 438        write_unlock_bh(&mon->lock);
 439}
 440
 441void tipc_mon_peer_down(struct net *net, u32 addr, int bearer_id)
 442{
 443        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 444        struct tipc_peer *self;
 445        struct tipc_peer *peer, *head;
 446        struct tipc_mon_domain *dom;
 447        int applied;
 448
 449        if (!mon)
 450                return;
 451
 452        self = get_self(net, bearer_id);
 453        write_lock_bh(&mon->lock);
 454        peer = get_peer(mon, addr);
 455        if (!peer) {
 456                pr_warn("Mon: unknown link %x/%u DOWN\n", addr, bearer_id);
 457                goto exit;
 458        }
 459        applied = peer->applied;
 460        peer->applied = 0;
 461        dom = peer->domain;
 462        peer->domain = NULL;
 463        if (peer->is_head)
 464                mon_identify_lost_members(peer, dom, applied);
 465        kfree(dom);
 466        peer->is_up = false;
 467        peer->is_head = false;
 468        peer->is_local = false;
 469        peer->down_cnt = 0;
 470        head = peer_head(peer);
 471        if (head == self)
 472                mon_update_local_domain(mon);
 473        mon_assign_roles(mon, head);
 474exit:
 475        write_unlock_bh(&mon->lock);
 476}
 477
 478/* tipc_mon_rcv - process monitor domain event message
 479 */
 480void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
 481                  struct tipc_mon_state *state, int bearer_id)
 482{
 483        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 484        struct tipc_mon_domain *arrv_dom = data;
 485        struct tipc_mon_domain dom_bef;
 486        struct tipc_mon_domain *dom;
 487        struct tipc_peer *peer;
 488        u16 new_member_cnt = mon_le16_to_cpu(arrv_dom->member_cnt);
 489        int new_dlen = dom_rec_len(arrv_dom, new_member_cnt);
 490        u16 new_gen = mon_le16_to_cpu(arrv_dom->gen);
 491        u16 acked_gen = mon_le16_to_cpu(arrv_dom->ack_gen);
 492        u16 arrv_dlen = mon_le16_to_cpu(arrv_dom->len);
 493        bool probing = state->probing;
 494        int i, applied_bef;
 495
 496        state->probing = false;
 497
 498        /* Sanity check received domain record */
 499        if (dlen < dom_rec_len(arrv_dom, 0))
 500                return;
 501        if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
 502                return;
 503        if (dlen < new_dlen || arrv_dlen != new_dlen)
 504                return;
 505
 506        /* Synch generation numbers with peer if link just came up */
 507        if (!state->synched) {
 508                state->peer_gen = new_gen - 1;
 509                state->acked_gen = acked_gen;
 510                state->synched = true;
 511        }
 512
 513        if (more(acked_gen, state->acked_gen))
 514                state->acked_gen = acked_gen;
 515
 516        /* Drop duplicate unless we are waiting for a probe response */
 517        if (!more(new_gen, state->peer_gen) && !probing)
 518                return;
 519
 520        write_lock_bh(&mon->lock);
 521        peer = get_peer(mon, addr);
 522        if (!peer || !peer->is_up)
 523                goto exit;
 524
 525        /* Peer is confirmed, stop any ongoing probing */
 526        peer->down_cnt = 0;
 527
 528        /* Task is done for duplicate record */
 529        if (!more(new_gen, state->peer_gen))
 530                goto exit;
 531
 532        state->peer_gen = new_gen;
 533
 534        /* Cache current domain record for later use */
 535        dom_bef.member_cnt = 0;
 536        dom = peer->domain;
 537        if (dom)
 538                memcpy(&dom_bef, dom, dom->len);
 539
 540        /* Transform and store received domain record */
 541        if (!dom || (dom->len < new_dlen)) {
 542                kfree(dom);
 543                dom = kmalloc(new_dlen, GFP_ATOMIC);
 544                peer->domain = dom;
 545                if (!dom)
 546                        goto exit;
 547        }
 548        dom->len = new_dlen;
 549        dom->gen = new_gen;
 550        dom->member_cnt = new_member_cnt;
 551        dom->up_map = mon_le64_to_cpu(arrv_dom->up_map);
 552        for (i = 0; i < new_member_cnt; i++)
 553                dom->members[i] = mon_le32_to_cpu(arrv_dom->members[i]);
 554
 555        /* Update peers affected by this domain record */
 556        applied_bef = peer->applied;
 557        mon_apply_domain(mon, peer);
 558        mon_identify_lost_members(peer, &dom_bef, applied_bef);
 559        mon_assign_roles(mon, peer_head(peer));
 560exit:
 561        write_unlock_bh(&mon->lock);
 562}
 563
 564void tipc_mon_prep(struct net *net, void *data, int *dlen,
 565                   struct tipc_mon_state *state, int bearer_id)
 566{
 567        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 568        struct tipc_mon_domain *dom = data;
 569        u16 gen = mon->dom_gen;
 570        u16 len;
 571
 572        /* Send invalid record if not active */
 573        if (!tipc_mon_is_active(net, mon)) {
 574                dom->len = 0;
 575                return;
 576        }
 577
 578        /* Send only a dummy record with ack if peer has acked our last sent */
 579        if (likely(state->acked_gen == gen)) {
 580                len = dom_rec_len(dom, 0);
 581                *dlen = len;
 582                dom->len = mon_cpu_to_le16(len);
 583                dom->gen = mon_cpu_to_le16(gen);
 584                dom->ack_gen = mon_cpu_to_le16(state->peer_gen);
 585                dom->member_cnt = 0;
 586                return;
 587        }
 588        /* Send the full record */
 589        read_lock_bh(&mon->lock);
 590        len = mon_le16_to_cpu(mon->cache.len);
 591        *dlen = len;
 592        memcpy(data, &mon->cache, len);
 593        read_unlock_bh(&mon->lock);
 594        dom->ack_gen = mon_cpu_to_le16(state->peer_gen);
 595}
 596
 597void tipc_mon_get_state(struct net *net, u32 addr,
 598                        struct tipc_mon_state *state,
 599                        int bearer_id)
 600{
 601        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 602        struct tipc_peer *peer;
 603
 604        if (!tipc_mon_is_active(net, mon)) {
 605                state->probing = false;
 606                state->monitoring = true;
 607                return;
 608        }
 609
 610        /* Used cached state if table has not changed */
 611        if (!state->probing &&
 612            (state->list_gen == mon->list_gen) &&
 613            (state->acked_gen == mon->dom_gen))
 614                return;
 615
 616        read_lock_bh(&mon->lock);
 617        peer = get_peer(mon, addr);
 618        if (peer) {
 619                state->probing = state->acked_gen != mon->dom_gen;
 620                state->probing |= peer->down_cnt;
 621                state->reset |= peer->down_cnt >= MAX_PEER_DOWN_EVENTS;
 622                state->monitoring = peer->is_local;
 623                state->monitoring |= peer->is_head;
 624                state->list_gen = mon->list_gen;
 625        }
 626        read_unlock_bh(&mon->lock);
 627}
 628
 629static void mon_timeout(struct timer_list *t)
 630{
 631        struct tipc_monitor *mon = from_timer(mon, t, timer);
 632        struct tipc_peer *self;
 633        int best_member_cnt = dom_size(mon->peer_cnt) - 1;
 634
 635        write_lock_bh(&mon->lock);
 636        self = mon->self;
 637        if (self && (best_member_cnt != self->applied)) {
 638                mon_update_local_domain(mon);
 639                mon_assign_roles(mon, self);
 640        }
 641        write_unlock_bh(&mon->lock);
 642        mod_timer(&mon->timer, jiffies + mon->timer_intv);
 643}
 644
 645int tipc_mon_create(struct net *net, int bearer_id)
 646{
 647        struct tipc_net *tn = tipc_net(net);
 648        struct tipc_monitor *mon;
 649        struct tipc_peer *self;
 650        struct tipc_mon_domain *dom;
 651
 652        if (tn->monitors[bearer_id])
 653                return 0;
 654
 655        mon = kzalloc(sizeof(*mon), GFP_ATOMIC);
 656        self = kzalloc(sizeof(*self), GFP_ATOMIC);
 657        dom = kzalloc(sizeof(*dom), GFP_ATOMIC);
 658        if (!mon || !self || !dom) {
 659                kfree(mon);
 660                kfree(self);
 661                kfree(dom);
 662                return -ENOMEM;
 663        }
 664        tn->monitors[bearer_id] = mon;
 665        rwlock_init(&mon->lock);
 666        mon->net = net;
 667        mon->peer_cnt = 1;
 668        mon->self = self;
 669        self->domain = dom;
 670        self->addr = tipc_own_addr(net);
 671        self->is_up = true;
 672        self->is_head = true;
 673        INIT_LIST_HEAD(&self->list);
 674        timer_setup(&mon->timer, mon_timeout, 0);
 675        mon->timer_intv = msecs_to_jiffies(MON_TIMEOUT + (tn->random & 0xffff));
 676        mod_timer(&mon->timer, jiffies + mon->timer_intv);
 677        return 0;
 678}
 679
 680void tipc_mon_delete(struct net *net, int bearer_id)
 681{
 682        struct tipc_net *tn = tipc_net(net);
 683        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 684        struct tipc_peer *self;
 685        struct tipc_peer *peer, *tmp;
 686
 687        if (!mon)
 688                return;
 689
 690        self = get_self(net, bearer_id);
 691        write_lock_bh(&mon->lock);
 692        tn->monitors[bearer_id] = NULL;
 693        list_for_each_entry_safe(peer, tmp, &self->list, list) {
 694                list_del(&peer->list);
 695                hlist_del(&peer->hash);
 696                kfree(peer->domain);
 697                kfree(peer);
 698        }
 699        mon->self = NULL;
 700        write_unlock_bh(&mon->lock);
 701        del_timer_sync(&mon->timer);
 702        kfree(self->domain);
 703        kfree(self);
 704        kfree(mon);
 705}
 706
 707void tipc_mon_reinit_self(struct net *net)
 708{
 709        struct tipc_monitor *mon;
 710        int bearer_id;
 711
 712        for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
 713                mon = tipc_monitor(net, bearer_id);
 714                if (!mon)
 715                        continue;
 716                write_lock_bh(&mon->lock);
 717                mon->self->addr = tipc_own_addr(net);
 718                write_unlock_bh(&mon->lock);
 719        }
 720}
 721
 722int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size)
 723{
 724        struct tipc_net *tn = tipc_net(net);
 725
 726        if (cluster_size > TIPC_CLUSTER_SIZE)
 727                return -EINVAL;
 728
 729        tn->mon_threshold = cluster_size;
 730
 731        return 0;
 732}
 733
 734int tipc_nl_monitor_get_threshold(struct net *net)
 735{
 736        struct tipc_net *tn = tipc_net(net);
 737
 738        return tn->mon_threshold;
 739}
 740
 741static int __tipc_nl_add_monitor_peer(struct tipc_peer *peer,
 742                                      struct tipc_nl_msg *msg)
 743{
 744        struct tipc_mon_domain *dom = peer->domain;
 745        struct nlattr *attrs;
 746        void *hdr;
 747
 748        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 749                          NLM_F_MULTI, TIPC_NL_MON_PEER_GET);
 750        if (!hdr)
 751                return -EMSGSIZE;
 752
 753        attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON_PEER);
 754        if (!attrs)
 755                goto msg_full;
 756
 757        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_ADDR, peer->addr))
 758                goto attr_msg_full;
 759        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_APPLIED, peer->applied))
 760                goto attr_msg_full;
 761
 762        if (peer->is_up)
 763                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_UP))
 764                        goto attr_msg_full;
 765        if (peer->is_local)
 766                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_LOCAL))
 767                        goto attr_msg_full;
 768        if (peer->is_head)
 769                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_HEAD))
 770                        goto attr_msg_full;
 771
 772        if (dom) {
 773                if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_DOMGEN, dom->gen))
 774                        goto attr_msg_full;
 775                if (nla_put_u64_64bit(msg->skb, TIPC_NLA_MON_PEER_UPMAP,
 776                                      dom->up_map, TIPC_NLA_MON_PEER_PAD))
 777                        goto attr_msg_full;
 778                if (nla_put(msg->skb, TIPC_NLA_MON_PEER_MEMBERS,
 779                            dom->member_cnt * sizeof(u32), &dom->members))
 780                        goto attr_msg_full;
 781        }
 782
 783        nla_nest_end(msg->skb, attrs);
 784        genlmsg_end(msg->skb, hdr);
 785        return 0;
 786
 787attr_msg_full:
 788        nla_nest_cancel(msg->skb, attrs);
 789msg_full:
 790        genlmsg_cancel(msg->skb, hdr);
 791
 792        return -EMSGSIZE;
 793}
 794
 795int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
 796                             u32 bearer_id, u32 *prev_node)
 797{
 798        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 799        struct tipc_peer *peer;
 800
 801        if (!mon)
 802                return -EINVAL;
 803
 804        read_lock_bh(&mon->lock);
 805        peer = mon->self;
 806        do {
 807                if (*prev_node) {
 808                        if (peer->addr == *prev_node)
 809                                *prev_node = 0;
 810                        else
 811                                continue;
 812                }
 813                if (__tipc_nl_add_monitor_peer(peer, msg)) {
 814                        *prev_node = peer->addr;
 815                        read_unlock_bh(&mon->lock);
 816                        return -EMSGSIZE;
 817                }
 818        } while ((peer = peer_nxt(peer)) != mon->self);
 819        read_unlock_bh(&mon->lock);
 820
 821        return 0;
 822}
 823
 824int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
 825                          u32 bearer_id)
 826{
 827        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 828        char bearer_name[TIPC_MAX_BEARER_NAME];
 829        struct nlattr *attrs;
 830        void *hdr;
 831        int ret;
 832
 833        ret = tipc_bearer_get_name(net, bearer_name, bearer_id);
 834        if (ret || !mon)
 835                return 0;
 836
 837        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 838                          NLM_F_MULTI, TIPC_NL_MON_GET);
 839        if (!hdr)
 840                return -EMSGSIZE;
 841
 842        attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON);
 843        if (!attrs)
 844                goto msg_full;
 845
 846        read_lock_bh(&mon->lock);
 847        if (nla_put_u32(msg->skb, TIPC_NLA_MON_REF, bearer_id))
 848                goto attr_msg_full;
 849        if (tipc_mon_is_active(net, mon))
 850                if (nla_put_flag(msg->skb, TIPC_NLA_MON_ACTIVE))
 851                        goto attr_msg_full;
 852        if (nla_put_string(msg->skb, TIPC_NLA_MON_BEARER_NAME, bearer_name))
 853                goto attr_msg_full;
 854        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEERCNT, mon->peer_cnt))
 855                goto attr_msg_full;
 856        if (nla_put_u32(msg->skb, TIPC_NLA_MON_LISTGEN, mon->list_gen))
 857                goto attr_msg_full;
 858
 859        read_unlock_bh(&mon->lock);
 860        nla_nest_end(msg->skb, attrs);
 861        genlmsg_end(msg->skb, hdr);
 862
 863        return 0;
 864
 865attr_msg_full:
 866        read_unlock_bh(&mon->lock);
 867        nla_nest_cancel(msg->skb, attrs);
 868msg_full:
 869        genlmsg_cancel(msg->skb, hdr);
 870
 871        return -EMSGSIZE;
 872}
 873