]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ospf6d: fix interface area configuration
authorIgor Ryzhov <iryzhov@nfware.com>
Tue, 25 May 2021 22:49:30 +0000 (01:49 +0300)
committerIgor Ryzhov <iryzhov@nfware.com>
Tue, 8 Jun 2021 18:38:09 +0000 (21:38 +0300)
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>
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_top.c

index 92934d3764d04c051e51e3475e75eb5102a65011..27ba030aedde9ba552817578cf50a34ecacdd59c 100644 (file)
 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;
index fa761d732dd9691b1bfcd12114f0fa74f17ad776..dd4d019015caf440656b711d2debd59021d5b4a7 100644 (file)
@@ -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 */
index b71d884fdc4c1c616d6fa10f8266856dee2a94e2..148f2dc50dedfdeebe2925c3b879d89679e2eba7 100644 (file)
@@ -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);
index fb1b947cf8e37848dccc7508d52f93b02540fa6c..796d75e89755b0b7566900f9f6a542d2a37bad34 100644 (file)
@@ -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 *);
index 33b5dd196072d177d7fc1611b4b3cecd04368b33..97b3bc096b8529d337d528beb7dbe285df026908 100644 (file)
@@ -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;