Statistics
| Branch: | Revision:

iof-bird-daemon / proto / pipe / pipe.c @ 662faa4a

History | View | Annotate | Download (4.63 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_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
35
{
36
  net *nn;
37
  rte *e;
38
  rta a;
39

    
40
  if (dest->pipe_busy)
41
    {
42
      log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
43
          n->n.prefix, n->n.pxlen, dest->name);
44
      return;
45
    }
46
  nn = net_get(dest, n->n.prefix, n->n.pxlen);
47
  if (new)
48
    {
49
      memcpy(&a, new->attrs, sizeof(rta));
50
      a.proto = &p->p;
51
      a.source = RTS_PIPE;
52
      a.aflags = 0;
53
      a.eattrs = attrs;
54
      e = rte_get_temp(&a);
55
      e->net = nn;
56
    }
57
  else
58
    e = NULL;
59
  dest->pipe_busy = 1;
60
  rte_update(dest, nn, &p->p, e);
61
  dest->pipe_busy = 0;
62
}
63

    
64
static void
65
pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs)
66
{
67
  struct pipe_proto *p = (struct pipe_proto *) P;
68

    
69
  DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
70
  pipe_send(p, p->peer, net, new, old, attrs);
71
}
72

    
73
static void
74
pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs)
75
{
76
  struct pipe_proto *p = ((struct pipe_proto *) P)->phantom;
77

    
78
  DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
79
  pipe_send(p, p->p.table, net, new, old, attrs);
80
}
81

    
82
static int
83
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
84
{
85
  struct proto *pp = (*ee)->attrs->proto;
86

    
87
  if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p)
88
    return -1;        /* Avoid local loops automatically */
89
  return 0;
90
}
91

    
92
static int
93
pipe_start(struct proto *P)
94
{
95
  struct pipe_proto *p = (struct pipe_proto *) P;
96
  struct pipe_proto *ph;
97
  struct announce_hook *a;
98

    
99
  /*
100
   *  Create a phantom protocol which will represent the remote
101
   *  end of the pipe (we need to do this in order to get different
102
   *  filters and announce functions and it unfortunately involves
103
   *  a couple of magic trickery).
104
   */
105
  ph = mb_alloc(P->pool, sizeof(struct pipe_proto));
106
  memcpy(ph, p, sizeof(struct pipe_proto));
107
  p->phantom = ph;
108
  ph->phantom = p;
109
  ph->p.rt_notify = pipe_rt_notify_sec;
110
  ph->p.proto_state = PS_UP;
111
  ph->p.core_state = ph->p.core_goal = FS_HAPPY;
112
  ph->p.in_filter = ph->p.out_filter = FILTER_ACCEPT;        /* We do all filtering on the local end */
113

    
114
  /*
115
   *  Connect the phantom protocol to the peer routing table, but
116
   *  keep it in the list of connections of the primary protocol,
117
   *  so that it gets disconnected at the right time and we also
118
   *  get all routes from both sides during the feeding phase.
119
   */
120
  a = proto_add_announce_hook(P, p->peer);
121
  a->proto = &ph->p;
122
  rt_lock_table(p->peer);
123

    
124
  return PS_UP;
125
}
126

    
127
static int
128
pipe_shutdown(struct proto *P)
129
{
130
  struct pipe_proto *p = (struct pipe_proto *) P;
131

    
132
  rt_unlock_table(p->peer);
133
  return PS_DOWN;
134
}
135

    
136
static struct proto *
137
pipe_init(struct proto_config *C)
138
{
139
  struct pipe_config *c = (struct pipe_config *) C;
140
  struct proto *P = proto_new(C, sizeof(struct pipe_proto));
141
  struct pipe_proto *p = (struct pipe_proto *) P;
142

    
143
  p->peer = c->peer->table;
144
  P->rt_notify = pipe_rt_notify_pri;
145
  P->import_control = pipe_import_control;
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, "-> %s", p->peer->name);
166
}
167

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

    
174
  return o->peer == n->peer;
175
}
176

    
177
struct protocol proto_pipe = {
178
  name:                "Pipe",
179
  template:        "pipe%d",
180
  postconfig:        pipe_postconfig,
181
  init:                pipe_init,
182
  start:        pipe_start,
183
  shutdown:        pipe_shutdown,
184
  reconfigure:        pipe_reconfigure,
185
  get_status:        pipe_get_status,
186
};