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 72 : 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 72 : struct static_nexthop *nh;
38 :
39 288 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
40 72 : if (nh->nh_vrf_id != nh_vrf_id)
41 0 : continue;
42 :
43 72 : if (nh->type != STATIC_IPV4_GATEWAY
44 : && nh->type != STATIC_IPV4_GATEWAY_IFNAME
45 : && nh->type != STATIC_IPV6_GATEWAY
46 72 : && nh->type != STATIC_IPV6_GATEWAY_IFNAME)
47 0 : continue;
48 :
49 72 : if (nhp->family == AF_INET
50 44 : && nhp->u.prefix4.s_addr == nh->addr.ipv4.s_addr)
51 28 : nh->nh_valid = !!nh_num;
52 :
53 72 : if (nhp->family == AF_INET6
54 28 : && memcmp(&nhp->u.prefix6, &nh->addr.ipv6, IPV6_MAX_BYTELEN)
55 : == 0)
56 20 : nh->nh_valid = !!nh_num;
57 :
58 72 : if (nh->state == STATIC_START)
59 52 : static_zebra_route_add(pn, true);
60 : }
61 72 : }
62 :
63 46 : 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 46 : struct route_table *stable;
68 46 : struct static_vrf *svrf;
69 46 : struct route_node *rn;
70 46 : struct static_path *pn;
71 46 : struct static_route_info *si;
72 :
73 46 : svrf = vrf->info;
74 46 : if (!svrf)
75 : return;
76 :
77 46 : stable = static_vrf_static_table(afi, safi, svrf);
78 46 : if (!stable)
79 : return;
80 :
81 46 : if (sp) {
82 2 : rn = srcdest_rnode_lookup(stable, sp, NULL);
83 2 : if (rn && rn->info) {
84 2 : si = static_route_info_from_rnode(rn);
85 8 : frr_each(static_path_list, &si->path_list, pn) {
86 2 : static_nht_update_path(pn, nhp, nh_num,
87 : nh_vrf_id, vrf);
88 : }
89 2 : route_unlock_node(rn);
90 : }
91 2 : return;
92 : }
93 :
94 140 : for (rn = route_top(stable); rn; rn = route_next(rn)) {
95 96 : si = static_route_info_from_rnode(rn);
96 96 : if (!si)
97 26 : continue;
98 280 : frr_each(static_path_list, &si->path_list, pn) {
99 70 : static_nht_update_path(pn, nhp, nh_num, nh_vrf_id, vrf);
100 : }
101 : }
102 : }
103 :
104 46 : 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 46 : struct vrf *vrf;
109 :
110 138 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
111 46 : static_nht_update_safi(sp, nhp, nh_num, afi, safi, vrf,
112 : nh_vrf_id);
113 46 : }
114 :
115 44 : 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 44 : struct static_vrf *svrf;
120 44 : struct route_table *stable;
121 44 : struct static_nexthop *nh;
122 44 : struct static_path *pn;
123 44 : struct route_node *rn;
124 44 : struct static_route_info *si;
125 :
126 44 : svrf = vrf->info;
127 44 : if (!svrf)
128 : return;
129 :
130 44 : stable = static_vrf_static_table(afi, safi, svrf);
131 44 : if (!stable)
132 : return;
133 :
134 140 : for (rn = route_top(stable); rn; rn = route_next(rn)) {
135 96 : si = static_route_info_from_rnode(rn);
136 96 : if (!si)
137 26 : continue;
138 280 : frr_each(static_path_list, &si->path_list, pn) {
139 280 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
140 70 : if (nh->nh_vrf_id != nh_vrf_id)
141 0 : continue;
142 :
143 70 : if (nhp->family == AF_INET
144 60 : && nhp->u.prefix4.s_addr
145 44 : != nh->addr.ipv4.s_addr)
146 16 : continue;
147 :
148 54 : if (nhp->family == AF_INET6
149 26 : && memcmp(&nhp->u.prefix6, &nh->addr.ipv6,
150 : 16)
151 : != 0)
152 8 : 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 46 : nh->state = STATIC_START;
161 : }
162 : }
163 : }
164 : }
165 :
166 44 : void static_nht_reset_start(struct prefix *nhp, afi_t afi, safi_t safi,
167 : vrf_id_t nh_vrf_id)
168 : {
169 44 : struct vrf *vrf;
170 :
171 132 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
172 44 : static_nht_reset_start_safi(nhp, afi, safi, vrf, nh_vrf_id);
173 44 : }
174 :
175 46 : 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 46 : struct static_vrf *svrf;
180 46 : struct route_table *stable;
181 46 : struct route_node *rn;
182 46 : struct static_nexthop *nh;
183 46 : struct static_path *pn;
184 46 : struct static_route_info *si;
185 :
186 46 : svrf = vrf->info;
187 46 : if (!svrf)
188 : return;
189 :
190 46 : stable = static_vrf_static_table(afi, safi, svrf);
191 46 : if (!stable)
192 : return;
193 :
194 46 : rn = srcdest_rnode_lookup(stable, sp, NULL);
195 46 : if (!rn)
196 : return;
197 46 : si = rn->info;
198 46 : if (si) {
199 184 : frr_each(static_path_list, &si->path_list, pn) {
200 138 : frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
201 46 : nh->state = state;
202 : }
203 : }
204 : }
205 :
206 46 : route_unlock_node(rn);
207 : }
208 :
209 46 : void static_nht_mark_state(struct prefix *sp, safi_t safi, vrf_id_t vrf_id,
210 : enum static_install_states state)
211 : {
212 46 : struct vrf *vrf;
213 :
214 46 : afi_t afi = AFI_IP;
215 :
216 46 : if (sp->family == AF_INET6)
217 29 : afi = AFI_IP6;
218 :
219 46 : vrf = vrf_lookup_by_id(vrf_id);
220 46 : if (!vrf || !vrf->info)
221 : return;
222 :
223 46 : static_nht_mark_state_safi(sp, afi, safi, vrf, state);
224 : }
|