summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
authorVyacheslav Trushkin <me@dogonthesun.net>2011-12-11 18:48:47 +0400
committerDenis Ovsienko <infrastation@yandex.ru>2012-01-02 18:37:24 +0400
commit2ea1ab1c30c765cd4703794fcfaf044454fb533c (patch)
tree650e97a5a9e8cc1fb8666ff6ce87647df3e0e604 /zebra
parent2654e43ca2eaa8d93268c9ec85ac2dd968e5fb94 (diff)
zebra: ZEBRA_HELLO and mopping up routes (BZ#448)
ZEBRA_HELLO message is used by routing daemons to inform zebra what type of routes daemon will be announcing to zebra. Also zebra uses route_type_oaths array to track which daemon announces which protocol. Zebra mops up routes if daemon didn't for some reason.
Diffstat (limited to 'zebra')
-rw-r--r--zebra/rib.h1
-rw-r--r--zebra/zebra_rib.c36
-rw-r--r--zebra/zserv.c59
3 files changed, 95 insertions, 1 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index 887ed3c2..20a206ea 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -266,6 +266,7 @@ extern void rib_weed_tables (void);
extern void rib_sweep_route (void);
extern void rib_close (void);
extern void rib_init (void);
+extern unsigned long rib_score_proto (u_char proto);
extern int
static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 8228350f..72633895 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2881,7 +2881,41 @@ rib_sweep_route (void)
rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
}
-
+
+/* Remove specific by protocol routes from 'table'. */
+static unsigned long
+rib_score_proto_table (u_char proto, struct route_table *table)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+ unsigned long n = 0;
+
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+ if (rib->type == proto)
+ {
+ rib_delnode (rn, rib);
+ n++;
+ }
+ }
+
+ return n;
+}
+
+/* Remove specific by protocol routes. */
+unsigned long
+rib_score_proto (u_char proto)
+{
+ return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0))
+ +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+
/* Close RIB and clean up kernel routes. */
static void
rib_close_table (struct route_table *table)
diff --git a/zebra/zserv.c b/zebra/zserv.c
index d558b2d2..ec8cbf2b 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -64,6 +64,15 @@ zserv_delayed_close(struct thread *thread)
return 0;
}
+/* When client connects, it sends hello message
+ * with promise to send zebra routes of specific type.
+ * Zebra stores a socket fd of the client into
+ * this array. And use it to clean up routes that
+ * client didn't remove for some reasons after closing
+ * connection.
+ */
+static int route_type_oaths[ZEBRA_ROUTE_MAX];
+
static int
zserv_flush_data(struct thread *thread)
{
@@ -1071,6 +1080,49 @@ zread_router_id_delete (struct zserv *client, u_short length)
return 0;
}
+/* Tie up route-type and client->sock */
+static void
+zread_hello (struct zserv *client)
+{
+ /* type of protocol (lib/zebra.h) */
+ u_char proto;
+ proto = stream_getc (client->ibuf);
+
+ /* accept only dynamic routing protocols */
+ if ((proto < ZEBRA_ROUTE_MAX)
+ && (proto > ZEBRA_ROUTE_STATIC))
+ {
+ zlog_notice ("client %d says hello and bids fair to announce only %s routes",
+ client->sock, zebra_route_string(proto));
+
+ /* if route-type was binded by other client */
+ if (route_type_oaths[proto])
+ zlog_warn ("sender of %s routes changed %c->%c",
+ zebra_route_string(proto), route_type_oaths[proto],
+ client->sock);
+
+ route_type_oaths[proto] = client->sock;
+ }
+}
+
+/* If client sent routes of specific type, zebra removes it
+ * and returns number of deleted routes.
+ */
+static void
+zebra_score_rib (int client_sock)
+{
+ int i;
+
+ for (i = ZEBRA_ROUTE_RIP; i < ZEBRA_ROUTE_MAX; i++)
+ if (client_sock == route_type_oaths[i])
+ {
+ zlog_notice ("client %d disconnected. %lu %s routes removed from the rib",
+ client_sock, rib_score_proto (i), zebra_route_string (i));
+ route_type_oaths[i] = 0;
+ break;
+ }
+}
+
/* Close zebra client. */
static void
zebra_client_close (struct zserv *client)
@@ -1079,6 +1131,7 @@ zebra_client_close (struct zserv *client)
if (client->sock)
{
close (client->sock);
+ zebra_score_rib (client->sock);
client->sock = -1;
}
@@ -1283,6 +1336,9 @@ zebra_client_read (struct thread *thread)
case ZEBRA_IPV4_IMPORT_LOOKUP:
zread_ipv4_import_lookup (client, length);
break;
+ case ZEBRA_HELLO:
+ zread_hello (client);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
@@ -1352,6 +1408,7 @@ zebra_serv ()
return;
}
+ memset (&route_type_oaths, 0, sizeof (route_type_oaths));
memset (&addr, 0, sizeof (struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons (ZEBRA_PORT);
@@ -1422,6 +1479,8 @@ zebra_serv_un (const char *path)
return;
}
+ memset (&route_type_oaths, 0, sizeof (route_type_oaths));
+
/* Make server socket. */
memset (&serv, 0, sizeof (struct sockaddr_un));
serv.sun_family = AF_UNIX;