]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/rt_netlink.c
OSPFD: Update Segment Routing following reviews
[mirror_frr.git] / zebra / rt_netlink.c
index bf1042a7249ec10de0852c58655f3ebf5137fad0..a77814668d4518d179abf30db4d5ea2b3081678d 100644 (file)
 #ifdef HAVE_NETLINK
 
 #include <net/if_arp.h>
+#include <linux/lwtunnel.h>
+#include <linux/mpls_iptunnel.h>
+#include <linux/neighbour.h>
+#include <linux/rtnetlink.h>
 
 /* Hack for GNU libc version 2. */
 #ifndef MSG_TRUNC
 #include "zebra/zebra_mroute.h"
 #include "zebra/zebra_vxlan.h"
 
-
-/* TODO - Temporary definitions, need to refine. */
 #ifndef AF_MPLS
 #define AF_MPLS 28
 #endif
 
-#ifndef RTA_VIA
-#define RTA_VIA                18
-#endif
-
-#ifndef RTA_NEWDST
-#define RTA_NEWDST     19
-#endif
-
-#ifndef RTA_ENCAP_TYPE
-#define RTA_ENCAP_TYPE 21
-#endif
-
-#ifndef RTA_ENCAP
-#define RTA_ENCAP      22
-#endif
-
-#ifndef RTA_EXPIRES
-#define RTA_EXPIRES     23
-#endif
-
-#ifndef LWTUNNEL_ENCAP_MPLS
-#define LWTUNNEL_ENCAP_MPLS  1
-#endif
-
-#ifndef MPLS_IPTUNNEL_DST
-#define MPLS_IPTUNNEL_DST  1
-#endif
-
-#ifndef NDA_MASTER
-#define NDA_MASTER   9
-#endif
-
-#ifndef NTF_MASTER
-#define NTF_MASTER   0x04
-#endif
-
-#ifndef NTF_SELF
-#define NTF_SELF     0x02
-#endif
-
-#ifndef NTF_EXT_LEARNED
-#define NTF_EXT_LEARNED 0x10
-#endif
-
-#ifndef NDA_IFINDEX
-#define NDA_IFINDEX  8
-#endif
-
-#ifndef NDA_VLAN
-#define NDA_VLAN     5
-#endif
-/* End of temporary definitions */
-
 static vlanid_t filter_vlan = 0;
 
 struct gw_family_t {
@@ -149,7 +98,7 @@ static inline int is_selfroute(int proto)
            || (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)
            || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
            || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
-           || (proto == RTPROT_RIP)) {
+           || (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)) {
                return 1;
        }
 
@@ -190,6 +139,9 @@ static inline int zebra2proto(int proto)
        case ZEBRA_ROUTE_LDP:
                proto = RTPROT_LDP;
                break;
+       case ZEBRA_ROUTE_SHARP:
+               proto = RTPROT_SHARP;
+               break;
        default:
                proto = RTPROT_ZEBRA;
                break;
@@ -267,7 +219,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
        struct rtattr *tb[RTA_MAX + 1];
        u_char flags = 0;
        struct prefix p;
-       struct prefix_ipv6 src_p;
+       struct prefix_ipv6 src_p = {};
        vrf_id_t vrf_id = VRF_DEFAULT;
 
        char anyaddr[16] = {0};
@@ -277,6 +229,8 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
        int table;
        int metric = 0;
        u_int32_t mtu = 0;
+       uint8_t distance = 0;
+       route_tag_t tag = 0;
 
        void *dest = NULL;
        void *gate = NULL;
@@ -368,6 +322,11 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
        if (tb[RTA_PRIORITY])
                metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
 
+#if defined(SUPPORT_REALMS)
+       if (tb[RTA_FLOW])
+               tag = *(uint32_t *)RTA_DATA(tb[RTA_FLOW]);
+#endif
+
        if (tb[RTA_METRICS]) {
                struct rtattr *mxrta[RTAX_MAX + 1];
 
@@ -405,16 +364,38 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                return 0;
        }
 
+       /*
+        * For ZEBRA_ROUTE_KERNEL types:
+        *
+        * The metric/priority of the route received from the kernel
+        * is a 32 bit number.  We are going to interpret the high
+        * order byte as the Admin Distance and the low order 3 bytes
+        * as the metric.
+        *
+        * This will allow us to do two things:
+        * 1) Allow the creation of kernel routes that can be
+        *    overridden by zebra.
+        * 2) Allow the old behavior for 'most' kernel route types
+        *    if a user enters 'ip route ...' v4 routes get a metric
+        *    of 0 and v6 routes get a metric of 1024.  Both of these
+        *    values will end up with a admin distance of 0, which
+        *    will cause them to win for the purposes of zebra.
+        */
+       if (proto == ZEBRA_ROUTE_KERNEL) {
+               distance = (metric >> 24) & 0xFF;
+               metric   = (metric & 0x00FFFFFF);
+       }
+
        if (IS_ZEBRA_DEBUG_KERNEL) {
                char buf[PREFIX_STRLEN];
                char buf2[PREFIX_STRLEN];
                zlog_debug(
-                       "%s %s%s%s vrf %u", nl_msg_type_to_str(h->nlmsg_type),
+                       "%s %s%s%s vrf %u metric: %d Admin Distance: %d", nl_msg_type_to_str(h->nlmsg_type),
                        prefix2str(&p, buf, sizeof(buf)),
                        src_p.prefixlen ? " from " : "",
                        src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
                                        : "",
-                       vrf_id);
+                       vrf_id, metric, distance);
        }
 
        afi_t afi = AFI_IP;
@@ -454,7 +435,8 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                                memcpy(&nh.gate, gate, sz);
 
                        rib_add(afi, SAFI_UNICAST, vrf_id, proto,
-                               0, flags, &p, NULL, &nh, table, metric, mtu, 0);
+                               0, flags, &p, NULL, &nh, table, metric,
+                               mtu, distance, tag);
                } else {
                        /* This is a multipath route */
 
@@ -466,7 +448,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
 
                        re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
                        re->type = proto;
-                       re->distance = 0;
+                       re->distance = distance;
                        re->flags = flags;
                        re->metric = metric;
                        re->mtu = mtu;
@@ -474,6 +456,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                        re->table = table;
                        re->nexthop_num = 0;
                        re->uptime = time(NULL);
+                       re->tag = tag;
 
                        for (;;) {
                                if (len < (int)sizeof(*rtnh)
@@ -526,7 +509,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                        if (re->nexthop_num == 0)
                                XFREE(MTYPE_RE, re);
                        else
-                               rib_add_multipath(AFI_IP, SAFI_UNICAST, &p,
+                               rib_add_multipath(afi, SAFI_UNICAST, &p,
                                                  NULL, re);
                }
        } else {
@@ -560,13 +543,13 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                                memcpy(&nh.gate, gate, sz);
                        rib_delete(afi, SAFI_UNICAST, vrf_id,
                                   proto, 0, flags, &p, NULL, &nh,
-                                  table, metric);
+                                  table, metric, true, NULL);
                } else {
                        /* XXX: need to compare the entire list of nexthops
                         * here for NLM_F_APPEND stupidity */
                        rib_delete(afi, SAFI_UNICAST, vrf_id,
                                   proto, 0, flags, &p, NULL, NULL,
-                                  table, metric);
+                                  table, metric, true, NULL);
                }
        }
 
@@ -822,7 +805,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
 {
        struct nexthop_label *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
-       char label_buf[100];
+       char label_buf[256];
 
        /*
         * label_buf is *only* currently used within debugging.
@@ -853,12 +836,13 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
                                                             0, 0, bos);
                                if (IS_ZEBRA_DEBUG_KERNEL) {
                                        if (!num_labels)
-                                               sprintf(label_buf, "label %d",
+                                               sprintf(label_buf, "label %u",
                                                        nh_label->label[i]);
                                        else {
-                                               sprintf(label_buf1, "/%d",
+                                               sprintf(label_buf1, "/%u",
                                                        nh_label->label[i]);
-                                               strcat(label_buf, label_buf1);
+                                               strlcat(label_buf, label_buf1,
+                                                       sizeof(label_buf));
                                        }
                                }
                                num_labels++;
@@ -1021,7 +1005,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
 {
        struct nexthop_label *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
-       char label_buf[100];
+       char label_buf[256];
 
        rtnh->rtnh_len = sizeof(*rtnh);
        rtnh->rtnh_flags = 0;
@@ -1057,12 +1041,13 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                                                             0, 0, bos);
                                if (IS_ZEBRA_DEBUG_KERNEL) {
                                        if (!num_labels)
-                                               sprintf(label_buf, "label %d",
+                                               sprintf(label_buf, "label %u",
                                                        nh_label->label[i]);
                                        else {
-                                               sprintf(label_buf1, "/%d",
+                                               sprintf(label_buf1, "/%u",
                                                        nh_label->label[i]);
-                                               strcat(label_buf, label_buf1);
+                                               strlcat(label_buf, label_buf1,
+                                                       sizeof(label_buf));
                                        }
                                }
                                num_labels++;
@@ -1320,23 +1305,6 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
        req.r.rtm_scope = RT_SCOPE_UNIVERSE;
        req.r.rtm_type = RTN_UNICAST;
 
-       if (re->nexthop_num == 1
-           && re->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
-               discard = 1;
-
-               switch (re->nexthop->bh_type) {
-               case BLACKHOLE_ADMINPROHIB:
-                       req.r.rtm_type = RTN_PROHIBIT;
-                       break;
-               case BLACKHOLE_REJECT:
-                       req.r.rtm_type = RTN_UNREACHABLE;
-                       break;
-               default:
-                       req.r.rtm_type = RTN_BLACKHOLE;
-                       break;
-               }
-       }
-
        addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
        if (src_p)
                addattr_l(&req.n, sizeof req, RTA_SRC, &src_p->u.prefix,
@@ -1350,7 +1318,10 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
         * by the routing protocol and for communicating with protocol peers.
         */
        addattr32(&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
-
+#if defined(SUPPORT_REALMS)
+       if (re->tag > 0 && re->tag <= 255)
+               addattr32(&req.n, sizeof req, RTA_FLOW, re->tag);
+#endif
        /* Table corresponding to this route. */
        if (re->table < 256)
                req.r.rtm_table = re->table;
@@ -1395,6 +1366,27 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
        if (nexthop_num == 1 || multipath_num == 1) {
                nexthop_num = 0;
                for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
+                       /*
+                        * So we want to cover 2 types of blackhole
+                        * routes here:
+                        * 1) A normal blackhole route( ala from a static
+                        *    install.
+                        * 2) A recursively resolved blackhole route
+                        */
+                       if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
+                               switch (nexthop->bh_type) {
+                               case BLACKHOLE_ADMINPROHIB:
+                                       req.r.rtm_type = RTN_PROHIBIT;
+                                       break;
+                               case BLACKHOLE_REJECT:
+                                       req.r.rtm_type = RTN_UNREACHABLE;
+                                       break;
+                               default:
+                                       req.r.rtm_type = RTN_BLACKHOLE;
+                                       break;
+                               }
+                               goto skip;
+                       }
                        if (CHECK_FLAG(nexthop->flags,
                                       NEXTHOP_FLAG_RECURSIVE)) {
                                if (!setsrc) {
@@ -1442,8 +1434,8 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
                                && CHECK_FLAG(nexthop->flags,
                                              NEXTHOP_FLAG_FIB))) {
                                routedesc = nexthop->rparent
-                                                   ? "recursive, 1 hop"
-                                                   : "single hop";
+                                                   ? "recursive, single-path"
+                                                   : "single-path";
 
                                _netlink_route_debug(cmd, p, nexthop, routedesc,
                                                     family, zvrf);
@@ -1525,8 +1517,8 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
                                && CHECK_FLAG(nexthop->flags,
                                              NEXTHOP_FLAG_FIB))) {
                                routedesc = nexthop->rparent
-                                                   ? "recursive, multihop"
-                                                   : "multihop";
+                                                   ? "recursive, multipath"
+                                                   : "multipath";
                                nexthop_num++;
 
                                _netlink_route_debug(cmd, p, nexthop, routedesc,
@@ -1617,17 +1609,51 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
        return suc;
 }
 
-int kernel_route_rib(struct prefix *p, struct prefix *src_p,
-                    struct route_entry *old, struct route_entry *new)
+void kernel_route_rib(struct prefix *p, struct prefix *src_p,
+                     struct route_entry *old, struct route_entry *new)
 {
+       int ret = 0;
+
        assert(old || new);
 
-       if (!old && new)
-               return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0);
-       if (old && !new)
-               return netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0);
+       if (new) {
+               if (p->family == AF_INET)
+                       ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p,
+                                                     new, (old) ? 1 : 0);
+               else {
+                       /*
+                        * So v6 route replace semantics are not in
+                        * the kernel at this point as I understand it.
+                        * So let's do a delete than an add.
+                        * In the future once v6 route replace semantics
+                        * are in we can figure out what to do here to
+                        * allow working with old and new kernels.
+                        *
+                        * I'm also intentionally ignoring the failure case
+                        * of the route delete.  If that happens yeah we're
+                        * screwed.
+                        */
+                       if (old)
+                               netlink_route_multipath(RTM_DELROUTE, p,
+                                                       src_p, old, 0);
+                       ret = netlink_route_multipath(RTM_NEWROUTE, p,
+                                                     src_p, new, 0);
+               }
+               kernel_route_rib_pass_fail(p, new,
+                                          (!ret) ?
+                                          SOUTHBOUND_INSTALL_SUCCESS :
+                                          SOUTHBOUND_INSTALL_FAILURE);
+               return;
+       }
 
-       return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 1);
+       if (old) {
+               ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0);
+
+               kernel_route_rib_pass_fail(p, old,
+                                          (!ret) ?
+                                          SOUTHBOUND_DELETE_SUCCESS :
+                                          SOUTHBOUND_DELETE_FAILURE);
+       }
 }
 
 int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
@@ -1712,7 +1738,6 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
        struct ndmsg *ndm;
        struct interface *ifp;
        struct zebra_if *zif;
-       struct zebra_vrf *zvrf;
        struct rtattr *tb[NDA_MAX + 1];
        struct interface *br_if;
        struct ethaddr mac;
@@ -1726,20 +1751,14 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
        ndm = NLMSG_DATA(h);
 
+       /* We only process macfdb notifications if EVPN is enabled */
+       if (!is_evpn_enabled())
+               return 0;
+
        /* The interface should exist. */
        ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
                                        ndm->ndm_ifindex);
-       if (!ifp)
-               return 0;
-
-       /* Locate VRF corresponding to interface. We only process MAC
-        * notifications
-        * if EVPN is enabled on this VRF.
-        */
-       zvrf = vrf_info_lookup(ifp->vrf_id);
-       if (!zvrf || !EVPN_ENABLED(zvrf))
-               return 0;
-       if (!ifp->info)
+       if (!ifp || !ifp->info)
                return 0;
 
        /* The interface should be something we're interested in. */
@@ -2029,7 +2048,6 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
        struct ndmsg *ndm;
        struct interface *ifp;
        struct zebra_if *zif;
-       struct zebra_vrf *zvrf;
        struct rtattr *tb[NDA_MAX + 1];
        struct interface *link_if;
        struct ethaddr mac;
@@ -2041,20 +2059,14 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
        ndm = NLMSG_DATA(h);
 
+       /* We only process neigh notifications if EVPN is enabled */
+       if (!is_evpn_enabled())
+               return 0;
+
        /* The interface should exist. */
        ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
                                        ndm->ndm_ifindex);
-       if (!ifp)
-               return 0;
-
-       /* Locate VRF corresponding to interface. We only process neigh
-        * notifications
-        * if EVPN is enabled on this VRF.
-        */
-       zvrf = vrf_info_lookup(ifp->vrf_id);
-       if (!zvrf || !EVPN_ENABLED(zvrf))
-               return 0;
-       if (!ifp->info)
+       if (!ifp || !ifp->info)
                return 0;
 
        /* Drop "permanent" entries. */
@@ -2345,6 +2357,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
        unsigned int nexthop_num;
        const char *routedesc;
        struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       int route_type;
 
        struct {
                struct nlmsghdr n;
@@ -2354,7 +2367,6 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
 
        memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE);
 
-
        /*
         * Count # nexthops so we can decide whether to use singlepath
         * or multipath case.
@@ -2378,7 +2390,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
                }
        }
 
-       if (nexthop_num == 0) // unexpected
+       if ((nexthop_num == 0) || (!lsp->best_nhlfe && (cmd != RTM_DELROUTE)))
                return 0;
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
@@ -2389,14 +2401,18 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
        req.r.rtm_family = AF_MPLS;
        req.r.rtm_table = RT_TABLE_MAIN;
        req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
-       req.r.rtm_protocol = RTPROT_ZEBRA;
        req.r.rtm_scope = RT_SCOPE_UNIVERSE;
        req.r.rtm_type = RTN_UNICAST;
 
-       if (cmd == RTM_NEWROUTE)
+       if (cmd == RTM_NEWROUTE) {
                /* We do a replace to handle update. */
                req.n.nlmsg_flags |= NLM_F_REPLACE;
 
+               /* set the protocol value if installing */
+               route_type = re_type_from_lsp_type(lsp->best_nhlfe->type);
+               req.r.rtm_protocol = zebra2proto(route_type);
+       }
+
        /* Fill destination */
        lse = mpls_lse_encode(lsp->ile.in_label, 0, 0, 1);
        addattr_l(&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t));
@@ -2405,7 +2421,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
         * chosen depend on the operation.
         */
        if (nexthop_num == 1 || multipath_num == 1) {
-               routedesc = "single hop";
+               routedesc = "single-path";
                _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
 
                nexthop_num = 0;
@@ -2427,17 +2443,6 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
                                _netlink_mpls_build_singlepath(routedesc, nhlfe,
                                                               &req.n, &req.r,
                                                               sizeof req, cmd);
-                               if (cmd == RTM_NEWROUTE) {
-                                       SET_FLAG(nhlfe->flags,
-                                                NHLFE_FLAG_INSTALLED);
-                                       SET_FLAG(nexthop->flags,
-                                                NEXTHOP_FLAG_FIB);
-                               } else {
-                                       UNSET_FLAG(nhlfe->flags,
-                                                  NHLFE_FLAG_INSTALLED);
-                                       UNSET_FLAG(nexthop->flags,
-                                                  NEXTHOP_FLAG_FIB);
-                               }
                                nexthop_num++;
                                break;
                        }
@@ -2453,7 +2458,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
                rta->rta_len = RTA_LENGTH(0);
                rtnh = RTA_DATA(rta);
 
-               routedesc = "multihop";
+               routedesc = "multipath";
                _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
 
                nexthop_num = 0;
@@ -2481,18 +2486,6 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
                                                              rta, rtnh, &req.r,
                                                              &src1);
                                rtnh = RTNH_NEXT(rtnh);
-
-                               if (cmd == RTM_NEWROUTE) {
-                                       SET_FLAG(nhlfe->flags,
-                                                NHLFE_FLAG_INSTALLED);
-                                       SET_FLAG(nexthop->flags,
-                                                NEXTHOP_FLAG_FIB);
-                               } else {
-                                       UNSET_FLAG(nhlfe->flags,
-                                                  NHLFE_FLAG_INSTALLED);
-                                       UNSET_FLAG(nexthop->flags,
-                                                  NEXTHOP_FLAG_FIB);
-                               }
                        }
                }
 
@@ -2506,23 +2499,4 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp)
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
                            0);
 }
-
-/*
- * Handle failure in LSP install, clear flags for NHLFE.
- */
-void clear_nhlfe_installed(zebra_lsp_t *lsp)
-{
-       zebra_nhlfe_t *nhlfe;
-       struct nexthop *nexthop;
-
-       for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
-               nexthop = nhlfe->nexthop;
-               if (!nexthop)
-                       continue;
-
-               UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
-               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
-       }
-}
-
 #endif /* HAVE_NETLINK */