1 /*
2  * Copyright (C) 2020  NetDEF, Inc.
3  *                     Renato Westphal
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; see the file COPYING; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <zebra.h>
21 
22 #include "isisd/isisd.h"
23 #include "isisd/isis_dynhn.h"
24 #include "isisd/isis_mt.h"
25 
26 #include "test_common.h"
27 
28 struct thread_master *master;
29 struct zebra_privs_t isisd_privs;
30 
isis_sock_init(struct isis_circuit * circuit)31 int isis_sock_init(struct isis_circuit *circuit)
32 {
33 	return 0;
34 }
35 
36 const struct isis_test_node *
test_topology_find_node(const struct isis_topology * topology,const char * hostname,uint8_t pseudonode_id)37 test_topology_find_node(const struct isis_topology *topology,
38 			const char *hostname, uint8_t pseudonode_id)
39 {
40 	for (size_t i = 0; topology->nodes[i].hostname[0]; i++)
41 		if (strmatch(hostname, topology->nodes[i].hostname)
42 		    && pseudonode_id == topology->nodes[i].pseudonode_id)
43 			return &topology->nodes[i];
44 
45 	return NULL;
46 }
47 
48 const struct isis_topology *
test_topology_find(struct isis_topology * test_topologies,uint16_t number)49 test_topology_find(struct isis_topology *test_topologies, uint16_t number)
50 {
51 	for (size_t i = 0; test_topologies[i].number; i++)
52 		if (test_topologies[i].number == number)
53 			return &test_topologies[i];
54 
55 	return NULL;
56 }
57 
58 static const struct isis_test_node *
test_find_adjacency(const struct isis_test_node * tnode,const char * hostname)59 test_find_adjacency(const struct isis_test_node *tnode, const char *hostname)
60 {
61 	for (size_t i = 0; tnode->adjacencies[i].hostname[0]; i++) {
62 		const struct isis_test_adj *tadj;
63 
64 		tadj = &tnode->adjacencies[i];
65 		if (strmatch(hostname, tadj->hostname))
66 			return tnode;
67 	}
68 
69 	return NULL;
70 }
71 
lsp_add(struct lspdb_head * lspdb,struct isis_area * area,int level,const uint8_t * sysid,uint8_t pseudonode_id)72 static struct isis_lsp *lsp_add(struct lspdb_head *lspdb,
73 				struct isis_area *area, int level,
74 				const uint8_t *sysid, uint8_t pseudonode_id)
75 {
76 	struct isis_lsp *lsp;
77 	uint8_t lspid[ISIS_SYS_ID_LEN + 2];
78 
79 	memcpy(lspid, sysid, ISIS_SYS_ID_LEN);
80 	LSP_PSEUDO_ID(lspid) = pseudonode_id;
81 	LSP_FRAGMENT(lspid) = 0;
82 
83 	lsp = lsp_new(area, lspid, 6000, 1, 0, 0, NULL, level);
84 	lsp->tlvs = isis_alloc_tlvs();
85 	lspdb_add(lspdb, lsp);
86 
87 	return lsp;
88 }
89 
lsp_add_ip_reach(struct isis_lsp * lsp,const struct isis_test_node * tnode,const char * prefix_str,uint32_t * next_sid_index)90 static void lsp_add_ip_reach(struct isis_lsp *lsp,
91 			     const struct isis_test_node *tnode,
92 			     const char *prefix_str, uint32_t *next_sid_index)
93 {
94 	struct prefix prefix;
95 	struct sr_prefix_cfg pcfg = {};
96 	struct sr_prefix_cfg *pcfg_p = NULL;
97 
98 	if (str2prefix(prefix_str, &prefix) != 1) {
99 		zlog_debug("%s: invalid network: %s", __func__, prefix_str);
100 		return;
101 	}
102 
103 	if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) {
104 		pcfg_p = &pcfg;
105 
106 		pcfg.sid = *next_sid_index;
107 		*next_sid_index = *next_sid_index + 1;
108 		pcfg.sid_type = SR_SID_VALUE_TYPE_INDEX;
109 		pcfg.last_hop_behavior = SR_LAST_HOP_BEHAVIOR_PHP;
110 	}
111 
112 	if (prefix.family == AF_INET)
113 		isis_tlvs_add_extended_ip_reach(lsp->tlvs,
114 						(struct prefix_ipv4 *)&prefix,
115 						10, false, pcfg_p);
116 	else
117 		isis_tlvs_add_ipv6_reach(lsp->tlvs, ISIS_MT_IPV6_UNICAST,
118 					 (struct prefix_ipv6 *)&prefix, 10,
119 					 false, pcfg_p);
120 }
121 
lsp_add_reach(struct isis_lsp * lsp,const struct isis_test_node * tnode,const uint8_t * ne_id,uint8_t pseudonode_id,uint32_t metric,int family,mpls_label_t * next_label)122 static void lsp_add_reach(struct isis_lsp *lsp,
123 			  const struct isis_test_node *tnode,
124 			  const uint8_t *ne_id, uint8_t pseudonode_id,
125 			  uint32_t metric, int family, mpls_label_t *next_label)
126 {
127 	uint8_t nodeid[ISIS_SYS_ID_LEN + 1];
128 	uint16_t mtid;
129 	struct isis_ext_subtlvs *ext = NULL;
130 
131 	memcpy(nodeid, ne_id, ISIS_SYS_ID_LEN);
132 	LSP_PSEUDO_ID(nodeid) = pseudonode_id;
133 
134 	if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) {
135 		struct isis_adj_sid *adj_sid;
136 
137 		adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid));
138 		adj_sid->family = family;
139 		SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
140 		SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
141 		if (family == AF_INET6)
142 			SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG);
143 		adj_sid->weight = 0;
144 		adj_sid->sid = *next_label;
145 		*next_label = *next_label + 1;
146 
147 		ext = isis_alloc_ext_subtlvs();
148 		isis_tlvs_add_adj_sid(ext, adj_sid);
149 	}
150 
151 	mtid = (family == AF_INET) ? ISIS_MT_IPV4_UNICAST
152 				   : ISIS_MT_IPV6_UNICAST;
153 
154 	isis_tlvs_add_extended_reach(lsp->tlvs, mtid, nodeid, metric, ext);
155 }
156 
lsp_add_router_capability(struct isis_lsp * lsp,const struct isis_test_node * tnode)157 static void lsp_add_router_capability(struct isis_lsp *lsp,
158 				      const struct isis_test_node *tnode)
159 {
160 	struct isis_router_cap cap = {};
161 
162 	if (!tnode->router_id)
163 		return;
164 
165 	if (inet_pton(AF_INET, tnode->router_id, &cap.router_id) != 1) {
166 		zlog_debug("%s: invalid router-id: %s", __func__,
167 			   tnode->router_id);
168 		return;
169 	}
170 
171 	if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) {
172 		cap.srgb.flags =
173 			ISIS_SUBTLV_SRGB_FLAG_I | ISIS_SUBTLV_SRGB_FLAG_V;
174 		cap.srgb.lower_bound = tnode->srgb.lower_bound
175 					       ? tnode->srgb.lower_bound
176 					       : SRGB_DFTL_LOWER_BOUND;
177 		cap.srgb.range_size = tnode->srgb.range_size
178 					      ? tnode->srgb.range_size
179 					      : SRGB_DFTL_RANGE_SIZE;
180 		cap.algo[0] = SR_ALGORITHM_SPF;
181 		cap.algo[1] = SR_ALGORITHM_UNSET;
182 	}
183 
184 	isis_tlvs_set_router_capability(lsp->tlvs, &cap);
185 }
186 
lsp_add_mt_router_info(struct isis_lsp * lsp,const struct isis_test_node * tnode)187 static void lsp_add_mt_router_info(struct isis_lsp *lsp,
188 				   const struct isis_test_node *tnode)
189 {
190 	if (tnode->protocols.ipv4)
191 		isis_tlvs_add_mt_router_info(lsp->tlvs, ISIS_MT_IPV4_UNICAST, 0,
192 					     false);
193 	if (tnode->protocols.ipv6)
194 		isis_tlvs_add_mt_router_info(lsp->tlvs, ISIS_MT_IPV6_UNICAST, 0,
195 					     false);
196 }
197 
lsp_add_protocols_supported(struct isis_lsp * lsp,const struct isis_test_node * tnode)198 static void lsp_add_protocols_supported(struct isis_lsp *lsp,
199 					const struct isis_test_node *tnode)
200 {
201 	struct nlpids nlpids = {};
202 
203 	if (!tnode->protocols.ipv4 && !tnode->protocols.ipv6)
204 		return;
205 
206 	if (tnode->protocols.ipv4) {
207 		nlpids.nlpids[nlpids.count] = NLPID_IP;
208 		nlpids.count++;
209 	}
210 	if (tnode->protocols.ipv6) {
211 		nlpids.nlpids[nlpids.count] = NLPID_IPV6;
212 		nlpids.count++;
213 	}
214 	isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
215 }
216 
topology_load_node_level(const struct isis_topology * topology,const struct isis_test_node * tnode,size_t tnode_index,struct isis_area * area,struct lspdb_head * lspdb,int level)217 static int topology_load_node_level(const struct isis_topology *topology,
218 				    const struct isis_test_node *tnode,
219 				    size_t tnode_index, struct isis_area *area,
220 				    struct lspdb_head *lspdb, int level)
221 {
222 	struct isis_lsp *lsp;
223 	uint32_t next_sid_index = (tnode_index + 1) * 10;
224 	mpls_label_t next_label = 16;
225 
226 	lsp = lsp_add(lspdb, area, level, tnode->sysid, tnode->pseudonode_id);
227 	lsp_add_mt_router_info(lsp, tnode);
228 	lsp_add_protocols_supported(lsp, tnode);
229 	lsp_add_router_capability(lsp, tnode);
230 
231 	/* Add IP Reachability Information. */
232 	for (size_t i = 0; tnode->networks[i]; i++) {
233 		if (i > MAX_NETWORKS) {
234 			zlog_debug(
235 				"%s: node has too many networks (maximum is %u)",
236 				__func__, MAX_NETWORKS);
237 			return -1;
238 		}
239 		lsp_add_ip_reach(lsp, tnode, tnode->networks[i],
240 				 &next_sid_index);
241 	}
242 
243 	/* Add IS Reachability Information. */
244 	for (size_t i = 0; tnode->adjacencies[i].hostname[0]; i++) {
245 		const struct isis_test_adj *tadj;
246 		const struct isis_test_node *tadj_node;
247 
248 		if (i > MAX_ADJACENCIES) {
249 			zlog_debug(
250 				"%s: node has too many adjacencies (maximum is %u)",
251 				__func__, MAX_ADJACENCIES);
252 			return -1;
253 		}
254 
255 		tadj = &tnode->adjacencies[i];
256 		tadj_node = test_topology_find_node(topology, tadj->hostname,
257 						    tadj->pseudonode_id);
258 		if (!tadj_node) {
259 			zlog_debug(
260 				"%s: node \"%s\" has an adjacency with non-existing node \"%s\"",
261 				__func__, tnode->hostname, tadj->hostname);
262 			return -1;
263 		}
264 		if (!test_find_adjacency(tadj_node, tnode->hostname)) {
265 			zlog_debug(
266 				"%s: node \"%s\" has an one-way adjacency with node \"%s\"",
267 				__func__, tnode->hostname, tadj->hostname);
268 			return -1;
269 		}
270 
271 		if (tnode->pseudonode_id || tadj_node->pseudonode_id
272 		    || (tnode->protocols.ipv4 && tadj_node->protocols.ipv4))
273 			lsp_add_reach(lsp, tnode, tadj_node->sysid,
274 				      tadj_node->pseudonode_id, tadj->metric,
275 				      AF_INET, &next_label);
276 		if (tadj_node->pseudonode_id
277 		    || (tnode->protocols.ipv6 && tadj_node->protocols.ipv6))
278 			lsp_add_reach(lsp, tnode, tadj_node->sysid,
279 				      tadj_node->pseudonode_id, tadj->metric,
280 				      AF_INET6, &next_label);
281 	}
282 
283 	return 0;
284 }
285 
topology_load_node(const struct isis_topology * topology,const struct isis_test_node * tnode,size_t tnode_index,struct isis_area * area,struct lspdb_head lspdb[])286 static int topology_load_node(const struct isis_topology *topology,
287 			      const struct isis_test_node *tnode,
288 			      size_t tnode_index, struct isis_area *area,
289 			      struct lspdb_head lspdb[])
290 {
291 	int ret;
292 
293 	isis_dynhn_insert(tnode->sysid, tnode->hostname, tnode->level);
294 
295 	for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
296 		if ((tnode->level & level) == 0)
297 			continue;
298 
299 		ret = topology_load_node_level(topology, tnode, tnode_index,
300 					       area, &lspdb[level - 1], level);
301 		if (ret != 0)
302 			return ret;
303 	}
304 
305 	return 0;
306 }
307 
test_topology_load(const struct isis_topology * topology,struct isis_area * area,struct lspdb_head lspdb[])308 int test_topology_load(const struct isis_topology *topology,
309 		       struct isis_area *area, struct lspdb_head lspdb[])
310 {
311 	for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
312 		lsp_db_init(&lspdb[level - 1]);
313 
314 	for (size_t i = 0; topology->nodes[i].hostname[0]; i++) {
315 		const struct isis_test_node *tnode = &topology->nodes[i];
316 		int ret;
317 
318 		if (i > MAX_NODES) {
319 			zlog_debug(
320 				"%s: topology has too many nodes (maximum is %u)",
321 				__func__, MAX_NODES);
322 			return -1;
323 		}
324 
325 		ret = topology_load_node(topology, tnode, i, area, lspdb);
326 		if (ret != 0)
327 			return ret;
328 	}
329 
330 	return 0;
331 }
332