Line data Source code
1 : /*
2 : * Static NHT code.
3 : * Copyright (C) 2018 Cumulus Networks, Inc.
4 : * Donald Sharp
5 : *
6 : * This program is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the Free
8 : * Software Foundation; either version 2 of the License, or (at your option)
9 : * any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 : #include <zebra.h>
21 :
22 : #include "prefix.h"
23 : #include "table.h"
24 : #include "vrf.h"
25 : #include "nexthop.h"
26 : #include "srcdest_table.h"
27 :
28 : #include "static_vrf.h"
29 : #include "static_routes.h"
30 : #include "static_zebra.h"
31 : #include "static_nht.h"
32 :
33 12 : static void static_nht_update_path(struct static_path *pn, struct prefix *nhp,
34 : uint32_t nh_num, vrf_id_t nh_vrf_id,
35 : struct vrf *vrf)
36 : {
37 12 : struct static_nexthop *nh;
38 :
39 48 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
40 12 : if (nh->nh_vrf_id != nh_vrf_id)
41 0 : continue;
42 :
43 12 : if (nh->type != STATIC_IPV4_GATEWAY
44 : && nh->type != STATIC_IPV4_GATEWAY_IFNAME
45 : && nh->type != STATIC_IPV6_GATEWAY
46 12 : && nh->type != STATIC_IPV6_GATEWAY_IFNAME)
47 0 : continue;
48 :
49 12 : if (nhp->family == AF_INET
50 12 : && nhp->u.prefix4.s_addr == nh->addr.ipv4.s_addr)
51 12 : nh->nh_valid = !!nh_num;
52 :
53 12 : if (nhp->family == AF_INET6
54 0 : && memcmp(&nhp->u.prefix6, &nh->addr.ipv6, IPV6_MAX_BYTELEN)
55 : == 0)
56 0 : nh->nh_valid = !!nh_num;
57 :
58 12 : if (nh->state == STATIC_START)
59 12 : static_zebra_route_add(pn, true);
60 : }
61 12 : }
62 :
63 12 : static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
64 : uint32_t nh_num, afi_t afi, safi_t safi,
65 : struct vrf *vrf, vrf_id_t nh_vrf_id)
66 : {
67 12 : struct route_table *stable;
68 12 : struct static_vrf *svrf;
69 12 : struct route_node *rn;
70 12 : struct static_path *pn;
71 12 : struct static_route_info *si;
72 :
73 12 : svrf = vrf->info;
74 12 : if (!svrf)
75 : return;
76 :
77 12 : stable = static_vrf_static_table(afi, safi, svrf);
78 12 : if (!stable)
79 : return;
80 :
81 12 : if (sp) {
82 0 : rn = srcdest_rnode_lookup(stable, sp, NULL);
83 0 : if (rn && rn->info) {
84 0 : si = static_route_info_from_rnode(rn);
85 0 : frr_each(static_path_list, &si->path_list, pn) {
86 0 : static_nht_update_path(pn, nhp, nh_num,
87 : nh_vrf_id, vrf);
88 : }
89 0 : route_unlock_node(rn);
90 : }
91 0 : return;
92 : }
93 :
94 24 : for (rn = route_top(stable); rn; rn = route_next(rn)) {
95 12 : si = static_route_info_from_rnode(rn);
96 12 : if (!si)
97 0 : continue;
98 48 : frr_each(static_path_list, &si->path_list, pn) {
99 12 : static_nht_update_path(pn, nhp, nh_num, nh_vrf_id, vrf);
100 : }
101 : }
102 : }
103 :
104 12 : void static_nht_update(struct prefix *sp, struct prefix *nhp, uint32_t nh_num,
105 : afi_t afi, safi_t safi, vrf_id_t nh_vrf_id)
106 : {
107 :
108 12 : struct vrf *vrf;
109 :
110 36 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
111 12 : static_nht_update_safi(sp, nhp, nh_num, afi, safi, vrf,
112 : nh_vrf_id);
113 12 : }
114 :
115 12 : static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
116 : safi_t safi, struct vrf *vrf,
117 : vrf_id_t nh_vrf_id)
118 : {
119 12 : struct static_vrf *svrf;
120 12 : struct route_table *stable;
121 12 : struct static_nexthop *nh;
122 12 : struct static_path *pn;
123 12 : struct route_node *rn;
124 12 : struct static_route_info *si;
125 :
126 12 : svrf = vrf->info;
127 12 : if (!svrf)
128 : return;
129 :
130 12 : stable = static_vrf_static_table(afi, safi, svrf);
131 12 : if (!stable)
132 : return;
133 :
134 24 : for (rn = route_top(stable); rn; rn = route_next(rn)) {
135 12 : si = static_route_info_from_rnode(rn);
136 12 : if (!si)
137 0 : continue;
138 48 : frr_each(static_path_list, &si->path_list, pn) {
139 48 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
140 12 : if (nh->nh_vrf_id != nh_vrf_id)
141 0 : continue;
142 :
143 12 : if (nhp->family == AF_INET
144 12 : && nhp->u.prefix4.s_addr
145 12 : != nh->addr.ipv4.s_addr)
146 0 : continue;
147 :
148 12 : if (nhp->family == AF_INET6
149 0 : && memcmp(&nhp->u.prefix6, &nh->addr.ipv6,
150 : 16)
151 : != 0)
152 0 : continue;
153 :
154 : /*
155 : * We've been told that a nexthop we
156 : * depend on has changed in some manner,
157 : * so reset the state machine to allow
158 : * us to start over.
159 : */
160 12 : nh->state = STATIC_START;
161 : }
162 : }
163 : }
164 : }
165 :
166 12 : void static_nht_reset_start(struct prefix *nhp, afi_t afi, safi_t safi,
167 : vrf_id_t nh_vrf_id)
168 : {
169 12 : struct vrf *vrf;
170 :
171 36 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
172 12 : static_nht_reset_start_safi(nhp, afi, safi, vrf, nh_vrf_id);
173 12 : }
174 :
175 5 : static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
176 : safi_t safi, struct vrf *vrf,
177 : enum static_install_states state)
178 : {
179 5 : struct static_vrf *svrf;
180 5 : struct route_table *stable;
181 5 : struct route_node *rn;
182 5 : struct static_nexthop *nh;
183 5 : struct static_path *pn;
184 5 : struct static_route_info *si;
185 :
186 5 : svrf = vrf->info;
187 5 : if (!svrf)
188 : return;
189 :
190 5 : stable = static_vrf_static_table(afi, safi, svrf);
191 5 : if (!stable)
192 : return;
193 :
194 5 : rn = srcdest_rnode_lookup(stable, sp, NULL);
195 5 : if (!rn)
196 : return;
197 5 : si = rn->info;
198 5 : if (si) {
199 20 : frr_each(static_path_list, &si->path_list, pn) {
200 15 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
201 5 : nh->state = state;
202 : }
203 : }
204 : }
205 :
206 5 : route_unlock_node(rn);
207 : }
208 :
209 5 : void static_nht_mark_state(struct prefix *sp, safi_t safi, vrf_id_t vrf_id,
210 : enum static_install_states state)
211 : {
212 5 : struct vrf *vrf;
213 :
214 5 : afi_t afi = AFI_IP;
215 :
216 5 : if (sp->family == AF_INET6)
217 0 : afi = AFI_IP6;
218 :
219 5 : vrf = vrf_lookup_by_id(vrf_id);
220 5 : if (!vrf || !vrf->info)
221 : return;
222 :
223 5 : static_nht_mark_state_safi(sp, afi, safi, vrf, state);
224 : }
|