Statistics
| Branch: | Revision:

iof-bird-daemon / proto / pipe / pipe.c @ 3daf783f

History | View | Annotate | Download (3.74 KB)

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

    
9
#define LOCAL_DEBUG
10

    
11
#include "nest/bird.h"
12
#include "nest/iface.h"
13
#include "nest/protocol.h"
14
#include "nest/route.h"
15
#include "conf/conf.h"
16
#include "filter/filter.h"
17
#include "lib/string.h"
18

    
19
#include "pipe.h"
20

    
21
static void
22
pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old)
23
{
24
  net *nn;
25
  rte *e;
26
  rta a;
27

    
28
  if (dest->pipe_busy)
29
    {
30
      log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
31
          n->n.prefix, n->n.pxlen, dest->name);
32
      return;
33
    }
34
  nn = net_get(dest, n->n.prefix, n->n.pxlen);
35
  if (new)
36
    {
37
      memcpy(&a, new->attrs, sizeof(rta));
38
      a.proto = &p->p;
39
      a.source = RTS_PIPE;
40
      a.aflags = 0;
41
      e = rte_get_temp(&a);
42
      e->net = nn;
43
    }
44
  else
45
    e = NULL;
46
  dest->pipe_busy = 1;
47
  rte_update(dest, nn, &p->p, e);
48
  dest->pipe_busy = 0;
49
}
50

    
51
static void
52
pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *tmpa)
53
{
54
  struct pipe_proto *p = (struct pipe_proto *) P;
55

    
56
  DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
57
  pipe_send(p, p->peer, net, new, old);
58
}
59

    
60
static void
61
pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *tmpa)
62
{
63
  struct pipe_proto *p = ((struct pipe_proto *) P)->phantom;
64

    
65
  DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
66
  pipe_send(p, p->p.table, net, new, old);
67
}
68

    
69
static int
70
pipe_import_control(struct proto *P, rte **ee, ea_list **ea, struct linpool *p)
71
{
72
  struct proto *pp = (*ee)->attrs->proto;
73

    
74
  if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p)
75
    return -1;        /* Avoid local loops automatically */
76
  return 0;
77
}
78

    
79
static int
80
pipe_start(struct proto *P)
81
{
82
  struct pipe_proto *p = (struct pipe_proto *) P;
83
  struct pipe_proto *ph;
84
  struct announce_hook *a;
85

    
86
  /*
87
   *  Create a phantom protocol which will represent the remote
88
   *  end of the pipe (we need to do this in order to get different
89
   *  filters and announce functions and it unfortunately involves
90
   *  a couple of magic trickery).
91
   */
92
  ph = mb_alloc(P->pool, sizeof(struct pipe_proto));
93
  memcpy(ph, p, sizeof(struct pipe_proto));
94
  p->phantom = ph;
95
  ph->phantom = p;
96
  ph->p.rt_notify = pipe_rt_notify_sec;
97
  ph->p.proto_state = PS_UP;
98
  ph->p.core_state = ph->p.core_goal = FS_HAPPY;
99
  ph->p.in_filter = ph->p.out_filter = FILTER_ACCEPT;        /* We do all filtering on the local end */
100

    
101
  /*
102
   *  Connect the phantom protocol to the peer routing table, but
103
   *  keep it in the list of connections of the primary protocol,
104
   *  so that it gets disconnected at the right time and we also
105
   *  get all routes from both sides during the feeding phase.
106
   */
107
  a = proto_add_announce_hook(P, p->peer);
108
  a->proto = &ph->p;
109

    
110
  return PS_UP;
111
}
112

    
113
static struct proto *
114
pipe_init(struct proto_config *C)
115
{
116
  struct pipe_config *c = (struct pipe_config *) C;
117
  struct proto *P = proto_new(C, sizeof(struct pipe_proto));
118
  struct pipe_proto *p = (struct pipe_proto *) P;
119

    
120
  p->peer = c->peer->table;
121
  P->rt_notify = pipe_rt_notify_pri;
122
  P->import_control = pipe_import_control;
123
  return P;
124
}
125

    
126
static void
127
pipe_postconfig(struct proto_config *C)
128
{
129
  struct pipe_config *c = (struct pipe_config *) C;
130

    
131
  if (!c->peer)
132
    cf_error("Name of peer routing table not specified");
133
  if (c->peer == C->table)
134
    cf_error("Primary table and peer table must be different");
135
}
136

    
137
static void
138
pipe_get_status(struct proto *P, byte *buf)
139
{
140
  struct pipe_proto *p = (struct pipe_proto *) P;
141

    
142
  bsprintf(buf, "-> %s", p->peer->name);
143
}
144

    
145
struct protocol proto_pipe = {
146
  name:                "Pipe",
147
  postconfig:        pipe_postconfig,
148
  init:                pipe_init,
149
  start:        pipe_start,
150
  get_status:        pipe_get_status,
151
};