Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* BGP RD definitions for BGP-based VPNs (IP/EVPN) |
3 | | * -- brought over from bgpd/bgp_mplsvpn.c |
4 | | * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | #include "command.h" |
9 | | #include "log.h" |
10 | | #include "prefix.h" |
11 | | #include "memory.h" |
12 | | #include "stream.h" |
13 | | #include "filter.h" |
14 | | #include "frrstr.h" |
15 | | |
16 | | #include "lib/printfrr.h" |
17 | | |
18 | | #include "bgpd/bgpd.h" |
19 | | #include "bgpd/bgp_rd.h" |
20 | | #include "bgpd/bgp_attr.h" |
21 | | |
22 | | #ifdef ENABLE_BGP_VNC |
23 | | #include "bgpd/rfapi/rfapi_backend.h" |
24 | | #endif |
25 | | |
26 | | uint16_t decode_rd_type(const uint8_t *pnt) |
27 | 176 | { |
28 | 176 | uint16_t v; |
29 | | |
30 | 176 | v = ((uint16_t)*pnt++ << 8); |
31 | 176 | #ifdef ENABLE_BGP_VNC |
32 | | /* |
33 | | * VNC L2 stores LHI in lower byte, so omit it |
34 | | */ |
35 | 176 | if (v != RD_TYPE_VNC_ETH) |
36 | 145 | v |= (uint16_t)*pnt; |
37 | | #else /* duplicate code for clarity */ |
38 | | v |= (uint16_t)*pnt; |
39 | | #endif |
40 | 176 | return v; |
41 | 176 | } |
42 | | |
43 | | void encode_rd_type(uint16_t v, uint8_t *pnt) |
44 | 0 | { |
45 | 0 | *((uint16_t *)pnt) = htons(v); |
46 | 0 | } |
47 | | |
48 | | /* type == RD_TYPE_AS */ |
49 | | void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as) |
50 | 15 | { |
51 | 15 | rd_as->as = (uint16_t)*pnt++ << 8; |
52 | 15 | rd_as->as |= (uint16_t)*pnt++; |
53 | 15 | ptr_get_be32(pnt, &rd_as->val); |
54 | 15 | } |
55 | | |
56 | | /* type == RD_TYPE_AS4 */ |
57 | | void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as) |
58 | 65 | { |
59 | 65 | pnt = ptr_get_be32(pnt, &rd_as->as); |
60 | 65 | rd_as->val = ((uint16_t)*pnt++ << 8); |
61 | 65 | rd_as->val |= (uint16_t)*pnt; |
62 | 65 | } |
63 | | |
64 | | /* type == RD_TYPE_IP */ |
65 | | void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip) |
66 | 6 | { |
67 | 6 | memcpy(&rd_ip->ip, pnt, 4); |
68 | 6 | pnt += 4; |
69 | | |
70 | 6 | rd_ip->val = ((uint16_t)*pnt++ << 8); |
71 | 6 | rd_ip->val |= (uint16_t)*pnt; |
72 | 6 | } |
73 | | |
74 | | #ifdef ENABLE_BGP_VNC |
75 | | /* type == RD_TYPE_VNC_ETH */ |
76 | | void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth) |
77 | 0 | { |
78 | 0 | rd_vnc_eth->type = RD_TYPE_VNC_ETH; |
79 | 0 | rd_vnc_eth->local_nve_id = pnt[1]; |
80 | 0 | memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETH_ALEN); |
81 | 0 | } |
82 | | #endif |
83 | | |
84 | | int str2prefix_rd(const char *str, struct prefix_rd *prd) |
85 | 0 | { |
86 | 0 | int ret = 0, type = RD_TYPE_UNDEFINED; |
87 | 0 | char *p, *p2; |
88 | 0 | struct stream *s = NULL; |
89 | 0 | char *half = NULL; |
90 | 0 | struct in_addr addr; |
91 | 0 | as_t as_val; |
92 | |
|
93 | 0 | prd->family = AF_UNSPEC; |
94 | 0 | prd->prefixlen = 64; |
95 | |
|
96 | 0 | p = strchr(str, ':'); |
97 | 0 | if (!p) |
98 | 0 | goto out; |
99 | | |
100 | | /* a second ':' is accepted */ |
101 | 0 | p2 = strchr(p + 1, ':'); |
102 | 0 | if (p2) { |
103 | | /* type is in first part */ |
104 | 0 | half = XMALLOC(MTYPE_TMP, (p - str) + 1); |
105 | 0 | memcpy(half, str, (p - str)); |
106 | 0 | half[p - str] = '\0'; |
107 | 0 | type = atoi(half); |
108 | 0 | if (type != RD_TYPE_AS && type != RD_TYPE_IP && |
109 | 0 | type != RD_TYPE_AS4) |
110 | 0 | goto out; |
111 | 0 | XFREE(MTYPE_TMP, half); |
112 | 0 | half = XMALLOC(MTYPE_TMP, (p2 - p)); |
113 | 0 | memcpy(half, p + 1, (p2 - p - 1)); |
114 | 0 | half[p2 - p - 1] = '\0'; |
115 | 0 | p = p2 + 1; |
116 | 0 | } else { |
117 | 0 | half = XMALLOC(MTYPE_TMP, (p - str) + 1); |
118 | 0 | memcpy(half, str, (p - str)); |
119 | 0 | half[p - str] = '\0'; |
120 | 0 | } |
121 | 0 | if (!all_digit(p + 1)) |
122 | 0 | goto out; |
123 | | |
124 | 0 | s = stream_new(RD_BYTES); |
125 | | |
126 | | /* if it is an AS format or an IP */ |
127 | 0 | if (asn_str2asn(half, &as_val)) { |
128 | 0 | if (as_val > UINT16_MAX) { |
129 | 0 | stream_putw(s, RD_TYPE_AS4); |
130 | 0 | stream_putl(s, as_val); |
131 | 0 | stream_putw(s, atol(p + 1)); |
132 | 0 | if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS4) |
133 | 0 | goto out; |
134 | 0 | } else { |
135 | 0 | stream_putw(s, RD_TYPE_AS); |
136 | 0 | stream_putw(s, as_val); |
137 | 0 | stream_putl(s, atol(p + 1)); |
138 | 0 | if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS) |
139 | 0 | goto out; |
140 | 0 | } |
141 | 0 | } else if (inet_aton(half, &addr)) { |
142 | 0 | stream_putw(s, RD_TYPE_IP); |
143 | 0 | stream_put_in_addr(s, &addr); |
144 | 0 | stream_putw(s, atol(p + 1)); |
145 | 0 | if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_IP) |
146 | 0 | goto out; |
147 | 0 | } else |
148 | 0 | goto out; |
149 | 0 | memcpy(prd->val, s->data, 8); |
150 | 0 | ret = 1; |
151 | |
|
152 | 0 | out: |
153 | 0 | if (s) |
154 | 0 | stream_free(s); |
155 | 0 | XFREE(MTYPE_TMP, half); |
156 | 0 | return ret; |
157 | 0 | } |
158 | | |
159 | | char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size, |
160 | | enum asnotation_mode asnotation) |
161 | 0 | { |
162 | 0 | const uint8_t *pnt; |
163 | 0 | uint16_t type; |
164 | 0 | struct rd_as rd_as; |
165 | 0 | struct rd_ip rd_ip; |
166 | 0 | int len = 0; |
167 | |
|
168 | 0 | assert(size >= RD_ADDRSTRLEN); |
169 | | |
170 | 0 | pnt = prd->val; |
171 | |
|
172 | 0 | type = decode_rd_type(pnt); |
173 | |
|
174 | 0 | if (type == RD_TYPE_AS) { |
175 | 0 | decode_rd_as(pnt + 2, &rd_as); |
176 | 0 | len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation), |
177 | 0 | &rd_as.as); |
178 | 0 | snprintfrr(buf + len, size - len, ":%u", rd_as.val); |
179 | 0 | return buf; |
180 | 0 | } else if (type == RD_TYPE_AS4) { |
181 | 0 | decode_rd_as4(pnt + 2, &rd_as); |
182 | 0 | len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation), |
183 | 0 | &rd_as.as); |
184 | 0 | snprintfrr(buf + len, size - len, ":%u", rd_as.val); |
185 | 0 | return buf; |
186 | 0 | } else if (type == RD_TYPE_IP) { |
187 | 0 | decode_rd_ip(pnt + 2, &rd_ip); |
188 | 0 | snprintfrr(buf, size, "%pI4:%hu", &rd_ip.ip, rd_ip.val); |
189 | 0 | return buf; |
190 | 0 | } |
191 | 0 | #ifdef ENABLE_BGP_VNC |
192 | 0 | else if (type == RD_TYPE_VNC_ETH) { |
193 | 0 | snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", |
194 | 0 | *(pnt + 1), /* LHI */ |
195 | 0 | *(pnt + 2), /* MAC[0] */ |
196 | 0 | *(pnt + 3), *(pnt + 4), *(pnt + 5), *(pnt + 6), |
197 | 0 | *(pnt + 7)); |
198 | |
|
199 | 0 | return buf; |
200 | 0 | } |
201 | 0 | #endif |
202 | | |
203 | 0 | snprintf(buf, size, "Unknown Type: %d", type); |
204 | 0 | return buf; |
205 | 0 | } |
206 | | |
207 | | void form_auto_rd(struct in_addr router_id, |
208 | | uint16_t rd_id, |
209 | | struct prefix_rd *prd) |
210 | 0 | { |
211 | 0 | char buf[100]; |
212 | |
|
213 | 0 | prd->family = AF_UNSPEC; |
214 | 0 | prd->prefixlen = 64; |
215 | 0 | snprintfrr(buf, sizeof(buf), "%pI4:%hu", &router_id, rd_id); |
216 | 0 | (void)str2prefix_rd(buf, prd); |
217 | 0 | } |
218 | | |
219 | | static ssize_t printfrr_prd_asnotation(struct fbuf *buf, |
220 | | struct printfrr_eargs *ea, |
221 | | const void *ptr, |
222 | | enum asnotation_mode asnotation) |
223 | 0 | { |
224 | 0 | char rd_buf[RD_ADDRSTRLEN]; |
225 | |
|
226 | 0 | if (!ptr) |
227 | 0 | return bputs(buf, "(null)"); |
228 | | |
229 | 0 | prefix_rd2str(ptr, rd_buf, sizeof(rd_buf), asnotation); |
230 | |
|
231 | 0 | return bputs(buf, rd_buf); |
232 | 0 | } |
233 | | |
234 | | printfrr_ext_autoreg_p("RDP", printfrr_prd); |
235 | | static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea, |
236 | | const void *ptr) |
237 | 0 | { |
238 | 0 | return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_PLAIN); |
239 | 0 | } |
240 | | |
241 | | printfrr_ext_autoreg_p("RDD", printfrr_prd_dot); |
242 | | static ssize_t printfrr_prd_dot(struct fbuf *buf, struct printfrr_eargs *ea, |
243 | | const void *ptr) |
244 | 0 | { |
245 | 0 | return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOT); |
246 | 0 | } |
247 | | |
248 | | printfrr_ext_autoreg_p("RDE", printfrr_prd_dotplus); |
249 | | static ssize_t printfrr_prd_dotplus(struct fbuf *buf, struct printfrr_eargs *ea, |
250 | | const void *ptr) |
251 | 0 | { |
252 | 0 | return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS); |
253 | 0 | } |