From baff583e8bb5f703ab07aab55fea9a7ddf42a468 Mon Sep 17 00:00:00 2001 From: Maitane Zotes Date: Wed, 5 Mar 2014 09:13:43 +0100 Subject: [PATCH] ospf6d: implement admin distance Until today the admin distance cannot be configured for any IPv6 routing protocol. This patch implements it for ospf6. Signed-off-by: Maitane Zotes Signed-off-by: Roman Hoog Antink --- ospf6d/ospf6_top.c | 185 +++++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.h | 8 ++ ospf6d/ospf6_zebra.c | 150 +++++++++++++++++++++++++++++++++++ ospf6d/ospf6_zebra.h | 19 +++++ 4 files changed, 362 insertions(+) diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 5def2acf69..3d632b644e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -155,6 +155,8 @@ ospf6_create (void) o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; + o->distance_table = route_table_init (); + /* Enable "log-adjacency-changes" */ SET_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); @@ -184,6 +186,9 @@ ospf6_delete (struct ospf6 *o) ospf6_route_table_delete (o->external_table); route_table_finish (o->external_id_table); + ospf6_distance_reset (o); + route_table_finish (o->distance_table); + XFREE (MTYPE_OSPF6_TOP, o); } @@ -460,6 +465,138 @@ ALIAS (no_ospf6_timers_lsa, "Minimum delay in receiving new version of a LSA\n" "Delay in milliseconds\n") +DEFUN (ospf6_distance, + ospf6_distance_cmd, + "distance <1-255>", + "Administrative distance\n" + "OSPF6 Administrative distance\n") +{ + struct ospf6 *o = vty->index; + + o->distance_all = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance, + no_ospf6_distance_cmd, + "no distance <1-255>", + NO_STR + "Administrative distance\n" + "OSPF6 Administrative distance\n") +{ + struct ospf6 *o = vty->index; + + o->distance_all = 0; + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6, + ospf6_distance_ospf6_cmd, + "distance ospf6 {intra-area <1-255>|inter-area <1-255>|external <1-255>}", + "Administrative distance\n" + "OSPF6 distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o = vty->index; + + if (argc < 3) /* should not happen */ + return CMD_WARNING; + + if (!argv[0] && !argv[1] && !argv[2]) + { + vty_out(vty, "%% Command incomplete. (Arguments required)%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argv[0] != NULL) + o->distance_intra = atoi (argv[0]); + + if (argv[1] != NULL) + o->distance_inter = atoi (argv[1]); + + if (argv[2] != NULL) + o->distance_external = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_ospf6, + no_ospf6_distance_ospf6_cmd, + "no distance ospf6 {intra-area <1-255>|inter-area <1-255>|external <1-255>}", + NO_STR + "Administrative distance\n" + "OSPF6 distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf6 *o = vty->index; + + if (argc < 3) /* should not happen */ + return CMD_WARNING; + + if (argv[0] != NULL) + o->distance_intra = 0; + + if (argv[1] != NULL) + o->distance_inter = 0; + + if (argv[2] != NULL) + o->distance_external = 0; + + if (argv[0] || argv[1] || argv[2]) + return CMD_SUCCESS; + + /* If no arguments are given, clear all distance information */ + o->distance_intra = 0; + o->distance_inter = 0; + o->distance_external = 0; + + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_source, + ospf6_distance_source_cmd, + "distance <1-255> X:X::X:X/M [WORD]", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf6 *o = vty->index; + + ospf6_distance_set (vty, o, argv[0], argv[1], argc == 3 ? argv[2] : NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_source, + no_ospf6_distance_source_cmd, + "no distance <1-255> X:X::X:X/M [WORD]", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf6 *o = vty->index; + + ospf6_distance_unset (vty, o, argv[0], argv[1], argc == 3 ? argv[2] : NULL); + + return CMD_SUCCESS; +} + DEFUN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area A.B.C.D", @@ -934,6 +1071,44 @@ ospf6_stub_router_config_write (struct vty *vty) return; } +static int +ospf6_distance_config_write (struct vty *vty) +{ + struct route_node *rn; + struct ospf6_distance *odistance; + + if (ospf6->distance_all) + vty_out (vty, " distance %u%s", ospf6->distance_all, VTY_NEWLINE); + + if (ospf6->distance_intra + || ospf6->distance_inter + || ospf6->distance_external) + { + vty_out (vty, " distance ospf6"); + + if (ospf6->distance_intra) + vty_out (vty, " intra-area %u", ospf6->distance_intra); + if (ospf6->distance_inter) + vty_out (vty, " inter-area %u", ospf6->distance_inter); + if (ospf6->distance_external) + vty_out (vty, " external %u", ospf6->distance_external); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + for (rn = route_top (ospf6->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + char buf[PREFIX_STRLEN]; + + vty_out (vty, " distance %u %s %s%s", odistance->distance, + prefix2str (&rn->p, buf, sizeof (buf)), + odistance->access_list ? odistance->access_list : "", + VTY_NEWLINE); + } + return 0; +} + /* OSPF configuration write function. */ static int config_write_ospf6 (struct vty *vty) @@ -976,6 +1151,7 @@ config_write_ospf6 (struct vty *vty) ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); ospf6_spf_config_write (vty); + ospf6_distance_config_write (vty); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa)) { @@ -1037,6 +1213,15 @@ ospf6_top_init (void) install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd); */ + + install_element (OSPF6_NODE, &ospf6_distance_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_cmd); + install_element (OSPF6_NODE, &ospf6_distance_ospf6_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_ospf6_cmd); +#if 0 + install_element (OSPF6_NODE, &ospf6_distance_source_cmd); + install_element (OSPF6_NODE, &no_ospf6_distance_source_cmd); +#endif } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 518db3860c..8985eeaa28 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -85,6 +85,14 @@ struct ospf6 struct thread *maxage_remover; u_int32_t ref_bandwidth; + + /* Distance parameters */ + u_char distance_all; + u_char distance_intra; + u_char distance_inter; + u_char distance_external; + + struct route_table *distance_table; }; #define OSPF6_DISABLED 0x01 diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 4d658ed1b8..3e4042d65d 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -40,6 +40,8 @@ #include "ospf6_zebra.h" #include "ospf6d.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance") + unsigned char conf_debug_ospf6_zebra = 0; /* information about zebra. */ @@ -480,6 +482,10 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) } dest = (struct prefix_ipv6 *) &request->prefix; + + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = ospf6_distance_apply (dest, request); + if (type == REM) ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api); else @@ -664,6 +670,150 @@ DEFUN (no_redistribute_ospf6, return CMD_SUCCESS; } +static struct ospf6_distance * +ospf6_distance_new (void) +{ + return XCALLOC (MTYPE_OSPF6_DISTANCE, sizeof (struct ospf6_distance)); +} + +static void +ospf6_distance_free (struct ospf6_distance *odistance) +{ + XFREE (MTYPE_OSPF6_DISTANCE, odistance); +} + +int +ospf6_distance_set (struct vty *vty, struct ospf6 *o, + const char *distance_str, + const char *ip_str, + const char *access_list_str) +{ + int ret; + struct prefix_ipv6 p; + u_char distance; + struct route_node *rn; + struct ospf6_distance *odistance; + + ret = str2prefix_ipv6 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get OSPF6 distance node. */ + rn = route_node_get (o->distance_table, (struct prefix *) &p); + if (rn->info) + { + odistance = rn->info; + route_unlock_node (rn); + } + else + { + odistance = ospf6_distance_new (); + rn->info = odistance; + } + + /* Set distance value. */ + odistance->distance = distance; + + /* Reset access-list configuration. */ + if (odistance->access_list) + { + free (odistance->access_list); + odistance->access_list = NULL; + } + if (access_list_str) + odistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +ospf6_distance_unset (struct vty *vty, struct ospf6 *o, + const char *distance_str, + const char *ip_str, + const char *access_list_str) +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rn; + struct ospf6_distance *odistance; + + ret = str2prefix_ipv6 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_lookup (o->distance_table, (struct prefix *) &p); + if (!rn) + { + vty_out (vty, "Cant't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + odistance = rn->info; + + if (odistance->access_list) + free (odistance->access_list); + ospf6_distance_free (odistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +ospf6_distance_reset (struct ospf6 *o) +{ + struct route_node *rn; + struct ospf6_distance *odistance; + + for (rn = route_top (o->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + if (odistance->access_list) + free (odistance->access_list); + ospf6_distance_free (odistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +u_char +ospf6_distance_apply (struct prefix_ipv6 *p, struct ospf6_route *or) +{ + struct ospf6 *o; + + o = ospf6; + if (o == NULL) + return 0; + + if (o->distance_intra) + if (or->path.type == OSPF6_PATH_TYPE_INTRA) + return o->distance_intra; + + if (o->distance_inter) + if (or->path.type == OSPF6_PATH_TYPE_INTER) + return o->distance_inter; + + if (o->distance_external) + if(or->path.type == OSPF6_PATH_TYPE_EXTERNAL1 + || or->path.type == OSPF6_PATH_TYPE_EXTERNAL2) + return o->distance_external; + + if (o->distance_all) + return o->distance_all; + + return 0; +} + static void ospf6_zebra_connected (struct zclient *zclient) { diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index 5b28c07636..83032b64b1 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -35,6 +35,16 @@ extern unsigned char conf_debug_ospf6_zebra; #define IS_OSPF6_DEBUG_ZEBRA(e) \ (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e) +/* OSPF6 distance */ +struct ospf6_distance +{ + /* Distance value for the IP source prefix */ + u_char distance; + + /* Name of the access-list to be matched */ + char *access_list; +}; + extern struct zclient *zclient; extern void ospf6_zebra_route_update_add (struct ospf6_route *request); @@ -48,6 +58,15 @@ extern void ospf6_zebra_init (struct thread_master *); extern void ospf6_zebra_add_discard (struct ospf6_route *request); extern void ospf6_zebra_delete_discard (struct ospf6_route *request); +struct ospf6; +extern void ospf6_distance_reset (struct ospf6 *); +extern u_char ospf6_distance_apply (struct prefix_ipv6 *, struct ospf6_route *); + +extern int ospf6_distance_set (struct vty *, struct ospf6 *, const char *, + const char *, const char *); +extern int ospf6_distance_unset (struct vty *, struct ospf6 *, const char *, + const char *, const char *); + extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); -- 2.39.5