Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * SRv6 definitions |
4 | | * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation |
5 | | */ |
6 | | |
7 | | #include "zebra.h" |
8 | | |
9 | | #include "srv6.h" |
10 | | #include "log.h" |
11 | | |
12 | | DEFINE_QOBJ_TYPE(srv6_locator); |
13 | 8 | DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); |
14 | 8 | DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); |
15 | 8 | |
16 | 8 | const char *seg6local_action2str(uint32_t action) |
17 | 8 | { |
18 | 0 | switch (action) { |
19 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END: |
20 | 0 | return "End"; |
21 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_X: |
22 | 0 | return "End.X"; |
23 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_T: |
24 | 0 | return "End.T"; |
25 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: |
26 | 0 | return "End.DX2"; |
27 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: |
28 | 0 | return "End.DX6"; |
29 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: |
30 | 0 | return "End.DX4"; |
31 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: |
32 | 0 | return "End.DT6"; |
33 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: |
34 | 0 | return "End.DT4"; |
35 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_B6: |
36 | 0 | return "End.B6"; |
37 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: |
38 | 0 | return "End.B6.Encap"; |
39 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_BM: |
40 | 0 | return "End.BM"; |
41 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_S: |
42 | 0 | return "End.S"; |
43 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_AS: |
44 | 0 | return "End.AS"; |
45 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_AM: |
46 | 0 | return "End.AM"; |
47 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: |
48 | 0 | return "End.DT46"; |
49 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: |
50 | 0 | return "unspec"; |
51 | 0 | default: |
52 | 0 | return "unknown"; |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | | int snprintf_seg6_segs(char *str, |
57 | | size_t size, const struct seg6_segs *segs) |
58 | 0 | { |
59 | 0 | str[0] = '\0'; |
60 | 0 | for (size_t i = 0; i < segs->num_segs; i++) { |
61 | 0 | char addr[INET6_ADDRSTRLEN]; |
62 | 0 | bool not_last = (i + 1) < segs->num_segs; |
63 | |
|
64 | 0 | inet_ntop(AF_INET6, &segs->segs[i], addr, sizeof(addr)); |
65 | 0 | strlcat(str, addr, size); |
66 | 0 | strlcat(str, not_last ? "," : "", size); |
67 | 0 | } |
68 | 0 | return strlen(str); |
69 | 0 | } |
70 | | |
71 | | const char *seg6local_context2str(char *str, size_t size, |
72 | | const struct seg6local_context *ctx, |
73 | | uint32_t action) |
74 | 0 | { |
75 | 0 | switch (action) { |
76 | | |
77 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END: |
78 | 0 | snprintf(str, size, "USP"); |
79 | 0 | return str; |
80 | | |
81 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_X: |
82 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: |
83 | 0 | snprintfrr(str, size, "nh6 %pI6", &ctx->nh6); |
84 | 0 | return str; |
85 | | |
86 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: |
87 | 0 | snprintfrr(str, size, "nh4 %pI4", &ctx->nh4); |
88 | 0 | return str; |
89 | | |
90 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_T: |
91 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: |
92 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: |
93 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: |
94 | 0 | snprintf(str, size, "table %u", ctx->table); |
95 | 0 | return str; |
96 | | |
97 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: |
98 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_B6: |
99 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: |
100 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_BM: |
101 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_S: |
102 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_AS: |
103 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_END_AM: |
104 | 0 | case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: |
105 | 0 | default: |
106 | 0 | snprintf(str, size, "unknown(%s)", __func__); |
107 | 0 | return str; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | static void srv6_locator_chunk_list_free(void *data) |
112 | 0 | { |
113 | 0 | struct srv6_locator_chunk *chunk = data; |
114 | |
|
115 | 0 | srv6_locator_chunk_free(&chunk); |
116 | 0 | } |
117 | | |
118 | | struct srv6_locator *srv6_locator_alloc(const char *name) |
119 | 0 | { |
120 | 0 | struct srv6_locator *locator = NULL; |
121 | |
|
122 | 0 | locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator)); |
123 | 0 | strlcpy(locator->name, name, sizeof(locator->name)); |
124 | 0 | locator->chunks = list_new(); |
125 | 0 | locator->chunks->del = srv6_locator_chunk_list_free; |
126 | |
|
127 | 0 | QOBJ_REG(locator, srv6_locator); |
128 | 0 | return locator; |
129 | 0 | } |
130 | | |
131 | | struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) |
132 | 0 | { |
133 | 0 | struct srv6_locator_chunk *chunk = NULL; |
134 | |
|
135 | 0 | chunk = XCALLOC(MTYPE_SRV6_LOCATOR_CHUNK, |
136 | 0 | sizeof(struct srv6_locator_chunk)); |
137 | 0 | return chunk; |
138 | 0 | } |
139 | | |
140 | | void srv6_locator_free(struct srv6_locator *locator) |
141 | 0 | { |
142 | 0 | if (locator) { |
143 | 0 | QOBJ_UNREG(locator); |
144 | 0 | list_delete(&locator->chunks); |
145 | |
|
146 | 0 | XFREE(MTYPE_SRV6_LOCATOR, locator); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) |
151 | 0 | { |
152 | 0 | XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); |
153 | 0 | } |
154 | | |
155 | | json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) |
156 | 0 | { |
157 | 0 | json_object *jo_root = NULL; |
158 | |
|
159 | 0 | jo_root = json_object_new_object(); |
160 | 0 | json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix); |
161 | 0 | json_object_string_add(jo_root, "proto", |
162 | 0 | zebra_route_string(chunk->proto)); |
163 | |
|
164 | 0 | return jo_root; |
165 | 0 | } |
166 | | |
167 | | json_object * |
168 | | srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk) |
169 | 0 | { |
170 | 0 | json_object *jo_root = NULL; |
171 | |
|
172 | 0 | jo_root = json_object_new_object(); |
173 | | |
174 | | /* set prefix */ |
175 | 0 | json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix); |
176 | | |
177 | | /* set block_bits_length */ |
178 | 0 | json_object_int_add(jo_root, "blockBitsLength", |
179 | 0 | chunk->block_bits_length); |
180 | | |
181 | | /* set node_bits_length */ |
182 | 0 | json_object_int_add(jo_root, "nodeBitsLength", chunk->node_bits_length); |
183 | | |
184 | | /* set function_bits_length */ |
185 | 0 | json_object_int_add(jo_root, "functionBitsLength", |
186 | 0 | chunk->function_bits_length); |
187 | | |
188 | | /* set argument_bits_length */ |
189 | 0 | json_object_int_add(jo_root, "argumentBitsLength", |
190 | 0 | chunk->argument_bits_length); |
191 | | |
192 | | /* set keep */ |
193 | 0 | json_object_int_add(jo_root, "keep", chunk->keep); |
194 | | |
195 | | /* set proto */ |
196 | 0 | json_object_string_add(jo_root, "proto", |
197 | 0 | zebra_route_string(chunk->proto)); |
198 | | |
199 | | /* set instance */ |
200 | 0 | json_object_int_add(jo_root, "instance", chunk->instance); |
201 | | |
202 | | /* set session_id */ |
203 | 0 | json_object_int_add(jo_root, "sessionId", chunk->session_id); |
204 | |
|
205 | 0 | return jo_root; |
206 | 0 | } |
207 | | |
208 | | json_object *srv6_locator_json(const struct srv6_locator *loc) |
209 | 0 | { |
210 | 0 | struct listnode *node; |
211 | 0 | struct srv6_locator_chunk *chunk; |
212 | 0 | json_object *jo_root = NULL; |
213 | 0 | json_object *jo_chunk = NULL; |
214 | 0 | json_object *jo_chunks = NULL; |
215 | |
|
216 | 0 | jo_root = json_object_new_object(); |
217 | | |
218 | | /* set name */ |
219 | 0 | json_object_string_add(jo_root, "name", loc->name); |
220 | | |
221 | | /* set prefix */ |
222 | 0 | json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); |
223 | | |
224 | | /* set block_bits_length */ |
225 | 0 | json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); |
226 | | |
227 | | /* set node_bits_length */ |
228 | 0 | json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); |
229 | | |
230 | | /* set function_bits_length */ |
231 | 0 | json_object_int_add(jo_root, "functionBitsLength", |
232 | 0 | loc->function_bits_length); |
233 | | |
234 | | /* set argument_bits_length */ |
235 | 0 | json_object_int_add(jo_root, "argumentBitsLength", |
236 | 0 | loc->argument_bits_length); |
237 | | |
238 | | /* set true if the locator is a Micro-segment (uSID) locator */ |
239 | 0 | if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) |
240 | 0 | json_object_string_add(jo_root, "behavior", "usid"); |
241 | | |
242 | | /* set status_up */ |
243 | 0 | json_object_boolean_add(jo_root, "statusUp", |
244 | 0 | loc->status_up); |
245 | | |
246 | | /* set chunks */ |
247 | 0 | jo_chunks = json_object_new_array(); |
248 | 0 | json_object_object_add(jo_root, "chunks", jo_chunks); |
249 | 0 | for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { |
250 | 0 | jo_chunk = srv6_locator_chunk_json(chunk); |
251 | 0 | json_object_array_add(jo_chunks, jo_chunk); |
252 | 0 | } |
253 | |
|
254 | 0 | return jo_root; |
255 | 0 | } |
256 | | |
257 | | json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) |
258 | 0 | { |
259 | 0 | struct listnode *node; |
260 | 0 | struct srv6_locator_chunk *chunk; |
261 | 0 | json_object *jo_root = NULL; |
262 | 0 | json_object *jo_chunk = NULL; |
263 | 0 | json_object *jo_chunks = NULL; |
264 | |
|
265 | 0 | jo_root = json_object_new_object(); |
266 | | |
267 | | /* set name */ |
268 | 0 | json_object_string_add(jo_root, "name", loc->name); |
269 | | |
270 | | /* set prefix */ |
271 | 0 | json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); |
272 | | |
273 | | /* set block_bits_length */ |
274 | 0 | json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); |
275 | | |
276 | | /* set node_bits_length */ |
277 | 0 | json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); |
278 | | |
279 | | /* set function_bits_length */ |
280 | 0 | json_object_int_add(jo_root, "functionBitsLength", |
281 | 0 | loc->function_bits_length); |
282 | | |
283 | | /* set argument_bits_length */ |
284 | 0 | json_object_int_add(jo_root, "argumentBitsLength", |
285 | 0 | loc->argument_bits_length); |
286 | | |
287 | | /* set true if the locator is a Micro-segment (uSID) locator */ |
288 | 0 | if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) |
289 | 0 | json_object_string_add(jo_root, "behavior", "usid"); |
290 | | |
291 | | /* set algonum */ |
292 | 0 | json_object_int_add(jo_root, "algoNum", loc->algonum); |
293 | | |
294 | | /* set status_up */ |
295 | 0 | json_object_boolean_add(jo_root, "statusUp", loc->status_up); |
296 | | |
297 | | /* set chunks */ |
298 | 0 | jo_chunks = json_object_new_array(); |
299 | 0 | json_object_object_add(jo_root, "chunks", jo_chunks); |
300 | 0 | for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { |
301 | 0 | jo_chunk = srv6_locator_chunk_detailed_json(chunk); |
302 | 0 | json_object_array_add(jo_chunks, jo_chunk); |
303 | 0 | } |
304 | |
|
305 | 0 | return jo_root; |
306 | 0 | } |