]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_rnh.c
zebra: clean up zapi organization
[mirror_frr.git] / zebra / zebra_rnh.c
index 9fc5afff0f392e01bf16638ad16247f4f7f56048..8b89979818e3dfcc3b208546b54803c08bdf98cf 100644 (file)
@@ -355,7 +355,8 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
        rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
 
        if (prn && re) {
-               for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
+               for (nexthop = re->ng.nexthop; nexthop;
+                    nexthop = nexthop->next) {
                        ret = zebra_nht_route_map_check(rmap_family, proto,
                                                        &prn->p, re, nexthop);
                        if (ret != RMAP_DENYMATCH) {
@@ -373,12 +374,10 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
  * Determine appropriate route (RE entry) resolving a tracked BGP route
  * for BGP route for import.
  */
-static
-struct route_entry *zebra_rnh_resolve_import_entry(vrf_id_t vrfid,
-                                                  int family,
-                                                  struct route_node *nrn,
-                                                  struct rnh *rnh,
-                                                  struct route_node **prn)
+static struct route_entry *
+zebra_rnh_resolve_import_entry(vrf_id_t vrfid, int family,
+                              struct route_node *nrn, struct rnh *rnh,
+                              struct route_node **prn)
 {
        struct route_table *route_table;
        struct route_node *rn;
@@ -397,15 +396,15 @@ struct route_entry *zebra_rnh_resolve_import_entry(vrf_id_t vrfid,
        /* Unlock route node - we don't need to lock when walking the tree. */
        route_unlock_node(rn);
 
-       if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) &&
-            !prefix_same(&nrn->p, &rn->p))
+       if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)
+           && !prefix_same(&nrn->p, &rn->p))
                return NULL;
 
        /* Identify appropriate route entry. */
-       RNODE_FOREACH_RE(rn, re) {
-               if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) &&
-                   CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) &&
-                   (re->type != ZEBRA_ROUTE_BGP))
+       RNODE_FOREACH_RE (rn, re) {
+               if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
+                   && CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
+                   && (re->type != ZEBRA_ROUTE_BGP))
                        break;
        }
 
@@ -430,7 +429,7 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family,
        struct nexthop *nexthop;
 
        if (re && (rnh->state == NULL)) {
-               for (ALL_NEXTHOPS(re->nexthop, nexthop))
+               for (ALL_NEXTHOPS(re->ng, nexthop))
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
                                state_changed = 1;
                                break;
@@ -515,6 +514,61 @@ static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
        }
 }
 
+static void zebra_rnh_process_pbr_tables(int family,
+                                        struct route_node *nrn,
+                                        struct rnh *rnh,
+                                        struct route_node *prn,
+                                        struct route_entry *re)
+{
+       struct zebra_ns_table *znst;
+       struct route_entry *o_re;
+       struct route_node *o_rn;
+       struct listnode *node;
+       struct zserv *client;
+       struct zebra_ns *zns;
+       afi_t afi = AFI_IP;
+
+       if (family == AF_INET6)
+               afi = AFI_IP6;
+
+       /*
+        * We are only concerned about nexthops that change for
+        * anyone using PBR
+        */
+       for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
+               if (client->proto == ZEBRA_ROUTE_PBR)
+                       break;
+       }
+
+       if (!client)
+               return;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) {
+               if (afi != znst->afi)
+                       continue;
+
+               for (o_rn = route_top(znst->table);
+                    o_rn; o_rn = srcdest_route_next(o_rn)) {
+                       RNODE_FOREACH_RE (o_rn, o_re) {
+                               if (o_re->type == ZEBRA_ROUTE_PBR)
+                                       break;
+
+                       }
+
+                       /*
+                        * If we have a PBR route and a nexthop changes
+                        * just rethink it.  Yes this is a hammer, but
+                        * a small one
+                        */
+                       if (o_re) {
+                               SET_FLAG(o_re->status, ROUTE_ENTRY_CHANGED);
+                               rib_queue_add(o_rn);
+                       }
+               }
+       }
+}
+
 static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
                                            struct route_node *nrn,
                                            struct rnh *rnh,
@@ -561,7 +615,7 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
                         * be having multiple. We care here only about
                         * registered nexthops.
                         */
-                       for (nexthop = sre->nexthop; nexthop;
+                       for (nexthop = sre->ng.nexthop; nexthop;
                             nexthop = nexthop->next) {
                                switch (nexthop->type) {
                                case NEXTHOP_TYPE_IPV4:
@@ -628,11 +682,10 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
  * Determine appropriate route (route entry) resolving a tracked
  * nexthop.
  */
-static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid,
-                                                    int family,
-                                                    struct route_node *nrn,
-                                                    struct rnh *rnh,
-                                                    struct route_node **prn)
+static struct route_entry *
+zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family,
+                               struct route_node *nrn, struct rnh *rnh,
+                               struct route_node **prn)
 {
        struct route_table *route_table;
        struct route_node *rn;
@@ -658,12 +711,12 @@ static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid,
                /* Do not resolve over default route unless allowed &&
                 * match route to be exact if so specified
                 */
-               if (is_default_prefix(&rn->p) &&
-                   !rnh_resolve_via_default(rn->p.family))
+               if (is_default_prefix(&rn->p)
+                   && !rnh_resolve_via_default(rn->p.family))
                        return NULL;
 
                /* Identify appropriate route entry. */
-               RNODE_FOREACH_RE(rn, re) {
+               RNODE_FOREACH_RE (rn, re) {
                        if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
                                continue;
                        if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
@@ -676,11 +729,10 @@ static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid,
                                if (re->type == ZEBRA_ROUTE_NHRP) {
                                        struct nexthop *nexthop;
 
-                                       for (nexthop = re->nexthop;
-                                            nexthop;
+                                       for (nexthop = re->ng.nexthop; nexthop;
                                             nexthop = nexthop->next)
                                                if (nexthop->type
-                                                    == NEXTHOP_TYPE_IFINDEX)
+                                                   == NEXTHOP_TYPE_IFINDEX)
                                                        break;
                                        if (nexthop)
                                                break;
@@ -755,6 +807,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
                zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
                                                rnh->state);
 
+               zebra_rnh_process_pbr_tables(family, nrn, rnh, prn,
+                                            rnh->state);
+
                /* Process pseudowires attached to this nexthop */
                zebra_rnh_process_pseudowires(vrfid, rnh);
        }
@@ -779,8 +834,8 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
 
        /* Identify route entry (RE) resolving this tracked entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn,
-                                                   rnh, &prn);
+               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
+                                                   &prn);
        else
                re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
                                                     &prn);
@@ -820,8 +875,8 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
 
        /* Identify route entry (RIB) resolving this tracked entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn,
-                                                   rnh, &prn);
+               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
+                                                   &prn);
        else
                re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
                                                     &prn);
@@ -890,34 +945,6 @@ void zebra_print_rnh_table(vrf_id_t vrfid, int af, struct vty *vty,
                        print_rnh(rn, vty);
 }
 
-int zebra_cleanup_rnh_client(vrf_id_t vrf_id, int family, struct zserv *client,
-                            rnh_type_t type)
-{
-       struct route_table *ntable;
-       struct route_node *nrn;
-       struct rnh *rnh;
-
-       if (IS_ZEBRA_DEBUG_NHT)
-               zlog_debug("%u: Client %s RNH cleanup for family %d type %d",
-                          vrf_id, zebra_route_string(client->proto), family,
-                          type);
-
-       ntable = get_rnh_table(vrf_id, family, type);
-       if (!ntable) {
-               zlog_debug("cleanup_rnh_client: rnh table not found\n");
-               return -1;
-       }
-
-       for (nrn = route_top(ntable); nrn; nrn = route_next(nrn)) {
-               if (!nrn->info)
-                       continue;
-
-               rnh = nrn->info;
-               zebra_remove_rnh_client(rnh, client, type);
-       }
-       return 1;
-}
-
 /**
  * free_state - free up the re structure associated with the rnh.
  */
@@ -929,8 +956,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
                return;
 
        /* free RE and nexthops */
-       zebra_deregister_rnh_static_nexthops(vrf_id, re->nexthop, rn);
-       nexthops_free(re->nexthop);
+       zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn);
+       nexthops_free(re->ng.nexthop);
        XFREE(MTYPE_RE, re);
 }
 
@@ -953,7 +980,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
        state->metric = re->metric;
        state->vrf_id = re->vrf_id;
 
-       route_entry_copy_nexthops(state, re->nexthop);
+       route_entry_copy_nexthops(state, re->ng.nexthop);
        rnh->state = state;
 }
 
@@ -988,8 +1015,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
        struct stream *s;
        struct route_entry *re;
        unsigned long nump;
-       u_char num;
-       struct nexthop *nexthop;
+       uint8_t num;
+       struct nexthop *nh;
        struct route_node *rn;
        int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE
                                                  : ZEBRA_NEXTHOP_UPDATE;
@@ -998,8 +1025,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
        re = rnh->state;
 
        /* Get output stream. */
-       s = client->obuf;
-       stream_reset(s);
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        zclient_create_header(s, cmd, vrf_id);
 
@@ -1019,41 +1045,53 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                break;
        }
        if (re) {
+               stream_putc(s, re->type);
+               stream_putw(s, re->instance);
                stream_putc(s, re->distance);
                stream_putl(s, re->metric);
                num = 0;
                nump = stream_get_endp(s);
                stream_putc(s, 0);
-               for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
-                       if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
-                            || CHECK_FLAG(nexthop->flags,
-                                          NEXTHOP_FLAG_RECURSIVE))
-                           && CHECK_FLAG(nexthop->flags,
-                                         NEXTHOP_FLAG_ACTIVE)) {
-                               stream_putc(s, nexthop->type);
-                               switch (nexthop->type) {
+               for (nh = re->ng.nexthop; nh; nh = nh->next)
+                       if ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+                            || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+                           && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) {
+                               stream_putc(s, nh->type);
+                               switch (nh->type) {
                                case NEXTHOP_TYPE_IPV4:
                                case NEXTHOP_TYPE_IPV4_IFINDEX:
-                                       stream_put_in_addr(s,
-                                                          &nexthop->gate.ipv4);
-                                       stream_putl(s, nexthop->ifindex);
+                                       stream_put_in_addr(s, &nh->gate.ipv4);
+                                       stream_putl(s, nh->ifindex);
                                        break;
                                case NEXTHOP_TYPE_IFINDEX:
-                                       stream_putl(s, nexthop->ifindex);
+                                       stream_putl(s, nh->ifindex);
                                        break;
                                case NEXTHOP_TYPE_IPV6:
                                case NEXTHOP_TYPE_IPV6_IFINDEX:
-                                       stream_put(s, &nexthop->gate.ipv6, 16);
-                                       stream_putl(s, nexthop->ifindex);
+                                       stream_put(s, &nh->gate.ipv6, 16);
+                                       stream_putl(s, nh->ifindex);
                                        break;
                                default:
                                        /* do nothing */
                                        break;
                                }
+                               if (nh->nh_label) {
+                                       stream_putc(s,
+                                                   nh->nh_label->num_labels);
+                                       if (nh->nh_label->num_labels)
+                                               stream_put(
+                                                       s,
+                                                       &nh->nh_label->label[0],
+                                                       nh->nh_label->num_labels
+                                                               * sizeof(mpls_label_t));
+                               } else
+                                       stream_putc(s, 0);
                                num++;
                        }
                stream_putc_at(s, nump, num);
        } else {
+               stream_putc(s, 0); // type
+               stream_putw(s, 0); // instance
                stream_putc(s, 0); // distance
                stream_putl(s, 0); // metric
                stream_putc(s, 0); // nexthops
@@ -1062,7 +1100,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
 
        client->nh_last_upd_time = monotime(NULL);
        client->last_write_cmd = cmd;
-       return zebra_server_send_message(client);
+       return zebra_server_send_message(client, s);
 }
 
 static void print_nh(struct nexthop *nexthop, struct vty *vty)
@@ -1115,7 +1153,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
        if (rnh->state) {
                vty_out(vty, " resolved via %s\n",
                        zebra_route_string(rnh->state->type));
-               for (nexthop = rnh->state->nexthop; nexthop;
+               for (nexthop = rnh->state->ng.nexthop; nexthop;
                     nexthop = nexthop->next)
                        print_nh(nexthop, vty);
        } else
@@ -1136,3 +1174,58 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
                vty_out(vty, " zebra[pseudowires]");
        vty_out(vty, "\n");
 }
+
+static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, int family,
+                                   struct zserv *client, rnh_type_t type)
+{
+       struct route_table *ntable;
+       struct route_node *nrn;
+       struct rnh *rnh;
+
+       if (IS_ZEBRA_DEBUG_NHT)
+               zlog_debug("%u: Client %s RNH cleanup for family %d type %d",
+                          vrf_id, zebra_route_string(client->proto), family,
+                          type);
+
+       ntable = get_rnh_table(vrf_id, family, type);
+       if (!ntable) {
+               zlog_debug("cleanup_rnh_client: rnh table not found\n");
+               return -1;
+       }
+
+       for (nrn = route_top(ntable); nrn; nrn = route_next(nrn)) {
+               if (!nrn->info)
+                       continue;
+
+               rnh = nrn->info;
+               zebra_remove_rnh_client(rnh, client, type);
+       }
+       return 1;
+}
+
+/* Cleanup registered nexthops (across VRFs) upon client disconnect. */
+void zebra_client_cleanup_rnh(struct zserv *client)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+
+       RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+               if ((zvrf = vrf->info) != NULL) {
+                       zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET, client,
+                                                RNH_NEXTHOP_TYPE);
+                       zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET6,
+                                                client, RNH_NEXTHOP_TYPE);
+                       zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET, client,
+                                                RNH_IMPORT_CHECK_TYPE);
+                       zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET6,
+                                                client, RNH_IMPORT_CHECK_TYPE);
+                       if (client->proto == ZEBRA_ROUTE_LDP) {
+                               hash_iterate(zvrf->lsp_table,
+                                            mpls_ldp_lsp_uninstall_all,
+                                            zvrf->lsp_table);
+                               mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP);
+                               mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP6);
+                       }
+               }
+       }
+}