xref: /netbsd-src/usr.sbin/ldpd/label.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /* $NetBSD: label.c,v 1.3 2010/12/30 11:29:21 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@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->sin.sin_addr),
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(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(struct in_addr *a, int prefixlen)
227 {
228 	union sockunion *so_dest, *so_pref;
229 	struct label *l;
230 
231 	so_dest = make_inet_union(inet_ntoa(*a));
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.sin.sin_addr),
268 		from_union_to_cidr(&(l->so_pref)));
269 	l->binding = newbind;
270 	send_label_tlv_to_all(&(l->so_dest.sin.sin_addr),
271 		from_union_to_cidr(&(l->so_pref)),
272 		l->binding);
273 }
274