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>
This commit is contained in:
Igor Ryzhov 2021-05-26 01:49:30 +03:00
parent 6869bb921e
commit 42cabc552d
5 changed files with 216 additions and 51 deletions

View File

@ -50,20 +50,28 @@
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
/* Utility functions. */ int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt)
int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt)
{ {
char *ep; char *ep;
area_id->s_addr = htonl(strtoul(str, &ep, 10)); *area_id = htonl(strtoul(str, &ep, 10));
if (*ep && !inet_aton(str, area_id)) if (*ep && inet_pton(AF_INET, str, area_id) != 1)
return -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; 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) int ospf6_area_cmp(void *va, void *vb)
{ {
struct ospf6_area *oa = (struct ospf6_area *)va; struct ospf6_area *oa = (struct ospf6_area *)va;

View File

@ -31,6 +31,7 @@ struct ospf6_area {
/* Area-ID */ /* Area-ID */
in_addr_t area_id; in_addr_t area_id;
#define OSPF6_AREA_FMT_UNSET 0
#define OSPF6_AREA_FMT_DOTTEDQUAD 1 #define OSPF6_AREA_FMT_DOTTEDQUAD 1
#define OSPF6_AREA_FMT_DECIMAL 2 #define OSPF6_AREA_FMT_DECIMAL 2
/* Area-ID string */ /* Area-ID string */
@ -130,20 +131,22 @@ struct ospf6_area {
#define OSPF6_CMD_AREA_GET(str, oa, ospf6) \ #define OSPF6_CMD_AREA_GET(str, oa, ospf6) \
{ \ { \
char *ep; \ uint32_t area_id; \
uint32_t area_id = htonl(strtoul(str, &ep, 10)); \ int format, ret; \
if (*ep && inet_pton(AF_INET, str, &area_id) != 1) { \ ret = str2area_id(str, &area_id, &format); \
if (ret) { \
vty_out(vty, "Malformed Area-ID: %s\n", str); \ 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); \ oa = ospf6_area_lookup(area_id, ospf6); \
if (oa == NULL) \ if (oa == NULL) \
oa = ospf6_area_create(area_id, ospf6, format); \ oa = ospf6_area_create(area_id, ospf6, format); \
} }
/* prototypes */ /* 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 int ospf6_area_cmp(void *va, void *vb);
extern struct ospf6_area *ospf6_area_create(uint32_t, struct ospf6 *, int); 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); extern void ospf6_area_init(void);
struct ospf6_interface; struct ospf6_interface;
extern void ospf6_area_interface_delete(struct ospf6_interface *oi); 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 */ #endif /* OSPF_AREA_H */

View File

@ -36,6 +36,7 @@
#include "ospf6_message.h" #include "ospf6_message.h"
#include "ospf6_route.h" #include "ospf6_route.h"
#include "ospf6_area.h" #include "ospf6_area.h"
#include "ospf6_abr.h"
#include "ospf6_interface.h" #include "ospf6_interface.h"
#include "ospf6_neighbor.h" #include "ospf6_neighbor.h"
#include "ospf6_intra.h" #include "ospf6_intra.h"
@ -330,31 +331,6 @@ ospf6_interface_get_linklocal_address(struct interface *ifp)
return l; 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) void ospf6_interface_state_update(struct interface *ifp)
{ {
struct ospf6_interface *oi; struct ospf6_interface *oi;
@ -1638,7 +1614,143 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
return CMD_SUCCESS; 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 */ /* 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, DEFUN (ipv6_ospf6_ifmtu,
ipv6_ospf6_ifmtu_cmd, ipv6_ospf6_ifmtu_cmd,
"ipv6 ospf6 ifmtu (1-65535)", "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 ospf6_interface *oi;
struct interface *ifp; struct interface *ifp;
char buf[INET_ADDRSTRLEN];
FOR_ALL_INTERFACES (vrf, ifp) { FOR_ALL_INTERFACES (vrf, ifp) {
oi = (struct ospf6_interface *)ifp->info; 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) if (ifp->desc)
vty_out(vty, " description %s\n", 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) if (oi->c_ifmtu)
vty_out(vty, " ipv6 ospf6 ifmtu %d\n", 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)) if (IS_OSPF6_DEBUG_ZEBRA(RECV))
zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name, zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu6); ifp->ifindex, ifp->mtu6);
ospf6_interface_if_add(ifp);
if (ifp->info)
ospf6_interface_start(ifp->info);
return 0; return 0;
} }
@ -2468,6 +2588,9 @@ static int ospf6_ifp_destroy(struct interface *ifp)
zlog_debug("Zebra Interface delete: %s index %d mtu %d", zlog_debug("Zebra Interface delete: %s index %d mtu %d",
ifp->name, ifp->ifindex, ifp->mtu6); ifp->name, ifp->ifindex, ifp->mtu6);
if (ifp->info)
ospf6_interface_stop(ifp->info);
return 0; return 0;
} }
@ -2485,6 +2608,8 @@ void ospf6_interface_init(void)
&show_ipv6_ospf6_interface_ifname_prefix_cmd); &show_ipv6_ospf6_interface_ifname_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_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, &ipv6_ospf6_cost_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd);

View File

@ -39,6 +39,9 @@ struct ospf6_interface {
/* back pointer */ /* back pointer */
struct ospf6_area *area; struct ospf6_area *area;
uint32_t area_id;
int area_id_format;
/* list of ospf6 neighbor */ /* list of ospf6 neighbor */
struct list *neighbor_list; struct list *neighbor_list;
@ -177,6 +180,9 @@ extern const char *const ospf6_interface_state_str[];
/* Function Prototypes */ /* Function Prototypes */
extern void ospf6_interface_start(struct ospf6_interface *oi);
extern void ospf6_interface_stop(struct ospf6_interface *oi);
extern struct ospf6_interface * extern struct ospf6_interface *
ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id); ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);
extern struct ospf6_interface *ospf6_interface_create(struct interface *); 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_enable(struct ospf6_interface *);
extern void ospf6_interface_disable(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_state_update(struct interface *);
extern void ospf6_interface_connected_route_update(struct interface *); extern void ospf6_interface_connected_route_update(struct interface *);
extern void ospf6_interface_connected_route_add(struct connected *); extern void ospf6_interface_connected_route_add(struct connected *);

View File

@ -410,6 +410,8 @@ static struct ospf6 *ospf6_create(const char *name)
struct ospf6 *ospf6_instance_create(const char *name) struct ospf6 *ospf6_instance_create(const char *name)
{ {
struct ospf6 *ospf6; struct ospf6 *ospf6;
struct vrf *vrf;
struct interface *ifp;
ospf6 = ospf6_create(name); ospf6 = ospf6_create(name);
if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
@ -417,6 +419,13 @@ struct ospf6 *ospf6_instance_create(const char *name)
if (ospf6->router_id == 0) if (ospf6->router_id == 0)
ospf6_router_id_update(ospf6); ospf6_router_id_update(ospf6);
ospf6_add(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) if (ospf6->fd < 0)
return ospf6; return ospf6;
@ -867,7 +876,7 @@ DEFUN (no_ospf6_distance_ospf6,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (ospf6_interface_area, DEFUN_HIDDEN (ospf6_interface_area,
ospf6_interface_area_cmd, ospf6_interface_area_cmd,
"interface IFNAME area <A.B.C.D|(0-4294967295)>", "interface IFNAME area <A.B.C.D|(0-4294967295)>",
"Enable routing on an IPv6 interface\n" "Enable routing on an IPv6 interface\n"
@ -885,6 +894,13 @@ DEFUN (ospf6_interface_area,
struct interface *ifp; struct interface *ifp;
vrf_id_t vrf_id = VRF_DEFAULT; vrf_id_t vrf_id = VRF_DEFAULT;
int ipv6_count = 0; 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) if (ospf6->vrf_id != VRF_UNKNOWN)
vrf_id = ospf6->vrf_id; vrf_id = ospf6->vrf_id;
@ -917,8 +933,17 @@ DEFUN (ospf6_interface_area,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
/* parse Area-ID */ if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa, ospf6); 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 */ /* attach interface to area */
listnode_add(oa->if_list, oi); /* sort ?? */ listnode_add(oa->if_list, oi); /* sort ?? */
@ -942,7 +967,7 @@ DEFUN (ospf6_interface_area,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (no_ospf6_interface_area, DEFUN_HIDDEN (no_ospf6_interface_area,
no_ospf6_interface_area_cmd, no_ospf6_interface_area_cmd,
"no interface IFNAME area <A.B.C.D|(0-4294967295)>", "no interface IFNAME area <A.B.C.D|(0-4294967295)>",
NO_STR NO_STR
@ -962,6 +987,11 @@ DEFUN (no_ospf6_interface_area,
uint32_t area_id; uint32_t area_id;
vrf_id_t vrf_id = VRF_DEFAULT; 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) if (ospf6->vrf_id != VRF_UNKNOWN)
vrf_id = ospf6->vrf_id; vrf_id = ospf6->vrf_id;
@ -1008,6 +1038,9 @@ DEFUN (no_ospf6_interface_area,
ospf6_abr_disable_area(oa); ospf6_abr_disable_area(oa);
} }
oi->area_id = 0;
oi->area_id_format = OSPF6_AREA_FMT_UNSET;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -1585,9 +1618,6 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6)
/* OSPF configuration write function. */ /* OSPF configuration write function. */
static int config_write_ospf6(struct vty *vty) static int config_write_ospf6(struct vty *vty)
{ {
struct listnode *j, *k;
struct ospf6_area *oa;
struct ospf6_interface *oi;
struct ospf6 *ospf6; struct ospf6 *ospf6;
struct listnode *node, *nnode; struct listnode *node, *nnode;
@ -1638,11 +1668,6 @@ static int config_write_ospf6(struct vty *vty)
ospf6_distance_config_write(vty, ospf6); ospf6_distance_config_write(vty, ospf6);
ospf6_distribute_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"); vty_out(vty, "!\n");
} }
return 0; return 0;