diff -urN linux-2.4.29-wt1/drivers/net/ppp_generic.c linux-2.4.29-wt1-mpls/drivers/net/ppp_generic.c --- linux-2.4.29-wt1/drivers/net/ppp_generic.c Sat Sep 13 07:57:25 2003 +++ linux-2.4.29-wt1-mpls/drivers/net/ppp_generic.c Sun Feb 6 18:27:29 2005 @@ -57,7 +57,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 */ @@ -281,6 +282,10 @@ return NP_IPX; case PPP_AT: return NP_AT; +#ifdef CONFIG_MPLS + case PPP_MPLS_UC: + return NP_MPLS_UC; +#endif } return -EINVAL; } @@ -291,6 +296,9 @@ PPP_IPV6, PPP_IPX, PPP_AT, +#ifdef CONFIG_MPLS + PPP_MPLS_UC, +#endif }; /* Translates an ethertype into an NP index */ @@ -306,6 +314,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; } @@ -316,6 +328,9 @@ ETH_P_IPV6, ETH_P_IPX, ETH_P_PPPTALK, +#ifdef CONFIG_MPLS + ETH_P_MPLS_UC, +#endif }; /* diff -urN linux-2.4.29-wt1/include/linux/if_arp.h linux-2.4.29-wt1-mpls/include/linux/if_arp.h --- linux-2.4.29-wt1/include/linux/if_arp.h Sun Feb 6 08:01:03 2005 +++ linux-2.4.29-wt1-mpls/include/linux/if_arp.h Sun Feb 6 18:27:29 2005 @@ -84,6 +84,7 @@ #define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ +#define ARPHRD_MPLS_TUNNEL 899 /* MPLS Tunnel Interface */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ diff -urN linux-2.4.29-wt1/include/linux/mpls.h linux-2.4.29-wt1-mpls/include/linux/mpls.h --- linux-2.4.29-wt1/include/linux/mpls.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/include/linux/mpls.h Sun Feb 6 18:27:29 2005 @@ -0,0 +1,221 @@ +#ifndef _LINUX_MPLS_H_ +#define _LINUX_MPLS_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#define MPLS_NUM_OPS 8 + +#define MPLS_LINUX_VERSION 0x01010702 + +#define SIOCMPLSFIRST 0x8C00 +#define SIOCGLABELSPACEMPLS 0x8C01 +#define SIOCSLABELSPACEMPLS 0x8C02 +#define SIOCMPLSDEBUG 0x8C03 +#define SIOCMPLSTUNNELADD 0x8C04 +#define SIOCMPLSTUNNELDEL 0x8C05 +#define SIOCMPLSTUNNELGET 0x8C06 +#define SIOCMPLSNHLFEADD 0x8C07 +#define SIOCMPLSNHLFEDEL 0x8C08 +#define SIOCMPLSNHLFEGET 0x8C09 +#define SIOCMPLSILMADD 0x8C0A +#define SIOCMPLSILMDEL 0x8C0B +#define SIOCMPLSILMGET 0x8C0C +#define SIOCMPLSXCADD 0x8C0D +#define SIOCMPLSXCDEL 0x8C0E +#define SIOCMPLSXCGET 0x8C0F +#define SIOCMPLSNHLFESETMTU 0x8C10 +#define SIOCMPLSILMSETPROTO 0x8C11 +#define SIOCMPLSILMFLUSH 0x8C12 +#define SIOCMPLSNHLFEFLUSH 0x8C13 +#define SIOCSMPLSININSTR 0x8C16 +#define SIOCGMPLSININSTR 0x8C17 +#define SIOCSMPLSOUTINSTR 0x8C18 +#define SIOCGMPLSOUTINSTR 0x8C19 +#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_DLV, + MPLS_OP_FWD, + MPLS_OP_NF_FWD, + MPLS_OP_DS_FWD, + MPLS_OP_EXP_FWD, + MPLS_OP_SET, + MPLS_OP_SET_RX, + MPLS_OP_SET_TC, + MPLS_OP_SET_DS, + MPLS_OP_SET_EXP, + MPLS_OP_EXP2TC, + MPLS_OP_EXP2DS, + MPLS_OP_TC2EXP, + MPLS_OP_DS2EXP, + MPLS_OP_NF2EXP, + MPLS_OP_MAX +}; + +enum mpls_label_type_enum { + MPLS_LABEL_GEN = 1, + MPLS_LABEL_ATM, + MPLS_LABEL_FR, + MPLS_LABEL_KEY +}; + +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_key; + unsigned int ml_gen; + unsigned int ml_fr; + struct mpls_label_atm ml_atm; + } u; + int ml_index; +}; + +struct mpls_in_label_req { + unsigned int mil_age; + unsigned int mil_proto; + struct mpls_label mil_label; +}; + +#define MPLS_LABELSPACE_MAX 255 + +struct mpls_labelspace_req { + int mls_ifindex; + int mls_labelspace; +}; + +struct mpls_nexthop_info { + unsigned int mni_if; + struct sockaddr mni_addr; +}; + +struct mpls_out_label_req { + unsigned int mol_age; + struct mpls_label mol_label; + unsigned int mol_mtu; + unsigned char mol_propogate_ttl; +}; + +struct mpls_xconnect_req { + struct mpls_label mx_in; + struct mpls_label mx_out; +}; + +#define MPLS_NFMARK_NUM 64 + +struct mpls_nfmark_fwd { + unsigned int nf_key[MPLS_NFMARK_NUM]; + unsigned short nf_mask; +}; + +#define MPLS_DSMARK_NUM 64 + +struct mpls_dsmark_fwd { + unsigned int df_key[MPLS_DSMARK_NUM]; + unsigned char df_mask; +}; + +#define MPLS_TCINDEX_NUM 64 + +struct mpls_tcindex_fwd { + unsigned int tc_key[MPLS_TCINDEX_NUM]; + unsigned short tc_mask; +}; + +#define MPLS_EXP_NUM 8 + +struct mpls_exp_fwd { + unsigned int ef_key[MPLS_EXP_NUM]; +}; + +struct mpls_exp2tcindex { + unsigned short e2t[MPLS_EXP_NUM]; +}; + +struct mpls_exp2dsmark { + unsigned char e2d[MPLS_EXP_NUM]; +}; + +struct mpls_tcindex2exp { + unsigned char t2e_mask; + unsigned char t2e[MPLS_TCINDEX_NUM]; +}; + +struct mpls_dsmark2exp { + unsigned char d2e_mask; + unsigned char d2e[MPLS_DSMARK_NUM]; +}; + +struct mpls_nfmark2exp { + unsigned char n2e_mask; + unsigned char n2e[MPLS_NFMARK_NUM]; +}; + +struct mpls_instruction_elem { + unsigned short mir_opcode; + unsigned char mir_direction; + union { + struct mpls_label push; + struct mpls_label fwd; + struct mpls_nfmark_fwd nf_fwd; + struct mpls_dsmark_fwd ds_fwd; + struct mpls_exp_fwd exp_fwd; + struct mpls_nexthop_info set; + unsigned int set_rx; + unsigned short set_tc; + unsigned short set_ds; + unsigned char set_exp; + struct mpls_exp2tcindex exp2tc; + struct mpls_exp2dsmark exp2ds; + struct mpls_tcindex2exp tc2exp; + struct mpls_dsmark2exp ds2exp; + struct mpls_nfmark2exp nf2exp; + } mir_data; +}; + +struct mpls_instruction_req { + struct mpls_instruction_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 -urN linux-2.4.29-wt1/include/linux/netdevice.h linux-2.4.29-wt1-mpls/include/linux/netdevice.h --- linux-2.4.29-wt1/include/linux/netdevice.h Sun Feb 6 18:19:19 2005 +++ linux-2.4.29-wt1-mpls/include/linux/netdevice.h Sun Feb 6 18:27:29 2005 @@ -345,6 +345,7 @@ void *dn_ptr; /* DECnet specific data */ void *ip6_ptr; /* IPv6 specific data */ void *ec_ptr; /* Econet specific data */ + void *mpls_ptr; /* MPLS specific data */ struct list_head poll_list; /* Link to poll list */ int quota; diff -urN linux-2.4.29-wt1/include/linux/netfilter_ipv4/ipt_MPLS.h linux-2.4.29-wt1-mpls/include/linux/netfilter_ipv4/ipt_MPLS.h --- linux-2.4.29-wt1/include/linux/netfilter_ipv4/ipt_MPLS.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/include/linux/netfilter_ipv4/ipt_MPLS.h Sun Feb 6 18:27:29 2005 @@ -0,0 +1,8 @@ +#ifndef _IPT_MPLS_H_target +#define _IPT_MPLS_H_target + +struct ipt_mpls_target_info { + unsigned int key; +}; + +#endif /*_IPT_MPLS_H_target*/ diff -urN linux-2.4.29-wt1/include/linux/ppp_defs.h linux-2.4.29-wt1-mpls/include/linux/ppp_defs.h --- linux-2.4.29-wt1/include/linux/ppp_defs.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.29-wt1-mpls/include/linux/ppp_defs.h Sun Feb 6 18:27:29 2005 @@ -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 -urN linux-2.4.29-wt1/include/linux/rtnetlink.h linux-2.4.29-wt1-mpls/include/linux/rtnetlink.h --- linux-2.4.29-wt1/include/linux/rtnetlink.h Mon Jan 10 07:12:12 2005 +++ linux-2.4.29-wt1-mpls/include/linux/rtnetlink.h Sun Feb 6 18:27:29 2005 @@ -204,6 +204,7 @@ RTA_PROTOINFO, RTA_FLOW, RTA_CACHEINFO, + RTA_LSP, __RTA_MAX }; @@ -227,6 +228,7 @@ unsigned char rtnh_flags; unsigned char rtnh_hops; int rtnh_ifindex; + int rtnh_lsp; }; /* rtnh_flags */ diff -urN linux-2.4.29-wt1/include/net/dst.h linux-2.4.29-wt1-mpls/include/net/dst.h --- linux-2.4.29-wt1/include/net/dst.h Sun Feb 6 08:01:03 2005 +++ linux-2.4.29-wt1-mpls/include/net/dst.h Sun Feb 6 18:27:29 2005 @@ -10,6 +10,9 @@ #include #include +#ifdef CONFIG_MPLS +#include +#endif /* * 0 - no debugging messages @@ -62,7 +65,10 @@ #endif struct dst_ops *ops; - + +#ifdef CONFIG_MPLS + struct mpls_out_info *mpls_moi; +#endif char info[0]; }; diff -urN linux-2.4.29-wt1/include/net/ip.h linux-2.4.29-wt1-mpls/include/net/ip.h --- linux-2.4.29-wt1/include/net/ip.h Sun Feb 6 08:01:05 2005 +++ linux-2.4.29-wt1-mpls/include/net/ip.h Sun Feb 6 18:27:29 2005 @@ -165,9 +165,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 -urN linux-2.4.29-wt1/include/net/ip_fib.h linux-2.4.29-wt1-mpls/include/net/ip_fib.h --- linux-2.4.29-wt1/include/net/ip_fib.h Sun Feb 6 08:01:44 2005 +++ linux-2.4.29-wt1-mpls/include/net/ip_fib.h Sun Feb 6 18:27:29 2005 @@ -32,6 +32,7 @@ unsigned char *rta_protoinfo; unsigned char *rta_flow; struct rta_cacheinfo *rta_ci; + u32 *rta_lsp; }; struct fib_nh @@ -48,6 +49,7 @@ #endif int nh_oif; u32 nh_gw; + u32 nh_lsp; }; /* @@ -76,6 +78,7 @@ #endif struct fib_nh fib_nh[0]; #define fib_dev fib_nh[0].nh_dev +#define fib_lsp fib_nh[0].nh_lsp }; @@ -112,6 +115,7 @@ #define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) #define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) #define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) +#define FIB_RES_LSP(res) (FIB_RES_NH(res).nh_lsp) struct fib_table { diff -urN linux-2.4.29-wt1/include/net/mpls.h linux-2.4.29-wt1-mpls/include/net/mpls.h --- linux-2.4.29-wt1/include/net/mpls.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/include/net/mpls.h Sun Feb 6 18:27:29 2005 @@ -0,0 +1,391 @@ +#ifndef _NET_MPLS_H_ +#define _NET_MPLS_H_ + +#include +#include +#include +#include +#include + +struct fib_result; +struct rtable; + +extern int mpls_debug; +#define MPLS_DEBUG(x) if(mpls_debug) printk x + +#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 + +#define MPLS_RESULT_SUCCESS 0 +#define MPLS_RESULT_RECURSE 1 +#define MPLS_RESULT_DROP 2 +#define MPLS_RESULT_DLV 3 +#define MPLS_RESULT_FWD 4 + +struct mpls_skb_parm { + unsigned int gap; +}; + +#define MPLSCB(skb) ((struct mpls_skb_parm*)((skb)->cb)) + +struct mpls_push_data { + unsigned int label:20; + unsigned int ttl:8; + unsigned int exp:3; + unsigned int bos:1; + unsigned char flag; + char popped_bos; +}; + +struct mpls_instruction { + unsigned short mi_opcode; + void *mi_data; +}; + +struct mpls_nfmark_fwd_info { + struct mpls_out_info *nfi_moi[MPLS_NFMARK_NUM]; + unsigned short nfi_mask; +}; + +struct mpls_dsmark_fwd_info { + struct mpls_out_info *dfi_moi[MPLS_DSMARK_NUM]; + unsigned char dfi_mask; +}; + +struct mpls_tcindex_fwd_info { + struct mpls_out_info *tfi_moi[MPLS_TCINDEX_NUM]; + unsigned short tfi_mask; +}; + +struct mpls_exp_fwd_info { + struct mpls_out_info *efi_moi[MPLS_EXP_NUM]; +}; + +struct mpls_exp2dsmark_info { + unsigned char e2d[MPLS_EXP_NUM]; +}; + +struct mpls_exp2tcindex_info { + unsigned short e2t[MPLS_EXP_NUM]; +}; + +struct mpls_tcindex2exp_info { + unsigned char t2e_mask; + unsigned char t2e[MPLS_TCINDEX_NUM]; +}; + +struct mpls_dsmark2exp_info { + unsigned char d2e_mask; + unsigned char d2e[MPLS_DSMARK_NUM]; +}; + +struct mpls_nfmark2exp_info { + unsigned char n2e_mask; + unsigned char n2e[MPLS_NFMARK_NUM]; +}; + +struct mpls_in_info { + atomic_t __refcnt; + struct list_head dev_entry; + struct list_head moi_entry; + struct mpls_instruction mii_instruction[MPLS_NUM_OPS]; + struct mpls_label mii_label; + unsigned int mii_key; + unsigned int mii_age; + unsigned short mii_proto; + unsigned short mii_labelspace; + unsigned short mii_instruction_length; + unsigned long mii_packets; + unsigned long mii_bytes; + unsigned long mii_drops; +}; + +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; + struct notifier_block *moi_notifier_list; + struct list_head list_out; + struct list_head list_in; + struct list_head dev_entry; + struct list_head moi_entry; + struct mpls_instruction moi_instruction[MPLS_NUM_OPS]; + int moi_ifindex; + unsigned int moi_key; + unsigned int moi_age; + unsigned short moi_instruction_length; + unsigned short moi_mtu_limit; + unsigned short moi_mtu; + unsigned char moi_propogate_ttl; + unsigned long moi_packets; + unsigned long moi_bytes; + unsigned long moi_drops; +}; + +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); + +struct mpls_dst { + atomic_t __refcnt; + struct dst_entry *md_dst; + struct sockaddr md_nh; +}; + +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; +}; + +struct mpls_interface { + struct list_head list_out; + struct list_head list_in; + int labelspace; +}; + +struct mpls_fwd_block { + struct notifier_block notifier_block; + struct mpls_out_info *owner; + struct mpls_out_info *fwd; +}; + +struct mpls_ops { + int (*fn)(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data); + char *msg; + int extra; +}; + +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_skb_dump(struct sk_buff* sk); +extern void mpls_dst_hold(struct mpls_dst *md); +extern void mpls_dst_release(struct mpls_dst *md); +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_get_in2out(struct mpls_xconnect_req *req); +extern int mpls_set_in_label_proto(struct mpls_in_label_req *in); + +extern int mpls_info_default_in_instruction(struct mpls_in_info *mii); +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_get_in_label_instructions(struct mpls_instruction_req *in); +extern int mpls_set_out_label_instructions(struct mpls_instruction_req *out); +extern int mpls_get_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_set_out_label_mtu(struct mpls_out_label_req *out); + +extern struct mpls_in_info *mpls_get_mii(unsigned int key); +extern struct mpls_in_info *mpls_get_mii_by_label(struct mpls_push_data *mpr, + struct mpls_label *label, int labelspace); +extern struct mpls_out_info *mpls_get_moi(unsigned int key); +extern int mpls_insert_mii(unsigned int key, struct mpls_in_info *mii); +extern int mpls_insert_moi(unsigned int key, struct mpls_out_info *moi); + +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 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 u32 mpls_opcode_pop(struct sk_buff *skb); +extern char mpls_opcode_push(struct sk_buff**,struct mpls_label*,struct mpls_push_data*); +extern int 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_instruction_clear(struct mpls_instruction*,int,enum mpls_direction_enum,void*); +extern int mpls_instruction_build(struct mpls_instruction_req*, + struct mpls_instruction*,int, void*); +extern struct net_device *mpls_dev_by_labelspace(int); + +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); +extern int mpls_tunnel_info(char *buffer,char **start,off_t offset,int length); + +extern void mpls_instruction_copy(struct mpls_instruction *out, + struct mpls_instruction *in,int length); + +void *mpls_create_if_info(void); +void mpls_delete_if_info(struct mpls_interface* mpls_if); +void mpls_set_nexthop(struct dst_entry*, u32); + +extern int mpls_version_info(char *buffer,char **start,off_t offset,int length); + +#endif diff -urN linux-2.4.29-wt1/net/Config.in linux-2.4.29-wt1-mpls/net/Config.in --- linux-2.4.29-wt1/net/Config.in Sun Feb 6 18:19:26 2005 +++ linux-2.4.29-wt1-mpls/net/Config.in Sun Feb 6 18:27:29 2005 @@ -90,6 +90,7 @@ fi fi tristate 'WAN router' CONFIG_WAN_ROUTER + bool 'Multi Protocol Label Switching - MPLS' CONFIG_MPLS bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL fi diff -urN linux-2.4.29-wt1/net/Makefile linux-2.4.29-wt1-mpls/net/Makefile --- linux-2.4.29-wt1/net/Makefile Sun Feb 6 18:19:26 2005 +++ linux-2.4.29-wt1-mpls/net/Makefile Sun Feb 6 18:27:29 2005 @@ -22,6 +22,7 @@ subdir-$(CONFIG_IPSEC) += ipsec subdir-$(CONFIG_UNIX) += unix subdir-$(CONFIG_IP_SCTP) += sctp +subdir-$(CONFIG_MPLS) += mpls ifneq ($(CONFIG_IPV6),n) ifneq ($(CONFIG_IPV6),) diff -urN linux-2.4.29-wt1/net/core/dst.c linux-2.4.29-wt1-mpls/net/core/dst.c --- linux-2.4.29-wt1/net/core/dst.c Sat Sep 13 07:57:33 2003 +++ linux-2.4.29-wt1-mpls/net/core/dst.c Sun Feb 6 18:27:29 2005 @@ -18,6 +18,10 @@ #include +#ifdef CONFIG_MPLS +#include +#endif + /* Locking strategy: * 1) Garbage collection state of dead destination cache * entries is protected by dst_lock. @@ -160,6 +164,10 @@ dst->ops->destroy(dst); if (dst->dev) dev_put(dst->dev); +#ifdef CONFIG_MPLS + if (dst->mpls_moi) + mpls_out_info_release(dst->mpls_moi); +#endif #if RT_CACHE_DEBUG >= 2 atomic_dec(&dst_total); #endif diff -urN linux-2.4.29-wt1/net/core/neighbour.c linux-2.4.29-wt1-mpls/net/core/neighbour.c --- linux-2.4.29-wt1/net/core/neighbour.c Sat Feb 5 23:49:16 2005 +++ linux-2.4.29-wt1-mpls/net/core/neighbour.c Sun Feb 6 18:27:29 2005 @@ -1090,7 +1090,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 -urN linux-2.4.29-wt1/net/ipv4/af_inet.c linux-2.4.29-wt1-mpls/net/ipv4/af_inet.c --- linux-2.4.29-wt1/net/ipv4/af_inet.c Sun Feb 6 18:19:20 2005 +++ linux-2.4.29-wt1-mpls/net/ipv4/af_inet.c Sun Feb 6 18:27:29 2005 @@ -116,6 +116,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 struct linux_mib net_statistics[NR_CPUS*2]; @@ -978,6 +981,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 -urN linux-2.4.29-wt1/net/ipv4/fib_semantics.c linux-2.4.29-wt1-mpls/net/ipv4/fib_semantics.c --- linux-2.4.29-wt1/net/ipv4/fib_semantics.c Sat Sep 13 07:57:34 2003 +++ linux-2.4.29-wt1-mpls/net/ipv4/fib_semantics.c Sun Feb 6 18:27:29 2005 @@ -150,6 +150,9 @@ #ifdef CONFIG_NET_CLS_ROUTE nh->nh_tclassid != onh->nh_tclassid || #endif +#ifdef CONFIG_MPLS + nh->nh_lsp != onh->nh_lsp || +#endif ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD)) return -1; onh++; @@ -236,6 +239,9 @@ return -EINVAL; nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; nh->nh_oif = nhp->rtnh_ifindex; +#ifdef CONFIG_MPLS + nh->nh_lsp = nhp->rtnh_lsp; +#endif nh->nh_weight = nhp->rtnh_hops + 1; if (attrlen) { nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); @@ -478,6 +484,10 @@ goto failure; if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) goto err_inval; +#ifdef CONFIG_MPLS + if (rta->rta_lsp && fi->fib_nh->nh_lsp != *rta->rta_lsp) + goto err_inval; +#endif if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4)) goto err_inval; #ifdef CONFIG_NET_CLS_ROUTE @@ -491,6 +501,10 @@ struct fib_nh *nh = fi->fib_nh; if (rta->rta_oif) nh->nh_oif = *rta->rta_oif; +#ifdef CONFIG_MPLS + if (rta->rta_lsp) + nh->nh_lsp = *rta->rta_lsp; +#endif if (rta->rta_gw) memcpy(&nh->nh_gw, rta->rta_gw, 4); #ifdef CONFIG_NET_CLS_ROUTE @@ -674,6 +688,10 @@ RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw); if (fi->fib_nh->nh_oif) RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); +#ifdef CONFIG_MPLS + if (fi->fib_nh->nh_lsp) + RTA_PUT(skb, RTA_LSP, sizeof(u32), &fi->fib_nh->nh_lsp); +#endif } #ifdef CONFIG_IP_ROUTE_MULTIPATH if (fi->fib_nhs > 1) { @@ -690,6 +708,9 @@ nhp->rtnh_flags = nh->nh_flags & 0xFF; nhp->rtnh_hops = nh->nh_weight-1; nhp->rtnh_ifindex = nh->nh_oif; +#ifdef CONFIG_MPLS + nhp->rtnh_lsp = nh->nh_lsp; +#endif if (nh->nh_gw) RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw); nhp->rtnh_len = skb->tail - (unsigned char*)nhp; diff -urN linux-2.4.29-wt1/net/ipv4/ip_output.c linux-2.4.29-wt1-mpls/net/ipv4/ip_output.c --- linux-2.4.29-wt1/net/ipv4/ip_output.c Sun Feb 6 18:19:19 2005 +++ linux-2.4.29-wt1-mpls/net/ipv4/ip_output.c Sun Feb 6 18:27:29 2005 @@ -113,6 +113,7 @@ static inline int output_maybe_reroute(struct sk_buff *skb) { + skb->protocol = htons(ETH_P_IP); return skb->dst->output(skb); } diff -urN linux-2.4.29-wt1/net/ipv4/netfilter/Config.in linux-2.4.29-wt1-mpls/net/ipv4/netfilter/Config.in --- linux-2.4.29-wt1/net/ipv4/netfilter/Config.in Sun Feb 6 18:19:19 2005 +++ linux-2.4.29-wt1-mpls/net/ipv4/netfilter/Config.in Sun Feb 6 18:27:29 2005 @@ -207,6 +207,9 @@ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE dep_tristate ' ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE dep_tristate ' CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_MANGLE + if [ "$CONFIG_MPLS" != "n" ]; then + dep_tristate ' MPLS target support' CONFIG_IP_NF_TARGET_MPLS $CONFIG_IP_NF_MANGLE + fi fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES dep_tristate ' XOR target support' CONFIG_IP_NF_TARGET_XOR $CONFIG_IP_NF_IPTABLES diff -urN linux-2.4.29-wt1/net/ipv4/netfilter/Makefile linux-2.4.29-wt1-mpls/net/ipv4/netfilter/Makefile --- linux-2.4.29-wt1/net/ipv4/netfilter/Makefile Sun Feb 6 18:19:19 2005 +++ linux-2.4.29-wt1-mpls/net/ipv4/netfilter/Makefile Sun Feb 6 18:27:29 2005 @@ -185,6 +185,7 @@ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o +obj-$(CONFIG_IP_NF_TARGET_MPLS) += ipt_MPLS.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o diff -urN linux-2.4.29-wt1/net/ipv4/netfilter/ipt_MPLS.c linux-2.4.29-wt1-mpls/net/ipv4/netfilter/ipt_MPLS.c --- linux-2.4.29-wt1/net/ipv4/netfilter/ipt_MPLS.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/ipv4/netfilter/ipt_MPLS.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,70 @@ +/* This is a module which is used for setting the MPLS field of an skb. */ +#include +#include +#include +#include + +#include +#include +#include + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_mpls_target_info *mplsinfo = targinfo; + int i; + + if((*pskb)->dst && (*pskb)->dst->output != mpls_output) { + mpls_set_nexthop((*pskb)->dst,mplsinfo->key); + } + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mpls_target_info))) { + printk(KERN_WARNING "MPLS: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_mpls_target_info))); + return 0; + } + +#if 0 + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "MPLS: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } +#endif + + return 1; +} + +static struct ipt_target ipt_mpls_reg += { { NULL, NULL }, "MPLS", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_mpls_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_mpls_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.29-wt1/net/ipv4/route.c linux-2.4.29-wt1-mpls/net/ipv4/route.c --- linux-2.4.29-wt1/net/ipv4/route.c Sun Feb 6 18:19:26 2005 +++ linux-2.4.29-wt1-mpls/net/ipv4/route.c Sun Feb 6 18:27:29 2005 @@ -98,6 +98,9 @@ #ifdef CONFIG_SYSCTL #include #endif +#ifdef CONFIG_MPLS +#include +#endif #define IP_MAX_MTU 0xFFF0 @@ -1279,6 +1282,11 @@ rt->u.dst.pmtu > 576) rt->u.dst.pmtu = 576; } +#ifdef CONFIG_MPLS + if (FIB_RES_LSP(*res)) { + mpls_set_nexthop(&rt->u.dst,FIB_RES_LSP(*res)); + } +#endif #ifdef CONFIG_NET_CLS_ROUTE rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid; #endif @@ -1565,7 +1573,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); @@ -2136,6 +2144,10 @@ if (rt->u.dst.tclassid) RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid); #endif +#ifdef CONFIG_MPLS + if (rt->u.dst.mpls_moi) + RTA_PUT(skb, RTA_LSP, 4, &rt->u.dst.mpls_moi->moi_key); +#endif if (rt->key.iif) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); else if (rt->rt_src != rt->key.src) @@ -2204,6 +2216,9 @@ u32 dst = 0; u32 src = 0; int iif = 0; +#ifdef CONFIG_MPLS + int lsp = 0; +#endif int err = -ENOBUFS; struct sk_buff *skb; @@ -2223,6 +2238,10 @@ memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4); if (rta[RTA_IIF - 1]) memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int)); +#ifdef CONFIG_MPLS + if (rta[RTA_LSP - 1]) + memcpy(&lsp, RTA_DATA(rta[RTA_LSP - 1]), sizeof(int)); +#endif if (iif) { struct net_device *dev = __dev_get_by_index(iif); diff -urN linux-2.4.29-wt1/net/mpls/Makefile linux-2.4.29-wt1-mpls/net/mpls/Makefile --- linux-2.4.29-wt1/net/mpls/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/Makefile Sun Feb 6 18:27:29 2005 @@ -0,0 +1,18 @@ +# +# 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). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mpls.o +obj-y := mpls_if.o mpls_in_info.o mpls_init.o mpls_input.o \ + mpls_ioctls.o mpls_opcode.o mpls_out_info.o mpls_output.o \ + mpls_proc.o mpls_ref.o mpls_utils.o mpls_tunnel.o + +include $(TOPDIR)/Rules.make + +tar: + tar -cvf /dev/f1 diff -urN linux-2.4.29-wt1/net/mpls/mpls_if.c linux-2.4.29-wt1-mpls/net/mpls/mpls_if.c --- linux-2.4.29-wt1/net/mpls/mpls_if.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_if.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,91 @@ +/* + * 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 + * + * It implements: + * -interface specific settings for MPLS + * + * 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 + +int mpls_get_labelspace(struct mpls_labelspace_req *req) { + const char *fn_name = "mpls_get_labelspace"; + struct net_device *dev; + int result = -1; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + dev = dev_get_by_index(req->mls_ifindex); + if(dev) { + if (dev->mpls_ptr) { + req->mls_labelspace = + ((struct mpls_interface*)(dev->mpls_ptr))->labelspace; + } else { + req->mls_labelspace = -1; + } + result = 0; + dev_put(dev); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return result; +} + +void *mpls_create_if_info(void) { + struct mpls_interface *mpls_if; + mpls_if = (struct mpls_interface*)kmalloc(sizeof(struct mpls_interface), + GFP_ATOMIC); + memset(mpls_if,0,sizeof(*mpls_if)); + mpls_if->labelspace = -1; + INIT_LIST_HEAD(&mpls_if->list_out); + INIT_LIST_HEAD(&mpls_if->list_in); + return (void*)mpls_if; +} + +void mpls_delete_if_info(struct mpls_interface* mpls_if) { + kfree(mpls_if); +} + +int mpls_set_labelspace(struct mpls_labelspace_req *req) { + const char *fn_name = "mpls_set_labelspace"; + struct net_device *dev; + int result = -1; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(req) { + MPLS_DEBUG(("%s: labelspace(%d)\n",fn_name,req->mls_labelspace)); + if((dev = dev_get_by_index(req->mls_ifindex))) { + if (!dev->mpls_ptr) { + dev->mpls_ptr = mpls_create_if_info(); + if (!dev->mpls_ptr) { + dev_put(dev); + return -ENOMEM; + } + } + if (req->mls_labelspace == -1) { + mpls_delete_if_info(dev->mpls_ptr); + dev->mpls_ptr = NULL; + } else { + ((struct mpls_interface*)(dev->mpls_ptr))->labelspace = + req->mls_labelspace; + } + result = 0; + dev_put(dev); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return result; +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_in_info.c linux-2.4.29-wt1-mpls/net/mpls/mpls_in_info.c --- linux-2.4.29-wt1/net/mpls/mpls_in_info.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_in_info.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,538 @@ +/* + * 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 + * + * It implements: + * -add/get/del/flush for the in label tree + * -binding in labels to out labels + * + * 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 /* must be before route.h */ +#include /* must be before route.h */ +#include /* must be before route.h */ +#include + +rwlock_t mpls_mii_lock; +struct mpls_in_info_tree mii_tree; +extern struct mpls_out_info_tree moi_tree; +extern struct mpls_in_info ipv4_explicit_null; +#ifdef CONFIG_IPV6 +extern struct mpls_in_info ipv6_explicit_null; +#endif + +static struct mpls_reserved_labels { + struct mpls_in_info *mii; + char *msg; + int bos; +} mpls_reserved[16] = { + { &ipv4_explicit_null, "IPv4 EXPLICIT NULL", 1 }, + { NULL, "ROUTER ALERT", 0 }, +#ifdef CONFIG_IPV6 + { &ipv6_explicit_null, "IPv6 EXPLICIT NULL", 1 }, +#else + { NULL, "IPv6 EXPLICIT NULL", 1 }, +#endif + { NULL, "IMPLICIT NULL", 1 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 }, + { NULL, "RESERVED", 0 } +}; + +int mpls_info_default_in_instruction(struct mpls_in_info *mii) { + const char *fn_name = "mpls_info_default_in_instruction"; + struct mpls_instruction instruction[MPLS_NUM_OPS]; + struct mpls_instruction_req mir; + int retval = -ENXIO; + int length; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(mii) { + mir.mir_direction = MPLS_IN; + + mir.mir_instruction[0].mir_opcode = MPLS_OP_POP; + mir.mir_instruction[1].mir_opcode = MPLS_OP_PEEK; + + mir.mir_instruction_length = 2; + + length = mpls_instruction_build(&mir,instruction,MPLS_NUM_OPS,(void*)mii); + if (length > 0) { + mpls_instruction_clear(mii->mii_instruction,mii->mii_instruction_length, + MPLS_IN,(void*)mii); + mpls_instruction_copy(mii->mii_instruction,instruction,length); + mii->mii_instruction_length = length; + } + retval = 0; + } + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +struct mpls_in_info *mpls_get_mii(unsigned int key) { + struct mpls_in_info *mii = NULL; + int retval = 0; + + read_lock(&mpls_mii_lock); + + RADIX_GET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + + if(retval || !mii) { + mii = NULL; + } else { + mpls_in_info_hold(mii); + } + + read_unlock(&mpls_mii_lock); + + return mii; +} + +struct mpls_in_info *mpls_get_mii_by_label(struct mpls_push_data *mpr, + struct mpls_label *label, int labelspace) { + const char *fn_name = "mpls_get_mii_by_label"; + struct mpls_in_info *mii = NULL; + + /* handle the reserved label range */ + if(label->ml_type == MPLS_LABEL_GEN && label->u.ml_gen < 16) { + + int want_bos = mpls_reserved[label->u.ml_gen].bos; + mii = mpls_reserved[label->u.ml_gen].mii; + MPLS_DEBUG(("%s: %s\n",fn_name,mpls_reserved[label->u.ml_gen].msg)); + + if (mii) { + mpls_in_info_hold(mii); + } else { + MPLS_DEBUG(("%s: invalid incoming label, dropping\n",fn_name)); + return NULL; + } + + if ((want_bos && !mpr->bos) || (!want_bos && mpr->bos)) { + MPLS_DEBUG(("%s: invalid incoming labelstack, dropping\n",fn_name)); + return NULL; + } + } else { + if (!(mii = mpls_get_mii(mpls_label2key(labelspace,label)))) { + MPLS_DEBUG(("%s: unknown incoming label, dropping\n",fn_name)); + return NULL; + } + } + return mii; +} + +int mpls_insert_mii(unsigned int key, struct mpls_in_info *mii) { + int retval = 0; + + write_lock(&mpls_mii_lock); + + RADIX_INSERT(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,retval); + + if(retval) { + MPLS_DEBUG(("Error create node in radix tree\n")); + retval = -ENOMEM; + } else { + RADIX_SET(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,mii,mii,retval); + if(retval) { + retval = -ENOENT; + } + } + + write_unlock(&mpls_mii_lock); + return retval; +} + +int mpls_get_in_label_instructions(struct mpls_instruction_req *in) { + return -ENOSYS; +} + +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); + if(!(mii = mpls_get_mii(key))) { + retval = -ESRCH; + goto mpls_set_in_label_instructions_cleanup; + } + + length = mpls_instruction_build(&mir,instruction,MPLS_NUM_OPS,(void*)mii); + if(length > 0) { + mpls_instruction_clear(mii->mii_instruction,mii->mii_instruction_length, + MPLS_IN,(void*)mii); + mpls_instruction_copy(mii->mii_instruction,instruction,length); + mii->mii_instruction_length = length; + } + mpls_in_info_release(mii); + } + +mpls_set_in_label_instructions_cleanup: + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_set_in_label_proto(struct mpls_in_label_req *in) { + const char *fn_name = "mpls_set_in_label_proto"; + struct mpls_in_info *mii = NULL; + struct mpls_label label; + unsigned int labelspace; + unsigned int key = 0; + int retval = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(in) { + + memcpy(&label,&(in->mil_label),sizeof(struct mpls_label)); + labelspace = in->mil_label.ml_index; + + key = mpls_label2key(labelspace,&label); + if(!(mii = mpls_get_mii(key))) { + MPLS_DEBUG(("%s: label does not exist\n",fn_name)); + retval = -ESRCH; + } else { + mii->mii_proto = in->mil_proto; + mpls_in_info_release(mii); + } + + } else { + retval = -EINVAL; + } + + 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; + int retval = -ENXIO; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(in) { + + if(in->mil_label.ml_type == MPLS_LABEL_GEN && + (in->mil_label.u.ml_gen > MPLS_IPV6_EXPLICIT_NULL && + in->mil_label.u.ml_gen < 16)) { + retval = -EINVAL; + goto mpls_add_in_label_cleanup; + } + + 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_label.ml_index; + mii->mii_age = jiffies; + mii->mii_proto = htons(ETH_P_IP); + INIT_LIST_HEAD(&mii->dev_entry); + INIT_LIST_HEAD(&mii->moi_entry); + mpls_info_default_in_instruction(mii); + + key = mpls_label2key(mii->mii_labelspace,&(mii->mii_label)); + mii->mii_key = key; + if (mpls_debug) { + printk("%s: %08x = ",fn_name, key); + mpls_print_label(&(mii->mii_label)); + } + + if((mii_out = mpls_get_mii(key))) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error node already exists\n",fn_name)); + mpls_in_info_release(mii_out); + goto mpls_add_in_label_cleanup; + } else { + if(mpls_insert_mii(key,mii)) { + 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_label.ml_index; + + key = mpls_label2key(labelspace,&label); + if (mpls_debug) { + printk("%s: %08x = ",fn_name, key); + mpls_print_label(&label); + } + if(!(mii = mpls_get_mii(key))) { + retval = -ESRCH; + 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_label.ml_index = mii->mii_labelspace; + mpls_in_info_release(mii); + + 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"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + mpls_instruction_clear(mii->mii_instruction,mii->mii_instruction_length, + MPLS_IN,(void*)mii); + + 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_label.ml_index; + + key = mpls_label2key(labelspace,&label); + if (mpls_debug) { + printk("%s: %08x = ",fn_name, key); + mpls_print_label(&label); + } + if(!(mii = mpls_get_mii(key))) { + 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_label.ml_index = mii->mii_labelspace; + + mpls_in_info_release(mii); + + mii = NULL; + if(mpls_insert_mii(key,mii)) { + MPLS_DEBUG(("%s: error setting node in radix tree\n",fn_name)); + retval = -ENOENT; + goto mpls_del_in_label_cleanup; + } + retval = 0; + } + +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_in.ml_index; + ifindex = req->mx_out.ml_index; + + key = mpls_label2key(labelspace,&in); + if (mpls_debug) { + printk("%s: %08x = ",fn_name, key); + mpls_print_label(&in); + } + if(!(mii = mpls_get_mii(key))) { + MPLS_DEBUG(("%s: couldn't find mii(%08x)\n",fn_name,key)); + retval = -ESRCH; + goto mpls_attach_in2out_cleanup; + } + + key = mpls_label2key(ifindex,&out); + if(!(moi = mpls_get_moi(key))) { + MPLS_DEBUG(("%s: couldn't find moi(%08x)\n",fn_name,key)); + MPLS_DEBUG(("%s: couldn't find ifindex(%d)\n",fn_name,ifindex)); + retval = -ESRCH; + goto mpls_attach_in2out_cleanup_1; + } + + len = mii->mii_instruction_length - 1; + if(mii->mii_instruction[len].mi_opcode == MPLS_OP_DLV || + mii->mii_instruction[len].mi_opcode == MPLS_OP_PEEK || + 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); + } else if(mii->mii_instruction[len].mi_opcode == MPLS_OP_DLV) { + kfree((unsigned short*)mii->mii_instruction[len].mi_data); + } + mii->mii_instruction[len].mi_opcode = MPLS_OP_FWD; + mii->mii_instruction[len].mi_data = (void*)moi; + } + retval = 0; + +mpls_attach_in2out_cleanup_1: + mpls_in_info_release(mii); + } + +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 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_in.ml_index; + + key = mpls_label2key(labelspace,&in); + if(!(mii = mpls_get_mii(key))) { + retval = -ESRCH; + goto mpls_detach_in2out_cleanup; + } + + key = mpls_label2key(0,&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_PEEK; + mpls_out_info_release(moi); + mii->mii_instruction[len].mi_data = 0; + } else { + goto mpls_detach_in2out_cleanup_1; + } + } else { + goto mpls_detach_in2out_cleanup_1; + } + retval = 0; + +mpls_detach_in2out_cleanup_1: + mpls_in_info_release(mii); + } + +mpls_detach_in2out_cleanup: + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_get_in2out(struct mpls_xconnect_req *req) { + return -ENOSYS; +} + +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)); + + read_lock(&mpls_mii_lock); + + RADIX_VISIT_ALL(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS, + mpls_del_in_info_node,NULL); + + RADIX_INIT(&mii_tree); + + read_unlock(&mpls_mii_lock); + + MPLS_DEBUG(("%s: exit\n",fn_name)); +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_init.c linux-2.4.29-wt1-mpls/net/mpls/mpls_init.c --- linux-2.4.29-wt1/net/mpls/mpls_init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_init.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,228 @@ +/* + * 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 + * + * It implements: + * -packet handler for type ETH_P_MPLS_UC + * + * 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 + +struct packet_type mpls_uc_pt = +{ + __constant_htons(ETH_P_MPLS_UC), + NULL, /* All devices */ + mpls_rcv, + (void*)1, + NULL, +}; + +#if 0 +struct packet_type mpls_mc_pt = +{ + __constant_htons(ETH_P_MPLS_MC); + NULL, /* All devices */ + mpls_mc_rcv, + (void*)1, + NULL, +}; +#endif + +struct mpls_in_info ipv4_explicit_null; +#ifdef CONFIG_IPV6 +struct mpls_in_info ipv6_explicit_null; +#endif + +kmem_cache_t *mpls_label_cachep = NULL; +kmem_cache_t *mpls_mpr_cachep = NULL; +int mpls_debug; + +extern struct mpls_in_info_tree mii_tree; +extern struct mpls_out_info_tree moi_tree; +extern rwlock_t mpls_mii_lock; +extern rwlock_t mpls_moi_lock; + +static int mpls_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device*)ptr; + struct mpls_interface *mif = dev->mpls_ptr; + struct list_head *pos; + struct list_head *tmp; + int i, j; + + if (!mif) { + return NOTIFY_DONE; + } + + list_for_each_safe(pos,tmp,&mif->list_out) { + struct mpls_out_info *holder = list_entry(pos,struct + mpls_out_info,dev_entry); + + switch (event) { + case NETDEV_UNREGISTER: + case NETDEV_DOWN: + /* + * the only MOI instruction that holds a netdev is MPLS_OP_SET. + * Spin through this MOIs intructions find MPLS_OP_SET, remove + * the instruction, thus releasing the netdev. + */ + j = 0; + for (i=0;imoi_instruction_length;i++) { + if (holder->moi_instruction[i].mi_opcode == MPLS_OP_SET) { + struct mpls_dst *mdst; + mdst = (struct mpls_dst*)holder->moi_instruction[i].mi_data; + mpls_dst_release(mdst); + } else { + j++; + } + + /* + * If a MPLS_OP_SET was removed, make sure to slide the + * rest of the instructions down. + */ + if (i > j) { + holder->moi_instruction[j].mi_opcode = + holder->moi_instruction[i].mi_opcode; + holder->moi_instruction[j].mi_data = + holder->moi_instruction[i].mi_data; + } + } + + /* adjust the length */ + holder->moi_instruction_length -= (i - j); + break; + case NETDEV_CHANGEMTU: + break; + case NETDEV_UP: + case NETDEV_CHANGE: + default: + break; + } + } + + list_for_each_safe(pos,tmp,&mif->list_in) { + struct mpls_in_info *holder = list_entry(pos, + struct mpls_in_info,dev_entry); + + switch (event) { + case NETDEV_UNREGISTER: + case NETDEV_DOWN: + j = 0; + /* + * the only MII instruction that holds a netdev is MPLS_OP_SET_RX. + * Spin through this MOIs intructions find MPLS_OP_SET_RX, remove + * the instruction, thus releasing the netdev. + */ + for (i=0;imii_instruction_length;i++) { + if (holder->mii_instruction[i].mi_opcode == MPLS_OP_SET_RX) { + dev_put((struct net_device*)holder->mii_instruction[i].mi_data); + } else { + j++; + } + + /* + * If a MPLS_OP_SET_RX was removed, make sure to slide the + * rest of the instructions down. + */ + if (i > j) { + holder->mii_instruction[j].mi_opcode = + holder->mii_instruction[i].mi_opcode; + holder->mii_instruction[j].mi_data = + holder->mii_instruction[i].mi_data; + } + } + + /* adjust the length */ + holder->mii_instruction_length -= (i - j); + break; + case NETDEV_CHANGEMTU: + case NETDEV_UP: + case NETDEV_CHANGE: + default: + break; + } + } + return NOTIFY_DONE; +} + +struct notifier_block mpls_netdev_notifier = { + notifier_call: mpls_netdev_event, +}; + +static int __init mpls_init(void) { + + printk("MPLS version %d.%d%d%d 11/14/2002 jleu@mindspring.com\n", + (MPLS_LINUX_VERSION >> 24) & 0xFF, + (MPLS_LINUX_VERSION >> 16) & 0xFF, + (MPLS_LINUX_VERSION >> 8) & 0xFF, + MPLS_LINUX_VERSION & 0xFF); + + dev_add_pack(&mpls_uc_pt); +#if 0 + dev_add_pack(&mpls_mc_pt); +#endif + + mpls_tunnel_init(); + + rwlock_init(&mpls_mii_lock); + rwlock_init(&mpls_moi_lock); + + RADIX_INIT(&mii_tree); + RADIX_INIT(&moi_tree); + + memset(&ipv4_explicit_null,0,sizeof(struct mpls_in_info)); + ipv4_explicit_null.mii_age = jiffies; + ipv4_explicit_null.mii_proto = htons(ETH_P_IP); + ipv4_explicit_null.mii_instruction_length = 2; + ipv4_explicit_null.mii_label.ml_type = MPLS_LABEL_GEN; + ipv4_explicit_null.mii_instruction[0].mi_opcode = MPLS_OP_POP; + ipv4_explicit_null.mii_instruction[1].mi_opcode = MPLS_OP_DLV; + ipv4_explicit_null.mii_instruction[1].mi_data = (void*)htons(ETH_P_IP); + +#ifdef CONFIG_IPV6 + memset(&ipv6_explicit_null,0,sizeof(struct mpls_in_info)); + ipv6_explicit_null.mii_age = jiffies; + ipv6_explicit_null.mii_proto = htons(ETH_P_IPV6); + ipv6_explicit_null.mii_instruction_length = 2; + ipv6_explicit_null.mii_label.ml_type = MPLS_LABEL_GEN; + ipv6_explicit_null.mii_instruction[0].mi_opcode = MPLS_OP_POP; + ipv6_explicit_null.mii_instruction[1].mi_opcode = MPLS_OP_DLV; + ipv6_explicit_null.mii_instruction[1].mi_data = (void*)htons(ETH_P_IPV6); +#endif + + mpls_label_cachep = kmem_cache_create("label", sizeof(struct mpls_label), 0, + SLAB_HWCACHE_ALIGN, 0, 0); + + mpls_mpr_cachep = kmem_cache_create("mpr", sizeof(struct mpls_push_data), 0, + SLAB_HWCACHE_ALIGN, 0, 0); + +#ifdef CONFIG_PROC_FS + proc_net_create("mpls_version", 0, mpls_version_info); + 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_tunnel", 0, mpls_tunnel_info); +#endif + + register_netdevice_notifier(&mpls_netdev_notifier); + + return 0; +} +module_init(mpls_init); diff -urN linux-2.4.29-wt1/net/mpls/mpls_input.c linux-2.4.29-wt1-mpls/net/mpls/mpls_input.c --- linux-2.4.29-wt1/net/mpls/mpls_input.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_input.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,288 @@ +/* + * 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 + * + * It implements: + * -functions that will receive an MPLS packet from the network + * and begin is path through the network stack + * + * 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 +#ifdef CONFIG_IPV6 +#include +#endif +#include + +extern int ip_rcv(struct sk_buff*,struct net_device*,struct packet_type*); +extern int ipv6_rcv(struct sk_buff*,struct net_device*,struct packet_type*); + +extern struct mpls_ops mpls_in_ops[]; +extern kmem_cache_t *mpls_label_cachep; +extern kmem_cache_t *mpls_mpr_cachep; + +static int mpls_dlv(struct sk_buff* skb, struct mpls_push_data *mpr) { + const char *fn_name = "mpls_dlv"; + int retval = 0; + + /* unshare the skb in hopes that tcpdump and friends will work corectly */ + if (!(skb = skb_unshare(skb, GFP_ATOMIC))) { + MPLS_DEBUG(("%s: unable to unshare skb\n",fn_name)); + return NET_RX_DROP; + } + + mpls_finish(skb); + + switch(skb->protocol) { + case __constant_htons(ETH_P_8021Q): + case __constant_htons(ETH_P_ALL): + { + skb->h.raw = NULL; + skb->mac.raw = NULL; + MPLS_DEBUG(("%s: sending out if %s\n",fn_name,skb->dev->name)); + retval = dev_queue_xmit(skb); + MPLS_DEBUG(("%s: result of tx'ing the packet %d\n",fn_name,retval)); + break; + } + case __constant_htons(ETH_P_IP): + { + if(mpr->ttl < skb->nh.iph->ttl) { + skb->ip_summed = CHECKSUM_NONE; + skb->nh.iph->ttl = mpr->ttl; + MPLS_DEBUG(("%s: setting ttl %d\n",fn_name,mpr->ttl)); + ip_send_check(skb->nh.iph); + } + retval = ip_rcv(skb,skb->dev,NULL); + MPLS_DEBUG(("%s: result of sending packet to IPv4 %d\n",fn_name,retval)); + break; + } +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): + { + if(mpr->ttl < skb->nh.ipv6h->hop_limit) { + skb->ip_summed = CHECKSUM_NONE; + skb->nh.ipv6h->hop_limit = mpr->ttl; + MPLS_DEBUG(("%s: setting ttl %d\n",fn_name,mpr->ttl)); + } + retval = ipv6_rcv(skb,skb->dev,NULL); + MPLS_DEBUG(("%s: result of sending packet to IPv6 %d\n",fn_name,retval)); + break; + } +#endif + default: + { + MPLS_DEBUG(("%s: unknown protocol 0x%04x\n",fn_name,skb->protocol)); + kfree_skb(skb); + retval = NET_RX_DROP; + } + } + return retval; +} + +int mpls_input(struct sk_buff* skb,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_out_info *moi = NULL; + struct mpls_in_info *mii = NULL; + int i = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + +mpls_input_start: + + if (mii) { + mpls_in_info_release(mii); + } + + 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)); + + mpls_skb_dump(skb); + + if (!(mii = mpls_get_mii_by_label(mpr,label,labelspace))) { + MPLS_DEBUG(("%s: unknown incoming label, dropping\n",fn_name)); + goto mpls_input_drop; + } + + mii->mii_packets++; + mii->mii_bytes += skb->len; + + if (mpr->ttl <= 1) { + int (*func)(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data); + + MPLS_DEBUG(("%s: TTL exceeded\n",fn_name)); + skb->protocol = mii->mii_proto; + + /* pop the label stack before handing off to L3 */ + /* eventually, this will setup an MPLS ICMP and send it */ + /* along the LSP */ + func = mpls_in_ops[MPLS_OP_POP].fn; + while(!mpr->popped_bos) { + func(&skb,mii,&moi,mpr,NULL); + } + + goto mpls_input_dlv; + } + + for(i=0;imii_instruction_length;i++) { + int (*func)(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data); + void *data; + int opcode; + char *msg; + + data = mii->mii_instruction[i].mi_data; + opcode = mii->mii_instruction[i].mi_opcode; + func = mpls_in_ops[opcode].fn; + msg = mpls_in_ops[opcode].msg; + + if (!func) { + MPLS_DEBUG(("%s: invalid opcode for input: %s\n",fn_name,msg)); + goto mpls_input_drop; + } + + MPLS_DEBUG(("%s: opcode %s\n",fn_name,msg)); + + switch (func(&skb,mii,&moi,mpr,data)) { + case MPLS_RESULT_RECURSE: + { + label->ml_type = MPLS_LABEL_GEN; + label->u.ml_gen = mpr->label; + goto mpls_input_start; + } + case MPLS_RESULT_DLV: + goto mpls_input_dlv; + case MPLS_RESULT_FWD: + goto mpls_input_fwd; + case MPLS_RESULT_DROP: + goto mpls_input_drop; + case MPLS_RESULT_SUCCESS: + break; + } + } + MPLS_DEBUG(("%s: finished executing in label program without DLV or FWD\n", + fn_name)); + +mpls_input_drop: + + kfree_skb(skb); + if (mii) { + mii->mii_drops++; + mpls_in_info_release(mii); + } + MPLS_DEBUG(("%s: dropped\n",fn_name)); + return NET_RX_DROP; + +mpls_input_dlv: + + mpls_in_info_release(mii); + MPLS_DEBUG(("%s: delivering\n",fn_name)); + return mpls_dlv(skb,mpr); + +mpls_input_fwd: + + mpls_in_info_release(mii); + MPLS_DEBUG(("%s: switching\n",fn_name)); + mpr->ttl--; + return mpls_output2(skb,moi,mpr); +} + +int mpls_rcv(struct sk_buff* skb,struct net_device* dev,struct packet_type* pt) { + const char *fn_name = "mpls_rcv"; + int labelspace; + int result = NET_RX_DROP; + struct mpls_label *label = NULL; + struct mpls_push_data *mpr = NULL; + struct mpls_interface *mip = (struct mpls_interface*)dev->mpls_ptr; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + mpls_skb_dump(skb); + + if (skb->pkt_type == PACKET_OTHERHOST) + goto mpls_rcv_drop; + + if (!(skb = skb_share_check(skb, GFP_ATOMIC))) + goto mpls_rcv_out; + + if (!pskb_may_pull(skb, sizeof(u32))) + goto mpls_rcv_err; + + MPLSCB(skb)->gap = 0; + + labelspace = mip ? mip->labelspace : -1; + if(labelspace < 0) { + MPLS_DEBUG(("%s: MPLS unicast packet recv on interface w/o a labelspace\n", + fn_name)); + goto mpls_rcv_drop; + } + + if (!(mpr = (struct mpls_push_data*)kmem_cache_alloc(mpls_mpr_cachep, + GFP_ATOMIC))) + goto mpls_rcv_err; + + if (!(label = (struct mpls_label*)kmem_cache_alloc(mpls_label_cachep, + GFP_ATOMIC))) + goto mpls_rcv_err2; + + memset(mpr,0,sizeof(struct mpls_push_data)); + memset(label,0,sizeof(struct mpls_label)); + + mpls_opcode_peek(skb,mpr); + + switch(dev->type) { + case ARPHRD_ETHER: + case ARPHRD_FDDI: + case ARPHRD_IEEE802: + case ARPHRD_PPP: + case ARPHRD_LOOPBACK: + case ARPHRD_HDLC: + case ARPHRD_IPGRE: + label->ml_type = MPLS_LABEL_GEN; + label->u.ml_gen = mpr->label; + break; + default: + MPLS_DEBUG(("%s: unknown interface type(%08x) for MPLS\n",fn_name, + dev->type)); + goto mpls_rcv_err3; + } + + /* JLEU: this would be a good spot to drop the frame into a MPLS BH queue */ + result = mpls_input(skb,dev,pt,label,mpr,labelspace); + kmem_cache_free(mpls_label_cachep,label); + kmem_cache_free(mpls_mpr_cachep,mpr); + MPLS_DEBUG(("%s: exit(%d)\n",fn_name,result)); + return result; + +mpls_rcv_err3: + kmem_cache_free(mpls_label_cachep,label); +mpls_rcv_err2: + kmem_cache_free(mpls_mpr_cachep,mpr); +mpls_rcv_err: + /* increment some err counter */ +mpls_rcv_drop: + kfree_skb(skb); +mpls_rcv_out: + MPLS_DEBUG(("%s: exit(DROP)\n",fn_name)); + return NET_RX_DROP; +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_ioctls.c linux-2.4.29-wt1-mpls/net/mpls/mpls_ioctls.c --- linux-2.4.29-wt1/net/mpls/mpls_ioctls.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_ioctls.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,207 @@ +/* + * 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 + * + * It implements: + * -IOCTLs which can be used from userland to create LSP + * through the network stack. + * + * 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 + +int mpls_ioctl(unsigned int cmd,void *arg) { + struct net_device *dev = NULL; + struct ifreq ifr; + int retval = -ENOSYS; + union mpls_io { + struct mpls_labelspace_req labelspace; + struct mpls_in_label_req in_label; + struct mpls_out_label_req out_label; + struct mpls_xconnect_req xconnect; + struct mpls_instruction_req instruction; + } u; + + switch(cmd) { + case SIOCMPLSDEBUG: + if(mpls_debug) mpls_debug = 0; + else mpls_debug = 1; + retval = 0; + break; + case SIOCSLABELSPACEMPLS: + case SIOCGLABELSPACEMPLS: + if (copy_from_user(&u.labelspace,arg, + sizeof(struct mpls_labelspace_req))) { + return -EFAULT; + } + switch(cmd) { + case SIOCSLABELSPACEMPLS: + retval = mpls_set_labelspace(&u.labelspace); + break; + case SIOCGLABELSPACEMPLS: + retval = mpls_get_labelspace(&u.labelspace); + if (copy_to_user(arg,&u.labelspace, + sizeof(struct mpls_labelspace_req))) { + return -EFAULT; + } + break; + default: + } + break; + case SIOCMPLSTUNNELADD: + case SIOCMPLSTUNNELDEL: + case SIOCMPLSTUNNELGET: + if (copy_from_user(&ifr,arg,sizeof(struct ifreq))) { + return -EFAULT; + } + switch(cmd) { + case SIOCMPLSTUNNELADD: + if (mpls_tunnel_locate(&ifr,1)) { + retval = 0; + } + break; + case SIOCMPLSTUNNELDEL: + if ((dev = mpls_tunnel_locate(&ifr,0))) { + rtnl_lock(); + retval = unregister_netdevice(dev); + rtnl_unlock(); + } + break; + default: + } + break; + case SIOCMPLSNHLFESETMTU: + case SIOCMPLSNHLFEADD: + case SIOCMPLSNHLFEDEL: + case SIOCMPLSNHLFEGET: + if (copy_from_user(&u.out_label,arg,sizeof(struct mpls_out_label_req))) { + return -EFAULT; + } + switch(cmd) { + case SIOCMPLSNHLFESETMTU: + retval = mpls_set_out_label_mtu(&u.out_label); + break; + case SIOCMPLSNHLFEADD: + retval = mpls_add_out_label(&u.out_label); + if (copy_to_user(arg,&u.out_label, + sizeof(struct mpls_out_label_req))) { + return -EFAULT; + } + break; + case SIOCMPLSNHLFEDEL: + retval = mpls_del_out_label(&u.out_label); + break; + case SIOCMPLSNHLFEGET: + retval = mpls_get_out_label(&u.out_label); + if (copy_to_user(arg,&u.out_label, + sizeof(struct mpls_out_label_req))) { + return -EFAULT; + } + break; + default: + } + break; + case SIOCMPLSILMSETPROTO: + case SIOCMPLSILMADD: + case SIOCMPLSILMDEL: + case SIOCMPLSILMGET: + if (copy_from_user(&u.in_label,arg,sizeof(struct mpls_in_label_req))) { + return -EFAULT; + } + switch(cmd) { + case SIOCMPLSILMSETPROTO: + retval = mpls_set_in_label_proto(&u.in_label); + break; + case SIOCMPLSILMADD: + retval = mpls_add_in_label(&u.in_label); + break; + case SIOCMPLSILMDEL: + retval = mpls_del_in_label(&u.in_label); + break; + case SIOCMPLSILMGET: + retval = mpls_get_in_label(&u.in_label); + if (copy_to_user(arg,&u.in_label,sizeof(struct mpls_in_label_req))) { + return -EFAULT; + } + break; + default: + } + break; + case SIOCMPLSXCADD: + case SIOCMPLSXCDEL: + case SIOCMPLSXCGET: + if (copy_from_user(&u.xconnect,arg,sizeof(struct mpls_xconnect_req))) { + return -EFAULT; + } + switch(cmd) { + case SIOCMPLSXCADD: + retval = mpls_attach_in2out(&u.xconnect); + break; + case SIOCMPLSXCDEL: + retval = mpls_detach_in2out(&u.xconnect); + break; + case SIOCMPLSXCGET: + retval = mpls_get_in2out(&u.xconnect); + if (copy_to_user(arg,&u.xconnect,sizeof(struct mpls_xconnect_req))) { + return -EFAULT; + } + break; + default: + } + break; + case SIOCSMPLSININSTR: + case SIOCGMPLSININSTR: + case SIOCSMPLSOUTINSTR: + case SIOCGMPLSOUTINSTR: + if (copy_from_user(&u.instruction,arg, + sizeof(struct mpls_instruction_req))) { + return -EFAULT; + } + switch(cmd) { + case SIOCSMPLSININSTR: + retval = mpls_set_in_label_instructions(&u.instruction); + break; + case SIOCSMPLSOUTINSTR: + retval = mpls_set_out_label_instructions(&u.instruction); + break; + case SIOCGMPLSININSTR: + retval = mpls_get_in_label_instructions(&u.instruction); + if (copy_to_user(arg,&u.instruction, + sizeof(struct mpls_instruction_req))) { + return -EFAULT; + } + break; + case SIOCGMPLSOUTINSTR: + retval = mpls_get_out_label_instructions(&u.instruction); + if (copy_to_user(arg,&u.instruction, + sizeof(struct mpls_instruction_req))) { + return -EFAULT; + } + break; + default: + } + break; + case SIOCMPLSILMFLUSH: + mpls_flush_in_tree(); + retval = 0; + break; + case SIOCMPLSNHLFEFLUSH: + mpls_flush_out_tree(); + retval = 0; + break; + } + return retval; +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_opcode.c linux-2.4.29-wt1-mpls/net/mpls/mpls_opcode.c --- linux-2.4.29-wt1/net/mpls/mpls_opcode.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_opcode.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,587 @@ +/* + * 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 + * + * It implements: + * -opcode that will execute on a sk_buff as it travels through + * the MPLS code + * + * 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 + +extern void copy_skb_header(struct sk_buff*,const struct sk_buff*); + +void mpls_finish(struct sk_buff *skb) { + const char *fn_name = "mpls_finish"; + unsigned int diff = MPLSCB(skb)->gap; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(diff > 0) { + memmove(skb->data - diff,skb->data,skb->len); + skb->data -= diff; + MPLSCB(skb)->gap = 0; + skb->h.raw -= diff; + skb->nh.raw -= diff; + skb->tail -= diff; + } else { + if(diff < 0) + MPLS_DEBUG(("%s: data - data_old < 0\n",fn_name)); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +static int mpls_push(struct sk_buff **skb,struct mpls_label *ml,struct mpls_push_data *mpr) { + const char *fn_name = "mpls_push"; + struct sk_buff *o = *skb; + struct sk_buff *n = NULL; + unsigned int label = 0; + u32 shim; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(!ml) { + MPLS_DEBUG(("%s: no outgoing label\n",fn_name)); + return MPLS_RESULT_DROP; + } + +try_again: + if(MPLSCB(o)->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); + MPLSCB(o)->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 = skb_copy_expand(o,32,32,GFP_ATOMIC); + if(n == NULL) { + return MPLS_RESULT_DROP; + } + + MPLSCB(n)->gap = 0; + + MPLS_DEBUG(("%s: dump old packet\n",fn_name)); + mpls_skb_dump(o); + + kfree_skb(o); + o = *skb = n; + + MPLS_DEBUG(("%s: dump new packet\n",fn_name)); + mpls_skb_dump(n); + + goto try_again; + } + + switch(ml->ml_type) { + case MPLS_LABEL_GEN: + label = ml->u.ml_gen; + 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; + mpr->popped_bos = 0; + +push_end: + MPLS_DEBUG(("%s: exit\n",fn_name)); + return MPLS_RESULT_SUCCESS;; +} + +int mpls_opcode_peek(struct sk_buff *skb, struct mpls_push_data *mpr) { + u32 shim; + + memcpy(&shim,skb->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; + + return MPLS_RESULT_RECURSE; +} + +/* in opcodes */ + +int mpls_in_op_nop(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_pop(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + if (mpr->popped_bos || (((*skb)->data + sizeof(u32)) >= (*skb)->tail)) { + return MPLS_RESULT_DROP; + } + + if (mpr->bos) { + mpr->popped_bos = 1; + } + skb_pull(*skb,sizeof(u32)); + (*skb)->h.raw += sizeof(u32); + (*skb)->nh.raw += sizeof(u32); + MPLSCB(*skb)->gap += sizeof(u32); + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_peek(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + if(mpr->bos) { + (*skb)->protocol = mii->mii_proto; + return MPLS_RESULT_DLV; + } + + mpls_opcode_peek(*skb,mpr); + + return MPLS_RESULT_RECURSE; +} + +int mpls_in_op_push(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + return mpls_push(skb,(struct mpls_label*)data,mpr); +} + +int mpls_in_op_dlv(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + (*skb)->protocol = mii->mii_proto; + + return MPLS_RESULT_DLV; +} + +int mpls_in_op_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + *moi = (struct mpls_out_info*)data; + return MPLS_RESULT_FWD; +} + +int mpls_in_op_exp_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_exp_fwd_info *efi = NULL; + efi = (struct mpls_exp_fwd_info*)data; + *moi = efi->efi_moi[mpr->exp & 0x7]; + return MPLS_RESULT_FWD; +} + +int mpls_in_op_set_rx(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + (*skb)->dev = (struct net_device*)data; + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_set_tc(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NET_SCHED + + unsigned short *tc = NULL; + tc = (unsigned short*)data; + (*skb)->tc_index = *tc; + +#endif + + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_set_ds(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + const char *fn_name = "mpls_in_op_set_ds"; + + unsigned short *ds = NULL; + ds = (unsigned short*)data; + + if(!mpr->bos) { + MPLS_DEBUG(("%s: SET_DS and not BOS\n",fn_name)); + return MPLS_RESULT_DROP; + } + switch(mii->mii_proto) { + case __constant_htons(ETH_P_IP): + { + ipv4_change_dsfield((*skb)->nh.iph,0x3,(*ds) << 2); + break; + } +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): + { + ipv6_change_dsfield((*skb)->nh.ipv6h,0x3,*ds); + break; + } +#endif + default: + { + MPLS_DEBUG(("%s: SET_DS on unknown protocol\n",fn_name)); + return MPLS_RESULT_DROP; + } + } + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_set_exp(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + unsigned char *exp = NULL; + exp = (unsigned char*)data; + mpr->exp = *exp; + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_exp2tc(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NET_SCHED + + struct mpls_exp2tcindex_info *e2ti = NULL; + e2ti = (struct mpls_exp2tcindex_info*)data; + if (e2ti->e2t[mpr->exp & 0x7] != 0xffff) { + (*skb)->tc_index = e2ti->e2t[mpr->exp & 0x7]; + } +#endif + return MPLS_RESULT_SUCCESS; +} + +int mpls_in_op_exp2ds(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + const char *fn_name = "mpls_in_op_exp2ds"; + + struct mpls_exp2dsmark_info *e2di = NULL; + e2di = (struct mpls_exp2dsmark_info*)data; + if (e2di->e2d[mpr->exp & 0x7] != 0xff) { + switch(mii->mii_proto) { + case __constant_htons(ETH_P_IP): + { + ipv4_change_dsfield((*skb)->nh.iph,0x3,e2di->e2d[mpr->exp & 0x7]<<2); + break; + } +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): + { + ipv6_change_dsfield((*skb)->nh.ipv6h,0x3,e2di->e2d[mpr->exp & 0x7]); + break; + } +#endif + default: + { + MPLS_DEBUG(("%s: EXP2DS on unknown protocol\n",fn_name)); + return MPLS_RESULT_DROP; + } + } + } + return MPLS_RESULT_SUCCESS; +} + +/* out opcodes */ + +int mpls_out_op_nop(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_push(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_label *ml = NULL; + if (!(ml = (struct mpls_label*)data)) { + return MPLS_RESULT_DROP; + } + if (mpls_push(skb,ml,mpr) != MPLS_RESULT_SUCCESS) { + return MPLS_RESULT_DROP; + } + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + if (!(*moi = (struct mpls_out_info*)data)) { + return MPLS_RESULT_DROP; + } + return MPLS_RESULT_FWD; +} + +int mpls_out_op_nf_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NETFILTER + + struct mpls_nfmark_fwd_info *nfi; + + nfi = (struct mpls_nfmark_fwd_info*)data; + if (!(*moi = nfi->nfi_moi[(*skb)->nfmark & nfi->nfi_mask])) { + return MPLS_RESULT_DROP; + } + +#endif + + return MPLS_RESULT_FWD; +} + +int mpls_out_op_ds_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_dsmark_fwd_info *dfi; + unsigned char ds; + + dfi = (struct mpls_dsmark_fwd_info*)data; + switch((*skb)->protocol) { + case __constant_htons(ETH_P_IP): + { + ds = (ipv4_get_dsfield((*skb)->nh.iph) >> 2) & dfi->dfi_mask; + break; + } +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): + { + ds = ipv6_get_dsfield((*skb)->nh.iph) & dfi->dfi_mask; + break; + } +#endif + default: + { + return MPLS_RESULT_DROP; + } + } + if (!(*moi = dfi->dfi_moi[ds])) { + return MPLS_RESULT_DROP; + } + return MPLS_RESULT_FWD; +} + +int mpls_out_op_exp_fwd(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_exp_fwd_info *efi; + efi = (struct mpls_exp_fwd_info*)data; + + if (!(*moi = efi->efi_moi[mpr->exp & 0x7])) { + return MPLS_RESULT_DROP; + } + return MPLS_RESULT_FWD; +} + +int mpls_out_op_set(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_dst *md; + md = (struct mpls_dst*)data; + + if ((*skb)->dst) { + dst_release((*skb)->dst); + } + dst_hold(md->md_dst); + (*skb)->dst = md->md_dst; + + /* no reason to dev_put(skb->dev) net_rx_action does this for us */ + /* 'dev_put(rx_dev)' */ + /* don't hold the dev we place in skb->dev, the dst is already */ + /* holding it for us */ + + (*skb)->dev = md->md_dst->dev; + (*skb)->protocol = __constant_htons(ETH_P_MPLS_UC); + + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_set_tc(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NET_SCHED + + unsigned short *tc; + tc = (unsigned short*)data; + (*skb)->tc_index = *tc; + +#endif + + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_set_exp(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + unsigned char *exp; + exp = (unsigned char*)data; + mpr->exp = *exp; + + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_tc2exp(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NET_SCHED + + struct mpls_tcindex2exp_info *t2ei; + unsigned short tc; + + t2ei = (struct mpls_tcindex2exp_info*)data; + tc = (*skb)->tc_index & t2ei->t2e_mask; + if (t2ei->t2e[tc] != 0xFF) { + mpr->exp = t2ei->t2e[tc]; + } + +#endif + + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_ds2exp(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + + struct mpls_dsmark2exp_info *d2ei; + unsigned char ds; + + d2ei = (struct mpls_dsmark2exp_info*)data; + switch((*skb)->protocol) { + case __constant_htons(ETH_P_IP): + { + ds = (ipv4_get_dsfield((*skb)->nh.iph) >> 2) & d2ei->d2e_mask; + break; + } +#ifdef CONFIG_IPV6 + case __constant_htons(ETH_P_IPV6): + { + ds = ipv6_get_dsfield((*skb)->nh.iph) & d2ei->d2e_mask; + break; + } +#endif + default: + { + return MPLS_RESULT_DROP; + } + } + if (d2ei->d2e[ds] != 0xFF) { + mpr->exp = d2ei->d2e[ds]; + } + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_nf2exp(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NETFILTER + + struct mpls_nfmark2exp_info *n2ei; + unsigned short nf; + + n2ei = (struct mpls_nfmark2exp_info*)data; + nf = (*skb)->nfmark & n2ei->n2e_mask; + if (n2ei->n2e[nf] != 0xFF) { + mpr->exp = n2ei->n2e[nf]; + } + +#endif + + return MPLS_RESULT_SUCCESS; +} + +int mpls_out_op_exp2tc(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void *data) { + +#ifdef CONFIG_NET_SCHED + + struct mpls_exp2tcindex_info *e2ti; + e2ti = (struct mpls_exp2tcindex_info*)data; + if(e2ti->e2t[mpr->exp & 0x7] != 0xFF) { + (*skb)->tc_index = e2ti->e2t[mpr->exp & 0x7]; + } + +#endif + + return MPLS_RESULT_SUCCESS; +} + +struct mpls_ops mpls_in_ops[MPLS_OP_MAX] = { + { mpls_in_op_nop, "NOP", 0 }, + { mpls_in_op_pop, "POP", 0 }, + { mpls_in_op_peek, "PEEK", 0 }, + { mpls_in_op_push, "PUSH", 0 }, + { mpls_in_op_dlv, "DLV", 0 }, + { mpls_in_op_fwd, "FWD", 0 }, + { NULL, "NF FWD", 0 }, + { NULL, "DS FWD", 0 }, + { mpls_in_op_exp_fwd, "EXP FWD", 0 }, + { NULL, "SET", 0 }, + { mpls_in_op_set_rx, "SET RX", 0 }, + { mpls_in_op_set_tc, "SET TC", 0 }, + { mpls_in_op_set_ds, "SET DS", 0 }, + { mpls_in_op_set_exp, "SET EXP", 0 }, + { mpls_in_op_exp2tc, "EXP2TX", 0 }, + { mpls_in_op_exp2ds, "EXP2DS", 0 }, + { NULL, "NF2EXP", 0 } +}; + +struct mpls_ops mpls_out_ops[MPLS_OP_MAX] = { + { mpls_out_op_nop, "NOP", 0 }, + { NULL, "POP", 0 }, + { NULL, "PEEK", 0 }, + { mpls_out_op_push, "PUSH", 0 }, + { NULL, "DLV", 0 }, + { mpls_out_op_fwd, "FWD", 0 }, + { mpls_out_op_nf_fwd, "NF FWD", 0 }, + { mpls_out_op_ds_fwd, "DS FWD", 0 }, + { mpls_out_op_exp_fwd, "EXP FWD", 0 }, + { mpls_out_op_set, "SET", 1 }, + { NULL, "SET_RX", 0 }, + { mpls_out_op_set_tc, "SET TC", 0 }, + { NULL, "SET DS", 0 }, + { mpls_out_op_set_exp, "SET EXP", 0 }, + { mpls_out_op_exp2tc, "EXP2TC", 0 }, + { NULL, "EXP2DS", 0 }, + { mpls_out_op_tc2exp, "TC2EXP", 0 }, + { mpls_out_op_ds2exp, "DS2EXP", 0 }, + { mpls_out_op_nf2exp, "NF2EXP", 0 } +}; diff -urN linux-2.4.29-wt1/net/mpls/mpls_out_info.c linux-2.4.29-wt1-mpls/net/mpls/mpls_out_info.c --- linux-2.4.29-wt1/net/mpls/mpls_out_info.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_out_info.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,412 @@ +/* + * 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 + * + * It implements: + * -add/get/del/flush for the out label tree + * -binding of FEC to out label + * + * 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 /* 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 + +rwlock_t mpls_moi_lock; +struct mpls_out_info_tree moi_tree; +extern kmem_cache_t *mpls_label_cachep; +static unsigned int mpls_out_info_key = 1; + +unsigned int mpls_get_out_key(void) { + mpls_out_info_key++; + return mpls_out_info_key; +} + +struct mpls_dst* mpls_find_dst(struct mpls_instruction *instr,int len) { + int i; + + for(i=0;i 0) { + mpls_instruction_clear(moi->moi_instruction,moi->moi_instruction_length, + MPLS_OUT,(void*)moi); + mpls_instruction_copy(moi->moi_instruction,instruction,length); + moi->moi_instruction_length = length; + } + retval = 0; + } + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +struct mpls_out_info *mpls_get_moi(unsigned int key) { + struct mpls_out_info *moi = NULL; + int retval = 0; + + read_lock(&mpls_moi_lock); + + RADIX_GET(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS,unsigned int, + key,MPLS_TREE_DEPTH,moi,moi,retval); + + if(retval || !moi) { + moi = NULL; + } else { + mpls_out_info_hold(moi); + } + + read_unlock(&mpls_moi_lock); + + return moi; +} + +int mpls_insert_moi(unsigned int key, struct mpls_out_info *moi) { + int retval = 0; + + write_lock(&mpls_moi_lock); + + RADIX_INSERT(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + unsigned int,key,MPLS_TREE_DEPTH,retval); + + if(retval) { + MPLS_DEBUG(("Error create node in radix tree\n")); + retval = -ENOMEM; + } else { + 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(("Error setting node in radix tree\n")); + retval = -ENOENT; + } + } + + write_unlock(&mpls_moi_lock); + + return retval; +} + +int mpls_get_out_label_instructions(struct mpls_instruction_req *out) { + return -ENOSYS; +} + +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 = 0; + 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); + if(!(moi = mpls_get_moi(key))) { + retval = -ESRCH; + goto mpls_set_out_label_instructions_cleanup; + } + + length = mpls_instruction_build(&mir,instruction,MPLS_NUM_OPS,(void*)moi); + if(length > 0) { + mpls_instruction_clear(moi->moi_instruction,moi->moi_instruction_length, + MPLS_OUT,(void*)moi); + mpls_instruction_copy(moi->moi_instruction,instruction,length); + moi->moi_instruction_length = length; + } else { + retval = -ENXIO; + } + + mpls_out_info_release(moi); + } else { + retval = -ENXIO; + } + +mpls_set_out_label_instructions_cleanup: + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return retval; +} + +int mpls_set_out_label_mtu(struct mpls_out_label_req *out) { + const char *fn_name = "mpls_set_out_label_mtu"; + struct mpls_out_info *moi = NULL; + int retval = 0; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + key = out->mol_label.u.ml_key; + if(!(moi = mpls_get_moi(key))) { + MPLS_DEBUG(("Node does not exists in radix tree\n")); + retval = -ESRCH; + } else { + if (moi->moi_mtu_limit >= out->mol_mtu) { + moi->moi_mtu = out->mol_mtu; + } else { + MPLS_DEBUG(("MTU is larger then lower layer (%d > %d)\n",out->mol_mtu, + moi->moi_mtu_limit)); + retval = -EINVAL; + } + mpls_out_info_release(moi); + rt_cache_flush(0); + } + } else { + retval = -EINVAL; + } + + 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; + int retval = 0; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + + moi = (struct mpls_out_info*)kmalloc(sizeof(struct mpls_out_info), + GFP_ATOMIC); + if(!moi) { + 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); + INIT_LIST_HEAD(&moi->list_out); + INIT_LIST_HEAD(&moi->list_in); + INIT_LIST_HEAD(&moi->moi_entry); + INIT_LIST_HEAD(&moi->dev_entry); + moi->moi_propogate_ttl = 1; + moi->moi_age = jiffies; + key = mpls_get_out_key(); + moi->moi_key = key; + if(mpls_debug) printk("%s: key = 0x%08x\n", fn_name, key); + out->mol_label.ml_type = MPLS_LABEL_KEY; + out->mol_label.u.ml_key = key; + + if((moi_out = mpls_get_moi(key))) { + MPLS_DEBUG(("Node already exists in radix tree\n")); + mpls_out_info_release(moi_out); + retval = -ESRCH; + goto mpls_add_out_label_cleanup; + } else { + if(mpls_insert_moi(key,moi)) { + MPLS_DEBUG(("Error inserting node in radix tree\n")); + retval = -ENOENT; + goto mpls_add_out_label_cleanup; + } + } + + /* we only reach here if everything succeeds */ + moi = NULL; + } else { + retval = -EINVAL; + } + +mpls_add_out_label_cleanup: + + if(moi) mpls_out_info_release(moi); + + 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; + unsigned int key; + int retval = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + memcpy(&label,&(out->mol_label),sizeof(struct mpls_label)); + if(mpls_debug) printk("%s: key = 0x%08x\n", fn_name, label.u.ml_key); + key = mpls_label2key(0,&label); + + if(!(moi = mpls_get_moi(key))) { + retval = -ESRCH; + goto mpls_get_out_label_cleanup; + } + out->mol_age = moi->moi_age; + out->mol_mtu = moi->moi_mtu; + out->mol_propogate_ttl = moi->moi_propogate_ttl; + out->mol_label.ml_type = MPLS_LABEL_KEY; + out->mol_label.u.ml_key = moi->moi_key; + mpls_out_info_release(moi); + } else { + retval = -ENXIO; + } + +mpls_get_out_label_cleanup: + + 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(),mpls_out_info_release(), + * (if the ref cnt is zero),__mpls_del_out_label() + * + * flush: mpls_ioctl(),mpls_flush_out_tree(),mpls_del_out_info_node(), + * mpls_out_info_release(),(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"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + mpls_instruction_clear(moi->moi_instruction,moi->moi_instruction_length, + MPLS_OUT,(void*)moi); + + kfree(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 = 0; + unsigned int key; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(out) { + memcpy(&label,&(out->mol_label),sizeof(struct mpls_label)); + if(mpls_debug) printk("%s: key = 0x%08x\n", fn_name, label.u.ml_key); + key = mpls_label2key(0,&label); + + if(!(moi = mpls_get_moi(key))) { + retval = -ESRCH; + goto mpls_del_out_label_cleanup; + } + out->mol_age = moi->moi_age; + + /* release once because we looked it up */ + mpls_out_info_release(moi); + + /* release once it was in the tree */ + mpls_out_info_release(moi); + + rt_cache_flush(0); + moi = NULL; + + /* now we're gonna remove it from the tree */ + if(mpls_insert_moi(key,moi)) { + retval = -ENOENT; + } + } + +mpls_del_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_del_out_info_node"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if(moi_node) { + if(moi_node->moi) { + mpls_out_info_release(moi_node->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)); + + read_lock(&mpls_moi_lock); + + RADIX_VISIT_ALL(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + mpls_del_out_info_node,NULL); + + RADIX_INIT(&moi_tree); + + read_unlock(&mpls_moi_lock); + + MPLS_DEBUG(("%s: exit\n",fn_name)); +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_output.c linux-2.4.29-wt1-mpls/net/mpls/mpls_output.c --- linux-2.4.29-wt1/net/mpls/mpls_output.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_output.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,226 @@ +/* + * 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 + * + * It implements: + * -functions that receive packets from mpls_input() + * or the IPv4 stack + * + * 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 +#include + +extern kmem_cache_t *mpls_mpr_cachep; +extern struct mpls_ops mpls_out_ops[]; + +int mpls_send(struct sk_buff *skb) { + const char *fn_name = "mpls_send"; + struct hh_cache *hh = NULL; + int retval = MPLS_RESULT_SUCCESS; + + MPLS_DEBUG(("%s: output device = %s\n",fn_name,skb->dev->name)); + mpls_finish(skb); + + if (skb->len > skb->dev->mtu) { + printk("MPLS: packet exceeded MTU %d > %d\n", skb->len, skb->dev->mtu); + return MPLS_RESULT_DROP; + } + + MPLS_DEBUG(("%s: GEN\n",fn_name)); + + if((hh = skb->dst->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); + + mpls_skb_dump(skb); + hh->hh_output(skb); + + } else if(skb->dst->neighbour) { + MPLS_DEBUG(("%s: using neighbour (%p)\n",fn_name,skb)); + + mpls_skb_dump(skb); + skb->dst->neighbour->output(skb); + + } else { + MPLS_DEBUG(("%s: no hh no neighbor!?\n",fn_name)); + mpls_skb_dump(skb); + retval = MPLS_RESULT_DROP; + } + + MPLS_DEBUG(("%s: mpls_send result %d\n",fn_name,retval)); + return retval; +} + +int mpls_output2(struct sk_buff *skb,struct mpls_out_info *moi, + struct mpls_push_data *mpr) { + const char *fn_name = "mpls_output2"; + int retval = -EINVAL; + int ready_to_tx; + int i; + + int (*func)(struct sk_buff** skb,struct mpls_in_info *mii, + struct mpls_out_info **moi, struct mpls_push_data *mpr, void* data); + void *data; + int opcode; + char *msg; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + +mpls_output2_start: + ready_to_tx = 0; + + moi->moi_packets++; + moi->moi_bytes += skb->len; + + for(i=0;imoi_instruction_length;i++) { + + opcode = moi->moi_instruction[i].mi_opcode; + data = moi->moi_instruction[i].mi_data; + msg = mpls_out_ops[opcode].msg; + + MPLS_DEBUG(("%s: opcode %s\n",fn_name,msg)); + + if (mpls_out_ops[opcode].extra) { + ready_to_tx = 1; + } + + if ((func = mpls_out_ops[opcode].fn)) { + switch(func(&skb,NULL,&moi,mpr,data)) { + case MPLS_RESULT_RECURSE: + case MPLS_RESULT_DLV: + goto mpls_output2_drop; + case MPLS_RESULT_FWD: + goto mpls_output2_start; + case MPLS_RESULT_DROP: + goto mpls_output2_drop; + case MPLS_RESULT_SUCCESS: + break; + } + } + } + + if (!ready_to_tx || (mpls_send(skb) != MPLS_RESULT_SUCCESS)) { + goto mpls_output2_drop; + } + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return NET_RX_SUCCESS; + +mpls_output2_drop: + MPLS_DEBUG(("%s: FWD F'ed up instruction!\n",fn_name)); + if (moi) { + moi->moi_drops++; + } + kfree_skb(skb); + return NET_RX_DROP; +} + +int mpls_output_shim(struct sk_buff *skb, struct mpls_out_info *moi) { + static const char *fn_name = "mpls_output"; + struct mpls_push_data *mpr; + unsigned int protocol; + int retval; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + mpr = (struct mpls_push_data*)kmem_cache_alloc(mpls_mpr_cachep,GFP_ATOMIC); + if(!mpr) { + MPLS_DEBUG(("%s: no mem\n",fn_name)); + kfree_skb(skb); + return NET_RX_DROP; + } + + if(moi->moi_propogate_ttl) { + protocol = skb->protocol; + } else { + protocol = 0; + } + + switch(protocol) { + case __constant_htons(ETH_P_IP): + { + mpr->ttl = skb->nh.iph->ttl; + break; + } + default: + { + mpr->ttl = 255; + break; + } + } + + mpr->bos = 1; + mpr->exp = 0; + + retval = mpls_output2(skb,moi,mpr); + kmem_cache_free(mpls_mpr_cachep,mpr); + + MPLS_DEBUG(("%s: exit\n",fn_name)); + + return retval; +} + +int mpls_output(struct sk_buff *skb) { + static const char *fn_name = "mpls_output"; + + if (!(skb = skb_share_check(skb, GFP_ATOMIC))) + return NET_RX_DROP; + + MPLSCB(skb)->gap = 0; + + if (!skb->dst->mpls_moi) { + MPLS_DEBUG(("%s: dst didn't have a moi\n",fn_name)); + kfree_skb(skb); + return NET_RX_DROP; + } + return mpls_output_shim(skb,skb->dst->mpls_moi); +} + +static int mpls_bogus_output(struct sk_buff *skb) { + printk(KERN_DEBUG "mpls_bogus_output: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n", + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), + skb->dev ? skb->dev->name : "?"); + + kfree_skb(skb); + return NET_RX_DROP; +} + +void mpls_set_nexthop(struct dst_entry *dst, u32 key) { + const char *fn_name = "mpls_set_nexthop"; + struct mpls_out_info *moi = NULL; + + MPLS_DEBUG(("%s: enter %d\n",fn_name,dst->pmtu)); + if (!(moi = mpls_get_moi(key))) { + dst->output = mpls_bogus_output; + return; + } + + dst->mpls_moi = moi; + dst->output = mpls_output; + dst->pmtu = moi->moi_mtu; + dst->advmss = dst->pmtu - 40; + + MPLS_DEBUG(("%s: exit %d\n",fn_name,dst->pmtu)); +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_proc.c linux-2.4.29-wt1-mpls/net/mpls/mpls_proc.c --- linux-2.4.29-wt1/net/mpls/mpls_proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_proc.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,614 @@ +/* + * 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 + * + * It implements: + * -functions that display the current in and out labels via + * the proc filesystem + * + * 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 + +extern struct mpls_tunnel_private* mpls_tunnel_list; +extern rwlock_t mpls_tunnel_lock; +extern rwlock_t mpls_mii_lock; +extern rwlock_t mpls_moi_lock; + +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; + case MPLS_LABEL_KEY: + sprintf(buffer,"key 0x%08x",ml->u.ml_key); + break; + } + return buffer; +} + +static int mpls_instruction_print(struct mpls_print_info *p, + struct mpls_instruction *instr, int length,int dir) { + int retval = 0; + int size; + int i; + + for(i=0;ibuffer+p->len,"POP "); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_instr_print; + } + 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_instr_print; + } + break; + } + 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*)instr[i].mi_data)); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_instr_print; + } + 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_instr_print; + } + break; + } + case MPLS_OP_FWD: + { + struct mpls_out_info *moi; + moi = (struct mpls_out_info*)instr[i].mi_data; + if(!mpls_check_print_info(p,15)) { + size = sprintf(p->buffer+p->len,"FWD(0x%08x) ",moi->moi_key); + mpls_adjust_print_info(size,p); + } else { + retval = -1; + goto mpls_instr_print; + } + break; + } + case MPLS_OP_NF_FWD: + { + struct mpls_nfmark_fwd_info *nfi = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,7)) { + size = sprintf(p->buffer+p->len,"NF_FWD("); + mpls_adjust_print_info(size,p); + } + for(j=0;jnfi_moi[j]) { + if(!mpls_check_print_info(p,27)) { + size = sprintf(p->buffer+p->len," NFMARK(%d)->OUT(0x%08x)",j, + nfi->nfi_moi[j]->moi_key); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_DS_FWD: + { + struct mpls_dsmark_fwd_info *dfi = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,7)) { + size = sprintf(p->buffer+p->len,"DS_FWD("); + mpls_adjust_print_info(size,p); + } + for(j=0;jdfi_moi[j]) { + if(!mpls_check_print_info(p,27)) { + size = sprintf(p->buffer+p->len," DSMARK(%d)->OUT(0x%08x)",j, + dfi->dfi_moi[j]->moi_key); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_EXP_FWD: + { + struct mpls_exp_fwd_info *efi = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"EXP_FWD("); + mpls_adjust_print_info(size,p); + } + for(j=0;jefi_moi[j]) { + if(!mpls_check_print_info(p,26)) { + size = sprintf(p->buffer+p->len," EXP(%d)->OUT(0x%08x)",j, + efi->efi_moi[j]->moi_key); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_SET: + { + if (dir == MPLS_IN) { + struct net_device *dev = instr[i].mi_data; + if(!mpls_check_print_info(p,IFNAMSIZ+6)) { + size = sprintf(p->buffer+p->len,"SET(%s) ",dev->name); + mpls_adjust_print_info(size,p); + } + } else { + struct mpls_dst *md = instr[i].mi_data; + if(!mpls_check_print_info(p,IFNAMSIZ+21)) { + size = sprintf(p->buffer+p->len,"SET(%s,%u.%u.%u.%u) ", + md->md_dst->dev->name, + NIPQUAD(((struct sockaddr_in*)&md->md_nh)->sin_addr.s_addr)); + mpls_adjust_print_info(size,p); + } + } + break; + } + case MPLS_OP_SET_TC: + { + unsigned short *tc = instr[i].mi_data; + if(!mpls_check_print_info(p,13)) { + size = sprintf(p->buffer+p->len,"SET_TC(%04x) ",*tc); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_SET_DS: + { + unsigned char *ds = instr[i].mi_data; + if(!mpls_check_print_info(p,11)) { + size = sprintf(p->buffer+p->len,"SET_DS(%02x) ",*ds); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_SET_EXP: + { + unsigned char *exp = instr[i].mi_data; + if(!mpls_check_print_info(p,11)) { + size = sprintf(p->buffer+p->len,"SET_EXP(%02x) ",*exp); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_EXP2TC: + { + struct mpls_exp2tcindex_info *e2ti = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"EXP2TC("); + mpls_adjust_print_info(size,p); + } + for(j=0;je2t[j]) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len," EXP(%d)->TC(%04x)",j, + e2ti->e2t[j]); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_EXP2DS: + { + struct mpls_exp2dsmark_info *e2di = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"EXP2DS("); + mpls_adjust_print_info(size,p); + } + for(j=0;je2d[j] != 0xFF) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len," EXP(%d)->DS(%02x)",j, + e2di->e2d[j]); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_DS2EXP: + { + struct mpls_dsmark2exp_info *d2ei = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"DS2EXP("); + mpls_adjust_print_info(size,p); + } + for(j=0;jd2e[j] != 0xFF) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len," DS(%02x)->EXP(%02x)",j, + d2ei->d2e[j]); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_TC2EXP: + { + struct mpls_tcindex2exp_info *t2ei = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"TC2EXP("); + mpls_adjust_print_info(size,p); + } + for(j=0;jt2e[j] != 0xFF) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len," TC(%02x)->EXP(%02x)",j, + t2ei->t2e[j]); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + case MPLS_OP_NF2EXP: + { + struct mpls_nfmark2exp_info *n2ei = instr[i].mi_data; + int j; + + if(!mpls_check_print_info(p,8)) { + size = sprintf(p->buffer+p->len,"NF2EXP("); + mpls_adjust_print_info(size,p); + } + for(j=0;jn2e[j] != 0xFF) { + if(!mpls_check_print_info(p,18)) { + size = sprintf(p->buffer+p->len," NF(%02x)->EXP(%02x)",j, + n2ei->n2e[j]); + mpls_adjust_print_info(size,p); + } + } + } + if(!mpls_check_print_info(p,2)) { + size = sprintf(p->buffer+p->len," ) "); + mpls_adjust_print_info(size,p); + } + break; + } + } + } +mpls_instr_print: + 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; + int retval = 0; + int size = 0; + + if(!moi) { + return 0; + } + + if(!mpls_check_print_info(p,39)) { + size = sprintf(p->buffer+p->len,"0x%08x %lu/%lu/%lu %d ",moi->moi_key, + moi->moi_packets,moi->moi_bytes,moi->moi_drops, + atomic_read(&moi->__refcnt)); + mpls_adjust_print_info(size,p); + + if(mpls_instruction_print(p,moi->moi_instruction, + moi->moi_instruction_length,MPLS_OUT)) { + retval = -1; + goto mpls_print_out_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_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; + int retval = 0; + int size = 0; + + if(!mii) { + return 0; + } + + if(!mpls_check_print_info(p,63)) { + /* print the in label */ + size = sprintf(p->buffer+p->len,"0x%08x %lu/%lu/%lu %s %d %d ",mii->mii_key, + mii->mii_packets,mii->mii_bytes,mii->mii_drops, + mpls_print_label_str(&mii->mii_label),mii->mii_labelspace, + atomic_read(&mii->__refcnt)); + mpls_adjust_print_info(size,p); + + /* print intructions */ + if(mpls_instruction_print(p,mii->mii_instruction, + mii->mii_instruction_length,MPLS_IN)) { + retval = -1; + goto mpls_print_in_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_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; + + read_lock(&mpls_mii_lock); + + RADIX_VISIT_ALL(&mii_tree,mpls_in_info_node,next,MPLS_TREE_BITS, + mpls_print_in_label_node,&print); + + read_unlock(&mpls_mii_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; +} + +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; + + read_lock(&mpls_moi_lock); + + RADIX_VISIT_ALL(&moi_tree,mpls_out_info_node,next,MPLS_TREE_BITS, + mpls_print_out_label_node,&print); + + read_unlock(&mpls_moi_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; +} + +int mpls_labelspace_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + struct net_device *dev = NULL; + int labelspace; + 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) { + labelspace = dev->mpls_ptr?((struct mpls_interface*)(dev->mpls_ptr))->labelspace:-1; + if(labelspace >= 0) { + if(!mpls_check_print_info(&print,6+IFNAMSIZ)) { + size = sprintf(print.buffer+print.len,"%s\t%d\t%d\n",dev->name, + labelspace,atomic_read(&dev->refcnt)); + 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; +} + +int mpls_tunnel_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + struct mpls_tunnel_private *ptr; + int size; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + write_lock(&mpls_tunnel_lock); + + for(ptr = mpls_tunnel_list;ptr;ptr = ptr->next) { + if(!mpls_check_print_info(&print,9+IFNAMSIZ)) { + size = sprintf(print.buffer+print.len,"%s\t0x%08x\n",ptr->mtp_dev->name, + ptr->mtp_moi?ptr->mtp_moi->moi_key:0); + mpls_adjust_print_info(size,&print); + } else { + break; + } + } + + write_unlock(&mpls_tunnel_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; +} + +int mpls_version_info(char *buffer, char **start, off_t offset, int length) { + struct mpls_print_info print; + int size; + + print.buffer = buffer; + print.offset = offset; + print.length = length; + print.len = 0; + print.pos = 0; + print.begin = 0; + + if(!mpls_check_print_info(&print,10)) { + size = sprintf(print.buffer+print.len,"%08x\n", MPLS_LINUX_VERSION); + mpls_adjust_print_info(size,&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; +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_ref.c linux-2.4.29-wt1-mpls/net/mpls/mpls_ref.c --- linux-2.4.29-wt1/net/mpls/mpls_ref.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_ref.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,124 @@ +/* + * 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 + * + * 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 +#include + +extern kmem_cache_t *mpls_label_cachep; + +void mpls_in_info_hold(struct mpls_in_info *mii) { + const char *fn_name = "mpls_in_info_hold"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(mii) { + atomic_inc(&mii->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&mii->__refcnt))); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} +void mpls_in_info_release(struct mpls_in_info *mii) { + const char *fn_name = "mpls_in_info_release"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(mii) { + atomic_dec(&mii->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&mii->__refcnt))); + if(!atomic_read(&mii->__refcnt)) { + __mpls_del_in_label(mii); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void mpls_out_info_hold(struct mpls_out_info *moi) { + const char *fn_name = "mpls_out_info_hold"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(moi) { + atomic_inc(&moi->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&moi->__refcnt))); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} +void mpls_out_info_release(struct mpls_out_info *moi) { + const char *fn_name = "mpls_out_info_release"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(moi) { + atomic_dec(&moi->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&moi->__refcnt))); + if(!atomic_read(&moi->__refcnt)) { + __mpls_del_out_label(moi); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void mpls_label_hold(struct mpls_label *ml) { + const char *fn_name = "mpls_label_hold"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(ml) { + atomic_inc(&ml->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&ml->__refcnt))); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} +void mpls_label_release(struct mpls_label *ml) { + const char *fn_name = "mpls_label_release"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(ml) { + atomic_dec(&ml->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&ml->__refcnt))); + if(!atomic_read(&ml->__refcnt)) { + kmem_cache_free(mpls_label_cachep,ml); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void mpls_dst_hold(struct mpls_dst *md) { + const char *fn_name = "mpls_dst_hold"; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + if(md) { + atomic_inc(&md->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&md->__refcnt))); + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} + +void mpls_dst_release(struct mpls_dst *md) { + const char *fn_name = "mpls_dst_release"; + + MPLS_DEBUG(("%s: enter %p\n",fn_name,md)); + if(md) { + atomic_dec(&md->__refcnt); + MPLS_DEBUG(("%s: new count %d\n",fn_name,atomic_read(&md->__refcnt))); + if(!atomic_read(&md->__refcnt)) { + if (md->md_dst) { + MPLS_DEBUG(("%s: dst release %p\n",fn_name,md->md_dst)); + dst_destroy(md->md_dst); + } + kfree(md); + } + } + MPLS_DEBUG(("%s: exit\n",fn_name)); +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_tunnel.c linux-2.4.29-wt1-mpls/net/mpls/mpls_tunnel.c --- linux-2.4.29-wt1/net/mpls/mpls_tunnel.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_tunnel.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,262 @@ +/* + * 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 + * + * 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 + +#if 0 +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; +}; +#endif + +extern struct mpls_out_info_tree moi_tree; +static int mpls_tunnel_dev_init(struct net_device *dev); + +struct mpls_tunnel_private* mpls_tunnel_list; +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; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + memcpy(&ml,&ifr->ifr_data,sizeof(struct mpls_label)); + mtp = (struct mpls_tunnel_private*)dev->priv; + if (!(moi = mpls_get_moi(mpls_label2key(ml.ml_index,&ml)))) { + retval = -ESRCH; + MPLS_DEBUG(("%s: error getting node in radix tree\n",fn_name)); + return retval; + } + + mtp->mtp_moi = moi; + dev->iflink = ml.ml_index; + dev->mtu = moi->moi_mtu; + 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; + } + + if(!(dev = (struct net_device*)kmalloc(sizeof(struct net_device)+ + sizeof(struct mpls_tunnel_private),GFP_KERNEL))) { + return NULL; + } + + memset(dev,0,sizeof(struct net_device)+sizeof(struct mpls_tunnel_private)); + + mtp = (struct mpls_tunnel_private*)(&dev[1]); + dev->priv = (void*)mtp; + mtp->mtp_dev = dev; + dev->init = mpls_tunnel_dev_init; + dev->features |= NETIF_F_DYNALLOC; + 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) { + /* can't do this, priv is alloced WITH the net_device + * 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)); + + if(skb->protocol == __constant_htons(ETH_P_MPLS_UC)) { + mpr.bos = 0; + } else { + mpr.bos = 1; + } + + dev->trans_start = jiffies; + + if(mtp->mtp_moi) { + mtp->stat.tx_packets++; + mtp->stat.tx_bytes += skb->len; + return mpls_output2(skb,mtp->mtp_moi,&mpr); + } + + dev_kfree_skb(skb); + mtp->stat.tx_errors++; + + MPLS_DEBUG(("%s: exit\n",fn_name)); + return 0; +} + +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) { + struct mpls_tunnel_private *mtp = (struct mpls_tunnel_private*)dev->priv; + + if (new_mtu < 4 || new_mtu > mtp->mtp_moi->moi_mtu) + 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->type = ARPHRD_MPLS_TUNNEL; + dev->hard_header_len = sizeof(u32); + dev->mtu = 1500; + dev->flags = IFF_NOARP|IFF_POINTOPOINT; + dev->iflink = 0; + dev->addr_len = 4; +} + +static int mpls_tunnel_dev_init(struct net_device *dev) { + mpls_tunnel_init_gen(dev); + return 0; +} + +int __init mpls_tunnel_init(void) { + mpls_tunnel_list = NULL; + return 0; +} diff -urN linux-2.4.29-wt1/net/mpls/mpls_utils.c linux-2.4.29-wt1-mpls/net/mpls/mpls_utils.c --- linux-2.4.29-wt1/net/mpls/mpls_utils.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.29-wt1-mpls/net/mpls/mpls_utils.c Sun Feb 6 18:27:29 2005 @@ -0,0 +1,884 @@ +/* + * 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 + * + * It implements: + * -various common functions called by the rest of the MPLS + * stack + * + * 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 +#include +#include +#include + +extern kmem_cache_t *mpls_label_cachep; +extern struct dst_ops ipv4_dst_ops; + +struct mpls_atm_key { + unsigned int type:2; + unsigned int index:8; + unsigned int vpi:8; + unsigned int vci:14; +}; + +struct mpls_gen_key { + unsigned int type:2; + unsigned int index:10; + unsigned int gen:20; +}; + +struct mpls_fr_key { + unsigned int type:2; + unsigned int index:10; + unsigned int fr:20; +}; + +struct mpls_key { + union { + struct mpls_atm_key atm; + struct mpls_gen_key gen; + struct mpls_fr_key fr; + unsigned int mark; + } u; +}; + +static struct mpls_dst *mpls_make_dst(unsigned int ifi,struct sockaddr *nh, + struct mpls_out_info *moi) { + struct net_device *dev = NULL; + struct mpls_dst *md = NULL; + struct rtable *rt = NULL; + unsigned int nhip; + + MPLS_DEBUG(("mpls_make_dst: enter\n")); + + if (!(dev = dev_get_by_index(ifi))) { + goto mpls_make_dst_4; + } + + if (!dev->mpls_ptr) { + dev->mpls_ptr = mpls_create_if_info(); + if (!dev->mpls_ptr) { + goto mpls_make_dst_3; + } + } + + if (!(md = (struct mpls_dst*)kmalloc(sizeof(struct mpls_dst),GFP_ATOMIC))) { + goto mpls_make_dst_2; + } + memset(md,0,sizeof(struct mpls_dst)); + mpls_dst_hold(md); + + if (!(rt = (struct rtable*)dst_alloc(&ipv4_dst_ops))) { + goto mpls_make_dst_1; + } + nhip = ((struct sockaddr_in*)nh)->sin_addr.s_addr; + + 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 = nhip; + rt->rt_gateway = nhip; + + memcpy(&md->md_nh,nh,sizeof(struct sockaddr)); + md->md_dst = (struct dst_entry*)rt; + md->md_dst->flags = DST_HOST; + md->md_dst->dev = dev; + md->md_dst->input = mpls_output; + md->md_dst->output = mpls_output; + md->md_dst->lastuse = jiffies; + md->md_dst->neighbour = NULL; + md->md_dst->hh = NULL; + md->md_dst->obsolete = 0; + /* no reason to hold the moi because this mpls_dst belongs to the moi ... */ + md->md_dst->mpls_moi = moi; + + if(arp_bind_neighbour(md->md_dst)) { + MPLS_DEBUG(("mpls_make_dst: bind neighbor failed\n")); + mpls_dst_release(md); + md = NULL; + } + + MPLS_DEBUG(("mpls_make_dst: exit(%p)\n",md)); + return md; + +mpls_make_dst_1: + mpls_dst_release(md); + +mpls_make_dst_2: + mpls_delete_if_info(dev->mpls_ptr); + +mpls_make_dst_3: + dev_put(dev); + +mpls_make_dst_4: + MPLS_DEBUG(("mpls_make_dst: exit(%p)\n",md)); + return NULL; +} + +void mpls_instruction_copy(struct mpls_instruction *out, + struct mpls_instruction *in,int length) { + int i; + + for(i=0;imoi_entry; + } else { + entry = &pmoi->moi_entry; + } + if (!list_empty(entry)) + list_del_init(entry); + + mpls_out_info_release(moi); + break; + } +#ifdef CONFIG_NETFILTER + case MPLS_OP_NF_FWD: + { + struct mpls_nfmark_fwd_info *nfi = + (struct mpls_nfmark_fwd_info*)instruction[i].mi_data; + struct mpls_out_info *moi = NULL; + int i; + + for(i=0;infi_moi[i])) { + mpls_out_info_release(moi); + } + } + kfree(nfi); + break; + } +#endif + case MPLS_OP_DS_FWD: + { + struct mpls_dsmark_fwd_info *dfi = + (struct mpls_dsmark_fwd_info*)instruction[i].mi_data; + struct mpls_out_info *moi = NULL; + int i; + + for(i=0;idfi_moi[i])) { + mpls_out_info_release(moi); + } + } + kfree(dfi); + break; + } + case MPLS_OP_EXP_FWD: + { + struct mpls_exp_fwd_info *efi = + (struct mpls_exp_fwd_info*)instruction[i].mi_data; + struct mpls_out_info *moi = NULL; + int i; + + for(i=0;iefi_moi[i])) { + mpls_out_info_release(moi); + } + } + kfree(efi); + break; + } + case MPLS_OP_SET_RX: + { + struct net_device *dev; + + /* dev is already being held */ + dev = (struct net_device*)instruction[i].mi_data; + + if (!list_empty(&pmii->dev_entry)) + list_del_init(&pmii->dev_entry); + + dev_put(dev); + break; + } + case MPLS_OP_SET: + { + struct net_device *dev = NULL; + + struct mpls_dst *mdst = (struct mpls_dst*)instruction[i].mi_data; + dev = mdst->md_dst->dev; + + /* hold device so mpls_dst_release doesn't delete it */ + dev_hold(dev); + mpls_dst_release(mdst); + + if (!list_empty(&pmoi->dev_entry)) + list_del_init(&pmoi->dev_entry); + + dev_put(dev); + break; + } +#ifdef CONFIG_NET_SCHED + case MPLS_OP_SET_TC: + { + kfree((unsigned short*)instruction[i].mi_data); + break; + } +#endif + case MPLS_OP_SET_DS: + case MPLS_OP_SET_EXP: + { + kfree((unsigned char*)instruction[i].mi_data); + break; + } + case MPLS_OP_EXP2DS: + { + kfree((struct mpls_exp2dsmark_info*)instruction[i].mi_data); + break; + } +#ifdef CONFIG_NET_SCHED + case MPLS_OP_EXP2TC: + { + kfree((struct mpls_exp2tcindex_info*)instruction[i].mi_data); + break; + } +#endif + case MPLS_OP_DS2EXP: + { + kfree((struct mpls_dsmark2exp_info*)instruction[i].mi_data); + break; + } +#ifdef CONFIG_NET_SCHED + case MPLS_OP_TC2EXP: + { + kfree((struct mpls_tcindex2exp_info*)instruction[i].mi_data); + break; + } +#endif +#ifdef CONFIG_NETFILTER + case MPLS_OP_NF2EXP: + { + kfree((struct mpls_nfmark2exp_info*)instruction[i].mi_data); + break; + } +#endif + } + } + MPLS_DEBUG(("%s: exit\n",func)); +} + +int mpls_instruction_build(struct mpls_instruction_req *mir, + struct mpls_instruction *instruction,int size, void *parent) { + const char *fn_name = "mpls_instruction_build"; + struct mpls_out_info *moi = NULL; + struct mpls_out_info *pmoi = NULL; + struct mpls_in_info *pmii = NULL; + struct mpls_label *ml = NULL; + int retval = -ENXIO; + unsigned int key = 0; + int last_able = 0; + int num_push = 0; + int i; + + unsigned short opcode = MPLS_OP_NOP; + void* data = 0; + int length = 0; + + MPLS_DEBUG(("%s: enter\n",fn_name)); + + if (mir->mir_direction == MPLS_IN) { + pmii = parent; + } else { + pmoi = parent; + } + + if(mir->mir_instruction_length > size) + goto mpls_instruction_build_cleanup; + + for(i = 0;imir_instruction_length;i++) { + opcode = mir->mir_instruction[i].mir_opcode; + last_able = 0; + data = NULL; + + switch(opcode) { + case MPLS_OP_POP: + { + break; + } + case MPLS_OP_PEEK: + { + last_able = 1; + break; + } + case MPLS_OP_PUSH: + { + ml = (struct mpls_label*)kmem_cache_alloc(mpls_label_cachep,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,sizeof(*ml)); + atomic_set(&ml->__refcnt,0); + mpls_label_hold(ml); + if(mpls_debug) { + printk("%s: push label "); + mpls_print_label(ml); + } + + data = (void*)ml; + num_push++; + break; + } + case MPLS_OP_DLV: + { + if(mir->mir_direction != MPLS_IN) { + retval = -EINVAL; + MPLS_DEBUG(("%s: DLV only valid for incoming labels\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + + last_able = 1; + data = NULL; + break; + } + case MPLS_OP_FWD: + { + key = mpls_label2key(mir->mir_instruction[i].mir_data.fwd.ml_index, + &mir->mir_instruction[i].mir_data.fwd); + if(!(moi = mpls_get_moi(key))) { + retval = -ESRCH; + goto mpls_instruction_build_cleanup; + } + if(pmoi) { + pmoi->moi_mtu = moi->moi_mtu - (4 * num_push); + pmoi->moi_mtu_limit = pmoi->moi_mtu; + list_add(&pmoi->moi_entry,&moi->list_out); + } else { + list_add(&pmii->moi_entry,&moi->list_in); + } + data = (void*)moi; + last_able = 1; + break; + } +#ifdef CONFIG_NETFILTER + case MPLS_OP_NF_FWD: + { + struct mpls_nfmark_fwd_info *nfi; + struct mpls_out_info *moi; + unsigned int min_mtu = 0xFFFFFFFF; + int j; + + nfi = (struct mpls_nfmark_fwd_info*)kmalloc(sizeof(*nfi),GFP_ATOMIC); + if(!nfi) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: NF_FWD error building NFMARK info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + memset(nfi,0,sizeof(*nfi)); + nfi->nfi_mask = mir->mir_instruction[i].mir_data.nf_fwd.nf_mask; + if (nfi->nfi_mask >= MPLS_NFMARK_NUM) { + MPLS_DEBUG(("%s: NF_FWD mask(%02x) allows too large of values\n", + fn_name,nfi->nfi_mask)); + goto mpls_instruction_build_cleanup; + } + + for(j=0;jmir_instruction[i].mir_data.nf_fwd.nf_key[j]) { + continue; + } + moi = mpls_get_moi(mir->mir_instruction[i].mir_data.nf_fwd.nf_key[j]); + if(!moi) { + MPLS_DEBUG(("%s: NF_FWD couldn't find out info with key %08x\n", + fn_name, mir->mir_instruction[i].mir_data.nf_fwd.nf_key[j])); + goto mpls_instruction_build_cleanup; + } + if (moi->moi_mtu < min_mtu) { + min_mtu = moi->moi_mtu; + } + nfi->nfi_moi[j] = moi; + } + + if(pmoi) { + pmoi->moi_mtu = min_mtu - (4 * num_push); + pmoi->moi_mtu_limit = pmoi->moi_mtu; + } + data = (void*)nfi; + last_able = 1; + break; + } +#endif + case MPLS_OP_DS_FWD: + { + struct mpls_dsmark_fwd_info *dfi; + struct mpls_out_info *moi; + unsigned int min_mtu = 0xFFFFFFFF; + int j; + + dfi = (struct mpls_dsmark_fwd_info*)kmalloc(sizeof(*dfi),GFP_ATOMIC); + if(!dfi) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: DS_FWD error building DSMARK info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + memset(dfi,0,sizeof(*dfi)); + dfi->dfi_mask = mir->mir_instruction[i].mir_data.ds_fwd.df_mask; + if (dfi->dfi_mask >= MPLS_DSMARK_NUM) { + MPLS_DEBUG(("%s: DS_FWD mask(%02x) allows too large of values\n", + fn_name,dfi->dfi_mask)); + goto mpls_instruction_build_cleanup; + } + + for(j=0;jmir_instruction[i].mir_data.ds_fwd.df_key[j]) { + continue; + } + moi = mpls_get_moi(mir->mir_instruction[i].mir_data.ds_fwd.df_key[j]); + if(!moi) { + MPLS_DEBUG(("%s: DS_FWD couldn't find out info with key %08x\n", + fn_name, mir->mir_instruction[i].mir_data.ds_fwd.df_key[j])); + goto mpls_instruction_build_cleanup; + } + if (moi->moi_mtu < min_mtu) { + min_mtu = moi->moi_mtu; + } + dfi->dfi_moi[j] = moi; + } + + if(pmoi) { + pmoi->moi_mtu = min_mtu - (4 * num_push); + pmoi->moi_mtu_limit = pmoi->moi_mtu; + } + data = (void*)dfi; + last_able = 1; + break; + } + case MPLS_OP_EXP_FWD: + { + struct mpls_exp_fwd_info *efi; + struct mpls_out_info *moi; + unsigned int min_mtu = 0xFFFFFFFF; + int j; + + efi = (struct mpls_exp_fwd_info*)kmalloc(sizeof(*efi),GFP_ATOMIC); + if(!efi) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: EXP_FWD error building EXP info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + memset(efi,0,sizeof(*efi)); + for(j=0;jmir_instruction[i].mir_data.exp_fwd.ef_key[j]) { + continue; + } + moi = mpls_get_moi(mir->mir_instruction[i].mir_data.exp_fwd.ef_key[j]); + if(!moi) { + MPLS_DEBUG(("%s: EXP_FWD couldn't find out info with key %08x\n", + fn_name, mir->mir_instruction[i].mir_data.exp_fwd.ef_key[j])); + goto mpls_instruction_build_cleanup; + } + if (moi->moi_mtu < min_mtu) { + min_mtu = moi->moi_mtu; + } + efi->efi_moi[j] = moi; + } + + if(pmoi) { + pmoi->moi_mtu = min_mtu - (4 * num_push); + pmoi->moi_mtu_limit = pmoi->moi_mtu; + } + data = (void*)efi; + last_able = 1; + break; + } + case MPLS_OP_SET_RX: + { + struct net_device *dev; + + dev = dev_get_by_index(mir->mir_instruction[i].mir_data.set_rx); + if(!dev) { + retval = -ESRCH; + MPLS_DEBUG(("%s: SET_RX couldn't find a interface with index %d\n", + fn_name, mir->mir_instruction[i].mir_data.set_rx)); + goto mpls_instruction_build_cleanup; + } + data = (void*)dev; + /* NOTE: we're still holding a ref to dev */ + list_add(&pmii->dev_entry, + &((struct mpls_interface*)dev->mpls_ptr)->list_in); + break; + } + case MPLS_OP_SET: + { + struct net_device *dev; + struct mpls_dst *md = NULL; + + dev = dev_get_by_index(mir->mir_instruction[i].mir_data.set.mni_if); + if(!dev) { + retval = -ESRCH; + MPLS_DEBUG(("%s: SET couldn't find a interface with index %d\n", + fn_name, mir->mir_instruction[i].mir_data.set.mni_if)); + goto mpls_instruction_build_cleanup; + } + + if (!dev->mpls_ptr) { + if (!(dev->mpls_ptr = mpls_create_if_info())) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: SET error building MPLS IF info\n",fn_name)); + dev_put(dev); + goto mpls_instruction_build_cleanup; + } + } + + /* NOTE: mpls_make_dst holds the dev, + * so release the hold from dev lookup*/ + md = mpls_make_dst(mir->mir_instruction[i].mir_data.set.mni_if, + &mir->mir_instruction[i].mir_data.set.mni_addr,moi); + dev_put(dev); + + if(!md) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: SET error building DST info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + pmoi->moi_mtu = dev->mtu - (4 * num_push); + pmoi->moi_mtu_limit = pmoi->moi_mtu; + data = (void*)md; + last_able = 1; + list_add(&pmoi->dev_entry, + &((struct mpls_interface*)dev->mpls_ptr)->list_out); + break; + } + case MPLS_OP_SET_TC: + { + unsigned short *tc; + tc = (unsigned short*)kmalloc(sizeof(*tc),GFP_ATOMIC); + if(!tc) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: SET_TC error building TC info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + *tc = mir->mir_instruction[i].mir_data.set_tc; + data = (void*)tc; + break; + } + case MPLS_OP_SET_DS: + { + unsigned char *ds; + ds = (unsigned char*)kmalloc(sizeof(*ds),GFP_ATOMIC); + if(!ds) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: SET_DS error building DS info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + *ds = mir->mir_instruction[i].mir_data.set_ds; + if (*ds > 0x3f) { + MPLS_DEBUG(("%s: SET_DS DS(%02x) too big\n",fn_name,*ds)); + goto mpls_instruction_build_cleanup; + } + data = (void*)ds; + break; + } + case MPLS_OP_SET_EXP: + { + unsigned char *exp; + exp = (unsigned char*)kmalloc(sizeof(*exp),GFP_ATOMIC); + if(!exp) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: SET_EXP error building EXP info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + *exp = mir->mir_instruction[i].mir_data.set_exp; + if (*exp >= MPLS_EXP_NUM) { + MPLS_DEBUG(("%s: SET_EXP EXP(%d) too big\n",fn_name,*exp)); + goto mpls_instruction_build_cleanup; + } + data = (void*)exp; + break; + } +#ifdef CONFIG_NET_SCHED + case MPLS_OP_EXP2TC: + { + struct mpls_exp2tcindex_info *e2ti; + int j; + + e2ti = (struct mpls_exp2tcindex_info*)kmalloc(sizeof(*e2ti), GFP_ATOMIC); + if(!e2ti) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: EXP2TC error building TC info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + for(j = 0;je2t[j] = mir->mir_instruction[i].mir_data.exp2tc.e2t[j]; + } + data = (void*)e2ti; + break; + } +#endif + case MPLS_OP_EXP2DS: + { + struct mpls_exp2dsmark_info *e2di = NULL; + int j; + + e2di = (struct mpls_exp2dsmark_info*)kmalloc(sizeof(*e2di), GFP_ATOMIC); + if(!e2di) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: error building DSMARK info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + for(j = 0;je2d[j] = mir->mir_instruction[i].mir_data.exp2ds.e2d[j]; + } + data = (void*)e2di; + break; + } +#ifdef CONFIG_NET_SCHED + case MPLS_OP_TC2EXP: + { + struct mpls_tcindex2exp_info *t2ei; + int j; + + t2ei = (struct mpls_tcindex2exp_info*)kmalloc(sizeof(*t2ei), GFP_ATOMIC); + if(!t2ei) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: TC2EXP error building EXP info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + t2ei->t2e_mask = mir->mir_instruction[i].mir_data.tc2exp.t2e_mask; + if (t2ei->t2e_mask >= MPLS_TCINDEX_NUM) { + MPLS_DEBUG(("%s: TC2EXP mask(%02x) allows too large of values\n", + fn_name,t2ei->t2e_mask)); + goto mpls_instruction_build_cleanup; + } + for(j = 0;jt2e[j] = mir->mir_instruction[i].mir_data.tc2exp.t2e[j]; + } + data = (void*)t2ei; + break; + } +#endif + case MPLS_OP_DS2EXP: + { + struct mpls_dsmark2exp_info *d2ei; + int j; + + d2ei = (struct mpls_dsmark2exp_info*)kmalloc(sizeof(*d2ei), GFP_ATOMIC); + if(!d2ei) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: DS2EXP error building EXP info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + d2ei->d2e_mask = mir->mir_instruction[i].mir_data.ds2exp.d2e_mask; + if (d2ei->d2e_mask >= MPLS_DSMARK_NUM) { + MPLS_DEBUG(("%s: DS2EXP mask(%02x) allows too large of values\n", + fn_name,d2ei->d2e_mask)); + goto mpls_instruction_build_cleanup; + } + for(j = 0;jd2e[j] = mir->mir_instruction[i].mir_data.ds2exp.d2e[j]; + } + data = (void*)d2ei; + break; + } +#ifdef CONFIG_NETFILTER + case MPLS_OP_NF2EXP: + { + struct mpls_nfmark2exp_info *n2ei; + int j; + + n2ei = (struct mpls_nfmark2exp_info*)kmalloc(sizeof(*n2ei), GFP_ATOMIC); + if(!n2ei) { + retval = -ENOMEM; + MPLS_DEBUG(("%s: NF2EXP error building EXP info\n",fn_name)); + goto mpls_instruction_build_cleanup; + } + n2ei->n2e_mask = mir->mir_instruction[i].mir_data.nf2exp.n2e_mask; + if (n2ei->n2e_mask >= MPLS_NFMARK_NUM) { + MPLS_DEBUG(("%s: NF2EXP mask(%02x) allows too large of values\n", + fn_name,n2ei->n2e_mask)); + goto mpls_instruction_build_cleanup; + } + for(j = 0;jn2e[j] = mir->mir_instruction[i].mir_data.nf2exp.n2e[j]; + } + data = (void*)n2ei; + break; + } +#endif + default: + { + MPLS_DEBUG(("%s: unsupport opcode: %d\n",fn_name,opcode)); + goto mpls_instruction_build_cleanup; + break; + } + } + + instruction[i].mi_opcode = opcode; + instruction[i].mi_data = data; + length++; + } + + if(!last_able) { + MPLS_DEBUG(("%s: invalid ending opcode: opcode = %d, length = %d\n", + fn_name,opcode,length)); + goto mpls_instruction_build_cleanup; + } + + rt_cache_flush(0); + + MPLS_DEBUG(("%s: exit(%d)\n",fn_name,length)); + return length; + +mpls_instruction_build_cleanup: + if(length) { + mpls_instruction_clear(instruction,length,mir->mir_direction,parent); + } + + 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; + int labelspace2; + + read_lock(&dev_base_lock); + + for (dev = dev_base; dev != NULL; dev = dev->next) { + labelspace2 = dev->mpls_ptr?((struct mpls_interface*)(dev->mpls_ptr))->labelspace:-1; + if(labelspace2 == 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; + } +} + +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; + case MPLS_LABEL_KEY: + temp.u.mark = label->u.ml_key; + break; + default: + } + return temp.u.mark; +} + +void mpls_skb_dump(struct sk_buff* sk) { + unsigned int i; + + if (!mpls_debug) return; + + printk("mpls_skb_dump: from %s with len %d (%d) headroom=%d tailroom=%d\n", + sk->dev?sk->dev->name:" net 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"); +} diff -urN linux-2.4.29-wt1/net/netsyms.c linux-2.4.29-wt1-mpls/net/netsyms.c --- linux-2.4.29-wt1/net/netsyms.c Sun Feb 6 18:19:26 2005 +++ linux-2.4.29-wt1-mpls/net/netsyms.c Sun Feb 6 18:27:29 2005 @@ -616,6 +616,14 @@ EXPORT_SYMBOL(nf_log_unregister); EXPORT_SYMBOL(nf_log_packet); EXPORT_SYMBOL(nf_log); + +#ifdef CONFIG_MPLS +#include +EXPORT_SYMBOL(mpls_output); +EXPORT_SYMBOL(mpls_get_moi); +EXPORT_SYMBOL(mpls_set_nexthop); +#endif + #ifdef CONFIG_INET #include EXPORT_SYMBOL(ip_route_me_harder);