back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_vlink.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 31 263 11.8 %
Date: 2023-02-24 18:38:32 Functions: 11 30 36.7 %

          Line data    Source code
       1             : /*
       2             :  * OSPFv3 virtual link implementation.
       3             :  *
       4             :  * Copyright (C) 2021 Network Device Education Foundation, Inc. ("NetDEF")
       5             :  *                    Rafael Zalamena
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "lib/zebra.h"
      23             : #include "lib/command.h"
      24             : #include "lib/memory.h"
      25             : 
      26             : #include "ospf6d/ospf6d.h"
      27             : #include "ospf6d/ospf6_area.h"
      28             : #include "ospf6d/ospf6_interface.h"
      29             : #include "ospf6d/ospf6_lsa.h"
      30             : #include "ospf6d/ospf6_message.h"
      31             : #include "ospf6d/ospf6_neighbor.h"
      32             : #include "ospf6d/ospf6_top.h"
      33             : #include "ospf6d/ospf6_vlink.h"
      34             : #include "ospf6d/ospf6_proto.h"
      35             : #include "ospf6d/ospf6_lsdb.h"
      36             : #include "ospf6d/ospf6_intra.h"
      37             : 
      38             : #ifndef VTYSH_EXTRACT_PL
      39             : #include "ospf6d/ospf6_vlink_clippy.c"
      40             : #endif /* VTYSH_EXTRACT_PL */
      41             : 
      42             : static uint8_t debug_vlink;
      43             : 
      44             : /* implementation note/rosetta stone:
      45             :  *
      46             :  * The most non-obvious aspect of this virtual link implementation is that it
      47             :  * uses ONE dummy interface for ALL virtual links, and that dummy interface is
      48             :  * a member of the backbone area.  Virtual links are neighbors on this dummy
      49             :  * interface, so everything works as usual for any neighbor in the backbone
      50             :  * area.  This dummy interface also ensures that the backbone area isn't
      51             :  * "empty" if the router only has virtual links.
      52             :  *
      53             :  * As a downside, this means the timers that are normally an interface
      54             :  * property are now duplicated as a virtual link property, but that's not a
      55             :  * huge impact.
      56             :  */
      57             : 
      58             : /* remaining TODOs:
      59             :  *
      60             :  * - verify router LSA updates from other routers that change their LA
      61             :  *   correctly propagate into the address being used for virtual links.  It
      62             :  *   works for most cases but there may be some corner cases left that don't
      63             :  *   update the address correctly.
      64             :  *
      65             :  * - authentication options for virtual links are completely missing
      66             :  *
      67             :  * - check if multiple parallel virtual links through different areas to the
      68             :  *   same router make sense.  (no clue if it does.  not currently supported.)
      69             :  *
      70             :  * - show commands.  There are none.
      71             :  */
      72             : 
      73          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VIRTUAL_LINK, "OSPF6 virtual link data");
      74          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VLINK_ADDR,   "OSPF6 virtual link address base");
      75             : 
      76           0 : static int ospf6_vlink_cmp(const struct ospf6_virtual_link *a,
      77             :                            const struct ospf6_virtual_link *b)
      78             : {
      79           0 :         return IPV4_ADDR_CMP(&a->remote, &b->remote);
      80             : }
      81             : 
      82           0 : DECLARE_RBTREE_UNIQ(ospf6_virtual_links, struct ospf6_virtual_link, item,
      83             :                     ospf6_vlink_cmp);
      84             : 
      85          34 : DECLARE_RBTREE_UNIQ(ospf6_area_vlinks, struct ospf6_virtual_link, areaitem,
      86             :                     ospf6_vlink_cmp);
      87             : 
      88           0 : static int ospf6_vlink_addr_cmp(const struct ospf6_vlink_addr *a,
      89             :                                 const struct ospf6_vlink_addr *b)
      90             : {
      91           0 :         return IPV6_ADDR_CMP(&a->remote_addr, &b->remote_addr);
      92             : }
      93             : 
      94           0 : DECLARE_RBTREE_UNIQ(ospf6_vlink_addrs, struct ospf6_vlink_addr, item,
      95             :                     ospf6_vlink_addr_cmp);
      96             : 
      97          64 : size_t ospf6_vlink_area_vlcount(struct ospf6_area *oa)
      98             : {
      99          64 :         return ospf6_area_vlinks_count(oa->vlinks);
     100             : }
     101             : 
     102           0 : static void ospf6_vlink_prep(struct ospf6 *o)
     103             : {
     104           0 :         struct interface *ifp;
     105             : 
     106           0 :         if (o->vlink_oi)
     107             :                 return;
     108             : 
     109           0 :         if (debug_vlink)
     110           0 :                 zlog_debug("creating OSPFv3 virtual link interface for VRF %u",
     111             :                            o->vrf_id);
     112             : 
     113             :         /* it is very intentional that the dummy interface has an empty
     114             :          * interface name;  otherwise the user could try to "configure" things
     115             :          * on this interface (which would just wreak havoc.)  With an empty
     116             :          * interface name, the CLI can't invoke "interface XYZ" commands.
     117             :          */
     118           0 :         ifp = if_create_virtual(vrf_lookup_by_id(o->vrf_id));
     119           0 :         UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
     120           0 :         SET_FLAG(ifp->flags, IFF_LOOPBACK | IFF_VIRTUAL);
     121             : 
     122           0 :         ifp->desc = asprintfrr(MTYPE_TMP, "OSPFv3 virtual link (VRF %u)",
     123             :                                o->vrf_id);
     124             : 
     125           0 :         o->vlink_oi = ospf6_interface_basic_create(ifp);
     126           0 :         o->vlink_oi->type = OSPF_IFTYPE_VIRTUALLINK;
     127           0 :         o->vlink_oi->state = OSPF6_INTERFACE_VIRTUALLINK;
     128           0 :         o->vlink_oi->ifmtu = 65520;
     129           0 :         o->vlink_oi->mtu_ignore = true;
     130             : 
     131           0 :         o->vlink_oi->area_id = 0;
     132           0 :         o->vlink_oi->area_id_format = OSPF6_AREA_FMT_DOTTEDQUAD;
     133             : 
     134           0 :         o->last_vlink_ifindex = 0x80000000;
     135             : 
     136           0 :         ospf6_interface_start(o->vlink_oi);
     137             : }
     138             : 
     139           0 : static void ospf6_vlink_unprep(struct ospf6 *o)
     140             : {
     141           0 :         struct interface *ifp;
     142             : 
     143           0 :         if (ospf6_virtual_links_count(o->vlinks))
     144           0 :                 return;
     145             : 
     146           0 :         if (debug_vlink)
     147           0 :                 zlog_debug("removing OSPFv3 virtual link interface for VRF %u",
     148             :                            o->vrf_id);
     149             : 
     150           0 :         ospf6_interface_stop(o->vlink_oi);
     151             : 
     152           0 :         ifp = o->vlink_oi->interface;
     153           0 :         ospf6_interface_basic_delete(o->vlink_oi);
     154           0 :         o->vlink_oi = NULL;
     155             : 
     156           0 :         if_delete(&ifp);
     157             : }
     158             : 
     159             : /**
     160             :  * Find OSPF virtual link by attributes.
     161             :  */
     162           0 : struct ospf6_virtual_link *ospf6_virtual_link_find(struct ospf6 *o,
     163             :                                                    struct in_addr remote)
     164             : {
     165           0 :         struct ospf6_virtual_link ref;
     166             : 
     167           0 :         ref.remote = remote;
     168           0 :         return ospf6_virtual_links_find(o->vlinks, &ref);
     169             : }
     170             : 
     171           0 : static struct ospf6_vlink_addr *ospf6_vlink_addr_new(
     172             :                 struct ospf6_virtual_link *vlink, struct in6_addr *addr)
     173             : {
     174           0 :         struct ospf6_vlink_addr *vaddr;
     175             : 
     176           0 :         vaddr = XCALLOC(MTYPE_OSPF6_VLINK_ADDR, sizeof(*vaddr));
     177           0 :         vaddr->remote_addr = *addr;
     178           0 :         return vaddr;
     179             : }
     180             : 
     181           0 : static void ospf6_vlink_addr_delall(struct ospf6_vlink_addrs_head *head)
     182             : {
     183           0 :         struct ospf6_vlink_addr *vaddr;
     184             : 
     185           0 :         while ((vaddr = ospf6_vlink_addrs_pop(head))) {
     186           0 :                 XFREE(MTYPE_OSPF6_VLINK_ADDR, vaddr);
     187             :         }
     188           0 : }
     189             : 
     190           0 : static void ospf6_vlink_hello(struct thread *t)
     191             : {
     192           0 :         struct ospf6_virtual_link *vlink = THREAD_ARG(t);
     193             : 
     194           0 :         ospf6_hello_send_addr(vlink->ospf6->vlink_oi, vlink, &vlink->transport);
     195             : 
     196           0 :         thread_add_timer(master, ospf6_vlink_hello, vlink,
     197             :                          vlink->hello_interval, &vlink->t_hello);
     198           0 : }
     199             : 
     200           0 : static void ospf6_vlink_refresh(struct ospf6_virtual_link *vlink)
     201             : {
     202           0 :         struct ospf6_vlink_addrs_head oldaddrs[1];
     203           0 :         struct ospf6_vlink_addr *vaddr, ref, *bestaddr = NULL;
     204           0 :         struct ospf6_route *ort;
     205           0 :         struct ospf6_lsa *lsa;
     206           0 :         struct prefix pfx;
     207           0 :         bool changed = false;
     208             : 
     209           0 :         ospf6_vlink_addrs_init(oldaddrs);
     210           0 :         ospf6_vlink_addrs_swap_all(oldaddrs, vlink->addrs);
     211             : 
     212           0 :         for (ALL_LSDB_TYPED_ADVRTR(vlink->area->lsdb,
     213             :                                    htons(OSPF6_LSTYPE_INTRA_PREFIX),
     214             :                                    vlink->remote.s_addr, lsa)) {
     215           0 :                 struct ospf6_intra_prefix_lsa *lsa_intra;
     216           0 :                 struct ospf6_prefix *op;
     217           0 :                 size_t i, count;
     218             : 
     219           0 :                 lsa_intra = (struct ospf6_intra_prefix_lsa *)(lsa->header + 1);
     220           0 :                 op = (struct ospf6_prefix *)(lsa_intra + 1);
     221           0 :                 count = ntohs(lsa_intra->prefix_num);
     222             : 
     223           0 :                 for (i = 0; i < count; i++, op = OSPF6_PREFIX_NEXT(op)) {
     224           0 :                         struct in6_addr *addr = op->addr;
     225             : 
     226           0 :                         if (!(op->prefix_options & OSPF6_PREFIX_OPTION_LA))
     227           0 :                                 continue;
     228             : 
     229           0 :                         ref.remote_addr = *addr;
     230           0 :                         vaddr = ospf6_vlink_addrs_find(oldaddrs, &ref);
     231           0 :                         if (vaddr)
     232           0 :                                 ospf6_vlink_addrs_del(oldaddrs, vaddr);
     233             :                         else
     234           0 :                                 vaddr = ospf6_vlink_addr_new(vlink, addr);
     235           0 :                         ospf6_vlink_addrs_add(vlink->addrs, vaddr);
     236             : 
     237           0 :                         if (!bestaddr)
     238           0 :                                 bestaddr = vaddr;
     239             :                 }
     240             :         }
     241             : 
     242           0 :         ospf6_linkstate_prefix(vlink->remote.s_addr, INADDR_ANY, &pfx);
     243           0 :         ort = ospf6_route_lookup(&pfx, vlink->area->spf_table);
     244             : 
     245           0 :         if (!ort || !bestaddr) {
     246           0 :                 const char *reason = ort ? "no routable address" : "no route";
     247             : 
     248           0 :                 if (vlink->spf_cost == ~0U)
     249           0 :                         goto out;
     250             : 
     251           0 :                 changed = true;
     252           0 :                 if (debug_vlink)
     253           0 :                         zlog_debug(
     254             :                                 "Virtual link to %pI4 through area %pI4 down (%s)",
     255             :                                 &vlink->remote, &vlink->area->area_id, reason);
     256             : 
     257           0 :                 vlink->spf_cost = ~0U;
     258           0 :                 memset(&vlink->transport, 0, sizeof(vlink->transport));
     259           0 :                 ospf6_neighbor_vlink_change(vlink->nbr, false);
     260             : 
     261           0 :                 THREAD_OFF(vlink->t_hello);
     262           0 :                 goto out;
     263             :         }
     264             : 
     265           0 :         if (debug_vlink)
     266           0 :                 zlog_debug(
     267             :                         "Virtual link to %pI4 (area %pI4): using %pI6, cost %u",
     268             :                         &vlink->remote, &vlink->area->area_id,
     269             :                         &bestaddr->remote_addr, ort->path.cost);
     270             : 
     271           0 :         if (!IPV6_ADDR_SAME(&vlink->transport, &bestaddr->remote_addr)) {
     272           0 :                 if (debug_vlink)
     273           0 :                         zlog_debug(
     274             :                                 "Virtual link to %pI4 (area %pI4) address changed",
     275             :                                 &vlink->remote, &vlink->area->area_id);
     276             : 
     277           0 :                 vlink->transport = bestaddr->remote_addr;
     278           0 :                 changed = true;
     279             :         }
     280           0 :         if (ort->path.cost != vlink->spf_cost) {
     281           0 :                 if (debug_vlink)
     282           0 :                         zlog_debug(
     283             :                                 "Virtual link to %pI4 (area %pI4) cost changed",
     284             :                                 &vlink->remote, &vlink->area->area_id);
     285             : 
     286           0 :                 vlink->spf_cost = ort->path.cost;
     287           0 :                 changed = true;
     288             :         }
     289             : 
     290           0 :         if (vlink->nbr->state < OSPF6_NEIGHBOR_ATTEMPT) {
     291           0 :                 ospf6_neighbor_vlink_change(vlink->nbr, true);
     292           0 :                 thread_add_timer(master, ospf6_vlink_hello, vlink,
     293             :                                  vlink->hello_interval, &vlink->t_hello);
     294             :         }
     295           0 : out:
     296           0 :         if (changed)
     297           0 :                 OSPF6_ROUTER_LSA_SCHEDULE(vlink->ospf6->backbone);
     298             : 
     299           0 :         ospf6_vlink_addr_delall(oldaddrs);
     300           0 : }
     301             : 
     302          18 : void ospf6_vlink_area_calculation(struct ospf6_area *oa)
     303             : {
     304          18 :         struct ospf6_virtual_link *vlink;
     305             : 
     306          18 :         assert(oa->area_id != 0);
     307             : 
     308          18 :         if (debug_vlink)
     309           0 :                 zlog_debug("recalculating %zu virtual links on area %pI4",
     310             :                            ospf6_area_vlinks_count(oa->vlinks), &oa->area_id);
     311             : 
     312          36 :         frr_each (ospf6_area_vlinks, oa->vlinks, vlink)
     313           0 :                 ospf6_vlink_refresh(vlink);
     314          18 : }
     315             : 
     316          73 : void ospf6_vlink_prefix_update(struct ospf6_area *oa, in_addr_t rtr)
     317             : {
     318          73 :         struct ospf6_virtual_link *vlink, ref;
     319             : 
     320          73 :         if (oa->area_id == 0)
     321          73 :                 return;
     322             : 
     323          11 :         ref.remote.s_addr = rtr;
     324          11 :         vlink = ospf6_area_vlinks_find(oa->vlinks, &ref);
     325          11 :         if (!vlink)
     326             :                 return;
     327             : 
     328           0 :         if (debug_vlink)
     329           0 :                 zlog_debug("recalculating virtual link addrs in %pI4 for %pI4",
     330             :                            &oa->area_id, &rtr);
     331             : 
     332           0 :         ospf6_vlink_refresh(vlink);
     333             : }
     334             : 
     335             : /**
     336             :  * OSPF virtual link registration function.
     337             :  *
     338             :  * Allocates memory and registers virtual link in OSPF instance / area.
     339             :  */
     340           0 : static struct ospf6_virtual_link *ospf6_virtual_link_new(struct ospf6_area *oa,
     341             :                                                          struct in_addr remote)
     342             : {
     343           0 :         struct ospf6_virtual_link *vlink;
     344             : 
     345           0 :         ospf6_vlink_prep(oa->ospf6);
     346             : 
     347           0 :         vlink = XCALLOC(MTYPE_OSPF6_VIRTUAL_LINK, sizeof(*vlink));
     348           0 :         vlink->ospf6 = oa->ospf6;
     349           0 :         vlink->area = oa;
     350           0 :         vlink->remote = remote;
     351           0 :         vlink->spf_cost = ~0U;
     352           0 :         ospf6_vlink_addrs_init(vlink->addrs);
     353             : 
     354           0 :         oa->ospf6->last_vlink_ifindex++;
     355           0 :         if (oa->ospf6->last_vlink_ifindex == 0)
     356           0 :                 oa->ospf6->last_vlink_ifindex = 0x80000000;
     357           0 :         vlink->v_ifindex = htonl(oa->ospf6->last_vlink_ifindex);
     358             : 
     359           0 :         vlink->dead_interval = VLINK_DEFAULT_DEAD_INTERVAL;
     360           0 :         vlink->hello_interval = VLINK_DEFAULT_HELLO_INTERVAL;
     361           0 :         vlink->transmit_delay = VLINK_DEFAULT_TRANSMIT_DELAY;
     362           0 :         vlink->retransmit_interval = VLINK_DEFAULT_RETRANSMIT_INTERVAL;
     363             : 
     364           0 :         ospf6_virtual_links_add(oa->ospf6->vlinks, vlink);
     365           0 :         ospf6_area_vlinks_add(oa->vlinks, vlink);
     366             : 
     367           0 :         vlink->nbr = ospf6_neighbor_create(remote.s_addr, oa->ospf6->vlink_oi);
     368           0 :         vlink->nbr->vlink = vlink;
     369             : 
     370           0 :         if (ospf6_area_vlinks_count(oa->vlinks) == 1)
     371             :                 /* make sure we have an intra-prefix with LA advertised */
     372           0 :                 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa);
     373             : 
     374           0 :         return vlink;
     375             : }
     376             : 
     377             : /**
     378             :  * OSPF virtual link removal function.
     379             :  *
     380             :  * Tears down the virtual link, remove area registration and free resources.
     381             :  */
     382           0 : static void ospf6_virtual_link_free(struct ospf6_virtual_link **vlink)
     383             : {
     384           0 :         struct ospf6_area *oa;
     385             : 
     386           0 :         if ((*vlink) == NULL)
     387             :                 return;
     388             : 
     389           0 :         oa = (*vlink)->area;
     390           0 :         THREAD_OFF((*vlink)->t_hello);
     391             : 
     392           0 :         if (ospf6_area_vlinks_count(oa->vlinks) == 0)
     393             :                 /* drop LA, maybe */
     394           0 :                 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa);
     395             : 
     396           0 :         (*vlink)->nbr->vlink = NULL;
     397           0 :         ospf6_neighbor_delete((*vlink)->nbr);
     398             : 
     399           0 :         ospf6_area_vlinks_del(oa->vlinks, (*vlink));
     400           0 :         ospf6_virtual_links_del(oa->ospf6->vlinks, (*vlink));
     401           0 :         ospf6_vlink_addr_delall((*vlink)->addrs);
     402           0 :         ospf6_vlink_addrs_fini((*vlink)->addrs);
     403           0 :         XFREE(MTYPE_OSPF6_VIRTUAL_LINK, (*vlink));
     404             : 
     405           0 :         ospf6_vlink_unprep(oa->ospf6);
     406             : }
     407             : 
     408           0 : void ospf6_vlink_init(struct ospf6 *o)
     409             : {
     410           0 :         ospf6_virtual_links_init(o->vlinks);
     411           0 : }
     412             : 
     413           0 : void ospf6_vlink_fini(struct ospf6 *o)
     414             : {
     415           0 :         struct ospf6_virtual_link *vlink;
     416             : 
     417           0 :         while ((vlink = ospf6_virtual_links_first(o->vlinks)))
     418           0 :                 ospf6_virtual_link_free(&vlink);
     419             : 
     420           0 :         ospf6_virtual_links_fini(o->vlinks);
     421           0 : }
     422             : 
     423           5 : void ospf6_vlink_area_init(struct ospf6_area *oa)
     424             : {
     425           5 :         ospf6_area_vlinks_init(oa->vlinks);
     426           5 : }
     427             : 
     428           5 : void ospf6_vlink_area_fini(struct ospf6_area *oa)
     429             : {
     430           5 :         struct ospf6_virtual_link *vlink;
     431             : 
     432          10 :         while ((vlink = ospf6_area_vlinks_first(oa->vlinks)))
     433           0 :                 ospf6_virtual_link_free(&vlink);
     434             : 
     435           5 :         ospf6_area_vlinks_fini(oa->vlinks);
     436           5 : }
     437             : 
     438             : /*
     439             :  * Commands
     440             :  */
     441           0 : DEFPY (debug_ospf6_vlink,
     442             :        debug_ospf6_vlink_cmd,
     443             :        "[no] debug ospf6 virtual-link",
     444             :        NO_STR
     445             :        DEBUG_STR
     446             :        OSPF6_STR
     447             :        "Debug OSPFv3 Virtual link management\n"
     448             :       )
     449             : {
     450           0 :         uint8_t flag = (vty->node == CONFIG_NODE) ? (1 << 1) : (1 << 0);
     451             : 
     452           0 :         if (no)
     453           0 :                 debug_vlink &= ~flag;
     454             :         else
     455           0 :                 debug_vlink |= flag;
     456           0 :         return CMD_SUCCESS;
     457             : }
     458             : 
     459           0 : void config_write_ospf6_debug_vlink(struct vty *vty)
     460             : {
     461           0 :         if (debug_vlink & (1 << 1))
     462           0 :                 vty_out(vty, "debug ospf6 virtual-link\n");
     463           0 : }
     464             : 
     465           0 : DEFPY(ospf6_vlink_config, ospf6_vlink_config_cmd,
     466             :       "[no] area <A.B.C.D$area_dot|(0-4294967295)$area_num> virtual-link A.B.C.D$peer "
     467             :       "[{hello-interval (1-65535)$hello|retransmit-interval (1-65535)$retx"
     468             :       "|transmit-delay (1-65535)$tx|dead-interval (1-65535)$dead}]",
     469             :       NO_STR
     470             :       "OSPF area parameters\n"
     471             :       "OSPF area ID in IP address format\n"
     472             :       "OSPF area ID as a decimal value\n"
     473             :       "Configure a virtual link\n"
     474             :       "Router ID of the remote ABR\n"
     475             :       "Hello packets interval\n"
     476             :       "Hello packets interval in seconds\n"
     477             :       "Retransmission interval between lost link state advertisements\n"
     478             :       "Retransmission interval between lost link state advertisements in seconds\n"
     479             :       "Link state transmission interval\n"
     480             :       "Link state transmission interval in seconds\n"
     481             :       "Interval before declaring a peer dead\n"
     482             :       "Interval before declaring a peer dead in seconds\n")
     483             : {
     484           0 :         struct ospf6_virtual_link *vlink;
     485           0 :         struct ospf6_area *oa;
     486           0 :         uint32_t area;
     487           0 :         VTY_DECLVAR_CONTEXT(ospf6, o);
     488             : 
     489           0 :         if (area_dot_str)
     490           0 :                 area = area_dot.s_addr;
     491             :         else
     492           0 :                 area = htonl(area_num);
     493             : 
     494             :         /* Validations. */
     495           0 :         if (area == 0) {
     496           0 :                 vty_out(vty,
     497             :                         "Virtual links cannot be configured on backbone\n");
     498           0 :                 return CMD_WARNING;
     499             :         }
     500             : 
     501           0 :         oa = ospf6_area_lookup(area, o);
     502           0 :         if (oa == NULL) {
     503           0 :                 vty_out(vty, "OSPFv3 area %u does not exist\n", area);
     504           0 :                 return CMD_WARNING;
     505             :         }
     506             : 
     507           0 :         if (IS_AREA_STUB(oa) || IS_AREA_NSSA(oa)) {
     508           0 :                 vty_out(vty,
     509             :                         "Virtual link can only be configured on regular areas");
     510           0 :                 return CMD_WARNING;
     511             :         }
     512             : 
     513           0 :         vlink = ospf6_virtual_link_find(o, peer);
     514           0 :         if (vlink && vlink->area->area_id != area) {
     515           0 :                 vty_out(vty,
     516             :                         "Virtual link to %pI4 exists in different area %pI4",
     517             :                         &peer, &vlink->area->area_id);
     518           0 :                 return CMD_WARNING;
     519             :         }
     520             : 
     521             :         /* Handle configuration removal. */
     522           0 :         if (no) {
     523           0 :                 if (vlink == NULL)
     524             :                         return CMD_SUCCESS;
     525             : 
     526           0 :                 ospf6_virtual_link_free(&vlink);
     527           0 :                 return CMD_SUCCESS;
     528             :         }
     529             : 
     530             :         /* Create and apply. */
     531           0 :         if (vlink == NULL)
     532           0 :                 vlink = ospf6_virtual_link_new(oa, peer);
     533             : 
     534           0 :         if (retx_str)
     535           0 :                 vlink->retransmit_interval = retx;
     536           0 :         if (tx_str)
     537           0 :                 vlink->transmit_delay = tx;
     538           0 :         if (hello_str)
     539           0 :                 vlink->hello_interval = hello;
     540           0 :         if (dead_str)
     541           0 :                 vlink->dead_interval = dead;
     542             : 
     543           0 :         ospf6_vlink_refresh(vlink);
     544             : 
     545           0 :         return CMD_SUCCESS;
     546             : }
     547             : 
     548           0 : void ospf6_vlink_area_config(struct ospf6_area *oa, struct vty *vty)
     549             : {
     550           0 :         struct ospf6_virtual_link *vlink;
     551             : 
     552           0 :         frr_each (ospf6_area_vlinks, oa->vlinks, vlink) {
     553           0 :                 vty_out(vty, " area %s virtual-link %pI4", oa->name,
     554             :                         &vlink->remote);
     555           0 :                 if (vlink->hello_interval != VLINK_DEFAULT_HELLO_INTERVAL)
     556           0 :                         vty_out(vty, " hello-interval %u", vlink->hello_interval);
     557           0 :                 if (vlink->dead_interval != VLINK_DEFAULT_DEAD_INTERVAL)
     558           0 :                         vty_out(vty, " dead-interval %u", vlink->dead_interval);
     559           0 :                 if (vlink->retransmit_interval != VLINK_DEFAULT_RETRANSMIT_INTERVAL)
     560           0 :                         vty_out(vty, " retransmit-interval %u", vlink->retransmit_interval);
     561           0 :                 if (vlink->transmit_delay != VLINK_DEFAULT_TRANSMIT_DELAY)
     562           0 :                         vty_out(vty, " transmit-delay %u", vlink->transmit_delay);
     563             : 
     564           0 :                 vty_out(vty, "\n");
     565             :         }
     566           0 : }
     567             : 
     568           4 : void ospf6_virtual_link_init(void)
     569             : {
     570           4 :         install_element(ENABLE_NODE, &debug_ospf6_vlink_cmd);
     571           4 :         install_element(CONFIG_NODE, &debug_ospf6_vlink_cmd);
     572             : 
     573           4 :         install_element(OSPF6_NODE, &ospf6_vlink_config_cmd);
     574           4 : }

Generated by: LCOV version v1.16-topotato