Statistics
| Branch: | Revision:

iof-bird-daemon / proto / pipe / pipe.c @ e81b440f

History | View | Annotate | Download (4.39 KB)

1
/*
2
 *        BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
3
 *
4
 *        (c) 1999--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Pipe
11
 *
12
 * The Pipe protocol is very simple. It just connects to two routing tables
13
 * using proto_add_announce_hook() and whenever it receives a rt_notify()
14
 * about a change in one of the tables, it converts it to a rte_update()
15
 * in the other one.
16
 *
17
 * To avoid pipe loops, Pipe keeps a `being updated' flag in each routing
18
 * table.
19
 */
20

    
21
#undef LOCAL_DEBUG
22

    
23
#include "nest/bird.h"
24
#include "nest/iface.h"
25
#include "nest/protocol.h"
26
#include "nest/route.h"
27
#include "conf/conf.h"
28
#include "filter/filter.h"
29
#include "lib/string.h"
30

    
31
#include "pipe.h"
32

    
33
static void
34
pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
35
{
36
  struct pipe_proto *p = (struct pipe_proto *) P;
37
  rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */
38
  struct proto *src;
39

    
40
  net *nn;
41
  rte *e;
42
  rta a;
43

    
44
  if (!new && !old)
45
    return;
46

    
47
  if (dest->pipe_busy)
48
    {
49
      log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
50
          n->n.prefix, n->n.pxlen, dest->name);
51
      return;
52
    }
53
  nn = net_get(dest, n->n.prefix, n->n.pxlen);
54
  if (new)
55
    {
56
      memcpy(&a, new->attrs, sizeof(rta));
57

    
58
      if (p->mode == PIPE_OPAQUE)
59
        {
60
          a.proto = &p->p;
61
          a.source = RTS_PIPE;
62
        }
63

    
64
      a.aflags = 0;
65
      a.eattrs = attrs;
66
      e = rte_get_temp(&a);
67
      e->net = nn;
68
      e->pflags = 0;
69

    
70
      if (p->mode == PIPE_TRANSPARENT)
71
        {
72
          /* Copy protocol specific embedded attributes. */
73
          memcpy(&(e->u), &(new->u), sizeof(e->u));
74
          e->pref = new->pref;
75
          e->pflags = new->pflags;
76
        }
77

    
78
      src = new->attrs->proto;
79
    }
80
  else
81
    {
82
      e = NULL;
83
      src = old->attrs->proto;
84
    }
85

    
86
  src_table->pipe_busy = 1;
87
  rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
88
  src_table->pipe_busy = 0;
89
}
90

    
91
static int
92
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
93
{
94
  struct proto *pp = (*ee)->sender;
95

    
96
  if (pp == P)
97
    return -1;        /* Avoid local loops automatically */
98
  return 0;
99
}
100

    
101
static int
102
pipe_reload_routes(struct proto *P)
103
{
104
  /*
105
   * Because the pipe protocol feeds routes from both routing tables
106
   * together, both directions are reloaded during refeed and 'reload
107
   * out' command works like 'reload' command. For symmetry, we also
108
   * request refeed when 'reload in' command is used.
109
   */
110
  proto_request_feeding(P);
111
  return 1;
112
}
113

    
114
static int
115
pipe_start(struct proto *P)
116
{
117
  struct pipe_proto *p = (struct pipe_proto *) P;
118
  struct announce_hook *a;
119

    
120
  /* Clean up the secondary stats */
121
  bzero(&p->peer_stats, sizeof(struct proto_stats));
122

    
123
  /* Lock the peer table, unlock is handled in proto_fell_down() */
124
  rt_lock_table(p->peer);
125

    
126
  /* Connect the protocol also to the peer routing table. */
127
  a = proto_add_announce_hook(P, p->peer);
128

    
129
  return PS_UP;
130
}
131

    
132
static struct proto *
133
pipe_init(struct proto_config *C)
134
{
135
  struct pipe_config *c = (struct pipe_config *) C;
136
  struct proto *P = proto_new(C, sizeof(struct pipe_proto));
137
  struct pipe_proto *p = (struct pipe_proto *) P;
138

    
139
  p->peer = c->peer->table;
140
  p->mode = c->mode;
141
  P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY;
142
  P->rt_notify = pipe_rt_notify;
143
  P->import_control = pipe_import_control;
144
  P->reload_routes = pipe_reload_routes;
145

    
146
  return P;
147
}
148

    
149
static void
150
pipe_postconfig(struct proto_config *C)
151
{
152
  struct pipe_config *c = (struct pipe_config *) C;
153

    
154
  if (!c->peer)
155
    cf_error("Name of peer routing table not specified");
156
  if (c->peer == C->table)
157
    cf_error("Primary table and peer table must be different");
158
}
159

    
160
static void
161
pipe_get_status(struct proto *P, byte *buf)
162
{
163
  struct pipe_proto *p = (struct pipe_proto *) P;
164

    
165
  bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
166
}
167

    
168
static int
169
pipe_reconfigure(struct proto *P, struct proto_config *new)
170
{
171
  // struct pipe_proto *p = (struct pipe_proto *) P;
172
  struct pipe_config *o = (struct pipe_config *) P->cf;
173
  struct pipe_config *n = (struct pipe_config *) new;
174

    
175
  if ((o->peer->table != n->peer->table) || (o->mode != n->mode))
176
    return 0;
177

    
178
  return 1;
179
}
180

    
181

    
182
struct protocol proto_pipe = {
183
  name:                "Pipe",
184
  template:        "pipe%d",
185
  postconfig:        pipe_postconfig,
186
  init:                pipe_init,
187
  start:        pipe_start,
188
  reconfigure:        pipe_reconfigure,
189
  get_status:        pipe_get_status,
190
};