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
 107/* dom_rec_len(): actual length of domain record for transport
 108 */
 109static int dom_rec_len(struct tipc_mon_domain *dom, u16 mcnt)
 110{
 111        return ((void *)&dom->members - (void *)dom) + (mcnt * sizeof(u32));
 112}
 113
 114/* dom_size() : calculate size of own domain based on number of peers
 115 */
 116static int dom_size(int peers)
 117{
 118        int i = 0;
 119
 120        while ((i * i) < peers)
 121                i++;
 122        return i < MAX_MON_DOMAIN ? i : MAX_MON_DOMAIN;
 123}
 124
 125static void map_set(u64 *up_map, int i, unsigned int v)
 126{
 127        *up_map &= ~(1ULL << i);
 128        *up_map |= ((u64)v << i);
 129}
 130
 131static int map_get(u64 up_map, int i)
 132{
 133        return (up_map & (1 << i)) >> i;
 134}
 135
 136static struct tipc_peer *peer_prev(struct tipc_peer *peer)
 137{
 138        return list_last_entry(&peer->list, struct tipc_peer, list);
 139}
 140
 141static struct tipc_peer *peer_nxt(struct tipc_peer *peer)
 142{
 143        return list_first_entry(&peer->list, struct tipc_peer, list);
 144}
 145
 146static struct tipc_peer *peer_head(struct tipc_peer *peer)
 147{
 148        while (!peer->is_head)
 149                peer = peer_prev(peer);
 150        return peer;
 151}
 152
 153static struct tipc_peer *get_peer(struct tipc_monitor *mon, u32 addr)
 154{
 155        struct tipc_peer *peer;
 156        unsigned int thash = tipc_hashfn(addr);
 157
 158        hlist_for_each_entry(peer, &mon->peers[thash], hash) {
 159                if (peer->addr == addr)
 160                        return peer;
 161        }
 162        return NULL;
 163}
 164
 165static struct tipc_peer *get_self(struct net *net, int bearer_id)
 166{
 167        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 168
 169        return mon->self;
 170}
 171
 172static inline bool tipc_mon_is_active(struct net *net, struct tipc_monitor *mon)
 173{
 174        struct tipc_net *tn = tipc_net(net);
 175
 176        return mon->peer_cnt > tn->mon_threshold;
 177}
 178
 179/* mon_identify_lost_members() : - identify amd mark potentially lost members
 180 */
 181static void mon_identify_lost_members(struct tipc_peer *peer,
 182                                      struct tipc_mon_domain *dom_bef,
 183                                      int applied_bef)
 184{
 185        struct tipc_peer *member = peer;
 186        struct tipc_mon_domain *dom_aft = peer->domain;
 187        int applied_aft = peer->applied;
 188        int i;
 189
 190        for (i = 0; i < applied_bef; i++) {
 191                member = peer_nxt(member);
 192
 193                /* Do nothing if self or peer already see member as down */
 194                if (!member->is_up || !map_get(dom_bef->up_map, i))
 195                        continue;
 196
 197                /* Loss of local node must be detected by active probing */
 198                if (member->is_local)
 199                        continue;
 200
 201                /* Start probing if member was removed from applied domain */
 202                if (!applied_aft || (applied_aft < i)) {
 203                        member->down_cnt = 1;
 204                        continue;
 205                }
 206
 207                /* Member loss is confirmed if it is still in applied domain */
 208                if (!map_get(dom_aft->up_map, i))
 209                        member->down_cnt++;
 210        }
 211}
 212
 213/* mon_apply_domain() : match a peer's domain record against monitor list
 214 */
 215static void mon_apply_domain(struct tipc_monitor *mon,
 216                             struct tipc_peer *peer)
 217{
 218        struct tipc_mon_domain *dom = peer->domain;
 219        struct tipc_peer *member;
 220        u32 addr;
 221        int i;
 222
 223        if (!dom || !peer->is_up)
 224                return;
 225
 226        /* Scan across domain members and match against monitor list */
 227        peer->applied = 0;
 228        member = peer_nxt(peer);
 229        for (i = 0; i < dom->member_cnt; i++) {
 230                addr = dom->members[i];
 231                if (addr != member->addr)
 232                        return;
 233                peer->applied++;
 234                member = peer_nxt(member);
 235        }
 236}
 237
 238/* mon_update_local_domain() : update after peer addition/removal/up/down
 239 */
 240static void mon_update_local_domain(struct tipc_monitor *mon)
 241{
 242        struct tipc_peer *self = mon->self;
 243        struct tipc_mon_domain *cache = &mon->cache;
 244        struct tipc_mon_domain *dom = self->domain;
 245        struct tipc_peer *peer = self;
 246        u64 prev_up_map = dom->up_map;
 247        u16 member_cnt, i;
 248        bool diff;
 249
 250        /* Update local domain size based on current size of cluster */
 251        member_cnt = dom_size(mon->peer_cnt) - 1;
 252        self->applied = member_cnt;
 253
 254        /* Update native and cached outgoing local domain records */
 255        dom->len = dom_rec_len(dom, member_cnt);
 256        diff = dom->member_cnt != member_cnt;
 257        dom->member_cnt = member_cnt;
 258        for (i = 0; i < member_cnt; i++) {
 259                peer = peer_nxt(peer);
 260                diff |= dom->members[i] != peer->addr;
 261                dom->members[i] = peer->addr;
 262                map_set(&dom->up_map, i, peer->is_up);
 263                cache->members[i] = htonl(peer->addr);
 264        }
 265        diff |= dom->up_map != prev_up_map;
 266        if (!diff)
 267                return;
 268        dom->gen = ++mon->dom_gen;
 269        cache->len = htons(dom->len);
 270        cache->gen = htons(dom->gen);
 271        cache->member_cnt = htons(member_cnt);
 272        cache->up_map = cpu_to_be64(dom->up_map);
 273        mon_apply_domain(mon, self);
 274}
 275
 276/* mon_update_neighbors() : update preceding neighbors of added/removed peer
 277 */
 278static void mon_update_neighbors(struct tipc_monitor *mon,
 279                                 struct tipc_peer *peer)
 280{
 281        int dz, i;
 282
 283        dz = dom_size(mon->peer_cnt);
 284        for (i = 0; i < dz; i++) {
 285                mon_apply_domain(mon, peer);
 286                peer = peer_prev(peer);
 287        }
 288}
 289
 290/* mon_assign_roles() : reassign peer roles after a network change
 291 * The monitor list is consistent at this stage; i.e., each peer is monitoring
 292 * a set of domain members as matched between domain record and the monitor list
 293 */
 294static void mon_assign_roles(struct tipc_monitor *mon, struct tipc_peer *head)
 295{
 296        struct tipc_peer *peer = peer_nxt(head);
 297        struct tipc_peer *self = mon->self;
 298        int i = 0;
 299
 300        for (; peer != self; peer = peer_nxt(peer)) {
 301                peer->is_local = false;
 302
 303                /* Update domain member */
 304                if (i++ < head->applied) {
 305                        peer->is_head = false;
 306                        if (head == self)
 307                                peer->is_local = true;
 308                        continue;
 309                }
 310                /* Assign next domain head */
 311                if (!peer->is_up)
 312                        continue;
 313                if (peer->is_head)
 314                        break;
 315                head = peer;
 316                head->is_head = true;
 317                i = 0;
 318        }
 319        mon->list_gen++;
 320}
 321
 322void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id)
 323{
 324        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 325        struct tipc_peer *self = get_self(net, bearer_id);
 326        struct tipc_peer *peer, *prev, *head;
 327
 328        write_lock_bh(&mon->lock);
 329        peer = get_peer(mon, addr);
 330        if (!peer)
 331                goto exit;
 332        prev = peer_prev(peer);
 333        list_del(&peer->list);
 334        hlist_del(&peer->hash);
 335        kfree(peer->domain);
 336        kfree(peer);
 337        mon->peer_cnt--;
 338        head = peer_head(prev);
 339        if (head == self)
 340                mon_update_local_domain(mon);
 341        mon_update_neighbors(mon, prev);
 342
 343        /* Revert to full-mesh monitoring if we reach threshold */
 344        if (!tipc_mon_is_active(net, mon)) {
 345                list_for_each_entry(peer, &self->list, list) {
 346                        kfree(peer->domain);
 347                        peer->domain = NULL;
 348                        peer->applied = 0;
 349                }
 350        }
 351        mon_assign_roles(mon, head);
 352exit:
 353        write_unlock_bh(&mon->lock);
 354}
 355
 356static bool tipc_mon_add_peer(struct tipc_monitor *mon, u32 addr,
 357                              struct tipc_peer **peer)
 358{
 359        struct tipc_peer *self = mon->self;
 360        struct tipc_peer *cur, *prev, *p;
 361
 362        p = kzalloc(sizeof(*p), GFP_ATOMIC);
 363        *peer = p;
 364        if (!p)
 365                return false;
 366        p->addr = addr;
 367
 368        /* Add new peer to lookup list */
 369        INIT_LIST_HEAD(&p->list);
 370        hlist_add_head(&p->hash, &mon->peers[tipc_hashfn(addr)]);
 371
 372        /* Sort new peer into iterator list, in ascending circular order */
 373        prev = self;
 374        list_for_each_entry(cur, &self->list, list) {
 375                if ((addr > prev->addr) && (addr < cur->addr))
 376                        break;
 377                if (((addr < cur->addr) || (addr > prev->addr)) &&
 378                    (prev->addr > cur->addr))
 379                        break;
 380                prev = cur;
 381        }
 382        list_add_tail(&p->list, &cur->list);
 383        mon->peer_cnt++;
 384        mon_update_neighbors(mon, p);
 385        return true;
 386}
 387
 388void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id)
 389{
 390        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 391        struct tipc_peer *self = get_self(net, bearer_id);
 392        struct tipc_peer *peer, *head;
 393
 394        write_lock_bh(&mon->lock);
 395        peer = get_peer(mon, addr);
 396        if (!peer && !tipc_mon_add_peer(mon, addr, &peer))
 397                goto exit;
 398        peer->is_up = true;
 399        head = peer_head(peer);
 400        if (head == self)
 401                mon_update_local_domain(mon);
 402        mon_assign_roles(mon, head);
 403exit:
 404        write_unlock_bh(&mon->lock);
 405}
 406
 407void tipc_mon_peer_down(struct net *net, u32 addr, int bearer_id)
 408{
 409        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 410        struct tipc_peer *self = get_self(net, bearer_id);
 411        struct tipc_peer *peer, *head;
 412        struct tipc_mon_domain *dom;
 413        int applied;
 414
 415        write_lock_bh(&mon->lock);
 416        peer = get_peer(mon, addr);
 417        if (!peer) {
 418                pr_warn("Mon: unknown link %x/%u DOWN\n", addr, bearer_id);
 419                goto exit;
 420        }
 421        applied = peer->applied;
 422        peer->applied = 0;
 423        dom = peer->domain;
 424        peer->domain = NULL;
 425        if (peer->is_head)
 426                mon_identify_lost_members(peer, dom, applied);
 427        kfree(dom);
 428        peer->is_up = false;
 429        peer->is_head = false;
 430        peer->is_local = false;
 431        peer->down_cnt = 0;
 432        head = peer_head(peer);
 433        if (head == self)
 434                mon_update_local_domain(mon);
 435        mon_assign_roles(mon, head);
 436exit:
 437        write_unlock_bh(&mon->lock);
 438}
 439
 440/* tipc_mon_rcv - process monitor domain event message
 441 */
 442void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
 443                  struct tipc_mon_state *state, int bearer_id)
 444{
 445        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 446        struct tipc_mon_domain *arrv_dom = data;
 447        struct tipc_mon_domain dom_bef;
 448        struct tipc_mon_domain *dom;
 449        struct tipc_peer *peer;
 450        u16 new_member_cnt = ntohs(arrv_dom->member_cnt);
 451        int new_dlen = dom_rec_len(arrv_dom, new_member_cnt);
 452        u16 new_gen = ntohs(arrv_dom->gen);
 453        u16 acked_gen = ntohs(arrv_dom->ack_gen);
 454        bool probing = state->probing;
 455        int i, applied_bef;
 456
 457        state->probing = false;
 458
 459        /* Sanity check received domain record */
 460        if (dlen < dom_rec_len(arrv_dom, 0))
 461                return;
 462        if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
 463                return;
 464        if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen)
 465                return;
 466
 467        /* Synch generation numbers with peer if link just came up */
 468        if (!state->synched) {
 469                state->peer_gen = new_gen - 1;
 470                state->acked_gen = acked_gen;
 471                state->synched = true;
 472        }
 473
 474        if (more(acked_gen, state->acked_gen))
 475                state->acked_gen = acked_gen;
 476
 477        /* Drop duplicate unless we are waiting for a probe response */
 478        if (!more(new_gen, state->peer_gen) && !probing)
 479                return;
 480
 481        write_lock_bh(&mon->lock);
 482        peer = get_peer(mon, addr);
 483        if (!peer || !peer->is_up)
 484                goto exit;
 485
 486        /* Peer is confirmed, stop any ongoing probing */
 487        peer->down_cnt = 0;
 488
 489        /* Task is done for duplicate record */
 490        if (!more(new_gen, state->peer_gen))
 491                goto exit;
 492
 493        state->peer_gen = new_gen;
 494
 495        /* Cache current domain record for later use */
 496        dom_bef.member_cnt = 0;
 497        dom = peer->domain;
 498        if (dom)
 499                memcpy(&dom_bef, dom, dom->len);
 500
 501        /* Transform and store received domain record */
 502        if (!dom || (dom->len < new_dlen)) {
 503                kfree(dom);
 504                dom = kmalloc(new_dlen, GFP_ATOMIC);
 505                peer->domain = dom;
 506                if (!dom)
 507                        goto exit;
 508        }
 509        dom->len = new_dlen;
 510        dom->gen = new_gen;
 511        dom->member_cnt = new_member_cnt;
 512        dom->up_map = be64_to_cpu(arrv_dom->up_map);
 513        for (i = 0; i < new_member_cnt; i++)
 514                dom->members[i] = ntohl(arrv_dom->members[i]);
 515
 516        /* Update peers affected by this domain record */
 517        applied_bef = peer->applied;
 518        mon_apply_domain(mon, peer);
 519        mon_identify_lost_members(peer, &dom_bef, applied_bef);
 520        mon_assign_roles(mon, peer_head(peer));
 521exit:
 522        write_unlock_bh(&mon->lock);
 523}
 524
 525void tipc_mon_prep(struct net *net, void *data, int *dlen,
 526                   struct tipc_mon_state *state, int bearer_id)
 527{
 528        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 529        struct tipc_mon_domain *dom = data;
 530        u16 gen = mon->dom_gen;
 531        u16 len;
 532
 533        /* Send invalid record if not active */
 534        if (!tipc_mon_is_active(net, mon)) {
 535                dom->len = 0;
 536                return;
 537        }
 538
 539        /* Send only a dummy record with ack if peer has acked our last sent */
 540        if (likely(state->acked_gen == gen)) {
 541                len = dom_rec_len(dom, 0);
 542                *dlen = len;
 543                dom->len = htons(len);
 544                dom->gen = htons(gen);
 545                dom->ack_gen = htons(state->peer_gen);
 546                dom->member_cnt = 0;
 547                return;
 548        }
 549        /* Send the full record */
 550        read_lock_bh(&mon->lock);
 551        len = ntohs(mon->cache.len);
 552        *dlen = len;
 553        memcpy(data, &mon->cache, len);
 554        read_unlock_bh(&mon->lock);
 555        dom->ack_gen = htons(state->peer_gen);
 556}
 557
 558void tipc_mon_get_state(struct net *net, u32 addr,
 559                        struct tipc_mon_state *state,
 560                        int bearer_id)
 561{
 562        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 563        struct tipc_peer *peer;
 564
 565        if (!tipc_mon_is_active(net, mon)) {
 566                state->probing = false;
 567                state->monitoring = true;
 568                return;
 569        }
 570
 571        /* Used cached state if table has not changed */
 572        if (!state->probing &&
 573            (state->list_gen == mon->list_gen) &&
 574            (state->acked_gen == mon->dom_gen))
 575                return;
 576
 577        read_lock_bh(&mon->lock);
 578        peer = get_peer(mon, addr);
 579        if (peer) {
 580                state->probing = state->acked_gen != mon->dom_gen;
 581                state->probing |= peer->down_cnt;
 582                state->reset |= peer->down_cnt >= MAX_PEER_DOWN_EVENTS;
 583                state->monitoring = peer->is_local;
 584                state->monitoring |= peer->is_head;
 585                state->list_gen = mon->list_gen;
 586        }
 587        read_unlock_bh(&mon->lock);
 588}
 589
 590static void mon_timeout(struct timer_list *t)
 591{
 592        struct tipc_monitor *mon = from_timer(mon, t, timer);
 593        struct tipc_peer *self;
 594        int best_member_cnt = dom_size(mon->peer_cnt) - 1;
 595
 596        write_lock_bh(&mon->lock);
 597        self = mon->self;
 598        if (self && (best_member_cnt != self->applied)) {
 599                mon_update_local_domain(mon);
 600                mon_assign_roles(mon, self);
 601        }
 602        write_unlock_bh(&mon->lock);
 603        mod_timer(&mon->timer, jiffies + mon->timer_intv);
 604}
 605
 606int tipc_mon_create(struct net *net, int bearer_id)
 607{
 608        struct tipc_net *tn = tipc_net(net);
 609        struct tipc_monitor *mon;
 610        struct tipc_peer *self;
 611        struct tipc_mon_domain *dom;
 612
 613        if (tn->monitors[bearer_id])
 614                return 0;
 615
 616        mon = kzalloc(sizeof(*mon), GFP_ATOMIC);
 617        self = kzalloc(sizeof(*self), GFP_ATOMIC);
 618        dom = kzalloc(sizeof(*dom), GFP_ATOMIC);
 619        if (!mon || !self || !dom) {
 620                kfree(mon);
 621                kfree(self);
 622                kfree(dom);
 623                return -ENOMEM;
 624        }
 625        tn->monitors[bearer_id] = mon;
 626        rwlock_init(&mon->lock);
 627        mon->net = net;
 628        mon->peer_cnt = 1;
 629        mon->self = self;
 630        self->domain = dom;
 631        self->addr = tipc_own_addr(net);
 632        self->is_up = true;
 633        self->is_head = true;
 634        INIT_LIST_HEAD(&self->list);
 635        timer_setup(&mon->timer, mon_timeout, 0);
 636        mon->timer_intv = msecs_to_jiffies(MON_TIMEOUT + (tn->random & 0xffff));
 637        mod_timer(&mon->timer, jiffies + mon->timer_intv);
 638        return 0;
 639}
 640
 641void tipc_mon_delete(struct net *net, int bearer_id)
 642{
 643        struct tipc_net *tn = tipc_net(net);
 644        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 645        struct tipc_peer *self;
 646        struct tipc_peer *peer, *tmp;
 647
 648        if (!mon)
 649                return;
 650
 651        self = get_self(net, bearer_id);
 652        write_lock_bh(&mon->lock);
 653        tn->monitors[bearer_id] = NULL;
 654        list_for_each_entry_safe(peer, tmp, &self->list, list) {
 655                list_del(&peer->list);
 656                hlist_del(&peer->hash);
 657                kfree(peer->domain);
 658                kfree(peer);
 659        }
 660        mon->self = NULL;
 661        write_unlock_bh(&mon->lock);
 662        del_timer_sync(&mon->timer);
 663        kfree(self->domain);
 664        kfree(self);
 665        kfree(mon);
 666}
 667
 668int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size)
 669{
 670        struct tipc_net *tn = tipc_net(net);
 671
 672        if (cluster_size > TIPC_CLUSTER_SIZE)
 673                return -EINVAL;
 674
 675        tn->mon_threshold = cluster_size;
 676
 677        return 0;
 678}
 679
 680int tipc_nl_monitor_get_threshold(struct net *net)
 681{
 682        struct tipc_net *tn = tipc_net(net);
 683
 684        return tn->mon_threshold;
 685}
 686
 687static int __tipc_nl_add_monitor_peer(struct tipc_peer *peer,
 688                                      struct tipc_nl_msg *msg)
 689{
 690        struct tipc_mon_domain *dom = peer->domain;
 691        struct nlattr *attrs;
 692        void *hdr;
 693
 694        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 695                          NLM_F_MULTI, TIPC_NL_MON_PEER_GET);
 696        if (!hdr)
 697                return -EMSGSIZE;
 698
 699        attrs = nla_nest_start(msg->skb, TIPC_NLA_MON_PEER);
 700        if (!attrs)
 701                goto msg_full;
 702
 703        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_ADDR, peer->addr))
 704                goto attr_msg_full;
 705        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_APPLIED, peer->applied))
 706                goto attr_msg_full;
 707
 708        if (peer->is_up)
 709                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_UP))
 710                        goto attr_msg_full;
 711        if (peer->is_local)
 712                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_LOCAL))
 713                        goto attr_msg_full;
 714        if (peer->is_head)
 715                if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_HEAD))
 716                        goto attr_msg_full;
 717
 718        if (dom) {
 719                if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_DOMGEN, dom->gen))
 720                        goto attr_msg_full;
 721                if (nla_put_u64_64bit(msg->skb, TIPC_NLA_MON_PEER_UPMAP,
 722                                      dom->up_map, TIPC_NLA_MON_PEER_PAD))
 723                        goto attr_msg_full;
 724                if (nla_put(msg->skb, TIPC_NLA_MON_PEER_MEMBERS,
 725                            dom->member_cnt * sizeof(u32), &dom->members))
 726                        goto attr_msg_full;
 727        }
 728
 729        nla_nest_end(msg->skb, attrs);
 730        genlmsg_end(msg->skb, hdr);
 731        return 0;
 732
 733attr_msg_full:
 734        nla_nest_cancel(msg->skb, attrs);
 735msg_full:
 736        genlmsg_cancel(msg->skb, hdr);
 737
 738        return -EMSGSIZE;
 739}
 740
 741int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
 742                             u32 bearer_id, u32 *prev_node)
 743{
 744        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 745        struct tipc_peer *peer;
 746
 747        if (!mon)
 748                return -EINVAL;
 749
 750        read_lock_bh(&mon->lock);
 751        peer = mon->self;
 752        do {
 753                if (*prev_node) {
 754                        if (peer->addr == *prev_node)
 755                                *prev_node = 0;
 756                        else
 757                                continue;
 758                }
 759                if (__tipc_nl_add_monitor_peer(peer, msg)) {
 760                        *prev_node = peer->addr;
 761                        read_unlock_bh(&mon->lock);
 762                        return -EMSGSIZE;
 763                }
 764        } while ((peer = peer_nxt(peer)) != mon->self);
 765        read_unlock_bh(&mon->lock);
 766
 767        return 0;
 768}
 769
 770int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
 771                          u32 bearer_id)
 772{
 773        struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 774        char bearer_name[TIPC_MAX_BEARER_NAME];
 775        struct nlattr *attrs;
 776        void *hdr;
 777        int ret;
 778
 779        ret = tipc_bearer_get_name(net, bearer_name, bearer_id);
 780        if (ret || !mon)
 781                return 0;
 782
 783        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 784                          NLM_F_MULTI, TIPC_NL_MON_GET);
 785        if (!hdr)
 786                return -EMSGSIZE;
 787
 788        attrs = nla_nest_start(msg->skb, TIPC_NLA_MON);
 789        if (!attrs)
 790                goto msg_full;
 791
 792        read_lock_bh(&mon->lock);
 793        if (nla_put_u32(msg->skb, TIPC_NLA_MON_REF, bearer_id))
 794                goto attr_msg_full;
 795        if (tipc_mon_is_active(net, mon))
 796                if (nla_put_flag(msg->skb, TIPC_NLA_MON_ACTIVE))
 797                        goto attr_msg_full;
 798        if (nla_put_string(msg->skb, TIPC_NLA_MON_BEARER_NAME, bearer_name))
 799                goto attr_msg_full;
 800        if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEERCNT, mon->peer_cnt))
 801                goto attr_msg_full;
 802        if (nla_put_u32(msg->skb, TIPC_NLA_MON_LISTGEN, mon->list_gen))
 803                goto attr_msg_full;
 804
 805        read_unlock_bh(&mon->lock);
 806        nla_nest_end(msg->skb, attrs);
 807        genlmsg_end(msg->skb, hdr);
 808
 809        return 0;
 810
 811attr_msg_full:
 812        read_unlock_bh(&mon->lock);
 813        nla_nest_cancel(msg->skb, attrs);
 814msg_full:
 815        genlmsg_cancel(msg->skb, hdr);
 816
 817        return -EMSGSIZE;
 818}
 819