]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_rnh.c
Merge branch 'master' into type5-default-originate
[mirror_frr.git] / zebra / zebra_rnh.c
index 8ab46f683c7ebe75cdcbaa7e2c052c7ec5d40e27..d960dbd93773a5946b64466d591bdd2ef88d834c 100644 (file)
@@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
                rnh->client_list = list_new();
                rnh->vrf_id = vrfid;
                rnh->zebra_static_route_list = list_new();
+               rnh->zebra_pseudowire_list = list_new();
                route_lock_node(rn);
                rn->info = rnh;
                rnh->node = rn;
@@ -159,8 +160,9 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
 void zebra_free_rnh(struct rnh *rnh)
 {
        rnh->flags |= ZEBRA_NHT_DELETED;
-       list_free(rnh->client_list);
-       list_free(rnh->zebra_static_route_list);
+       list_delete_and_null(&rnh->client_list);
+       list_delete_and_null(&rnh->zebra_static_route_list);
+       list_delete_and_null(&rnh->zebra_pseudowire_list);
        free_state(rnh->vrf_id, rnh->state, rnh->node);
        XFREE(MTYPE_RNH, rnh);
 }
@@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
        }
        listnode_delete(rnh->client_list, client);
        if (list_isempty(rnh->client_list)
-           && list_isempty(rnh->zebra_static_route_list))
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
                zebra_delete_rnh(rnh, type);
 }
 
@@ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
        listnode_delete(rnh->zebra_static_route_list, static_rn);
 
        if (list_isempty(rnh->client_list)
-           && list_isempty(rnh->zebra_static_route_list))
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
                zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
 }
 
@@ -284,6 +288,59 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
        }
 }
 
+/* XXX move this utility function elsewhere? */
+static void addr2hostprefix(int af, const union g_addr *addr,
+                           struct prefix *prefix)
+{
+       switch (af) {
+       case AF_INET:
+               prefix->family = AF_INET;
+               prefix->prefixlen = IPV4_MAX_BITLEN;
+               prefix->u.prefix4 = addr->ipv4;
+               break;
+       case AF_INET6:
+               prefix->family = AF_INET6;
+               prefix->prefixlen = IPV6_MAX_BITLEN;
+               prefix->u.prefix6 = addr->ipv6;
+               break;
+       default:
+               memset(prefix, 0, sizeof(*prefix));
+               zlog_warn("%s: unknown address family %d", __func__, af);
+               break;
+       }
+}
+
+void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
+{
+       struct prefix nh;
+       struct rnh *rnh;
+
+       addr2hostprefix(pw->af, &pw->nexthop, &nh);
+       rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
+       if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
+               listnode_add(rnh->zebra_pseudowire_list, pw);
+               pw->rnh = rnh;
+               zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
+       }
+}
+
+void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
+{
+       struct rnh *rnh;
+
+       rnh = pw->rnh;
+       if (!rnh)
+               return;
+
+       listnode_delete(rnh->zebra_pseudowire_list, pw);
+       pw->rnh = NULL;
+
+       if (list_isempty(rnh->client_list)
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
+               zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
+}
+
 /* Apply the NHT route-map for a client to the route (and nexthops)
  * resolving a NH.
  */
@@ -313,11 +370,12 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
 }
 
 /*
- * Determine appropriate route (RE entry) resolving a tracked entry
- * (nexthop or BGP route for import).
+ * Determine appropriate route (RE entry) resolving a tracked BGP route
+ * for BGP route for import.
  */
-static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family,
-                                                  rnh_type_t type,
+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)
@@ -336,49 +394,21 @@ static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family,
        if (!rn)
                return NULL;
 
-       /* When resolving nexthops, do not resolve via the default route unless
-        * 'ip nht resolve-via-default' is configured.
-        */
-       if ((type == RNH_NEXTHOP_TYPE)
-           && (is_default_prefix(&rn->p)
-               && !nh_resolve_via_default(rn->p.family)))
-               re = NULL;
-       else if ((type == RNH_IMPORT_CHECK_TYPE)
-                && CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)
-                && !prefix_same(&nrn->p, &rn->p))
-               re = NULL;
-       else {
-               /* Identify appropriate route entry. */
-               RNODE_FOREACH_RE(rn, re)
-               {
-                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
-                               continue;
-                       if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                               continue;
+       /* Unlock route node - we don't need to lock when walking the tree. */
+       route_unlock_node(rn);
 
-                       if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
-                               if (re->type == ZEBRA_ROUTE_CONNECT)
-                                       break;
-                               if (re->type == ZEBRA_ROUTE_NHRP) {
-                                       struct nexthop *nexthop;
-                                       for (nexthop = re->nexthop; nexthop;
-                                            nexthop = nexthop->next)
-                                               if (nexthop->type
-                                                   == NEXTHOP_TYPE_IFINDEX)
-                                                       break;
-                                       if (nexthop)
-                                               break;
-                               }
-                       } else if ((type == RNH_IMPORT_CHECK_TYPE)
-                                  && (re->type == ZEBRA_ROUTE_BGP))
-                               continue;
-                       else
-                               break;
-               }
+       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))
+                       break;
        }
 
-       /* Need to unlock route node */
-       route_unlock_node(rn);
        if (re)
                *prn = rn;
        return re;
@@ -522,8 +552,7 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
        /* Evaluate each static route associated with this nexthop. */
        for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
                                  static_rn)) {
-               RNODE_FOREACH_RE(static_rn, sre)
-               {
+               RNODE_FOREACH_RE (static_rn, sre) {
                        if (sre->type != ZEBRA_ROUTE_STATIC)
                                continue;
 
@@ -595,6 +624,95 @@ 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)
+{
+       struct route_table *route_table;
+       struct route_node *rn;
+       struct route_entry *re;
+
+       *prn = NULL;
+
+       route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
+       if (!route_table)
+               return NULL;
+
+       rn = route_node_match(route_table, &nrn->p);
+       if (!rn)
+               return NULL;
+
+       /* Unlock route node - we don't need to lock when walking the tree. */
+       route_unlock_node(rn);
+
+       /* While resolving nexthops, we may need to walk up the tree from the
+        * most-specific match. Do similar logic as in zebra_rib.c
+        */
+       while (rn) {
+               /* 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))
+                       return NULL;
+
+               /* Identify appropriate route entry. */
+               RNODE_FOREACH_RE(rn, re) {
+                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+                               continue;
+                       if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+                               continue;
+
+                       if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
+                               if ((re->type == ZEBRA_ROUTE_CONNECT)
+                                   || (re->type == ZEBRA_ROUTE_STATIC))
+                                       break;
+                               if (re->type == ZEBRA_ROUTE_NHRP) {
+                                       struct nexthop *nexthop;
+
+                                       for (nexthop = re->nexthop;
+                                            nexthop;
+                                            nexthop = nexthop->next)
+                                               if (nexthop->type
+                                                    == NEXTHOP_TYPE_IFINDEX)
+                                                       break;
+                                       if (nexthop)
+                                               break;
+                               }
+                       } else
+                               break;
+               }
+
+               /* Route entry found, we're done; else, walk up the tree. */
+               if (re) {
+                       *prn = rn;
+                       return re;
+               }
+
+               if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+                       rn = rn->parent;
+               else
+                       return NULL;
+       }
+
+       return NULL;
+}
+
+static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
+{
+       struct zebra_pw *pw;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw))
+               zebra_pw_update(pw);
+}
+
 /*
  * See if a tracked nexthop entry has undergone any change, and if so,
  * take appropriate action; this involves notifying any clients and/or
@@ -636,6 +754,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
                /* Process static routes attached to this nexthop */
                zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
                                                rnh->state);
+
+               /* Process pseudowires attached to this nexthop */
+               zebra_rnh_process_pseudowires(vrfid, rnh);
        }
 }
 
@@ -657,7 +778,12 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
        rnh = nrn->info;
 
        /* Identify route entry (RE) resolving this tracked entry. */
-       re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn);
+       if (type == RNH_IMPORT_CHECK_TYPE)
+               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn,
+                                                   rnh, &prn);
+       else
+               re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
+                                                    &prn);
 
        /* If the entry cannot be resolved and that is also the existing state,
         * there is nothing further to do.
@@ -692,10 +818,18 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
 
        rnh = nrn->info;
 
-       re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn);
+       /* 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);
+       else
+               re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
+                                                    &prn);
 
-       if (re)
+       if (re) {
                UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
+               UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+       }
 }
 
 /* Evaluate all tracked entries (nexthops or routes for import into BGP)
@@ -817,6 +951,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
        state->type = re->type;
        state->distance = re->distance;
        state->metric = re->metric;
+       state->vrf_id = re->vrf_id;
 
        route_entry_copy_nexthops(state, re->nexthop);
        rnh->state = state;
@@ -840,7 +975,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
        if (r1->nexthop_num != r2->nexthop_num)
                return 1;
 
-       if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED))
+       if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)
+           || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED))
                return 1;
 
        return 0;
@@ -865,7 +1001,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, vrf_id);
+       zclient_create_header(s, cmd, vrf_id);
 
        stream_putw(s, rn->p.family);
        switch (rn->p.family) {
@@ -883,6 +1019,8 @@ 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;
@@ -897,6 +1035,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                                stream_putc(s, nexthop->type);
                                switch (nexthop->type) {
                                case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
                                        stream_put_in_addr(s,
                                                           &nexthop->gate.ipv4);
                                        stream_putl(s, nexthop->ifindex);
@@ -904,15 +1043,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                                case NEXTHOP_TYPE_IFINDEX:
                                        stream_putl(s, nexthop->ifindex);
                                        break;
-                               case NEXTHOP_TYPE_IPV4_IFINDEX:
-                                       stream_put_in_addr(s,
-                                                          &nexthop->gate.ipv4);
-                                       stream_putl(s, nexthop->ifindex);
-                                       break;
                                case NEXTHOP_TYPE_IPV6:
-                                       stream_put(s, &nexthop->gate.ipv6, 16);
-                                       stream_putl(s, nexthop->ifindex);
-                                       break;
                                case NEXTHOP_TYPE_IPV6_IFINDEX:
                                        stream_put(s, &nexthop->gate.ipv6, 16);
                                        stream_putl(s, nexthop->ifindex);
@@ -925,6 +1056,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                        }
                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
@@ -1003,5 +1136,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
        if (!list_isempty(rnh->zebra_static_route_list))
                vty_out(vty, " zebra%s",
                        rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
+       if (!list_isempty(rnh->zebra_pseudowire_list))
+               vty_out(vty, " zebra[pseudowires]");
        vty_out(vty, "\n");
 }