diff options
Diffstat (limited to 'ospf6d/ospf6_zebra.c')
-rw-r--r-- | ospf6d/ospf6_zebra.c | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c new file mode 100644 index 000000000..7b8a8dcfb --- /dev/null +++ b/ospf6d/ospf6_zebra.c @@ -0,0 +1,727 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ospf6d.h" + +#include "ospf6_interface.h" +#include "ospf6_asbr.h" + +#include "ospf6_linklist.h" + +/* information about zebra. */ +struct zclient *zclient = NULL; + +/* redistribute function */ +void +ospf6_zebra_redistribute (int type) +{ + int top_change = 0; + + if (zclient->redist[type]) + return; + + if (! ospf6_is_asbr (ospf6)) + top_change = 1; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + if (top_change) + CALL_CHANGE_HOOK (&top_hook, ospf6); +} + +void +ospf6_zebra_no_redistribute (int type) +{ + int top_change = 0; + + if (!zclient->redist[type]) + return; + + if (ospf6_is_asbr (ospf6)) + top_change = 1; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + if (top_change) + CALL_CHANGE_HOOK (&top_hook, ospf6); +} + +int +ospf6_zebra_is_redistribute (int type) +{ + return zclient->redist[type]; +} + + +/* Inteface addition message from zebra. */ +int +ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F add: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + + ospf6_interface_if_add (ifp); + + return 0; +} + +int +ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) +{ +#if 0 + struct interface *ifp = NULL; + + ifp = zebra_interface_delete_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + + ospf6_interface_if_del (ifp); +#endif + + return 0; +} + +int +ospf6_zebra_if_state_update (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read (zclient->ibuf); + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + ospf6_interface_state_update (ifp); + return 0; +} + +int +ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_add_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_address_update (c->ifp); + + return 0; +} + +int +ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_delete_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_address_update (c->ifp); + + return 0; +} + + + +const char *zebra_route_name[ZEBRA_ROUTE_MAX] = +{ + "System", + "Kernel", + "Connect", + "Static", + "RIP", + "RIPng", + "OSPF", + "OSPF6", + "BGP", +}; + +const char *zebra_route_abname[ZEBRA_ROUTE_MAX] = + { "X", "K", "C", "S", "r", "R", "o", "O", "B" }; + +int +ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct prefix_ipv6 p; + struct in6_addr *nexthop; + char prefixstr[128], nexthopstr[128]; + + s = zclient->ibuf; + ifindex = 0; + nexthop = NULL; + memset (&api, 0, sizeof (api)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop = (struct in6_addr *) + malloc (api.nexthop_num * sizeof (struct in6_addr)); + stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + /* log */ + if (IS_OSPF6_DUMP_ZEBRA) + { + prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); + inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr)); + + if (command == ZEBRA_IPV6_ROUTE_ADD) + zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld", + zebra_route_name [api.type], prefixstr, + nexthopstr, ifindex); + else + zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld", + zebra_route_name [api.type], prefixstr, + nexthopstr, ifindex); + } + + if (command == ZEBRA_IPV6_ROUTE_ADD) + ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p, + api.nexthop_num, nexthop); + else + ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p); + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + free (nexthop); + + return 0; +} + + +DEFUN (show_zebra, + show_zebra_cmd, + "show zebra", + SHOW_STR + "Zebra information\n") +{ + int i; + if (!zclient) + vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE); + + vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE); + vty_out (vty, " enable: %d%s", zclient->enable, VTY_NEWLINE); + vty_out (vty, " fail: %d%s", zclient->fail, VTY_NEWLINE); + vty_out (vty, " redistribute default: %d%s", zclient->redist_default, + VTY_NEWLINE); + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + vty_out (vty, " RouteType: %s - %s%s", zebra_route_name[i], + zclient->redist[i] ? "redistributed" : "not redistributed", + VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: router zebra"); + + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Configure routing process\n" + "Disable connection to zebra daemon\n") +{ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("no router zebra"); + + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +/* Zebra configuration write function. */ +int +ospf6_zebra_config_write (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-zebra)# ", +}; + +#define ADD 0 +#define CHANGE 1 +#define REMOVE 2 + +static void +ospf6_zebra_route_update (int type, struct ospf6_route_req *request) +{ + char buf[96], ifname[IFNAMSIZ]; + + struct zapi_ipv6 api; + struct ospf6_route_req route; + struct linklist *nexthop_list; + struct linklist_node node; + struct ospf6_nexthop *nexthop = NULL; + struct in6_addr **nexthops; + unsigned int *ifindexes; + struct prefix_ipv6 *p; + int i, ret = 0; + + if (IS_OSPF6_DUMP_ZEBRA) + { + prefix2str (&request->route.prefix, buf, sizeof (buf)); + if (type == REMOVE) + zlog_info ("ZEBRA: Send remove route: %s", buf); + else + zlog_info ("ZEBRA: Send add route: %s", buf); + } + + if (zclient->sock < 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: failed: not connected to zebra"); + return; + } + + if (request->path.origin.adv_router == ospf6->router_id && + (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || + request->path.type == OSPF6_PATH_TYPE_EXTERNAL2)) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: self originated external route, ignore"); + return; + } + + /* Only the best path (i.e. the first path of the path-list + in 'struct ospf6_route') will be sent to zebra. */ + ospf6_route_lookup (&route, &request->route.prefix, request->table); + if (memcmp (&route.path, &request->path, sizeof (route.path))) + { + /* this is not preferred best route, ignore */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: not best path, ignore"); + return; + } + + nexthop_list = linklist_create (); + + /* for each nexthop */ + for (ospf6_route_lookup (&route, &request->route.prefix, request->table); + ! ospf6_route_end (&route); ospf6_route_next (&route)) + { + if (memcmp (&route.path, &request->path, sizeof (route.path))) + break; + + #define IN6_IS_ILLEGAL_NEXTHOP(a)\ + ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\ + (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff)) + if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address)) + { + zlog_warn ("ZEBRA: Illegal nexthop"); + continue; + } + + if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop))) + continue; + + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop)); + if (! nexthop) + { + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + continue; + } + + memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + + if (type == REMOVE && nexthop_list->count != 0) + type = ADD; + else if (type == REMOVE && nexthop_list->count == 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: all nexthop with the selected path has gone"); + + if (! memcmp (&request->route, &route.route, + sizeof (struct ospf6_route))) + { + /* send 'add' of alternative route */ + struct ospf6_path seconde_path; + + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: found alternative path to add"); + + memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path)); + type = ADD; + + while (! memcmp (&seconde_path, &route.path, + sizeof (struct ospf6_path))) + { + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, + sizeof (struct ospf6_nexthop)); + if (! nexthop) + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + else + { + memcpy (nexthop, &route.nexthop, + sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + + ospf6_route_next (&route); + } + } + else + { + /* there is no alternative route. send 'remove' to zebra for + requested route */ + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: can't find alternative path, remove"); + + if (IS_OSPF6_DUMP_ZEBRA) + { + zlog_info ("ZEBRA: Debug: walk over the route ?"); + ospf6_route_log_request ("Debug route", "***", &route); + ospf6_route_log_request ("Debug request", "***", request); + } + + nexthop = XCALLOC (MTYPE_OSPF6_OTHER, + sizeof (struct ospf6_nexthop)); + if (! nexthop) + zlog_warn ("ZEBRA: Can't update nexthop: malloc failed"); + else + { + memcpy (nexthop, &request->nexthop, + sizeof (struct ospf6_nexthop)); + linklist_add (nexthop, nexthop_list); + } + } + } + + if (nexthop_list->count == 0) + { + if (IS_OSPF6_DUMP_ZEBRA) + zlog_info ("ZEBRA: no nexthop, ignore"); + linklist_delete (nexthop_list); + return; + } + + /* allocate memory for nexthop_list */ + nexthops = XCALLOC (MTYPE_OSPF6_OTHER, + nexthop_list->count * sizeof (struct in6_addr *)); + if (! nexthops) + { + zlog_warn ("ZEBRA: Can't update zebra route: malloc failed"); + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + return; + } + + /* allocate memory for ifindex_list */ + ifindexes = XCALLOC (MTYPE_OSPF6_OTHER, + nexthop_list->count * sizeof (unsigned int)); + if (! ifindexes) + { + zlog_warn ("ZEBRA: Can't update zebra route: malloc failed"); + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + XFREE (MTYPE_OSPF6_OTHER, nexthops); + return; + } + + i = 0; + for (linklist_head (nexthop_list, &node); ! linklist_end (&node); + linklist_next (&node)) + { + nexthop = node.data; + if (IS_OSPF6_DUMP_ZEBRA) + { + inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf)); + if_indextoname (nexthop->ifindex, ifname); + zlog_info ("ZEBRA: nexthop: %s%%%s(%d)", + buf, ifname, nexthop->ifindex); + } + nexthops[i] = &nexthop->address; + ifindexes[i] = nexthop->ifindex; + i++; + } + + api.type = ZEBRA_ROUTE_OSPF6; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.nexthop_num = nexthop_list->count; + api.nexthop = nexthops; + api.ifindex_num = nexthop_list->count; + api.ifindex = ifindexes; + + p = (struct prefix_ipv6 *) &request->route.prefix; + if (type == REMOVE && nexthop_list->count == 1) + ret = zapi_ipv6_delete (zclient, p, &api); + else + ret = zapi_ipv6_add (zclient, p, &api); + + if (ret < 0) + zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", strerror (errno)); + + for (linklist_head (nexthop_list, &node); !linklist_end (&node); + linklist_next (&node)) + XFREE (MTYPE_OSPF6_OTHER, node.data); + linklist_delete (nexthop_list); + XFREE (MTYPE_OSPF6_OTHER, nexthops); + XFREE (MTYPE_OSPF6_OTHER, ifindexes); + + return; +} + +void +ospf6_zebra_route_update_add (struct ospf6_route_req *request) +{ + ospf6_zebra_route_update (ADD, request); +} + +void +ospf6_zebra_route_update_remove (struct ospf6_route_req *request) +{ + ospf6_zebra_route_update (REMOVE, request); +} + +static void +ospf6_zebra_redistribute_ospf6 () +{ + struct route_node *node; + + for (node = route_top (ospf6->route_table->table); node; + node = route_next (node)) + { + if (! node || ! node->info) + continue; + ospf6_zebra_route_update_add (node->info); + } +} + +static void +ospf6_zebra_no_redistribute_ospf6 () +{ + struct route_node *node; + + if (! ospf6) + return; + + for (node = route_top (ospf6->route_table->table); node; + node = route_next (node)) + { + if (! node || ! node->info) + continue; + + ospf6_zebra_route_update_remove (node->info); + } +} + + +DEFUN (redistribute_ospf6, + redistribute_ospf6_cmd, + "redistribute ospf6", + "Redistribute control\n" + "OSPF6 route\n") +{ + /* log */ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: redistribute ospf6"); + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; + + /* set zebra route table */ + ospf6_zebra_redistribute_ospf6 (); + + return CMD_SUCCESS; +} + +DEFUN (no_redistribute_ospf6, + no_redistribute_ospf6_cmd, + "no redistribute ospf6", + NO_STR + "Redistribute control\n" + "OSPF6 route\n") +{ + /* log */ + if (IS_OSPF6_DUMP_CONFIG) + zlog_info ("Config: no redistribute ospf6"); + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; + + if (! ospf6) + return CMD_SUCCESS; + + /* clean up zebra route table */ + ospf6_zebra_no_redistribute_ospf6 (); + + ospf6_route_hook_unregister (ospf6_zebra_route_update_add, + ospf6_zebra_route_update_add, + ospf6_zebra_route_update_remove, + ospf6->route_table); + + return CMD_SUCCESS; +} + +void +ospf6_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF6); + zclient->interface_add = ospf6_zebra_if_add; + zclient->interface_delete = ospf6_zebra_if_del; + zclient->interface_up = ospf6_zebra_if_state_update; + zclient->interface_down = ospf6_zebra_if_state_update; + zclient->interface_address_add = ospf6_zebra_if_address_update_add; + zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; + zclient->ipv4_route_add = NULL; + zclient->ipv4_route_delete = NULL; + zclient->ipv6_route_add = ospf6_zebra_read_ipv6; + zclient->ipv6_route_delete = ospf6_zebra_read_ipv6; + + /* redistribute connected route by default */ + /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */ + + /* Install zebra node. */ + install_node (&zebra_node, ospf6_zebra_config_write); + + /* Install command element for zebra node. */ + install_element (VIEW_NODE, &show_zebra_cmd); + install_element (ENABLE_NODE, &show_zebra_cmd); + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &redistribute_ospf6_cmd); + install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd); + +#if 0 + hook.name = "ZebraRouteUpdate"; + hook.hook_add = ospf6_zebra_route_update_add; + hook.hook_change = ospf6_zebra_route_update_add; + hook.hook_remove = ospf6_zebra_route_update_remove; + ospf6_hook_register (&hook, &route_hook); +#endif + + return; +} + +void +ospf6_zebra_finish () +{ + zclient_stop (zclient); + zclient_free (zclient); + zclient = (struct zclient *) NULL; +} + |