summaryrefslogtreecommitdiff
path: root/zebra/zserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zserv.c')
-rw-r--r--zebra/zserv.c81
1 files changed, 73 insertions, 8 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c
index dc3d432b..672dee88 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)
{
@@ -741,6 +750,8 @@ zread_ipv4_add (struct zserv *client, u_short length)
struct stream *s;
unsigned int ifindex;
u_char ifname_len;
+ safi_t safi;
+
/* Get input stream. */
s = client->ibuf;
@@ -752,6 +763,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
rib->type = stream_getc (s);
rib->flags = stream_getc (s);
message = stream_getc (s);
+ safi = stream_getw (s);
rib->uptime = time (NULL);
/* IPv4 prefix. */
@@ -803,7 +815,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
/* Table */
rib->table=zebrad.rtm_table_default;
- rib_add_ipv4_multipath (&p, rib);
+ rib_add_ipv4_multipath (&p, rib, safi);
return 0;
}
@@ -829,6 +841,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
+ api.safi = stream_getw (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -877,7 +890,7 @@ zread_ipv4_delete (struct zserv *client, u_short length)
api.metric = 0;
rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
- client->rtm_table);
+ client->rtm_table, api.safi);
return 0;
}
@@ -924,6 +937,7 @@ zread_ipv6_add (struct zserv *client, u_short length)
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
+ api.safi = stream_getw (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -965,10 +979,10 @@ zread_ipv6_add (struct zserv *client, u_short length)
if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric,
- api.distance);
+ api.distance, api.safi);
else
rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric,
- api.distance);
+ api.distance, api.safi);
return 0;
}
@@ -991,6 +1005,7 @@ zread_ipv6_delete (struct zserv *client, u_short length)
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
+ api.safi = stream_getw (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -1030,9 +1045,9 @@ zread_ipv6_delete (struct zserv *client, u_short length)
api.metric = 0;
if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
- rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table);
+ rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi);
else
- rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table);
+ rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi);
return 0;
}
@@ -1071,6 +1086,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 +1137,7 @@ zebra_client_close (struct zserv *client)
if (client->sock)
{
close (client->sock);
+ zebra_score_rib (client->sock);
client->sock = -1;
}
@@ -1283,6 +1342,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 +1414,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 +1485,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;
@@ -1733,11 +1798,11 @@ zebra_init (void)
/* Make zebra server socket, wiping any existing one (see bug #403). */
void
-zebra_zserv_socket_init (void)
+zebra_zserv_socket_init (char *path)
{
#ifdef HAVE_TCP_ZEBRA
zebra_serv ();
#else
- zebra_serv_un (ZEBRA_SERV_PATH);
+ zebra_serv_un (path ? path : ZEBRA_SERV_PATH);
#endif /* HAVE_TCP_ZEBRA */
}