2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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
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.
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
32 #include <sys/param.h>
33 #include <sys/malloc.h> /* for M_NOWAIT */
35 #include <sys/systm.h>
37 #include <net/if_var.h>
39 #include <netinet/ip.h>
41 #include <netproto/mpls/mpls.h>
42 #include <netproto/mpls/mpls_var.h>
44 static int mpls_push(struct mbuf
**, mpls_label_t
,
45 mpls_s_t
, mpls_exp_t
, mpls_ttl_t
);
46 static int mpls_swap(struct mbuf
*, mpls_label_t
);
47 static int mpls_pop(struct mbuf
*, mpls_s_t
*);
50 mpls_output(struct mbuf
*m
, struct rtentry
*rt
)
52 struct sockaddr_mpls
*smpls
= NULL
;
61 * Check if we are coming from an MPLS routing table lookup.
62 * The rt_key of this rtentry will have a family AF_MPLS if so.
64 stackempty
= rt_key(rt
)->sa_family
!= AF_MPLS
? 1 : 0;
66 switch (rt_key(rt
)->sa_family
) {
68 ip
= mtod(m
, struct ip
*);
74 for (i
=0; i
< MPLS_MAXLOPS
&& rt
->rt_shim
[i
] != NULL
; ++i
) {
75 smpls
= (struct sockaddr_mpls
*)rt
->rt_shim
[i
];
76 switch (smpls
->smpls_op
) {
79 ntohl(smpls
->smpls_label
),
81 * If we are the first label push, then
82 * set the bottom-of-stack bit.
84 (stackempty
&& i
== 0) ? 1 : 0,
90 m
->m_flags
|= M_MPLSLABELED
;
94 * Operation is only permmited if label stack
99 KKASSERT(m
->m_flags
& M_MPLSLABELED
);
100 error
= mpls_swap(m
, ntohl(smpls
->smpls_label
));
106 * Operation is only permmited if label stack
111 KKASSERT(m
->m_flags
& M_MPLSLABELED
);
112 error
= mpls_pop(m
, &stackempty
);
116 * If we are popping out the last label then
117 * mark the mbuf as ~M_MPLSLABELED.
120 m
->m_flags
&= ~M_MPLSLABELED
;
123 /* Unknown label operation */
132 * Returns FALSE if no further output processing required.
135 mpls_output_process(struct mbuf
*m
, struct rtentry
*rt
)
139 /* Does this route have MPLS label operations? */
140 if (!(rt
->rt_flags
& RTF_MPLSOPS
))
143 error
= mpls_output(m
, rt
);
153 mpls_push(struct mbuf
**m
, mpls_label_t label
, mpls_s_t s
, mpls_exp_t exp
, mpls_ttl_t ttl
) {
155 u_int32_t buf
= 0; /* Silence warning */
157 M_PREPEND(*m
, sizeof(struct mpls
), M_NOWAIT
);
161 MPLS_SET_LABEL(buf
, label
);
162 MPLS_SET_STACK(buf
, s
);
163 MPLS_SET_EXP(buf
, exp
);
164 MPLS_SET_TTL(buf
, ttl
);
165 mpls
= mtod(*m
, struct mpls
*);
166 mpls
->mpls_shim
= htonl(buf
);
172 mpls_swap(struct mbuf
*m
, mpls_label_t label
) {
177 if (m
->m_len
< sizeof(struct mpls
) &&
178 (m
= m_pullup(m
, sizeof(struct mpls
))) == NULL
)
181 mpls
= mtod(m
, struct mpls
*);
182 buf
= ntohl(mpls
->mpls_shim
);
185 /* XXX: should send icmp ttl expired. */
186 mplsstat
.mplss_ttlexpired
++;
189 MPLS_SET_LABEL(buf
, label
);
190 MPLS_SET_TTL(buf
, ttl
); /* XXX tunnel mode: uniform, pipe, short pipe */
191 mpls
->mpls_shim
= htonl(buf
);
197 mpls_pop(struct mbuf
*m
, mpls_s_t
*sbit
) {
201 if (m
->m_len
< sizeof(struct mpls
)) {
202 m
= m_pullup(m
, sizeof(struct mpls
));
206 mpls
= mtod(m
, struct mpls
*);
207 buf
= ntohl(mpls
->mpls_shim
);
208 *sbit
= MPLS_STACK(buf
);
210 m_adj(m
, sizeof(struct mpls
));