From e723861da171fd811f499665e5432dce4e364ee6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 17:58:14 -0700 Subject: [PATCH] per-interface ospf enable and area set command. --- doc/ospfd.texi | 5 ++ ospfd/ospf_interface.h | 2 + ospfd/ospf_vty.c | 108 ++++++++++++++++++++++++ ospfd/ospfd.c | 181 ++++++++++++++++++++++++++++++++++++----- ospfd/ospfd.h | 5 ++ 5 files changed, 281 insertions(+), 20 deletions(-) diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 856a2ba05f..5b1b2acb2a 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -507,6 +507,11 @@ incremented by this value when transmitting. The default value is 1 seconds. @end deffn +@deffn {Interface Command} {ip ospf area (A.B.C.D|<0-4294967295>)} {} +@deffnx {Interface Command} {no ip ospf area} {} +Enable ospf on an interface and set associated area. +@end deffn + @node Redistribute routes to OSPF @section Redistribute routes to OSPF diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 75a8d060ff..e2d929020f 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -48,6 +48,8 @@ struct ospf_if_params DECLARE_IF_PARAM (u_char, bfd); /* Respond to BFD events */ DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */ DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ + /* Enable OSPF on this interface with area if_area */ + DECLARE_IF_PARAM (struct in_addr, if_area); DECLARE_IF_PARAM (u_char, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 84251fe44b..2854a41b4f 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -446,6 +446,13 @@ DEFUN (ospf_network_area, struct in_addr area_id; int ret, format; + if (ospf->if_ospf_cli_count > 0) + { + vty_out (vty, "Please remove all ip ospf area x.x.x.x commands first.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + /* Get network prefix and Area ID. */ VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); @@ -5887,6 +5894,95 @@ ALIAS (no_ip_ospf_transmit_delay, "OSPF interface commands\n" "Link state transmit delay\n") +DEFUN (ip_ospf_area, + ip_ospf_area_cmd, + "ip ospf area (A.B.C.D|<0-4294967295>)", + "IP Information\n" + "OSPF interface commands\n" + "Enable OSPF on this interface\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct interface *ifp = vty->index; + int format, ret; + struct in_addr area_id; + struct ospf *ospf; + struct ospf_if_params *params; + struct route_node *rn; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + ret = ospf_str2area_id (argv[0], &area_id, &format); + if (ret < 0) + { + vty_out (vty, "Please specify area by A.B.C.D|<0-4294967295>%s", + VTY_NEWLINE); + return CMD_WARNING; + } + if (memcmp (ifp->name, "VLINK", 5) == 0) + { + vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + params = IF_DEF_PARAMS (ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + { + return CMD_WARNING; + } + + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + { + if (rn->info != NULL) + { + vty_out (vty, "Please remove all network commands first.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* enable ospf on this interface with area_id */ + ospf_interface_set (ifp, area_id); + ospf->if_ospf_cli_count++; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_area, + no_ip_ospf_area_cmd, + "no ip ospf area", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Disable OSPF on this interface\n") +{ + struct interface *ifp = vty->index; + struct ospf *ospf; + struct ospf_if_params *params; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + params = IF_DEF_PARAMS (ifp); + if (!OSPF_IF_PARAM_CONFIGURED(params, if_area)) + { + vty_out (vty, "Can't find specified inteface area configuration.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_interface_unset (ifp); + ospf->if_ospf_cli_count--; + return CMD_SUCCESS; +} + DEFUN (ospf_redistribute_source, ospf_redistribute_source_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD @@ -6951,6 +7047,14 @@ config_write_interface (struct vty *vty) vty_out (vty, "%s", VTY_NEWLINE); } + /* Area print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, if_area)) + { + vty_out (vty, " ip ospf area %s%s", + inet_ntoa (params->if_area), VTY_NEWLINE); + + } + /* bfd print. */ if (OSPF_IF_PARAM_CONFIGURED (params, bfd)) vty_out (vty, " ip ospf bfd%s", VTY_NEWLINE); @@ -7601,6 +7705,10 @@ ospf_vty_if_init (void) install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); + /* "ip ospf area" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_area_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_area_cmd); + /* These commands are compatibitliy for previous version. */ install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 272c544bc6..a69b5595d7 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -403,6 +403,7 @@ ospf_finish_final (struct ospf *ospf) struct route_node *rn; struct ospf_nbr_nbma *nbr_nbma; struct ospf_lsa *lsa; + struct interface *ifp; struct ospf_interface *oi; struct ospf_area *area; struct ospf_vl_data *vl_data; @@ -429,6 +430,16 @@ ospf_finish_final (struct ospf *ospf) list_delete (ospf->vlinks); + /* Remove any ospf interface config params */ + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + { + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + UNSET_IF_PARAM (params, if_area); + } + /* Reset interface. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) ospf_if_free (oi); @@ -721,6 +732,76 @@ ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi) listnode_delete (area->oiflist, oi); } +static struct ospf_interface * +add_ospf_interface (struct interface *ifp, struct ospf_area *area, + struct connected *co) +{ + struct ospf_interface *oi; + + oi = ospf_if_new (area->ospf, ifp, co->address); + oi->connected = co; + + oi->area = area; + + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + oi->output_cost = ospf_if_get_output_cost (oi); + + /* Add pseudo neighbor. */ + ospf_nbr_add_self (oi); + + /* Relate ospf interface to ospf instance. */ + oi->ospf = area->ospf; + + /* update network type as interface flag */ + /* If network type is specified previously, + skip network type setting. */ + oi->type = IF_DEF_PARAMS (ifp)->type; + + ospf_area_add_if (oi->area, oi); + + /* if router_id is not configured, dont bring up + * interfaces. + * ospf_router_id_update() will call ospf_if_update + * whenever r-id is configured instead. + */ + if ((area->ospf->router_id.s_addr != 0) + && if_is_operative (ifp)) + ospf_if_up (oi); + + return (oi); +} + +static void update_redistributed(struct ospf *ospf, int add_to_ospf) +{ + struct route_node *rn; + struct external_info *ei; + + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + { + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + { + if ((ei = rn->info) != NULL) + { + if (add_to_ospf) + { + if (ospf_external_info_find_lsa (ospf, &ei->p)) + if (!ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_flush (ospf, ei->type, &ei->p, + ei->ifindex /*, ei->nexthop */); + } + else + { + if (!ospf_external_info_find_lsa (ospf, &ei->p)) + if (ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_originate (ospf, ei); + } + } + } + } +} + /* Config network statement related functions. */ static struct ospf_network * @@ -750,7 +831,6 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_network *network; struct ospf_area *area; struct route_node *rn; - struct external_info *ei; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; rn = route_node_get (ospf->networks, (struct prefix *)p); @@ -768,15 +848,7 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, ospf_network_run ((struct prefix *)p, area); /* Update connected redistribute. */ - if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) - if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) - for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); - rn; rn = route_next (rn)) - if ((ei = rn->info) != NULL) - if (ospf_external_info_find_lsa (ospf, &ei->p)) - if (!ospf_distribute_check_connected (ospf, ei)) - ospf_external_lsa_flush (ospf, ei->type, &ei->p, - ei->ifindex /*, ei->nexthop */); + update_redistributed(ospf, 1); /* interfaces possibly added */ ospf_area_check_free (ospf, area_id); @@ -789,7 +861,6 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, { struct route_node *rn; struct ospf_network *network; - struct external_info *ei; struct listnode *node, *nnode; struct ospf_interface *oi; @@ -833,14 +904,76 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, } /* Update connected redistribute. */ - if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) - if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) - for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); - rn; rn = route_next (rn)) - if ((ei = rn->info) != NULL) - if (!ospf_external_info_find_lsa (ospf, &ei->p)) - if (ospf_distribute_check_connected (ospf, ei)) - ospf_external_lsa_originate (ospf, ei); + update_redistributed(ospf, 0); /* interfaces possibly removed */ + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_interface_set (struct interface *ifp, struct in_addr area_id) +{ + struct ospf_area *area; + struct listnode *cnode; + struct connected *co; + struct ospf *ospf; + struct ospf_if_params *params; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + if ((ospf = ospf_lookup ()) == NULL) + return 1; /* Ospf not ready yet */ + + params = IF_DEF_PARAMS (ifp); + + SET_IF_PARAM (params, if_area); + params->if_area = area_id; + + area = ospf_area_get (ospf, area_id, ret); + + for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) + { + if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) + continue; + + if (co->address->family == AF_INET + && !ospf_if_table_lookup(ifp, co->address)) + { + add_ospf_interface(ifp, area, co); + } + } + + /* Update connected redistribute. */ + update_redistributed(ospf, 1); /* interface possibly added */ + return 1; +} + +int +ospf_interface_unset (struct interface *ifp) +{ + struct ospf *ospf; + struct ospf_if_params *params; + struct listnode *node, *nnode; + struct ospf_interface *oi; + struct in_addr area_id; + + ospf = ospf_lookup (); + if (!ospf) + return 1; /* Ospf not ready yet */ + + params = IF_DEF_PARAMS (ifp); + UNSET_IF_PARAM (params, if_area); + area_id = params->if_area; + + for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) + { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + if (oi->ifp == ifp) ospf_if_free (oi); + } + + /* Update connected redistribute. */ + update_redistributed(ospf, 0); /* interfaces possibly removed */ + ospf_area_check_free (ospf, area_id); return 1; } @@ -960,7 +1093,8 @@ ospf_if_update (struct ospf *ospf, struct interface *ifp) struct route_node *rn; struct ospf_network *network; struct ospf_area *area; - + struct ospf_if_params *params; + if (!ospf) ospf = ospf_lookup (); @@ -976,6 +1110,13 @@ ospf_if_update (struct ospf *ospf, struct interface *ifp) area = ospf_area_get (ospf, network->area_id, network->format); ospf_network_run_interface (&rn->p, area, ifp); } + + /* create oif for any new co */ + params = IF_DEF_PARAMS (ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + { + ospf_interface_set (ifp, params->if_area); + } } void diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 11525a5fb8..d98519a169 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -284,6 +284,9 @@ struct ospf /* Statistics for LSA used for new instantiation. */ u_int32_t rx_lsa_count; + /* Counter of "ip ospf area x.x.x.x" */ + u_int32_t if_ospf_cli_count; + struct route_table *distance_table; }; @@ -572,4 +575,6 @@ extern void ospf_snmp_init (void); extern void ospf_master_init (void); +extern int ospf_interface_set (struct interface *ifp, struct in_addr area_id); +extern int ospf_interface_unset (struct interface *ifp); #endif /* _ZEBRA_OSPFD_H */ -- 2.39.5