Merge branch 'vendor/FILE'
[dragonfly.git] / sys / netproto / mpls / mpls_output.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  * 3. Neither the name of The DragonFly Project nor the names of its
15  *    contributors may be used to endorse or promote products derived
16  *    from this software without specific, prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/param.h>
33 #include <sys/mbuf.h>
34 #include <sys/systm.h>
35
36 #include <net/if_var.h>
37
38 #include <netinet/ip.h>
39
40 #include <netproto/mpls/mpls.h>
41 #include <netproto/mpls/mpls_var.h>
42
43 static int mpls_push(struct mbuf **, mpls_label_t,
44                      mpls_s_t, mpls_exp_t, mpls_ttl_t);
45 static int mpls_swap(struct mbuf *, mpls_label_t);
46 static int mpls_pop(struct mbuf *, mpls_s_t *);
47
48 int
49 mpls_output(struct mbuf *m, struct rtentry *rt)
50 {
51         struct sockaddr_mpls *smpls = NULL;
52         int error = 0, i;
53         mpls_s_t stackempty;
54         mpls_ttl_t ttl = 255;
55         struct ip *ip;
56
57         M_ASSERTPKTHDR(m);
58
59         /*
60          * Check if we are coming from an MPLS routing table lookup.
61          * The rt_key of this rtentry will have a family AF_MPLS if so.
62          */
63         stackempty = rt_key(rt)->sa_family != AF_MPLS ? 1 : 0;
64         if (stackempty) {
65                 switch (rt_key(rt)->sa_family) {
66                 case AF_INET:
67                         ip = mtod(m, struct ip *);
68                         ttl = ip->ip_ttl;
69                         break;
70                 }
71         }
72
73         for (i=0; i < MPLS_MAXLOPS && rt->rt_shim[i] != NULL; ++i) {
74                 smpls = (struct sockaddr_mpls *)rt->rt_shim[i];
75                 switch (smpls->smpls_op) {
76                 case MPLSLOP_PUSH:
77                         error = mpls_push(&m,
78                                   ntohl(smpls->smpls_label),
79                                   /*
80                                    * If we are the first label push, then
81                                    * set the bottom-of-stack bit.
82                                    */
83                                   (stackempty && i == 0) ? 1 : 0,
84                                   0,
85                                   ttl);
86                         if (error)
87                                 return (error);
88                         stackempty = 0;
89                         m->m_flags |= M_MPLSLABELED;
90                         break;
91                 case MPLSLOP_SWAP:
92                         /*
93                          * Operation is only permmited if label stack
94                          * is not empty.
95                          */
96                         if (stackempty)
97                                 return (ENOTSUP);
98                         KKASSERT(m->m_flags & M_MPLSLABELED);
99                         error = mpls_swap(m, ntohl(smpls->smpls_label));
100                         if (error)
101                                 return (error);
102                         break;
103                 case MPLSLOP_POP:
104                         /*
105                          * Operation is only permmited if label stack
106                          * is not empty.
107                          */
108                         if (stackempty)
109                                 return (ENOTSUP);
110                         KKASSERT(m->m_flags & M_MPLSLABELED);
111                         error = mpls_pop(m, &stackempty);
112                         if (error)
113                                 return (error);
114                         /*
115                          * If we are popping out the last label then
116                          * mark the mbuf as ~M_MPLSLABELED.
117                          */
118                         if (stackempty)
119                                 m->m_flags &= ~M_MPLSLABELED;
120                         break;
121                 default:
122                         /* Unknown label operation */
123                         return (ENOTSUP);
124                 }
125         }
126         
127         return (error);
128 }
129
130 /*
131  * Returns FALSE if no further output processing required.
132  */
133 boolean_t
134 mpls_output_process(struct mbuf *m, struct rtentry *rt)
135 {
136         int error;
137
138         /* Does this route have MPLS label operations? */
139         if (!(rt->rt_flags & RTF_MPLSOPS))
140                 return TRUE;
141
142         error = mpls_output(m, rt);
143         if (error) {
144                 m_freem(m);
145                 return FALSE;
146         }
147
148         return TRUE;
149 }
150
151 static int
152 mpls_push(struct mbuf **m, mpls_label_t label, mpls_s_t s, mpls_exp_t exp, mpls_ttl_t ttl) {
153         struct mpls *mpls;
154         u_int32_t buf = 0;      /* Silence warning */
155
156         M_PREPEND(*m, sizeof(struct mpls), M_NOWAIT);
157         if (*m == NULL)
158                 return (ENOBUFS);
159
160         MPLS_SET_LABEL(buf, label);
161         MPLS_SET_STACK(buf, s);
162         MPLS_SET_EXP(buf, exp);
163         MPLS_SET_TTL(buf, ttl);
164         mpls = mtod(*m, struct mpls *);
165         mpls->mpls_shim = htonl(buf);
166         
167         return (0);
168 }
169
170 static int
171 mpls_swap(struct mbuf *m, mpls_label_t label) {
172         struct mpls *mpls;
173         u_int32_t buf;
174         mpls_ttl_t ttl;
175
176         if (m->m_len < sizeof(struct mpls) &&
177            (m = m_pullup(m, sizeof(struct mpls))) == NULL)
178                 return (ENOBUFS);
179
180         mpls = mtod(m, struct mpls *);
181         buf = ntohl(mpls->mpls_shim);
182         ttl = MPLS_TTL(buf);
183         if (--ttl <= 0) {
184                 /* XXX: should send icmp ttl expired. */
185                 mplsstat.mplss_ttlexpired++;
186                 return (ETIMEDOUT);
187         }
188         MPLS_SET_LABEL(buf, label);
189         MPLS_SET_TTL(buf, ttl); /* XXX tunnel mode: uniform, pipe, short pipe */
190         mpls->mpls_shim = htonl(buf);
191         
192         return (0);
193 }
194
195 static int
196 mpls_pop(struct mbuf *m, mpls_s_t *sbit) {
197         struct mpls *mpls;
198         u_int32_t buf;
199
200         if (m->m_len < sizeof(struct mpls)) {
201                 m = m_pullup(m, sizeof(struct mpls));
202                 if (m == NULL)
203                         return (ENOBUFS);
204         }
205         mpls = mtod(m, struct mpls *);
206         buf = ntohl(mpls->mpls_shim);
207         *sbit = MPLS_STACK(buf);
208
209         m_adj(m, sizeof(struct mpls));
210
211         return (0);
212 }