Revision f4a60a9b

View differences:

conf/conf.c
136 136
  protos_preconfig(c);
137 137
  rt_preconfig(c);
138 138
  cf_parse();
139
  protos_postconfig(c);
139

  
140 140
  if (EMPTY_LIST(c->protos))
141 141
    cf_error("No protocol is specified in the config file");
142
  /* XXXX */
142

  
143
  /*
143 144
  if (!c->router_id)
144 145
    cf_error("Router ID must be configured manually");
146
  */
145 147

  
146 148
  done = 1;
147 149

  
conf/conf.h
24 24

  
25 25
  int mrtdump_file;			/* Configured MRTDump file (sysdep, fd in unix) */
26 26
  char *syslog_name;			/* Name used for syslog (NULL -> no syslog) */
27
  struct rtable_config *master_rtc;	/* Configuration of master routing table */
27
  struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
28 28
  struct iface_patt *router_id_from;	/* Configured list of router ID iface patterns */
29 29

  
30 30
  u32 router_id;			/* Our Router ID */
conf/confbase.Y
46 46
  struct symbol *s;
47 47
  char *t;
48 48
  struct rtable_config *r;
49
  struct channel_config *cc;
49 50
  struct f_inst *x;
50 51
  struct filter *f;
51 52
  struct f_tree *e;
......
61 62
  bird_clock_t time;
62 63
  struct f_prefix px;
63 64
  struct proto_spec ps;
65
  struct channel_limit cl;
64 66
  struct timeformat *tf;
65 67
}
66 68

  
lib/birdlib.h
34 34
#define ABS(a)   ((a)>=0 ? (a) : -(a))
35 35
#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a))
36 36
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
37
#define CALL(fn, args...) ({ if (fn) fn(args); })
37 38

  
38 39
static inline int uint_cmp(uint i1, uint i2)
39 40
{ return (int)(i1 > i2) - (int)(i1 < i2); }
lib/lists.h
39 39
#define WALK_LIST2(n,nn,list,pos) \
40 40
  for(nn=(list).head; NODE_VALID(nn) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nn->next)
41 41
#define WALK_LIST_DELSAFE(n,nxt,list) \
42
     for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
42
  for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
43
#define WALK_LIST2_DELSAFE(n,nn,nxt,list,pos) \
44
  for(nn=HEAD(list); (nxt=nn->next) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nxt)
45

  
43 46
/* WALK_LIST_FIRST supposes that called code removes each processed node */
44 47
#define WALK_LIST_FIRST(n,list) \
45 48
     while(n=HEAD(list), (NODE (n))->next)
lib/net.c
4 4
#include "lib/net.h"
5 5

  
6 6

  
7
const char * const net_label[] = {
8
  [NET_IP4] = "ipv4",
9
  [NET_IP6] = "ipv6",
10
  [NET_VPN4] = "vpn4",
11
  [NET_VPN6] = "vpn6"
12
};
13

  
7 14
const u16 net_addr_length[] = {
8 15
  [NET_IP4] = sizeof(net_addr_ip4),
9 16
  [NET_IP6] = sizeof(net_addr_ip6),
lib/net.h
21 21
#define NET_ROA6	6
22 22
#define NET_MAX		7
23 23

  
24
#define NB_IP4		(1 << NET_IP4)
25
#define NB_IP6		(1 << NET_IP6)
26
#define NB_VPN4		(1 << NET_VPN4)
27
#define NB_VPN6		(1 << NET_VPN6)
28

  
29
#define NB_IP		(NB_IP4 | NB_IP6)
30
#define NB_ANY		0xffffffff
31

  
32

  
24 33
typedef struct net_addr {
25 34
  u8 type;
26 35
  u8 pxlen;
......
88 97
} net_addr_union;
89 98

  
90 99

  
100
extern const char * const net_label[];
91 101
extern const u16 net_addr_length[];
92 102
extern const u8  net_max_prefix_length[];
93 103
extern const u16 net_max_text_length[];
......
149 159
    net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
150 160
}
151 161

  
162

  
163
static inline int net_val_match(u8 type, u32 mask)
164
{ return !!((1 << type) & mask); }
165

  
166
static inline int net_type_match(const net_addr *a, u32 mask)
167
{ return net_val_match(a->type, mask); }
168

  
152 169
static inline int net_is_ip(const net_addr *a)
153 170
{ return (a->type == NET_IP4) || (a->type == NET_IP6); }
154 171

  
nest/config.Y
17 17
CF_DEFINES
18 18

  
19 19
static struct proto_config *this_proto;
20
static struct channel_config *this_channel;
20 21
static struct iface_patt *this_ipatt;
21 22
static struct iface_patt_node *this_ipn;
22 23
/* static struct roa_table_config *this_roa_table; */
......
49 50
  return rv;
50 51
}
51 52

  
53
static void
54
proto_postconfig(void)
55
{
56
  CALL(this_proto->protocol->postconfig, this_proto);
57
  this_channel = NULL;
58
  this_proto = NULL;
59
}
60

  
61

  
52 62
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
53 63

  
54 64
CF_DECLS
......
76 86
%type <s> optsym
77 87
%type <ra> r_args
78 88
%type <sd> sym_args
79
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action table_type table_sorted tos
89
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos
80 90
%type <ps> proto_patt proto_patt2
81
%type <g> limit_spec
91
%type <cc> channel_start proto_channel
92
%type <cl> limit_spec
82 93

  
83 94
CF_GRAMMAR
84 95

  
......
115 126
 | listen_opts listen_opt
116 127
 ;
117 128

  
118
listen_opt: 
129
listen_opt:
119 130
   ADDRESS ipa { new_config->listen_bgp_addr = $2; }
120 131
 | PORT expr { new_config->listen_bgp_port = $2; }
121 132
 | V6ONLY { new_config->listen_bgp_flags = 0; }
......
128 139
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
129 140

  
130 141

  
131
/* Creation of routing tables */
142
/* Network types (for tables, channels) */
132 143

  
133
CF_ADDTO(conf, table)
134

  
135
table_type:
136
   /* empty */ { $$ = NET_IP4; }
137
 | IPV4 { $$ = NET_IP4; }
144
net_type:
145
   IPV4 { $$ = NET_IP4; }
138 146
 | IPV6 { $$ = NET_IP6; }
139 147
 | VPN4 { $$ = NET_VPN4; }
140 148
 | VPN6 { $$ = NET_VPN6; }
......
142 150
 | ROA6 { $$ = NET_ROA6; }
143 151
 ;
144 152

  
153

  
154
/* Creation of routing tables */
155

  
156
CF_ADDTO(conf, table)
157

  
145 158
table_sorted:
146 159
          { $$ = 0; }
147 160
 | SORTED { $$ = 1; }
148 161
 ;
149 162

  
150
table: table_type TABLE SYM table_sorted {
163
table: net_type TABLE SYM table_sorted {
151 164
   struct rtable_config *cf;
152 165
   cf = rt_new_table($3, $1);
153 166
   cf->sorted = $4;
154 167
   }
155 168
 ;
156 169

  
170

  
157 171
/* Definition of protocols */
158 172

  
159
CF_ADDTO(conf, proto)
173
CF_ADDTO(conf, proto { proto_postconfig(); })
160 174

  
161 175
proto_start:
162 176
   PROTOCOL { $$ = SYM_PROTO; }
......
194 208

  
195 209
proto_item:
196 210
   /* EMPTY */
197
 | PREFERENCE expr {
198
     if ($2 < 0 || $2 > 0xFFFF) cf_error("Invalid preference");
199
     this_proto->preference = $2;
200
   }
201 211
 | DISABLED bool { this_proto->disabled = $2; }
202 212
 | DEBUG debug_mask { this_proto->debug = $2; }
203 213
 | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
204
 | IMPORT imexport { this_proto->in_filter = $2; }
205
 | EXPORT imexport { this_proto->out_filter = $2; }
206
 | RECEIVE LIMIT limit_spec { this_proto->rx_limit = $3; }
207
 | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
208
 | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
209
 | IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; }
210
 | TABLE rtable { this_proto->table = $2; }
211 214
 | ROUTER ID idval { this_proto->router_id = $3; }
212 215
 | DESCRIPTION text { this_proto->dsc = $2; }
213 216
 ;
214 217

  
218

  
219
channel_start: net_type
220
{
221
  $$ = this_channel = channel_config_new(NULL, $1, this_proto);
222
};
223

  
224
channel_item:
225
   TABLE rtable {
226
     if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
227
       cf_error("Incompatible table type");
228
     this_channel->table = $2;
229
   }
230
 | IMPORT imexport { this_channel->in_filter = $2; }
231
 | EXPORT imexport { this_channel->out_filter = $2; }
232
 | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
233
 | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
234
 | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
235
 | PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
236
 | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
237
 ;
238

  
239
channel_opts:
240
   /* empty */
241
 | channel_opts channel_item ';'
242
 ;
243

  
244
channel_opt_list:
245
   /* empty */
246
 | '{' channel_opts '}'
247
 ;
248

  
249
channel_end:
250
{
251
  if (!this_channel->table)
252
    cf_error("Routing table not specified");
253

  
254
  this_channel = NULL;
255
};
256

  
257
proto_channel: channel_start channel_opt_list channel_end;
258

  
259

  
260
rtable:
261
   SYM {
262
     if ($1->class != SYM_TABLE) cf_error("Table expected");
263
     $$ = $1->def;
264
   }
265
 ;
266

  
215 267
imexport:
216 268
   FILTER filter { $$ = $2; }
217 269
 | where_filter
......
228 280
 ;
229 281

  
230 282
limit_spec:
231
   expr limit_action {
232
     struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit));
233
     l->limit = $1;
234
     l->action = $2;
235
     $$ = l;
236
   }
237
 | OFF { $$ = NULL; }
238
 ;
239

  
240
rtable:
241
   SYM {
242
     if ($1->class != SYM_TABLE) cf_error("Table name expected");
243
     $$ = $1->def;
244
   }
283
   expr limit_action { $$ = (struct channel_limit){ .limit = $1, $$.action = $2 }; }
284
 | OFF { $$ = (struct channel_limit){}; }
245 285
 ;
246 286

  
247 287
CF_ADDTO(conf, debug_default)
......
315 355
dev_proto:
316 356
   dev_proto_start proto_name '{'
317 357
 | dev_proto proto_item ';'
358
 | dev_proto proto_channel ';'
318 359
 | dev_proto dev_iface_patt ';'
319 360
 ;
320 361

  
nest/iface.c
138 138
static inline void
139 139
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
140 140
{
141
  if (p->ifa_notify)
141
  if (p->ifa_notify && (p->proto_state != PS_DOWN))
142 142
    {
143 143
      if (p->debug & D_IFACES)
144 144
	log(L_TRACE "%s < %s address %N on interface %s %s",
......
155 155

  
156 156
  DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
157 157

  
158
  WALK_LIST(p, active_proto_list)
158
  WALK_LIST(p, proto_list)
159 159
    ifa_send_notify(p, c, a);
160 160
}
161 161

  
......
174 174
static inline void
175 175
if_send_notify(struct proto *p, unsigned c, struct iface *i)
176 176
{
177
  if (p->if_notify)
177
  if (p->if_notify && (p->proto_state != PS_DOWN))
178 178
    {
179 179
      if (p->debug & D_IFACES)
180 180
	log(L_TRACE "%s < interface %s %s", p->name, i->name,
......
215 215
	ifa_notify_change_(IF_CHANGE_DOWN, a);
216 216
      }
217 217

  
218
  WALK_LIST(p, active_proto_list)
218
  WALK_LIST(p, proto_list)
219 219
    if_send_notify(p, c, i);
220 220

  
221 221
  if (c & IF_CHANGE_UP)
nest/neighbor.c
239 239
  rem_node(&n->n);
240 240
  add_tail(&neigh_hash_table[neigh_hash(n->proto, &n->addr)], &n->n);
241 241
  DBG("Waking up sticky neighbor %I\n", n->addr);
242
  if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
242
  if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
243 243
    n->proto->neigh_notify(n);
244 244
}
245 245

  
......
252 252
    n->iface = NULL;
253 253
  n->ifa = NULL;
254 254
  n->scope = -1;
255
  if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
255
  if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
256 256
    n->proto->neigh_notify(n);
257 257
  rem_node(&n->n);
258 258
  if (n->flags & NEF_STICKY)
......
333 333
  WALK_LIST_DELSAFE(x, y, i->neighbors)
334 334
    {
335 335
      neighbor *n = SKIP_BACK(neighbor, if_n, x);
336
      if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
336
      if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
337 337
	n->proto->neigh_notify(n);
338 338
    }
339 339
}
nest/proto.c
21 21
#include "filter/filter.h"
22 22

  
23 23
pool *proto_pool;
24
list  proto_list;
24 25

  
25 26
static list protocol_list;
26
static list proto_list;
27 27

  
28 28
#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
29 29

  
30
list active_proto_list;
31
static list inactive_proto_list;
32
static list initial_proto_list;
33
static list flush_proto_list;
34
static struct proto *initial_device_proto;
35

  
36
static event *proto_flush_event;
37 30
static timer *proto_shutdown_timer;
38 31
static timer *gr_wait_timer;
39 32

  
......
46 39
static u32 graceful_restart_locks;
47 40

  
48 41
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
49
static char *c_states[] = { "HUNGRY", "???", "HAPPY", "FLUSHING" };
50 42

  
51
static void proto_flush_loop(void *);
43
extern struct protocol proto_unix_iface;
44

  
52 45
static void proto_shutdown_loop(struct timer *);
53 46
static void proto_rethink_goal(struct proto *p);
54
static void proto_want_export_up(struct proto *p);
55
static void proto_fell_down(struct proto *p);
56 47
static char *proto_state_name(struct proto *p);
48
static void channel_verify_limits(struct channel *c);
49
static void channel_reset_limit(struct channel_limit *l);
57 50

  
58
static void
59
proto_relink(struct proto *p)
60
{
61
  list *l = NULL;
62 51

  
63
  switch (p->core_state)
64
    {
65
    case FS_HUNGRY:
66
      l = &inactive_proto_list;
67
      break;
68
    case FS_HAPPY:
69
      l = &active_proto_list;
70
      break;
71
    case FS_FLUSHING:
72
      l = &flush_proto_list;
73
      break;
74
    default:
75
      ASSERT(0);
76
    }
52
static inline int proto_is_done(struct proto *p)
53
{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
77 54

  
78
  rem_node(&p->n);
79
  add_tail(l, &p->n);
80
}
55
static inline int channel_is_active(struct channel *c)
56
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
81 57

  
82 58
static void
83 59
proto_log_state_change(struct proto *p)
84 60
{
85 61
  if (p->debug & D_STATES)
62
  {
63
    char *name = proto_state_name(p);
64
    if (name != p->last_state_name_announced)
86 65
    {
87
      char *name = proto_state_name(p);
88
      if (name != p->last_state_name_announced)
89
	{
90
	  p->last_state_name_announced = name;
91
	  PD(p, "State changed to %s", proto_state_name(p));
92
	}
66
      p->last_state_name_announced = name;
67
      PD(p, "State changed to %s", proto_state_name(p));
93 68
    }
69
  }
94 70
  else
95 71
    p->last_state_name_announced = NULL;
96 72
}
97 73

  
98 74

  
99
/**
100
 * proto_new - create a new protocol instance
101
 * @c: protocol configuration
102
 * @size: size of protocol data structure (each protocol instance is represented by
103
 * a structure starting with generic part [struct &proto] and continued
104
 * with data specific to the protocol)
105
 *
106
 * When a new configuration has been read in, the core code starts
107
 * initializing all the protocol instances configured by calling their
108
 * init() hooks with the corresponding instance configuration. The initialization
109
 * code of the protocol is expected to create a new instance according to the
110
 * configuration by calling this function and then modifying the default settings
111
 * to values wanted by the protocol.
112
 */
113
void *
114
proto_new(struct proto_config *c, unsigned size)
75
struct channel_config *
76
proto_cf_find_channel(struct proto_config *pc, uint net_type)
115 77
{
116
  struct protocol *pr = c->protocol;
117
  struct proto *p = mb_allocz(proto_pool, size);
118

  
119
  p->cf = c;
120
  p->debug = c->debug;
121
  p->mrtdump = c->mrtdump;
122
  p->name = c->name;
123
  p->preference = c->preference;
124
  p->disabled = c->disabled;
125
  p->proto = pr;
126
  p->table = c->table->table;
127
  p->hash_key = random_u32();
128
  c->proto = p;
129
  return p;
78
  struct channel_config *cc;
79

  
80
  WALK_LIST(cc, pc->channels)
81
    if (cc->net_type == net_type)
82
      return cc;
83

  
84
  return NULL;
130 85
}
131 86

  
132
static void
133
proto_init_instance(struct proto *p)
87
/**
88
 * proto_find_channel_by_table - find channel connected to a routing table
89
 * @p: protocol instance
90
 * @t: routing table
91
 *
92
 * Returns pointer to channel or NULL
93
 */
94
struct channel *
95
proto_find_channel_by_table(struct proto *p, struct rtable *t)
134 96
{
135
  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
136
  p->pool = rp_new(proto_pool, p->proto->name);
137
  p->attn = ev_new(p->pool);
138
  p->attn->data = p;
97
  struct channel *c;
139 98

  
140
  if (graceful_restart_state == GRS_INIT)
141
    p->gr_recovery = 1;
99
  WALK_LIST(c, p->channels)
100
    if (c->table == t)
101
      return c;
142 102

  
143
  if (! p->proto->multitable)
144
    rt_lock_table(p->table);
103
  return NULL;
145 104
}
146 105

  
147
extern pool *rt_table_pool;
148 106
/**
149
 * proto_add_announce_hook - connect protocol to a routing table
107
 * proto_add_channel - connect protocol to a routing table
150 108
 * @p: protocol instance
151
 * @t: routing table to connect to
152
 * @stats: per-table protocol statistics
153
 *
154
 * This function creates a connection between the protocol instance @p and the
155
 * routing table @t, making the protocol hear all changes in the table.
109
 * @cf: channel configuration
156 110
 *
157
 * The announce hook is linked in the protocol ahook list. Announce hooks are
158
 * allocated from the routing table resource pool and when protocol accepts
159
 * routes also in the table ahook list. The are linked to the table ahook list
160
 * and unlinked from it depending on export_state (in proto_want_export_up() and
161
 * proto_want_export_down()) and they are automatically freed after the protocol
162
 * is flushed (in proto_fell_down()).
111
 * This function creates a channel between the protocol instance @p and the
112
 * routing table specified in the configuration @cf, making the protocol hear
113
 * all changes in the table and allowing the protocol to update routes in the
114
 * table.
163 115
 *
164
 * Unless you want to listen to multiple routing tables (as the Pipe protocol
165
 * does), you needn't to worry about this function since the connection to the
166
 * protocol's primary routing table is initialized automatically by the core
167
 * code.
116
 * The channel is linked in the protocol channel list and when active also in
117
 * the table channel list. Channels are allocated from the global resource pool
118
 * (@proto_pool) and they are automatically freed when the protocol is removed.
168 119
 */
169
struct announce_hook *
170
proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
120

  
121
struct channel *
122
proto_add_channel(struct proto *p, struct channel_config *cf)
123
{
124
  struct channel *c = mb_allocz(proto_pool, cf->channel->channel_size);
125

  
126
  c->name = cf->name;
127
  c->channel = cf->channel;
128
  c->proto = p;
129
  c->table = cf->table->table;
130

  
131
  c->in_filter = cf->in_filter;
132
  c->out_filter = cf->out_filter;
133
  c->rx_limit = cf->rx_limit;
134
  c->in_limit = cf->in_limit;
135
  c->out_limit = cf->out_limit;
136

  
137
  c->net_type = cf->net_type;
138
  c->ra_mode = cf->ra_mode;
139
  c->preference = cf->preference;
140
  c->merge_limit = cf->merge_limit;
141
  c->in_keep_filtered = cf->in_keep_filtered;
142

  
143
  c->channel_state = CS_DOWN;
144
  c->export_state = ES_DOWN;
145
  c->last_state_change = now;
146
  c->reloadable = 1;
147

  
148
  CALL(c->channel->init, c, cf);
149

  
150
  add_tail(&p->channels, &c->n);
151

  
152
  PD(p, "Channel %s connected to table %s", c->name, c->table->name);
153

  
154
  return c;
155
}
156

  
157
void
158
proto_remove_channel(struct proto *p, struct channel *c)
159
{
160
  ASSERT(c->channel_state == CS_DOWN);
161

  
162
  PD(p, "Channel %s removed", c->name);
163

  
164
  rem_node(&c->n);
165
  mb_free(c);
166
}
167

  
168

  
169
static void
170
proto_start_channels(struct proto *p)
171
{
172
  struct channel *c;
173
  WALK_LIST(c, p->channels)
174
    if (!c->disabled)
175
      channel_set_state(c, CS_UP);
176
}
177

  
178
static void
179
proto_pause_channels(struct proto *p)
171 180
{
172
  struct announce_hook *h;
181
  struct channel *c;
182
  WALK_LIST(c, p->channels)
183
    if (!c->disabled && channel_is_active(c))
184
      channel_set_state(c, CS_START);
185
}
173 186

  
174
  DBG("Connecting protocol %s to table %s\n", p->name, t->name);
175
  PD(p, "Connected to table %s", t->name);
187
static void
188
proto_stop_channels(struct proto *p)
189
{
190
  struct channel *c;
191
  WALK_LIST(c, p->channels)
192
    if (!c->disabled && channel_is_active(c))
193
      channel_set_state(c, CS_FLUSHING);
194
}
176 195

  
177
  h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
178
  h->table = t;
179
  h->proto = p;
180
  h->stats = stats;
196
static void
197
proto_remove_channels(struct proto *p)
198
{
199
  struct channel *c;
200
  WALK_LIST_FIRST(c, p->channels)
201
    proto_remove_channel(p, c);
202
}
203

  
204
static void
205
channel_schedule_feed(struct channel *c, int initial)
206
{
207
  // DBG("%s: Scheduling meal\n", p->name);
208
  ASSERT(c->channel_state == CS_UP);
181 209

  
182
  h->next = p->ahooks;
183
  p->ahooks = h;
210
  c->export_state = ES_FEEDING;
211
  c->refeeding = !initial;
184 212

  
185
  if (p->rt_notify && (p->export_state != ES_DOWN))
186
    add_tail(&t->hooks, &h->n);
187
  return h;
213
  ev_schedule(c->feed_event);
214
}
215

  
216
static void
217
channel_feed_loop(void *ptr)
218
{
219
  struct channel *c = ptr;
220

  
221
  if (c->export_state != ES_FEEDING)
222
    return;
223

  
224
  if (!c->feed_active)
225
    if (c->proto->feed_begin)
226
      c->proto->feed_begin(c, !c->refeeding);
227

  
228
  // DBG("Feeding protocol %s continued\n", p->name);
229
  if (!rt_feed_channel(c))
230
  {
231
    ev_schedule(c->feed_event);
232
    return;
233
  }
234

  
235
  // DBG("Feeding protocol %s finished\n", p->name);
236
  c->export_state = ES_READY;
237
  // proto_log_state_change(p);
238

  
239
  if (c->proto->feed_end)
240
    c->proto->feed_end(c);
241
}
242

  
243

  
244
static void
245
channel_start_export(struct channel *c)
246
{
247
  ASSERT(c->channel_state == CS_UP);
248
  ASSERT(c->export_state == ES_DOWN);
249

  
250
  channel_schedule_feed(c, 1);	/* Sets ES_FEEDING */
251
}
252

  
253
static void
254
channel_stop_export(struct channel *c)
255
{
256
  /* Need to abort feeding */
257
  if (c->export_state == ES_FEEDING)
258
    rt_feed_channel_abort(c);
259

  
260
  c->export_state = ES_DOWN;
261
}
262

  
263
static void
264
channel_do_start(struct channel *c)
265
{
266
  rt_lock_table(c->table);
267
  add_tail(&c->table->channels, &c->table_node);
268
  c->proto->active_channels++;
269

  
270
  c->feed_event = ev_new(c->proto->pool);
271
  c->feed_event->data = c;
272
  c->feed_event->hook = channel_feed_loop;
273

  
274
  channel_reset_limit(&c->rx_limit);
275
  channel_reset_limit(&c->in_limit);
276
  channel_reset_limit(&c->out_limit);
277

  
278
  CALL(c->channel->start, c);
279
}
280

  
281
static void
282
channel_do_flush(struct channel *c)
283
{
284
  rt_schedule_prune(c->table);
285

  
286
  c->gr_wait = 0;
287
  if (c->gr_lock)
288
    channel_graceful_restart_unlock(c);
289

  
290
  CALL(c->channel->shutdown, c);
291
}
292

  
293
static void
294
channel_do_down(struct channel *c)
295
{
296
  rem2_node(&c->table_node);
297
  rt_unlock_table(c->table);
298
  c->proto->active_channels--;
299

  
300
  if ((c->stats.imp_routes + c->stats.filt_routes) != 0)
301
    log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name);
302

  
303
  memset(&c->stats, 0, sizeof(struct proto_stats));
304

  
305
  /* Schedule protocol shutddown */
306
  if (proto_is_done(c->proto))
307
    ev_schedule(c->proto->event);
308
}
309

  
310
void
311
channel_set_state(struct channel *c, uint state)
312
{
313
  uint cs = c->channel_state;
314
  uint es = c->export_state;
315

  
316
  DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]);
317
  if (state == cs)
318
    return;
319

  
320
  c->channel_state = state;
321
  c->last_state_change = now;
322

  
323
  switch (state)
324
  {
325
  case CS_START:
326
    ASSERT(cs == CS_DOWN || cs == CS_UP);
327

  
328
    if (cs == CS_DOWN)
329
      channel_do_start(c);
330

  
331
    if (es != ES_DOWN)
332
      channel_stop_export(c);
333

  
334
    break;
335

  
336
  case CS_UP:
337
    ASSERT(cs == CS_DOWN || cs == CS_START);
338

  
339
    if (cs == CS_DOWN)
340
      channel_do_start(c);
341

  
342
    if (!c->gr_wait)
343
      channel_start_export(c);
344

  
345
    break;
346

  
347
  case CS_FLUSHING:
348
    ASSERT(cs == CS_START || cs == CS_UP);
349

  
350
    if (es != ES_DOWN)
351
      channel_stop_export(c);
352

  
353
    channel_do_flush(c);
354
    break;
355

  
356
  case CS_DOWN:
357
    ASSERT(cs == CS_FLUSHING);
358

  
359
    channel_do_down(c);
360
    break;
361

  
362
  default:
363
    ASSERT(0);
364
  }
365
  // XXXX proto_log_state_change(c);
188 366
}
189 367

  
190 368
/**
191
 * proto_find_announce_hook - find announce hooks
192
 * @p: protocol instance
193
 * @t: routing table
369
 * channel_request_feeding - request feeding routes to the channel
370
 * @c: given channel
194 371
 *
195
 * Returns pointer to announce hook or NULL
372
 * Sometimes it is needed to send again all routes to the channel. This is
373
 * called feeding and can be requested by this function. This would cause
374
 * channel export state transition to ES_FEEDING (during feeding) and when
375
 * completed, it will switch back to ES_READY. This function can be called
376
 * even when feeding is already running, in that case it is restarted.
196 377
 */
197
struct announce_hook *
198
proto_find_announce_hook(struct proto *p, struct rtable *t)
378
void
379
channel_request_feeding(struct channel *c)
199 380
{
200
  struct announce_hook *a;
381
  ASSERT(c->channel_state == CS_UP);
201 382

  
202
  for (a = p->ahooks; a; a = a->next)
203
    if (a->table == t)
204
      return a;
383
  /* Do nothing if we are still waiting for feeding */
384
  if (c->export_state == ES_DOWN)
385
    return;
205 386

  
206
  return NULL;
387
  /* If we are already feeding, we want to restart it */
388
  if (c->export_state == ES_FEEDING)
389
  {
390
    /* Unless feeding is in initial state */
391
    if (!c->feed_active)
392
	return;
393

  
394
    rt_feed_channel_abort(c);
395
  }
396

  
397
  channel_reset_limit(&c->out_limit);
398

  
399
  /* Hack: reset exp_routes during refeed, and do not decrease it later */
400
  c->stats.exp_routes = 0;
401

  
402
  channel_schedule_feed(c, 0);	/* Sets ES_FEEDING */
403
  // proto_log_state_change(c);
404
}
405

  
406
static inline int
407
channel_reloadable(struct channel *c)
408
{
409
  return c->proto->reload_routes && c->reloadable;
207 410
}
208 411

  
209 412
static void
210
proto_link_ahooks(struct proto *p)
413
channel_request_reload(struct channel *c)
211 414
{
212
  struct announce_hook *h;
415
  ASSERT(c->channel_state == CS_UP);
416
  // ASSERT(channel_reloadable(c));
417

  
418
  c->proto->reload_routes(c);
213 419

  
214
  if (p->rt_notify)
215
    for(h=p->ahooks; h; h=h->next)
216
      add_tail(&h->table->hooks, &h->n);
420
  /*
421
   * Should this be done before reload_routes() hook?
422
   * Perhaps, but routes are updated asynchronously.
423
   */
424
  channel_reset_limit(&c->rx_limit);
425
  channel_reset_limit(&c->in_limit);
217 426
}
218 427

  
219
static void
220
proto_unlink_ahooks(struct proto *p)
428
const struct channel_class channel_basic = {
429
  .channel_size = sizeof(struct channel),
430
  .config_size = sizeof(struct channel_config)
431
};
432

  
433
void *
434
channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto)
435
{
436
  struct channel_config *cf = NULL;
437
  struct rtable_config *tab = NULL;
438
  const char *name = NULL;
439

  
440
  if (net_type)
441
  {
442
    if (!net_val_match(net_type, proto->protocol->channel_mask))
443
      cf_error("Unsupported channel type");
444

  
445
    if (proto->net_type && (net_type != proto->net_type))
446
      cf_error("Different channel type");
447

  
448
    tab = new_config->def_tables[net_type];
449
    name = net_label[net_type];
450
  }
451

  
452
  if (!cc)
453
    cc = &channel_basic;
454

  
455
  cf = cfg_allocz(cc->config_size);
456
  cf->name = name;
457
  cf->channel = cc;
458
  cf->table = tab;
459
  cf->out_filter = FILTER_REJECT;
460

  
461
  cf->net_type = net_type;
462
  cf->ra_mode = RA_OPTIMAL;
463
  cf->preference = proto->protocol->preference;
464

  
465
  add_tail(&proto->channels, &cf->n);
466

  
467
  return cf;
468
}
469

  
470
struct channel_config *
471
channel_copy_config(struct channel_config *src, struct proto_config *proto)
472
{
473
  struct channel_config *dst = cfg_alloc(src->channel->config_size);
474

  
475
  memcpy(dst, src, src->channel->config_size);
476
  add_tail(&proto->channels, &dst->n);
477
  CALL(src->channel->copy_config, dst, src);
478

  
479
  return dst;
480
}
481

  
482

  
483
static int reconfigure_type;  /* Hack to propagate type info to channel_reconfigure() */
484

  
485
int
486
channel_reconfigure(struct channel *c, struct channel_config *cf)
487
{
488
  /* FIXME: better handle these changes, also handle in_keep_filtered */
489
  if ((c->table != cf->table->table) || (c->ra_mode != cf->ra_mode))
490
    return 0;
491

  
492
  int import_changed = !filter_same(c->in_filter, cf->in_filter);
493
  int export_changed = !filter_same(c->out_filter, cf->out_filter);
494

  
495
  if (c->preference != cf->preference)
496
    import_changed = 1;
497

  
498
  if (c->merge_limit != cf->merge_limit)
499
    export_changed = 1;
500

  
501
  /* Reconfigure channel fields */
502
  c->in_filter = cf->in_filter;
503
  c->out_filter = cf->out_filter;
504
  c->rx_limit = cf->rx_limit;
505
  c->in_limit = cf->in_limit;
506
  c->out_limit = cf->out_limit;
507

  
508
  // c->ra_mode = cf->ra_mode;
509
  c->merge_limit = cf->merge_limit;
510
  c->preference = cf->preference;
511
  c->in_keep_filtered = cf->in_keep_filtered;
512

  
513
  channel_verify_limits(c);
514

  
515
  CALL(c->channel->reconfigure, c, cf);
516

  
517
  /* If the channel is not open, it has no routes and we cannot reload it anyways */
518
  if (c->channel_state != CS_UP)
519
    return 1;
520

  
521
  if (reconfigure_type == RECONFIG_SOFT)
522
  {
523
    if (import_changed)
524
      log(L_INFO "Channel %s.%s changed import", c->proto->name, c->name);
525

  
526
    if (export_changed)
527
      log(L_INFO "Channel %s.%s changed export", c->proto->name, c->name);
528

  
529
    return 1;
530
  }
531

  
532
  /* Route reload may be not supported */
533
  if (import_changed && !channel_reloadable(c))
534
    return 0;
535

  
536
  if (import_changed || export_changed)
537
    log(L_INFO "Reloading channel %s.%s", c->proto->name, c->name);
538

  
539
  if (import_changed)
540
    channel_request_reload(c);
541

  
542
  if (export_changed)
543
    channel_request_feeding(c);
544

  
545
  return 1;
546
}
547

  
548

  
549
int
550
proto_configure_channel(struct proto *p, struct channel **pc, struct channel_config *cf)
221 551
{
222
  struct announce_hook *h;
552
  struct channel *c = *pc;
223 553

  
224
  if (p->rt_notify)
225
    for(h=p->ahooks; h; h=h->next)
226
      rem_node(&h->n);
554
  if (!c && cf)
555
  {
556
    *pc = proto_add_channel(p, cf);
557
  }
558
  else if (c && !cf)
559
  {
560
    if (c->channel_state != CS_DOWN)
561
    {
562
      log(L_INFO "Cannot remove channel %s.%s", c->proto->name, c->name);
563
      return 0;
564
    }
565

  
566
    proto_remove_channel(p, c);
567
    *pc = NULL;
568
  }
569
  else if (c && cf)
570
  {
571
    if (!channel_reconfigure(c, cf))
572
    {
573
      log(L_INFO "Cannot reconfigure channel %s.%s", c->proto->name, c->name);
574
      return 0;
575
    }
576
  }
577

  
578
  return 1;
227 579
}
228 580

  
581

  
229 582
static void
230
proto_free_ahooks(struct proto *p)
583
proto_event(void *ptr)
231 584
{
232
  struct announce_hook *h, *hn;
585
  struct proto *p = ptr;
586

  
587
  if (p->do_start)
588
  {
589
    if_feed_baby(p);
590
    p->do_start = 0;
591
  }
233 592

  
234
  for(h = p->ahooks; h; h = hn)
593
  if (p->do_stop)
235 594
  {
236
    hn = h->next;
237
    mb_free(h);
595
    if (p->proto == &proto_unix_iface)
596
      if_flush_ifaces(p);
597
    p->do_stop = 0;
238 598
  }
239 599

  
240
  p->ahooks = NULL;
241
  p->main_ahook = NULL;
600
  if (proto_is_done(p))
601
  {
602
    if (p->proto->cleanup)
603
      p->proto->cleanup(p);
604

  
605
    p->active = 0;
606
    proto_log_state_change(p);
607
    proto_rethink_goal(p);
608
  }
609
}
610

  
611

  
612
/**
613
 * proto_new - create a new protocol instance
614
 * @c: protocol configuration
615
 *
616
 * When a new configuration has been read in, the core code starts
617
 * initializing all the protocol instances configured by calling their
618
 * init() hooks with the corresponding instance configuration. The initialization
619
 * code of the protocol is expected to create a new instance according to the
620
 * configuration by calling this function and then modifying the default settings
621
 * to values wanted by the protocol.
622
 */
623
void *
624
proto_new(struct proto_config *cf)
625
{
626
  struct proto *p = mb_allocz(proto_pool, cf->protocol->proto_size);
627

  
628
  p->cf = cf;
629
  p->debug = cf->debug;
630
  p->mrtdump = cf->mrtdump;
631
  p->name = cf->name;
632
  p->proto = cf->protocol;
633
  p->net_type = cf->net_type;
634
  p->disabled = cf->disabled;
635
  p->hash_key = random_u32();
636
  cf->proto = p;
637

  
638
  init_list(&p->channels);
639

  
640
  return p;
641
}
642

  
643
static struct proto *
644
proto_init(struct proto_config *c, node *n)
645
{
646
  struct protocol *pr = c->protocol;
647
  struct proto *p = pr->init(c);
648

  
649
  p->proto_state = PS_DOWN;
650
  p->last_state_change = now;
651
  insert_node(&p->n, n);
652

  
653
  p->event = ev_new(proto_pool);
654
  p->event->hook = proto_event;
655
  p->event->data = p;
656

  
657
  PD(p, "Initializing%s", p->disabled ? " [disabled]" : "");
658

  
659
  return p;
660
}
661

  
662
static void
663
proto_start(struct proto *p)
664
{
665
  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
666
  p->pool = rp_new(proto_pool, p->proto->name);
667

  
668
  if (graceful_restart_state == GRS_INIT)
669
    p->gr_recovery = 1;
242 670
}
243 671

  
244 672

  
......
263 691
void *
264 692
proto_config_new(struct protocol *pr, int class)
265 693
{
266
  struct proto_config *c = cfg_allocz(pr->config_size);
694
  struct proto_config *cf = cfg_allocz(pr->config_size);
267 695

  
268 696
  if (class == SYM_PROTO)
269
    add_tail(&new_config->protos, &c->n);
270
  c->global = new_config;
271
  c->protocol = pr;
272
  c->name = pr->name;
273
  c->preference = pr->preference;
274
  c->class = class;
275
  c->out_filter = FILTER_REJECT;
276
  c->table = c->global->master_rtc;
277
  c->debug = new_config->proto_default_debug;
278
  c->mrtdump = new_config->proto_default_mrtdump;
279
  return c;
697
    add_tail(&new_config->protos, &cf->n);
698

  
699
  cf->global = new_config;
700
  cf->protocol = pr;
701
  cf->name = pr->name;
702
  cf->class = class;
703
  cf->debug = new_config->proto_default_debug;
704
  cf->mrtdump = new_config->proto_default_mrtdump;
705

  
706
  init_list(&cf->channels);
707

  
708
  return cf;
280 709
}
281 710

  
711

  
282 712
/**
283 713
 * proto_copy_config - copy a protocol configuration
284 714
 * @dest: destination protocol configuration
......
293 723
void
294 724
proto_copy_config(struct proto_config *dest, struct proto_config *src)
295 725
{
726
  struct channel_config *cc;
296 727
  node old_node;
297 728
  int old_class;
298 729
  char *old_name;
......
305 736

  
306 737
  DBG("Copying configuration from %s to %s\n", src->name, dest->name);
307 738

  
308
  /* 
739
  /*
309 740
   * Copy struct proto_config here. Keep original node, class and name.
310 741
   * protocol-specific config copy is handled by protocol copy_config() hook
311 742
   */
......
314 745
  old_class = dest->class;
315 746
  old_name = dest->name;
316 747

  
317
  memcpy(dest, src, sizeof(struct proto_config));
748
  memcpy(dest, src, src->protocol->config_size);
318 749

  
319 750
  dest->n = old_node;
320 751
  dest->class = old_class;
321 752
  dest->name = old_name;
753
  init_list(&dest->channels);
322 754

  
755
  WALK_LIST(cc, src->channels)
756
    channel_copy_config(cc, dest);
757

  
758
  /* FIXME: allow for undefined copy_config */
323 759
  dest->protocol->copy_config(dest, src);
324 760
}
325 761

  
......
339 775
  init_list(&c->protos);
340 776
  DBG("Protocol preconfig:");
341 777
  WALK_LIST(p, protocol_list)
342
    {
343
      DBG(" %s", p->name);
344
      p->name_counter = 0;
345
      if (p->preconfig)
346
	p->preconfig(p, c);
347
    }
348
  DBG("\n");
349
}
350

  
351
/**
352
 * protos_postconfig - post-configuration processing
353
 * @c: new configuration
354
 *
355
 * This function calls the postconfig() hooks of all protocol
356
 * instances specified in configuration @c. The hooks are not
357
 * called for protocol templates.
358
 */
359
void
360
protos_postconfig(struct config *c)
361
{
362
  struct proto_config *x;
363
  struct protocol *p;
364

  
365
  DBG("Protocol postconfig:");
366
  WALK_LIST(x, c->protos)
367
    {
368
      DBG(" %s", x->name);
369

  
370
      p = x->protocol;
371
      if (p->postconfig)
372
	p->postconfig(x);
373
    }
778
  {
779
    DBG(" %s", p->name);
780
    p->name_counter = 0;
781
    if (p->preconfig)
782
      p->preconfig(p, c);
783
  }
374 784
  DBG("\n");
375 785
}
376 786

  
377
extern struct protocol proto_unix_iface;
378

  
379
static struct proto *
380
proto_init(struct proto_config *c)
381
{
382
  struct protocol *p = c->protocol;
383
  struct proto *q = p->init(c);
384

  
385
  q->proto_state = PS_DOWN;
386
  q->core_state = FS_HUNGRY;
387
  q->export_state = ES_DOWN;
388
  q->last_state_change = now;
389

  
390
  add_tail(&initial_proto_list, &q->n);
391

  
392
  if (p == &proto_unix_iface)
393
    initial_device_proto = q;
394

  
395
  add_tail(&proto_list, &q->glob_node);
396
  PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
397
  return q;
398
}
399

  
400
int proto_reconfig_type;  /* Hack to propagate type info to pipe reconfigure hook */
401

  
402 787
static int
403 788
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
404 789
{
......
408 793

  
409 794
  /* If there is a too big change in core attributes, ... */
410 795
  if ((nc->protocol != oc->protocol) ||
411
      (nc->disabled != p->disabled) ||
412
      (nc->table->table != oc->table->table))
796
      (nc->net_type != oc->net_type) ||
797
      (nc->disabled != p->disabled))
798

  
413 799
    return 0;
414 800

  
801
  p->name = nc->name;
415 802
  p->debug = nc->debug;
416 803
  p->mrtdump = nc->mrtdump;
417
  proto_reconfig_type = type;
804
  reconfigure_type = type;
418 805

  
419 806
  /* Execute protocol specific reconfigure hook */
420
  if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
807
  if (!p->proto->reconfigure || !p->proto->reconfigure(p, nc))
421 808
    return 0;
422 809

  
423 810
  DBG("\t%s: same\n", oc->name);
424 811
  PD(p, "Reconfigured");
425 812
  p->cf = nc;
426
  p->name = nc->name;
427
  p->preference = nc->preference;
428

  
429

  
430
  /* Multitable protocols handle rest in their reconfigure hooks */
431
  if (p->proto->multitable)
432
    return 1;
433

  
434
  /* Update filters and limits in the main announce hook
435
     Note that this also resets limit state */
436
  if (p->main_ahook)
437
    {  
438
      struct announce_hook *ah = p->main_ahook;
439
      ah->in_filter = nc->in_filter;
440
      ah->out_filter = nc->out_filter;
441
      ah->rx_limit = nc->rx_limit;
442
      ah->in_limit = nc->in_limit;
443
      ah->out_limit = nc->out_limit;
444
      ah->in_keep_filtered = nc->in_keep_filtered;
445
      proto_verify_limits(ah);
446
    }
447

  
448
  /* Update routes when filters changed. If the protocol in not UP,
449
     it has no routes and we can ignore such changes */
450
  if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
451
    return 1;
452

  
453
  int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
454
  int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
455

  
456
  /* We treat a change in preferences by reimporting routes */
457
  if (nc->preference != oc->preference)
458
    import_changed = 1;
459

  
460
  if (import_changed || export_changed)
461
    log(L_INFO "Reloading protocol %s", p->name);
462

  
463
  /* If import filter changed, call reload hook */
464
  if (import_changed && ! (p->reload_routes && p->reload_routes(p)))
465
    {
466
      /* Now, the protocol is reconfigured. But route reload failed
467
	 and we have to do regular protocol restart. */
468
      log(L_INFO "Restarting protocol %s", p->name);
469
      p->disabled = 1;
470
      p->down_code = PDC_CF_RESTART;
471
      proto_rethink_goal(p);
472
      p->disabled = 0;
473
      proto_rethink_goal(p);
474
      return 1;
475
    }
476

  
477
  if (export_changed)
478
    proto_request_feeding(p);
479 813

  
480 814
  return 1;
481 815
}
......
512 846
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
513 847
{
514 848
  struct proto_config *oc, *nc;
515
  struct proto *p, *n;
516 849
  struct symbol *sym;
850
  struct proto *p;
851
  node *n;
852

  
517 853

  
518 854
  DBG("protos_commit:\n");
519 855
  if (old)
856
  {
857
    WALK_LIST(oc, old->protos)
520 858
    {
521
      WALK_LIST(oc, old->protos)
522
	{
523
	  p = oc->proto;
524
	  sym = cf_find_symbol(new, oc->name);
525
	  if (sym && sym->class == SYM_PROTO && !new->shutdown)
526
	    {
527
	      /* Found match, let's check if we can smoothly switch to new configuration */
528
	      /* No need to check description */
529
	      nc = sym->def;
530
	      nc->proto = p;
531

  
532
	      /* We will try to reconfigure protocol p */
533
	      if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
534
		continue;
535

  
536
	      /* Unsuccessful, we will restart it */
537
	      if (!p->disabled && !nc->disabled)
538
		log(L_INFO "Restarting protocol %s", p->name);
539
	      else if (p->disabled && !nc->disabled)
540
		log(L_INFO "Enabling protocol %s", p->name);
541
	      else if (!p->disabled && nc->disabled)
542
		log(L_INFO "Disabling protocol %s", p->name);
543

  
544
	      p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
545
	      p->cf_new = nc;
546
	    }
547
	  else if (!new->shutdown)
548
	    {
549
	      log(L_INFO "Removing protocol %s", p->name);
550
	      p->down_code = PDC_CF_REMOVE;
551
	      p->cf_new = NULL;
552
	    }
553
	  else /* global shutdown */
554
	    {
555
	      p->down_code = PDC_CMD_SHUTDOWN;
556
	      p->cf_new = NULL;
557
	    }
558

  
559
	  p->reconfiguring = 1;
560
	  config_add_obstacle(old);
561
	  proto_rethink_goal(p);
562
	}
859
      p = oc->proto;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff