| /* |
| * 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; |
| } |
| |