bgpd, change peer config handling

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

bgpd, change peer config handling

Claudio Jeker
Move the struct peer into bgpd_config and switch it to a TAILQ instead of
the hand-rolled list. This changes the way peers are reloaded since now
both parent and session engine are now merging the lists.

If you are using neighbor templates you should really test this diff since
it may fix problems when switching from a templated peer to a fully
confiured one. All other users are also invited to test this :)

--
:wq Claudio

Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
retrieving revision 1.213
diff -u -p -r1.213 bgpd.c
--- bgpd.c 7 Mar 2019 07:42:36 -0000 1.213
+++ bgpd.c 14 Mar 2019 11:11:57 -0000
@@ -43,7 +43,7 @@ __dead void usage(void);
 int main(int, char *[]);
 pid_t start_child(enum bgpd_process, char *, int, int, int);
 int send_filterset(struct imsgbuf *, struct filter_set_head *);
-int reconfigure(char *, struct bgpd_config *, struct peer **);
+int reconfigure(char *, struct bgpd_config *);
 int dispatch_imsg(struct imsgbuf *, int, struct bgpd_config *);
 int control_setup(struct bgpd_config *);
 int imsg_send_sockets(struct imsgbuf *, struct imsgbuf *);
@@ -100,7 +100,6 @@ int
 main(int argc, char *argv[])
 {
  struct bgpd_config *conf;
- struct peer *peer_l, *p;
  struct rde_rib *rr;
  struct pollfd pfd[POLL_MAX];
  time_t timeout;
@@ -125,8 +124,6 @@ main(int argc, char *argv[])
  if (saved_argv0 == NULL)
  saved_argv0 = "bgpd";
 
- peer_l = NULL;
-
  while ((ch = getopt(argc, argv, "cdD:f:nRSv")) != -1) {
  switch (ch) {
  case 'c':
@@ -169,20 +166,14 @@ main(int argc, char *argv[])
  usage();
 
  if (cmd_opts & BGPD_OPT_NOACTION) {
- conf = new_config();
- if (parse_config(conffile, conf, &peer_l))
+ if ((conf = parse_config(conffile, NULL)) == NULL)
  exit(1);
 
  if (cmd_opts & BGPD_OPT_VERBOSE)
- print_config(conf, &ribnames, &conf->networks, peer_l,
-    conf->filters, conf->mrt, &conf->l3vpns);
+ print_config(conf, &ribnames);
  else
  fprintf(stderr, "configuration OK\n");
 
- while ((p = peer_l) != NULL) {
- peer_l = p->next;
- free(p);
- }
  while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
  SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
  free(rr);
@@ -261,7 +252,7 @@ BROKEN if (pledge("stdio rpath wpath cpa
  if (imsg_send_sockets(ibuf_se, ibuf_rde))
  fatal("could not establish imsg links");
  conf = new_config();
- quit = reconfigure(conffile, conf, &peer_l);
+ quit = reconfigure(conffile, conf);
  if (pftable_clear_all() != 0)
  quit = 1;
 
@@ -317,7 +308,7 @@ BROKEN if (pledge("stdio rpath wpath cpa
  u_int error;
 
  reconfig = 0;
- switch (reconfigure(conffile, conf, &peer_l)) {
+ switch (reconfigure(conffile, conf)) {
  case -1: /* fatal error */
  quit = 1;
  break;
@@ -358,10 +349,6 @@ BROKEN if (pledge("stdio rpath wpath cpa
  ibuf_rde = NULL;
  }
 
- while ((p = peer_l) != NULL) {
- peer_l = p->next;
- free(p);
- }
  while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
  SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
  free(rr);
@@ -451,8 +438,9 @@ send_filterset(struct imsgbuf *i, struct
 }
 
 int
-reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l)
+reconfigure(char *conffile, struct bgpd_config *conf)
 {
+ struct bgpd_config *new_conf;
  struct peer *p;
  struct filter_rule *r;
  struct listen_addr *la;
@@ -469,12 +457,13 @@ reconfigure(char *conffile, struct bgpd_
  reconfpending = 2; /* one per child */
 
  log_info("rereading config");
- if (parse_config(conffile, conf, peer_l)) {
+ if ((new_conf = parse_config(conffile, &conf->peers)) == NULL) {
  log_warnx("config file %s has errors, not reloading",
     conffile);
  reconfpending = 0;
  return (1);
  }
+ merge_config(conf, new_conf);
 
  if (prepare_listeners(conf) == -1) {
  reconfpending = 0;
@@ -524,7 +513,7 @@ reconfigure(char *conffile, struct bgpd_
  }
 
  /* send peer list to the SE */
- for (p = *peer_l; p != NULL; p = p->next) {
+ TAILQ_FOREACH(p, &conf->peers, entry) {
  if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1,
     &p->conf, sizeof(struct peer_config)) == -1)
  return (-1);
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.377
diff -u -p -r1.377 bgpd.h
--- bgpd.h 7 Mar 2019 07:42:36 -0000 1.377
+++ bgpd.h 14 Mar 2019 10:40:33 -0000
@@ -231,6 +231,9 @@ struct listen_addr {
 TAILQ_HEAD(listen_addrs, listen_addr);
 TAILQ_HEAD(filter_set_head, filter_set);
 
+struct peer;
+TAILQ_HEAD(peer_head, peer);
+
 struct l3vpn;
 SIMPLEQ_HEAD(l3vpn_head, l3vpn);
 
@@ -267,6 +270,7 @@ struct filter_rule;
 TAILQ_HEAD(filter_head, filter_rule);
 
 struct bgpd_config {
+ struct peer_head peers;
  struct l3vpn_head l3vpns;
  struct network_head networks;
  struct filter_head *filters;
@@ -376,7 +380,6 @@ struct peer_config {
  enum export_type export_type;
  enum enforce_as enforce_as;
  enum enforce_as enforce_local_as;
- enum reconf_action reconf_action;
  u_int16_t max_prefix_restart;
  u_int16_t holdtime;
  u_int16_t min_holdtime;
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
retrieving revision 1.86
diff -u -p -r1.86 config.c
--- config.c 15 Mar 2019 09:54:54 -0000 1.86
+++ config.c 15 Mar 2019 10:47:02 -0000
@@ -54,6 +54,7 @@ new_config(void)
  fatal(NULL);
 
  /* init the various list for later */
+ TAILQ_INIT(&conf->peers);
  TAILQ_INIT(&conf->networks);
  SIMPLEQ_INIT(&conf->l3vpns);
  SIMPLEQ_INIT(&conf->prefixsets);
@@ -156,6 +157,7 @@ free_prefixtree(struct prefixset_tree *p
 void
 free_config(struct bgpd_config *conf)
 {
+ struct peer *p;
  struct listen_addr *la;
  struct mrt *m;
 
@@ -181,6 +183,11 @@ free_config(struct bgpd_config *conf)
  }
  free(conf->mrt);
 
+ while ((p = TAILQ_FIRST(&conf->peers)) != NULL) {
+ TAILQ_REMOVE(&conf->peers, p, entry);
+ free(p);
+ }
+
  free(conf->csock);
  free(conf->rcsock);
 
@@ -188,11 +195,11 @@ free_config(struct bgpd_config *conf)
 }
 
 void
-merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
-    struct peer *peer_l)
+merge_config(struct bgpd_config *xconf, struct bgpd_config *conf)
 {
  struct listen_addr *nla, *ola, *next;
  struct network *n;
+ struct peer *p, *np;
 
  /*
  * merge the freshly parsed conf into the running xconf
@@ -298,6 +305,26 @@ merge_config(struct bgpd_config *xconf,
  free(nla);
  }
  }
+
+ /*
+ * merge peers:
+ * - need to know which peers are new, replaced and removed
+ * - first mark all new peers as RECONF_REINIT
+ * - walk over old peers and check if there is a corresponding new
+ *   peer if so mark it RECONF_KEEP. Remove all old peers.
+ * - swap lists (old peer list is actually empty).
+ */
+ TAILQ_FOREACH(p, &conf->peers, entry)
+ p->reconf_action = RECONF_REINIT;
+ while ((p = TAILQ_FIRST(&xconf->peers)) != NULL) {
+ np = getpeerbyid(conf, p->conf.id);
+ if (np != NULL)
+ np->reconf_action = RECONF_KEEP;
+
+ TAILQ_REMOVE(&xconf->peers, p, entry);
+ free(p);
+ }
+ TAILQ_CONCAT(&xconf->peers, &conf->peers, entry);
 
  /* conf is merged so free it */
  free_config(conf);
Index: control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.95
diff -u -p -r1.95 control.c
--- control.c 12 Feb 2019 13:30:39 -0000 1.95
+++ control.c 14 Mar 2019 10:42:22 -0000
@@ -220,7 +220,8 @@ control_close(int fd)
 }
 
 int
-control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
+control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt,
+    struct peer_head *peers)
 {
  struct imsg imsg;
  struct ctl_conn *c;
@@ -294,7 +295,7 @@ control_dispatch_msg(struct pollfd *pfd,
     0, NULL, 0);
  break;
  case IMSG_CTL_SHOW_TERSE:
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, peers, entry)
  imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR,
     0, 0, -1, p, sizeof(struct peer));
  imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, NULL, 0);
@@ -309,7 +310,8 @@ control_dispatch_msg(struct pollfd *pfd,
  } else {
  neighbor = NULL;
  }
- for (matched = 0, p = peers; p != NULL; p = p->next) {
+ matched = 0;
+ TAILQ_FOREACH(p, peers, entry) {
  if (!peer_matched(p, neighbor))
  continue;
 
@@ -337,7 +339,7 @@ control_dispatch_msg(struct pollfd *pfd,
  }
  }
  }
- if (!matched && peers != NULL) {
+ if (!matched && TAILQ_EMPTY(peers)) {
  control_result(c, CTL_RES_NOSUCHPEER);
  } else if (!neighbor || !neighbor->show_timers) {
  imsg_ctl_rde(IMSG_CTL_END, imsg.hdr.pid,
@@ -362,7 +364,8 @@ control_dispatch_msg(struct pollfd *pfd,
  neighbor = imsg.data;
  neighbor->descr[PEER_DESCR_LEN - 1] = 0;
 
- for (matched = 0, p = peers; p != NULL; p = p->next) {
+ matched = 0;
+ TAILQ_FOREACH(p, peers, entry) {
  if (!peer_matched(p, neighbor))
  continue;
 
@@ -417,7 +420,7 @@ control_dispatch_msg(struct pollfd *pfd,
  * Mark as deleted, will be
  * collected on next poll loop.
  */
- p->conf.reconf_action =
+ p->reconf_action =
     RECONF_DELETE;
  control_result(c, CTL_RES_OK);
  }
@@ -458,10 +461,10 @@ control_dispatch_msg(struct pollfd *pfd,
  neighbor->descr[PEER_DESCR_LEN - 1] = 0;
 
  /* check if at least one neighbor exists */
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, peers, entry)
  if (peer_matched(p, neighbor))
  break;
- if (p == NULL && peers != NULL) {
+ if (p == NULL && TAILQ_EMPTY(peers)) {
  control_result(c, CTL_RES_NOSUCHPEER);
  break;
  }
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.384
diff -u -p -r1.384 parse.y
--- parse.y 15 Mar 2019 09:54:54 -0000 1.384
+++ parse.y 15 Mar 2019 10:47:45 -0000
@@ -88,7 +88,7 @@ char *symget(const char *);
 
 static struct bgpd_config *conf;
 static struct network_head *netconf;
-static struct peer *peer_l, *peer_l_old;
+static struct peer_head *new_peers, *cur_peers;
 static struct peer *curpeer;
 static struct peer *curgroup;
 static struct l3vpn *curvpn;
@@ -99,7 +99,6 @@ static struct filter_head *peerfilter_l;
 static struct filter_head *groupfilter_l;
 static struct filter_rule *curpeer_filter[2];
 static struct filter_rule *curgroup_filter[2];
-static u_int32_t id;
 
 struct filter_rib_l {
  struct filter_rib_l *next;
@@ -1203,8 +1202,7 @@ neighbor : { curpeer = new_peer(); }
 
  if (neighbor_consistent(curpeer) == -1)
  YYERROR;
- curpeer->next = peer_l;
- peer_l = curpeer;
+ TAILQ_INSERT_TAIL(new_peers, curpeer, entry);
  curpeer = curgroup;
  }
  ;
@@ -1812,7 +1810,7 @@ filter_peer : ANY {
  fatal(NULL);
  $$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
  $$->next = NULL;
- for (p = peer_l; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, new_peers, entry)
  if (!memcmp(&p->conf.remote_addr,
     &$1, sizeof(p->conf.remote_addr))) {
  $$->p.peerid = p->conf.id;
@@ -1839,7 +1837,7 @@ filter_peer : ANY {
  fatal(NULL);
  $$->p.remote_as = $$->p.peerid = 0;
  $$->next = NULL;
- for (p = peer_l; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, new_peers, entry)
  if (!strcmp(p->conf.group, $2)) {
  $$->p.groupid = p->conf.groupid;
  break;
@@ -3263,11 +3261,10 @@ init_config(struct bgpd_config *c)
  fatal(NULL);
 }
 
-int
-parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers)
+struct bgpd_config *
+parse_config(char *filename, struct peer_head *ph)
 {
  struct sym *sym, *next;
- struct peer *p, *pnext;
  struct rde_rib *rr;
  struct network       *n;
  int errors = 0;
@@ -3285,12 +3282,11 @@ parse_config(char *filename, struct bgpd
  TAILQ_INIT(peerfilter_l);
  TAILQ_INIT(groupfilter_l);
 
- peer_l = NULL;
- peer_l_old = *xpeers;
  curpeer = NULL;
  curgroup = NULL;
- id = 1;
 
+ cur_peers = ph;
+ new_peers = &conf->peers;
  netconf = &conf->networks;
 
  add_rib("Adj-RIB-In", conf->default_tableid,
@@ -3334,13 +3330,15 @@ parse_config(char *filename, struct bgpd
  errors++;
  }
 
+ /* clear the globals */
+ curpeer = NULL;
+ curgroup = NULL;
+ cur_peers = NULL;
+ new_peers = NULL;
+ netconf = NULL;
+
  if (errors) {
 errors:
- for (p = peer_l; p != NULL; p = pnext) {
- pnext = p->next;
- free(p);
- }
-
  while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
  SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
  free(rr);
@@ -3351,7 +3349,7 @@ errors:
  filterlist_free(groupfilter_l);
 
  free_config(conf);
- return -1;
+ return (NULL);
  } else {
  /*
  * Concatenate filter list and static group and peer filtersets
@@ -3364,18 +3362,11 @@ errors:
 
  optimize_filters(conf->filters);
 
- merge_config(xconf, conf, peer_l);
- *xpeers = peer_l;
-
- for (p = peer_l_old; p != NULL; p = pnext) {
- pnext = p->next;
- free(p);
- }
-
  free(filter_l);
  free(peerfilter_l);
  free(groupfilter_l);
- return 0;
+
+ return (conf);
  }
 }
 
@@ -3784,7 +3775,6 @@ alloc_peer(void)
 
  /* some sane defaults */
  p->state = STATE_NONE;
- p->next = NULL;
  p->conf.distance = 1;
  p->conf.export_type = EXPORT_UNSET;
  p->conf.announce_capa = 1;
@@ -3796,6 +3786,9 @@ alloc_peer(void)
  p->conf.local_as = conf->as;
  p->conf.local_short_as = conf->short_as;
 
+ if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
+ p->conf.flags |= PEERFLAG_TRANS_AS;
+
  return (p);
 }
 
@@ -3818,9 +3811,6 @@ new_peer(void)
  p->conf.local_as = curgroup->conf.local_as;
  p->conf.local_short_as = curgroup->conf.local_short_as;
  }
- p->next = NULL;
- if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
- p->conf.flags |= PEERFLAG_TRANS_AS;
  return (p);
 }
 
@@ -3962,32 +3952,39 @@ find_prefixset(char *name, struct prefix
 int
 get_id(struct peer *newpeer)
 {
- struct peer *p;
+ static u_int32_t id = 1;
+ struct peer *p = NULL;
 
- for (p = peer_l_old; p != NULL; p = p->next)
- if (newpeer->conf.remote_addr.aid) {
- if (!memcmp(&p->conf.remote_addr,
-    &newpeer->conf.remote_addr,
-    sizeof(p->conf.remote_addr))) {
- newpeer->conf.id = p->conf.id;
- return (0);
- }
- } else { /* newpeer is a group */
- if (strcmp(newpeer->conf.group, p->conf.group) == 0) {
- newpeer->conf.id = p->conf.groupid;
- return (0);
- }
+ /* check if the peer already existed before */
+ if (newpeer->conf.remote_addr.aid) {
+ /* neighbor */
+ if (cur_peers)
+ TAILQ_FOREACH(p, cur_peers, entry)
+ if (memcmp(&p->conf.remote_addr,
+    &newpeer->conf.remote_addr,
+    sizeof(p->conf.remote_addr)) == 0)
+ break;
+ if (p) {
+ newpeer->conf.id = p->conf.id;
+ return (0);
  }
-
- /* new one */
- for (; id < UINT_MAX / 2; id++) {
- for (p = peer_l_old; p != NULL &&
-    p->conf.id != id && p->conf.groupid != id; p = p->next)
- ; /* nothing */
- if (p == NULL) { /* we found a free id */
- newpeer->conf.id = id++;
+ } else {
+ /* group */
+ if (cur_peers)
+ TAILQ_FOREACH(p, cur_peers, entry)
+ if (strcmp(p->conf.group,
+    newpeer->conf.group) == 0)
+ break;
+ if (p) {
+ newpeer->conf.id = p->conf.groupid;
  return (0);
  }
+ }
+
+ /* else new one */
+ if (id < UINT_MAX / 2) {
+ newpeer->conf.id = id++;
+ return (0);
  }
 
  return (-1);
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.133
diff -u -p -r1.133 printconf.c
--- printconf.c 15 Mar 2019 09:54:54 -0000 1.133
+++ printconf.c 15 Mar 2019 10:47:02 -0000
@@ -49,11 +49,11 @@ const char *print_auth_alg(u_int8_t);
 const char *print_enc_alg(u_int8_t);
 void print_announce(struct peer_config *, const char *);
 void print_as(struct filter_rule *);
-void print_rule(struct peer *, struct filter_rule *);
-const char *mrt_type(enum mrt_type);
+void print_rule(struct bgpd_config *, struct filter_rule *);
+const char * mrt_type(enum mrt_type);
 void print_mrt(struct bgpd_config *, u_int32_t, u_int32_t,
     const char *, const char *);
-void print_groups(struct bgpd_config *, struct peer *);
+void print_groups(struct bgpd_config *);
 int peer_compare(const void *, const void *);
 
 void
@@ -759,7 +759,7 @@ print_as(struct filter_rule *r)
 }
 
 void
-print_rule(struct peer *peer_l, struct filter_rule *r)
+print_rule(struct bgpd_config *conf, struct filter_rule *r)
 {
  struct peer *p;
  int i;
@@ -784,17 +784,17 @@ print_rule(struct peer *peer_l, struct f
  printf("eeeeeeeps. ");
 
  if (r->peer.peerid) {
- for (p = peer_l; p != NULL && p->conf.id != r->peer.peerid;
-    p = p->next)
- ; /* nothing */
+ TAILQ_FOREACH(p, &conf->peers, entry)
+ if (p->conf.id == r->peer.peerid)
+ break;
  if (p == NULL)
  printf("? ");
  else
  printf("%s ", log_addr(&p->conf.remote_addr));
  } else if (r->peer.groupid) {
- for (p = peer_l; p != NULL &&
-    p->conf.groupid != r->peer.groupid; p = p->next)
- ; /* nothing */
+ TAILQ_FOREACH(p, &conf->peers, entry)
+ if (p->conf.groupid == r->peer.groupid)
+ break;
  if (p == NULL)
  printf("group ? ");
  else
@@ -928,7 +928,7 @@ print_mrt(struct bgpd_config *conf, u_in
 }
 
 void
-print_groups(struct bgpd_config *conf, struct peer *peer_l)
+print_groups(struct bgpd_config *conf)
 {
  struct peer_config **peerlist;
  struct peer *p;
@@ -939,14 +939,14 @@ print_groups(struct bgpd_config *conf, s
  const char *c;
 
  peer_cnt = 0;
- for (p = peer_l; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &conf->peers, entry)
  peer_cnt++;
 
  if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL)
  fatal("print_groups calloc");
 
  i = 0;
- for (p = peer_l; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &conf->peers, entry)
  peerlist[i++] = &p->conf;
 
  qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare);
@@ -986,10 +986,7 @@ peer_compare(const void *aa, const void
 }
 
 void
-print_config(struct bgpd_config *conf, struct rib_names *rib_l,
-    struct network_head *net_l, struct peer *peer_l,
-    struct filter_head *rules_l, struct mrt_head *mrt_l,
-    struct l3vpn_head *vpns_l)
+print_config(struct bgpd_config *conf, struct rib_names *rib_l)
 {
  struct filter_rule *r;
  struct network *n;
@@ -1001,11 +998,11 @@ print_config(struct bgpd_config *conf, s
  print_as_sets(conf->as_sets);
  print_prefixsets(&conf->prefixsets);
  print_originsets(&conf->originsets);
- TAILQ_FOREACH(n, net_l, entry)
+ TAILQ_FOREACH(n, &conf->networks, entry)
  print_network(&n->net, "");
- if (!SIMPLEQ_EMPTY(vpns_l))
+ if (!SIMPLEQ_EMPTY(&conf->l3vpns))
  printf("\n");
- SIMPLEQ_FOREACH(vpn, vpns_l, entry)
+ SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
  print_l3vpn(vpn);
  printf("\n");
  SIMPLEQ_FOREACH(rr, rib_l, entry) {
@@ -1020,7 +1017,7 @@ print_config(struct bgpd_config *conf, s
  }
  printf("\n");
  print_mrt(conf, 0, 0, "", "");
- print_groups(conf, peer_l);
- TAILQ_FOREACH(r, rules_l, entry)
- print_rule(peer_l, r);
+ print_groups(conf);
+ TAILQ_FOREACH(r, conf->filters, entry)
+ print_rule(conf, r);
 }
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.376
diff -u -p -r1.376 session.c
--- session.c 15 Mar 2019 09:54:54 -0000 1.376
+++ session.c 15 Mar 2019 17:45:22 -0000
@@ -94,17 +94,15 @@ void session_up(struct peer *);
 void session_down(struct peer *);
 int imsg_rde(int, u_int32_t, void *, u_int16_t);
 void session_demote(struct peer *, int);
+void merge_peers(struct bgpd_config *, struct bgpd_config *);
 
 int la_cmp(struct listen_addr *, struct listen_addr *);
-struct peer *getpeerbyip(struct sockaddr *);
-struct peer *getpeerbyid(u_int32_t);
 void session_template_clone(struct peer *, struct sockaddr *,
     u_int32_t, u_int32_t);
 int session_match_mask(struct peer *, struct bgpd_addr *);
 
 struct bgpd_config *conf, *nconf;
 struct bgpd_sysdep sysdep;
-struct peer *peers, *npeers;
 volatile sig_atomic_t session_quit;
 int pending_reconf;
 int csock = -1, rcsock = -1;
@@ -196,7 +194,7 @@ session_main(int debug, int verbose)
  u_int listener_cnt, ctl_cnt, mrt_cnt;
  u_int new_cnt;
  struct passwd *pw;
- struct peer *p, **peer_l = NULL, *last, *next;
+ struct peer *p, **peer_l = NULL, *next;
  struct mrt *m, *xm, **mrt_l = NULL;
  struct pollfd *pfd = NULL;
  struct ctl_conn *ctl_conn;
@@ -251,46 +249,43 @@ session_main(int debug, int verbose)
 
  while (session_quit == 0) {
  /* check for peers to be initialized or deleted */
- last = NULL;
  if (!pending_reconf) {
- for (p = peers; p != NULL; p = next) {
- next = p->next;
+ for (p = TAILQ_FIRST(&conf->peers); p != NULL;
+   p = next) {
+ next = TAILQ_NEXT(p, entry);
  /* cloned peer that idled out? */
  if (p->template && (p->state == STATE_IDLE ||
     p->state == STATE_ACTIVE) &&
     time(NULL) - p->stats.last_updown >=
     INTERVAL_HOLD_CLONED)
- p->conf.reconf_action = RECONF_DELETE;
+ p->reconf_action = RECONF_DELETE;
 
  /* new peer that needs init? */
  if (p->state == STATE_NONE)
  init_peer(p);
 
  /* reinit due? */
- if (p->conf.reconf_action == RECONF_REINIT) {
+ if (p->reconf_action == RECONF_REINIT) {
  session_stop(p, ERR_CEASE_ADMIN_RESET);
  if (!p->conf.down)
  timer_set(p, Timer_IdleHold, 0);
  }
 
  /* deletion due? */
- if (p->conf.reconf_action == RECONF_DELETE) {
+ if (p->reconf_action == RECONF_DELETE) {
  if (p->demoted)
  session_demote(p, -1);
  p->conf.demote_group[0] = 0;
  session_stop(p, ERR_CEASE_PEER_UNCONF);
  log_peer_warnx(&p->conf, "removed");
- if (last != NULL)
- last->next = next;
- else
- peers = next;
+ TAILQ_REMOVE(&conf->peers, p, entry);
  timer_remove_all(p);
+ pfkey_remove(p);
  free(p);
  peer_cnt--;
  continue;
  }
- p->conf.reconf_action = RECONF_NONE;
- last = p;
+ p->reconf_action = RECONF_NONE;
  }
  }
 
@@ -375,7 +370,7 @@ session_main(int debug, int verbose)
  idx_listeners = i;
  timeout = 240; /* loop every 240s at least */
 
- for (p = peers; p != NULL; p = p->next) {
+ TAILQ_FOREACH(p, &conf->peers, entry) {
  time_t nextaction;
  struct peer_timer *pt;
 
@@ -526,7 +521,7 @@ session_main(int debug, int verbose)
  session_dispatch_msg(&pfd[j],
     peer_l[j - idx_listeners]);
 
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &conf->peers, entry)
  if (p->rbuf && p->rbuf->wpos)
  session_process_msg(p);
 
@@ -535,11 +530,11 @@ session_main(int debug, int verbose)
  mrt_write(mrt_l[j - idx_peers]);
 
  for (; j < i; j++)
- control_dispatch_msg(&pfd[j], &ctl_cnt);
+ control_dispatch_msg(&pfd[j], &ctl_cnt, &conf->peers);
  }
 
- while ((p = peers) != NULL) {
- peers = p->next;
+ while ((p = TAILQ_FIRST(&conf->peers)) != NULL) {
+ TAILQ_REMOVE(&conf->peers, p, entry);
  strlcpy(p->conf.shutcomm,
     "bgpd shutting down",
     sizeof(p->conf.shutcomm));
@@ -608,7 +603,7 @@ init_peer(struct peer *p)
  * do not handle new peers. they must reach ESTABLISHED beforehands.
  * peers added at runtime have reconf_action set to RECONF_REINIT.
  */
- if (p->conf.reconf_action != RECONF_REINIT && p->conf.demote_group[0])
+ if (p->reconf_action != RECONF_REINIT && p->conf.demote_group[0])
  session_demote(p, +1);
 }
 
@@ -1008,7 +1003,7 @@ session_accept(int listenfd)
  return;
  }
 
- p = getpeerbyip((struct sockaddr *)&cliaddr);
+ p = getpeerbyip(conf, (struct sockaddr *)&cliaddr);
 
  if (p != NULL && p->state == STATE_IDLE && p->errcnt < 2) {
  if (timer_running(p, Timer_IdleHold, NULL)) {
@@ -1523,7 +1518,7 @@ session_update(u_int32_t peerid, void *d
  struct peer *p;
  struct bgp_msg *buf;
 
- if ((p = getpeerbyid(peerid)) == NULL) {
+ if ((p = getpeerbyid(conf, peerid)) == NULL) {
  log_warnx("no such peer: id=%u", peerid);
  return;
  }
@@ -2555,12 +2550,10 @@ session_dispatch_imsg(struct imsgbuf *ib
  struct mrt xmrt;
  struct mrt *mrt;
  struct imsgbuf *i;
- struct peer_config *pconf;
- struct peer *p, *next;
+ struct peer *p;
  struct listen_addr *la, *nla;
  struct kif *kif;
  u_char *data;
- enum reconf_action reconf;
  int n, fd, depend_ok, restricted;
  u_int8_t aid, errcode, subcode;
 
@@ -2606,7 +2599,6 @@ session_dispatch_imsg(struct imsgbuf *ib
  if (idx != PFD_PIPE_MAIN)
  fatalx("reconf request not from parent");
  nconf = new_config();
- npeers = NULL;
 
  copy_config(nconf, imsg.data);
  pending_reconf = 1;
@@ -2614,45 +2606,12 @@ session_dispatch_imsg(struct imsgbuf *ib
  case IMSG_RECONF_PEER:
  if (idx != PFD_PIPE_MAIN)
  fatalx("reconf request not from parent");
- pconf = imsg.data;
- p = getpeerbyaddr(&pconf->remote_addr);
- if (p == NULL) {
- if ((p = calloc(1, sizeof(struct peer))) ==
-    NULL)
- fatal("new_peer");
- p->state = p->prev_state = STATE_NONE;
- p->next = npeers;
- npeers = p;
- reconf = RECONF_REINIT;
- } else
- reconf = RECONF_KEEP;
-
- memcpy(&p->conf, pconf, sizeof(struct peer_config));
- p->conf.reconf_action = reconf;
-
- /* sync the RDE in case we keep the peer */
- if (reconf == RECONF_KEEP) {
- if (imsg_rde(IMSG_SESSION_ADD, p->conf.id,
-    &p->conf, sizeof(struct peer_config)) == -1)
- fatalx("imsg_compose error");
- if (p->conf.template) {
- /* apply the conf to all clones */
- struct peer *np;
- for (np = peers; np; np = np->next) {
- if (np->template != p)
- continue;
- session_template_clone(np,
-    NULL, np->conf.id,
-    np->conf.remote_as);
- if (imsg_rde(IMSG_SESSION_ADD,
-    np->conf.id, &np->conf,
-    sizeof(struct peer_config))
-    == -1)
- fatalx("imsg_compose"
-    " error");
- }
- }
- }
+ if ((p = calloc(1, sizeof(struct peer))) == NULL)
+ fatal("new_peer");
+ memcpy(&p->conf, imsg.data, sizeof(struct peer_config));
+ p->state = p->prev_state = STATE_NONE;
+ p->reconf_action = RECONF_REINIT;
+ TAILQ_INSERT_TAIL(&nconf->peers, p, entry);
  break;
  case IMSG_RECONF_LISTENER:
  if (idx != PFD_PIPE_MAIN)
@@ -2723,23 +2682,7 @@ session_dispatch_imsg(struct imsgbuf *ib
  if (nconf == NULL)
  fatalx("got IMSG_RECONF_DONE but no config");
  copy_config(conf, nconf);
-
- /* add new peers */
- for (p = npeers; p != NULL; p = next) {
- next = p->next;
- p->next = peers;
- peers = p;
- }
- /* find ones that need attention */
- for (p = peers; p != NULL; p = p->next) {
- /* needs to be deleted? */
- if (p->conf.reconf_action == RECONF_NONE &&
-    !p->template)
- p->conf.reconf_action = RECONF_DELETE;
- /* had demotion, is demoted, demote removed? */
- if (p->demoted && !p->conf.demote_group[0])
- session_demote(p, -1);
- }
+ merge_peers(conf, nconf);
 
  /* delete old listeners */
  for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL;
@@ -2781,7 +2724,7 @@ session_dispatch_imsg(struct imsgbuf *ib
  kif = imsg.data;
  depend_ok = kif->depend_state;
 
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &conf->peers, entry)
  if (!strcmp(p->conf.if_depend, kif->ifname)) {
  if (depend_ok && !p->depend_ok) {
  p->depend_ok = depend_ok;
@@ -2876,7 +2819,7 @@ session_dispatch_imsg(struct imsgbuf *ib
  log_warnx("RDE sent invalid notification");
  break;
  }
- if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) {
+ if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) {
  log_warnx("no such peer: id=%u",
     imsg.hdr.peerid);
  break;
@@ -2916,7 +2859,7 @@ session_dispatch_imsg(struct imsgbuf *ib
  log_warnx("RDE sent invalid restart msg");
  break;
  }
- if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) {
+ if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) {
  log_warnx("no such peer: id=%u",
     imsg.hdr.peerid);
  break;
@@ -2943,7 +2886,7 @@ session_dispatch_imsg(struct imsgbuf *ib
  case IMSG_SESSION_DOWN:
  if (idx != PFD_PIPE_ROUTE)
  fatalx("update request not from RDE");
- if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) {
+ if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) {
  log_warnx("no such peer: id=%u",
     imsg.hdr.peerid);
  break;
@@ -2993,26 +2936,12 @@ la_cmp(struct listen_addr *a, struct lis
 }
 
 struct peer *
-getpeerbyaddr(struct bgpd_addr *addr)
-{
- struct peer *p;
-
- /* we might want a more effective way to find peers by IP */
- for (p = peers; p != NULL &&
-    memcmp(&p->conf.remote_addr, addr, sizeof(p->conf.remote_addr));
-    p = p->next)
- ; /* nothing */
-
- return (p);
-}
-
-struct peer *
-getpeerbydesc(const char *descr)
+getpeerbydesc(struct bgpd_config *c, const char *descr)
 {
  struct peer *p, *res = NULL;
  int match = 0;
 
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &c->peers, entry)
  if (!strcmp(p->conf.descr, descr)) {
  res = p;
  match++;
@@ -3029,7 +2958,7 @@ getpeerbydesc(const char *descr)
 }
 
 struct peer *
-getpeerbyip(struct sockaddr *ip)
+getpeerbyip(struct bgpd_config *c, struct sockaddr *ip)
 {
  struct bgpd_addr addr;
  struct peer *p, *newpeer, *loose = NULL;
@@ -3038,13 +2967,13 @@ getpeerbyip(struct sockaddr *ip)
  sa2addr(ip, &addr, NULL);
 
  /* we might want a more effective way to find peers by IP */
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &c->peers, entry)
  if (!p->conf.template &&
     !memcmp(&addr, &p->conf.remote_addr, sizeof(addr)))
  return (p);
 
  /* try template matching */
- for (p = peers; p != NULL; p = p->next)
+ TAILQ_FOREACH(p, &c->peers, entry)
  if (p->conf.template &&
     p->conf.remote_addr.aid == addr.aid &&
     session_match_mask(p, &addr))
@@ -3058,22 +2987,20 @@ getpeerbyip(struct sockaddr *ip)
  fatal(NULL);
  memcpy(newpeer, loose, sizeof(struct peer));
  for (id = UINT_MAX; id > UINT_MAX / 2; id--) {
- for (p = peers; p != NULL && p->conf.id != id;
-    p = p->next)
- ; /* nothing */
- if (p == NULL) { /* we found a free id */
+ TAILQ_FOREACH(p, &c->peers, entry)
+ if (p->conf.id == id)
+ break;
+ if (p == NULL) /* we found a free id */
  break;
- }
  }
  newpeer->template = loose;
  session_template_clone(newpeer, ip, id, 0);
  newpeer->state = newpeer->prev_state = STATE_NONE;
- newpeer->conf.reconf_action = RECONF_KEEP;
+ newpeer->reconf_action = RECONF_KEEP;
  newpeer->rbuf = NULL;
  init_peer(newpeer);
  bgp_fsm(newpeer, EVNT_START);
- newpeer->next = peers;
- peers = newpeer;
+ TAILQ_INSERT_TAIL(&c->peers, newpeer, entry);
  return (newpeer);
  }
 
@@ -3081,16 +3008,15 @@ getpeerbyip(struct sockaddr *ip)
 }
 
 struct peer *
-getpeerbyid(u_int32_t peerid)
+getpeerbyid(struct bgpd_config *c, u_int32_t peerid)
 {
  struct peer *p;
 
- /* we might want a more effective way to find peers by IP */
- for (p = peers; p != NULL &&
-    p->conf.id != peerid; p = p->next)
- ; /* nothing */
-
- return (p);
+ /* we might want a more effective way to find peers by id */
+ TAILQ_FOREACH(p, &c->peers, entry)
+ if (p->conf.id == peerid)
+ return (p);
+ return (NULL);
 }
 
 int
@@ -3285,4 +3211,52 @@ session_stop(struct peer *peer, u_int8_t
  break;
  }
  bgp_fsm(peer, EVNT_STOP);
+}
+
+void
+merge_peers(struct bgpd_config *c, struct bgpd_config *nc)
+{
+ struct peer *p, *np;
+
+ TAILQ_FOREACH(p, &c->peers, entry) {
+ /* templates are handled specially */
+ if (p->template != NULL)
+ continue;
+ np = getpeerbyid(nc, p->conf.id);
+ if (np == NULL) {
+ p->reconf_action = RECONF_DELETE;
+ continue;
+ }
+
+ memcpy(&p->conf, &np->conf, sizeof(p->conf));
+ TAILQ_REMOVE(&nc->peers, np, entry);
+ free(np);
+
+ p->reconf_action = RECONF_KEEP;
+
+ /* had demotion, is demoted, demote removed? */
+ if (p->demoted && !p->conf.demote_group[0])
+ session_demote(p, -1);
+
+ /* sync the RDE in case we keep the peer */
+ if (imsg_rde(IMSG_SESSION_ADD, p->conf.id,
+    &p->conf, sizeof(struct peer_config)) == -1)
+ fatalx("imsg_compose error");
+
+ /* apply the config to all clones of a template */
+ if (p->conf.template) {
+ struct peer *xp;
+ TAILQ_FOREACH(xp, &conf->peers, entry) {
+ if (xp->template != p)
+ continue;
+ session_template_clone(xp, NULL, xp->conf.id,
+    xp->conf.remote_as);
+ if (imsg_rde(IMSG_SESSION_ADD, xp->conf.id,
+    &xp->conf, sizeof(xp->conf)) == -1)
+ fatalx("imsg_compose error");
+ }
+ }
+ }
+
+ TAILQ_CONCAT(&c->peers, &nc->peers, entry);
 }
Index: session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.134
diff -u -p -r1.134 session.h
--- session.h 7 Mar 2019 07:42:36 -0000 1.134
+++ session.h 15 Mar 2019 15:31:27 -0000
@@ -196,6 +196,7 @@ TAILQ_HEAD(peer_timer_head, peer_timer);
 struct peer {
  struct peer_config conf;
  struct peer_stats stats;
+ TAILQ_ENTRY(peer) entry;
  struct {
  struct capabilities ann;
  struct capabilities peer;
@@ -207,13 +208,12 @@ struct peer {
  u_int32_t spi_out;
  enum auth_method method;
  u_int8_t established;
- } auth;
+ } auth;
  struct bgpd_addr local;
  struct bgpd_addr remote;
  struct peer_timer_head timers;
  struct msgbuf wbuf;
  struct ibuf_read *rbuf;
- struct peer *next;
  struct peer *template;
  int fd;
  int lasterr;
@@ -222,6 +222,7 @@ struct peer {
  u_int32_t remote_bgpid;
  enum session_state state;
  enum session_state prev_state;
+ enum reconf_action reconf_action;
  u_int16_t short_as;
  u_int16_t holdtime;
  u_int16_t local_port;
@@ -232,7 +233,6 @@ struct peer {
  u_int8_t throttled;
 };
 
-extern struct peer *peers;
 extern time_t pauseaccept;
 
 struct ctl_timer {
@@ -247,8 +247,7 @@ int carp_demote_get(char *);
 int carp_demote_set(char *, int);
 
 /* config.c */
-void merge_config(struct bgpd_config *, struct bgpd_config *,
-    struct peer *);
+void merge_config(struct bgpd_config *, struct bgpd_config *);
 int prepare_listeners(struct bgpd_config *);
 
 /* control.c */
@@ -256,7 +255,7 @@ int control_check(char *);
 int control_init(int, char *);
 int control_listen(int);
 void control_shutdown(int);
-int control_dispatch_msg(struct pollfd *, u_int *);
+int control_dispatch_msg(struct pollfd *, u_int *, struct peer_head *);
 unsigned int control_accept(int, int);
 
 /* log.c */
@@ -276,7 +275,7 @@ void mrt_dump_state(struct mrt *, u_in
 void mrt_done(struct mrt *);
 
 /* parse.y */
-int parse_config(char *, struct bgpd_config *, struct peer **);
+struct bgpd_config *parse_config(char *, struct peer_head *);
 
 /* pfkey.c */
 int pfkey_read(int, struct sadb_msg *);
@@ -285,9 +284,7 @@ int pfkey_remove(struct peer *);
 int pfkey_init(struct bgpd_sysdep *);
 
 /* printconf.c */
-void print_config(struct bgpd_config *, struct rib_names *,
-    struct network_head *, struct peer *, struct filter_head *,
-    struct mrt_head *, struct l3vpn_head *);
+void print_config(struct bgpd_config *, struct rib_names *);
 
 /* rde.c */
 void rde_main(int, int);
@@ -296,8 +293,9 @@ void rde_main(int, int);
 void session_main(int, int);
 void bgp_fsm(struct peer *, enum session_events);
 int session_neighbor_rrefresh(struct peer *p);
-struct peer *getpeerbyaddr(struct bgpd_addr *);
-struct peer *getpeerbydesc(const char *);
+struct peer *getpeerbydesc(struct bgpd_config *, const char *);
+struct peer *getpeerbyip(struct bgpd_config *, struct sockaddr *);
+struct peer *getpeerbyid(struct bgpd_config *, u_int32_t);
 int peer_matched(struct peer *, struct ctl_neighbor *);
 int imsg_ctl_parent(int, u_int32_t, pid_t, void *, u_int16_t);
 int imsg_ctl_rde(int, pid_t, void *, u_int16_t);