diff -uNr --exclude=CVS linux-2.4.0-test11.clean/drivers/net/ppp_generic.c linux-kernel-mpls/drivers/net/ppp_generic.c --- linux-2.4.0-test11.clean/drivers/net/ppp_generic.c Mon Nov 27 13:23:31 2000 +++ linux-kernel-mpls/drivers/net/ppp_generic.c Mon Nov 27 13:36:41 2000 @@ -54,7 +54,8 @@ #define NP_IPV6 1 /* Internet Protocol V6 */ #define NP_IPX 2 /* IPX protocol */ #define NP_AT 3 /* Appletalk protocol */ -#define NUM_NP 4 /* Number of NPs. */ +#define NP_MPLS_UC 4 /* MPLS Unicast Packets */ +#define NUM_NP 5 /* Number of NPs. */ #define MPHDRLEN 6 /* multilink protocol header length */ #define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */ @@ -249,6 +250,10 @@ return NP_IPX; case PPP_AT: return NP_AT; +#ifdef CONFIG_MPLS + case PPP_MPLS_UC: + return NP_MPLS_UC; +#endif } return -EINVAL; } @@ -259,6 +264,9 @@ PPP_IPV6, PPP_IPX, PPP_AT, +#ifdef CONFIG_MPLS + PPP_MPLS_UC, +#endif }; /* Translates an ethertype into an NP index */ @@ -274,6 +282,10 @@ case ETH_P_PPPTALK: case ETH_P_ATALK: return NP_AT; +#ifdef CONFIG_MPLS + case ETH_P_MPLS_UC: + return NP_MPLS_UC; +#endif } return -1; } @@ -284,6 +296,9 @@ ETH_P_IPV6, ETH_P_IPX, ETH_P_PPPTALK, +#ifdef CONFIG_MPLS + ETH_P_MPLS_UC, +#endif }; /* diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/atmdev.h linux-kernel-mpls/include/linux/atmdev.h --- linux-2.4.0-test11.clean/include/linux/atmdev.h Mon Nov 27 13:22:08 2000 +++ linux-kernel-mpls/include/linux/atmdev.h Tue Nov 28 12:23:18 2000 @@ -234,6 +234,9 @@ ATM_VF_SESSION, /* VCC is p2mp session control descriptor */ ATM_VF_HASSAP, /* SAP has been set */ ATM_VF_CLOSE, /* asynchronous close - treat like VF_RELEASED*/ +#ifdef CONFIG_MPLS + ATM_VF_MPLS, /* VCC is open by MPLS */ +#endif }; diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/if_arp.h linux-kernel-mpls/include/linux/if_arp.h --- linux-2.4.0-test11.clean/include/linux/if_arp.h Mon Nov 27 13:22:05 2000 +++ linux-kernel-mpls/include/linux/if_arp.h Tue Nov 28 07:17:56 2000 @@ -77,6 +77,7 @@ #define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ /* 787->799 reserved for fibrechannel media types */ #define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ +#define ARPHRD_MPLS_TUNNEL 801 /* MPLS Tunnel Interface */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/if_ether.h linux-kernel-mpls/include/linux/if_ether.h --- linux-2.4.0-test11.clean/include/linux/if_ether.h Mon Nov 27 13:22:12 2000 +++ linux-kernel-mpls/include/linux/if_ether.h Mon Nov 27 13:35:14 2000 @@ -58,6 +58,8 @@ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ #define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ #define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ +#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ +#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ #define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ #define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport * over Ethernet diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/mpls.h linux-kernel-mpls/include/linux/mpls.h --- linux-2.4.0-test11.clean/include/linux/mpls.h Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/include/linux/mpls.h Mon Nov 27 13:54:48 2000 @@ -0,0 +1,183 @@ +#ifndef _LINUX_MPLS_H_ +#define _LINUX_MPLS_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#define MPLS_NUM_OPS 8 + +#define SIOCMPLSFIRST 0x8C00 +#define SIOCGLABELSPACEMPLS 0x8C01 +#define SIOCSLABELSPACEMPLS 0x8C02 +#define SIOCMPLSDEBUG 0x8C03 +#define SIOCMPLSTUNNELADD 0x8C04 +#define SIOCMPLSTUNNELDEL 0x8C05 +#define SIOCMPLSLAST 0x8C3F + +#define SIOCMPLSTUNNELADDOUT (SIOCDEVPRIVATE + 1) +#define SIOCMPLSTUNNELDELOUT (SIOCDEVPRIVATE + 2) + +#define MPLS_IPV4_EXPLICIT_NULL 0 /* only valid as sole label stack entry + Pop label and send to IPv4 stack */ +#define MPLS_ROUTER_ALERT 1 /* anywhere except bottom, packet it is + forwared to a software module + determined by the next label, + if the packet is forwarded, push this + label back on */ +#define MPLS_IPV6_EXPLICIT_NULL 2 /* only valid as sole label stack entry + Pop label and send to IPv6 stack */ +#define MPLS_IMPLICIT_NULL 3 /* a LIB with this, signifies to pop + the next label and use that */ + +enum mpls_direction_enum { + MPLS_IN = 0x10, + MPLS_OUT = 0x20 +}; + +enum mpls_opcode_enum { + MPLS_OP_NOP = 0x00, + MPLS_OP_POP, + MPLS_OP_PEEK, + MPLS_OP_PUSH, + MPLS_OP_FWD, + MPLS_OP_DLV, + MPLS_OP_ROT, + MPLS_OP_SET, + MPLS_OP_POPALL +}; + +enum mpls_label_type_enum { + MPLS_LABEL_GEN = 1, + MPLS_LABEL_ATM, + MPLS_LABEL_FR +}; + +struct mpls_atm_key { + unsigned int index:8; + unsigned int vpi:8; + unsigned int vci:14; + unsigned int type:2; +}; + +struct mpls_gen_key { + unsigned int index:10; + unsigned int gen:20; + unsigned int type:2; +}; + +struct mpls_fr_key { + unsigned int index:10; + unsigned int fr:20; + unsigned int type:2; +}; + +struct mpls_key { + union { + struct mpls_atm_key atm; + struct mpls_gen_key gen; + struct mpls_fr_key fr; + unsigned int mark; + } u; +}; + +struct mpls_label_atm { + unsigned short mla_vpi; + unsigned short mla_vci; +}; + +struct mpls_label { +#ifdef __KERNEL__ + atomic_t __refcnt; +#else + int __refcnt; +#endif + enum mpls_label_type_enum ml_type; + union { + unsigned int ml_gen; + unsigned int ml_fr; + struct mpls_label_atm ml_atm; + } u; + int ml_index; +}; + +struct mpls_fec { + unsigned int prefix; + unsigned int source; + unsigned char len; + unsigned char tos; + unsigned int output_ifindex; + unsigned int input_ifindex; + struct mpls_fec *next; +}; + +struct mpls_opcode_req { + enum mpls_opcode_enum opcode; + unsigned int data; +}; + +struct mpls_in_label_req { + unsigned char rtnl_family; + unsigned int mil_age; + struct mpls_label mil_label; +#define mil_labelspace mil_label.ml_index +}; + +#define MPLS_LABELSPACE_MAX 255 + +struct mpls_labelspace_req { + int mls_ifindex; + int mls_labelspace; +}; + +struct mpls_out_label_req { + unsigned char rtnl_family; + unsigned int mol_age; + struct mpls_label mol_label; +#define mol_ifindex mol_label.ml_index + struct sockaddr mol_nh; +}; + +struct mpls_xconnect_req { + unsigned char rtnl_family; + struct mpls_label mx_in; + struct mpls_label mx_out; +#define mx_ilabelspace mx_in.ml_index +#define mx_oifindex mx_out.ml_index +}; + +struct mpls_bind_fec_req { + unsigned char rtnl_family; + struct mpls_fec mbf_fec; + struct mpls_label mbf_label; +#define mbf_ifindex mbf_label.ml_index +}; + +struct mpls_instruction_req_elem { + unsigned short mir_opcode; + unsigned char mir_direction; + union { + struct { + struct mpls_label label; + } push; + struct { + struct mpls_label label; + int index; + } fwd; + unsigned int set; + unsigned int dlv; + } mir_data; +}; + +struct mpls_instruction_req { + unsigned char rtnl_family; + struct mpls_instruction_req_elem mir_instruction[MPLS_NUM_OPS]; + struct mpls_label mir_label; + unsigned char mir_instruction_length; + unsigned char mir_direction; + int mir_index; +}; + +#endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/netdevice.h linux-kernel-mpls/include/linux/netdevice.h --- linux-2.4.0-test11.clean/include/linux/netdevice.h Mon Nov 27 13:21:57 2000 +++ linux-kernel-mpls/include/linux/netdevice.h Tue Nov 28 07:17:56 2000 @@ -395,6 +395,9 @@ rwlock_t fastpath_lock; struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; #endif +#ifdef CONFIG_MPLS + int mpls_labelspace; +#endif #ifdef CONFIG_NET_DIVERT /* this will get initialized at each interface type init routine */ struct divert_blk *divert; @@ -654,6 +657,7 @@ extern int netdev_fastroute_obstacles; extern void dev_clear_fastroute(struct net_device *dev); #endif +extern struct packet_type *find_packet_type(unsigned short type); #endif /* __KERNEL__ */ diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/ppp_defs.h linux-kernel-mpls/include/linux/ppp_defs.h --- linux-2.4.0-test11.clean/include/linux/ppp_defs.h Mon Nov 27 13:22:11 2000 +++ linux-kernel-mpls/include/linux/ppp_defs.h Mon Nov 27 13:35:13 2000 @@ -74,12 +74,15 @@ #define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ #define PPP_COMPFRAG 0xfb /* fragment compressed below bundle */ #define PPP_COMP 0xfd /* compressed packet */ +#define PPP_MPLS_UC 0x0281 /* Multi Protocol Label Switching - Unicast */ +#define PPP_MPLS_MC 0x0283 /* Multi Protocol Label Switching - Multicast */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ #define PPP_IPXCP 0x802b /* IPX Control Protocol */ #define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define PPP_CCPFRAG 0x80fb /* CCP at link level (below MP bundle) */ #define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_MPLSCP 0x8281 /* Multi Protocol Label Switching */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/rtnetlink.h linux-kernel-mpls/include/linux/rtnetlink.h --- linux-2.4.0-test11.clean/include/linux/rtnetlink.h Mon Nov 27 13:22:05 2000 +++ linux-kernel-mpls/include/linux/rtnetlink.h Mon Nov 27 13:50:50 2000 @@ -2,6 +2,7 @@ #define __LINUX_RTNETLINK_H #include +#include #define RTNL_DEBUG 1 @@ -46,7 +47,36 @@ #define RTM_DELTFILTER (RTM_BASE+29) #define RTM_GETTFILTER (RTM_BASE+30) +#ifdef CONFIG_MPLS + +#define RTM_NEWNHLFE (RTM_BASE+32) +#define RTM_DELNHLFE (RTM_BASE+33) +#define RTM_GETNHLFE (RTM_BASE+34) + +#define RTM_NEWILM (RTM_BASE+36) +#define RTM_DELILM (RTM_BASE+37) +#define RTM_GETILM (RTM_BASE+38) + +#define RTM_NEWXC (RTM_BASE+40) +#define RTM_DELXC (RTM_BASE+41) +#define RTM_GETXC (RTM_BASE+42) + +#define RTM_NEWFTN (RTM_BASE+44) +#define RTM_DELFTN (RTM_BASE+45) +#define RTM_GETFTN (RTM_BASE+46) + +#define RTM_SETOUTINSTR (RTM_BASE+48) +#define RTM_GETOUTINSTR (RTM_BASE+49) +#define RTM_SETININSTR (RTM_BASE+50) +#define RTM_GETININSTR (RTM_BASE+51) + +#define RTM_MAX (RTM_BASE+52) + +#else + #define RTM_MAX (RTM_BASE+31) + +#endif /* Generic structure for encapsulation optional route information. diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/linux/skbuff.h linux-kernel-mpls/include/linux/skbuff.h --- linux-2.4.0-test11.clean/include/linux/skbuff.h Mon Nov 27 13:22:12 2000 +++ linux-kernel-mpls/include/linux/skbuff.h Tue Nov 28 07:17:26 2000 @@ -122,6 +122,13 @@ unsigned char *head; /* Head of buffer */ unsigned char *data; /* Data head pointer */ +#ifdef CONFIG_MPLS + char mpls_gap; /* Gap between data and end of hard header */ + /* introduced by MPLS */ +#ifdef CONFIG_MPLS_INGRESS_POLICING + __u32 mpls_index; /* traffic control index */ +#endif +#endif unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ void (*destructor)(struct sk_buff *); /* Destruct function */ @@ -169,6 +176,7 @@ int newheadroom, int newtailroom, int priority); +extern void copy_skb_header(struct sk_buff *new, const struct sk_buff *old); #define dev_kfree_skb(a) kfree_skb(a) extern void skb_over_panic(struct sk_buff *skb, int len, void *here); extern void skb_under_panic(struct sk_buff *skb, int len, void *here); @@ -945,6 +953,7 @@ extern void skb_init(void); extern void skb_add_mtu(int mtu); +extern void skb_dump(struct sk_buff* skb); #ifdef CONFIG_NETFILTER static inline void diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/net/dst.h linux-kernel-mpls/include/net/dst.h --- linux-2.4.0-test11.clean/include/net/dst.h Mon Nov 27 13:22:12 2000 +++ linux-kernel-mpls/include/net/dst.h Tue Nov 28 07:17:56 2000 @@ -10,13 +10,14 @@ #include #include +#include /* * 0 - no debugging messages * 1 - rare events and bugs (default) * 2 - trace mode. */ -#define RT_CACHE_DEBUG 0 +#define RT_CACHE_DEBUG 1 #define DST_GC_MIN (1*HZ) #define DST_GC_INC (5*HZ) @@ -63,6 +64,7 @@ struct dst_ops *ops; + void *dst_proto_data[NUM_AUX_PROTO_DATA]; char info[0]; }; diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/net/fib_aux.h linux-kernel-mpls/include/net/fib_aux.h --- linux-2.4.0-test11.clean/include/net/fib_aux.h Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/include/net/fib_aux.h Mon Nov 27 13:35:15 2000 @@ -0,0 +1,16 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _NET_FIB_AUX_H +#define _NET_FIB_AUX_H + +#include + +#define AUX_PROTO_DATA_MPLS 0 +#define NUM_AUX_PROTO_DATA 1 + +#endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/net/ip.h linux-kernel-mpls/include/net/ip.h --- linux-2.4.0-test11.clean/include/net/ip.h Mon Nov 27 13:22:15 2000 +++ linux-kernel-mpls/include/net/ip.h Tue Nov 28 07:17:56 2000 @@ -162,9 +162,9 @@ static inline int ip_send(struct sk_buff *skb) { if (skb->len > skb->dst->pmtu) - return ip_fragment(skb, ip_finish_output); + return ip_fragment(skb,skb->dst->output); else - return ip_finish_output(skb); + return skb->dst->output(skb); } /* The function in 2.2 was invalid, producing wrong result for diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/net/ip_fib.h linux-kernel-mpls/include/net/ip_fib.h --- linux-2.4.0-test11.clean/include/net/ip_fib.h Mon Nov 27 13:22:13 2000 +++ linux-kernel-mpls/include/net/ip_fib.h Mon Nov 27 13:35:15 2000 @@ -17,6 +17,7 @@ #define _NET_IP_FIB_H #include +#include struct kern_rta { @@ -89,6 +90,7 @@ unsigned char nh_sel; unsigned char type; unsigned char scope; + void *proto_data[NUM_AUX_PROTO_DATA]; struct fib_info *fi; #ifdef CONFIG_IP_MULTIPLE_TABLES struct fib_rule *r; @@ -131,6 +133,7 @@ int first, int count); void (*tb_select_default)(struct fib_table *table, const struct rt_key *key, struct fib_result *res); + int (*tb_add_proto_data)(struct fib_table *tb, const struct rt_key *key, struct fib_result *res,int proto_data); unsigned char tb_data[0]; }; @@ -160,6 +163,14 @@ return 0; } +extern inline int fib_add_proto_data(const struct rt_key *key, struct fib_result *res,int proto_num) +{ + if (local_table->tb_add_proto_data(local_table, key, res, proto_num) && + main_table->tb_add_proto_data(main_table, key, res, proto_num)) + return -ENETUNREACH; + return 0; +} + static inline void fib_select_default(const struct rt_key *key, struct fib_result *res) { if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) @@ -172,6 +183,8 @@ extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; extern int fib_lookup(const struct rt_key *key, struct fib_result *res); +extern int fib_add_proto_data(const struct rt_key *key,struct fib_result *res, + int proto_num); extern struct fib_table *__fib_new_table(int id); extern void fib_rule_put(struct fib_rule *r); diff -uNr --exclude=CVS linux-2.4.0-test11.clean/include/net/mpls.h linux-kernel-mpls/include/net/mpls.h --- linux-2.4.0-test11.clean/include/net/mpls.h Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/include/net/mpls.h Tue Nov 28 07:25:40 2000 @@ -0,0 +1,314 @@ +#ifndef _NET_MPLS_H_ +#define _NET_MPLS_H_ + +#include +#include +#include +#include +#include + +extern int mpls_debug; +#define MPLS_DEBUG(x) if(mpls_debug) printk x +#define MPLS_ATM_VCC_RX 1 /* uni-directional VCC for RX */ +#define MPLS_ATM_VCC_TX 2 /* uni-directional VCC for TX */ + +#define RADIX_INIT(head) \ +{ \ + (head)->RdX_root = NULL; \ +} + +#define RADIX_ENTRY(type,bits) \ +struct { \ + struct type *RdX_next[(0x01 << bits)]; \ +} + +#define RADIX_HEAD(name,type) \ +struct name { \ + struct type *RdX_root; \ +}; + +#define RADIX_INSERT(head,type,field,bits,tdef,key,klen,result) \ +{ \ + struct type **RdX_node = &((head)->RdX_root); \ + tdef RdX_mask; \ + int RdX_index; \ + int RdX_size = sizeof(tdef)*8; \ + char RdX_status = 0; \ + int RdX_count = 0; \ + \ + if(klen % bits) result = -1; \ + else { \ + RdX_mask = (0x01 << bits)-1; \ + while((RdX_count*bits) < klen) { \ + RdX_status = 1; \ + if(!(*RdX_node)) { \ + RdX_status = 2; \ + (*RdX_node) = (struct type *)kmalloc(sizeof(struct type), \ + GFP_KERNEL); \ + if(!(*RdX_node)) { \ + result = -2; \ + break; \ + } \ + RdX_status = 3; \ + memset((*RdX_node),0,sizeof(struct type)); \ + RdX_status = 4; \ + } \ + RdX_index = (key >> (RdX_size - bits - (RdX_count * bits))) & RdX_mask; \ + RdX_status = 5; \ + RdX_node = &((*RdX_node)->field.RdX_next[RdX_index]); \ + RdX_status = 6; \ + RdX_count++; \ + result = 0; \ + } \ + if(result != -2 && (!(*RdX_node))) { \ + (*RdX_node) = (struct type *)kmalloc(sizeof(struct type), \ + GFP_KERNEL); \ + if(!(*RdX_node)) { \ + result = -2; \ + } else { \ + memset((*RdX_node),0,sizeof(struct type)); \ + } \ + } \ + } \ +} + +#define RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,RxD_set) \ +{ \ + struct type *RdX_node = (head)->RdX_root; \ + tdef RdX_mask; \ + int RdX_index; \ + int RdX_size = sizeof(tdef)*8; \ + int RdX_count = 0; \ + \ + if(klen % bits) result = -1; \ + else { \ + RdX_mask = (0x01 << bits)-1; \ + while((RdX_count*bits) < klen) { \ + if(!RdX_node) { \ + result = -2; \ + break; \ + } else { \ + RdX_index = (key >> (RdX_size - bits - (RdX_count * bits))) & RdX_mask;\ + RdX_node = RdX_node->field.RdX_next[RdX_index]; \ + } \ + RdX_count++; \ + } \ + if(!RdX_node) { \ + result = -3; \ + } else { \ + if(RxD_set) { \ + RdX_node->flm = elem; \ + } else { \ + elem = RdX_node->flm; \ + } \ + result = 0; \ + } \ + } \ +} + +#define RADIX_SET(head,type,field,bits,tdef,key,klen,flm,elem,result) \ + RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,1) +#define RADIX_GET(head,type,field,bits,tdef,key,klen,flm,elem,result) \ + RADIX_DO(head,type,field,bits,tdef,key,klen,flm,elem,result,0) + +#define RADIX_VISIT_ALL(head,type,field,bits,visit,extra) \ +{ \ + int RdX_node_count = (0x1 << bits); \ + struct type *RdX_stack[RdX_node_count]; \ + int RdX_stack_count[RdX_node_count]; \ + int RdX_stack_depth = 0; \ + struct type *RdX_node; \ + int RdX_done = 0; \ + int R = 0; \ + \ + if((RdX_node = (head)->RdX_root)) { \ + while(!RdX_done) { \ + if(RdX_node->field.RdX_next[R]) { \ + RdX_stack[RdX_stack_depth] = RdX_node; \ + RdX_stack_count[RdX_stack_depth] = R + 1; \ + RdX_stack_depth++; \ + RdX_node = RdX_node->field.RdX_next[R]; \ + R = 0; \ + } else { \ + R++; \ + if(R >= RdX_node_count) { \ + if(visit(RdX_node,extra)) { \ + RdX_done = 1; \ + break; \ + } \ + RdX_stack_depth--; \ + if(RdX_stack_depth >= 0) { \ + RdX_node = RdX_stack[RdX_stack_depth]; \ + R = RdX_stack_count[RdX_stack_depth]; \ + } else { \ + RdX_done = 1; \ + } \ + } \ + } \ + } \ + } \ +} + +#define MPLS_TREE_BITS 4 +#define MPLS_TREE_DEPTH 32 + +struct mpls_push_data { + unsigned int label:20; + unsigned int ttl:8; + unsigned int exp:3; + unsigned int bos:1; + unsigned char flag; +}; + +struct mpls_instruction { + unsigned short mi_opcode; + unsigned int mi_data; +}; + +struct mpls_in_info { + atomic_t __refcnt; + unsigned int mii_key; + unsigned int mii_age; + unsigned int mii_proto; + unsigned short mii_labelspace; + unsigned short mii_instruction_length; + struct mpls_label mii_label; +#ifdef CONFIG_ATM + struct atm_vcc *mii_vcc; +#endif + struct mpls_instruction mii_instruction[MPLS_NUM_OPS]; +}; + +struct mpls_in_info_node { + RADIX_ENTRY(mpls_in_info_node,MPLS_TREE_BITS) next; + struct mpls_in_info *mii; +}; +RADIX_HEAD(mpls_in_info_tree,mpls_in_info_node); + +extern struct mpls_in_info_tree mii_tree; + +struct mpls_out_info { + atomic_t __refcnt; + int moi_ifindex; + unsigned int moi_key; + struct dst_entry *moi_dst; + struct net_device *moi_dev; + struct sockaddr moi_nh; +#ifdef CONFIG_ATM + struct atm_vcc *moi_vcc; +#endif + unsigned int moi_age; + unsigned short moi_instruction_length; + struct mpls_fec *moi_fec_list; + struct mpls_instruction moi_instruction[MPLS_NUM_OPS]; +}; + +struct mpls_out_info_node { + RADIX_ENTRY(mpls_out_info_node,MPLS_TREE_BITS) next; + struct mpls_out_info *moi; +}; +RADIX_HEAD(mpls_out_info_tree,mpls_out_info_node); + +extern struct mpls_out_info_tree moi_tree; + +extern void __mpls_del_in_label(struct mpls_in_info*); +extern void __mpls_del_out_label(struct mpls_out_info*); + +extern void mpls_label_hold(struct mpls_label *ml); +extern void mpls_label_release(struct mpls_label *ml); +extern void mpls_in_info_hold(struct mpls_in_info *mii); +extern void mpls_in_info_release(struct mpls_in_info *mii); +extern void mpls_out_info_hold(struct mpls_out_info *moi); +extern void mpls_out_info_release(struct mpls_out_info *moi); + +extern int mpls_add_in_label(struct mpls_in_label_req *in); +extern int mpls_get_in_label(struct mpls_in_label_req *in); +extern int mpls_del_in_label(struct mpls_in_label_req *in); +extern int mpls_attach_in2out(struct mpls_xconnect_req *req); +extern int mpls_detach_in2out(struct mpls_xconnect_req *req); + +extern int mpls_set_default_out_instruction(struct mpls_out_info*); +extern int mpls_set_in_label_instructions(struct mpls_instruction_req *in); +extern int mpls_set_out_label_instructions(struct mpls_instruction_req *out); +extern int mpls_add_out_label(struct mpls_out_label_req *out); +extern int mpls_get_out_label(struct mpls_out_label_req *out); +extern int mpls_del_out_label(struct mpls_out_label_req *out); +extern int mpls_bind_out2fec(struct mpls_bind_fec_req *req); +extern int mpls_unbind_out2fec(struct mpls_bind_fec_req *req); + +extern void mpls_flush_in_tree(void); +extern void mpls_flush_out_tree(void); + +extern int mpls_ioctl(unsigned int cmd,void *arg); +extern int mpls_output(struct sk_buff *skb); +extern int mpls_fec_compare(struct mpls_fec *a,struct mpls_fec *b); +extern unsigned int mpls_label2key(int,struct mpls_label*); +extern int mpls_rcv(struct sk_buff*,struct net_device*,struct packet_type*); + +extern int mpls_out_label_info(char*,char**,off_t,int); +extern int mpls_in_label_info(char*,char**,off_t,int); +extern int mpls_labelspace_info(char*,char**,off_t,int); +extern int mpls_fec_info(char*,char**,off_t,int); + +extern u32 mpls_opcode_pop(struct sk_buff *skb); +extern char mpls_opcode_push(struct sk_buff**,struct mpls_label*,struct mpls_push_data*); +extern char mpls_opcode_peek(struct sk_buff*,struct mpls_push_data*); +extern int mpls_input(struct sk_buff*,struct net_device*,struct packet_type*,struct mpls_label*,struct mpls_push_data*,int); +extern void mpls_finish(struct sk_buff*); +extern int mpls_output2(struct sk_buff*,struct mpls_out_info*,struct mpls_push_data*); + +extern int mpls_get_labelspace(struct mpls_labelspace_req *req); +extern int mpls_set_labelspace(struct mpls_labelspace_req *req); + +extern void mpls_print_label(struct mpls_label*); +extern void mpls_print_key(u32); +extern void mpls_instruction_clear(struct mpls_instruction*,int); +extern int mpls_instruction_build(struct mpls_instruction_req*, + struct mpls_instruction*,int); +extern struct net_device *mpls_dev_by_labelspace(int); + +#ifdef CONFIG_MPLS_TUNNEL +extern int mpls_tunnel_init(void); +extern struct net_device* mpls_tunnel_locate(struct ifreq* ifr,int create); +extern void mpls_tunnel_unlink(struct net_device* dev); +extern void mpls_tunnel_link(struct net_device* dev); +#endif + +extern struct dst_entry *mpls_make_dst(struct net_device*,unsigned int,struct mpls_out_info*); +extern void mpls_instruction_copy(struct mpls_instruction *out, + struct mpls_instruction *in,int length); + +#ifdef CONFIG_RTNETLINK +extern int mpls_rtm_newnhlfe(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_delnhlfe(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_getnhlfe(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_dump_nhlfe(struct sk_buff *skb,struct netlink_callback *cb); +extern int mpls_rtm_newilm(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_delilm(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_getilm(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_dump_ilm(struct sk_buff *skb,struct netlink_callback *cb); +extern int mpls_rtm_newxc(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_delxc(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_getxc(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_dump_xc(struct sk_buff *skb,struct netlink_callback *cb); +extern int mpls_rtm_newftn(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_delftn(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_rtm_getftn(struct sk_buff *skb,struct nlmsghdr* nlh,void *arg); +extern int mpls_dump_ftn(struct sk_buff *skb,struct netlink_callback *cb); +extern int mpls_rtm_set_out_instr(struct sk_buff *skb,struct nlmsghdr* nlh, + void *arg); +extern int mpls_rtm_get_out_instr(struct sk_buff *skb,struct nlmsghdr* nlh, + void *arg); +extern int mpls_rtm_set_in_instr(struct sk_buff *skb,struct nlmsghdr* nlh, + void *arg); +extern int mpls_rtm_get_in_instr(struct sk_buff *skb,struct nlmsghdr* nlh, + void *arg); +#endif + +#ifdef CONFIG_ATM +extern struct atm_vcc *mpls_atm_create_vcc(struct net_device*,int,int,int); +extern int mpls_atm_vcc_delete(struct atm_vcc*); +extern int atm_init_mpls(struct atm_vcc*); +#endif + +#endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/Config.in linux-kernel-mpls/net/Config.in --- linux-2.4.0-test11.clean/net/Config.in Mon Nov 27 13:25:57 2000 +++ linux-kernel-mpls/net/Config.in Mon Nov 27 13:39:13 2000 @@ -75,6 +75,11 @@ bool ' Native Econet' CONFIG_ECONET_NATIVE fi tristate 'WAN router' CONFIG_WAN_ROUTER + bool 'Multi Protocol Label Switching - MPLS' CONFIG_MPLS + if [ "$CONFIG_MPLS" = "y" ]; then + bool ' MPLS Ingress Policing' CONFIG_MPLS_INGRESS_POLICING + bool ' MPLS Tunnel Interface' CONFIG_MPLS_TUNNEL + fi bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/Makefile linux-kernel-mpls/net/Makefile --- linux-2.4.0-test11.clean/net/Makefile Mon Nov 27 13:25:55 2000 +++ linux-kernel-mpls/net/Makefile Mon Nov 27 13:39:11 2000 @@ -19,6 +19,7 @@ subdir-$(CONFIG_NETFILTER) += ipv4/netfilter subdir-$(CONFIG_UNIX) += unix subdir-$(CONFIG_IPV6) += ipv6 +subdir-$(CONFIG_MPLS) += mpls ifneq ($(CONFIG_IPV6),n) ifneq ($(CONFIG_IPV6),) diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/atm/atm_misc.c linux-kernel-mpls/net/atm/atm_misc.c --- linux-2.4.0-test11.clean/net/atm/atm_misc.c Mon Nov 27 13:25:54 2000 +++ linux-kernel-mpls/net/atm/atm_misc.c Mon Nov 27 13:39:09 2000 @@ -29,7 +29,8 @@ int guess = atm_guess_pdu2truesize(pdu_size); atm_force_charge(vcc,guess); - if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) { + if ((vcc->sk == NULL) || + (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf)) { struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags); if (skb) { diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/atm/common.c linux-kernel-mpls/net/atm/common.c --- linux-2.4.0-test11.clean/net/atm/common.c Mon Nov 27 13:25:54 2000 +++ linux-kernel-mpls/net/atm/common.c Tue Nov 28 12:23:18 2000 @@ -65,6 +65,9 @@ #endif #include "signaling.h" /* for WAITING and sigd_attach */ +#ifdef CONFIG_MPLS +#include +#endif #if 0 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) @@ -72,6 +75,7 @@ #define DPRINTK(format,args...) #endif +extern struct atm_vcc *nodev_vccs; static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) { @@ -88,19 +92,23 @@ return skb; } +struct atm_vcc *atm_create_vcc(struct atm_vcc *ivcc,int family) { + struct atm_vcc *vcc = NULL; -int atm_create(struct socket *sock,int protocol,int family) -{ - struct sock *sk; - struct atm_vcc *vcc; + if(ivcc) vcc = ivcc; + else { + vcc = kmalloc(sizeof(struct atm_vcc),GFP_KERNEL); + memset(vcc,0,sizeof(struct atm_vcc)); + if (nodev_vccs) nodev_vccs->prev = vcc; + vcc->prev = NULL; + vcc->next = nodev_vccs; + nodev_vccs = vcc; + } - sock->sk = NULL; - if (sock->type == SOCK_STREAM) return -EINVAL; - if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; - vcc = sk->protinfo.af_atm; - memset(&vcc->flags,0,sizeof(vcc->flags)); + if(!vcc) return NULL; + memset(&vcc->flags,0,sizeof(vcc->flags)); vcc->dev = NULL; - vcc->family = sock->ops->family; + vcc->family = family; vcc->alloc_tx = alloc_tx; vcc->callback = NULL; memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); @@ -117,19 +125,30 @@ init_waitqueue_head(&vcc->sleep); skb_queue_head_init(&vcc->recvq); skb_queue_head_init(&vcc->listenq); + + + return vcc; +} + +int atm_create(struct socket *sock,int protocol,int family) +{ + struct sock *sk; + struct atm_vcc *vcc; + + sock->sk = NULL; + if (sock->type == SOCK_STREAM) return -EINVAL; + if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; + vcc = sk->protinfo.af_atm; + atm_create_vcc(vcc,family); sk->sleep = &vcc->sleep; sock->sk = sk; return 0; } - -void atm_release_vcc_sk(struct sock *sk,int free_sk) -{ - struct atm_vcc *vcc; +void atm_release_vcc(struct atm_vcc *vcc) { struct sk_buff *skb; - vcc = sk->protinfo.af_atm; - clear_bit(ATM_VF_READY,&vcc->flags); + clear_bit(ATM_VF_READY,&vcc->flags); if (vcc->dev) { if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ @@ -145,6 +164,14 @@ atomic_read(&vcc->rx_inuse)); bind_vcc(vcc,NULL); } +} + +void atm_release_vcc_sk(struct sock *sk,int free_sk) +{ + struct atm_vcc *vcc; + + vcc = sk->protinfo.af_atm; + atm_release_vcc(vcc); if (free_sk) free_atm_vcc_sk(sk); } @@ -221,7 +248,12 @@ vcc->qos.aal = ATM_AAL5; /* fall through */ case ATM_AAL5: - error = atm_init_aal5(vcc); +#ifdef CONFIG_MPLS + if (test_bit(ATM_VF_MPLS,&vcc->flags)) + error = atm_init_mpls(vcc); + else +#endif + error = atm_init_aal5(vcc); vcc->stats = &dev->stats.aal5; break; default: diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/core/dev.c linux-kernel-mpls/net/core/dev.c --- linux-2.4.0-test11.clean/net/core/dev.c Mon Nov 27 13:26:05 2000 +++ linux-kernel-mpls/net/core/dev.c Mon Nov 27 13:39:22 2000 @@ -704,6 +704,9 @@ * ... and announce new interface. */ notifier_call_chain(&netdev_chain, NETDEV_UP, dev); +#ifdef CONFIG_MPLS + dev->mpls_labelspace = -1; +#endif } return(ret); } @@ -790,6 +793,9 @@ * Tell people we are down */ notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); +#ifdef CONFIG_MPLS + dev->mpls_labelspace = -1; +#endif /* * Drop the module refcount @@ -2121,7 +2127,7 @@ and requires shared lock, because it sleeps writing to user space. */ - + if (cmd == SIOCGIFCONF) { rtnl_shlock(); ret = dev_ifconf((char *) arg); @@ -2702,6 +2708,32 @@ net_device_init(); return 0; +} + +struct packet_type *find_packet_type(unsigned short type) { + struct packet_type *ptype, *pt_prev = NULL; + struct packet_type *new_pt = NULL; + +/* JLEU I need to find a better way to do this */ + + br_read_lock(BR_NETPROTO_LOCK); + for(ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { + // printk("find_packet_type: %08x <=> %08x\n",type,ptype->type); + if(ptype->type == type) { + if(pt_prev) { + new_pt = pt_prev; + goto find_packet_type_done; + } + } + pt_prev = ptype; + } + if(pt_prev) { + new_pt = pt_prev; + } +find_packet_type_done: + br_read_unlock(BR_NETPROTO_LOCK); + + return new_pt; } #ifdef CONFIG_HOTPLUG diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/core/neighbour.c linux-kernel-mpls/net/core/neighbour.c --- linux-2.4.0-test11.clean/net/core/neighbour.c Mon Nov 27 13:26:05 2000 +++ linux-kernel-mpls/net/core/neighbour.c Mon Nov 27 13:39:21 2000 @@ -953,7 +953,7 @@ if (dev->hard_header_cache && dst->hh == NULL) { write_lock_bh(&neigh->lock); if (dst->hh == NULL) - neigh_hh_init(neigh, dst, dst->ops->protocol); + neigh_hh_init(neigh, dst, skb->protocol); err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len); write_unlock_bh(&neigh->lock); } else { diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/core/skbuff.c linux-kernel-mpls/net/core/skbuff.c --- linux-2.4.0-test11.clean/net/core/skbuff.c Mon Nov 27 13:26:05 2000 +++ linux-kernel-mpls/net/core/skbuff.c Mon Nov 27 13:39:22 2000 @@ -197,6 +197,12 @@ /* Load the data pointers. */ skb->head = data; skb->data = data; +#ifdef CONFIG_MPLS + skb->mpls_gap = 0; +#ifdef CONFIG_MPLS_INGRESS_POLICING + skb->mpls_index = 0; +#endif +#endif skb->tail = data; skb->end = data + size; @@ -246,6 +252,12 @@ #endif memset(skb->cb, 0, sizeof(skb->cb)); skb->priority = 0; +#ifdef CONFIG_MPLS + skb->mpls_gap = 0; +#ifdef CONFIG_MPLS_INGRESS_POLICING + skb->mpls_index = 0; +#endif +#endif } /* @@ -339,7 +351,7 @@ return n; } -static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) +void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) { /* * Shift between the two data areas in bytes @@ -376,6 +388,12 @@ #ifdef CONFIG_NET_SCHED new->tc_index = old->tc_index; #endif +#ifdef CONFIG_MPLS + new->mpls_gap = old->mpls_gap; +#ifdef CONFIG_MPLS_INGRESS_POLICING + new->mpls_index = old->mpls_index; +#endif +#endif } /** @@ -476,6 +494,24 @@ kmem_add_cache_size(mtu); } #endif + +void skb_dump(struct sk_buff* sk) { + unsigned int i; + + printk("skb_dump: from %s with len %d (%d) headroom=%d tailroom=%d\n", + sk->rx_dev?sk->rx_dev->name:"ip stack",sk->len,sk->truesize, + skb_headroom(sk),skb_tailroom(sk)); + + for(i=(unsigned int)sk->head;i<=(unsigned int)sk->tail;i++) { + if(i==(unsigned int)sk->data) printk("{"); + if(i==(unsigned int)sk->h.raw) printk("#"); + if(i==(unsigned int)sk->nh.raw) printk("|"); + if(i==(unsigned int)sk->mac.raw) printk("*"); + printk("%02x",*((unsigned char*)i)); + if(i==(unsigned int)sk->tail) printk("}"); + } + printk("\n"); +} void __init skb_init(void) { diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/ipv4/af_inet.c linux-kernel-mpls/net/ipv4/af_inet.c --- linux-2.4.0-test11.clean/net/ipv4/af_inet.c Mon Nov 27 13:26:13 2000 +++ linux-kernel-mpls/net/ipv4/af_inet.c Mon Nov 27 13:39:31 2000 @@ -113,6 +113,9 @@ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) #include /* Note : will define WIRELESS_EXT */ #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ +#ifdef CONFIG_MPLS +#include +#endif #define min(a,b) ((a)<(b)?(a):(b)) @@ -912,6 +915,11 @@ if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) return(dev_ioctl(cmd,(void *) arg)); #endif /* WIRELESS_EXT */ + +#ifdef CONFIG_MPLS + if((cmd >= SIOCMPLSFIRST) && (cmd <= SIOCMPLSLAST)) + return(mpls_ioctl(cmd,(void *) arg)); +#endif /* CONFIG_MPLS */ if (sk->prot->ioctl==NULL || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD) return(dev_ioctl(cmd,(void *) arg)); diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/ipv4/devinet.c linux-kernel-mpls/net/ipv4/devinet.c --- linux-2.4.0-test11.clean/net/ipv4/devinet.c Mon Nov 27 13:26:10 2000 +++ linux-kernel-mpls/net/ipv4/devinet.c Mon Nov 27 13:39:27 2000 @@ -53,6 +53,9 @@ #ifdef CONFIG_KMOD #include #endif +#ifdef CONFIG_MPLS +#include +#endif #include #include @@ -964,6 +967,47 @@ { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, +#endif +#ifdef CONFIG_MPLS + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + { NULL, NULL, }, + + { mpls_rtm_newnhlfe, NULL, }, + { mpls_rtm_delnhlfe, NULL, }, + { mpls_rtm_getnhlfe, mpls_dump_nhlfe, }, + { NULL, NULL, }, + + { mpls_rtm_newilm, NULL, }, + { mpls_rtm_delilm, NULL, }, + { mpls_rtm_getilm, mpls_dump_ilm, }, + { NULL, NULL, }, + + { mpls_rtm_newxc, NULL, }, + { mpls_rtm_delxc, NULL, }, + { mpls_rtm_getxc, mpls_dump_xc, }, + { NULL, NULL, }, + + { mpls_rtm_newftn, NULL, }, + { mpls_rtm_delftn, NULL, }, + { mpls_rtm_getftn, mpls_dump_ftn, }, + { NULL, NULL, }, + + { mpls_rtm_set_out_instr, NULL, }, + { mpls_rtm_get_out_instr, NULL, }, + { mpls_rtm_set_in_instr, NULL, }, + { mpls_rtm_get_in_instr, NULL, }, #endif }; diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/ipv4/fib_hash.c linux-kernel-mpls/net/ipv4/fib_hash.c --- linux-2.4.0-test11.clean/net/ipv4/fib_hash.c Mon Nov 27 13:26:10 2000 +++ linux-kernel-mpls/net/ipv4/fib_hash.c Mon Nov 27 13:39:28 2000 @@ -75,6 +75,7 @@ u8 fn_type; u8 fn_scope; u8 fn_state; + void *fn_proto_data[NUM_AUX_PROTO_DATA]; }; #define FN_S_ZOMBIE 1 @@ -265,6 +266,86 @@ return fz; } +static struct fib_node * +fn_hash_lookup_exact(struct fib_table *tb, const struct rt_key *key, struct fib_result *res) +{ + struct fn_hash *t = (struct fn_hash*)tb->tb_data; + int z = res->prefixlen; + struct fn_zone *fz; + struct fib_node *f; + fn_key_t k; + int err; + + FTprint("fn_hash_lookup_exact: enter %08x/%d\n",key->dst,z); + + if(z>32 || ((fz=t->fn_zones[z])==NULL) || ((key->dst&~FZ_MASK(fz)))) + goto exact_out; + + k = fz_key(key->dst, fz); + + for (f = fz_chain(k, fz); f; f = f->fn_next) { + if (!fn_key_eq(k, f->fn_key)) { + if (fn_key_leq(k, f->fn_key)) + break; + else + continue; + } +#ifdef CONFIG_IP_ROUTE_TOS + if (f->fn_tos && f->fn_tos != key->tos) + continue; +#endif + f->fn_state |= FN_S_ACCESSED; + + if (f->fn_state&FN_S_ZOMBIE) + continue; + if (f->fn_scope < key->scope) + continue; + + err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res); + if (err == 0) { + FTprint("found %08x/%d\n",fz_prefix(k,fz),z); + return f; + } + if (err < 0) + goto exact_out; + } +exact_out: + + return NULL; +} + +static int +fn_hash_add_proto_data(struct fib_table *tb, const struct rt_key *key, struct fib_result *res,int proto_num) { + struct fib_node *f = NULL; + int result = 1; + + FTprint("fn_hash_add_proto_data: enter\n"); + + read_lock(&fib_hash_lock); + f = fn_hash_lookup_exact(tb,key,res); + read_unlock(&fib_hash_lock); + + if(f) { + FTprint("setting proto data[%d] (%p) in FIB_NODE\n", + proto_num, res->proto_data[proto_num]); + +#if 0 + if(res->proto_data[proto_num] == NULL) { + if(f->fn_proto_data[proto_num]) + mpls_out_info_release(f->fn_mpls_label); + } else { + mpls_out_info_hold(f->fn_mpls_label); + } +#endif + + f->fn_proto_data[proto_num] = res->proto_data[proto_num]; + rt_cache_flush(0); + result = 0; + } + FTprint("fn_hash_add_proto_data: exit\n"); + return result; +} + static int fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res) { @@ -297,9 +378,14 @@ err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res); if (err == 0) { + int i; res->type = f->fn_type; res->scope = f->fn_scope; res->prefixlen = fz->fz_order; + + for(i=0;iproto_data[i] = f->fn_proto_data[i]; + goto out; } if (err < 0) @@ -920,6 +1006,7 @@ tb->tb_delete = fn_hash_delete; tb->tb_flush = fn_hash_flush; tb->tb_select_default = fn_hash_select_default; + tb->tb_add_proto_data = fn_hash_add_proto_data; #ifdef CONFIG_RTNETLINK tb->tb_dump = fn_hash_dump; #endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/ipv4/fib_rules.c linux-kernel-mpls/net/ipv4/fib_rules.c --- linux-2.4.0-test11.clean/net/ipv4/fib_rules.c Mon Nov 27 13:26:10 2000 +++ linux-kernel-mpls/net/ipv4/fib_rules.c Mon Nov 27 13:39:28 2000 @@ -289,9 +289,12 @@ } } -int fib_lookup(const struct rt_key *key, struct fib_result *res) +#define FIB_LOOKUP 1 +#define FIB_ADD_PROTO_DATA 2 + +static int fib_execute(const struct rt_key *key, struct fib_result *res,int proto_num, int cmd) { - int err; + int err = -ENETUNREACH; struct fib_rule *r, *policy; struct fib_table *tb; @@ -333,7 +336,14 @@ if ((tb = fib_get_table(r->r_table)) == NULL) continue; - err = tb->tb_lookup(tb, key, res); + switch(cmd) { + case FIB_LOOKUP: + err = tb->tb_lookup(tb, key, res); + break; + case FIB_ADD_PROTO_DATA: + err = tb->tb_add_proto_data(tb, key, res, proto_num); + break; + } if (err == 0) { res->r = policy; if (policy) @@ -349,6 +359,16 @@ FRprintk("FAILURE\n"); read_unlock(&fib_rules_lock); return -ENETUNREACH; +} + +int fib_add_proto_data(const struct rt_key *key, struct fib_result *res,int proto_num) +{ + return fib_execute(key,res,proto_num,FIB_ADD_PROTO_DATA); +} + +int fib_lookup(const struct rt_key *key, struct fib_result *res) +{ + return fib_execute(key,res,0,FIB_LOOKUP); } void fib_select_default(const struct rt_key *key, struct fib_result *res) diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/ipv4/route.c linux-kernel-mpls/net/ipv4/route.c --- linux-2.4.0-test11.clean/net/ipv4/route.c Mon Nov 27 13:26:13 2000 +++ linux-kernel-mpls/net/ipv4/route.c Mon Nov 27 13:39:31 2000 @@ -97,6 +97,10 @@ #include #endif +#ifdef CONFIG_MPLS +#include +#endif + #define IP_MAX_MTU 0xFFF0 #define RT_GC_TIMEOUT (300*HZ) @@ -1117,7 +1121,7 @@ } #endif -static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) +void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) { struct fib_info *fi = res->fi; @@ -1135,6 +1139,41 @@ #ifdef CONFIG_NET_CLS_ROUTE rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid; #endif +#ifdef CONFIG_MPLS + /* + * JLEU: we need to do this here because both + * ip_route_output_slow() and ip_route_output_slow() + * us this to finish the next hop calculations + * + */ + if(res->proto_data[AUX_PROTO_DATA_MPLS]) { + struct mpls_out_info *moi; + int i; + + MPLS_DEBUG(("rt_set_nexthop: adding label to dst\n")); + MPLS_DEBUG(("rt_set_nexthop: before - mtu = %d\n", + rt->u.dst.pmtu)); + rt->u.dst.output = mpls_output; + rt->u.dst.dst_proto_data[AUX_PROTO_DATA_MPLS] = + res->proto_data[AUX_PROTO_DATA_MPLS]; + moi = res->proto_data[AUX_PROTO_DATA_MPLS]; +mpls_again: + for(i=0;imoi_instruction_length;i++) { + switch(moi->moi_instruction[i].mi_opcode) { + case MPLS_OP_FWD: + moi = (struct mpls_out_info*) + moi->moi_instruction[i].mi_data; + goto mpls_again; + break; + case MPLS_OP_PUSH: + rt->u.dst.pmtu -= 4; + break; + } + } + MPLS_DEBUG(("rt_set_nexthop: after - mtu = %d\n", + rt->u.dst.pmtu)); + } +#endif } else { rt->u.dst.pmtu = rt->u.dst.dev->mtu; } @@ -1413,7 +1452,7 @@ rth->rt_spec_dst= spec_dst; rth->u.dst.input = ip_forward; - rth->u.dst.output = ip_output; + rth->u.dst.output = ip_finish_output; rt_set_nexthop(rth, &res, itag); diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/Makefile linux-kernel-mpls/net/mpls/Makefile --- linux-2.4.0-test11.clean/net/mpls/Makefile Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/Makefile Mon Nov 27 13:39:10 2000 @@ -0,0 +1,27 @@ +# +# Makefile for the Linux MPLS layer. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + + +O_TARGET := mpls.o +MPLS_OBJS := mpls_if.o mpls_in_info.o mpls_init.o mpls_input.o \ + mpls_ioctls.o mpls_netlink.o mpls_opcode.o mpls_out_info.o \ + mpls_output.o mpls_proc.o mpls_ref.o mpls_utils.o + +ifeq ($(CONFIG_ATM),y) +MPLS_OBJS += mpls_atm.o +endif + +ifeq ($(CONFIG_MPLS_TUNNEL),y) +MPLS_OBJS += mpls_tunnel.o +endif + +M_OBJS := $(O_TARGET) + +O_OBJS := $(MPLS_OBJS) + +include $(TOPDIR)/Rules.make diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_atm.c linux-kernel-mpls/net/mpls/mpls_atm.c --- linux-2.4.0-test11.clean/net/mpls/mpls_atm.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_atm.c Tue Nov 28 12:23:18 2000 @@ -0,0 +1,122 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -Hooks for ATM labels + * + * Authors: James R. Leu, + * + * Fixes: + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +extern void atm_release_vcc(struct atm_vcc*); +extern struct atm_vcc *atm_create_vcc(struct atm_vcc*,int); +extern int atm_connect_vcc(struct atm_vcc*,int,short,int); + +extern struct packet_type mpls_uc_pt; + +void mpls_atm_push(struct atm_vcc *vcc,struct sk_buff *skb) { + const char *fn_name = "mpls_atm_push"; + MPLS_DEBUG(("%s: enter\n",fn_name)); + skb->dev = (struct net_device*)vcc->user_back; + skb->nh.raw = skb->data; + ATM_SKB(skb)->vcc = vcc; + dev_hold(skb->dev); + mpls_rcv(skb,skb->dev,&mpls_uc_pt); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void mpls_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb) { + const char *fn_name = "mpls_atm_pop"; + MPLS_DEBUG(("%s: enter\n",fn_name)); + MPLS_DEBUG(("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize)); + atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); + dev_kfree_skb_any(skb); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +int mpls_atm_vcc_delete(struct atm_vcc *vcc) { + int result = -1; + + if(vcc) { + atm_release_vcc(vcc); + result = 0; + } + return result; +} + +struct atm_vcc *mpls_atm_create_vcc(struct net_device *dev,int vpi,int vci, + int flag) { + const char *fn_name = "mpls_atm_create_vcc"; + struct atm_vcc *vcc = NULL; + + MPLS_DEBUG(("%s: enter(%d,%d,%d,%d)\n",fn_name,dev->iflink,vpi,vci,flag)); + + if(dev->iflink >= 0 && + vci < ATM_MAX_VCI && vci >= 0 && + vpi < ATM_MAX_VPI && vpi >= 0) { + MPLS_DEBUG(("%s: create_vcc\n",fn_name)); + vcc = atm_create_vcc(NULL,PF_ATMPVC); + } + if(vcc) { + vcc->vpi = vpi; + vcc->vci = vci; + vcc->itf = (short )simple_strtoul(&(dev->name[strlen(dev->name)-1]), NULL, 10); + vcc->user_back = (void*)dev; + + vcc->qos.txtp.traffic_class = ATM_NONE; + vcc->qos.rxtp.traffic_class = ATM_NONE; + vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU; + vcc->qos.rxtp.max_sdu = ATM_MAX_AAL5_PDU; + vcc->qos.aal = ATM_AAL5; + + if(flag & MPLS_ATM_VCC_RX) { + vcc->qos.rxtp.traffic_class = ATM_UBR; + } + if(flag & MPLS_ATM_VCC_TX) { + vcc->qos.txtp.traffic_class = ATM_UBR; + } + set_bit(ATM_VF_HASQOS,&vcc->flags); + set_bit(ATM_VF_MPLS,&vcc->flags); + + MPLS_DEBUG(("%s: setting up vcc\n",fn_name)); + + if(atm_connect_vcc(vcc,vcc->itf,vcc->vpi,vcc->vci)<0) { + MPLS_DEBUG(("%s: connect failed\n",fn_name)); + atm_release_vcc(vcc); + kfree(vcc); + vcc = NULL; + } + } + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return vcc; +} + +int atm_init_mpls(struct atm_vcc *vcc) +{ + vcc->push = mpls_atm_push; + vcc->pop = mpls_atm_pop; + vcc->push_oam = NULL; + vcc->send = vcc->dev->ops->send; + return 0; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_if.c linux-kernel-mpls/net/mpls/mpls_if.c --- linux-2.4.0-test11.clean/net/mpls/mpls_if.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_if.c Mon Nov 27 13:39:11 2000 @@ -0,0 +1,70 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -interface specific settings for MPLS + * + * Authors: James R. Leu, + * + * Fixes: + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include + +int mpls_get_labelspace(struct mpls_labelspace_req *req) { + const char *fn_name = "mpls_get_labelspace"; + int ifindex; + int labelspace; + struct net_device *dev; + int result = -1; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + copy_from_user(&ifindex,&(req->mls_ifindex),sizeof(int)); + + dev = dev_get_by_index(ifindex); + if(dev) { + labelspace = dev->mpls_labelspace; + copy_to_user(&(req->mls_labelspace),&labelspace,sizeof(int)); + result = 0; + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return result; +} + +int mpls_set_labelspace(struct mpls_labelspace_req *req) { + const char *fn_name = "mpls_set_labelspace"; + int ifindex; + int labelspace; + struct net_device *dev; + int result = -1; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + copy_from_user(&ifindex,&(req->mls_ifindex),sizeof(int)); + copy_from_user(&labelspace,&(req->mls_labelspace),sizeof(int)); + + MPLS_DEBUG(("%s: labelspace(%d)\n",fn_name,labelspace)); + if((dev = dev_get_by_index(ifindex))) { + dev->mpls_labelspace = labelspace; + result = 0; + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return result; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_in_info.c linux-kernel-mpls/net/mpls/mpls_in_info.c --- linux-2.4.0-test11.clean/net/mpls/mpls_in_info.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_in_info.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,414 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -add/get/del/flush for the in label tree + * -binding in labels to out labels + * + * Authors: James R. Leu, + * + * + * Additions: + * 06/19/2000 - Philip Quiney + James R. Leu - label stacking + * 11/13/2000 - James R. Leu - Converted to use Netlink vs. IOCTLs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include /* must be before route.h */ +#include /* must be before route.h */ +#include /* must be before route.h */ +#include +#ifdef CONFIG_ATM +#include +#endif + +struct mpls_in_info_tree mii_tree; +extern struct mpls_out_info_tree moi_tree; + +int mpls_info_default_in_instruction(struct mpls_in_info *mii) { + const char *fn_name = "mpls_info_default_in_instruction"; + int retval = -ENXIO; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(mii) { + mii->mii_instruction[0].mi_opcode = MPLS_OP_POP; + mii->mii_instruction[0].mi_data = 0; + + mii->mii_instruction[1].mi_opcode = MPLS_OP_DLV; + mii->mii_instruction[1].mi_data = 0; + + mii->mii_instruction_length = 2; + retval = 0; + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_set_in_label_instructions(struct mpls_instruction_req *in) { + const char *fn_name = "mpls_set_in_label_instructions"; + struct mpls_instruction instruction[MPLS_NUM_OPS]; + struct mpls_in_info *mii = NULL; + struct mpls_instruction_req mir; + unsigned int key = 0; + int retval = -ENXIO; + int length = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(in) { + memcpy(&mir,in,sizeof(struct mpls_instruction_req)); + + if(mir.mir_direction != MPLS_IN) { + MPLS_DEBUG(("%s: invalid direction\n",fn_name)); + goto mpls_set_in_label_instructions_cleanup; + } + + key = mpls_label2key(mir.mir_index,&mir.mir_label); + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval || !mii) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + goto mpls_set_in_label_instructions_cleanup; + } + + length = mpls_instruction_build(&mir,instruction,MPLS_NUM_OPS); + if(length > 0) { + mpls_instruction_clear(mii->mii_instruction,mii->mii_instruction_length); + mpls_instruction_copy(mii->mii_instruction,instruction,length); + mii->mii_instruction_length = length; + rt_cache_flush(0); + } + } + +mpls_set_in_label_instructions_cleanup: + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_add_in_label(struct mpls_in_label_req *in) { + const char *fn_name = "mpls_add_in_label"; + struct mpls_in_info *mii = NULL, *mii_out = NULL; + unsigned int key = 0; +#ifdef CONFIG_ATM + struct atm_vcc *vcc = NULL; +#endif + int retval = -ENXIO; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(in) { + mii = (struct mpls_in_info*)kmalloc(sizeof(struct mpls_in_info),GFP_ATOMIC); + if(!mii) { + retval = -ENOMEM; + goto mpls_add_in_label_cleanup; + } + + memset(mii,0,sizeof(struct mpls_in_info)); + mpls_in_info_hold(mii); + + memcpy(&(mii->mii_label),&(in->mil_label),sizeof(struct mpls_label)); + mii->mii_labelspace = in->mil_labelspace; + mii->mii_age = jiffies; + mii->mii_proto = __constant_htons(ETH_P_IP); + mpls_info_default_in_instruction(mii); +#ifdef CONFIG_ATM + if(mii->mii_label.ml_type == MPLS_LABEL_ATM) { + struct net_device *dev; + if(!(dev = mpls_dev_by_labelspace(mii->mii_labelspace))) { + printk("%s: couldn't find interface with labelspace %d\n", + fn_name,mii->mii_labelspace); + goto mpls_add_in_label_cleanup; + } + + vcc = mpls_atm_create_vcc(dev,mii->mii_label.u.ml_atm.mla_vpi, + mii->mii_label.u.ml_atm.mla_vci,MPLS_ATM_VCC_RX); + + if(vcc) { + printk("%s: succeeded creating vcc\n",fn_name); + mii->mii_vcc = vcc; + } else { + printk("%s: failed creating vcc\n",fn_name); + goto mpls_add_in_label_cleanup; + } + } +#endif + + key = mpls_label2key(mii->mii_labelspace,&(mii->mii_label)); + mii->mii_key = key; + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii_out,retval); + if(!retval && mii_out) { + MPLS_DEBUG(("%s: error node already exists\n",fn_name)); + retval = -ESRCH; + goto mpls_add_in_label_cleanup; + } + if(retval) { + RADIX_INSERT(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,retval); + if(retval) { + MPLS_DEBUG(("%s: error create node in radix tree\n",fn_name)); + retval = -ENOMEM; + goto mpls_add_in_label_cleanup; + } + } + + RADIX_SET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval) { + MPLS_DEBUG(("%s: error setting node in radix tree\n",fn_name)); + retval = -ENOENT; + goto mpls_add_in_label_cleanup; + } + + /* we only make it here if everything succeeds */ + mii = NULL; + retval = 0; + } + +mpls_add_in_label_cleanup: + if(mii) mpls_in_info_release(mii); + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_get_in_label(struct mpls_in_label_req *in) { + const char *fn_name = "mpls_get_in_label"; + struct mpls_in_info *mii = NULL; + struct mpls_label label; + unsigned int labelspace; + int retval = -ENXIO; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(in) { + memcpy(&label,&(in->mil_label),sizeof(struct mpls_label)); + labelspace = in->mil_labelspace; + + key = mpls_label2key(labelspace,&label); + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval || !mii) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + goto mpls_get_in_label_cleanup; + } + memcpy(&(in->mil_label),&(mii->mii_label),sizeof(struct mpls_label)); + in->mil_age = mii->mii_age; + in->mil_labelspace = mii->mii_labelspace; + + retval = 0; + } + +mpls_get_in_label_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +void __mpls_del_in_label(struct mpls_in_info *mii) { + const char *fn_name = "__mpls_del_in_label"; + int i; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + for(i=0;imii_instruction_length;i++) { + if(mii->mii_instruction[i].mi_opcode == MPLS_OP_FWD) { + mpls_out_info_release((struct mpls_out_info*)(mii->mii_instruction[i].mi_data)); + } + } +#ifdef CONFIG_ATM + if(mii->mii_vcc) { + mpls_atm_vcc_delete(mii->mii_vcc); + } +#endif + kfree(mii); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +int mpls_del_in_label(struct mpls_in_label_req *in) { + const char *fn_name = "mpls_del_in_label"; + struct mpls_in_info *mii = NULL; + struct mpls_label label; + unsigned int labelspace; + int retval = -ENXIO; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(in) { + memcpy(&label,&(in->mil_label),sizeof(struct mpls_label)); + labelspace = in->mil_labelspace; + + key = mpls_label2key(labelspace,&label); + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval || !mii) { + MPLS_DEBUG(("%s: no such entry\n",fn_name)); + retval = -ESRCH; + goto mpls_del_in_label_cleanup; + } + + memcpy(&(in->mil_label),&(mii->mii_label),sizeof(struct mpls_label)); + in->mil_age = mii->mii_age; + in->mil_labelspace = mii->mii_labelspace; + + mpls_in_info_release(mii); + + mii = NULL; + RADIX_SET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval) { + MPLS_DEBUG(("%s: error setting to NULL\n",fn_name)); + retval = -ENOENT; + goto mpls_del_in_label_cleanup; + } + } + +mpls_del_in_label_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_attach_in2out(struct mpls_xconnect_req *req) { + const char *fn_name = "mpls_attach_in2out"; + struct mpls_in_info *mii; + struct mpls_out_info *moi; + struct mpls_label in,out; + int retval = -ENXIO; + int labelspace; + int ifindex; + int key; + int len = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + memcpy(&in,&(req->mx_in),sizeof(struct mpls_label)); + memcpy(&out,&(req->mx_out),sizeof(struct mpls_label)); + labelspace = req->mx_ilabelspace; + ifindex = req->mx_oifindex; + + key = mpls_label2key(labelspace,&in); + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval || !mii) { + MPLS_DEBUG(("%s: no incoming entry\n",fn_name)); + retval = -ESRCH; + goto mpls_attach_in2out_cleanup; + } + + key = mpls_label2key(ifindex,&out); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + MPLS_DEBUG(("%s: no outgoing entry\n",fn_name)); + retval = -ESRCH; + goto mpls_attach_in2out_cleanup; + } + + len = mii->mii_instruction_length - 1; + if(mii->mii_instruction[len].mi_opcode == MPLS_OP_DLV || + mii->mii_instruction[len].mi_opcode == MPLS_OP_FWD) { + + if(mii->mii_instruction[len].mi_opcode == MPLS_OP_FWD) { + mpls_out_info_release( + (struct mpls_out_info*)mii->mii_instruction[len].mi_data); + } + if(mii->mii_instruction[len].mi_opcode == MPLS_OP_DLV) { + mii->mii_instruction[len].mi_opcode = MPLS_OP_FWD; + } + mpls_out_info_hold(moi); + mii->mii_instruction[len].mi_data = (unsigned int)moi; + } + } + retval = 0; + +mpls_attach_in2out_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_detach_in2out(struct mpls_xconnect_req *req) { + const char *fn_name = "mpls_detach_in2out"; + struct mpls_in_info *mii; + struct mpls_out_info *moi; + struct mpls_label in,out; + int retval = -ENXIO; + int labelspace; + int ifindex; + int key = 0; + int len = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + memcpy(&in,&(req->mx_in),sizeof(struct mpls_label)); + memcpy(&out,&(req->mx_out),sizeof(struct mpls_label)); + labelspace = req->mx_ilabelspace; + ifindex = req->mx_oifindex; + + key = mpls_label2key(labelspace,&in); + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval || !mii) { + MPLS_DEBUG(("%s: no incoming entry\n",fn_name)); + retval = -ESRCH; + goto mpls_detach_in2out_cleanup; + } + + key = mpls_label2key(ifindex,&out); + len = mii->mii_instruction_length - 1; + if(mii->mii_instruction[len].mi_opcode == MPLS_OP_FWD) { + moi = (struct mpls_out_info*)mii->mii_instruction[len].mi_data; + if(key == moi->moi_key) { + mii->mii_instruction[len].mi_opcode = MPLS_OP_DLV; + mpls_out_info_release(moi); + mii->mii_instruction[len].mi_data = 0; + } else { + goto mpls_detach_in2out_cleanup; + } + } else { + goto mpls_detach_in2out_cleanup; + } + } + retval = 0; + +mpls_detach_in2out_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +static int mpls_del_in_info_node(struct mpls_in_info_node *mii_node,void *d) { + const char *fn_name = "mpls_del_in_info_node"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(mii_node->mii) mpls_in_info_release(mii_node->mii); + kfree(mii_node); + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +void mpls_flush_in_tree(void) { + const char *fn_name = "mpls_flush_in_tree"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + RADIX_VISIT_ALL(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS, + mpls_del_in_info_node,NULL); + RADIX_INIT(&mii_tree); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_init.c linux-kernel-mpls/net/mpls/mpls_init.c --- linux-2.4.0-test11.clean/net/mpls/mpls_init.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_init.c Tue Nov 28 12:24:23 2000 @@ -0,0 +1,72 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -packet handler for type ETH_P_MPLS_UC + * + * Authors: James R. Leu, + * + * + * Additions: + * 02/28/2000 added MPLS Tunnel Interfaces + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +extern struct mpls_in_info_tree mii_tree; +extern struct mpls_out_info_tree moi_tree; +int mpls_debug; +struct packet_type mpls_uc_pt; + +static int __init mpls_init(void) { + + printk("MPLS version 0.700 11/28/2000 jleu@mindspring.com\n"); + + mpls_uc_pt.type = __constant_htons(ETH_P_MPLS_UC); + mpls_uc_pt.dev = NULL; /* ? */ + mpls_uc_pt.func = mpls_rcv; + mpls_uc_pt.data = NULL; + dev_add_pack(&mpls_uc_pt); + +#ifdef CONFIG_MPLS_TUNNEL + mpls_tunnel_init(); +#endif + + RADIX_INIT(&mii_tree); + RADIX_INIT(&moi_tree); + +/* + pt = (struct packet_type*)kmalloc(sizeof(struct packet_type),GFP_KERNEL); + pt->type = __constant_htons(ETH_P_MPLS_MC); + pt->dev = NULL; + pt->func = mpls_rcv_mc; + pt->data = NULL; + dev_add_pack(pt); +*/ + +#ifdef CONFIG_PROC_FS + proc_net_create("mpls_in", 0, mpls_in_label_info); + proc_net_create("mpls_out", 0, mpls_out_label_info); + proc_net_create("mpls_labelspace", 0, mpls_labelspace_info); + proc_net_create("mpls_fec", 0, mpls_fec_info); +#endif + + return 0; +} +module_init(mpls_init); diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_input.c linux-kernel-mpls/net/mpls/mpls_input.c --- linux-2.4.0-test11.clean/net/mpls/mpls_input.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_input.c Mon Nov 27 13:58:43 2000 @@ -0,0 +1,330 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -functions that will receive an MPLS packet from the network + * and begin is path through the network stack + * + * Authors: James R. Leu, + * + * Fixes: + * 2000-03-22 jleu, converted to the new mpls__info structures + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#ifdef CONFIG_IPV6 +#include +#endif +#include +#ifdef CONFIG_WAN +#include +#endif +#ifdef CONFIG_ATM +#include +#endif + +void mpls_finish(struct sk_buff *sk) { + const char *fn_name = "mpls_finish"; + unsigned int diff = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(sk->mpls_gap) + diff = sk->mpls_gap; + + if(diff > 0) { + memmove(sk->data - diff,sk->data,sk->len); + sk->data -= diff; + sk->mpls_gap = 0; + sk->h.raw -= diff; + sk->nh.raw -= diff; + } else { + if(diff < 0) + MPLS_DEBUG(("%s: data - data_old < 0\n",fn_name)); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +int mpls_input(struct sk_buff* sk,struct net_device* dev, + struct packet_type* pt,struct mpls_label *label,struct mpls_push_data *mpr, + int labelspace) { + const char *fn_name = "mpls_input"; + struct mpls_in_info *mii = NULL; + struct mpls_out_info *moi = NULL; + struct packet_type *new_pt = NULL; + unsigned int key; + char at_bottom = 0; + int retval,i = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + +mpls_input_start: + + MPLS_DEBUG(("%s: labelspace=%d,label=%d,exp=%01x,B.O.S=%d,TTL=%d\n", + fn_name,labelspace,mpr->label,mpr->exp,mpr->bos,mpr->ttl)); + +#ifdef CONFIG_MPLS_DEBUG + if(mpls_debug) skb_dump(sk); +#endif + + if(label->ml_type == MPLS_LABEL_GEN) { + switch(label->u.ml_gen) { + case MPLS_IPV4_EXPLICIT_NULL: + if(mpr->bos) { + goto mpls_input_ipv4; + } else { + kfree_skb(sk); + retval = -ENXIO; + goto mpls_input_end; + } + break; + case MPLS_ROUTER_ALERT: + MPLS_DEBUG(("%s: ROUTER ALERT!!!\n",fn_name)); + if(!mpr->bos) { + } else { + kfree_skb(sk); + retval = -ENXIO; + goto mpls_input_end; + } + break; +#ifdef CONFIG_IPV6 + case MPLS_IPV6_EXPLICIT_NULL: + if(mpr->bos) { + goto mpls_input_ipv6; + } else { + kfree_skb(sk); + retval = -ENXIO; + goto mpls_input_end; + } + break; +#endif + case MPLS_IMPLICIT_NULL: + MPLS_DEBUG(("%s: IMPLICIT NULL!!!\n",fn_name)); + kfree_skb(sk); + retval = -ENXIO; + goto mpls_input_end; + break; + } + } + + key = mpls_label2key(labelspace,label); + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + + if(retval || !mii) { + kfree_skb(sk); + MPLS_DEBUG(("%s: unknown incoming label, dropping\n",fn_name)); + retval = -ENXIO; + goto mpls_input_end; + } + + for(i=0;imii_instruction_length;i++) { + switch(mii->mii_instruction[i].mi_opcode) { + case MPLS_OP_NOP: + MPLS_DEBUG(("%s: nop\n",fn_name)); + break; + case MPLS_OP_POP: + MPLS_DEBUG(("%s: pop\n",fn_name)); + if(!at_bottom) { + if(mpr->bos) at_bottom = 1; + mpls_opcode_pop(sk); + } else { + MPLS_DEBUG(("%s: cannot pop label, at BOS\n",fn_name)); + } + break; + case MPLS_OP_PEEK: + if(at_bottom) goto mpls_input_dlv; + mpls_opcode_peek(sk,mpr); + label->ml_type = MPLS_LABEL_GEN; + label->u.ml_gen = mpr->label; + goto mpls_input_start; + break; + case MPLS_OP_PUSH: + MPLS_DEBUG(("%s: push\n",fn_name)); + mpls_opcode_push(&sk, + (struct mpls_label*)mii->mii_instruction[i].mi_data,mpr); + break; +#if 0 + case MPLS_OP_ROT: + MPLS_DEBUG(("%s: rot\n",fn_name)); + mpls_opcode_rot(sk,mii); + break; +#endif + case MPLS_OP_POPALL: + MPLS_DEBUG(("%s: popall\n",fn_name)); + while(!mpls_opcode_pop(sk)); + break; + case MPLS_OP_FWD: + moi = (struct mpls_out_info*)mii->mii_instruction[i].mi_data; + retval = mpls_output2(sk,moi,mpr); + break; + case MPLS_OP_SET: + sk->rx_dev = (struct net_device*)mii->mii_instruction[i].mi_data; + break; + case MPLS_OP_DLV: +mpls_input_dlv: + new_pt = find_packet_type(mii->mii_proto); + MPLS_DEBUG(("%s: mii_proto %d\n",fn_name,mii->mii_proto)); + if(!new_pt) { + MPLS_DEBUG(("%s: unsupported protocol\n",fn_name)); + kfree_skb(sk); + retval = -ENXIO; + goto mpls_input_end; + } + mpls_finish(sk); + sk->protocol = mii->mii_proto; + + switch(mii->mii_proto) { + case __constant_htons(ETH_P_IP): +mpls_input_ipv4: + sk->nh.iph->ttl = mpr->ttl; + MPLS_DEBUG(("%s: setting ttl %d\n",fn_name,mpr->ttl)); + ip_send_check(sk->nh.iph); + sk->ip_summed = CHECKSUM_NONE; + MPLS_DEBUG(("%s: sending to IPv4\n",fn_name)); + if(mpls_debug) skb_dump(sk); + retval = ip_rcv(sk,dev,new_pt); + MPLS_DEBUG(("%s: retval from ip_rcv %d\n",fn_name,retval)); + break; +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): +mpls_input_ipv6: + retval = ipv6_rcv(sk,dev,new_pt); + break; +#endif + default: + MPLS_DEBUG(("%s: unsupported protocol\n",fn_name)); + kfree_skb(sk); + retval = -ENXIO; + break; + } + } + } + MPLS_DEBUG(("%s: finished executing in label program\n",fn_name)); + +mpls_input_end: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_rcv(struct sk_buff* sk,struct net_device* dev,struct packet_type* pt) { + const char *fn_name = "mpls_rcv"; + int labelspace; + int result = -ENXIO; + struct mpls_label *label = NULL; + struct mpls_push_data *mpr = NULL; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + labelspace = dev->mpls_labelspace; + + mpr=(struct mpls_push_data*)kmalloc(sizeof(struct mpls_push_data),GFP_ATOMIC); + if(!mpr) { + kfree_skb(sk); + result = -ENOMEM; + goto mpls_rcv_3; + } + label = (struct mpls_label*)kmalloc(sizeof(struct mpls_label),GFP_ATOMIC); + if(!label) { + kfree_skb(sk); + result = -ENOMEM; + goto mpls_rcv_2; + } + + memset(mpr,0,sizeof(struct mpls_push_data)); + memset(label,0,sizeof(struct mpls_label)); + + if(labelspace < 0) { + printk("%s: MPLS unicast packet recv on interface w/o a labelspace\n", + fn_name); + kfree_skb(sk); + result = -ENODEV; + goto mpls_rcv_1; + } + + if(!(sk && sk->data && (sk->len >= sizeof(u32)))) { + kfree_skb(sk); + result = -ENOMEM; + goto mpls_rcv_1; + } + + mpls_opcode_peek(sk,mpr); + + switch(dev->type) { + case ARPHRD_ETHER: + case ARPHRD_FDDI: + case ARPHRD_IEEE802: + case ARPHRD_PPP: + case ARPHRD_LOOPBACK: + case ARPHRD_HDLC: + label->ml_type = MPLS_LABEL_GEN; + label->u.ml_gen = mpr->label; + break; +#ifdef CONFIG_WAN + case ARPHRD_DLCI: +#if 0 + label->ml_type = MPLS_LABEL_FR; + { + struct dlci_local *dlp = (struct dlci_local*)dev->priv; + struct frad_local *flp = (struct frad_local*)dlp->slave->priv; + int i; + + for(i=0;imaster[i] == dev) + break; + + if(i == CONFIG_DLCI_MAX) { + kfree_skb(sk); + result = -ENODEV; + goto mpls_rcv_1; + } + + label->u.ml_fr = flp->dlci[i]; + } +#endif + break; +#endif +#ifdef CONFIG_ATM + case ARPHRD_ATM: + label->ml_type = MPLS_LABEL_ATM; + { + struct atm_vcc *vcc = ATM_SKB(sk)->vcc; + label->u.ml_atm.mla_vpi = vcc->vpi; + label->u.ml_atm.mla_vci = vcc->vci; + } + break; +#endif + default: + printk("%s: unknown interface type(%08x) for MPLS\n",fn_name,dev->type); + kfree_skb(sk); + result = -ENODEV; + goto mpls_rcv_1; + } + /* JLEU: this would be a good spot to drop the frame into a MPLS BH queue */ + + result = mpls_input(sk,dev,pt,label,mpr,labelspace); + +mpls_rcv_1: + kfree(label); +mpls_rcv_2: + kfree(mpr); +mpls_rcv_3: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return result; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_ioctls.c linux-kernel-mpls/net/mpls/mpls_ioctls.c --- linux-2.4.0-test11.clean/net/mpls/mpls_ioctls.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_ioctls.c Mon Nov 27 13:39:11 2000 @@ -0,0 +1,65 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -IOCTLs which can be used from userland to create LSP + * through the network stack. + * + * Authors: James R. Leu, + * + * Additions: + * 11/13/2000 - James R. Leu - Most of the managment has been + * converted to use Netlink instead of IOCTLs + * + * Fixes: + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +int mpls_ioctl(unsigned int cmd,void *arg) { +#ifdef CONFIG_MPLS_TUNNEL + struct net_device *dev = NULL; +#endif + int retval = -ENOSYS; + + switch(cmd) { + case SIOCMPLSDEBUG: + if(mpls_debug) mpls_debug = 0; + else mpls_debug = 1; + retval = 0; + break; + case SIOCGLABELSPACEMPLS: + retval = mpls_get_labelspace((struct mpls_labelspace_req*)arg); + break; + case SIOCSLABELSPACEMPLS: + retval = mpls_set_labelspace((struct mpls_labelspace_req*)arg); + break; +#ifdef CONFIG_MPLS_TUNNEL + case SIOCMPLSTUNNELADD: + if(mpls_tunnel_locate((struct ifreq*)arg,1)) { + retval = 0; + } + break; + case SIOCMPLSTUNNELDEL: + if((dev = mpls_tunnel_locate((struct ifreq*)arg,0))) { + mpls_tunnel_unlink(dev); + retval = 0; + } + break; +#endif + } + return retval; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_netlink.c linux-kernel-mpls/net/mpls/mpls_netlink.c --- linux-2.4.0-test11.clean/net/mpls/mpls_netlink.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_netlink.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,208 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -netlink handlers which recv mgs from netlink sockets. These + * msgs contain info for configuring MPLS objects + * + * Authors: James R. Leu, + * + * Fixes: + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include + +int mpls_rtm_newnhlfe(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_out_label_req* o_req = NLMSG_DATA(nlh); + int retval = mpls_add_out_label(o_req); + return retval; +} + +int mpls_rtm_delnhlfe(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_out_label_req* o_req = NLMSG_DATA(nlh); + int retval = mpls_del_out_label(o_req); + return retval; +} + +int mpls_rtm_getnhlfe(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_out_label_req* o_req = NLMSG_DATA(nlh); + // case SIOCGETMPLSOUTPGRM: + int retval = mpls_get_out_label(o_req); + return retval; +} + +int mpls_dump_nhlfe(struct sk_buff *skb, struct netlink_callback *cb) { + printk("mpls_dump_nhlfe\n"); + return 0; +} + +int mpls_rtm_set_out_instr(struct sk_buff *skb, struct nlmsghdr* nlh, + void *arg) { + struct mpls_instruction_req* o_req = NLMSG_DATA(nlh); + int retval = mpls_set_out_label_instructions(o_req); + return retval; +} + +int mpls_rtm_get_out_instr(struct sk_buff *skb, struct nlmsghdr* nlh, + void *arg) { +/* + struct mpls_instruction_req* o_req = NLMSG_DATA(nlh); + int retval = mpls_set_out_label_instructions(o_req); + */ + return -ENOSYS; +} + +int mpls_rtm_newilm(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_in_label_req *i_req = NLMSG_DATA(nlh); + // int retval = mpls_set_in_label_instructions((struct mpls_instruction_req*)arg); + int retval = mpls_add_in_label(i_req); + printk("mpls_rtm_newilm\n"); + return retval; +} + +int mpls_rtm_delilm(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_in_label_req *i_req = NLMSG_DATA(nlh); + int retval = mpls_del_in_label(i_req); + printk("mpls_rtm_delilm\n"); + return retval; +} + +int mpls_rtm_getilm(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_in_label_req *i_req = NLMSG_DATA(nlh); + // case SIOCGETMPLSINPGRM: + int retval = mpls_get_in_label(i_req); + printk("mpls_rtm_getilm\n"); + return retval; +} + +int mpls_dump_ilm(struct sk_buff *skb, struct netlink_callback *cb) { + printk("mpls_dump_ilm\n"); + return 0; +} + +int mpls_rtm_set_in_instr(struct sk_buff *skb, struct nlmsghdr* nlh, + void *arg) { + struct mpls_instruction_req* i_req = NLMSG_DATA(nlh); + int retval = mpls_set_in_label_instructions(i_req); + return retval; +} + +int mpls_rtm_get_in_instr(struct sk_buff *skb, struct nlmsghdr* nlh, + void *arg) { +/* + struct mpls_instruction_req* i_req = NLMSG_DATA(nlh); + int retval = mpls_set_in_label_instructions(i_req); + */ + return -ENOSYS; +} + +int mpls_rtm_newxc(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_xconnect_req *x_req = NLMSG_DATA(nlh); + int retval = mpls_attach_in2out(x_req); + printk("mpls_rtm_newxc\n"); + return retval; +} + +int mpls_rtm_delxc(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_xconnect_req *x_req = NLMSG_DATA(nlh); + int retval = mpls_detach_in2out(x_req); + printk("mpls_rtm_delxc\n"); + return retval; +} + +int mpls_rtm_getxc(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + printk("mpls_rtm_getxc\n"); + return 0; +} + +int mpls_dump_xc(struct sk_buff *skb, struct netlink_callback *cb) { + printk("mpls_dump_xc\n"); + return 0; +} + +int mpls_rtm_newftn(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_bind_fec_req *f_req = NLMSG_DATA(nlh); + int retval = mpls_bind_out2fec(f_req); + printk("mpls_rtm_newftn\n"); + return retval; +} + +int mpls_rtm_delftn(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct mpls_bind_fec_req *f_req = NLMSG_DATA(nlh); + int retval = mpls_unbind_out2fec(f_req); + printk("mpls_rtm_delftn\n"); + return retval; +} + +int mpls_rtm_getftn(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + printk("mpls_rtm_getftn\n"); + return 0; +} + +int mpls_dump_ftn(struct sk_buff *skb, struct netlink_callback *cb) { + printk("mpls_dump_ftn\n"); + return 0; +} + +#if 0 +extern struct mpls_in_tree mpls_in; +extern struct mpls_out_tree mpls_out; + +int mpls_ioctl(unsigned int cmd,void *arg) { + int retval = -ENOSYS; + + switch(cmd) { + case SIOCMPLSDEBUG: + if(mpls_debug) mpls_debug = 0; + else mpls_debug = 1; + retval = 0; + break; + case SIOCGLABELSPACEMPLS: + retval = mpls_get_labelspace((struct mpls_labelspace_req*)arg); + break; + case SIOCSLABELSPACEMPLS: + retval = mpls_set_labelspace((struct mpls_labelspace_req*)arg); + break; +#ifdef CONFIG_MPLS_TUNNEL +#if 0 + case SIOCMPLSTUNNELADDOUT: + retval = mpls_tunnel_add_out((struct mpls_tunnel_req*)arg); + break; + case SIOCMPLSTUNNELDELOUT: + retval = mpls_tunnel_del_out((struct mpls_tunnel_req*)arg); + break; +#endif + case SIOCMPLSTUNNELADD: + { + struct net_device *dev2 = NULL; + dev2 = mpls_tunnel_locate(&((struct mpls_tunnel_req*)arg)->mt_dest,1); + /* check if it already exists */ + mpls_tunnel_link(dev2); + netdev_state_change(dev2); + break; + } + case SIOCMPLSTUNNELDEL: + dev2 = mpls_tunnel_locate(&((struct mpls_tunnel_req*)arg)->mt_dest,0); + mpls_tunnel_unlink(dev2); + unregister_netdevice(dev2); + break; +#endif + } + return retval; +} +#endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_opcode.c linux-kernel-mpls/net/mpls/mpls_opcode.c --- linux-2.4.0-test11.clean/net/mpls/mpls_opcode.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_opcode.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,181 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -opcode that will execute on a sk_buff as it travels through + * the MPLS code + * + * Authors: James R. Leu, + * + * Fixes: + * 2000-03-22 jleu, converted to the new mpls__info structures + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#ifdef CONFIG_ATM +#include +#endif + +extern void copy_skb_header(struct sk_buff*,const struct sk_buff*); + +char mpls_opcode_peek(struct sk_buff *sk,struct mpls_push_data *mpr) { + const char *fn_name = "mpls_opcode_peek"; + u32 shim; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + memcpy(&shim,sk->nh.raw,sizeof(u32)); + shim = ntohl(shim); + + if(!mpr->flag) { + mpr->ttl = shim & 0xFF; + mpr->flag = 1; + } + mpr->bos = (shim >> 8) & 0x1; + mpr->exp = (shim >> 9) & 0x7; + mpr->label = (shim >> 12) & 0xFFFFF; + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +u32 mpls_opcode_pop(struct sk_buff *skb) { + const char* fn_name = "mpls_opcode_pop"; + char retval = 0; + u32 shim; + +/* if it is ATM or FR we need to adjust the cb[] data */ + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(skb->data + sizeof(u32) < skb->tail) { + memmove(&shim,skb->data,sizeof(u32)); + shim = ntohl(shim); + skb_pull(skb,sizeof(u32)); + skb->h.raw += sizeof(u32); + skb->nh.raw += sizeof(u32); + skb->mpls_gap += sizeof(u32); + retval = shim; + } else { + printk("%s: packet is not big enough to carry a shim!\n",fn_name); + } + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +char mpls_opcode_push(struct sk_buff **skb,struct mpls_label *ml,struct mpls_push_data *mpr) { + const char *fn_name = "mpls_opcode_push"; + struct sk_buff *o = *skb; + struct sk_buff *n = NULL; + unsigned int label = 0; + char retval = -EINVAL; + u32 shim; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(!ml) { + MPLS_DEBUG(("%s: no outgoing label\n",fn_name)); + return retval; + } + + if(o->mpls_gap >= sizeof(u32)) { + /* + * if we have room between data and end of mac.raw + * just shift the data,n.raw,nh.raw pointers and use the room + * this would happen if we had a pop previous to this + */ + MPLS_DEBUG(("%s: using gap\n",fn_name)); + skb_push(o,sizeof(u32)); + o->h.raw -= sizeof(u32); + o->nh.raw -= sizeof(u32); + o->mpls_gap -= sizeof(u32); + } else if((o->end - o->tail) > sizeof(u32)) { + /* + * if we have tailroom, just move tha data down enough room for + * the shim + */ + MPLS_DEBUG(("%s: using tailroom\n",fn_name)); + memmove(o->data+sizeof(u32),o->data,o->len); + o->len += sizeof(u32); + o->tail += sizeof(u32); + MPLS_DEBUG(("%s: done using tailroom\n",fn_name)); + } else { + /* + * we have no room in the inn, go ahead and create a new sk_buff + * with enough extra room for one shim + */ + MPLS_DEBUG(("%s: creating larger packet\n",fn_name)); + n = alloc_skb(o->truesize + sizeof(u32),GFP_ATOMIC); + if(n == NULL) return -ENOMEM; + + /* + I hate hard-coding numbers like this: Maybe use mpls_gap + Revist --JHS + */ + skb_reserve(n,16); + skb_put(n,sizeof(u32)+o->len); + memmove(n->data+sizeof(u32), o->data, o->len); + + /* + * this is what skb_grow does + */ + copy_skb_header(n,o); + kfree_skb(o); + o = *skb = n; + } + + switch(ml->ml_type) { + case MPLS_LABEL_GEN: + label = ml->u.ml_gen; + break; + case MPLS_LABEL_ATM: + label = 0; + break; + case MPLS_LABEL_FR: + label = 0; + /* JLEU need to find appropriate device */ + /* TODO: set FR_SKB values */ + break; + default: + printk("%s: invalid label type(%d)\n",fn_name,ml->ml_type); + goto push_end; + } + + /* + * no matter what layer 2 we are on, we need the shim! (mpls-encap RFC) + */ + shim = htonl(((label & 0xFFFFF) << 12) | ((mpr->exp & 0x7) << 9) | + ((mpr->bos & 0x1) << 8) | (mpr->ttl & 0xFF)); + memmove(o->data,&shim,sizeof(u32)); + mpr->label = label; + mpr->bos = 0; + + retval = 0; + +push_end: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +#if 0 +char mpls_opcode_rot(struct sk_buff *skb,struct mpls_in_label *mil) { + struct mpls_label_ring_node *ptr = TAILQ_FIRST(&(mil->out_label_list)); + + TAILQ_REMOVE(&(mil->out_label_list),ptr,list); + TAILQ_INSERT_TAIL(&(mil->out_label_list),ptr,list); + + return 0; +} +#endif diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_out_info.c linux-kernel-mpls/net/mpls/mpls_out_info.c --- linux-2.4.0-test11.clean/net/mpls/mpls_out_info.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_out_info.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,575 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -add/get/del/flush for the out label tree + * -binding of FEC to out label + * + * Authors: James R. Leu, + * + * + * Additions: + * 06/19/2000 - Philip Quiney + James R. Leu - label staking + * 06/24/2000 - James R. Leu - unbind_fec2out + * 11/13/2000 - James R. Leu - Converted to use Netlink vs. IOCTLs + * + * Fixes: + * 06/19/2000 - Philip Quiney - dst shouldn't "hold" out_info + * 06/24/2000 - James R. Leu - dst shouldn't be create in add + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include /* must be before route.h */ +#include /* must be before route.h */ +#include /* must be before route.h */ +#include /* must be before ip_fib.h */ +#include +#ifdef CONFIG_ATM +#include +#endif + +struct mpls_out_info_tree moi_tree; +extern struct dst_entry *mpls_make_dst(struct net_device *dev,unsigned int nh, + struct mpls_out_info *moi); + +int mpls_info_default_moi_instruction(struct mpls_out_info *moi, + struct mpls_label *ml) { + const char *fn_name = "mpls_info_default_moi_instruction"; + int retval = -ENXIO; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(moi) { + mpls_label_hold(ml); + moi->moi_instruction[0].mi_opcode = MPLS_OP_PUSH; + moi->moi_instruction[0].mi_data = (unsigned int)ml; + + moi->moi_instruction[1].mi_opcode = MPLS_OP_SET; + moi->moi_instruction[1].mi_data = 0; + + moi->moi_instruction_length = 2; + retval = 0; + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_set_out_label_instructions(struct mpls_instruction_req *out) { + const char *fn_name = "mpls_set_out_label_instructions"; + struct mpls_instruction instruction[MPLS_NUM_OPS]; + struct mpls_out_info *moi = NULL; + struct mpls_instruction_req mir; + unsigned int key = 0; + int retval = -ENXIO; + int length = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + memcpy(&mir,out,sizeof(struct mpls_instruction_req)); + + if(mir.mir_direction != MPLS_OUT) { + MPLS_DEBUG(("%s: invalid direction\n",fn_name)); + goto mpls_set_out_label_instructions_cleanup; + } + + key = mpls_label2key(mir.mir_index,&mir.mir_label); + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + goto mpls_set_out_label_instructions_cleanup; + } + + length = mpls_instruction_build(&mir,instruction,MPLS_NUM_OPS); + if(length > 0) { + mpls_instruction_clear(moi->moi_instruction,moi->moi_instruction_length); + mpls_instruction_copy(moi->moi_instruction,instruction,length); + moi->moi_instruction_length = length; + rt_cache_flush(0); + } + } + +mpls_set_out_label_instructions_cleanup: + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_add_out_label(struct mpls_out_label_req *out) { + const char *fn_name = "mpls_add_out_label"; + struct mpls_out_info *moi = NULL; + struct mpls_out_info *moi_out = NULL; + struct mpls_label *ml = NULL; + struct sockaddr nh; +#ifdef CONFIG_ATM + struct atm_vcc *vcc = NULL; +#endif + struct net_device *dev = NULL; + struct dst_entry *dst = NULL; + int retval = -ENXIO; + unsigned int ifi; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + ml = (struct mpls_label*)kmalloc(sizeof(struct mpls_label),GFP_ATOMIC); + moi = (struct mpls_out_info*)kmalloc(sizeof(struct mpls_out_info), + GFP_ATOMIC); + if(!moi || !ml) { + retval = -ENOMEM; + goto mpls_add_out_label_cleanup; + } + + memset(moi,0,sizeof(struct mpls_out_info)); + /* holding because it will go in the tree */ + mpls_out_info_hold(moi); + + memcpy(ml,&(out->mol_label),sizeof(struct mpls_label)); + atomic_set(&ml->__refcnt,0); + memcpy(&nh,&(out->mol_nh),sizeof(struct sockaddr)); + ifi = out->mol_ifindex; + + moi->moi_age = jiffies; + moi->moi_ifindex = ifi; + dev = moi->moi_dev = dev_get_by_index(ifi); + if(dev == NULL) { + MPLS_DEBUG(("%s: no such device with index %d\n",fn_name,ifi)); + retval = -ENXIO; + goto mpls_add_out_label_cleanup; + } + + switch(nh.sa_family) { + case AF_INET: + dst = mpls_make_dst(dev,((struct sockaddr_in*)&nh)->sin_addr.s_addr, + moi); + if(!dst) { + MPLS_DEBUG(("%s: mpls_make_dst failed\n",fn_name)); + goto mpls_add_out_label_cleanup; + } + dst_hold(dst); + moi->moi_dst = dst; + /* + * holding because it will be used by dst - sounds plausible eh? + * Unfortunately had the side effect of never allowing the release of + * the label as the final call to the dst wasn't called till the + * __mpls_del_out_label call which didn't happen as the refcount was not + * zero - Catch 22 + mpls_out_info_hold(moi); + */ + dst->dst_proto_data[AUX_PROTO_DATA_MPLS] = moi; + break; + } + + mpls_info_default_moi_instruction(moi,ml); + + switch(ml->ml_type) { + case MPLS_LABEL_GEN: + if(moi->moi_dst == NULL) { + MPLS_DEBUG(("%s: failed to create DST\n",fn_name)); + goto mpls_add_out_label_cleanup; + } + break; +#ifdef CONFIG_WAN + case MPLS_LABEL_FR: + break; +#endif +#ifdef CONFIG_ATM + case MPLS_LABEL_ATM: + vcc = mpls_atm_create_vcc(dev,ml->u.ml_atm.mla_vpi, + ml->u.ml_atm.mla_vci,MPLS_ATM_VCC_TX); + if(vcc) { + MPLS_DEBUG(("%s: succeeded to create VCC\n",fn_name)); + moi->moi_vcc = vcc; + } else { + MPLS_DEBUG(("%s: failed to create VCC\n",fn_name)); + goto mpls_add_out_label_cleanup; + } + break; +#endif + default: + MPLS_DEBUG(("%s: invalid label type\n",fn_name)); + goto mpls_add_out_label_cleanup; + } + + if(mpls_debug) mpls_print_label(ml); + key = mpls_label2key(ifi,ml); + moi->moi_key = key; + if(mpls_debug) mpls_print_key(key); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi_out,retval); + if(!retval && moi_out) { + MPLS_DEBUG(("%s: error node already exists\n",fn_name)); + retval = -ESRCH; + goto mpls_add_out_label_cleanup; + } + if(retval) { + RADIX_INSERT(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + unsigned int,key,MPLS_TREE_DEPTH,retval); + if(retval) { + MPLS_DEBUG(("%s: error create node in radix tree\n",fn_name)); + retval = -ENOMEM; + goto mpls_add_out_label_cleanup; + } + } + RADIX_SET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval) { + MPLS_DEBUG(("%s: error setting node in radix tree\n",fn_name)); + retval = -ENOENT; + goto mpls_add_out_label_cleanup; + } + + /* we only reach here if everything succeeds */ + moi = NULL; + ml = NULL; + retval = 0; + } + +mpls_add_out_label_cleanup: + if(moi) mpls_out_info_release(moi); + if(ml) mpls_label_release(ml); + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_get_out_label(struct mpls_out_label_req *out) { + const char *fn_name = "mpls_get_out_label"; + struct mpls_out_info *moi = NULL; + struct mpls_label label; + int retval = -ENXIO; + unsigned int ifi; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + memcpy(&label,&(out->mol_label),sizeof(struct mpls_label)); + ifi = out->mol_ifindex; + + if(mpls_debug) mpls_print_label(&label); + key = mpls_label2key(ifi,&label); + if(mpls_debug) mpls_print_key(key); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + goto mpls_get_out_label_cleanup; + } + + memcpy(&(out->mol_label),&label,sizeof(struct mpls_label)); + memcpy(&(out->mol_nh),&(moi->moi_nh),sizeof(struct sockaddr)); + out->mol_age = moi->moi_age; + retval = 0; + } + +mpls_get_out_label_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +static void mpls_fill_key_res(struct mpls_fec *fec,struct mpls_out_info *moi, + struct rt_key *k,struct fib_result *res) { + const char *fn_name = "mpls_fill_key_res"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + k->dst = fec->prefix; + k->src = fec->source; + k->tos = fec->tos; + k->iif = (fec->input_ifindex)?(fec->input_ifindex):(loopback_dev.ifindex); + k->oif = fec->output_ifindex; + k->scope = RT_SCOPE_UNIVERSE; + res->fi = NULL; + res->prefixlen = fec->len; + res->proto_data[AUX_PROTO_DATA_MPLS] = moi; +#ifdef CONFIG_IP_MULTIPLE_TABLES + res->r = NULL; +#endif + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +int mpls_prep_out2fec(struct mpls_bind_fec_req *req,struct mpls_fec *fec, + struct mpls_out_info **moi) { + const char *fn_name = "mpls_prep_out2fec"; + struct mpls_label label; + unsigned int key; + unsigned int ifi; + int retval = -ENXIO; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + memcpy(&label,&(req->mbf_label),sizeof(struct mpls_label)); + ifi = req->mbf_ifindex; + memcpy(fec,&(req->mbf_fec),sizeof(struct mpls_fec)); + fec->next = NULL; + + if(mpls_debug) mpls_print_label(&label); + key = mpls_label2key(ifi,&label); + if(mpls_debug) mpls_print_key(key); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,*moi,retval); + if(retval || !*moi) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + } + return retval; +} + +int mpls_bind_out2fec(struct mpls_bind_fec_req *req) { + const char *fn_name = "mpls_bind_out2fec"; + struct mpls_out_info *moi; + struct mpls_fec *fec = NULL; + struct fib_result res; + struct rt_key k; + int retval = -ENXIO; + + if(req) { + if(!(fec = (struct mpls_fec*)kmalloc(sizeof(struct mpls_fec),GFP_ATOMIC))) { + retval = -ENOMEM; + goto mpls_bind_out2fec_cleanup; + } + + if((retval = mpls_prep_out2fec(req,fec,&moi)) < 0) { + goto mpls_bind_out2fec_cleanup; + } + + mpls_fill_key_res(fec,moi,&k,&res); + if(fib_add_proto_data(&k,&res,AUX_PROTO_DATA_MPLS) == 0) { + struct mpls_fec **ptr = NULL; + /* + * copy the label into the FIB_NODE data, dst's made from this FIB will + * copy the label from here + */ + MPLS_DEBUG(("%s: copied label to the FIB_NODE\n",fn_name)); + + /* + * its already bound in the FIB so it's succesful, we just need + * to add it to our list + */ + + retval = 0; + + for(ptr = &(moi->moi_fec_list);*ptr;ptr = &((*ptr)->next)) { + if(!mpls_fec_compare(*ptr,fec)) { + MPLS_DEBUG(("%s: Its' already in the list\n",fn_name)); + goto mpls_bind_out2fec_cleanup; + } + } + if(ptr) { + MPLS_DEBUG(("%s: Added FEC to list\n",fn_name)); + *ptr = fec; + fec = NULL; + } + + } else { + MPLS_DEBUG(("%s: couldn't find the FIB_NODE(%d)\n",fn_name,retval)); + retval = -ENETUNREACH; + } + } +mpls_bind_out2fec_cleanup: + if(fec) kfree(fec); + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_unbind_out2fec(struct mpls_bind_fec_req *req) { + const char *fn_name = "mpls_unbind_out2fec"; + struct mpls_fec *fec = NULL; + struct mpls_out_info *moi; + struct fib_result res; + int retval = -ENXIO; + struct rt_key k; + + if(req) { + if(!(fec = (struct mpls_fec*)kmalloc(sizeof(struct mpls_fec),GFP_ATOMIC))) { + retval = -ENOMEM; + goto mpls_unbind_out2fec_cleanup; + } + + if((retval = mpls_prep_out2fec(req,fec,&moi)) < 0) { + goto mpls_unbind_out2fec_cleanup; + } + + mpls_fill_key_res(fec,NULL,&k,&res); + if(fib_add_proto_data(&k,&res,AUX_PROTO_DATA_MPLS) == 0) { + struct mpls_fec **ptr = NULL ,*p_ptr = NULL; + + for(ptr = &(moi->moi_fec_list);*ptr;ptr = &((*ptr)->next)) { + if(!mpls_fec_compare(*ptr,fec)) { + if(p_ptr) { + p_ptr->next = (*ptr)->next; + } else { + moi->moi_fec_list = (*ptr)->next; + } + kfree(*ptr); + break; + } + p_ptr = *ptr; + } + } + } + +mpls_unbind_out2fec_cleanup: + if(fec) kfree(fec); + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +/* + * this delete setup may look weird: + * + * there are two external entrance points. flush and del_out_label. + * flush goes throu and deletes ALL out labels. It does so by going through + * the entire tree and deletes the nodes for each entry as well. + * here are the call stacks: + * + * del_out_info: mpls_ioctl(),mpls_del_out_label(),do_mpls_del_out_label(), + * (if the ref cnt is zero),__mpls_del_out_label() + * + * flush: mpls_ioctl(),mpls_flush_out_tree(),mpls_del_out_info_node(), + * do_mpls_del_out_label(),(if the ref cnt is zero),__mpls_del_out_label() + * + * you'll notice that the only place that the memmory for the out label get's + * freed is in __mpls_del_out_label(). Make sure to use correct ref cnt'ing + * or you'll leak.... + */ + +void __mpls_del_out_label(struct mpls_out_info *moi) { + const char *fn_name = "__mpls_del_out_label"; + int i; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + for(i=0;imoi_instruction_length;i++) { + if(moi->moi_instruction[i].mi_opcode == MPLS_OP_SET) { + if(moi->moi_dst) { + dst_set_expires(moi->moi_dst,0); + dst_release(moi->moi_dst); + moi->moi_dst = NULL; + } + dev_put(moi->moi_dev); + moi->moi_dev = NULL; + } else if(moi->moi_instruction[i].mi_opcode == MPLS_OP_PUSH) { + mpls_label_release((struct mpls_label*)moi->moi_instruction[i].mi_data); + moi->moi_instruction[i].mi_data = 0; + } + } + kfree(moi); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void do_mpls_del_out_label(struct mpls_out_info *moi) { + const char *fn_name = "do_mpls_del_out_label"; + struct mpls_fec **ptr,*ptr2,*ptr3; + struct fib_result res; + struct rt_key k; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + for(ptr = &(moi->moi_fec_list);*ptr;ptr = &((*ptr)->next)) { + mpls_fill_key_res(*ptr,NULL,&k,&res); + fib_add_proto_data(&k,&res,AUX_PROTO_DATA_MPLS); + } + + ptr2 = moi->moi_fec_list; + while(ptr2) { + ptr3 = ptr2->next; + kfree(ptr2); + ptr2 = ptr3; + } + mpls_out_info_release(moi); + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +int mpls_del_out_label(struct mpls_out_label_req *out) { + const char *fn_name = "mpls_del_out_label"; + struct mpls_out_info *moi = NULL; + struct mpls_label label; + int retval = -ENXIO; + unsigned int ifi; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + memcpy(&label,&(out->mol_label),sizeof(struct mpls_label)); + ifi = out->mol_ifindex; + + if(mpls_debug) mpls_print_label(&label); + key = mpls_label2key(ifi,&label); + if(mpls_debug) mpls_print_key(key); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + goto mpls_get_out_label_cleanup; + } + memcpy(&(out->mol_nh),&(moi->moi_nh),sizeof(struct sockaddr)); + out->mol_age = moi->moi_age; + + do_mpls_del_out_label(moi); + moi = NULL; + + RADIX_SET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval) { + MPLS_DEBUG(("%s: error setting node in radix tree\n",fn_name)); + retval = -ENOENT; + } + } +mpls_get_out_label_cleanup: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +static int mpls_del_out_info_node(struct mpls_out_info_node *moi_node,void *d) { + const char *fn_name = "mpls_info_default_moi_instruction"; + struct mpls_out_info *moi = NULL; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(moi_node) { + moi = moi_node->moi; + if(moi) + do_mpls_del_out_label(moi); + kfree(moi_node); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +void mpls_flush_out_tree(void) { + const char *fn_name = "mpls_flush_out_tree"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + RADIX_VISIT_ALL(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + mpls_del_out_info_node,NULL); + RADIX_INIT(&moi_tree); + + MPLS_DEBUG(("%s: exit\n",fn_name)); +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_output.c linux-kernel-mpls/net/mpls/mpls_output.c --- linux-2.4.0-test11.clean/net/mpls/mpls_output.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_output.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,211 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -functions that receive packets from mpls_input() + * or the IPv4 stack + * + * Authors: James R. Leu, + * + * Fixes: + * 2000-03-18 JHS: Add ingress policing feature for LER + * 2000-03-22 jleu, converted to the new mpls__info structures + * 2000-09-19 jleu, converted ingress policing to forward to exiting + * out going labels + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_WAN +#include +#endif +#ifdef CONFIG_ATM +#include +#endif + +int mpls_output2(struct sk_buff *skb,struct mpls_out_info *moi, + struct mpls_push_data *mpr) { + const char *fn_name = "mpls_output2"; + struct hh_cache *hh = NULL; + struct mpls_label *ml = NULL; + int retval = -EINVAL; + int i; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + +mpls_output2_start: + for(i=0;imoi_instruction_length;i++) { + switch(moi->moi_instruction[i].mi_opcode) { + case MPLS_OP_NOP: + MPLS_DEBUG(("%s: nop\n",fn_name)); + break; + case MPLS_OP_FWD: + MPLS_DEBUG(("%s: fwd\n",fn_name)); + moi = (struct mpls_out_info*)moi->moi_instruction[i].mi_data; + if(moi == NULL) { + MPLS_DEBUG(("%s: F'ed up instruction!\n",fn_name)); + kfree_skb(skb); + goto mpls_output2_end; + } + goto mpls_output2_start; + break; + case MPLS_OP_PUSH: + MPLS_DEBUG(("%s: push\n",fn_name)); + ml = (struct mpls_label*)moi->moi_instruction[i].mi_data; + if(ml == NULL) { + MPLS_DEBUG(("%s: F'ed up route cache!\n",fn_name)); + kfree_skb(skb); + goto mpls_output2_end; + } + mpls_opcode_push(&skb,ml,mpr); + break; + case MPLS_OP_SET: + skb->dev = moi->moi_dev; + + switch(moi->moi_dev->type) { +#ifdef CONFIG_ATM + case ARPHRD_ATM: + MPLS_DEBUG(("%s: set ATM\n",fn_name)); + ATM_SKB(skb)->vcc = moi->moi_vcc; + break; +#endif +#ifdef CONFIG_WAN + case ARPHRD_DLCI: + MPLS_DEBUG(("%s: set FR\n",fn_name)); + break; +#endif + default: + MPLS_DEBUG(("%s: set GEN\n",fn_name)); + + if(skb->dst) dst_release(skb->dst); + dst_hold(moi->moi_dst); + skb->dst = moi->moi_dst; + + skb->protocol = __constant_htons(ETH_P_MPLS_UC); + break; + } + } + } + + MPLS_DEBUG(("%s: output device = %s\n",fn_name,moi->moi_dev->name)); + mpls_finish(skb); + + switch(moi->moi_dev->type) { +#ifdef CONFIG_ATM + case ARPHRD_ATM: + MPLS_DEBUG(("%s: ATM\n",fn_name)); + if(ATM_SKB(skb) && ATM_SKB(skb)->vcc && ATM_SKB(skb)->vcc->send) { + MPLS_DEBUG(("%s: ATM send\n",fn_name)); + retval = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc,skb); + } + break; +#endif +#ifdef CONFIG_WAN + case ARPHRD_DLCI: + MPLS_DEBUG(("%s: FR\n",fn_name)); + break; +#endif + default: + MPLS_DEBUG(("%s: GEN\n",fn_name)); + hh = skb->dst->hh; + + if(hh) { + MPLS_DEBUG(("%s: using hh\n",fn_name)); + read_lock_bh(&hh->hh_lock); + memmove(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); +#ifdef CONFIG_MPLS_DEBUG + skb_dump(skb); +#endif + retval = hh->hh_output(skb); + } else if(skb->dst->neighbour) { + MPLS_DEBUG(("%s: using neighbour (%p)\n",fn_name,skb)); +#ifdef CONFIG_MPLS_DEBUG + skb_dump(skb); +#endif + retval = skb->dst->neighbour->output(skb); + } else { + MPLS_DEBUG(("%s: no output :-(\n",fn_name)); +#ifdef CONFIG_MPLS_DEBUG + skb_dump(skb); +#endif + kfree_skb(skb); + } + break; + } + +mpls_output2_end: + MPLS_DEBUG(("%s: exit(%d)\n",fn_name,retval)); + return retval; +} + +int mpls_output(struct sk_buff *skb) { + static const char *fn_name = "mpls_output"; + struct mpls_push_data *mpr = (struct mpls_push_data*)kmalloc( + sizeof(struct mpls_push_data),GFP_ATOMIC); +#ifdef CONFIG_MPLS_INGRESS_POLICING + struct mpls_out_info *moi = NULL; +#endif + int retval; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(!mpr) { + kfree_skb(skb); + return -ENOMEM; + } + + switch(skb->protocol) { + case __constant_htons(ETH_P_IP): + mpr->ttl = skb->nh.iph->ttl; + break; + default: + printk("%s: unknown protocol(%04x)\n",fn_name,skb->protocol); + mpr->ttl = 255; + break; + } + + mpr->bos = 1; + mpr->exp = 0; + +#ifdef CONFIG_MPLS_INGRESS_POLICING + if (skb->mpls_index) { + unsigned int key = skb->mpls_index; + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + MPLS_DEBUG(("%s: unknown mpls_index\n",fn_name)); + return -ESRCH; + } + } else { + moi = skb->dst->dst_proto_data[AUX_PROTO_DATA_MPLS]; + } + retval = mpls_output2(skb,moi,mpr); +#else + retval = mpls_output2(skb,skb->dst->dst_proto_data[AUX_PROTO_DATA_MPLS],mpr); +#endif + kfree(mpr); + + MPLS_DEBUG(("%s: exit\n",fn_name)); + + return retval; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_proc.c linux-kernel-mpls/net/mpls/mpls_proc.c --- linux-2.4.0-test11.clean/net/mpls/mpls_proc.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_proc.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,358 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -functions that display the current in and out labels via + * the proc filesystem + * + * Authors: James R. Leu, + * + * Additions: + * 06/25/2000 - James R. Leu - added instructions output, + * fec output, labelspace output + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +struct mpls_print_info { + char *buffer; + off_t begin; + off_t pos; + int len; + int length; + int offset; +}; + +static void mpls_adjust_print_info(int size,struct mpls_print_info *p) { + p->len += size; + p->pos = p->begin + p->len; + if(p->pos < p->offset) { + p->len = 0; + p->begin = p->pos; + } +} + +static int mpls_check_print_info(struct mpls_print_info *p,int entry_size) { + int retval = 0; + + if(p->pos >= (p->offset + p->length - entry_size)) + retval = -1; + + return retval; +} + +static char *mpls_print_label_str(struct mpls_label* ml) { + static char buffer[16]; + + switch(ml->ml_type) { + case MPLS_LABEL_GEN: + sprintf(buffer,"gen %d",ml->u.ml_gen); + break; + case MPLS_LABEL_ATM: + sprintf(buffer,"atm %d/%d",ml->u.ml_atm.mla_vpi, + ml->u.ml_atm.mla_vci); + break; + case MPLS_LABEL_FR: + sprintf(buffer,"fr %d",ml->u.ml_fr); + break; + } + return buffer; +} + +static int mpls_print_fec_info(struct mpls_out_info_node *node,struct mpls_print_info *p) { + struct mpls_out_info *moi = node->moi; + struct mpls_fec *ptr = NULL; + int retval = 0; + int size; + + if(!moi) + return retval; + + if(!mpls_check_print_info(p,9)) { + size = sprintf(p->buffer+p->len,"%08x ",moi->moi_key); + mpls_adjust_print_info(size,p); + + for(ptr=moi->moi_fec_list;ptr;ptr=ptr->next) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len,"%s/%d ",in_ntoa(ptr->prefix), + ptr->len); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_fec_info_exit; + } + } + if(!mpls_check_print_info(p,1)) { + size = sprintf(p->buffer+p->len,"\n"); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + } + } else { + retval = -1; + } +mpls_print_fec_info_exit: + return retval; +} + +static int mpls_print_out_label_node(struct mpls_out_info_node *node,struct mpls_print_info *p) { + struct mpls_out_info *moi = node->moi; + struct mpls_out_info *fmoi = NULL; + int retval = 0; + int size; + int i; + + if(!moi) + return retval; + + if(!mpls_check_print_info(p,9)) { + size = sprintf(p->buffer+p->len,"%08x ",moi->moi_key); + mpls_adjust_print_info(size,p); + + for(i=0;imoi_instruction_length;i++) { + switch(moi->moi_instruction[i].mi_opcode) { + case MPLS_OP_PUSH: + if(!mpls_check_print_info(p,17)) { + size = sprintf(p->buffer+p->len,"PUSH(%s) ", + mpls_print_label_str((struct mpls_label*) + moi->moi_instruction[i].mi_data)); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_out_info_exit; + } + break; + case MPLS_OP_SET: + if(!mpls_check_print_info(p,IFNAMSIZ+6)) { + size = sprintf(p->buffer+p->len,"SET(%s) ",moi->moi_dev->name); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_out_info_exit; + } + break; + case MPLS_OP_FWD: + fmoi = (struct mpls_out_info*)moi->moi_instruction[i].mi_data; + + if(!mpls_check_print_info(p,15)) { + size = sprintf(p->buffer+p->len,"FWD(%08x) ",fmoi->moi_key); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_out_info_exit; + } + break; + } + } + if(!mpls_check_print_info(p,1)) { + size = sprintf(p->buffer+p->len,"\n"); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + } + } else { + retval = -1; + } +mpls_print_out_info_exit: + return retval; +} + +static int mpls_print_in_label_node(struct mpls_in_info_node *node,struct mpls_print_info *p) { + struct mpls_in_info *mii = node->mii; + struct mpls_out_info *moi = NULL; + int retval = 0; + int size = 0; + int i; + + if(!mii) + return retval; + + if(!mpls_check_print_info(p,33)) { + /* print the in label */ + size = sprintf(p->buffer+p->len,"%08x %s %d ",mii->mii_key, + mpls_print_label_str(&mii->mii_label),mii->mii_labelspace); + mpls_adjust_print_info(size,p); + + /* print intructions */ + for(i=0;imii_instruction_length;i++) { + switch(mii->mii_instruction[i].mi_opcode) { + case MPLS_OP_PUSH: + if(!mpls_check_print_info(p,17)) { + size = sprintf(p->buffer+p->len,"PUSH(%s) ", + mpls_print_label_str((struct mpls_label*) + moi->moi_instruction[i].mi_data)); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_in_info_exit; + } + case MPLS_OP_FWD: + moi = (struct mpls_out_info*)mii->mii_instruction[i].mi_data; + + if(!mpls_check_print_info(p,15)) { + size = sprintf(p->buffer+p->len,"FWD(%08x) ",moi->moi_key); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_in_info_exit; + } + break; + case MPLS_OP_POP: + if(!mpls_check_print_info(p,4)) { + size = sprintf(p->buffer+p->len,"POP "); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_in_info_exit; + } + break; + case MPLS_OP_DLV: + if(!mpls_check_print_info(p,4)) { + size = sprintf(p->buffer+p->len,"DLV "); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_in_info_exit; + } + break; + case MPLS_OP_PEEK: + if(!mpls_check_print_info(p,5)) { + size = sprintf(p->buffer+p->len,"PEEK "); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_print_in_info_exit; + } + break; + } + } + if(!mpls_check_print_info(p,1)) { + size = sprintf(p->buffer+p->len,"\n"); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + } + } else { + retval = -1; + } +mpls_print_in_info_exit: + return retval; +} + +/* -------------------- EXPORTED FUNCTIONS FOLLOW -------------------- */ + +int mpls_in_label_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + RADIX_VISIT_ALL(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS, + mpls_print_in_label_node,&print); + + *start = print.buffer + (print.offset - print.begin); + print.len -= (print.offset - print.begin); + if(print.len > print.length) + print.len = print.length; + if(print.len < 0) + print.len = 0; + return print.len; +} + +int mpls_out_label_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + RADIX_VISIT_ALL(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + mpls_print_out_label_node,&print); + + *start = print.buffer + (print.offset - print.begin); + print.len -= (print.offset - print.begin); + if(print.len > print.length) + print.len = print.length; + if(print.len < 0) + print.len = 0; + return print.len; +} + +int mpls_fec_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + RADIX_VISIT_ALL(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + mpls_print_fec_info,&print); + + *start = print.buffer + (print.offset - print.begin); + print.len -= (print.offset - print.begin); + if(print.len > print.length) + print.len = print.length; + if(print.len < 0) + print.len = 0; + return print.len; +} + +int mpls_labelspace_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + struct net_device *dev = NULL; + int size = 0; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + read_lock(&dev_base_lock); + for(dev = dev_base; dev != NULL; dev = dev->next) { + if(dev->mpls_labelspace != -1) { + if(!mpls_check_print_info(&print,6+IFNAMSIZ)) { + size = sprintf(print.buffer+print.len,"%s\t%d\n",dev->name, + dev->mpls_labelspace); + mpls_adjust_print_info(size,&print); + } else { + break; + } + } + } + read_unlock(&dev_base_lock); + + *start = print.buffer + (print.offset - print.begin); + print.len -= (print.offset - print.begin); + if(print.len > print.length) + print.len = print.length; + if(print.len < 0) + print.len = 0; + return print.len; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_ref.c linux-kernel-mpls/net/mpls/mpls_ref.c --- linux-2.4.0-test11.clean/net/mpls/mpls_ref.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_ref.c Mon Nov 27 13:39:10 2000 @@ -0,0 +1,51 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -functions for refernce count mpls structrures + * + * Authors: James R. Leu, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include + +void mpls_in_info_hold(struct mpls_in_info *mii) { + if(mii) atomic_inc(&mii->__refcnt); +} +void mpls_in_info_release(struct mpls_in_info *mii) { + if(mii) atomic_dec(&mii->__refcnt); + if(!atomic_read(&mii->__refcnt)) { + __mpls_del_in_label(mii); + } +} + +void mpls_out_info_hold(struct mpls_out_info *moi) { + if(moi) atomic_inc(&moi->__refcnt); +} +void mpls_out_info_release(struct mpls_out_info *moi) { + if(moi) atomic_dec(&moi->__refcnt); + if(!atomic_read(&moi->__refcnt)) { + __mpls_del_out_label(moi); + } +} + +void mpls_label_hold(struct mpls_label *ml) { + if(ml) atomic_inc(&ml->__refcnt); +} +void mpls_label_release(struct mpls_label *ml) { + if(ml) atomic_dec(&ml->__refcnt); + if(!atomic_read(&ml->__refcnt)) { + kfree(ml); + } +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_tunnel.c linux-kernel-mpls/net/mpls/mpls_tunnel.c --- linux-2.4.0-test11.clean/net/mpls/mpls_tunnel.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_tunnel.c Tue Nov 28 11:31:25 2000 @@ -0,0 +1,265 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * + * Authors: James R. Leu, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct mpls_tunnel_private { + struct mpls_out_info *mtp_moi; + struct net_device *mtp_dev; + struct sockaddr mtp_dest; + struct mpls_tunnel_private* next; + struct net_device_stats stat; +}; + +extern struct mpls_out_info_tree moi_tree; +static int mpls_tunnel_dev_init(struct net_device *dev); + +static struct mpls_tunnel_private* mpls_tunnel_list; + +static rwlock_t mpls_tunnel_lock = RW_LOCK_UNLOCKED; + +int mpls_tunnel_del_out(struct net_device* dev,struct ifreq *ifr) { + const char *fn_name = "mpls_tunnel_del_out"; + struct mpls_tunnel_private *mtp = NULL; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + mtp = (struct mpls_tunnel_private*)dev->priv; + mpls_out_info_release(mtp->mtp_moi); + mtp->mtp_moi = NULL; + + netif_stop_queue(dev); + dev->iflink = 0; + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +int mpls_tunnel_add_out(struct net_device* dev,struct ifreq *ifr) { + const char *fn_name = "mpls_tunnel_add_out"; + struct mpls_tunnel_private *mtp = NULL; + struct mpls_out_info *moi = NULL; + struct mpls_label ml; + int retval = -ENXIO; + int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + memcpy(&ml,&ifr->ifr_data,sizeof(struct mpls_label)); + mtp = (struct mpls_tunnel_private*)dev->priv; + key = mpls_label2key(ml.ml_index,&ml); + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + return retval; + } + + mpls_out_info_hold(moi); + mtp->mtp_moi = moi; + dev->iflink = ml.ml_index; + netif_start_queue(dev); + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +void mpls_tunnel_link(struct net_device *dev) { + struct mpls_tunnel_private *mtp = (struct mpls_tunnel_private*)dev->priv; + write_lock_bh(&mpls_tunnel_lock); + mtp->next = mpls_tunnel_list; + mpls_tunnel_list = mtp; + write_unlock_bh(&mpls_tunnel_lock); +} + +void mpls_tunnel_unlink(struct net_device *dev) { + struct mpls_tunnel_private *mtp = (struct mpls_tunnel_private*)dev->priv; + struct mpls_tunnel_private **ptr; + + for(ptr = &mpls_tunnel_list;*ptr;ptr = &((*ptr)->next)) { + if(*ptr == mtp) { + write_lock_bh(&mpls_tunnel_lock); + (*ptr) = mtp->next; + write_unlock_bh(&mpls_tunnel_lock); + return; + } + } +} + +struct net_device *mpls_tunnel_locate(struct ifreq *ifr,int create) { + struct net_device *dev = NULL; + struct mpls_tunnel_private *mtp; + struct mpls_tunnel_private *ptr; + struct sockaddr *dest = &ifr->ifr_dstaddr; + int i; + + for(ptr = mpls_tunnel_list;ptr;ptr = ptr->next) { + if (!strncmp(ptr->mtp_dev->name,ifr->ifr_name,IFNAMSIZ)) { + return ptr->mtp_dev; + } + } + + if(!create) { + return NULL; + } + + dev = kmalloc(sizeof(struct net_device)+sizeof(struct mpls_tunnel_private),GFP_KERNEL); + if(!dev) { + return NULL; + } + + + memset(dev,0,sizeof(struct net_device)+sizeof(struct mpls_tunnel_private)); + + dev->priv = (void*)(dev+1); + mtp = (struct mpls_tunnel_private*)dev->priv; + mtp->mtp_dev = dev; + dev->init = mpls_tunnel_dev_init; + dev->new_style = 1; + memcpy(&mtp->mtp_dest,dest,sizeof(struct sockaddr)); + strcpy(dev->name,ifr->ifr_name); + if(dev->name[0] == '0') { + for(i = 0;i < 100;i++) { + + sprintf(dev->name,"mpls%d",i); + if (__dev_get_by_name(dev->name) == NULL) + break; + } + if(i == 100) { + kfree(dev); + return NULL; + } + strcpy(ifr->ifr_name,dev->name); + } + + rtnl_lock(); + if(register_netdevice(dev) < 0) { + kfree(dev); + rtnl_unlock(); + return NULL; + } + rtnl_unlock(); + + dev_hold(dev); + mpls_tunnel_link(dev); + return dev; +} + +static void mpls_tunnel_uninit(struct net_device *dev) { + mpls_tunnel_unlink(dev); + dev_put(dev); +} + +static void mpls_tunnel_destructor(struct net_device *dev) { + kfree(dev->priv); + dev->priv = NULL; +} + +static int mpls_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { + const char *fn_name = "mpls_tunnel_xmit"; + struct mpls_tunnel_private *mtp = (struct mpls_tunnel_private*)dev->priv; + struct mpls_push_data mpr = { 0,255,0,1,0 }; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + skb_unlink(skb); + + if(skb->protocol == __constant_htons(ETH_P_MPLS_UC)) { + mpr.bos = 0; + } else { + mpr.bos = 1; + } + + dev->trans_start = jiffies; + + if(mtp->mtp_moi) { + return mpls_output2(skb,mtp->mtp_moi,&mpr); + } + + dev_kfree_skb(skb); + mtp->stat.tx_errors++; + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return -1; +} + +static struct net_device_stats *mpls_tunnel_get_stats(struct net_device *dev) { + return &(((struct mpls_tunnel_private*)dev->priv)->stat); +} + +static int mpls_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr,int cmd) +{ + int retval = -ENOSYS; + + switch (cmd) { + case SIOCMPLSTUNNELADDOUT: + retval = mpls_tunnel_add_out(dev,ifr); + break; + case SIOCMPLSTUNNELDELOUT: + retval = mpls_tunnel_del_out(dev,ifr); + break; + default: + break; + } + return retval; +} + +static int mpls_tunnel_change_mtu(struct net_device *dev, int new_mtu) { + if (new_mtu < 4 || new_mtu > 0xFFFB) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static void mpls_tunnel_init_gen(struct net_device *dev) { + dev->uninit = mpls_tunnel_uninit; + dev->destructor = mpls_tunnel_destructor; + dev->hard_start_xmit = mpls_tunnel_xmit; + dev->get_stats = mpls_tunnel_get_stats; + dev->do_ioctl = mpls_tunnel_ioctl; + dev->change_mtu = mpls_tunnel_change_mtu; + + dev_init_buffers(dev); + + dev->type = ARPHRD_MPLS_TUNNEL; + dev->hard_header_len = sizeof(u32); + dev->mtu = 1500 - sizeof(u32); + dev->flags = IFF_NOARP|IFF_POINTOPOINT; + dev->iflink = 0; + dev->addr_len = 4; +} + +int __init mpls_tunnel_dev_init(struct net_device *dev) { + mpls_tunnel_init_gen(dev); + return 0; +} + +int __init mpls_tunnel_init(void) { + printk(KERN_INFO "MPLS Tunnel interface\n"); + mpls_tunnel_list = NULL; + return 0; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/mpls/mpls_utils.c linux-kernel-mpls/net/mpls/mpls_utils.c --- linux-2.4.0-test11.clean/net/mpls/mpls_utils.c Wed Dec 31 18:00:00 1969 +++ linux-kernel-mpls/net/mpls/mpls_utils.c Mon Nov 27 13:39:11 2000 @@ -0,0 +1,313 @@ +/* + * MPLS An implementation of MPLS forwarding for the Linux Kernel. + * MPLS is implemented based off of the IETF drafts: + * -draft-ietf-mpls-arch-06 + * -draft-ietf-mpls-framework-05 + * -draft-ietf-mpls-label-encaps-07 + * -draft-ietf-mpls-atm-02 + * + * It implements: + * -various common functions called by the rest of the MPLS + * stack + * + * Authors: James R. Leu, + * + * Additions: + * 06/19/2000 - James R. Leu - added instruction build/clear + * routines. + * 06/24/2000 - James R. Leu - added mpls_fec_compare + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void mpls_instruction_copy(struct mpls_instruction *out, + struct mpls_instruction *in,int length) { + int i; + + for(i=0;imir_instruction_length > size) + goto mpls_instruction_build_cleanup; + + for(i = 0;imir_instruction_length;i++) { + opcode = mir->mir_instruction[i].mir_opcode; + switch(opcode) { + case MPLS_OP_PUSH: + ml = (struct mpls_label*)kmalloc(sizeof(struct mpls_label), + GFP_ATOMIC); + + if(!ml) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: error building in label instructions\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + + memcpy(ml,&mir->mir_instruction[i].mir_data.push.label, + sizeof(struct mpls_label)); + atomic_set(&ml->__refcnt,0); + mpls_label_hold(ml); + mpls_print_label(ml); + data = (unsigned int)ml; + break; + case MPLS_OP_FWD: + key = mpls_label2key(mir->mir_instruction[i].mir_data.fwd.index, + &mir->mir_instruction[i].mir_data.fwd.label); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + unsigned int,key,MPLS_TREE_DEPTH,moi,moi,retval); + if(retval || !moi) { + MPLS_DEBUG(("%s: no outgoing entry\n",fn_name)); + retval = -ESRCH; + goto mpls_instruction_build_cleanup; + } + + mpls_out_info_hold(moi); + data = (unsigned int)moi; + break; + case MPLS_OP_DLV: + case MPLS_OP_NOP: + case MPLS_OP_POP: + case MPLS_OP_PEEK: + case MPLS_OP_ROT: + case MPLS_OP_POPALL: + data = 0; + break; + case MPLS_OP_SET: + data = 0; + if(mir->mir_direction == MPLS_IN) { + data = dev_get_by_index(mir->mir_instruction[i].mir_data.set); + if(!data) { + MPLS_DEBUG(("%s: could find a interface with index %d\n",fn_name, + mir->mir_instruction[i].mir_data.set)); + goto mpls_instruction_build_cleanup; + } + } + break; + default: + MPLS_DEBUG(("%s: unsupport opcode\n",fn_name)); + goto mpls_instruction_build_cleanup; + break; + } + instruction[i].mi_opcode = opcode; + instruction[i].mi_data = data; + length++; + } + + if(opcode != MPLS_OP_SET && opcode != MPLS_OP_DLV && opcode != MPLS_OP_FWD && + opcode != MPLS_OP_PEEK) { + MPLS_DEBUG(("%s: invalid ending opcode\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + + MPLS_DEBUG(("%s: exit(%d)\n",fn_name,length)); + return length; + +mpls_instruction_build_cleanup: + if(length) + mpls_instruction_clear(instruction,length); + + MPLS_DEBUG(("%s: exit(0)\n",fn_name)); + return 0; +} + +struct net_device *mpls_dev_by_labelspace(int labelspace) { + struct net_device *retval = NULL; + struct net_device *dev; + + read_lock(&dev_base_lock); + + for (dev = dev_base; dev != NULL; dev = dev->next) { + if(dev->mpls_labelspace == labelspace) { + retval = dev; + break; + } + } + + read_unlock(&dev_base_lock); + + return retval; +} + +void mpls_print_label(struct mpls_label *label) { + switch(label->ml_type) { + case MPLS_LABEL_GEN: + printk("Label GEN %d\n",label->u.ml_gen); + break; + case MPLS_LABEL_ATM: + printk("Label ATM %d/%d\n",label->u.ml_atm.mla_vpi, + label->u.ml_atm.mla_vci); + break; + case MPLS_LABEL_FR: + printk("Label FR %d\n",label->u.ml_fr); + break; + default: + printk("Label UNKNOWN (%d)\n",label->ml_type); + break; + } +} + +void mpls_print_key(u32 key) { + struct mpls_key mlk; + + mlk.u.mark = key; + switch(mlk.u.gen.type) { + case MPLS_LABEL_GEN: + printk("Key GEN %d %d\n",mlk.u.gen.gen,mlk.u.gen.index); + break; + case MPLS_LABEL_ATM: + printk("Key ATM %d/%d %d\n",mlk.u.atm.vpi,mlk.u.atm.vci,mlk.u.atm.index); + break; + case MPLS_LABEL_FR: + printk("Key FR %d %d\n",mlk.u.fr.fr,mlk.u.fr.index); + break; + default: + printk("Key UNKNOWN %08x\n",mlk.u.mark); + break; + } +} + +int mpls_fec_compare(struct mpls_fec *a,struct mpls_fec *b) { + int retval = -1; + + if(a && b) { + if(a->output_ifindex == b->output_ifindex && + a->input_ifindex == b->input_ifindex && + a->prefix == b->prefix && + a->source == b->source && + a->len == b->len && + a->tos == b->tos) { + retval = 0; + } + } + return retval; +} + +unsigned int mpls_label2key(int index,struct mpls_label *label) { + struct mpls_key temp; + + switch(label->ml_type) { + case MPLS_LABEL_GEN: + temp.u.gen.index = index; + temp.u.gen.gen = label->u.ml_gen; + temp.u.gen.type = label->ml_type; + break; + case MPLS_LABEL_ATM: + temp.u.atm.index = index; + temp.u.atm.vpi = label->u.ml_atm.mla_vpi; + temp.u.atm.vci = label->u.ml_atm.mla_vci; + temp.u.atm.type = label->ml_type; + break; + case MPLS_LABEL_FR: + temp.u.fr.index = index; + temp.u.fr.fr = label->u.ml_fr; + temp.u.fr.type = label->ml_type; + break; + default: + } + return temp.u.mark; +} + +extern struct dst_ops ipv4_dst_ops; + +struct dst_entry *mpls_make_dst(struct net_device *dev,unsigned int nh, + struct mpls_out_info *moi) { + struct rtable *rt = (struct rtable*)dst_alloc(&ipv4_dst_ops); + + MPLS_DEBUG(("mpls_make_dst: enter\n")); + + if(rt != NULL) { + rt->u.dst.__use = 1; + atomic_set(&rt->u.dst.__refcnt, 1); + + rt->key.tos = 0; + rt->key.oif = dev->ifindex; + + rt->rt_iif = rt->key.iif = 0; + rt->rt_src = rt->rt_spec_dst = rt->key.src = 0; + rt->rt_flags = 0; + rt->rt_dst = rt->key.dst = nh; + rt->rt_gateway = nh; + + rt->u.dst.flags = DST_HOST; + rt->u.dst.dev = dev; + dev_hold(rt->u.dst.dev); + rt->u.dst.input = mpls_output; + rt->u.dst.output = mpls_output; + rt->u.dst.lastuse = jiffies; + rt->u.dst.neighbour = NULL; + rt->u.dst.hh = NULL; + rt->u.dst.obsolete = 0; + + MPLS_DEBUG(("mpls_make_dst: before bind neighbor\n")); + if(arp_bind_neighbour(&rt->u.dst)) { + MPLS_DEBUG(("mpls_make_dst: bind neighbor failed\n")); + ip_rt_put(rt); + dst_free(&rt->u.dst); + rt = NULL; + } else { + MPLS_DEBUG(("mpls_make_dst: bind neighbor succeeded\n")); + rt->u.dst.output = mpls_output; + rt->u.dst.dst_proto_data[AUX_PROTO_DATA_MPLS] = moi; + } + } + + MPLS_DEBUG(("mpls_make_dst: exit(%p)\n",rt)); + return (struct dst_entry*)rt; +} diff -uNr --exclude=CVS linux-2.4.0-test11.clean/net/sched/sch_ingress.c linux-kernel-mpls/net/sched/sch_ingress.c --- linux-2.4.0-test11.clean/net/sched/sch_ingress.c Mon Nov 27 13:25:58 2000 +++ linux-kernel-mpls/net/sched/sch_ingress.c Mon Nov 27 13:39:14 2000 @@ -156,8 +156,11 @@ break; #endif }; - +#ifdef CONFIG_MPLS_INGRESS_POLICING + skb->mpls_index = TC_H_MIN(res.classid); +#else skb->tc_index = TC_H_MIN(res.classid); +#endif return result; }