]>
Commit | Line | Data |
---|---|---|
fe9f1a6d OZ |
1 | |
2 | #include "nest/bird.h" | |
3 | #include "lib/ip.h" | |
4 | #include "lib/net.h" | |
77234bbb | 5 | #include "lib/flowspec.h" |
fe9f1a6d | 6 | |
d7661fbe | 7 | |
f4a60a9b | 8 | const char * const net_label[] = { |
a82f692e OZ |
9 | [NET_IP4] = "ipv4", |
10 | [NET_IP6] = "ipv6", | |
11 | [NET_VPN4] = "vpn4", | |
12 | [NET_VPN6] = "vpn6", | |
13 | [NET_ROA4] = "roa4", | |
14 | [NET_ROA6] = "roa6", | |
15 | [NET_FLOW4] = "flow4", | |
16 | [NET_FLOW6] = "flow6", | |
be17805c | 17 | [NET_IP6_SADR]= "ipv6-sadr", |
33ad6e01 | 18 | [NET_MPLS] = "mpls", |
f4a60a9b OZ |
19 | }; |
20 | ||
fe9f1a6d | 21 | const u16 net_addr_length[] = { |
a82f692e OZ |
22 | [NET_IP4] = sizeof(net_addr_ip4), |
23 | [NET_IP6] = sizeof(net_addr_ip6), | |
24 | [NET_VPN4] = sizeof(net_addr_vpn4), | |
25 | [NET_VPN6] = sizeof(net_addr_vpn6), | |
26 | [NET_ROA4] = sizeof(net_addr_roa4), | |
27 | [NET_ROA6] = sizeof(net_addr_roa6), | |
28 | [NET_FLOW4] = 0, | |
29 | [NET_FLOW6] = 0, | |
be17805c | 30 | [NET_IP6_SADR]= sizeof(net_addr_ip6_sadr), |
33ad6e01 | 31 | [NET_MPLS] = sizeof(net_addr_mpls), |
9b136840 | 32 | }; |
fe9f1a6d | 33 | |
d7661fbe | 34 | const u8 net_max_prefix_length[] = { |
a82f692e OZ |
35 | [NET_IP4] = IP4_MAX_PREFIX_LENGTH, |
36 | [NET_IP6] = IP6_MAX_PREFIX_LENGTH, | |
37 | [NET_VPN4] = IP4_MAX_PREFIX_LENGTH, | |
38 | [NET_VPN6] = IP6_MAX_PREFIX_LENGTH, | |
39 | [NET_ROA4] = IP4_MAX_PREFIX_LENGTH, | |
40 | [NET_ROA6] = IP6_MAX_PREFIX_LENGTH, | |
41 | [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, | |
42 | [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, | |
be17805c | 43 | [NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH, |
33ad6e01 | 44 | [NET_MPLS] = 0, |
d7661fbe JMM |
45 | }; |
46 | ||
7fd4143e | 47 | const u16 net_max_text_length[] = { |
a82f692e OZ |
48 | [NET_IP4] = 18, /* "255.255.255.255/32" */ |
49 | [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ | |
50 | [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ | |
51 | [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ | |
52 | [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ | |
53 | [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ | |
54 | [NET_FLOW4] = 0, /* "flow4 { ... }" */ | |
55 | [NET_FLOW6] = 0, /* "flow6 { ... }" */ | |
be17805c | 56 | [NET_IP6_SADR]= 92, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ |
33ad6e01 | 57 | [NET_MPLS] = 7, /* "1048575" */ |
7fd4143e JMM |
58 | }; |
59 | ||
d7661fbe | 60 | |
8c9986d3 JMM |
61 | int |
62 | rd_format(const u64 rd, char *buf, int buflen) | |
63 | { | |
64 | switch (rd >> 48) | |
65 | { | |
2282030b JMM |
66 | case 0: return bsnprintf(buf, buflen, "%u:%u", (u32) (rd >> 32), (u32) rd); |
67 | case 1: return bsnprintf(buf, buflen, "%I4:%u", ip4_from_u32(rd >> 16), (u32) (rd & 0xffff)); | |
68 | case 2: if (((u32) (rd >> 16)) >> 16) | |
69 | return bsnprintf(buf, buflen, "%u:%u", (u32) (rd >> 16), (u32) (rd & 0xffff)); | |
70 | else | |
71 | return bsnprintf(buf, buflen, "2:%u:%u", (u32) (rd >> 16), (u32) (rd & 0xffff)); | |
8c9986d3 JMM |
72 | default: return bsnprintf(buf, buflen, "X:%08x:%08x", (u32) (rd >> 32), (u32) rd); |
73 | } | |
74 | } | |
75 | ||
9b136840 | 76 | int |
fe9f1a6d OZ |
77 | net_format(const net_addr *N, char *buf, int buflen) |
78 | { | |
79 | net_addr_union *n = (void *) N; | |
d311368b | 80 | buf[0] = 0; |
fe9f1a6d | 81 | |
fe9f1a6d OZ |
82 | switch (n->n.type) |
83 | { | |
84 | case NET_IP4: | |
e691d16a | 85 | return bsnprintf(buf, buflen, "%I4/%d", n->ip4.prefix, n->ip4.pxlen); |
fe9f1a6d | 86 | case NET_IP6: |
e691d16a | 87 | return bsnprintf(buf, buflen, "%I6/%d", n->ip6.prefix, n->ip6.pxlen); |
fe9f1a6d | 88 | case NET_VPN4: |
d311368b | 89 | { |
8c9986d3 | 90 | int c = rd_format(n->vpn4.rd, buf, buflen); |
a5d2a344 | 91 | ADVANCE(buf, buflen, c); |
8c9986d3 | 92 | return bsnprintf(buf, buflen, " %I4/%d", n->vpn4.prefix, n->vpn4.pxlen); |
d311368b | 93 | } |
fe9f1a6d | 94 | case NET_VPN6: |
d311368b | 95 | { |
8c9986d3 JMM |
96 | /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4 */ |
97 | int c = rd_format(n->vpn6.rd, buf, buflen); | |
a5d2a344 | 98 | ADVANCE(buf, buflen, c); |
8c9986d3 | 99 | return bsnprintf(buf, buflen, " %I6/%d", n->vpn6.prefix, n->vpn6.pxlen); |
d311368b | 100 | } |
de9b87f5 | 101 | case NET_ROA4: |
f9d729ab | 102 | return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn); |
de9b87f5 | 103 | case NET_ROA6: |
f9d729ab | 104 | return bsnprintf(buf, buflen, "%I6/%u-%u AS%u", n->roa6.prefix, n->roa6.pxlen, n->roa6.max_pxlen, n->roa6.asn); |
77234bbb OZ |
105 | case NET_FLOW4: |
106 | return flow4_net_format(buf, buflen, &n->flow4); | |
107 | case NET_FLOW6: | |
108 | return flow6_net_format(buf, buflen, &n->flow6); | |
be17805c OZ |
109 | case NET_IP6_SADR: |
110 | return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen); | |
33ad6e01 JMM |
111 | case NET_MPLS: |
112 | return bsnprintf(buf, buflen, "%u", n->mpls.label); | |
fe9f1a6d | 113 | } |
9b136840 | 114 | |
d311368b | 115 | bug("unknown network type"); |
9b136840 JMM |
116 | } |
117 | ||
9b136840 JMM |
118 | ip_addr |
119 | net_pxmask(const net_addr *a) | |
120 | { | |
121 | switch (a->type) | |
122 | { | |
123 | case NET_IP4: | |
124 | case NET_VPN4: | |
de9b87f5 | 125 | case NET_ROA4: |
77234bbb | 126 | case NET_FLOW4: |
9b136840 JMM |
127 | return ipa_from_ip4(ip4_mkmask(net4_pxlen(a))); |
128 | ||
129 | case NET_IP6: | |
130 | case NET_VPN6: | |
de9b87f5 | 131 | case NET_ROA6: |
77234bbb | 132 | case NET_FLOW6: |
be17805c | 133 | case NET_IP6_SADR: |
9b136840 JMM |
134 | return ipa_from_ip6(ip6_mkmask(net6_pxlen(a))); |
135 | ||
33ad6e01 | 136 | case NET_MPLS: |
9b136840 JMM |
137 | default: |
138 | return IPA_NONE; | |
139 | } | |
140 | } | |
141 | ||
5e173e9f JMM |
142 | int |
143 | net_compare(const net_addr *a, const net_addr *b) | |
9b136840 | 144 | { |
5e173e9f JMM |
145 | if (a->type != b->type) |
146 | return uint_cmp(a->type, b->type); | |
9b136840 | 147 | |
5e173e9f JMM |
148 | switch (a->type) |
149 | { | |
150 | case NET_IP4: | |
151 | return net_compare_ip4((const net_addr_ip4 *) a, (const net_addr_ip4 *) b); | |
152 | case NET_IP6: | |
153 | return net_compare_ip6((const net_addr_ip6 *) a, (const net_addr_ip6 *) b); | |
154 | case NET_VPN4: | |
155 | return net_compare_vpn4((const net_addr_vpn4 *) a, (const net_addr_vpn4 *) b); | |
156 | case NET_VPN6: | |
157 | return net_compare_vpn6((const net_addr_vpn6 *) a, (const net_addr_vpn6 *) b); | |
de9b87f5 PT |
158 | case NET_ROA4: |
159 | return net_compare_roa4((const net_addr_roa4 *) a, (const net_addr_roa4 *) b); | |
160 | case NET_ROA6: | |
161 | return net_compare_roa6((const net_addr_roa6 *) a, (const net_addr_roa6 *) b); | |
77234bbb OZ |
162 | case NET_FLOW4: |
163 | return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b); | |
164 | case NET_FLOW6: | |
165 | return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b); | |
be17805c OZ |
166 | case NET_IP6_SADR: |
167 | return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b); | |
33ad6e01 JMM |
168 | case NET_MPLS: |
169 | return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b); | |
5e173e9f JMM |
170 | } |
171 | return 0; | |
9b136840 JMM |
172 | } |
173 | ||
d15b0b0a OZ |
174 | #define NET_HASH(a,t) net_hash_##t((const net_addr_##t *) a) |
175 | ||
176 | u32 | |
177 | net_hash(const net_addr *n) | |
178 | { | |
179 | switch (n->type) | |
180 | { | |
181 | case NET_IP4: return NET_HASH(n, ip4); | |
182 | case NET_IP6: return NET_HASH(n, ip6); | |
183 | case NET_VPN4: return NET_HASH(n, vpn4); | |
184 | case NET_VPN6: return NET_HASH(n, vpn6); | |
185 | case NET_ROA4: return NET_HASH(n, roa4); | |
186 | case NET_ROA6: return NET_HASH(n, roa6); | |
77234bbb OZ |
187 | case NET_FLOW4: return NET_HASH(n, flow4); |
188 | case NET_FLOW6: return NET_HASH(n, flow6); | |
be17805c | 189 | case NET_IP6_SADR: return NET_HASH(n, ip6_sadr); |
4278abfe | 190 | case NET_MPLS: return NET_HASH(n, mpls); |
d15b0b0a OZ |
191 | default: bug("invalid type"); |
192 | } | |
193 | } | |
194 | ||
195 | ||
4278abfe OZ |
196 | #define NET_VALIDATE(a,t) net_validate_##t((const net_addr_##t *) a) |
197 | ||
9b136840 | 198 | int |
4278abfe | 199 | net_validate(const net_addr *n) |
9b136840 | 200 | { |
4278abfe | 201 | switch (n->type) |
9b136840 | 202 | { |
4278abfe OZ |
203 | case NET_IP4: return NET_VALIDATE(n, ip4); |
204 | case NET_IP6: return NET_VALIDATE(n, ip6); | |
205 | case NET_VPN4: return NET_VALIDATE(n, vpn4); | |
206 | case NET_VPN6: return NET_VALIDATE(n, vpn6); | |
207 | case NET_ROA4: return NET_VALIDATE(n, roa4); | |
208 | case NET_ROA6: return NET_VALIDATE(n, roa6); | |
209 | case NET_FLOW4: return NET_VALIDATE(n, flow4); | |
210 | case NET_FLOW6: return NET_VALIDATE(n, flow6); | |
be17805c | 211 | case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr); |
4278abfe OZ |
212 | case NET_MPLS: return NET_VALIDATE(n, mpls); |
213 | default: return 0; | |
9b136840 | 214 | } |
fe9f1a6d OZ |
215 | } |
216 | ||
aedd3a6b JMM |
217 | void |
218 | net_normalize(net_addr *N) | |
219 | { | |
220 | net_addr_union *n = (void *) N; | |
221 | ||
222 | switch (n->n.type) | |
223 | { | |
224 | case NET_IP4: | |
225 | case NET_VPN4: | |
de9b87f5 | 226 | case NET_ROA4: |
77234bbb | 227 | case NET_FLOW4: |
aedd3a6b JMM |
228 | return net_normalize_ip4(&n->ip4); |
229 | ||
230 | case NET_IP6: | |
231 | case NET_VPN6: | |
de9b87f5 | 232 | case NET_ROA6: |
77234bbb | 233 | case NET_FLOW6: |
aedd3a6b | 234 | return net_normalize_ip6(&n->ip6); |
33ad6e01 | 235 | |
be17805c OZ |
236 | case NET_IP6_SADR: |
237 | return net_normalize_ip6_sadr(&n->ip6_sadr); | |
238 | ||
33ad6e01 JMM |
239 | case NET_MPLS: |
240 | return; | |
aedd3a6b JMM |
241 | } |
242 | } | |
243 | ||
fe9f1a6d OZ |
244 | int |
245 | net_classify(const net_addr *N) | |
246 | { | |
247 | net_addr_union *n = (void *) N; | |
248 | ||
249 | switch (n->n.type) | |
250 | { | |
251 | case NET_IP4: | |
252 | case NET_VPN4: | |
de9b87f5 | 253 | case NET_ROA4: |
77234bbb | 254 | case NET_FLOW4: |
fe9f1a6d OZ |
255 | return ip4_zero(n->ip4.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip4_classify(n->ip4.prefix); |
256 | ||
257 | case NET_IP6: | |
258 | case NET_VPN6: | |
de9b87f5 | 259 | case NET_ROA6: |
77234bbb | 260 | case NET_FLOW6: |
9b136840 | 261 | return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); |
33ad6e01 | 262 | |
be17805c OZ |
263 | case NET_IP6_SADR: |
264 | return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix); | |
265 | ||
d14f8c3c JMM |
266 | case NET_MPLS: |
267 | return IADDR_HOST | SCOPE_UNIVERSE; | |
fe9f1a6d | 268 | } |
9b136840 | 269 | |
0bf95f99 | 270 | return IADDR_INVALID; |
fe9f1a6d | 271 | } |
aedd3a6b JMM |
272 | |
273 | int | |
0bf95f99 | 274 | ipa_in_netX(const ip_addr a, const net_addr *n) |
aedd3a6b | 275 | { |
0bf95f99 | 276 | switch (n->type) |
aedd3a6b JMM |
277 | { |
278 | case NET_IP4: | |
279 | case NET_VPN4: | |
de9b87f5 | 280 | case NET_ROA4: |
77234bbb | 281 | case NET_FLOW4: |
0bf95f99 OZ |
282 | if (!ipa_is_ip4(a)) return 0; |
283 | return ip4_zero(ip4_and(ip4_xor(ipa_to_ip4(a), net4_prefix(n)), | |
284 | ip4_mkmask(net4_pxlen(n)))); | |
aedd3a6b JMM |
285 | |
286 | case NET_IP6: | |
287 | case NET_VPN6: | |
de9b87f5 | 288 | case NET_ROA6: |
77234bbb | 289 | case NET_FLOW6: |
0bf95f99 OZ |
290 | if (ipa_is_ip4(a)) return 0; |
291 | return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)), | |
292 | ip6_mkmask(net6_pxlen(n)))); | |
aedd3a6b | 293 | |
be17805c OZ |
294 | case NET_IP6_SADR: |
295 | if (ipa_is_ip4(a)) return 0; | |
296 | return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)), | |
297 | ip6_mkmask(net6_pxlen(n)))); | |
298 | ||
33ad6e01 | 299 | case NET_MPLS: |
0bf95f99 OZ |
300 | default: |
301 | return 0; | |
302 | } | |
aedd3a6b JMM |
303 | } |
304 | ||
305 | int | |
0bf95f99 | 306 | net_in_netX(const net_addr *a, const net_addr *n) |
aedd3a6b | 307 | { |
0bf95f99 | 308 | if (a->type != n->type) |
aedd3a6b JMM |
309 | return 0; |
310 | ||
0bf95f99 | 311 | return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n); |
aedd3a6b | 312 | } |
67a2eb91 OZ |
313 | |
314 | #define CHECK_NET(T,S) \ | |
315 | ({ if (sizeof(T) != S) die("sizeof %s is %d/%d", #T, (int) sizeof(T), S); }) | |
316 | ||
317 | void | |
318 | net_init(void) | |
319 | { | |
320 | CHECK_NET(net_addr, 24); | |
321 | CHECK_NET(net_addr_ip4, 8); | |
322 | CHECK_NET(net_addr_ip6, 20); | |
323 | CHECK_NET(net_addr_vpn4, 16); | |
324 | CHECK_NET(net_addr_vpn6, 32); | |
325 | CHECK_NET(net_addr_roa4, 16); | |
326 | CHECK_NET(net_addr_roa6, 28); | |
327 | CHECK_NET(net_addr_flow4, 8); | |
328 | CHECK_NET(net_addr_flow6, 20); | |
be17805c | 329 | CHECK_NET(net_addr_ip6_sadr, 40); |
67a2eb91 OZ |
330 | CHECK_NET(net_addr_mpls, 8); |
331 | } |