]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #13632 from LabNConsulting/chopps/mgmt-avoid-race
authorDonald Sharp <donaldsharp72@gmail.com>
Wed, 31 May 2023 11:28:50 +0000 (07:28 -0400)
committerGitHub <noreply@github.com>
Wed, 31 May 2023 11:28:50 +0000 (07:28 -0400)
mgmtd: fix possible race btw read config and backend connection

13 files changed:
bgpd/bgp_attr.c
ldpd/hello.c
lib/if.c
mgmtd/subdir.am
ospf6d/ospf6_gr.c
ospf6d/ospf6_gr.h
ospfd/ospf_gr.c
ospfd/ospf_gr.h
pimd/pim_cmd_common.c
ripd/subdir.am
tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
zebra/interface.c

index d5223a1e6e4a63b86b9648dc4577b61f5ae38498..ec9f12d61a16e83bb53b0364f7533eb58bb08aab 100644 (file)
@@ -4682,6 +4682,10 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
                 * there! (JK)
                 * Folks, talk to me: what is reasonable here!?
                 */
+
+               /* Make sure dup aspath before the modification */
+               if (aspath == attr->aspath)
+                       aspath = aspath_dup(attr->aspath);
                aspath = aspath_delete_confed_seq(aspath);
 
                stream_putc(s,
index 83c0b2f8ca00c981a571a090bf5f45df18d617ee..0b07f24b45816bf8f185176f6ec949173e574521 100644 (file)
@@ -41,8 +41,8 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
                /* multicast destination address */
                switch (af) {
                case AF_INET:
-                       if (!(leconf->ipv4.flags & F_LDPD_AF_NO_GTSM))
-                               flags |= F_HELLO_GTSM;
+                       if (!CHECK_FLAG(leconf->ipv4.flags, F_LDPD_AF_NO_GTSM))
+                               SET_FLAG(flags, F_HELLO_GTSM);
                        dst.v4 = global.mcast_addr_v4;
                        break;
                case AF_INET6:
@@ -56,9 +56,11 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
                af = tnbr->af;
                holdtime = tnbr_get_hello_holdtime(tnbr);
                flags = F_HELLO_TARGETED;
-               if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count
-                   || tnbr->rlfa_count)
+               if (CHECK_FLAG(tnbr->flags, F_TNBR_CONFIGURED) ||
+                       tnbr->pw_count ||
+                       tnbr->rlfa_count)
                        flags |= F_HELLO_REQ_TARG;
+
                fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
 
                /* unicast destination address */
@@ -88,10 +90,10 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
        if ((buf = ibuf_open(size)) == NULL)
                fatal(__func__);
 
-       err |= gen_ldp_hdr(buf, size);
+       SET_FLAG(err, gen_ldp_hdr(buf, size));
        size -= LDP_HDR_SIZE;
-       err |= gen_msg_hdr(buf, MSG_TYPE_HELLO, size);
-       err |= gen_hello_prms_tlv(buf, holdtime, flags);
+       SET_FLAG(err, gen_msg_hdr(buf, MSG_TYPE_HELLO, size));
+       SET_FLAG(err, gen_hello_prms_tlv(buf, holdtime, flags));
 
        /*
         * RFC 7552 - Section 6.1:
@@ -101,19 +103,19 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
         */
        switch (af) {
        case AF_INET:
-               err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
-                   leconf->ipv4.trans_addr.v4.s_addr);
+               SET_FLAG(err, gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
+                   leconf->ipv4.trans_addr.v4.s_addr));
                break;
        case AF_INET6:
-               err |= gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR,
-                   leconf->ipv6.trans_addr.v6.s6_addr);
+               SET_FLAG(err, gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR,
+                   leconf->ipv6.trans_addr.v6.s6_addr));
                break;
        default:
                fatalx("send_hello: unknown af");
        }
 
-       err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_CONFIG,
-           htonl(global.conf_seqnum));
+       SET_FLAG(err, gen_opt4_hello_prms_tlv(buf, TLV_TYPE_CONFIG,
+           htonl(global.conf_seqnum)));
 
        /*
         * RFC 7552 - Section 6.1.1:
@@ -121,7 +123,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
         * MUST include the Dual-Stack capability TLV in all of its LDP Hellos".
         */
        if (ldp_is_dual_stack(leconf))
-               err |= gen_ds_hello_prms_tlv(buf, leconf->trans_pref);
+               SET_FLAG(err, gen_ds_hello_prms_tlv(buf, leconf->trans_pref));
 
        if (err) {
                ibuf_free(buf);
@@ -169,8 +171,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
 
        r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
        if (r == -1) {
-               log_debug("%s: lsr-id %pI4: failed to decode params", __func__,
-                   &lsr_id);
+               log_debug("%s: lsr-id %pI4: failed to decode params", __func__, &lsr_id);
                return;
        }
        /* safety checks */
@@ -179,14 +180,12 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                    __func__, &lsr_id, holdtime);
                return;
        }
-       if (multicast && (flags & F_HELLO_TARGETED)) {
-               log_debug("%s: lsr-id %pI4: multicast targeted hello", __func__,
-                   &lsr_id);
+       if (multicast && CHECK_FLAG(flags, F_HELLO_TARGETED)) {
+               log_debug("%s: lsr-id %pI4: multicast targeted hello", __func__, &lsr_id);
                return;
        }
-       if (!multicast && !((flags & F_HELLO_TARGETED))) {
-               log_debug("%s: lsr-id %pI4: unicast link hello", __func__,
-                   &lsr_id);
+       if (!multicast && !CHECK_FLAG(flags, F_HELLO_TARGETED)) {
+               log_debug("%s: lsr-id %pI4: unicast link hello", __func__, &lsr_id);
                return;
        }
        buf += r;
@@ -204,10 +203,10 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                    __func__, &lsr_id);
                return;
        }
-       ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0;
+       ds_tlv = CHECK_FLAG(tlvs_rcvd, F_HELLO_TLV_RCVD_DS) ? 1 : 0;
 
        /* implicit transport address */
-       if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR))
+       if (!CHECK_FLAG(tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
                trans_addr = *src;
        if (bad_addr(af, &trans_addr)) {
                log_debug("%s: lsr-id %pI4: invalid transport address %s",
@@ -223,7 +222,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                 * (i.e., MUST discard the targeted Hello if it failed the
                 * check)".
                 */
-               if (flags & F_HELLO_TARGETED) {
+               if (CHECK_FLAG(flags, F_HELLO_TARGETED)) {
                        log_debug("%s: lsr-id %pI4: invalid targeted hello transport address %s", __func__, &lsr_id,
                             log_addr(af, &trans_addr));
                        return;
@@ -232,7 +231,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
        }
 
        memset(&source, 0, sizeof(source));
-       if (flags & F_HELLO_TARGETED) {
+       if (CHECK_FLAG(flags, F_HELLO_TARGETED)) {
                /*
                 * RFC 7552 - Section 5.2:
                * "The link-local IPv6 addresses MUST NOT be used as the
@@ -247,26 +246,27 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                tnbr = tnbr_find(leconf, af, src);
 
                /* remove the dynamic tnbr if the 'R' bit was cleared */
-               if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC) &&
-                   !((flags & F_HELLO_REQ_TARG))) {
-                       tnbr->flags &= ~F_TNBR_DYNAMIC;
+               if (tnbr && 
+                   CHECK_FLAG(tnbr->flags, F_TNBR_DYNAMIC) &&
+                   !CHECK_FLAG(flags, F_HELLO_REQ_TARG)) {
+                       UNSET_FLAG(tnbr->flags, F_TNBR_DYNAMIC);
                        tnbr = tnbr_check(leconf, tnbr);
                }
 
                if (!tnbr) {
                        struct ldpd_af_conf     *af_conf;
 
-                       if (!(flags & F_HELLO_REQ_TARG))
+                       if (!CHECK_FLAG(flags, F_HELLO_REQ_TARG))
                                return;
                        af_conf = ldp_af_conf_get(leconf, af);
-                       if (!(af_conf->flags & F_LDPD_AF_THELLO_ACCEPT))
+                       if (!CHECK_FLAG(af_conf->flags, F_LDPD_AF_THELLO_ACCEPT))
                                return;
                        if (ldpe_acl_check(af_conf->acl_thello_accept_from, af,
                            src, (af == AF_INET) ? 32 : 128) != FILTER_PERMIT)
                                return;
 
                        tnbr = tnbr_new(af, src);
-                       tnbr->flags |= F_TNBR_DYNAMIC;
+                       SET_FLAG(tnbr->flags, F_TNBR_DYNAMIC);
                        tnbr_update(tnbr);
                        RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
                }
@@ -308,8 +308,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                 */
                log_debug("%s: lsr-id %pI4: remote transport preference does not match the local preference", __func__, &lsr_id);
                if (nbr)
-                       session_shutdown(nbr, S_TRANS_MISMTCH, msg->id,
-                           msg->type);
+                       session_shutdown(nbr, S_TRANS_MISMTCH, msg->id, msg->type);
                if (adj)
                        adj_del(adj, S_SHUTDOWN);
                return;
@@ -323,15 +322,13 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                switch (af) {
                case AF_INET:
                        if (nbr_adj_count(nbr, AF_INET6) > 0) {
-                               session_shutdown(nbr, S_DS_NONCMPLNCE,
-                                   msg->id, msg->type);
+                               session_shutdown(nbr, S_DS_NONCMPLNCE, msg->id, msg->type);
                                return;
                        }
                        break;
                case AF_INET6:
                        if (nbr_adj_count(nbr, AF_INET) > 0) {
-                               session_shutdown(nbr, S_DS_NONCMPLNCE,
-                                   msg->id, msg->type);
+                               session_shutdown(nbr, S_DS_NONCMPLNCE, msg->id, msg->type);
                                return;
                        }
                        break;
@@ -384,16 +381,15 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
 
        /* dynamic LDPv4 GTSM negotiation as per RFC 6720 */
        if (nbr) {
-               if (flags & F_HELLO_GTSM)
-                       nbr->flags |= F_NBR_GTSM_NEGOTIATED;
+               if (CHECK_FLAG(flags, F_HELLO_GTSM))
+                       SET_FLAG(nbr->flags, F_NBR_GTSM_NEGOTIATED);
                else
-                       nbr->flags &= ~F_NBR_GTSM_NEGOTIATED;
+                       UNSET_FLAG(nbr->flags, F_NBR_GTSM_NEGOTIATED);
        }
 
        /* update neighbor's configuration sequence number */
        if (nbr && (tlvs_rcvd & F_HELLO_TLV_RCVD_CONF)) {
-               if (conf_seqnum > nbr->conf_seqnum &&
-                   nbr_pending_idtimer(nbr))
+               if (conf_seqnum > nbr->conf_seqnum && nbr_pending_idtimer(nbr))
                        nbr_stop_idtimer(nbr);
                nbr->conf_seqnum = conf_seqnum;
        }
@@ -465,7 +461,7 @@ gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value)
 static int
 gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value)
 {
-       if (leconf->flags & F_LDPD_DS_CISCO_INTEROP)
+       if (CHECK_FLAG(leconf->flags, F_LDPD_DS_CISCO_INTEROP))
                value = htonl(value);
        else
                value = htonl(value << 28);
@@ -533,26 +529,26 @@ tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
                                return (-1);
                        if (af != AF_INET)
                                return (-1);
-                       if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)
+                       if (CHECK_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
                                break;
                        memcpy(&addr->v4, buf, sizeof(addr->v4));
-                       *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
+                       SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR);
                        break;
                case TLV_TYPE_IPV6TRANSADDR:
                        if (tlv_len != sizeof(addr->v6))
                                return (-1);
                        if (af != AF_INET6)
                                return (-1);
-                       if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)
+                       if (CHECK_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
                                break;
                        memcpy(&addr->v6, buf, sizeof(addr->v6));
-                       *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
+                       SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR);
                        break;
                case TLV_TYPE_CONFIG:
                        if (tlv_len != sizeof(uint32_t))
                                return (-1);
                        memcpy(conf_number, buf, sizeof(uint32_t));
-                       *tlvs_rcvd |= F_HELLO_TLV_RCVD_CONF;
+                       SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_CONF);
                        break;
                case TLV_TYPE_DUALSTACK:
                        if (tlv_len != sizeof(uint32_t))
@@ -566,19 +562,18 @@ tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
                        if (!ldp_is_dual_stack(leconf))
                                break;
                        /* Shame on you, Cisco! */
-                       if (leconf->flags & F_LDPD_DS_CISCO_INTEROP) {
-                               memcpy(trans_pref, buf + sizeof(uint16_t),
-                                   sizeof(uint16_t));
+                       if (CHECK_FLAG(leconf->flags, F_LDPD_DS_CISCO_INTEROP)) {
+                               memcpy(trans_pref, buf + sizeof(uint16_t), sizeof(uint16_t));
                                *trans_pref = ntohs(*trans_pref);
                        } else {
                                memcpy(trans_pref, buf , sizeof(uint16_t));
                                *trans_pref = ntohs(*trans_pref) >> 12;
                        }
-                       *tlvs_rcvd |= F_HELLO_TLV_RCVD_DS;
+                       SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_DS);
                        break;
                default:
                        /* if unknown flag set, ignore TLV */
-                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+                       if (!CHECK_FLAG(ntohs(tlv.type), UNKNOWN_FLAG))
                                return (-1);
                        break;
                }
index 08d89187427319b7ac525f36a43c0e5ee7916f92..6f567861d19ca9d7d8de97eb46c5568438b2ab24 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -1028,6 +1028,7 @@ void if_terminate(struct vrf *vrf)
                if (ifp->node) {
                        ifp->node->info = NULL;
                        route_unlock_node(ifp->node);
+                       ifp->node = NULL;
                }
                if_delete(&ifp);
        }
index 213b94bab7754eec3793faa638a0368158eade34..67b45d5bd9bb334eb0966b8c1618d694a5a33747 100644 (file)
@@ -53,12 +53,16 @@ sbin_PROGRAMS += mgmtd/mgmtd
 mgmtd_mgmtd_SOURCES = \
        mgmtd/mgmt_main.c \
        # end
+nodist_mgmtd_mgmtd_SOURCES = \
+       # nothing
 mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./
 mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS)
 mgmtd_mgmtd_LDADD += mgmtd/libmgmt_be_nb.la
 
 if STATICD
-$(mgmtd_mgmtd_OBJECTS): yang/frr-staticd.yang.c
-CLEANFILES += yang/frr-staticd.yang.c
+nodist_mgmtd_mgmtd_SOURCES += \
+       yang/frr-staticd.yang.c \
+       yang/frr-bfdd.yang.c \
+       # end
 nodist_mgmtd_libmgmt_be_nb_la_SOURCES += staticd/static_vty.c
 endif
index 3d5d4d259f47e4f39d9583e78a92191f4594b9c2..ecaaa038ab5d4dac14e19af718092e44a50e66f0 100644 (file)
@@ -239,7 +239,8 @@ static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
 
 /* Enter the Graceful Restart mode. */
 void ospf6_gr_restart_enter(struct ospf6 *ospf6,
-                           enum ospf6_gr_restart_reason reason, int timestamp)
+                           enum ospf6_gr_restart_reason reason,
+                           time_t timestamp)
 {
        unsigned long remaining_time;
 
index e6566a609872de63bb6dbd92321e40c0cbecb851..84ef3aeb8acd4bc03599ec3f5db757cf62bf1408 100644 (file)
@@ -158,7 +158,7 @@ extern int config_write_ospf6_debug_gr_helper(struct vty *vty);
 extern void ospf6_gr_iface_send_grace_lsa(struct event *thread);
 extern void ospf6_gr_restart_enter(struct ospf6 *ospf6,
                                   enum ospf6_gr_restart_reason reason,
-                                  int timestamp);
+                                  time_t timestamp);
 extern void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf,
                                            struct ospf6_area *area);
 extern void ospf6_gr_nvm_read(struct ospf6 *ospf);
index 6999b3f623a6584ddcd38d18984d8502e6b3c9e9..2a346f2388c1f2d45955c61cf1f1cfb8594da4f6 100644 (file)
@@ -282,7 +282,7 @@ static void ospf_gr_restart_exit(struct ospf *ospf, const char *reason)
 
 /* Enter the Graceful Restart mode. */
 void ospf_gr_restart_enter(struct ospf *ospf,
-                          enum ospf_gr_restart_reason reason, int timestamp)
+                          enum ospf_gr_restart_reason reason, time_t timestamp)
 {
        unsigned long remaining_time;
 
index 750d77381d85b1f14dc6072fc0a9a5b23ff05f08..22f9e1ef22533c04da39d6efd0e1145cd988d808 100644 (file)
@@ -169,7 +169,7 @@ extern void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
 extern void ospf_gr_iface_send_grace_lsa(struct event *thread);
 extern void ospf_gr_restart_enter(struct ospf *ospf,
                                  enum ospf_gr_restart_reason reason,
-                                 int timestamp);
+                                 time_t timestamp);
 extern void ospf_gr_check_lsdb_consistency(struct ospf *ospf,
                                                  struct ospf_area *area);
 extern void ospf_gr_check_adjs(struct ospf *ospf);
index 75df09ec354ecee4b9155f681ac2462385dffd12..5b905a9536f9eca38000a65282ef54bafa49d0e2 100644 (file)
@@ -2747,7 +2747,7 @@ void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
                }
        }
 
-       if (!found_ifname)
+       if (!found_ifname && !json)
                vty_out(vty, "%% No such interface\n");
 }
 
@@ -3200,7 +3200,7 @@ void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
                }
        }
 
-       if (!found_neighbor)
+       if (!found_neighbor && !json)
                vty_out(vty, "%% No such interface or neighbor\n");
 }
 
index 294a05e575ae09b007011b388860202d6b3a632a..c793a6d6853828b1397d488c9e092eed3d50a540 100644 (file)
@@ -48,6 +48,7 @@ noinst_HEADERS += \
 ripd_ripd_LDADD = lib/libfrr.la $(LIBCAP)
 nodist_ripd_ripd_SOURCES = \
        yang/frr-ripd.yang.c \
+       yang/frr-bfdd.yang.c \
        # end
 
 ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
index 8058823baf5b1fbd3ff8411054f446a629ffe8d2..75e66566b75bf54549954320288afb9c79e91c64 100644 (file)
@@ -26,6 +26,7 @@ from time import sleep
 from lib.topogen import Topogen, get_topogen
 from lib.topojson import build_config_from_json
 from lib.topolog import logger
+from lib import topotest
 
 from lib.bgp import (
     verify_bgp_convergence,
@@ -1559,8 +1560,14 @@ def test_verify_default_originate_with_2way_ecmp_p2(request):
     step("Ping R1 configure IPv4 and IPv6 loopback address from R2")
     pingaddr = topo["routers"]["r1"]["links"]["lo"]["ipv4"].split("/")[0]
     router = tgen.gears["r2"]
-    output = router.run("ping -c 4 -w 4 {}".format(pingaddr))
-    assert " 0% packet loss" in output, "Ping R1->R2  FAILED"
+
+    def ping_router():
+        output = router.run("ping -c 4 -w 4 {}".format(pingaddr))
+        logger.info(output)
+        if " 0% packet loss" not in output:
+            return False
+
+    _, res = topotest.run_and_expect(ping_router, None, count=10, wait=1)
     logger.info("Ping from R1 to R2 ... success")
 
     step("Shuting up the active route")
index eb0f30f84a5890218ff6f4e070ae472c69c575ea..7c2c7cfdaa43724a3870b7cbaab742c502ffc640 100644 (file)
@@ -98,7 +98,8 @@ def check_ping4(name, dest_addr, expect_connected):
         tgen = get_topogen()
         output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr))
         logger.info(output)
-        assert match in output, "ping fail"
+        if match not in output:
+            return "ping fail"
 
     match = ", {} packet loss".format("0%" if expect_connected else "100%")
     logger.info("[+] check {} {} {}".format(name, dest_addr, match))
index 231ddc51dbec169052480665ab7648778a3b9761..ccf1a0a204b790416b75a2e7abafeb4ab3d87afe 100644 (file)
@@ -267,6 +267,9 @@ struct interface *if_link_per_ns(struct zebra_ns *ns, struct interface *ifp)
 /* Delete a VRF. This is called in vrf_terminate(). */
 void if_unlink_per_ns(struct interface *ifp)
 {
+       if (!ifp->node)
+               return;
+
        ifp->node->info = NULL;
        route_unlock_node(ifp->node);
        ifp->node = NULL;