--- embedaddon/quagga/zebra/zserv.c 2012/02/21 17:26:11 1.1.1.1 +++ embedaddon/quagga/zebra/zserv.c 2013/07/21 23:54:41 1.1.1.3 @@ -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) { @@ -131,6 +140,30 @@ zserv_create_header (struct stream *s, uint16_t cmd) stream_putw (s, cmd); } +static void +zserv_encode_interface (struct stream *s, struct interface *ifp) +{ + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); + stream_putq (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->mtu6); + stream_putl (s, ifp->bandwidth); +#ifdef HAVE_STRUCT_SOCKADDR_DL + stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); +#else + stream_putl (s, ifp->hw_addr_len); + if (ifp->hw_addr_len) + stream_put (s, ifp->hw_addr, ifp->hw_addr_len); +#endif /* HAVE_STRUCT_SOCKADDR_DL */ + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); +} + /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: @@ -154,29 +187,9 @@ zsend_interface_add (struct zserv *client, struct inte s = client->obuf; stream_reset (s); - /* Message type. */ zserv_create_header (s, ZEBRA_INTERFACE_ADD); + zserv_encode_interface (s, ifp); - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); -#else - stream_putl (s, ifp->hw_addr_len); - if (ifp->hw_addr_len) - stream_put (s, ifp->hw_addr, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); - return zebra_server_send_message(client); } @@ -192,22 +205,10 @@ zsend_interface_delete (struct zserv *client, struct i s = client->obuf; stream_reset (s); - + zserv_create_header (s, ZEBRA_INTERFACE_DELETE); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); + zserv_encode_interface (s, ifp); - /* Write packet length. */ - stream_putw_at (s, 0, stream_get_endp (s)); - return zebra_server_send_message (client); } @@ -319,20 +320,8 @@ zsend_interface_update (int cmd, struct zserv *client, stream_reset (s); zserv_create_header (s, cmd); + zserv_encode_interface (s, ifp); - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); - return zebra_server_send_message(client); } @@ -741,7 +730,9 @@ 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 +743,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. */ @@ -783,13 +775,18 @@ zread_ipv4_add (struct zserv *client, u_short length) nexthop.s_addr = stream_get_ipv4 (s); nexthop_ipv4_add (rib, &nexthop, NULL); break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop.s_addr = stream_get_ipv4 (s); + ifindex = stream_getl (s); + nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; - case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); - break; - } + case ZEBRA_NEXTHOP_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } } } @@ -803,7 +800,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; } @@ -814,7 +811,7 @@ zread_ipv4_delete (struct zserv *client, u_short lengt int i; struct stream *s; struct zapi_ipv4 api; - struct in_addr nexthop; + struct in_addr nexthop, *nexthop_p; unsigned long ifindex; struct prefix_ipv4 p; u_char nexthop_num; @@ -824,11 +821,13 @@ zread_ipv4_delete (struct zserv *client, u_short lengt s = client->ibuf; ifindex = 0; nexthop.s_addr = 0; + nexthop_p = NULL; /* Type, flags, message. */ 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)); @@ -856,7 +855,12 @@ zread_ipv4_delete (struct zserv *client, u_short lengt break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); + nexthop_p = &nexthop; break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + nexthop.s_addr = stream_get_ipv4 (s); + ifindex = stream_getl (s); + break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; @@ -876,8 +880,8 @@ zread_ipv4_delete (struct zserv *client, u_short lengt else api.metric = 0; - rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, - client->rtm_table); + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, + client->rtm_table, api.safi); return 0; } @@ -924,6 +928,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 +970,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 +996,7 @@ zread_ipv6_delete (struct zserv *client, u_short lengt 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 +1036,9 @@ zread_ipv6_delete (struct zserv *client, u_short lengt 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 +1077,49 @@ zread_router_id_delete (struct zserv *client, u_short 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 +1128,7 @@ zebra_client_close (struct zserv *client) if (client->sock) { close (client->sock); + zebra_score_rib (client->sock); client->sock = -1; } @@ -1283,6 +1333,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 +1405,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 +1476,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 +1789,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 */ }