xref: /netbsd-src/usr.sbin/ldpd/label.c (revision 4817a0b0b8fe9612e8ebe21a9bf2d97b95038a97)
1 /* $NetBSD: label.c,v 1.2 2010/12/09 00:10:59 christos 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@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 void
45 label_init()
46 {
47 	SLIST_INIT(&label_head);
48 }
49 
50 /*
51  * if binding == 0 it receives a free one
52  */
53 struct label   *
54 label_add(union sockunion * so_dest, union sockunion * so_pref,
55 	  union sockunion * so_gate, uint32_t binding, struct ldp_peer * p,
56 	  uint32_t label)
57 {
58 	struct label   *l;
59 	char	spreftmp[INET_ADDRSTRLEN];
60 
61 	l = calloc(1, sizeof(*l));
62 
63 	if (!l) {
64 		fatalp("label_add: malloc problem\n");
65 		return NULL;
66 	}
67 
68 	assert(so_dest);
69 	assert(so_pref);
70 	assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
71 
72 	memcpy(&l->so_dest, so_dest, sizeof(union sockunion));
73 	memcpy(&l->so_pref, so_pref, sizeof(union sockunion));
74 
75 	if (so_gate)
76 		memcpy(&l->so_gate, so_gate, sizeof(union sockunion));
77 	if (binding)
78 		l->binding = binding;
79 	else
80 		l->binding = get_free_local_label();
81 	l->p = p;
82 	l->label = label;
83 
84 	SLIST_INSERT_HEAD(&label_head, l, labels);
85 
86 	strlcpy(spreftmp, union_ntoa(so_pref), INET_ADDRSTRLEN);
87 	warnp("[label_add] added binding %d for %s/%s\n", l->binding,
88 	    union_ntoa(so_dest), spreftmp);
89 
90 	send_label_tlv_to_all(&(so_dest->sin.sin_addr),
91 	    from_union_to_cidr(so_pref), l->binding);
92 	return l;
93 }
94 
95 /* Unlink a label */
96 void
97 label_del(struct label * l)
98 {
99 	warnp("[label_del] deleted binding %d for %s\n", l->binding,
100 	   union_ntoa(&l->so_dest));
101 	SLIST_REMOVE(&label_head, l, label, labels);
102 	free(l);
103 }
104 
105 /*
106  * Delete or Reuse the old IPv4 route, delete MPLS route (if any)
107  */
108 void
109 label_reattach_route(struct label *l, int readd)
110 {
111 	union sockunion *u;
112 	union sockunion emptysu;
113 	struct rt_msg rg;
114 	int oldbinding = l->binding;
115 
116 	warnp("[label_reattach_route] binding %d deleted\n",
117 		l->binding);
118 
119 	l->p = NULL;
120 	l->binding = MPLS_LABEL_IMPLNULL;
121 
122 	/* No gateway ? */
123 	memset(&emptysu, 0, sizeof (union sockunion));
124 	if (memcmp(&l->so_gate, &emptysu, sizeof(union sockunion)) == 0)
125 		return;
126 
127 	if (l->label != MPLS_LABEL_IMPLNULL && readd == LDP_READD_CHANGE) {
128 	/* Delete and re-add IPv4 route */
129 		if (get_route(&rg, &l->so_dest, &l->so_pref, 1) == LDP_E_OK) {
130 			delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
131 			add_route(&l->so_dest, &l->so_pref, &l->so_gate, NULL, NULL,
132 			    NO_FREESO, RTM_READD);
133 		} else if (from_union_to_cidr(&l->so_pref) == 32 &&
134 		    l->so_dest.sa.sa_family == AF_INET &&
135 		    get_route(&rg, &l->so_dest, NULL, 1) == LDP_E_OK) {
136 			delete_route(&l->so_dest, NULL, NO_FREESO);
137 			add_route(&l->so_dest, NULL, &l->so_gate, NULL, NULL,
138 			    NO_FREESO, RTM_READD);
139 		} else
140 			add_route(&l->so_dest, &l->so_pref,
141 			    &l->so_gate, NULL, NULL, NO_FREESO, RTM_READD);
142 	} else
143 		if (readd != LDP_READD_NODEL)
144 			delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
145 
146 	l->label = 0;
147 
148 	/* Deletes pure MPLS route */
149 	if (oldbinding >= MIN_LABEL) {
150 		u = make_mpls_union(oldbinding);
151 		delete_route(u, NULL, FREESO);
152 	}
153 }
154 /*
155  * Get a label by dst and pref
156  */
157 struct label*
158 label_get(union sockunion *sodest, union sockunion *sopref)
159 {
160 	struct label *l;
161 
162 	SLIST_FOREACH (l, &label_head, labels)
163 	    if (sodest->sin.sin_addr.s_addr ==
164 		    l->so_dest.sin.sin_addr.s_addr &&
165 		sopref->sin.sin_addr.s_addr ==
166 		    l->so_pref.sin.sin_addr.s_addr)
167 			return l;
168 	return NULL;
169 }
170 
171 /*
172  * Find all labels that points to a peer
173  * and reattach them to IPv4
174  */
175 void
176 label_reattach_all_peer_labels(struct ldp_peer *p, int readd)
177 {
178 	struct label   *l;
179 
180 	SLIST_FOREACH(l, &label_head, labels)
181 		if (l->p == p)
182 			label_reattach_route(l, readd);
183 }
184 
185 /*
186  * Find all labels that points to a peer
187  * and delete them
188  */
189 void
190 del_all_peer_labels(struct ldp_peer * p, int readd)
191 {
192 	struct label   *l;
193 	int		do_remove = 1;
194 
195 	while(do_remove == 1) {
196 		do_remove = 0;
197 		SLIST_FOREACH(l, &label_head, labels) {
198 			if(l->p != p)
199 				continue;
200 			label_reattach_route(l, readd);
201 			label_del(l);
202 			/* remove must not interact with foreach */
203 			SLIST_REMOVE(&label_head, l, label, labels);
204 			do_remove = 1;
205 			break;		/* XXX: suboptimal */
206 		}
207 	} // while
208 }
209 
210 /*
211  * Finds a label by its binding and deletes it
212  */
213 void
214 label_del_by_binding(uint32_t binding, int readd)
215 {
216 	struct label   *l;
217 
218 	SLIST_FOREACH(l, &label_head, labels)
219 		if ((uint32_t)l->binding == binding) {
220 			label_reattach_route(l, readd);
221 			label_del(l);
222 			SLIST_REMOVE(&label_head, l, label, labels);
223 			break;
224 		}
225 }
226 
227 /*
228  * For Compatibility with old bindinds code
229  */
230 struct label*
231 label_get_by_prefix(struct in_addr *a, int prefixlen)
232 {
233 	union sockunion *so_dest, *so_pref;
234 	struct label *l;
235 
236 	so_dest = make_inet_union(inet_ntoa(*a));
237 	so_pref = from_cidr_to_union(prefixlen);
238 
239 	l = label_get(so_dest, so_pref);
240 
241 	free(so_dest);
242 	free(so_pref);
243 
244 	return l;
245 }
246 
247 /*
248  * Get a free binding
249  */
250 uint32_t
251 get_free_local_label()
252 {
253 	struct label *l;
254 	uint32_t lbl;
255 
256 	for (lbl = MIN_LABEL; lbl <= MAX_LABEL; lbl++) {
257 		SLIST_FOREACH(l, &label_head, labels)
258 			if ((uint32_t)l->binding == lbl)
259 				break;
260 		if (l == NULL)
261 			return lbl;
262 	}
263 	return 0;
264 }
265 
266 /*
267  * Change local binding
268  */
269 void
270 change_local_label(struct label *l, uint32_t newbind)
271 {
272 	send_withdraw_tlv_to_all(&(l->so_dest.sin.sin_addr),
273 		from_union_to_cidr(&(l->so_pref)));
274 	l->binding = newbind;
275 	send_label_tlv_to_all(&(l->so_dest.sin.sin_addr),
276 		from_union_to_cidr(&(l->so_pref)),
277 		l->binding);
278 }
279