label.c revision 1.5 1 /* $NetBSD: label.c,v 1.5 2013/07/11 05:45:23 kefren Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren (at) NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <netmpls/mpls.h>
33
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "ldp.h"
39 #include "tlv_stack.h"
40 #include "mpls_routes.h"
41 #include "label.h"
42 #include "ldp_errors.h"
43
44 int min_label = MIN_LABEL, max_label = MAX_LABEL;
45
46 void
47 label_init()
48 {
49 SLIST_INIT(&label_head);
50 }
51
52 /*
53 * if binding == 0 it receives a free one
54 */
55 struct label *
56 label_add(union sockunion * so_dest, union sockunion * so_pref,
57 union sockunion * so_gate, uint32_t binding, struct ldp_peer * p,
58 uint32_t label)
59 {
60 struct label *l;
61 char spreftmp[INET_ADDRSTRLEN];
62
63 l = calloc(1, sizeof(*l));
64
65 if (!l) {
66 fatalp("label_add: malloc problem\n");
67 return NULL;
68 }
69
70 assert(so_dest);
71 assert(so_pref);
72 assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
73
74 memcpy(&l->so_dest, so_dest, sizeof(union sockunion));
75 memcpy(&l->so_pref, so_pref, sizeof(union sockunion));
76
77 if (so_gate)
78 memcpy(&l->so_gate, so_gate, sizeof(union sockunion));
79 if (binding)
80 l->binding = binding;
81 else
82 l->binding = get_free_local_label();
83 l->p = p;
84 l->label = label;
85
86 SLIST_INSERT_HEAD(&label_head, l, labels);
87
88 strlcpy(spreftmp, union_ntoa(so_pref), INET_ADDRSTRLEN);
89 warnp("[label_add] added binding %d for %s/%s\n", l->binding,
90 union_ntoa(so_dest), spreftmp);
91
92 send_label_tlv_to_all(&(so_dest->sa),
93 from_union_to_cidr(so_pref), l->binding);
94 return l;
95 }
96
97 /* Unlink a label */
98 void
99 label_del(struct label * l)
100 {
101 warnp("[label_del] deleted binding %d for %s\n", l->binding,
102 union_ntoa(&l->so_dest));
103 SLIST_REMOVE(&label_head, l, label, labels);
104 free(l);
105 }
106
107 /*
108 * Delete or Reuse the old IPv4 route, delete MPLS route (if any)
109 */
110 void
111 label_reattach_route(struct label *l, int readd)
112 {
113 union sockunion *u;
114 union sockunion emptysu;
115 struct rt_msg rg;
116 int oldbinding = l->binding;
117
118 warnp("[label_reattach_route] binding %d deleted\n",
119 l->binding);
120
121 l->p = NULL;
122 l->binding = MPLS_LABEL_IMPLNULL;
123
124 /* No gateway ? */
125 memset(&emptysu, 0, sizeof (union sockunion));
126 if (memcmp(&l->so_gate, &emptysu, sizeof(union sockunion)) == 0)
127 return;
128
129 if (l->label != MPLS_LABEL_IMPLNULL && readd == LDP_READD_CHANGE) {
130 /* Delete and re-add IPv4 route */
131 if (get_route(&rg, &l->so_dest, &l->so_pref, 1) == LDP_E_OK) {
132 delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
133 add_route(&l->so_dest, &l->so_pref, &l->so_gate, NULL, NULL,
134 NO_FREESO, RTM_READD);
135 } else if (from_union_to_cidr(&l->so_pref) == 32 &&
136 l->so_dest.sa.sa_family == AF_INET &&
137 get_route(&rg, &l->so_dest, NULL, 1) == LDP_E_OK) {
138 delete_route(&l->so_dest, NULL, NO_FREESO);
139 add_route(&l->so_dest, NULL, &l->so_gate, NULL, NULL,
140 NO_FREESO, RTM_READD);
141 } else
142 add_route(&l->so_dest, &l->so_pref,
143 &l->so_gate, NULL, NULL, NO_FREESO, RTM_READD);
144 } else
145 if (readd != LDP_READD_NODEL)
146 delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
147
148 l->label = 0;
149
150 /* Deletes pure MPLS route */
151 if (oldbinding >= min_label) {
152 u = make_mpls_union(oldbinding);
153 delete_route(u, NULL, FREESO);
154 }
155 }
156 /*
157 * Get a label by dst and pref
158 */
159 struct label*
160 label_get(union sockunion *sodest, union sockunion *sopref)
161 {
162 struct label *l;
163
164 SLIST_FOREACH (l, &label_head, labels)
165 if (sodest->sin.sin_addr.s_addr ==
166 l->so_dest.sin.sin_addr.s_addr &&
167 sopref->sin.sin_addr.s_addr ==
168 l->so_pref.sin.sin_addr.s_addr)
169 return l;
170 return NULL;
171 }
172
173 /*
174 * Find all labels that points to a peer
175 * and reattach them to IPv4
176 */
177 void
178 label_reattach_all_peer_labels(const struct ldp_peer *p, int readd)
179 {
180 struct label *l;
181
182 SLIST_FOREACH(l, &label_head, labels)
183 if (l->p == p)
184 label_reattach_route(l, readd);
185 }
186
187 /*
188 * Find all labels that points to a peer
189 * and delete them
190 */
191 void
192 del_all_peer_labels(struct ldp_peer * p, int readd)
193 {
194 struct label *l, *lnext;
195
196 SLIST_FOREACH_SAFE(l, &label_head, labels, lnext) {
197 if(l->p != p)
198 continue;
199 label_reattach_route(l, readd);
200 label_del(l);
201 SLIST_REMOVE(&label_head, l, label, labels);
202 }
203 }
204
205 /*
206 * Finds a label by its binding and deletes it
207 */
208 void
209 label_del_by_binding(uint32_t binding, int readd)
210 {
211 struct label *l;
212
213 SLIST_FOREACH(l, &label_head, labels)
214 if ((uint32_t)l->binding == binding) {
215 label_reattach_route(l, readd);
216 label_del(l);
217 SLIST_REMOVE(&label_head, l, label, labels);
218 break;
219 }
220 }
221
222 /*
223 * For Compatibility with old bindinds code
224 */
225 struct label*
226 label_get_by_prefix(const struct sockaddr *a, int prefixlen)
227 {
228 union sockunion *so_dest, *so_pref;
229 struct label *l;
230
231 so_dest = make_inet_union(satos(a)); // XXX: grobian
232 so_pref = from_cidr_to_union(prefixlen);
233
234 l = label_get(so_dest, so_pref);
235
236 free(so_dest);
237 free(so_pref);
238
239 return l;
240 }
241
242 /*
243 * Get a free binding
244 */
245 uint32_t
246 get_free_local_label()
247 {
248 struct label *l;
249 int lbl;
250
251 for (lbl = min_label; lbl <= max_label; lbl++) {
252 SLIST_FOREACH(l, &label_head, labels)
253 if (l->binding == lbl)
254 break;
255 if (l == NULL)
256 return lbl;
257 }
258 return 0;
259 }
260
261 /*
262 * Change local binding
263 */
264 void
265 change_local_label(struct label *l, uint32_t newbind)
266 {
267 send_withdraw_tlv_to_all(&(l->so_dest.sa),
268 from_union_to_cidr(&(l->so_pref)));
269 l->binding = newbind;
270 send_label_tlv_to_all(&(l->so_dest.sa),
271 from_union_to_cidr(&(l->so_pref)),
272 l->binding);
273 }
274