Add NETISR_FLAG_NOTMPSAFE, which could be used as the last parameter to
[dragonfly.git] / sys / netproto / mpls / mpls_input.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  * $DragonFly: src/sys/netproto/mpls/mpls_input.c,v 1.4 2008/09/24 14:26:39 sephe Exp $
32  */
33
34 #include <sys/globaldata.h>
35 #include <sys/kernel.h>
36 #include <sys/mbuf.h>
37 #include <sys/param.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40
41 #include <net/if_var.h>
42 #include <net/netisr.h>
43 #include <net/route.h>
44
45 #include <netproto/mpls/mpls.h>
46 #include <netproto/mpls/mpls_var.h>
47
48 struct mpls_stats       mplsstats_percpu[MAXCPU];
49 struct route            mplsforward_rt[MAXCPU];
50
51 int mplsforwarding = 1;
52 /*
53 SYSCTL_INT(_net_mpls, OID_AUTO, forwarding, CTLFLAG_RW,
54     &mplsforwarding, 0, "Enable MPLS forwarding between interfaces");
55 */
56
57 static void     mpls_input_handler(struct netmsg *);
58 static void     mpls_forward(struct mbuf *);
59
60 void
61 mpls_init(void)
62 {
63 #ifdef SMP
64         int cpu;
65 #endif
66
67         /*
68          * Initialize MPLS statistics counters for each CPU.
69          *
70          */
71 #ifdef SMP
72         for (cpu = 0; cpu < ncpus; ++cpu) {
73                 bzero(&mplsstats_percpu[cpu], sizeof(struct mpls_stats));
74         }
75 #else
76         bzero(&mplsstat, sizeof(struct mpls_stats));
77 #endif
78
79         netisr_register(NETISR_MPLS, mpls_mport, mpls_input_handler,
80                         NETISR_FLAG_NOTMPSAFE);
81 }
82
83 static void
84 mpls_input_handler(struct netmsg *msg0)
85 {
86         struct mbuf *m = ((struct netmsg_packet *)msg0)->nm_packet;
87
88         mpls_input(m);
89 }
90
91 void
92 mpls_input(struct mbuf *m)
93 {
94         struct mpls *mpls = NULL;
95         mpls_label_t label;
96
97         M_ASSERTPKTHDR(m);
98
99         mplsstat.mplss_total++;
100
101         /* length checks already performed at mpls_demux() */
102         KASSERT(m->m_pkthdr.len >= sizeof(struct mpls),
103             ("mpls_input: mpls header too small"));
104         
105 again:
106         if (m->m_len < sizeof(struct mpls)) {
107                 m = m_pullup(m, sizeof(struct mpls));
108                 if (m == NULL) {
109                         mplsstat.mplss_toosmall++;
110                         return;
111                 }
112         }
113
114         mpls = mtod(m, struct mpls*);
115         label = MPLS_LABEL(ntohl(mpls->mpls_shim));
116         switch (label) {
117         case 0:
118                 /* 
119                  * Label 0: represents "IPv4 Explicit NULL Label".
120                  */
121                 if (MPLS_STACK(ntohl(mpls->mpls_shim))) {
122                         /* Decapsulate the ip datagram from the mpls frame. */
123                         m_adj(m, sizeof(struct mpls));
124 /*
125                         ip_input(m);
126 */
127                         netisr_dispatch(NETISR_IP, m);
128                         return;
129                 }
130                 goto again; /* If not the bottom label, per RFC4182. */
131
132         case 1:
133                 /*
134                  * Label 1: represents "Router Alert Label" and is valid 
135                  * anywhere except at the bottom of the stack.
136                  */
137                 break;
138
139         case 2:
140                 /* 
141                  * Label 2: represents "IPv6 Explicit NULL Label".
142                  */
143                 if (MPLS_STACK(ntohl(mpls->mpls_shim))) {
144                         /* Decapsulate the ip datagram from the mpls frame. */
145                         m_adj(m, sizeof(struct mpls));
146                         netisr_dispatch(NETISR_IPV6, m);
147                         return;
148                 }
149                 goto again; /* If not the bottom label, per RFC4182. */
150
151         case 3:
152                 /*
153                  * Label 3: represents the "Implicit NULL Label" and must not 
154                  * appear on the wire.
155                  */
156                 break;
157         default:
158                 /*
159                  * Labels 4 - 15: reserved, drop them.
160                  */
161                 if (label <= 15) {
162                         mplsstat.mplss_reserved++;
163                         m_freem(m);
164                         return;
165                 }
166                 if (mplsforwarding) {
167                         mpls_forward(m);
168                         return;
169                 } else {
170                         mplsstat.mplss_cantforward++;
171                         m_freem(m);
172                         return;
173                 }
174         }
175
176         mplsstat.mplss_invalid++;
177         m_freem(m);
178 }
179
180 static void
181 mpls_forward(struct mbuf *m)
182 {
183         struct sockaddr_mpls *smpls;
184         struct mpls *mpls;
185         struct route *cache_rt = &mplsforward_rt[mycpuid];
186         mpls_label_t label;
187         struct ifnet *ifp;
188         struct sockaddr *dst;
189         int error;
190
191         KASSERT(m->m_len >= sizeof(struct mpls),
192             ("mpls_forward: mpls header not in one mbuf"));
193
194         mpls = mtod(m, struct mpls *);
195         label = MPLS_LABEL(ntohl(mpls->mpls_shim));
196
197         smpls = (struct sockaddr_mpls *) &cache_rt->ro_dst;
198         if (cache_rt->ro_rt == NULL || smpls->smpls_label != label) {
199                 if (cache_rt->ro_rt != NULL) {
200                         RTFREE(cache_rt->ro_rt);
201                         cache_rt->ro_rt = NULL;
202                 }
203                 smpls->smpls_family = AF_MPLS;
204                 smpls->smpls_len = sizeof(struct sockaddr_mpls);
205                 smpls->smpls_label = htonl(label);
206                 rtalloc(cache_rt);
207                 if (cache_rt->ro_rt == NULL) {
208                         /* route not found */
209                         return;
210                 }
211         }
212
213         ifp = cache_rt->ro_rt->rt_ifp;
214         dst = cache_rt->ro_rt->rt_gateway;
215         error = mpls_output(m, cache_rt->ro_rt);
216         if (error)
217                 goto bad;
218         error = (*ifp->if_output)(ifp, m, dst, cache_rt->ro_rt);
219         if (error)
220                 goto bad;
221         mplsstat.mplss_forwarded++;
222
223         return;
224 bad:
225         m_freem(m);
226 }