diff options
author | Igor Ryzhov <iryzhov@nfware.com> | 2021-05-26 00:49:30 +0200 |
---|---|---|
committer | Igor Ryzhov <iryzhov@nfware.com> | 2021-06-08 20:38:09 +0200 |
commit | 42cabc552d50b3dbc658b88a27b75fd6a2f7bec5 (patch) | |
tree | 80f2fe12c51a8075e481376adc13eb37b90d7c54 | |
parent | tests: fix ospf6_topo1_vrf (diff) | |
download | frr-42cabc552d50b3dbc658b88a27b75fd6a2f7bec5.tar.xz frr-42cabc552d50b3dbc658b88a27b75fd6a2f7bec5.zip |
ospf6d: fix interface area configuration
Currently the interface area is configured from the router node using
"interface IFNAME area ID" command. There are multiple problems with
this command:
- it is not in line with all other interface-related commands - other
parameters are configured from the interface node using "ipv6 ospf6"
prefix
- it is not in line with OSPFv2 - area is configured from the interface
node using "ip ospf area" command
- most importantly, it doesn't work correctly when the interface is in
a different VRF - instead of configuring the interface, it creates a
new fake interface and configuring it instead
To fix all the problems, this commit adds a new command to the interface
configuration node - "ipv6 ospf6 area ID". The purpose of the command is
completely the same, but it works correctly in a multi-VRF environment.
The old command is preserved for the backward compatibility, but the
warning is added that it is deprecated because it doesn't work correctly
with VRFs.
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
-rw-r--r-- | ospf6d/ospf6_area.c | 18 | ||||
-rw-r--r-- | ospf6d/ospf6_area.h | 16 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.c | 177 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.h | 7 | ||||
-rw-r--r-- | ospf6d/ospf6_top.c | 49 |
5 files changed, 216 insertions, 51 deletions
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 92934d376..27ba030ae 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -50,20 +50,28 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name"); -/* Utility functions. */ -int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt) +int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt) { char *ep; - area_id->s_addr = htonl(strtoul(str, &ep, 10)); - if (*ep && !inet_aton(str, area_id)) + *area_id = htonl(strtoul(str, &ep, 10)); + if (*ep && inet_pton(AF_INET, str, area_id) != 1) return -1; - *area_id_fmt = *ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD; + *area_id_fmt = + !*ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD; return 0; } +void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt) +{ + if (area_id_fmt == OSPF6_AREA_FMT_DECIMAL) + snprintf(buf, len, "%u", ntohl(area_id)); + else + inet_ntop(AF_INET, &area_id, buf, len); +} + int ospf6_area_cmp(void *va, void *vb) { struct ospf6_area *oa = (struct ospf6_area *)va; diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index fa761d732..dd4d01901 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -31,6 +31,7 @@ struct ospf6_area { /* Area-ID */ in_addr_t area_id; +#define OSPF6_AREA_FMT_UNSET 0 #define OSPF6_AREA_FMT_DOTTEDQUAD 1 #define OSPF6_AREA_FMT_DECIMAL 2 /* Area-ID string */ @@ -130,20 +131,22 @@ struct ospf6_area { #define OSPF6_CMD_AREA_GET(str, oa, ospf6) \ { \ - char *ep; \ - uint32_t area_id = htonl(strtoul(str, &ep, 10)); \ - if (*ep && inet_pton(AF_INET, str, &area_id) != 1) { \ + uint32_t area_id; \ + int format, ret; \ + ret = str2area_id(str, &area_id, &format); \ + if (ret) { \ vty_out(vty, "Malformed Area-ID: %s\n", str); \ - return CMD_SUCCESS; \ + return CMD_WARNING; \ } \ - int format = !*ep ? OSPF6_AREA_FMT_DECIMAL \ - : OSPF6_AREA_FMT_DOTTEDQUAD; \ oa = ospf6_area_lookup(area_id, ospf6); \ if (oa == NULL) \ oa = ospf6_area_create(area_id, ospf6, format); \ } /* prototypes */ +extern int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt); +extern void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt); + extern int ospf6_area_cmp(void *va, void *vb); extern struct ospf6_area *ospf6_area_create(uint32_t, struct ospf6 *, int); @@ -163,6 +166,5 @@ extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6); extern void ospf6_area_init(void); struct ospf6_interface; extern void ospf6_area_interface_delete(struct ospf6_interface *oi); -int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt); #endif /* OSPF_AREA_H */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index b71d884fd..148f2dc50 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -36,6 +36,7 @@ #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_area.h" +#include "ospf6_abr.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" @@ -330,31 +331,6 @@ ospf6_interface_get_linklocal_address(struct interface *ifp) return l; } -void ospf6_interface_if_add(struct interface *ifp) -{ - struct ospf6_interface *oi; - unsigned int iobuflen; - - oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL) - return; - - /* Try to adjust I/O buffer size with IfMtu */ - if (oi->ifmtu == 0) - oi->ifmtu = ifp->mtu6; - iobuflen = ospf6_iobuf_size(ifp->mtu6); - if (oi->ifmtu > iobuflen) { - if (IS_OSPF6_DEBUG_INTERFACE) - zlog_debug( - "Interface %s: IfMtu is adjusted to I/O buffer size: %d.", - ifp->name, iobuflen); - oi->ifmtu = iobuflen; - } - - /* interface start */ - ospf6_interface_state_update(oi->interface); -} - void ospf6_interface_state_update(struct interface *ifp) { struct ospf6_interface *oi; @@ -1638,7 +1614,143 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, return CMD_SUCCESS; } +void ospf6_interface_start(struct ospf6_interface *oi) +{ + struct ospf6 *ospf6; + struct ospf6_area *oa; + + if (oi->area_id_format == OSPF6_AREA_FMT_UNSET) + return; + + ospf6 = ospf6_lookup_by_vrf_id(oi->interface->vrf_id); + if (!ospf6) + return; + + oa = ospf6_area_lookup(oi->area_id, ospf6); + if (oa == NULL) + oa = ospf6_area_create(oi->area_id, ospf6, oi->area_id_format); + + /* attach interface to area */ + listnode_add(oa->if_list, oi); + oi->area = oa; + + SET_FLAG(oa->flag, OSPF6_AREA_ENABLE); + + /* start up */ + ospf6_interface_enable(oi); + + /* If the router is ABR, originate summary routes */ + if (ospf6_is_router_abr(ospf6)) + ospf6_abr_enable_area(oa); +} + +void ospf6_interface_stop(struct ospf6_interface *oi) +{ + struct ospf6_area *oa; + + oa = oi->area; + if (!oa) + return; + + ospf6_interface_disable(oi); + + listnode_delete(oa->if_list, oi); + oi->area = NULL; + + if (oa->if_list->count == 0) { + UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE); + ospf6_abr_disable_area(oa); + } +} + /* interface variable set command */ +DEFUN (ipv6_ospf6_area, + ipv6_ospf6_area_cmd, + "ipv6 ospf6 area <A.B.C.D|(0-4294967295)>", + IP6_STR + OSPF6_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + "OSPF6 area ID in decimal notation\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; + int idx_ipv4 = 3; + uint32_t area_id; + int format; + int ipv6_count = 0; + + assert(ifp); + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + assert(oi); + + if (oi->area) { + vty_out(vty, "%s already attached to Area %s\n", + oi->interface->name, oi->area->name); + return CMD_SUCCESS; + } + + /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface + * then don't allow ospfv3 to be configured + */ + ipv6_count = connected_count_by_family(ifp, AF_INET6); + if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) { + vty_out(vty, + "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", + ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count); + return CMD_WARNING_CONFIG_FAILED; + } else if (oi->ifmtu >= OSPF6_JUMBO_MTU + && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) { + vty_out(vty, + "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", + ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count); + return CMD_WARNING_CONFIG_FAILED; + } + + if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { + vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + oi->area_id = area_id; + oi->area_id_format = format; + + ospf6_interface_start(oi); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_area, + no_ipv6_ospf6_area_cmd, + "no ipv6 ospf6 area [<A.B.C.D|(0-4294967295)>]", + NO_STR + IP6_STR + OSPF6_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + "OSPF6 area ID in decimal notation\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; + + assert(ifp); + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + assert(oi); + + ospf6_interface_stop(oi); + + oi->area_id = 0; + oi->area_id_format = OSPF6_AREA_FMT_UNSET; + + return CMD_SUCCESS; +} + DEFUN (ipv6_ospf6_ifmtu, ipv6_ospf6_ifmtu_cmd, "ipv6 ospf6 ifmtu (1-65535)", @@ -2334,6 +2446,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) { struct ospf6_interface *oi; struct interface *ifp; + char buf[INET_ADDRSTRLEN]; FOR_ALL_INTERFACES (vrf, ifp) { oi = (struct ospf6_interface *)ifp->info; @@ -2348,6 +2461,11 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); + if (oi->area_id_format != OSPF6_AREA_FMT_UNSET) { + area_id2str(buf, sizeof(buf), oi->area_id, + oi->area_id_format); + vty_out(vty, " ipv6 ospf6 area %s\n", buf); + } if (oi->c_ifmtu) vty_out(vty, " ipv6 ospf6 ifmtu %d\n", oi->c_ifmtu); @@ -2427,7 +2545,9 @@ static int ospf6_ifp_create(struct interface *ifp) if (IS_OSPF6_DEBUG_ZEBRA(RECV)) zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); - ospf6_interface_if_add(ifp); + + if (ifp->info) + ospf6_interface_start(ifp->info); return 0; } @@ -2468,6 +2588,9 @@ static int ospf6_ifp_destroy(struct interface *ifp) zlog_debug("Zebra Interface delete: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); + if (ifp->info) + ospf6_interface_stop(ifp->info); + return 0; } @@ -2485,6 +2608,8 @@ void ospf6_interface_init(void) &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_area_cmd); + install_element(INTERFACE_NODE, &no_ipv6_ospf6_area_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index fb1b947cf..796d75e89 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -39,6 +39,9 @@ struct ospf6_interface { /* back pointer */ struct ospf6_area *area; + uint32_t area_id; + int area_id_format; + /* list of ospf6 neighbor */ struct list *neighbor_list; @@ -177,6 +180,9 @@ extern const char *const ospf6_interface_state_str[]; /* Function Prototypes */ +extern void ospf6_interface_start(struct ospf6_interface *oi); +extern void ospf6_interface_stop(struct ospf6_interface *oi); + extern struct ospf6_interface * ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id); extern struct ospf6_interface *ospf6_interface_create(struct interface *); @@ -185,7 +191,6 @@ extern void ospf6_interface_delete(struct ospf6_interface *); extern void ospf6_interface_enable(struct ospf6_interface *); extern void ospf6_interface_disable(struct ospf6_interface *); -extern void ospf6_interface_if_add(struct interface *); extern void ospf6_interface_state_update(struct interface *); extern void ospf6_interface_connected_route_update(struct interface *); extern void ospf6_interface_connected_route_add(struct connected *); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 33b5dd196..97b3bc096 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -410,6 +410,8 @@ static struct ospf6 *ospf6_create(const char *name) struct ospf6 *ospf6_instance_create(const char *name) { struct ospf6 *ospf6; + struct vrf *vrf; + struct interface *ifp; ospf6 = ospf6_create(name); if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) @@ -417,6 +419,13 @@ struct ospf6 *ospf6_instance_create(const char *name) if (ospf6->router_id == 0) ospf6_router_id_update(ospf6); ospf6_add(ospf6); + if (ospf6->vrf_id != VRF_UNKNOWN) { + vrf = vrf_lookup_by_id(ospf6->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) { + if (ifp->info) + ospf6_interface_start(ifp->info); + } + } if (ospf6->fd < 0) return ospf6; @@ -867,7 +876,7 @@ DEFUN (no_ospf6_distance_ospf6, return CMD_SUCCESS; } -DEFUN (ospf6_interface_area, +DEFUN_HIDDEN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area <A.B.C.D|(0-4294967295)>", "Enable routing on an IPv6 interface\n" @@ -885,6 +894,13 @@ DEFUN (ospf6_interface_area, struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; int ipv6_count = 0; + uint32_t area_id; + int format; + + vty_out(vty, + "This command is deprecated, because it is not VRF-aware.\n"); + vty_out(vty, + "Please, use \"ipv6 ospf6 area\" on an interface instead.\n"); if (ospf6->vrf_id != VRF_UNKNOWN) vrf_id = ospf6->vrf_id; @@ -917,8 +933,17 @@ DEFUN (ospf6_interface_area, return CMD_WARNING_CONFIG_FAILED; } - /* parse Area-ID */ - OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa, ospf6); + if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { + vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + oi->area_id = area_id; + oi->area_id_format = format; + + oa = ospf6_area_lookup(area_id, ospf6); + if (oa == NULL) + oa = ospf6_area_create(area_id, ospf6, format); /* attach interface to area */ listnode_add(oa->if_list, oi); /* sort ?? */ @@ -942,7 +967,7 @@ DEFUN (ospf6_interface_area, return CMD_SUCCESS; } -DEFUN (no_ospf6_interface_area, +DEFUN_HIDDEN (no_ospf6_interface_area, no_ospf6_interface_area_cmd, "no interface IFNAME area <A.B.C.D|(0-4294967295)>", NO_STR @@ -962,6 +987,11 @@ DEFUN (no_ospf6_interface_area, uint32_t area_id; vrf_id_t vrf_id = VRF_DEFAULT; + vty_out(vty, + "This command is deprecated, because it is not VRF-aware.\n"); + vty_out(vty, + "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n"); + if (ospf6->vrf_id != VRF_UNKNOWN) vrf_id = ospf6->vrf_id; @@ -1008,6 +1038,9 @@ DEFUN (no_ospf6_interface_area, ospf6_abr_disable_area(oa); } + oi->area_id = 0; + oi->area_id_format = OSPF6_AREA_FMT_UNSET; + return CMD_SUCCESS; } @@ -1585,9 +1618,6 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6) /* OSPF configuration write function. */ static int config_write_ospf6(struct vty *vty) { - struct listnode *j, *k; - struct ospf6_area *oa; - struct ospf6_interface *oi; struct ospf6 *ospf6; struct listnode *node, *nnode; @@ -1638,11 +1668,6 @@ static int config_write_ospf6(struct vty *vty) ospf6_distance_config_write(vty, ospf6); ospf6_distribute_config_write(vty, ospf6); - for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, j, oa)) { - for (ALL_LIST_ELEMENTS_RO(oa->if_list, k, oi)) - vty_out(vty, " interface %s area %s\n", - oi->interface->name, oa->name); - } vty_out(vty, "!\n"); } return 0; |