Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / proto / pipe / pipe.c @ 6b3f1a54

History | View | Annotate | Download (8.24 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
 * A pipe has two announce hooks, the first connected to the main
21
 * table, the second connected to the peer table. When a new route is
22
 * announced on the main table, it gets checked by an export filter in
23
 * ahook 1, and, after that, it is announced to the peer table via
24
 * rte_update(), an import filter in ahook 2 is called. When a new
25
 * route is announced in the peer table, an export filter in ahook2
26
 * and an import filter in ahook 1 are used. Oviously, there is no
27
 * need in filtering the same route twice, so both import filters are
28
 * set to accept, while user configured 'import' and 'export' filters
29
 * are used as export filters in ahooks 2 and 1. Route limits are
30
 * handled similarly, but on the import side of ahooks.
31
 */
32

    
33
#undef LOCAL_DEBUG
34

    
35
#include "nest/bird.h"
36
#include "nest/iface.h"
37
#include "nest/protocol.h"
38
#include "nest/route.h"
39
#include "nest/cli.h"
40
#include "conf/conf.h"
41
#include "filter/filter.h"
42
#include "lib/string.h"
43

    
44
#include "pipe.h"
45

    
46
static void
47
pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs)
48
{
49
  struct pipe_proto *p = (void *) P;
50
  struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
51
  struct rte_src *src;
52

    
53
  rte *e;
54
  rta *a;
55

    
56
  if (!new && !old)
57
    return;
58

    
59
  if (dst->table->pipe_busy)
60
    {
61
      log(L_ERR "Pipe loop detected when sending %N to table %s",
62
          n->n.addr, dst->table->name);
63
      return;
64
    }
65

    
66
  if (new)
67
    {
68
      a = alloca(rta_size(new->attrs));
69
      memcpy(a, new->attrs, rta_size(new->attrs));
70

    
71
      a->aflags = 0;
72
      a->eattrs = attrs;
73
      a->hostentry = NULL;
74
      e = rte_get_temp(a);
75
      e->pflags = 0;
76

    
77
      /* Copy protocol specific embedded attributes. */
78
      memcpy(&(e->u), &(new->u), sizeof(e->u));
79
      e->pref = new->pref;
80
      e->pflags = new->pflags;
81

    
82
      src = a->src;
83
    }
84
  else
85
    {
86
      e = NULL;
87
      src = old->attrs->src;
88
    }
89

    
90
  src_ch->table->pipe_busy = 1;
91
  rte_update2(dst, n->n.addr, e, src);
92
  src_ch->table->pipe_busy = 0;
93
}
94

    
95
static int
96
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
97
{
98
  struct proto *pp = (*ee)->sender->proto;
99

    
100
  if (pp == P)
101
    return -1;        /* Avoid local loops automatically */
102

    
103
  return 0;
104
}
105

    
106
static void
107
pipe_reload_routes(struct channel *C)
108
{
109
  struct pipe_proto *p = (void *) C->proto;
110

    
111
  /* Route reload on one channel is just refeed on the other */
112
  channel_request_feeding((C == p->pri) ? p->sec : p->pri);
113
}
114

    
115

    
116
static void
117
pipe_postconfig(struct proto_config *CF)
118
{
119
  struct pipe_config *cf = (void *) CF;
120
  struct channel_config *cc = proto_cf_main_channel(CF);
121

    
122
  if (!cc->table)
123
    cf_error("Primary routing table not specified");
124

    
125
  if (!cf->peer)
126
    cf_error("Secondary routing table not specified");
127

    
128
  if (cc->table == cf->peer)
129
    cf_error("Primary table and peer table must be different");
130

    
131
  if (cc->table->addr_type != cf->peer->addr_type)
132
    cf_error("Primary table and peer table must have the same type");
133

    
134
  if (cc->rx_limit.action)
135
    cf_error("Pipe protocol does not support receive limits");
136

    
137
  if (cc->in_keep_filtered)
138
    cf_error("Pipe protocol prohibits keeping filtered routes");
139
}
140

    
141
static int
142
pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
143
{
144
  struct channel_config *cc = proto_cf_main_channel(&cf->c);
145

    
146
  struct channel_config pri_cf = {
147
    .name = "pri",
148
    .channel = cc->channel,
149
    .table = cc->table,
150
    .out_filter = cc->out_filter,
151
    .in_limit = cc->in_limit,
152
    .ra_mode = RA_ANY
153
  };
154

    
155
  struct channel_config sec_cf = {
156
    .name = "sec",
157
    .channel = cc->channel,
158
    .table = cf->peer,
159
    .out_filter = cc->in_filter,
160
    .in_limit = cc->out_limit,
161
    .ra_mode = RA_ANY
162
  };
163

    
164
  return
165
    proto_configure_channel(&p->p, &p->pri, &pri_cf) &&
166
    proto_configure_channel(&p->p, &p->sec, &sec_cf);
167
}
168

    
169
static struct proto *
170
pipe_init(struct proto_config *CF)
171
{
172
  struct proto *P = proto_new(CF);
173
  struct pipe_proto *p = (void *) P;
174
  struct pipe_config *cf = (void *) CF;
175

    
176
  P->rt_notify = pipe_rt_notify;
177
  P->import_control = pipe_import_control;
178
  P->reload_routes = pipe_reload_routes;
179

    
180
  pipe_configure_channels(p, cf);
181

    
182
  return P;
183
}
184

    
185
static int
186
pipe_reconfigure(struct proto *P, struct proto_config *CF)
187
{
188
  struct pipe_proto *p = (void *) P;
189
  struct pipe_config *cf = (void *) CF;
190

    
191
  return pipe_configure_channels(p, cf);
192
}
193

    
194
static void
195
pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
196
{
197
  /* Just a shallow copy, not many items here */
198
}
199

    
200
static void
201
pipe_get_status(struct proto *P, byte *buf)
202
{
203
  struct pipe_proto *p = (void *) P;
204

    
205
  bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name);
206
}
207

    
208
static void
209
pipe_show_stats(struct pipe_proto *p)
210
{
211
  struct proto_stats *s1 = &p->pri->stats;
212
  struct proto_stats *s2 = &p->sec->stats;
213

    
214
  /*
215
   * Pipe stats (as anything related to pipes) are a bit tricky. There
216
   * are two sets of stats - s1 for ahook to the primary routing and
217
   * s2 for the ahook to the secondary routing table. The user point
218
   * of view is that routes going from the primary routing table to
219
   * the secondary routing table are 'exported', while routes going in
220
   * the other direction are 'imported'.
221
   *
222
   * Each route going through a pipe is, technically, first exported
223
   * to the pipe and then imported from that pipe and such operations
224
   * are counted in one set of stats according to the direction of the
225
   * route propagation. Filtering is done just in the first part
226
   * (export). Therefore, we compose stats for one directon for one
227
   * user direction from both import and export stats, skipping
228
   * immediate and irrelevant steps (exp_updates_accepted,
229
   * imp_updates_received, imp_updates_filtered, ...).
230
   *
231
   * Rule of thumb is that stats s1 have the correct 'polarity'
232
   * (imp/exp), while stats s2 have switched 'polarity'.
233
   */
234

    
235
  cli_msg(-1006, "  Routes:         %u imported, %u exported",
236
          s1->imp_routes, s2->imp_routes);
237
  cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
238
  cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
239
          s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
240
          s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
241
  cli_msg(-1006, "    Import withdraws:   %10u %10u        --- %10u %10u",
242
          s2->exp_withdraws_received, s1->imp_withdraws_invalid,
243
          s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
244
  cli_msg(-1006, "    Export updates:     %10u %10u %10u %10u %10u",
245
          s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
246
          s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
247
  cli_msg(-1006, "    Export withdraws:   %10u %10u        --- %10u %10u",
248
          s1->exp_withdraws_received, s2->imp_withdraws_invalid,
249
          s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
250
}
251

    
252
static void
253
pipe_show_proto_info(struct proto *P)
254
{
255
  struct pipe_proto *p = (void *) P;
256

    
257
  cli_msg(-1006, "  Channel %s", "main");
258
  cli_msg(-1006, "    Table:          %s", p->pri->table->name);
259
  cli_msg(-1006, "    Peer table:     %s", p->sec->table->name);
260
  cli_msg(-1006, "    Import filter:  %s", filter_name(p->sec->out_filter));
261
  cli_msg(-1006, "    Export filter:  %s", filter_name(p->pri->out_filter));
262

    
263
  channel_show_limit(&p->pri->in_limit, "Import limit:");
264
  channel_show_limit(&p->sec->in_limit, "Export limit:");
265

    
266
  if (P->proto_state != PS_DOWN)
267
    pipe_show_stats(p);
268
}
269

    
270

    
271
struct protocol proto_pipe = {
272
  .name =                "Pipe",
273
  .template =                "pipe%d",
274
  .proto_size =                sizeof(struct pipe_proto),
275
  .config_size =        sizeof(struct pipe_config),
276
  .postconfig =                pipe_postconfig,
277
  .init =                pipe_init,
278
  .reconfigure =        pipe_reconfigure,
279
  .copy_config =         pipe_copy_config,
280
  .get_status =         pipe_get_status,
281
  .show_proto_info =         pipe_show_proto_info
282
};