Change NHLFE MTU calculation
[mpls-linux.git] / src / mpls_input.c
blobfdf333b7bf579cc4349d57d6bd01db2fcc4d2767
1 /*****************************************************************************
2 * MPLS
3 * An implementation of the MPLS (MultiProtocol Label
4 * Switching Architecture) for Linux.
6 * Authors:
7 * James Leu <jleu@mindspring.com>
8 * Ramon Casellas <casellas@infres.enst.fr>
10 * (c) 1999-2004 James Leu <jleu@mindspring.com>
11 * (c) 2003-2004 Ramon Casellas <casellas@infres.enst.fr>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 ****************************************************************************/
19 #include <linux/autoconf.h>
20 #include <linux/kernel.h>
21 #include <linux/netdevice.h>
22 #include <linux/mm.h>
23 #include <linux/slab.h>
24 #include <linux/if_ether.h>
25 #include <linux/if_vlan.h>
26 #include <linux/if_arp.h>
27 #include <linux/kobject.h>
28 #include <net/ip.h>
29 #include <net/icmp.h>
30 #ifdef CONFIG_IPV6
31 #include <net/ipv6.h>
32 #endif
33 #include <net/mpls.h>
36 /**
37 * mpls_input - Begin labelled packet processing.
38 * @skb: socket buffer, containing the good stuff.
39 * @dev: device that receives the packet.
40 * @pt: packet type (handler) structure.
41 * @label: label value + metadata (type)
42 * @labelspace: incoming labelspace.
43 **/
45 static int
46 mpls_input (struct sk_buff *skb, struct net_device *dev,
47 struct packet_type *pt, struct mpls_label *label,
48 int labelspace)
50 MPLS_IN_OPCODE_PROTOTYPE(*func); /* Function Pointer for Opcodes */
51 struct mpls_prot_driver *prot = NULL;
52 struct mpls_nhlfe *nhlfe = NULL; /* Current NHLFE */
53 struct mpls_ilm *ilm = NULL; /* Current ILM */
54 struct mpls_instr *mi = NULL;
55 void *data = NULL; /* current data for opcode */
56 int opcode = 0; /* Current opcode to execute */
57 char *msg = NULL; /* Human readable desc. opcode */
58 int retval;
60 MPLS_ENTER;
62 mpls_input_start:
64 if (ilm) {
65 /* we only hit this case when we have a recursive label
66 * lookup. drop the previous protocol driver, and ilm
68 mpls_proto_release(MPLSCB(skb)->prot);
69 mpls_ilm_release(ilm);
72 MPLS_DEBUG("labelspace=%d,label=%d,exp=%01x,B.O.S=%d,TTL=%d\n",
73 labelspace, MPLSCB(skb)->label, MPLSCB(skb)->exp,
74 MPLSCB(skb)->bos, MPLSCB(skb)->ttl);
76 /* GET a reference to the ilm given this label value/labelspace*/
77 ilm = mpls_get_ilm_by_label (label, labelspace, MPLSCB(skb)->bos);
78 if (unlikely(!ilm)) {
79 MPLS_DEBUG("unknown incoming label, dropping\n");
80 goto mpls_input_drop;
83 mpls_proto_hold(ilm->ilm_proto);
84 MPLSCB(skb)->prot = ilm->ilm_proto;
86 ilm->ilm_stats.packets++;
87 ilm->ilm_stats.bytes += skb->len;
89 /* Iterate all the opcodes for this ILM */
90 for (mi = ilm->ilm_instr; mi; mi = mi->mi_next) {
91 data = mi->mi_data;
92 opcode = mi->mi_opcode;
93 msg = mpls_ops[opcode].msg;
94 func = mpls_ops[opcode].in;
96 MPLS_DEBUG("opcode %s\n",msg);
97 if (!func) {
98 MPLS_DEBUG("invalid opcode for input: %s\n",msg);
99 goto mpls_input_drop;
102 switch (func(&skb,ilm,&nhlfe,data)) {
103 case MPLS_RESULT_RECURSE:
104 label->ml_type = MPLS_LABEL_GEN;
105 label->u.ml_gen = MPLSCB(skb)->label;
106 goto mpls_input_start;
107 case MPLS_RESULT_DLV:
108 goto mpls_input_dlv;
109 case MPLS_RESULT_FWD:
110 goto mpls_input_fwd;
111 case MPLS_RESULT_DROP:
112 mpls_proto_release(MPLSCB(skb)->prot);
113 goto mpls_input_drop;
114 case MPLS_RESULT_SUCCESS:
115 break;
118 MPLS_DEBUG("finished executing in label program without DLV or FWD\n");
119 mpls_proto_release(MPLSCB(skb)->prot);
121 /* fall through to drop */
123 mpls_input_drop:
125 /* proto driver isn't held yet, no need to release it */
126 if (ilm) {
127 ilm->ilm_drops++;
128 mpls_ilm_release(ilm);
130 MPLS_DEBUG("dropped\n");
131 return NET_RX_DROP;
133 mpls_input_dlv:
135 dst_hold(&ilm->u.dst);
136 skb_dst_set(skb, &ilm->u.dst);
139 * clean up the packet so that protocols like DHCP
140 * will work across a LSP
142 if (ilm->ilm_fix_hh) {
143 if (mpls_finish(skb) == NULL) {
144 MPLS_DEBUG("unable to finish skb\n");
145 return NET_RX_DROP;
149 mpls_ilm_release(ilm);
151 /* ala Cisco, take the lesser of the TTLs
152 * -if propogate TTL was done at the ingress LER, then the
153 * shim TTL will be less the the header TTL
154 * -if no propogate TTL was done as the ingress LER, a
155 * default TTL was placed in the shim, which makes the
156 * entire length of the LSP look like one hop to traceroute.
157 * As long as the default value placed in the shim is
158 * significantly larger then the TTL in the header, then
159 * traceroute will work fine. If not, then traceroute
160 * will continualy show the egress of the LSP as the
161 * next hop in the path.
164 if (MPLSCB(skb)->ttl < MPLSCB(skb)->prot->get_ttl(skb)) {
165 MPLSCB(skb)->prot->set_ttl(skb, MPLSCB(skb)->ttl);
168 /* we're done with the PDU, it now goes to another layer for handling
169 * it is safe to release the protocol driver now
171 mpls_proto_release(MPLSCB(skb)->prot);
173 MPLS_DEBUG("delivering\n");
175 return 0;
177 mpls_input_fwd:
179 mpls_ilm_release (ilm);
181 if (MPLSCB(skb)->ttl <= 1) {
182 printk("TTL exceeded\n");
184 prot = MPLSCB(skb)->prot;
185 retval = prot->ttl_expired(&skb);
186 mpls_proto_release(prot);
188 if (retval)
189 return retval;
191 /* otherwise prot->ttl_expired() must have modified the
192 * skb and want it to be forwarded down the LSP
196 (MPLSCB(skb)->ttl)--;
198 dst_hold(&nhlfe->u.dst);
199 skb_dst_set(skb, &nhlfe->u.dst);
201 /* mpls_switch() does a mpls_proto_release() */
203 MPLS_DEBUG("switching\n");
205 return 0;
209 * mpls_skb_recv - Main MPLS packet receive function.
210 * @skb : socket buffer, containing the good stuff.
211 * @dev : device that receives the packet.
212 * @pt : packet type handler.
215 int
216 mpls_skb_recv (
217 struct sk_buff *skb,
218 struct net_device *dev,
219 struct packet_type *pt,
220 struct net_device *orig)
222 int labelspace;
223 int result = NET_RX_DROP;
224 struct mpls_label label;
225 struct mpls_interface *mip = mpls_get_if_info(dev->ifindex);
227 MPLS_ENTER;
228 MPLS_DEBUG_CALL(mpls_skb_dump(skb));
230 if (skb->pkt_type == PACKET_OTHERHOST)
231 goto mpls_rcv_drop;
233 if (!(skb = skb_share_check (skb, GFP_ATOMIC)))
234 goto mpls_rcv_out;
236 if (!pskb_may_pull (skb, MPLS_SHIM_SIZE))
237 goto mpls_rcv_err;
239 labelspace = mip ? mip->labelspace : -1;
240 if (unlikely(labelspace < 0)) {
241 MPLS_DEBUG("unicast packet recv on if. w/o labelspace (%s) - packet dropped\n",dev->name);
242 goto mpls_rcv_drop;
245 memset(MPLSCB(skb), 0, sizeof(*MPLSCB(skb)));
246 memset(&label, 0, sizeof(label));
247 MPLSCB(skb)->top_of_stack = skb->data;
249 mpls_opcode_peek (skb);
251 /* we need the label struct for when we support ATM and FR */
252 switch(dev->type) {
253 case ARPHRD_ETHER:
254 case ARPHRD_FDDI:
255 case ARPHRD_IEEE802:
256 case ARPHRD_PPP:
257 case ARPHRD_LOOPBACK:
258 case ARPHRD_HDLC:
259 case ARPHRD_IPGRE:
260 label.ml_type = MPLS_LABEL_GEN;
261 label.u.ml_gen = MPLSCB(skb)->label;
262 break;
263 default:
264 printk("Unknown IfType(%08x) for MPLS\n",dev->type);
265 goto mpls_rcv_err;
268 if (mpls_input (skb,dev,pt,&label,labelspace))
269 goto mpls_rcv_drop;
271 result = dst_input(skb);
273 MPLS_DEBUG("exit(%d)\n",result);
274 return result;
276 mpls_rcv_err:
277 /* increment some err counter */
278 mpls_rcv_drop:
279 kfree_skb (skb);
280 mpls_rcv_out:
281 MPLS_DEBUG("exit(DROP)\n");
282 return NET_RX_DROP;
290 * mpls_skb_recv_mc - Main Multicast MPLS packet receive function.
291 * @skb : socket buffer, containing the good stuff.
292 * @dev : device that receives the packet.
293 * @pt : packet handler. (MPLS UC)
296 int mpls_skb_recv_mc (
297 struct sk_buff *skb,
298 struct net_device *dev,
299 struct packet_type *pt,
300 struct net_device *orig)
302 kfree_skb(skb);
303 MPLS_DEBUG("Not implemented\n");
304 return NET_RX_DROP;