├── .gitignore ├── logo.md ├── logo.jpg ├── LICENSE ├── bgp_fsm.go ├── README.md ├── bgp_util_funcs.go ├── bgp_ipv6_ucast.go ├── bgp_mp_generic.go ├── simple_bgp_injector_test.go ├── simple_injector_arch.md ├── bgp_net.go ├── bgp_ipv4_ucast.go ├── bgp_capabilities.go ├── bgp_path_attrs.go ├── bgp_msgs.go ├── bgp_msgs_test.go └── simple_bgp_injector.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /logo.md: -------------------------------------------------------------------------------- 1 | Logo is based on the work of Renée French 2 | -------------------------------------------------------------------------------- /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tehnerd/bgp2go/HEAD/logo.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Nikita V. Shirokov 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of bgp2go nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /bgp_fsm.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | /* 4 | Lots of fields for the future (mb) implementation 5 | */ 6 | type FSM struct { 7 | State string 8 | DelayOpenTime uint32 9 | ConnectRetryCounter uint32 10 | ConnectRetryTimer uint32 11 | ConnectRetryTime uint32 12 | HoldTimer uint32 13 | HoldTime uint32 14 | KeepaliveTimer uint32 15 | KeepaliveTime uint32 16 | } 17 | 18 | /* 19 | This is very(VERY; in most cases not even honors rfc 4271) 20 | simple bgp's FSM. but should works for my 21 | current use cases. if neeed, it will be update and/or totally 22 | rewriten. 23 | */ 24 | func (fsm *FSM) Event(event string) string { 25 | switch event { 26 | case "Start": 27 | fsm.State = "Connect" 28 | return "Connect" 29 | case "OpenRcv": 30 | if fsm.State == "Connect" { 31 | fsm.State = "OpenConfirm" 32 | // we must send back open msg + keepalive 33 | return "OpenKA" 34 | } else if fsm.State == "OpenSent" { 35 | return "Keepalive" 36 | } 37 | case "OpenSent": 38 | if fsm.State == "Connect" { 39 | fsm.State = "OpenSent" 40 | return "WaitConfirm" 41 | } 42 | case "Keepalive": 43 | if fsm.State == "OpenConfirm" || fsm.State == "OpenSent" { 44 | fsm.State = "Established" 45 | return "Established" 46 | } else if fsm.State == "Established" { 47 | return "Keepalive" 48 | } 49 | case "Update": 50 | if fsm.State == "Established" { 51 | return "Established" 52 | } 53 | //Any type of errors. mostly placeholder 54 | default: 55 | fsm.State = "Connect" 56 | return "Notification" 57 | } 58 | fsm.State = "Connect" 59 | return "Generic FSM Error" 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Golang's bgp implementation (control plane only) 2 | 3 | ### What is it? 4 | This is a package for golang which implements BGP's (rfc 4271 etc) feature sets 5 | 6 | ### Intendent usecases: 7 | The package must allow to participate in bgp exchange. Main goals is to be able to inject locally generated routes to 8 | the bgp domain (for example from the SLBs; i've started this project as a side package, for my keepalived project) as well as 9 | to be able to recieve and process bgp msgs from the peers (for example to be used in some kind of analytic tool) 10 | 11 | ### Where it's now? 12 | Right now i'm trying to implement minimal functionals to be able to exchange ipv4 bgp routes. (we already can parse almost 13 | any msgs from the peers) 14 | 15 | ### Where it's going to be in a... ? 16 | #### Nearest future 17 | The second musthave feature (the first one is working ipv4 implementation) is ipv6 18 | #### Future 19 | I want for this package to be able to parse and/or generate 20 | ''' 21 | IPv4 unicast routes 22 | IPv4 labeled unicast routes 23 | IPv6 unicast routes 24 | IPv6 labeled unicast routes 25 | (and maybe; not yet sure; flowspec) 26 | ''' 27 | And to be able to parse routes for the rest of the know mp-bgp's families (vpns vpls etc etc etc) 28 | 29 | ### Why i dont use exabgp instead? 30 | Because i want to have golang's implementation and it's interesting for me to write this 31 | 32 | ### how active this project will be? 33 | as i can see it right now, it will be my pet project (where i'm going to contribute @ after work hours), so dont expect 34 | that this is going to be fulltime project (well at least while i'm working alone @ in) 35 | -------------------------------------------------------------------------------- /bgp_util_funcs.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | const ( 11 | IPV4_TOTAL_OCTETS = 4 12 | BITS_IN_OCTET = 8 13 | ) 14 | 15 | func IPv4ToUint32(ipv4 string) (uint32, error) { 16 | octets := strings.Split(ipv4, ".") 17 | if len(octets) != IPV4_TOTAL_OCTETS { 18 | return 0, errors.New("cant convert ipv4 to string") 19 | } 20 | ipv4int := uint32(0) 21 | for cntr := 0; cntr < IPV4_TOTAL_OCTETS; cntr++ { 22 | tmpVal, err := strconv.Atoi(octets[cntr]) 23 | if err != nil { 24 | return 0, errors.New("cant convert ipv4 to string") 25 | } 26 | ipv4int += uint32(tmpVal << uint((3-cntr)*BITS_IN_OCTET)) 27 | } 28 | return ipv4int, nil 29 | } 30 | 31 | func Uint32IPv4ToString(ipv4 uint32) string { 32 | ipv4addr := "" 33 | octet := 0 34 | 35 | for cntr := 0; cntr < IPV4_TOTAL_OCTETS; cntr++ { 36 | octet = int((ipv4 >> ((3 - uint(cntr)) * BITS_IN_OCTET)) & 255) 37 | if cntr == 0 { 38 | ipv4addr = strconv.Itoa(octet) 39 | } else { 40 | ipv4addr = strings.Join([]string{ipv4addr, strconv.Itoa(octet)}, ".") 41 | } 42 | } 43 | return ipv4addr 44 | } 45 | 46 | func CommunityPrettyPrint(community uint32) (uint16, uint16) { 47 | var asn uint16 48 | var cpart uint16 //TODO(tehnerd): check rfc for proper naming 49 | asn = uint16(community >> 16 & (1<<16 - 1)) 50 | cpart = uint16(community & (1<<16 - 1)) 51 | return asn, cpart 52 | } 53 | 54 | func PrettyPrintV4NLRI(route IPV4_NLRI, next_hop uint32) { 55 | prefix := Uint32IPv4ToString(route.Prefix) 56 | nh := Uint32IPv4ToString(next_hop) 57 | fmt.Printf("Route: %v/%v label: %v pathid: %v nexthop:%v \n", 58 | prefix, route.Length, route.Label, route.PathID, nh) 59 | } 60 | 61 | func PrintBgpUpdate(bgpRoute *BGPRoute) { 62 | OriginString := "" 63 | switch bgpRoute.ORIGIN { 64 | case ORIGIN_IGP: 65 | OriginString = "IGP" 66 | case ORIGIN_EGP: 67 | OriginString = "EGP" 68 | case ORIGIN_INCOMPLETE: 69 | OriginString = "Incomplete" 70 | } 71 | fmt.Printf("content of bgp update message is:\n") 72 | fmt.Printf("Origin: %v\n", OriginString) 73 | fmt.Printf("AS_PATH: %v\n", bgpRoute.AS_PATH) 74 | if bgpRoute.NEXT_HOP != nil { 75 | fmt.Printf("NEXT_HOP: %v\n", bgpRoute.NEXT_HOP) 76 | } 77 | fmt.Printf("MED: %v\n", bgpRoute.MULTI_EXIT_DISC) 78 | fmt.Printf("Local pref: %v\n", bgpRoute.LOCAL_PREF) 79 | fmt.Printf("is Atomic Aggregate: %v\n", bgpRoute.ATOMIC_AGGR) 80 | for _, community := range bgpRoute.Community { 81 | asn, cpart := CommunityPrettyPrint(community) 82 | fmt.Printf("Community: %v:%v\n", asn, cpart) 83 | } 84 | for _, route := range bgpRoute.Routes { 85 | PrettyPrintV4NLRI(route, bgpRoute.NEXT_HOPv4) 86 | } 87 | 88 | } 89 | 90 | func IPv6StringToAddr(ipv6 string) (IPv6Addr, error) { 91 | var ipv6addr IPv6Addr 92 | ipv6fields := strings.Split(ipv6, ":") 93 | //parts in string's represent of V6 address 94 | if len(ipv6fields) != 8 { 95 | tmpAddrPart := make([]string, 0) 96 | for n, val := range ipv6fields { 97 | if len(val) == 0 { 98 | tmpAddrPart = append(tmpAddrPart, ipv6fields[n+1:]...) 99 | ipv6fields = ipv6fields[:n] 100 | break 101 | } 102 | } 103 | for len(ipv6fields) != (8 - len(tmpAddrPart)) { 104 | ipv6fields = append(ipv6fields, "0") 105 | } 106 | ipv6fields = append(ipv6fields, tmpAddrPart...) 107 | } 108 | for n, part := range ipv6fields { 109 | for len(part) < 4 { 110 | part = "0" + part 111 | } 112 | ipv6fields[n] = part 113 | } 114 | //in ipv6 we have 4parts of 32bits each 115 | for i := 0; i < 4; i++ { 116 | val, err := strconv.ParseUint(ipv6fields[2*i]+ipv6fields[2*i+1], 16, 32) 117 | if err != nil { 118 | return ipv6addr, fmt.Errorf("cant convert string to v6 addr: %v\n", err) 119 | } 120 | ipv6addr[i] = uint32(val) 121 | } 122 | return ipv6addr, nil 123 | } 124 | 125 | func IPv6AddrToString(ipv6addr IPv6Addr) string { 126 | ipv6 := "" 127 | for i := 0; i < 4; i++ { 128 | ipv6 += strconv.FormatUint(uint64(ipv6addr[i]), 16) 129 | ipv6 += ":" 130 | } 131 | return ipv6 132 | } 133 | -------------------------------------------------------------------------------- /bgp_ipv6_ucast.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | ) 8 | 9 | const ( 10 | IPV6_ADDRESS_LEN = 16 11 | ) 12 | 13 | type IPv6Addr [4]uint32 14 | 15 | func (ipv6 IPv6Addr) isEqual(oIpv6 IPv6Addr) bool { 16 | return (ipv6[0] == oIpv6[0] && 17 | ipv6[1] == oIpv6[1] && 18 | ipv6[2] == oIpv6[2] && 19 | ipv6[3] == oIpv6[3]) 20 | } 21 | 22 | type IPV6_NLRI struct { 23 | Length uint8 24 | Prefix IPv6Addr 25 | } 26 | 27 | //TODO(tehnerd): labeled ipv6 and add path for ipv6 28 | 29 | //NH_LEN of 16 is hardcoded rightnow; TODO: support for linklocal 30 | func EncodeIPv6NLRI(nlris []IPV6_NLRI) ([]byte, error) { 31 | buf := new(bytes.Buffer) 32 | encodedNlris := make([]byte, 0) 33 | for _, nlri := range nlris { 34 | err := binary.Write(buf, binary.BigEndian, &nlri.Length) 35 | if err != nil { 36 | return nil, fmt.Errorf("cant encode ipv6 nlri length: %v\n", err) 37 | } 38 | err = binary.Write(buf, binary.BigEndian, &nlri.Prefix) 39 | if err != nil { 40 | return nil, fmt.Errorf("cant encode ipv6 nlri length: %v\n", err) 41 | } 42 | encodingLen := (nlri.Length + 7) / 8 43 | encodedNlris = append(encodedNlris, 44 | buf.Bytes()[:ONE_OCTET+encodingLen]...) 45 | buf.Reset() 46 | } 47 | return encodedNlris, nil 48 | 49 | } 50 | 51 | func DecodeIPv6NLRI(data []byte) ([]IPV6_NLRI, error) { 52 | nlris := make([]IPV6_NLRI, 0) 53 | if len(data) < ONE_OCTET { 54 | return nlris, EndOfRib{} 55 | } 56 | for len(data) > 0 { 57 | ipv6nlri := IPV6_NLRI{} 58 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &ipv6nlri.Length) 59 | if err != nil { 60 | return nlris, fmt.Errorf("cant decode ipv6 nlri length: %v\n", err) 61 | } 62 | data = data[ONE_OCTET:] 63 | prefixPart := make([]byte, 0) 64 | prefixBytes := (ipv6nlri.Length + 7) / 8 65 | prefixPart = append(prefixPart, data[:prefixBytes]...) 66 | for len(prefixPart) < IPV6_ADDRESS_LEN { 67 | prefixPart = append(prefixPart, 0) 68 | } 69 | err = binary.Read(bytes.NewReader(prefixPart), binary.BigEndian, &ipv6nlri.Prefix) 70 | if err != nil { 71 | return nlris, fmt.Errorf("cant decode ipv6 nlri prefix: %v\n", err) 72 | } 73 | nlris = append(nlris, ipv6nlri) 74 | data = data[prefixBytes:] 75 | } 76 | return nlris, nil 77 | } 78 | 79 | func EncodeIPV6_MP_REACH_NLRI(nh IPv6Addr, nlris []IPV6_NLRI) ([]byte, error) { 80 | buf := new(bytes.Buffer) 81 | mpReachHdr := MP_REACH_NLRI_HDR{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST, 82 | NHLength: IPV6_ADDRESS_LEN} 83 | err := binary.Write(buf, binary.BigEndian, &mpReachHdr) 84 | if err != nil { 85 | return nil, err 86 | } 87 | err = binary.Write(buf, binary.BigEndian, &nh) 88 | if err != nil { 89 | return nil, err 90 | } 91 | reserved := uint8(0) 92 | err = binary.Write(buf, binary.BigEndian, &reserved) 93 | if err != nil { 94 | return nil, err 95 | } 96 | encNLRI, err := EncodeIPv6NLRI(nlris) 97 | if err != nil { 98 | return nil, err 99 | } 100 | mp_reach := append(buf.Bytes(), encNLRI...) 101 | return mp_reach, nil 102 | } 103 | 104 | func DecodeIPV6_MP_REACH_NLRI(data []byte, mpHdr MP_REACH_NLRI_HDR) (IPv6Addr, 105 | []IPV6_NLRI, error) { 106 | var nh IPv6Addr 107 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &nh) 108 | if err != nil { 109 | return nh, nil, err 110 | } 111 | /* 112 | TODO: check if len != IPV_ADDRESS_LEN (means that we have encoded link local 113 | as well 114 | one_octet -> reserved field 115 | */ 116 | data = data[mpHdr.NHLength+ONE_OCTET:] 117 | nlris, err := DecodeIPv6NLRI(data) 118 | if err != nil { 119 | return nh, nil, fmt.Errorf("cant decode ipv6 nlri: %v\n", err) 120 | } 121 | return nh, nlris, nil 122 | } 123 | 124 | func EncodeIPV6_MP_UNREACH_NLRI(nlris []IPV6_NLRI) ([]byte, error) { 125 | buf := new(bytes.Buffer) 126 | mpUnreachHdr := MP_UNREACH_NLRI_HDR{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST} 127 | err := binary.Write(buf, binary.BigEndian, &mpUnreachHdr) 128 | if err != nil { 129 | return nil, err 130 | } 131 | encNLRI, err := EncodeIPv6NLRI(nlris) 132 | if err != nil { 133 | return nil, err 134 | } 135 | mp_unreach := append(buf.Bytes(), encNLRI...) 136 | return mp_unreach, nil 137 | } 138 | -------------------------------------------------------------------------------- /bgp_mp_generic.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | ) 8 | 9 | const ( 10 | MP_AFI_IPV4 = 1 11 | MP_AFI_IPV6 = 2 12 | MP_AFI_VPLS = 25 13 | MP_SAFI_UCAST = 1 14 | MP_SAFI_MCAST = 2 15 | MP_SAFI_LABELED = 4 16 | 17 | LABEL_SIZE_BITS = 24 18 | LABEL_BOS = 1 19 | ) 20 | 21 | /* 22 | Detail info could be found in RFC4760 23 | */ 24 | 25 | type MP_REACH_NLRI_HDR struct { 26 | AFI uint16 27 | SAFI uint8 28 | NHLength uint8 29 | //NEXT_HOP variable length 30 | /* 31 | we also have reserved byte, but we dont 32 | add it to this struct coz it will be harder for 33 | us to decode it (we have nh of variable length between 34 | afi/safi/nhlen and reserved) 35 | */ 36 | //RESERVED uint8 (ONE_OCTET) 37 | //MP_NRLI variable length 38 | } 39 | 40 | type MP_UNREACH_NLRI_HDR struct { 41 | AFI uint16 42 | SAFI uint8 43 | //WithdrawRoutes 44 | } 45 | 46 | func DecodeMP_REACH_NLRI_HDR(data []byte) (MP_REACH_NLRI_HDR, error) { 47 | var hdr MP_REACH_NLRI_HDR 48 | if len(data) < FOUR_OCTETS { 49 | return hdr, fmt.Errorf("error in length of mp_reach_nlri hdr\n") 50 | } 51 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &hdr) 52 | if err != nil { 53 | return hdr, fmt.Errorf("cant decode mp_reach_nlri hdr: %v\n", err) 54 | } 55 | return hdr, nil 56 | } 57 | 58 | func DecodeMP_REACH_NLRI(data []byte, bgpRoute *BGPRoute) error { 59 | hdr, err := DecodeMP_REACH_NLRI_HDR(data) 60 | if err != nil { 61 | return err 62 | } 63 | //hdr size 64 | data = data[FOUR_OCTET_SHIFT:] 65 | switch hdr.AFI { 66 | case MP_AFI_IPV4: 67 | switch hdr.SAFI { 68 | case MP_SAFI_UCAST: 69 | nh, nlris, err := DecodeIPV4_MP_REACH_NLRI(bgpRoute.Flags, data, hdr) 70 | if err != nil { 71 | return err 72 | } 73 | bgpRoute.NEXT_HOPv4 = nh 74 | bgpRoute.Routes = append(bgpRoute.Routes, nlris...) 75 | case MP_SAFI_LABELED: 76 | bgpRoute.Flags.Labeled = true 77 | nh, nlris, err := DecodeIPV4_MP_REACH_NLRI(bgpRoute.Flags, data, hdr) 78 | if err != nil { 79 | return err 80 | } 81 | bgpRoute.NEXT_HOPv4 = nh 82 | bgpRoute.Routes = append(bgpRoute.Routes, nlris...) 83 | } 84 | case MP_AFI_IPV6: 85 | switch hdr.SAFI { 86 | case MP_SAFI_UCAST: 87 | nh, nlris, err := DecodeIPV6_MP_REACH_NLRI(data, hdr) 88 | if err != nil { 89 | return err 90 | } 91 | bgpRoute.NEXT_HOPv6 = nh 92 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, nlris...) 93 | } 94 | } 95 | return nil 96 | } 97 | 98 | func DecodeMP_UNREACH_NLRI(data []byte, bgpRoute *BGPRoute) error { 99 | hdr, err := DecodeMP_UNREACH_NLRI_HDR(data) 100 | if err != nil { 101 | return err 102 | } 103 | //unreach hdr size 104 | data = data[THREE_OCTET_SHIFT:] 105 | switch hdr.AFI { 106 | case MP_AFI_IPV4: 107 | switch hdr.SAFI { 108 | case MP_SAFI_UCAST: 109 | nlris, err := DecodeIPv4NLRI(bgpRoute.Flags, data) 110 | if err != nil { 111 | return err 112 | } 113 | bgpRoute.WithdrawRoutes = append(bgpRoute.WithdrawRoutes, 114 | nlris...) 115 | case MP_SAFI_LABELED: 116 | nlris, err := DecodeIPv4NLRI(bgpRoute.Flags, data) 117 | if err != nil { 118 | return err 119 | } 120 | bgpRoute.WithdrawRoutes = append(bgpRoute.WithdrawRoutes, 121 | nlris...) 122 | 123 | } 124 | case MP_AFI_IPV6: 125 | switch hdr.SAFI { 126 | case MP_SAFI_UCAST: 127 | nlris, err := DecodeIPv6NLRI(data) 128 | if err != nil { 129 | return err 130 | } 131 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, 132 | nlris...) 133 | case MP_SAFI_LABELED: 134 | nlris, err := DecodeIPv6NLRI(data) 135 | if err != nil { 136 | return err 137 | } 138 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, 139 | nlris...) 140 | 141 | } 142 | } 143 | return nil 144 | } 145 | 146 | func DecodeMP_UNREACH_NLRI_HDR(data []byte) (MP_UNREACH_NLRI_HDR, error) { 147 | var hdr MP_UNREACH_NLRI_HDR 148 | if len(data) < THREE_OCTETS { 149 | return hdr, fmt.Errorf("error in length of mp_unreach_nlri hdr\n") 150 | } 151 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &hdr) 152 | if err != nil { 153 | return hdr, fmt.Errorf("cant decode mp_unreach_nlri hdr: %v\n", err) 154 | } 155 | return hdr, nil 156 | } 157 | -------------------------------------------------------------------------------- /simple_bgp_injector_test.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func prepareConnectionPassive(contextType string) (SockControlChans, chan BGPCommand, chan BGPCommand) { 9 | scc := SockControlChans{} 10 | scc.Init() 11 | scc.localAddr = "192.168.0.2" 12 | cmndChanTo := make(chan BGPCommand) 13 | cmndChanFrom := make(chan BGPCommand) 14 | rid, _ := IPv4ToUint32("172.16.0.1") 15 | bgpNeighbourContext := BGPNeighbourContext{RouterID: rid, 16 | ASN: 6500, ToMainContext: cmndChanTo, 17 | ToNeighbourContext: cmndChanFrom, 18 | NeighbourAddr: "192.168.0.1"} 19 | if contextType == "mp" { 20 | bgpNeighbourContext.MPCaps = append(bgpNeighbourContext.MPCaps, 21 | MPCapability{AFI: MP_AFI_IPV6, 22 | SAFI: MP_SAFI_UCAST}) 23 | bgpNeighbourContext.MPCaps = append(bgpNeighbourContext.MPCaps, 24 | MPCapability{AFI: MP_AFI_IPV4, 25 | SAFI: MP_SAFI_UCAST}) 26 | } 27 | go StartBGPNeighbourContext(&bgpNeighbourContext, true, scc) 28 | return scc, cmndChanTo, cmndChanFrom 29 | } 30 | 31 | func generateTestNeighbourContext(contextType string) BGPNeighbourContext { 32 | rid, _ := IPv4ToUint32("172.16.0.2") 33 | testContext := BGPNeighbourContext{RouterID: rid, 34 | ASN: 6501, ToMainContext: nil, 35 | ToNeighbourContext: nil, 36 | NeighbourAddr: "192.168.0.2"} 37 | if contextType == "mp" { 38 | testContext.MPCaps = append(testContext.MPCaps, MPCapability{AFI: MP_AFI_IPV6, 39 | SAFI: MP_SAFI_UCAST}) 40 | testContext.MPCaps = append(testContext.MPCaps, MPCapability{AFI: MP_AFI_IPV4, 41 | SAFI: MP_SAFI_UCAST}) 42 | } 43 | return testContext 44 | 45 | } 46 | 47 | func TestSessionInit(t *testing.T) { 48 | fmt.Println("############## SimpleBgpInjector's tests ##############") 49 | testContext := generateTestNeighbourContext("v4") 50 | scc, fromN, toN := prepareConnectionPassive("v4") 51 | //fsm: passive waits for open 52 | GenerateOpenMsg(&testContext, scc.readChan, "") 53 | //collision check 54 | msgFromN := <-fromN 55 | if msgFromN.Cmnd != "PassiveCollisionCheck" { 56 | fmt.Println("###") 57 | fmt.Println(msgFromN.Cmnd) 58 | t.Errorf("error in passive connection fsm. no collision check") 59 | } 60 | toN <- BGPCommand{Cmnd: "NoCollision"} 61 | msgFromN = <-fromN 62 | if msgFromN.Cmnd != "speaksInet" { 63 | fmt.Println("rcved this cmnd instead of expected: ", msgFromN.Cmnd) 64 | t.Errorf("error in mpcap enbaled session open msg handling\n") 65 | return 66 | } 67 | 68 | //passive send open, and then keepalive in response to our open msg 69 | msg := <-scc.writeChan 70 | hdr, err := DecodeMsgHeader(msg) 71 | if err != nil { 72 | t.Errorf("%v\n", err) 73 | } 74 | if hdr.Type != BGP_OPEN_MSG { 75 | t.Errorf("wrong first msg from passive peer") 76 | } 77 | _, err = DecodeOpenMsg(msg[MSG_HDR_SIZE:]) 78 | if err != nil { 79 | t.Errorf("error in parsing open msg from passive: %v\n", err) 80 | } 81 | msg = <-scc.writeChan 82 | hdr, err = DecodeMsgHeader(msg) 83 | if err != nil { 84 | t.Errorf("%v\n", err) 85 | } 86 | if hdr.Type != BGP_KEEPALIVE_MSG { 87 | t.Errorf("error in passive fsm; 2nd msg must be keepalive") 88 | } 89 | scc.readChan <- GenerateKeepalive() 90 | msgFromN = <-fromN 91 | if msgFromN.Cmnd != "PassiveEstablished" { 92 | t.Errorf("error in passive fsm. must be in PassiveEstablished state") 93 | } 94 | toN <- BGPCommand{Cmnd: "Shutdown"} 95 | } 96 | 97 | func TestMPSessionInit(t *testing.T) { 98 | testContext := generateTestNeighbourContext("mp") 99 | scc, fromN, toN := prepareConnectionPassive("mp") 100 | //fsm: passive waits for open 101 | GenerateOpenMsg(&testContext, scc.readChan, "") 102 | //collision check 103 | msgFromN := <-fromN 104 | if msgFromN.Cmnd != "PassiveCollisionCheck" { 105 | fmt.Println("###") 106 | fmt.Println(msgFromN.Cmnd) 107 | t.Errorf("error in passive connection fsm. no collision check") 108 | } 109 | toN <- BGPCommand{Cmnd: "NoCollision"} 110 | for cntr := 0; cntr < len(testContext.MPCaps); cntr++ { 111 | msgFromN = <-fromN 112 | if msgFromN.Cmnd != "speaksInet" && msgFromN.Cmnd != "speaksInet6" { 113 | fmt.Println("rcved this cmnd instead of expected: ", msgFromN.Cmnd) 114 | t.Errorf("error in mpcap enbaled session open msg handling\n") 115 | return 116 | } 117 | } 118 | //passive send open, and then keepalive in response to our open msg 119 | msg := <-scc.writeChan 120 | hdr, err := DecodeMsgHeader(msg) 121 | if err != nil { 122 | t.Errorf("%v\n", err) 123 | } 124 | if hdr.Type != BGP_OPEN_MSG { 125 | t.Errorf("wrong first msg from passive peer") 126 | } 127 | _, err = DecodeOpenMsg(msg[MSG_HDR_SIZE:]) 128 | if err != nil { 129 | t.Errorf("error in parsing open msg from passive: %v\n", err) 130 | } 131 | msg = <-scc.writeChan 132 | hdr, err = DecodeMsgHeader(msg) 133 | if err != nil { 134 | t.Errorf("%v\n", err) 135 | } 136 | if hdr.Type != BGP_KEEPALIVE_MSG { 137 | t.Errorf("error in passive fsm; 2nd msg must be keepalive") 138 | } 139 | scc.readChan <- GenerateKeepalive() 140 | msgFromN = <-fromN 141 | if msgFromN.Cmnd != "PassiveEstablished" { 142 | t.Errorf("error in passive fsm. must be in PassiveEstablished state") 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /simple_injector_arch.md: -------------------------------------------------------------------------------- 1 | ``` 2 | (if listen enable) +-----------------------+ 3 | +-------------------------> listen for connection | 4 | | +-------------------+---+ 5 | cmdns from external+----+--+ | | 6 | +--v------------+-+ | 7 | | bgp main context+--------->control cmnds (to/from)+--+ | 8 | +--+-------+------+ | | 9 | replies to external<----+--+ | | | 10 | | +-------+-+ +-----+------v------v-----+ 11 | v |keepalive| |passive neighbour context| 12 | cntrl cmnds (to/from) | +--+(per neighbour context) +-------+ 13 | + +-------+-+ +-----+-------------------+ | 14 | +---------v+-------------+ | | | 15 | +--------+--+ |start active connection | | | | 16 | | keepalive +------------+(per neighbour context) | +----+ | | 17 | | | +-+-------------+--------+ | | | 18 | +-----------+------+ | | | | | 19 | | | | ++-----v---------+ +-----v-----------+ 20 | | | | | write goroutine| |read goroutine | 21 | | | | |(to neighbour) | |(from neighbour) | 22 | | | | +----------------+ +-----------------+ 23 | | | | 24 | +-------v-------v+ +---v------------+ 25 | | write goroutine| |read goroutine | 26 | |(to neighbour) | |(from neighbour)| 27 | +----------------+ +----------------+ 28 | 29 | ``` 30 | 31 | #### BGP Main Context 32 | ``` 33 | /* 34 | Generic per bgp process data 35 | */ 36 | type BGPContext struct { 37 | ASN uint32 38 | RouterID uint32 39 | //TODO: rib per afi/safi 40 | RIBv4 []IPV4_NLRI 41 | ListenLocal bool 42 | Neighbours []BGPNeighbour 43 | ToMainContext chan BGPCommand 44 | } 45 | ``` 46 | 47 | responsible for storing all the routes and control per neighbour context (send what to advertise, 48 | report about other connections state (for example during collision detection phase) etc) as 49 | well as main point of entry to/from external application. 50 | (we are using chans of 51 | ``` 52 | /* 53 | used to communicate w/ main bgp process from external apps. 54 | For example: 55 | Cmnd: Advertise 56 | Data: ipv4/ipv6 address/mask 57 | or 58 | Cmnd: Withdraw 59 | Data: ipv4/ipv6 address/mask 60 | */ 61 | type BGPProcessMsg struct { 62 | Cmnd string 63 | Data string 64 | } 65 | ``` 66 | for that purpose. 67 | 68 | #### BGP Neighbour context 69 | ``` 70 | type BGPNeighbourContext struct { 71 | ToMainContext chan BGPCommand 72 | ToNeighbourContext chan BGPCommand 73 | /* 74 | used when we have both inboud and outbound coonnection to the same 75 | peer and yet do not know which one is going to be threated as collision 76 | */ 77 | NeighbourAddr string 78 | ASN uint32 79 | RouterID uint32 80 | NextHop string 81 | fsm FSM 82 | //placeholders, not yet implemented 83 | InboundPolicy string 84 | OutboundPolicy string 85 | } 86 | ``` 87 | 88 | responsible for all comunications with external bgp neighbour 89 | (generate bgp msgs, check FSM states etc) 90 | 91 | we are using chans of 92 | ``` 93 | 94 | type BGPCommand struct { 95 | From string 96 | Cmnd string 97 | CmndData string 98 | Route BGPRoute 99 | //For anonymous connections 100 | ResponseChan chan string 101 | //for passive(when someone connected to us) connection to start 102 | sockChans SockControlChans 103 | } 104 | 105 | ``` 106 | for that purpose 107 | -------------------------------------------------------------------------------- /bgp_net.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | /* Generic networking routines for bgp */ 4 | 5 | import ( 6 | "errors" 7 | "fmt" 8 | "net" 9 | "regexp" 10 | "strings" 11 | "syscall" 12 | ) 13 | 14 | const ( 15 | BGP_PORT = "179" 16 | DSCP_CS6 = 192 17 | ) 18 | 19 | var ( 20 | CANT_CONNECT_ERROR = errors.New("cant connect to remote peer") 21 | ) 22 | 23 | type SockControlChans struct { 24 | fromWriteError chan uint8 25 | toWriteError chan uint8 26 | readError chan uint8 27 | toReadError chan uint8 28 | readChan chan []byte 29 | writeChan chan []byte 30 | controlChan chan string 31 | localAddr string 32 | keepaliveFeedback chan uint8 33 | } 34 | 35 | func (sockChans *SockControlChans) Init() { 36 | sockChans.fromWriteError = make(chan uint8) 37 | sockChans.toWriteError = make(chan uint8) 38 | sockChans.readError = make(chan uint8) 39 | sockChans.toReadError = make(chan uint8) 40 | sockChans.readChan = make(chan []byte) 41 | sockChans.writeChan = make(chan []byte) 42 | sockChans.controlChan = make(chan string) 43 | 44 | } 45 | 46 | func ConnectToNeighbour(neighbour string, 47 | fromWriteError, toWriteError, readError, toReadError chan uint8, 48 | readChan, writeChan chan []byte, 49 | controlChan chan string) error { 50 | remoteAddr := strings.Join([]string{neighbour, BGP_PORT}, ":") 51 | tcpAddr, err := net.ResolveTCPAddr("tcp", remoteAddr) 52 | if err != nil { 53 | return fmt.Errorf("cant resolve remote address: %v\n", err) 54 | } 55 | tcpConn, err := net.DialTCP("tcp", nil, tcpAddr) 56 | if err != nil { 57 | return CANT_CONNECT_ERROR 58 | } 59 | //We want to mark our bgp packets with CS6 60 | fd, _ := tcpConn.File() 61 | syscall.SetsockoptInt(int(fd.Fd()), syscall.IPPROTO_IP, syscall.IP_TOS, DSCP_CS6) 62 | fd.Close() 63 | /* 64 | sending our localaddress; so it can be used as NEXT_HOP 65 | */ 66 | host, _, _ := net.SplitHostPort(tcpConn.LocalAddr().String()) 67 | controlChan <- host 68 | go ReadFromNeighbour(tcpConn, readChan, readError, toReadError) 69 | go WriteToNeighbour(tcpConn, writeChan, fromWriteError, toWriteError) 70 | return nil 71 | } 72 | 73 | func ReadFromNeighbour(sock *net.TCPConn, readChan chan []byte, 74 | readError, toReadError chan uint8) { 75 | loop := 1 76 | for loop == 1 { 77 | buf := make([]byte, 1024) 78 | bytes, err := sock.Read(buf) 79 | if err != nil { 80 | select { 81 | case readError <- uint8(1): 82 | loop = 0 83 | continue 84 | case <-toReadError: 85 | loop = 0 86 | continue 87 | } 88 | } 89 | select { 90 | case readChan <- buf[:bytes]: 91 | case <-toReadError: 92 | loop = 0 93 | continue 94 | } 95 | } 96 | } 97 | 98 | func WriteToNeighbour(sock *net.TCPConn, writeChan chan []byte, 99 | fromWriteError, toWriteError chan uint8) { 100 | loop := 1 101 | for loop == 1 { 102 | select { 103 | case msg := <-writeChan: 104 | WRITE: 105 | bytes, err := sock.Write(msg) 106 | if err != nil { 107 | select { 108 | case fromWriteError <- uint8(1): 109 | case <-toWriteError: 110 | } 111 | loop = 0 112 | continue 113 | } 114 | if bytes != len(msg) { 115 | msg = msg[bytes:] 116 | goto WRITE 117 | } 118 | case <-toWriteError: 119 | loop = 0 120 | } 121 | } 122 | 123 | /* 124 | it could be already clossed (for example connection has been closed from the remote side 125 | however we could initate closing as well (for example error in msg parsing) 126 | it both cases(closing a working connection, or clossing a clossed) that shouldnt be a problem. 127 | */ 128 | 129 | sock.Close() 130 | } 131 | 132 | /* 133 | simple_bgp_injector specific routines 134 | 135 | */ 136 | 137 | func BGPListenForConnection(toMainContext chan BGPCommand) error { 138 | addr := strings.Join([]string{"", BGP_PORT}, ":") 139 | tcpAddr, err := net.ResolveTCPAddr("tcp", addr) 140 | //TODO: log instead of return 141 | if err != nil { 142 | return fmt.Errorf("cant parse local address: %v\n", err) 143 | } 144 | servSock, err := net.ListenTCP("tcp", tcpAddr) 145 | if err != nil { 146 | return fmt.Errorf("cant bind to local address: %v\n", err) 147 | } 148 | for { 149 | sock, err := servSock.AcceptTCP() 150 | if err != nil { 151 | sock.Close() 152 | continue 153 | } 154 | fd, _ := sock.File() 155 | syscall.SetsockoptInt(int(fd.Fd()), syscall.IPPROTO_IP, syscall.IP_TOS, DSCP_CS6) 156 | fd.Close() 157 | go ProcessPeerConection(sock, toMainContext) 158 | } 159 | } 160 | 161 | func ProcessPeerConection(sock *net.TCPConn, toMainContext chan BGPCommand) { 162 | radr := strings.Split(sock.RemoteAddr().String(), ":")[0] 163 | sockChans := SockControlChans{} 164 | sockChans.Init() 165 | toMainContext <- BGPCommand{Cmnd: "NewConnection", CmndData: radr, 166 | ResponseChan: sockChans.controlChan} 167 | response := <-sockChans.controlChan 168 | if response == "teardown" { 169 | sock.Close() 170 | return 171 | } 172 | ladr, _, _ := net.SplitHostPort(sock.LocalAddr().String()) 173 | if v4, _ := regexp.MatchString(`^(\d{1,3}\.){3}\d{1,3}$`, ladr); v4 { 174 | toMainContext <- BGPCommand{Cmnd: "NewRouterID", CmndData: ladr} 175 | } 176 | sockChans.localAddr = ladr 177 | go ReadFromNeighbour(sock, sockChans.readChan, sockChans.readError, 178 | sockChans.toReadError) 179 | go WriteToNeighbour(sock, sockChans.writeChan, sockChans.fromWriteError, 180 | sockChans.toWriteError) 181 | toMainContext <- BGPCommand{Cmnd: "AddPassiveNeighbour", CmndData: radr, 182 | sockChans: sockChans} 183 | 184 | } 185 | -------------------------------------------------------------------------------- /bgp_ipv4_ucast.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | ) 8 | 9 | const ( 10 | IPV4_ADDRESS_LEN = 4 11 | ) 12 | 13 | //this is routine for encoding of ipv4 route as mp_reach/unreach nlri (part of) 14 | func EncodeIPv4NLRI(flags RouteFlags, nlris []IPV4_NLRI) ([]byte, error) { 15 | buf := new(bytes.Buffer) 16 | encodedNlris := make([]byte, 0) 17 | for _, nlri := range nlris { 18 | encodingLen := (nlri.Length + 7) / 8 19 | if flags.Labeled { 20 | //Size of the label in octets 21 | nlri.Length += LABEL_SIZE_BITS 22 | } 23 | err := binary.Write(buf, binary.BigEndian, &nlri.Length) 24 | if err != nil { 25 | return nil, fmt.Errorf("cant encode ipv4 nlri's length: %v\n", err) 26 | } 27 | var additionalData uint8 28 | if flags.Labeled { 29 | //mpls label: <20 bits label><3 bits TC(aka exp)><1 bit bos> 30 | label := uint32(((nlri.Label << 4) | LABEL_BOS)) 31 | additionalData += 3 32 | lBuffer := new(bytes.Buffer) 33 | err = binary.Write(lBuffer, binary.BigEndian, &label) 34 | if err != nil { 35 | return nil, fmt.Errorf("cant encode ipv4 nlri's label: %v\n", err) 36 | } 37 | n, _ := buf.Write(lBuffer.Bytes()[1:]) 38 | if n != 3 { 39 | return nil, fmt.Errorf("cant encode ipv4 nlri's label: %v\n", err) 40 | } 41 | } 42 | err = binary.Write(buf, binary.BigEndian, &nlri.Prefix) 43 | if err != nil { 44 | return nil, fmt.Errorf("cant encode ipv6 nlri length: %v\n", err) 45 | } 46 | encodedNlris = append(encodedNlris, 47 | buf.Bytes()[:ONE_OCTET+encodingLen+additionalData]...) 48 | buf.Reset() 49 | } 50 | return encodedNlris, nil 51 | } 52 | 53 | //this is routine for decoding of ipv4 route as mp_reach/unreach nlri 54 | func DecodeIPv4NLRI(flags RouteFlags, data []byte) ([]IPV4_NLRI, error) { 55 | nlris := make([]IPV4_NLRI, 0) 56 | var pathID uint32 57 | if len(data) < ONE_OCTET { 58 | return nlris, EndOfRib{} 59 | } 60 | if flags.WithPathId { 61 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &pathID) 62 | if err != nil { 63 | return nlris, fmt.Errorf("cant decode nlri's pathId: %v\n", err) 64 | } 65 | data = data[FOUR_OCTETS:] 66 | } 67 | for len(data) > 0 { 68 | nlri := IPV4_NLRI{} 69 | nlri.PathID = pathID 70 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &nlri.Length) 71 | if err != nil { 72 | return nlris, fmt.Errorf("cant decode ipv4 nlri length: %v\n", err) 73 | } 74 | data = data[ONE_OCTET:] 75 | if flags.Labeled { 76 | encLabel := make([]byte, 1) 77 | encLabel = append(encLabel, data[:THREE_OCTETS]...) 78 | label := uint32(0) 79 | err := binary.Read(bytes.NewReader(encLabel), binary.BigEndian, &label) 80 | if err != nil { 81 | return nlris, fmt.Errorf("cant decode nlri's label: %v\n", err) 82 | } 83 | nlri.Label = (label >> 4) 84 | nlri.Length -= LABEL_SIZE_BITS 85 | //FIXME(tehnerd): check data size; mailformed packets could result w/ outofbound 86 | if len(data) < 3 { 87 | panic(len(data)) 88 | } 89 | data = data[THREE_OCTETS:] 90 | } 91 | prefixPart := make([]byte, 0) 92 | prefixBytes := (nlri.Length + 7) / 8 93 | prefixPart = append(prefixPart, data[:prefixBytes]...) 94 | for len(prefixPart) < IPV4_ADDRESS_LEN { 95 | prefixPart = append(prefixPart, 0) 96 | } 97 | err = binary.Read(bytes.NewReader(prefixPart), binary.BigEndian, &nlri.Prefix) 98 | if err != nil { 99 | return nlris, fmt.Errorf("cant decode ipv4 nlri prefix: %v\n", err) 100 | } 101 | nlris = append(nlris, nlri) 102 | data = data[prefixBytes:] 103 | } 104 | return nlris, nil 105 | } 106 | 107 | //TODO(tehnerd): accept mp_reach_nlri_hdr as input val for func 108 | func EncodeIPV4_MP_REACH_NLRI(nh uint32, flags RouteFlags, nlris []IPV4_NLRI) ([]byte, error) { 109 | if len(nlris) < 1 { 110 | return nil, fmt.Errorf("zero length NLRIs slice\n") 111 | } 112 | buf := new(bytes.Buffer) 113 | mpReachHdr := MP_REACH_NLRI_HDR{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST, 114 | NHLength: IPV4_ADDRESS_LEN} 115 | err := binary.Write(buf, binary.BigEndian, &mpReachHdr) 116 | if err != nil { 117 | return nil, err 118 | } 119 | err = binary.Write(buf, binary.BigEndian, &nh) 120 | if err != nil { 121 | return nil, err 122 | } 123 | reserved := uint8(0) 124 | err = binary.Write(buf, binary.BigEndian, &reserved) 125 | if err != nil { 126 | return nil, err 127 | } 128 | if flags.WithPathId { 129 | /* 130 | we can group nlris into the same slice only if all of em has the same 131 | bgp's path attrs and same pathID, so it's safe to only look at first nlri for 132 | path's id value 133 | */ 134 | err = binary.Write(buf, binary.BigEndian, &nlris[0].PathID) 135 | if err != nil { 136 | return nil, err 137 | } 138 | } 139 | encNLRI, err := EncodeIPv4NLRI(flags, nlris) 140 | if err != nil { 141 | return nil, err 142 | } 143 | mp_reach := append(buf.Bytes(), encNLRI...) 144 | return mp_reach, nil 145 | } 146 | 147 | func EncodeLabeledIPV4_MP_REACH_NLRI(nh uint32, 148 | flags RouteFlags, nlris []IPV4_NLRI) ([]byte, error) { 149 | if len(nlris) < 1 { 150 | return nil, fmt.Errorf("zero length NLRIs slice\n") 151 | } 152 | buf := new(bytes.Buffer) 153 | mpReachHdr := MP_REACH_NLRI_HDR{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_LABELED, 154 | NHLength: IPV4_ADDRESS_LEN} 155 | err := binary.Write(buf, binary.BigEndian, &mpReachHdr) 156 | if err != nil { 157 | return nil, err 158 | } 159 | err = binary.Write(buf, binary.BigEndian, &nh) 160 | if err != nil { 161 | return nil, err 162 | } 163 | var reserved uint8 164 | err = binary.Write(buf, binary.BigEndian, &reserved) 165 | if err != nil { 166 | return nil, err 167 | } 168 | if flags.WithPathId { 169 | /* same logic as above for ipv4 nlri */ 170 | err = binary.Write(buf, binary.BigEndian, &nlris[0].PathID) 171 | if err != nil { 172 | return nil, err 173 | } 174 | } 175 | encNLRI, err := EncodeIPv4NLRI(flags, nlris) 176 | if err != nil { 177 | return nil, err 178 | } 179 | mp_reach := append(buf.Bytes(), encNLRI...) 180 | return mp_reach, nil 181 | } 182 | 183 | func DecodeIPV4_MP_REACH_NLRI(flags RouteFlags, 184 | data []byte, mpHdr MP_REACH_NLRI_HDR) (uint32, []IPV4_NLRI, error) { 185 | var nh uint32 186 | err := binary.Read(bytes.NewReader(data), binary.BigEndian, &nh) 187 | if err != nil { 188 | return nh, nil, err 189 | } 190 | /* 191 | one_octet -> reserved field 192 | */ 193 | data = data[mpHdr.NHLength+ONE_OCTET:] 194 | nlris, err := DecodeIPv4NLRI(flags, data) 195 | if err != nil { 196 | return nh, nil, fmt.Errorf("cant decode ipv4 nlri: %v\n", err) 197 | } 198 | return nh, nlris, nil 199 | } 200 | 201 | func EncodeIPV4_MP_UNREACH_NLRI(flags RouteFlags, nlris []IPV4_NLRI) ([]byte, error) { 202 | /* 203 | compare to the mp_reach_nlri this one (nlris above) could be 204 | zero len when this path_attr been used as EOR marker 205 | */ 206 | buf := new(bytes.Buffer) 207 | mpUnreachHdr := MP_UNREACH_NLRI_HDR{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST} 208 | err := binary.Write(buf, binary.BigEndian, &mpUnreachHdr) 209 | if err != nil { 210 | return nil, err 211 | } 212 | encNLRI, err := EncodeIPv4NLRI(flags, nlris) 213 | if err != nil { 214 | return nil, err 215 | } 216 | mp_unreach := append(buf.Bytes(), encNLRI...) 217 | return mp_unreach, nil 218 | } 219 | 220 | func EncodeLabeledIPV4_MP_UNREACH_NLRI(flags RouteFlags, nlris []IPV4_NLRI) ([]byte, error) { 221 | buf := new(bytes.Buffer) 222 | mpUnreachHdr := MP_UNREACH_NLRI_HDR{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_LABELED} 223 | err := binary.Write(buf, binary.BigEndian, &mpUnreachHdr) 224 | if err != nil { 225 | return nil, err 226 | } 227 | encNLRI, err := EncodeIPv4NLRI(flags, nlris) 228 | if err != nil { 229 | return nil, err 230 | } 231 | mp_unreach := append(buf.Bytes(), encNLRI...) 232 | return mp_unreach, nil 233 | } 234 | -------------------------------------------------------------------------------- /bgp_capabilities.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | ) 8 | 9 | /* 10 | All details could be found in RFC5492 11 | */ 12 | 13 | const ( 14 | CAPABILITIES_OPTIONAL_PARAM = 2 15 | CAPABILITY_MP_EXTENSION = 1 16 | CAPABILITY_GRACEFUL_RESTART = 64 17 | CAPABILITY_AS4_NUMBER = 65 18 | CAPABILITY_ADD_PATH = 69 19 | MAX_UINT8 = 255 20 | ) 21 | 22 | const ( 23 | GR_TIME_FIELD_SIZE = 12 24 | GR_RESTART_FLAG_OFFSET = 15 25 | GR_FORWARDING_BIT_OFFSET = 7 26 | ) 27 | 28 | type Capability struct { 29 | Code uint8 30 | Length uint8 31 | } 32 | 33 | /* 34 | This is struct where we store session's supported capabilities 35 | XXX: 4byte ASN: implementation must insure, that open msg either contains mappend 2byte asn in 36 | myasn field of open msg, or AS_TRANS(23456) if our asn > 65535 37 | */ 38 | type BGPCapabilities struct { 39 | SupportASN4 bool 40 | ASN4 uint32 41 | AddPath uint8 42 | SupportGR bool 43 | } 44 | 45 | //Multiprotocol Extension 46 | type MPCapability struct { 47 | AFI uint16 48 | _ uint8 49 | SAFI uint8 50 | } 51 | 52 | //ADDPath 53 | type AddPathCapability struct { 54 | AFI uint16 55 | SAFI uint16 56 | /* Send/Recv/both */ 57 | Flags uint8 58 | } 59 | 60 | //Graceful Restart 61 | type GRCapability struct { 62 | FlagsAndTime uint16 63 | /* 64 | Commented because according to RFC: 65 | "When a sender of this capability does not include any in 66 | the capability, it means that the sender is not capable of preserving 67 | its forwarding state during BGP restart, but supports procedures for 68 | the Receiving Speaker (as defined in Section 4.2 of this document). 69 | In that case, the value of the "Restart Time" field advertised by the 70 | sender is irrelevant." 71 | So far no plans to support SSO. 72 | SupportedAF []PerAFISAFIGR 73 | */ 74 | } 75 | 76 | type PerAFISAFIGR struct { 77 | AFI uint16 78 | SAFI uint8 79 | //Forwarding bit and <7 reserved bit> 80 | Flags uint8 81 | } 82 | 83 | func (grc *GRCapability) GetFlags() uint8 { 84 | return uint8(grc.FlagsAndTime >> GR_TIME_FIELD_SIZE) 85 | } 86 | 87 | func (grc *GRCapability) SetFlags(restart bool) { 88 | if restart { 89 | grc.FlagsAndTime |= (1 << GR_RESTART_FLAG_OFFSET) 90 | } else { 91 | grc.FlagsAndTime &= ((1 << GR_RESTART_FLAG_OFFSET) - 1) 92 | } 93 | } 94 | 95 | func (grc *GRCapability) GetTime() uint16 { 96 | return grc.FlagsAndTime & ((1 << GR_TIME_FIELD_SIZE) - 1) 97 | } 98 | 99 | func (grc *GRCapability) SetTime(time uint16) { 100 | flags := grc.GetFlags() 101 | grc.FlagsAndTime = (time & ((1 << GR_TIME_FIELD_SIZE) - 1)) 102 | grc.FlagsAndTime |= (uint16(flags) << GR_TIME_FIELD_SIZE) 103 | } 104 | 105 | func isMPCapabilityEqual(cap1, cap2 MPCapability) bool { 106 | return (cap1.AFI == cap2.AFI) && (cap1.SAFI == cap2.SAFI) 107 | } 108 | 109 | func capInList(mpCap MPCapability, capList []MPCapability) bool { 110 | for _, val := range capList { 111 | if isMPCapabilityEqual(mpCap, val) { 112 | return true 113 | } 114 | } 115 | return false 116 | } 117 | 118 | func DecodeCapability(msg []byte) (Capability, []byte, error) { 119 | capability := Capability{} 120 | if len(msg) < TWO_OCTETS { 121 | return capability, nil, fmt.Errorf("error in capability length\n") 122 | } 123 | err := binary.Read(bytes.NewReader(msg), binary.BigEndian, &capability) 124 | if err != nil { 125 | return capability, nil, fmt.Errorf("error in capability decoding: %v\n", err) 126 | } 127 | if len(msg) < (TWO_OCTETS + int(capability.Length)) { 128 | return capability, nil, fmt.Errorf("error in capability decoding: capability len\n") 129 | } 130 | return capability, msg[TWO_OCTETS : TWO_OCTETS+capability.Length], nil 131 | } 132 | 133 | func EncodeCapability(capability Capability, data []byte) ([]byte, error) { 134 | if len(data) > MAX_UINT8 { 135 | return nil, fmt.Errorf("encoded capability is to big\n") 136 | } 137 | capability.Length = uint8(len(data)) 138 | buf := new(bytes.Buffer) 139 | err := binary.Write(buf, binary.BigEndian, &capability) 140 | if err != nil { 141 | return nil, fmt.Errorf("error during capability encoding: %v\n") 142 | } 143 | encodedCap := append(buf.Bytes(), data...) 144 | return encodedCap, nil 145 | } 146 | 147 | func DecodeMPCapability(msg []byte) (MPCapability, error) { 148 | mpCapabiltiy := MPCapability{} 149 | if len(msg) != FOUR_OCTETS { 150 | return mpCapabiltiy, fmt.Errorf("wrong len of mp capability") 151 | } 152 | err := binary.Read(bytes.NewReader(msg), binary.BigEndian, &mpCapabiltiy) 153 | if err != nil { 154 | return mpCapabiltiy, fmt.Errorf("error during mp capability decoding: %v\n", err) 155 | } 156 | return mpCapabiltiy, nil 157 | } 158 | 159 | func EncodeMPCapability(mpCap MPCapability) ([]byte, error) { 160 | buf := new(bytes.Buffer) 161 | err := binary.Write(buf, binary.BigEndian, &mpCap) 162 | if err != nil { 163 | return nil, fmt.Errorf("error during mp capability encoding: %v\n", err) 164 | } 165 | return buf.Bytes(), nil 166 | } 167 | 168 | func EncodeASN4Capability(asn4 uint32) ([]byte, error) { 169 | buf := new(bytes.Buffer) 170 | err := binary.Write(buf, binary.BigEndian, &asn4) 171 | if err != nil { 172 | return nil, fmt.Errorf("cant encode asn4: %v\n", err) 173 | } 174 | capability, err := EncodeCapability(Capability{Code: CAPABILITY_AS4_NUMBER}, 175 | buf.Bytes()) 176 | if err != nil { 177 | return nil, fmt.Errorf("cant encode asn4 capabiltiy: %v\n", err) 178 | } 179 | return capability, nil 180 | } 181 | 182 | func DecodeASN4Capabiltiy(encAsn4 []byte) (uint32, error) { 183 | var asn4 uint32 184 | err := binary.Read(bytes.NewReader(encAsn4), binary.BigEndian, &asn4) 185 | if err != nil { 186 | return asn4, fmt.Errorf("cant decode asn4: %v\n", err) 187 | } 188 | return asn4, nil 189 | } 190 | 191 | /* 192 | TODO: right now i've implemented only capability anounce; 193 | no actual encoding for nlri w/ add path has been implemented yet 194 | */ 195 | func EncodeAddPathCapability(addPaths []AddPathCapability) ([]byte, error) { 196 | buf := new(bytes.Buffer) 197 | encodedAddPaths := make([]byte, 0) 198 | for _, addPath := range addPaths { 199 | err := binary.Write(buf, binary.BigEndian, &addPath) 200 | if err != nil { 201 | return nil, fmt.Errorf("cant encode AddPath: %v\n", err) 202 | } 203 | encodedAddPaths = append(encodedAddPaths, buf.Bytes()...) 204 | } 205 | //TODO: check that len of encodedAddPaths is less than 255 206 | capability, err := EncodeCapability(Capability{Code: CAPABILITY_ADD_PATH}, 207 | encodedAddPaths) 208 | if err != nil { 209 | return nil, fmt.Errorf("cant encode AddPath capabiltiy: %v\n", err) 210 | } 211 | return capability, nil 212 | 213 | } 214 | 215 | func DecodeAddPathCapability(capability []byte) ([]AddPathCapability, error) { 216 | addPathList := make([]AddPathCapability, 0) 217 | addPath := AddPathCapability{} 218 | if len(capability) < FIVE_OCTETS { 219 | return nil, fmt.Errorf("incorrect add path capability lenght (<5)\n") 220 | } 221 | for len(capability) > 0 { 222 | err := binary.Read(bytes.NewReader(capability), binary.BigEndian, &addPath) 223 | if err != nil { 224 | return nil, fmt.Errorf("cant decode add path capability: %v\n", err) 225 | } 226 | addPathList = append(addPathList, addPath) 227 | capability = capability[FIVE_OCTETS:] 228 | } 229 | 230 | return addPathList, nil 231 | } 232 | 233 | /* Error to handle EOR Marker */ 234 | type EndOfRib struct { 235 | eor bool 236 | } 237 | 238 | func (eor EndOfRib) Error() string { 239 | return "EOR" 240 | } 241 | 242 | /* Graceful Restart Capability rfc 4274 */ 243 | func DecodeGRCapability(data []byte) (GRCapability, error) { 244 | var grCap GRCapability 245 | /* right now we only care about flags and time for GR */ 246 | err := binary.Read(bytes.NewReader(data[:TWO_OCTETS]), 247 | binary.BigEndian, &grCap) 248 | if err != nil { 249 | return grCap, fmt.Errorf("cant decode gr capability: %v\n", err) 250 | } 251 | return grCap, nil 252 | } 253 | 254 | func EncodeGRCapability(cap GRCapability) ([]byte, error) { 255 | buf := new(bytes.Buffer) 256 | err := binary.Write(buf, binary.BigEndian, &cap) 257 | if err != nil { 258 | return nil, fmt.Errorf("cant encode gr capability: %v\n", err) 259 | } 260 | /* we dont support per afi/safi gr; hence gr contains only flags and 261 | len is 2 octest 262 | */ 263 | capability, err := EncodeCapability(Capability{ 264 | Code: CAPABILITY_GRACEFUL_RESTART}, 265 | buf.Bytes()) 266 | if err != nil { 267 | return nil, fmt.Errorf("cant encode asn4 capabiltiy: %v\n", err) 268 | } 269 | return capability, nil 270 | } 271 | -------------------------------------------------------------------------------- /bgp_path_attrs.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | ) 9 | 10 | const ( 11 | /* Attributes */ 12 | 13 | BAF_OPTIONAL = 0x80 14 | BAF_TRANSITIVE = 0x40 15 | BAF_PARTIAL = 0x20 16 | BAF_EXT_LEN = 0x10 17 | 18 | BA_ORIGIN = 0x01 19 | BA_AS_PATH = 0x02 20 | BA_NEXT_HOP = 0x03 21 | BA_MULTI_EXIT_DISC = 0x04 22 | BA_LOCAL_PREF = 0x05 23 | BA_ATOMIC_AGGR = 0x06 24 | BA_AGGREGATOR = 0x07 25 | BA_COMMUNITY = 0x08 26 | BA_ORIGINATOR_ID = 0x09 27 | BA_CLUSTER_LIST = 0x0a 28 | 29 | BA_DPA = 0x0b 30 | BA_ADVERTISER = 0x0c 31 | BA_RCID_PATH = 0x0d 32 | BA_MP_REACH_NLRI = 0x0e 33 | BA_MP_UNREACH_NLRI = 0x0f 34 | BA_EXT_COMMUNITY = 0x10 35 | BA_AS4_PATH = 0x11 36 | BA_AS4_AGGREGATOR = 0x12 37 | 38 | ORIGIN_IGP = 0 39 | ORIGIN_EGP = 1 40 | ORIGIN_INCOMPLETE = 2 41 | 42 | /* Well-known communities */ 43 | 44 | BGP_COMM_NO_EXPORT = 0xffffff01 /* Don't export outside local AS / confed. */ 45 | BGP_COMM_NO_ADVERTISE = 0xffffff02 /* Don't export at all */ 46 | BGP_COMM_NO_EXPORT_SUBCONFED = 0xffffff03 /* NO_EXPORT even in local confederation */ 47 | 48 | AS_SET = 1 49 | AS_SEQ = 2 50 | ) 51 | 52 | type PathAttr struct { 53 | AttrFlags uint8 54 | AttrTypeCode uint8 55 | AttrLength uint16 56 | ExtendedLength bool 57 | Data []byte 58 | } 59 | 60 | func EncodePathAttr(pathAttr *PathAttr, data []byte) ([]byte, error) { 61 | 62 | buf := new(bytes.Buffer) 63 | 64 | err := binary.Write(buf, binary.BigEndian, &pathAttr.AttrFlags) 65 | if err != nil { 66 | return nil, fmt.Errorf("cant encode path attr flags: %v\n", err) 67 | } 68 | 69 | err = binary.Write(buf, binary.BigEndian, &pathAttr.AttrTypeCode) 70 | if err != nil { 71 | return nil, fmt.Errorf("cant encode path attr type code: %v\n", err) 72 | } 73 | 74 | if pathAttr.ExtendedLength { 75 | attrLen := uint16(len(data)) 76 | err = binary.Write(buf, binary.BigEndian, &attrLen) 77 | if err != nil { 78 | return nil, fmt.Errorf("cant encode path attr ext length: %v\n", err) 79 | } 80 | } else { 81 | attrLen := uint8(len(data)) 82 | err = binary.Write(buf, binary.BigEndian, &attrLen) 83 | if err != nil { 84 | return nil, fmt.Errorf("cant encode path attr ext length: %v\n", err) 85 | } 86 | 87 | } 88 | data = append(buf.Bytes(), data...) 89 | return data, nil 90 | } 91 | 92 | func EncodeBGPRouteAttrs(bgpRoute *BGPRoute) ([]byte, error) { 93 | encodedAttrs := make([]byte, 0) 94 | pathAttr := PathAttr{} 95 | data, err := EncodeOriginAttr(&bgpRoute.ORIGIN, &pathAttr) 96 | if err != nil { 97 | return nil, err 98 | } 99 | encodedAttrs = append(encodedAttrs, data...) 100 | 101 | //For MP-BGP next_hop is not a mandatory attribute; coz we have another one in mp-nlri 102 | if bgpRoute.NEXT_HOP != nil { 103 | data, err = EncodeNextHopAttr(bgpRoute.NEXT_HOP, &pathAttr) 104 | if err != nil { 105 | return nil, err 106 | } 107 | 108 | encodedAttrs = append(encodedAttrs, data...) 109 | } 110 | //TODO: implement "withdraw" flag; so we wont check this len for each of supported mp-afi 111 | if len(bgpRoute.WithdrawRoutesV6) == 0 { 112 | data, err = EncodeASPathAttr(bgpRoute.AS_PATH, &pathAttr, bgpRoute.ASN4) 113 | if err != nil { 114 | return nil, err 115 | } 116 | encodedAttrs = append(encodedAttrs, data...) 117 | } 118 | 119 | if len(bgpRoute.WithdrawRoutesV6) == 0 { 120 | if bgpRoute.MULTI_EXIT_DISC != 0 { 121 | data, err = EncodeMEDAttr(&bgpRoute.MULTI_EXIT_DISC, &pathAttr) 122 | if err != nil { 123 | return nil, err 124 | } 125 | encodedAttrs = append(encodedAttrs, data...) 126 | } 127 | } 128 | 129 | if bgpRoute.LOCAL_PREF != 0 { 130 | data, err = EncodeLPAttr(&bgpRoute.LOCAL_PREF, &pathAttr) 131 | if err != nil { 132 | return nil, err 133 | } 134 | encodedAttrs = append(encodedAttrs, data...) 135 | } 136 | if bgpRoute.ATOMIC_AGGR { 137 | data, err = EncodeAAGRAttr(&pathAttr) 138 | if err != nil { 139 | return nil, err 140 | } 141 | encodedAttrs = append(encodedAttrs, data...) 142 | 143 | } 144 | if len(bgpRoute.RoutesV6) != 0 { 145 | data, err = EncodeV6MPRNLRI(bgpRoute.NEXT_HOPv6, 146 | bgpRoute.RoutesV6, &pathAttr) 147 | if err != nil { 148 | return nil, err 149 | } 150 | encodedAttrs = append(encodedAttrs, data...) 151 | } 152 | if len(bgpRoute.WithdrawRoutesV6) != 0 { 153 | data, err = EncodeV6MPUNRNLRI(bgpRoute.WithdrawRoutesV6, 154 | &pathAttr) 155 | if err != nil { 156 | return nil, err 157 | } 158 | encodedAttrs = append(encodedAttrs, data...) 159 | } 160 | if bgpRoute.MPINET { 161 | if len(bgpRoute.Routes) != 0 { 162 | data, err = EncodeV4MPRNLRI(bgpRoute.NEXT_HOPv4, 163 | bgpRoute.Flags, bgpRoute.Routes, &pathAttr) 164 | if err != nil { 165 | return nil, err 166 | } 167 | encodedAttrs = append(encodedAttrs, data...) 168 | } 169 | if len(bgpRoute.WithdrawRoutes) != 0 { 170 | data, err = EncodeV4MPUNRNLRI(bgpRoute.Flags, 171 | bgpRoute.WithdrawRoutes, &pathAttr) 172 | if err != nil { 173 | return nil, err 174 | } 175 | encodedAttrs = append(encodedAttrs, data...) 176 | } 177 | } 178 | 179 | if len(bgpRoute.Community) != 0 { 180 | for _, community := range bgpRoute.Community { 181 | data, err := EncodeBGPCommunity(community, &pathAttr) 182 | if err != nil { 183 | return nil, err 184 | } 185 | encodedAttrs = append(encodedAttrs, data...) 186 | } 187 | } 188 | 189 | return encodedAttrs, nil 190 | } 191 | 192 | func EncodeMEDAttr(med *uint32, pathAttr *PathAttr) ([]byte, error) { 193 | buf := new(bytes.Buffer) 194 | err := binary.Write(buf, binary.BigEndian, med) 195 | if err != nil { 196 | return nil, fmt.Errorf("error during MULTI_EXIT_DISC encoding: %v\n", err) 197 | } 198 | pathAttr.AttrFlags = BAF_OPTIONAL 199 | pathAttr.AttrTypeCode = BA_MULTI_EXIT_DISC 200 | /* 201 | this is generic copy-paste code; uint32 would never exceed 255bytes in len. 202 | mb will remove it later 203 | */ 204 | encData := buf.Bytes() 205 | if len(encData) > 255 { 206 | pathAttr.ExtendedLength = true 207 | pathAttr.AttrFlags |= BAF_EXT_LEN 208 | } else { 209 | pathAttr.ExtendedLength = false 210 | } 211 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 212 | if err != nil { 213 | return nil, fmt.Errorf("error during ORIGIN attr encoding: %v\n", err) 214 | } 215 | return encodedAttr, nil 216 | } 217 | 218 | func EncodeLPAttr(lp *uint32, pathAttr *PathAttr) ([]byte, error) { 219 | buf := new(bytes.Buffer) 220 | err := binary.Write(buf, binary.BigEndian, lp) 221 | if err != nil { 222 | return nil, fmt.Errorf("error during MULTI_EXIT_DISC encoding: %v\n", err) 223 | } 224 | pathAttr.AttrFlags = BAF_TRANSITIVE 225 | pathAttr.AttrTypeCode = BA_LOCAL_PREF 226 | encData := buf.Bytes() 227 | if len(encData) > 255 { 228 | pathAttr.ExtendedLength = true 229 | pathAttr.AttrFlags |= BAF_EXT_LEN 230 | } else { 231 | pathAttr.ExtendedLength = false 232 | } 233 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 234 | if err != nil { 235 | return nil, fmt.Errorf("error during LOCAL_PREF attr encoding: %v\n", err) 236 | } 237 | return encodedAttr, nil 238 | } 239 | 240 | func EncodeAAGRAttr(pathAttr *PathAttr) ([]byte, error) { 241 | pathAttr.AttrFlags = BAF_TRANSITIVE 242 | pathAttr.AttrTypeCode = BA_ATOMIC_AGGR 243 | pathAttr.ExtendedLength = false 244 | zeroLen := make([]byte, 0) 245 | encodedAttr, err := EncodePathAttr(pathAttr, zeroLen) 246 | if err != nil { 247 | return nil, fmt.Errorf("error during ATOMIC_AGGR attr encoding: %v\n", err) 248 | } 249 | return encodedAttr, nil 250 | } 251 | 252 | func EncodeOriginAttr(origin *uint8, pathAttr *PathAttr) ([]byte, error) { 253 | buf := new(bytes.Buffer) 254 | err := binary.Write(buf, binary.BigEndian, origin) 255 | if err != nil { 256 | return nil, fmt.Errorf("error during ORIGIN encoding: %v\n", err) 257 | } 258 | pathAttr.AttrFlags = BAF_TRANSITIVE 259 | pathAttr.AttrTypeCode = BA_ORIGIN 260 | encData := buf.Bytes() 261 | if len(encData) > 255 { 262 | pathAttr.ExtendedLength = true 263 | pathAttr.AttrFlags |= BAF_EXT_LEN 264 | } else { 265 | pathAttr.ExtendedLength = false 266 | } 267 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 268 | if err != nil { 269 | return nil, fmt.Errorf("error during ORIGIN attr encoding: %v\n", err) 270 | } 271 | return encodedAttr, nil 272 | } 273 | 274 | func EncodeNextHopAttr(nh []byte, pathAttr *PathAttr) ([]byte, error) { 275 | pathAttr.AttrFlags = BAF_TRANSITIVE 276 | pathAttr.AttrTypeCode = BA_NEXT_HOP 277 | encData := nh 278 | if len(encData) > 255 { 279 | pathAttr.ExtendedLength = true 280 | pathAttr.AttrFlags |= BAF_EXT_LEN 281 | } else { 282 | pathAttr.ExtendedLength = false 283 | } 284 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 285 | if err != nil { 286 | return nil, fmt.Errorf("error during ORIGIN attr encoding: %v\n", err) 287 | } 288 | return encodedAttr, nil 289 | } 290 | 291 | func EncodeV6MPRNLRI(nh IPv6Addr, nlris []IPV6_NLRI, pathAttr *PathAttr) ([]byte, error) { 292 | pathAttr.AttrFlags = BAF_OPTIONAL 293 | pathAttr.AttrTypeCode = BA_MP_REACH_NLRI 294 | encData, err := EncodeIPV6_MP_REACH_NLRI(nh, nlris) 295 | if err != nil { 296 | return nil, fmt.Errorf("cant encode ipv6 mp reach nlri: %v\n", err) 297 | } 298 | pathAttr.ExtendedLength = true 299 | pathAttr.AttrFlags |= BAF_EXT_LEN 300 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 301 | if err != nil { 302 | return nil, fmt.Errorf("error during MP_REACH_NLRI attr encoding: %v\n", err) 303 | } 304 | return encodedAttr, nil 305 | } 306 | 307 | func EncodeV4MPRNLRI(nh uint32, flags RouteFlags, nlris []IPV4_NLRI, 308 | pathAttr *PathAttr) ([]byte, error) { 309 | pathAttr.AttrFlags = BAF_OPTIONAL 310 | pathAttr.AttrTypeCode = BA_MP_REACH_NLRI 311 | encData, err := EncodeIPV4_MP_REACH_NLRI(nh, flags, nlris) 312 | if err != nil { 313 | return nil, fmt.Errorf("cant encode ipv4 mp reach nlri: %v\n", err) 314 | } 315 | pathAttr.ExtendedLength = true 316 | pathAttr.AttrFlags |= BAF_EXT_LEN 317 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 318 | if err != nil { 319 | return nil, fmt.Errorf("error during MP_REACH_NLRI attr encoding: %v\n", err) 320 | } 321 | return encodedAttr, nil 322 | } 323 | 324 | func EncodeV6MPUNRNLRI(nlris []IPV6_NLRI, pathAttr *PathAttr) ([]byte, error) { 325 | pathAttr.AttrFlags = BAF_OPTIONAL 326 | pathAttr.AttrTypeCode = BA_MP_UNREACH_NLRI 327 | encData, err := EncodeIPV6_MP_UNREACH_NLRI(nlris) 328 | if err != nil { 329 | return nil, fmt.Errorf("cant encode ipv6 mp unreach nlri: %v\n", err) 330 | } 331 | pathAttr.ExtendedLength = true 332 | pathAttr.AttrFlags |= BAF_EXT_LEN 333 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 334 | if err != nil { 335 | return nil, fmt.Errorf("error during MP_UNREACH_NLRI attr encoding: %v\n", err) 336 | } 337 | return encodedAttr, nil 338 | } 339 | 340 | func EncodeV4MPUNRNLRI(flags RouteFlags, nlris []IPV4_NLRI, 341 | pathAttr *PathAttr) ([]byte, error) { 342 | pathAttr.AttrFlags = BAF_OPTIONAL 343 | pathAttr.AttrTypeCode = BA_MP_UNREACH_NLRI 344 | encData, err := EncodeIPV4_MP_UNREACH_NLRI(flags, nlris) 345 | if err != nil { 346 | return nil, fmt.Errorf("cant encode ipv4 mp unreach nlri: %v\n", err) 347 | } 348 | pathAttr.ExtendedLength = true 349 | pathAttr.AttrFlags |= BAF_EXT_LEN 350 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 351 | if err != nil { 352 | return nil, fmt.Errorf("error during MP_UNREACH_NLRI attr encoding: %v\n", err) 353 | } 354 | return encodedAttr, nil 355 | } 356 | 357 | func EncodeBGPCommunity(community uint32, pathAttr *PathAttr) ([]byte, error) { 358 | pathAttr.AttrFlags = BAF_TRANSITIVE | BAF_OPTIONAL 359 | pathAttr.AttrTypeCode = BA_COMMUNITY 360 | buf := new(bytes.Buffer) 361 | err := binary.Write(buf, binary.BigEndian, &community) 362 | if err != nil { 363 | return nil, fmt.Errorf("error during community encoding: %v\n", err) 364 | } 365 | pathAttr.ExtendedLength = false 366 | encodedAttr, err := EncodePathAttr(pathAttr, buf.Bytes()) 367 | if err != nil { 368 | return nil, fmt.Errorf("error during AS_PATH attr encoding: %v\n", err) 369 | } 370 | return encodedAttr, nil 371 | } 372 | 373 | /* 374 | TODO: lots of things must be implemented.(for example as_path can has more than one 375 | path_segment. also not sure will it work with non zero as_path (gonna test/fix it later, 376 | right now i need only update msg with empty as_path) 377 | */ 378 | func EncodeASPathAttr(pathSegment []PathSegment, pathAttr *PathAttr, asn4 bool) ([]byte, error) { 379 | pathAttr.AttrFlags = BAF_TRANSITIVE 380 | pathAttr.AttrTypeCode = BA_AS_PATH 381 | var as2 uint16 382 | encData := make([]byte, 0) 383 | for _, segment := range pathSegment { 384 | buf := new(bytes.Buffer) 385 | err := binary.Write(buf, binary.BigEndian, &segment.PSType) 386 | if err != nil { 387 | return nil, fmt.Errorf("error during AS_PATH ps_type attr encoding: %v\n", err) 388 | } 389 | err = binary.Write(buf, binary.BigEndian, &segment.PSLength) 390 | if err != nil { 391 | return nil, fmt.Errorf("error during AS_PATH ps_length attr encoding: %v\n", err) 392 | } 393 | for _, asn := range segment.PSValue { 394 | if !asn4 { 395 | as2 = uint16(asn) 396 | err = binary.Write(buf, binary.BigEndian, &as2) 397 | if err != nil { 398 | return nil, fmt.Errorf("error during AS_PATH asn attr encoding: %v\n", err) 399 | } 400 | } else { 401 | err = binary.Write(buf, binary.BigEndian, &asn) 402 | if err != nil { 403 | return nil, fmt.Errorf("error during AS_PATH asn attr encoding: %v\n", err) 404 | } 405 | } 406 | } 407 | encData = append(encData, buf.Bytes()...) 408 | } 409 | if len(encData) > 255 { 410 | pathAttr.ExtendedLength = true 411 | } else { 412 | pathAttr.ExtendedLength = false 413 | } 414 | encodedAttr, err := EncodePathAttr(pathAttr, encData) 415 | if err != nil { 416 | return nil, fmt.Errorf("error during AS_PATH attr encoding: %v\n", err) 417 | } 418 | return encodedAttr, nil 419 | } 420 | 421 | func DecodePathAttr(msg []byte, pathAttr *PathAttr) error { 422 | reader := bytes.NewReader(msg) 423 | pathAttr.ExtendedLength = false 424 | err := binary.Read(reader, binary.BigEndian, &(pathAttr.AttrFlags)) 425 | if err != nil { 426 | return errors.New("cant decode update msg") 427 | } 428 | err = binary.Read(reader, binary.BigEndian, &(pathAttr.AttrTypeCode)) 429 | if err != nil { 430 | return errors.New("cant decode update msg") 431 | } 432 | if pathAttr.AttrFlags&BAF_EXT_LEN != 0 { 433 | err = binary.Read(reader, binary.BigEndian, &(pathAttr.AttrLength)) 434 | if err != nil { 435 | return errors.New("cant decode update msg") 436 | } 437 | pathAttr.ExtendedLength = true 438 | pathAttr.Data = msg[FOUR_OCTET_SHIFT : FOUR_OCTET_SHIFT+int(pathAttr.AttrLength)] 439 | } else { 440 | tmpLength := uint8(0) 441 | err = binary.Read(reader, binary.BigEndian, &(tmpLength)) 442 | if err != nil { 443 | return errors.New("cant decode update msg") 444 | } 445 | pathAttr.AttrLength = uint16(tmpLength) 446 | pathAttr.Data = msg[THREE_OCTET_SHIFT : THREE_OCTET_SHIFT+int(pathAttr.AttrLength)] 447 | } 448 | return nil 449 | } 450 | -------------------------------------------------------------------------------- /bgp_msgs.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | ) 9 | 10 | const ( 11 | 12 | //Misc const 13 | MAX_MSG_SIZE = 4096 14 | MSG_HDR_SIZE = 19 15 | MIN_OPEN_MSG_SIZE = 29 16 | OPEN_MSG_HDR_SIZE = 10 17 | ONE_OCTET_SHIFT = 1 18 | TWO_OCTET_SHIFT = 2 19 | THREE_OCTET_SHIFT = 3 20 | FOUR_OCTET_SHIFT = 4 21 | ONE_OCTET = 1 22 | TWO_OCTETS = 2 23 | THREE_OCTETS = 3 24 | FOUR_OCTETS = 4 25 | FIVE_OCTETS = 5 26 | 27 | // BGP's msg's types 28 | BGP_OPEN_MSG = 1 29 | BGP_UPDATE_MSG = 2 30 | BGP_NOTIFICATION_MSG = 3 31 | BGP_KEEPALIVE_MSG = 4 32 | BGP_ROUTEREFRESH_MSG = 5 33 | 34 | /* BGP Error codes and subcodes */ 35 | BGP_MSG_HEADER_ERROR = 1 36 | BGP_OPEN_MSG_ERROR = 2 37 | BGP_UPDATE_MSG_ERROR = 3 38 | BGP_HOLD_TIMER_EXPIRED = 4 39 | BGP_FSM_ERROR = 5 40 | BGP_CASE_ERROR = 6 41 | 42 | /*MSG Header subcodes */ 43 | BGP_MH_ERROR_NOTSYNC = 1 44 | BGP_MH_ERROR_BADLENGTH = 2 45 | BGP_MH_ERROR_BADTYPE = 3 46 | 47 | /*Open msg subcodes */ 48 | BGP_OM_ERROR_USUP_VER = 1 49 | BGP_OM_ERROR_BAD_PEER_AS = 2 50 | BGP_OM_ERROR_BGP_ID = 3 51 | BGP_OM_ERROR_USUP_OPT = 4 52 | BGP_OM_ERROR_DEPRICATED = 5 53 | BGP_OM_ERROR_UACCEPT_HOLD = 6 54 | 55 | /* Update msg subcodes */ 56 | BGP_UPD_ERROR_MAILFORMED_ATTR = 1 57 | BGP_UPD_ERROR_UNREC_WELL_KNOWN = 2 58 | BGP_UPD_ERROR_MISSING_WELL_KNOWN = 3 59 | BGP_UPD_ERROR_ATTR_FLAG = 4 60 | BGP_UPD_ERROR_ATTR_LENGTH = 5 61 | BGP_UPD_ERROR_INVALID_ORIGIN = 6 62 | BGP_UPD_ERROR_DEPRICATED = 7 63 | BGP_UPD_ERROR_INVALID_NH = 8 64 | BGP_UPD_ERROR_OPT_ATTR = 9 65 | BGP_UPD_ERROR_INVALID_NETWORK = 10 66 | BGP_UPD_ERROR_MAILFORMED_AS_PATH = 11 67 | 68 | /* Case errors subcodes */ 69 | BGP_CASE_ERROR_GENERIC = 0 70 | BGP_CASE_ERROR_COLLISION = 7 71 | 72 | /* BGP Generic Error */ 73 | BGP_GENERIC_ERROR = 0 74 | ) 75 | 76 | /* 77 | All details about headers format etc could be found in rfc 4271 78 | */ 79 | 80 | type MsgHeader struct { 81 | Marker [16]byte 82 | Length uint16 83 | Type uint8 84 | } 85 | 86 | type OpenMsg struct { 87 | Hdr OpenMsgHdr 88 | MPCaps []MPCapability 89 | Caps BGPCapabilities 90 | } 91 | 92 | type OpenMsgHdr struct { 93 | Version uint8 94 | MyASN uint16 95 | HoldTime uint16 96 | BGPID uint32 97 | OptParamLength uint8 98 | //OptParamWill be in separate struct 99 | } 100 | 101 | type OptionalParamHeader struct { 102 | ParamType uint8 103 | ParamLength uint8 104 | } 105 | 106 | //TODO: add optional capabilities structs; such as 32bit asn; rr etc 107 | 108 | type UpdateMsgLengths struct { 109 | WithdrawRoutesLength uint16 110 | //WithdrawRoutes variable 111 | TotalPathAttrsLength uint16 112 | //Path attrs variable 113 | //NLRI variable 114 | } 115 | 116 | type NotificationMsg struct { 117 | ErrorCode uint8 118 | ErrorSubcode uint8 119 | /* 120 | according to 4271 there also could be data field of variable length, 121 | but so far havent seen that anyone actually uses it; 122 | removing it greatly simplifies notification encoding and shouldnt 123 | break anything, coz during notification rcving we must tear down the session anyway 124 | and for that purpose ErrorCode & Subcodes fields should be enought; 125 | data field could be added in future, if there are going to be any demands 126 | */ 127 | } 128 | 129 | type PathSegment struct { 130 | PSType uint8 131 | PSLength uint8 132 | PSValue []uint32 133 | } 134 | 135 | type Agregator struct { 136 | ASN uint16 137 | AgregatorID uint32 138 | } 139 | 140 | type IPV4_NLRI struct { 141 | Length uint8 142 | Prefix uint32 143 | PathID uint32 144 | Label uint32 145 | } 146 | 147 | type RouteFlags struct { 148 | Labeled bool 149 | WithPathId bool 150 | /* 151 | flag that this route would be sent to ebgp peer. 152 | we will remove local_pref and add ourself's asn according to this flag 153 | */ 154 | EBGP bool 155 | } 156 | 157 | type BGPRoute struct { 158 | ORIGIN uint8 159 | AS_PATH []PathSegment 160 | NEXT_HOP []byte 161 | //TODO: mb it's better to use generic nh([]byte; above) 162 | NEXT_HOPv6 IPv6Addr 163 | NEXT_HOPv4 uint32 164 | MULTI_EXIT_DISC uint32 165 | LOCAL_PREF uint32 166 | ATOMIC_AGGR bool 167 | //TODO(tehnerd): move ASN4 to RouteFlags 168 | ASN4 bool 169 | Flags RouteFlags 170 | MPINET bool 171 | AGGREGATOR Agregator 172 | Routes []IPV4_NLRI 173 | RoutesV6 []IPV6_NLRI 174 | WithdrawRoutes []IPV4_NLRI 175 | WithdrawRoutesV6 []IPV6_NLRI 176 | Community []uint32 177 | } 178 | 179 | func DecodeMsgHeader(msg []byte) (MsgHeader, error) { 180 | msgHdr := MsgHeader{} 181 | if len(msg) < MSG_HDR_SIZE { 182 | return msgHdr, errors.New("msg too short") 183 | } 184 | err := binary.Read(bytes.NewReader(msg), binary.BigEndian, &msgHdr) 185 | if err != nil { 186 | return msgHdr, errors.New("cant decode msg header") 187 | } 188 | if msgHdr.Length > MAX_MSG_SIZE { 189 | return msgHdr, errors.New("msg too long") 190 | } 191 | return msgHdr, nil 192 | } 193 | 194 | func EncodeMsgHeader(msgHeader *MsgHeader) ([]byte, error) { 195 | // 16 bytes all of 1s 196 | msgHeader.Marker = [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} 197 | buf := new(bytes.Buffer) 198 | err := binary.Write(buf, binary.BigEndian, msgHeader) 199 | if err != nil { 200 | return nil, errors.New("cant encode msg header") 201 | } 202 | return buf.Bytes(), nil 203 | } 204 | 205 | func DecodeOpenMsg(msg []byte) (OpenMsg, error) { 206 | openMsg := OpenMsg{} 207 | err := binary.Read(bytes.NewReader(msg), binary.BigEndian, &openMsg.Hdr) 208 | if err != nil { 209 | return openMsg, errors.New("cant decode open msg") 210 | } 211 | if openMsg.Hdr.OptParamLength > 0 { 212 | msg = msg[OPEN_MSG_HDR_SIZE:] 213 | for len(msg) > 0 { 214 | optParamHdr, optParam, err := DecodeOptionalParamHeader(msg) 215 | if err != nil { 216 | return openMsg, fmt.Errorf("cant decode opt param hdr: %v\n", err) 217 | } 218 | msg = msg[TWO_OCTETS+optParamHdr.ParamLength:] 219 | if optParamHdr.ParamType == CAPABILITIES_OPTIONAL_PARAM { 220 | for len(optParam) > 0 { 221 | capHdr, capability, err := DecodeCapability(optParam) 222 | optParam = optParam[TWO_OCTETS+capHdr.Length:] 223 | if err != nil { 224 | return openMsg, fmt.Errorf("cant decode capability hdr: %v\n", err) 225 | } 226 | switch capHdr.Code { 227 | case CAPABILITY_MP_EXTENSION: 228 | mpCap, err := DecodeMPCapability(capability) 229 | if err != nil { 230 | return openMsg, fmt.Errorf("cant decode mp capability: %v\n", err) 231 | } 232 | openMsg.MPCaps = append(openMsg.MPCaps, mpCap) 233 | case CAPABILITY_AS4_NUMBER: 234 | asn4, err := DecodeASN4Capabiltiy(capability) 235 | if err != nil { 236 | return openMsg, fmt.Errorf("cant decode 4byte asn capability: %v\n", err) 237 | } 238 | openMsg.Caps.SupportASN4 = true 239 | openMsg.Caps.ASN4 = asn4 240 | case CAPABILITY_GRACEFUL_RESTART: 241 | _, err := DecodeGRCapability(capability) 242 | if err != nil { 243 | return openMsg, fmt.Errorf("%v\n", err) 244 | } 245 | openMsg.Caps.SupportGR = true 246 | } 247 | } 248 | } 249 | } 250 | } 251 | return openMsg, nil 252 | } 253 | 254 | func EncodeOpenMsg(openMsg *OpenMsg) ([]byte, error) { 255 | buf := new(bytes.Buffer) 256 | encodedOptParams := make([]byte, 0) 257 | for _, mpCap := range openMsg.MPCaps { 258 | encMPCap, err := EncodeMPCapability(mpCap) 259 | if err != nil { 260 | return nil, fmt.Errorf("cant encode mp cap: %v\n", err) 261 | } 262 | encCap, err := EncodeCapability(Capability{Code: CAPABILITY_MP_EXTENSION}, 263 | encMPCap) 264 | if err != nil { 265 | return nil, fmt.Errorf("cant encode capability: %v\n", err) 266 | } 267 | encParamHdr, err := EncodeOptionalParamHeader(OptionalParamHeader{ 268 | ParamType: CAPABILITIES_OPTIONAL_PARAM, 269 | ParamLength: uint8(len(encCap)), 270 | }) 271 | encodedOptParams = append(encodedOptParams, encParamHdr...) 272 | encodedOptParams = append(encodedOptParams, encCap...) 273 | } 274 | if openMsg.Caps.SupportASN4 { 275 | encCap, err := EncodeASN4Capability(openMsg.Caps.ASN4) 276 | if err != nil { 277 | return nil, fmt.Errorf("cant encode asn4 cap: %v\n", err) 278 | } 279 | encParamHdr, err := EncodeOptionalParamHeader(OptionalParamHeader{ 280 | ParamType: CAPABILITIES_OPTIONAL_PARAM, 281 | ParamLength: uint8(len(encCap)), 282 | }) 283 | encodedOptParams = append(encodedOptParams, encParamHdr...) 284 | encodedOptParams = append(encodedOptParams, encCap...) 285 | } 286 | if openMsg.Caps.SupportGR { 287 | var cap GRCapability 288 | encCap, err := EncodeGRCapability(cap) 289 | if err != nil { 290 | return nil, fmt.Errorf("cant encode GR cap: %v\n", err) 291 | } 292 | encParamHdr, err := EncodeOptionalParamHeader(OptionalParamHeader{ 293 | ParamType: CAPABILITIES_OPTIONAL_PARAM, 294 | ParamLength: uint8(len(encCap)), 295 | }) 296 | encodedOptParams = append(encodedOptParams, encParamHdr...) 297 | encodedOptParams = append(encodedOptParams, encCap...) 298 | } 299 | 300 | openMsg.Hdr.OptParamLength = uint8(len(encodedOptParams)) 301 | err := binary.Write(buf, binary.BigEndian, openMsg.Hdr) 302 | if err != nil { 303 | return nil, errors.New("cant encode open msg") 304 | } 305 | encodedOpen := buf.Bytes() 306 | msgHdr := MsgHeader{Type: BGP_OPEN_MSG, Length: MIN_OPEN_MSG_SIZE + 307 | uint16(openMsg.Hdr.OptParamLength)} 308 | encodedHdr, err := EncodeMsgHeader(&msgHdr) 309 | if err != nil { 310 | return nil, fmt.Errorf("cant encode open msg: %v\n", err) 311 | } 312 | encodedOpen = append(encodedHdr, encodedOpen...) 313 | encodedOpen = append(encodedOpen, encodedOptParams...) 314 | return encodedOpen, nil 315 | } 316 | 317 | func DecodeOptionalParamHeader(msg []byte) (OptionalParamHeader, []byte, error) { 318 | optParamHdr := OptionalParamHeader{} 319 | if len(msg) < TWO_OCTETS { 320 | return optParamHdr, nil, fmt.Errorf("opt param len is not enough for decoding\n") 321 | } 322 | err := binary.Read(bytes.NewReader(msg), binary.BigEndian, &optParamHdr) 323 | if err != nil { 324 | return optParamHdr, nil, fmt.Errorf("cant decode optional param header: %v\n", err) 325 | } 326 | if len(msg) < (TWO_OCTETS + int(optParamHdr.ParamLength)) { 327 | return optParamHdr, nil, fmt.Errorf("opt param+msg len is not enough for decoding\n") 328 | } 329 | return optParamHdr, msg[TWO_OCTETS : TWO_OCTETS+optParamHdr.ParamLength], nil 330 | 331 | } 332 | 333 | func EncodeOptionalParamHeader(optParamHdr OptionalParamHeader) ([]byte, error) { 334 | buf := new(bytes.Buffer) 335 | err := binary.Write(buf, binary.BigEndian, optParamHdr) 336 | if err != nil { 337 | return nil, errors.New("cant encode optional param header") 338 | } 339 | return buf.Bytes(), nil 340 | } 341 | 342 | func AddAttrToRoute(bgpRoute *BGPRoute, pathAttr *PathAttr) error { 343 | reader := bytes.NewReader(pathAttr.Data) 344 | err := errors.New("placeholder") 345 | switch pathAttr.AttrTypeCode { 346 | case BA_ORIGIN: 347 | err = binary.Read(reader, binary.BigEndian, &(bgpRoute.ORIGIN)) 348 | if err != nil { 349 | return fmt.Errorf("cant decode ORIGIN Attr: %v\n", err) 350 | } 351 | case BA_MULTI_EXIT_DISC: 352 | err = binary.Read(reader, binary.BigEndian, &(bgpRoute.MULTI_EXIT_DISC)) 353 | if err != nil { 354 | return fmt.Errorf("cant decode MED Attr: %v\n", err) 355 | } 356 | 357 | case BA_LOCAL_PREF: 358 | err = binary.Read(reader, binary.BigEndian, &(bgpRoute.LOCAL_PREF)) 359 | if err != nil { 360 | return fmt.Errorf("cant decode LOCAL_PREF Attr: %v\n", err) 361 | } 362 | case BA_ATOMIC_AGGR: 363 | bgpRoute.ATOMIC_AGGR = true 364 | case BA_NEXT_HOP: 365 | bgpRoute.NEXT_HOP = append(bgpRoute.NEXT_HOP, pathAttr.Data...) 366 | case BA_COMMUNITY: 367 | var community uint32 368 | for reader.Len() >= 4 { 369 | err = binary.Read(reader, binary.BigEndian, &community) 370 | if err != nil { 371 | return fmt.Errorf("cant decode COMMUNITY Attr: %v\n", err) 372 | } 373 | bgpRoute.Community = append(bgpRoute.Community, community) 374 | } 375 | case BA_AS_PATH: 376 | //TODO: as_path can has more than one path segment 377 | if pathAttr.AttrLength != 0 { 378 | segmentOffset := 0 379 | for segmentOffset < int(pathAttr.AttrLength) { 380 | var segment PathSegment 381 | err = binary.Read(reader, binary.BigEndian, &(segment.PSType)) 382 | err = binary.Read(reader, binary.BigEndian, &(segment.PSLength)) 383 | if err != nil { 384 | return fmt.Errorf("cant decode ASPathLen & Type: %v\n", err) 385 | } 386 | var asn uint16 387 | var asn4 uint32 388 | for cntr := 0; cntr < int(segment.PSLength); cntr++ { 389 | if !bgpRoute.ASN4 { 390 | err = binary.Read(reader, binary.BigEndian, &asn) 391 | } else { 392 | err = binary.Read(reader, binary.BigEndian, &asn4) 393 | } 394 | if err != nil { 395 | return fmt.Errorf("cant decode ASPathLen ASNS: %v\n", err) 396 | } 397 | if !bgpRoute.ASN4 { 398 | segment.PSValue = append(segment.PSValue, uint32(asn)) 399 | } else { 400 | segment.PSValue = append(segment.PSValue, asn4) 401 | } 402 | } 403 | bgpRoute.AS_PATH = append(bgpRoute.AS_PATH, segment) 404 | //2 octes = len of pstype + pslength; 2 octest - size of asn2 and 4 octets size of asn4 405 | if !bgpRoute.ASN4 { 406 | segmentOffset += (TWO_OCTET_SHIFT + TWO_OCTETS*int(segment.PSLength)) 407 | } else { 408 | segmentOffset += (TWO_OCTET_SHIFT + FOUR_OCTETS*int(segment.PSLength)) 409 | } 410 | } 411 | } else { 412 | return nil 413 | } 414 | case BA_MP_REACH_NLRI: 415 | err := DecodeMP_REACH_NLRI(pathAttr.Data, bgpRoute) 416 | if err != nil { 417 | return err 418 | } 419 | case BA_MP_UNREACH_NLRI: 420 | err := DecodeMP_UNREACH_NLRI(pathAttr.Data, bgpRoute) 421 | if err != nil { 422 | return err 423 | } 424 | } 425 | return nil 426 | } 427 | 428 | //will incremently add features; update msg, compare to other ones, has lots of variable length fields 429 | func DecodeUpdateMsg(msg []byte, caps *BGPCapabilities) (BGPRoute, error) { 430 | updMsgLen := UpdateMsgLengths{} 431 | bgpRoute := BGPRoute{} 432 | bgpRoute.ASN4 = caps.SupportASN4 433 | offset := MSG_HDR_SIZE 434 | err := binary.Read(bytes.NewReader(msg[offset:]), binary.BigEndian, &(updMsgLen.WithdrawRoutesLength)) 435 | if err != nil { 436 | return bgpRoute, fmt.Errorf("cant decode update msg withdraw length: %v\n", err) 437 | } 438 | offset = MSG_HDR_SIZE + TWO_OCTET_SHIFT 439 | withdrawRoutes, err := DecodeIPv4Route(offset, offset+int(updMsgLen.WithdrawRoutesLength), 440 | msg) 441 | if err != nil { 442 | return bgpRoute, err 443 | } 444 | bgpRoute.WithdrawRoutes = withdrawRoutes 445 | offset = MSG_HDR_SIZE + TWO_OCTET_SHIFT + int(updMsgLen.WithdrawRoutesLength) 446 | err = binary.Read(bytes.NewReader(msg[offset:]), binary.BigEndian, &(updMsgLen.TotalPathAttrsLength)) 447 | if err != nil { 448 | return bgpRoute, fmt.Errorf("cant decode update msg total path attr length: %v\n", err) 449 | } 450 | pathAttr := PathAttr{} 451 | offset = 2*TWO_OCTET_SHIFT + int(updMsgLen.WithdrawRoutesLength) + MSG_HDR_SIZE 452 | attrsEndOffset := offset + int(updMsgLen.TotalPathAttrsLength) 453 | for offset < attrsEndOffset { 454 | err = DecodePathAttr(msg[offset:], &pathAttr) 455 | if err != nil { 456 | return bgpRoute, fmt.Errorf("cant decode update msg attribute: %v\n", err) 457 | } 458 | err := AddAttrToRoute(&bgpRoute, &pathAttr) 459 | if err != nil { 460 | switch err.(type) { 461 | case EndOfRib: 462 | return bgpRoute, err 463 | default: 464 | return bgpRoute, 465 | fmt.Errorf("cant decode update msg attribute data: %v\n", err) 466 | } 467 | } 468 | //Size of path's attr heaer either 3 of 4 octets 469 | if pathAttr.ExtendedLength { 470 | offset = offset + FOUR_OCTET_SHIFT + int(pathAttr.AttrLength) 471 | } else { 472 | offset = offset + THREE_OCTET_SHIFT + int(pathAttr.AttrLength) 473 | } 474 | } 475 | offset = (2*TWO_OCTET_SHIFT + int(updMsgLen.WithdrawRoutesLength) + 476 | int(updMsgLen.TotalPathAttrsLength) + MSG_HDR_SIZE) 477 | //right now we are trying to implement minimal functionality. so that means ipv4 only 478 | //TODO: ipv6 must must (or even MP-BGP) 479 | routes, err := DecodeIPv4Route(offset, len(msg), msg) 480 | if err != nil { 481 | return bgpRoute, err 482 | } 483 | bgpRoute.Routes = append(bgpRoute.Routes, routes...) 484 | return bgpRoute, nil 485 | } 486 | 487 | func DecodeIPv4Route(offset, finalPosition int, msg []byte) ([]IPV4_NLRI, error) { 488 | prefix := IPV4_NLRI{} 489 | prefixList := make([]IPV4_NLRI, 0) 490 | for offset < finalPosition { 491 | err := binary.Read(bytes.NewReader(msg[offset:]), binary.BigEndian, &(prefix.Length)) 492 | if err != nil { 493 | return prefixList, fmt.Errorf("cant decode update msg prefix length: %v\n", err) 494 | } 495 | offset += ONE_OCTET_SHIFT 496 | //awsm trick from BIRD 497 | prefixBytes := int((prefix.Length + 7) / 8) 498 | prefixPart := make([]byte, 0) 499 | prefixPart = append(prefixPart, msg[offset:offset+prefixBytes]...) 500 | for cntr := prefixBytes; cntr < FOUR_OCTETS; cntr++ { 501 | prefixPart = append(prefixPart, byte(0)) 502 | } 503 | err = binary.Read(bytes.NewReader(prefixPart), binary.BigEndian, &(prefix.Prefix)) 504 | if err != nil { 505 | return prefixList, fmt.Errorf("cant decode update msg prefix: %v\n", err) 506 | } 507 | prefixList = append(prefixList, prefix) 508 | offset += prefixBytes 509 | } 510 | return prefixList, nil 511 | } 512 | 513 | func (bgpRoute *BGPRoute) AddV4NextHop(ipv4 string) error { 514 | v4addr, err := IPv4ToUint32(ipv4) 515 | if err != nil { 516 | return err 517 | } 518 | buf := new(bytes.Buffer) 519 | err = binary.Write(buf, binary.BigEndian, &v4addr) 520 | if err != nil { 521 | return err 522 | } 523 | bgpRoute.NEXT_HOP = buf.Bytes() 524 | return nil 525 | } 526 | 527 | func DecodeV4NextHop(bgpRoute *BGPRoute) (uint32, error) { 528 | reader := bytes.NewReader(bgpRoute.NEXT_HOP) 529 | ipv4 := uint32(0) 530 | err := binary.Read(reader, binary.BigEndian, &ipv4) 531 | if err != nil { 532 | return ipv4, fmt.Errorf("cant decove ipv4 next hop: %v\n", err) 533 | } 534 | return ipv4, nil 535 | } 536 | 537 | func EncodeUpdateMsg(bgpRoute *BGPRoute) ([]byte, error) { 538 | if len(bgpRoute.WithdrawRoutes) > 0 { 539 | return EncodeWithdrawUpdateMsg(bgpRoute) 540 | } 541 | encodedUpdate := make([]byte, 0) 542 | buf := new(bytes.Buffer) 543 | updMsgLen := UpdateMsgLengths{} 544 | encodedAttrs, err := EncodeBGPRouteAttrs(bgpRoute) 545 | if err != nil { 546 | return nil, fmt.Errorf("cant encode path attributes: %v\n", err) 547 | } 548 | encodedRoutes, err := EncodeIPv4Route(bgpRoute.Routes) 549 | if err != nil { 550 | return nil, fmt.Errorf("cant encoded bgp routes: %v\n", err) 551 | } 552 | updMsgLen.TotalPathAttrsLength = uint16(len(encodedAttrs)) 553 | err = binary.Write(buf, binary.BigEndian, &updMsgLen.WithdrawRoutesLength) 554 | if err != nil { 555 | return nil, fmt.Errorf("cant encode withdar routes length\n") 556 | } 557 | encodedUpdate = append(encodedUpdate, buf.Bytes()...) 558 | err = binary.Write(buf, binary.BigEndian, &updMsgLen.TotalPathAttrsLength) 559 | if err != nil { 560 | return nil, fmt.Errorf("cant encode total path attrs length\n") 561 | } 562 | encodedUpdate = append(encodedUpdate, buf.Bytes()[TWO_OCTET_SHIFT:]...) 563 | encodedUpdate = append(encodedUpdate, encodedAttrs...) 564 | if !bgpRoute.MPINET { 565 | encodedUpdate = append(encodedUpdate, encodedRoutes...) 566 | } 567 | msgHdr := MsgHeader{Type: BGP_UPDATE_MSG, Length: MSG_HDR_SIZE + uint16(len(encodedUpdate))} 568 | encMsgHdr, err := EncodeMsgHeader(&msgHdr) 569 | if err != nil { 570 | return nil, fmt.Errorf("cant encode update msg hdr: %v\n", err) 571 | } 572 | encodedUpdate = append(encMsgHdr, encodedUpdate...) 573 | return encodedUpdate, nil 574 | } 575 | 576 | //TODO: mp_unreach caries withdraw routes in path_attr 577 | func EncodeWithdrawUpdateMsg(bgpRoute *BGPRoute) ([]byte, error) { 578 | encodedUpdate := make([]byte, 0) 579 | buf := new(bytes.Buffer) 580 | encodedWithdrawRoutes, err := EncodeIPv4Route(bgpRoute.WithdrawRoutes) 581 | if err != nil { 582 | return nil, fmt.Errorf("cant encode withdraw routes") 583 | } 584 | updMsgLen := UpdateMsgLengths{WithdrawRoutesLength: uint16(len(encodedWithdrawRoutes))} 585 | err = binary.Write(buf, binary.BigEndian, &updMsgLen.WithdrawRoutesLength) 586 | if err != nil { 587 | return nil, fmt.Errorf("cant encode withdar routes length\n") 588 | } 589 | encodedUpdate = append(encodedUpdate, buf.Bytes()...) 590 | encodedUpdate = append(encodedUpdate, encodedWithdrawRoutes...) 591 | err = binary.Write(buf, binary.BigEndian, &updMsgLen.TotalPathAttrsLength) 592 | if err != nil { 593 | return nil, fmt.Errorf("cant encode total path attrs length\n") 594 | } 595 | encodedUpdate = append(encodedUpdate, buf.Bytes()[TWO_OCTET_SHIFT:]...) 596 | msgHdr := MsgHeader{Type: BGP_UPDATE_MSG, Length: MSG_HDR_SIZE + uint16(len(encodedUpdate))} 597 | encMsgHdr, err := EncodeMsgHeader(&msgHdr) 598 | if err != nil { 599 | return nil, fmt.Errorf("cant encode update msg hdr: %v\n", err) 600 | } 601 | encodedUpdate = append(encMsgHdr, encodedUpdate...) 602 | return encodedUpdate, nil 603 | } 604 | 605 | func EncodeIPv4Route(routesSlice []IPV4_NLRI) ([]byte, error) { 606 | buf := new(bytes.Buffer) 607 | routes := make([]byte, 0) 608 | prefixBits := 0 609 | notUsedBits := 0 610 | for _, route := range routesSlice { 611 | err := binary.Write(buf, binary.BigEndian, route.Length) 612 | if err != nil { 613 | return routes, fmt.Errorf("error during encoding routes: %v\n", err) 614 | } 615 | err = binary.Write(buf, binary.BigEndian, route.Prefix) 616 | if err != nil { 617 | return routes, fmt.Errorf("error during encoding routes: %v\n", err) 618 | } 619 | prefixBits = int((route.Length + 7) / 8) 620 | notUsedBits = FOUR_OCTET_SHIFT - prefixBits 621 | routes = append(routes, buf.Next(ONE_OCTET_SHIFT+prefixBits)...) 622 | buf.Next(notUsedBits) 623 | } 624 | return routes, nil 625 | } 626 | 627 | func DecodeNotificationMsg(msg []byte) (NotificationMsg, error) { 628 | offset := MSG_HDR_SIZE 629 | notification := NotificationMsg{} 630 | reader := bytes.NewReader(msg[offset:]) 631 | err := binary.Read(reader, binary.BigEndian, ¬ification) 632 | if err != nil { 633 | return notification, errors.New("cant decode notification") 634 | } 635 | return notification, nil 636 | } 637 | 638 | func EncodeNotificationMsg(notification *NotificationMsg) ([]byte, error) { 639 | encodedNotification := make([]byte, 0) 640 | buf := new(bytes.Buffer) 641 | err := binary.Write(buf, binary.BigEndian, notification) 642 | if err != nil { 643 | return nil, fmt.Errorf("can encode notification msg: %v\n", err) 644 | } 645 | encodedNotification = append(encodedNotification, buf.Bytes()...) 646 | msgHdr := MsgHeader{ 647 | Type: BGP_NOTIFICATION_MSG, 648 | Length: MSG_HDR_SIZE + uint16(len(encodedNotification))} 649 | encMsgHdr, err := EncodeMsgHeader(&msgHdr) 650 | if err != nil { 651 | return nil, fmt.Errorf("can encode notification msg hdr: %v\n", err) 652 | } 653 | encodedNotification = append(encMsgHdr, encodedNotification...) 654 | return encodedNotification, nil 655 | } 656 | 657 | func GenerateKeepalive() []byte { 658 | keepAlive := MsgHeader{} 659 | keepAlive.Length = MSG_HDR_SIZE 660 | keepAlive.Type = BGP_KEEPALIVE_MSG 661 | kaMsg, _ := EncodeMsgHeader(&keepAlive) 662 | return kaMsg 663 | } 664 | 665 | /* 666 | not sure if it's correct. prob should be inside mp_unreach_nlri. 667 | gona read rfc ... 668 | */ 669 | func GenerateEndOfRIB() []byte { 670 | encodedUpdate := make([]byte, 0) 671 | buf := new(bytes.Buffer) 672 | updMsgLen := UpdateMsgLengths{WithdrawRoutesLength: 0, TotalPathAttrsLength: 0} 673 | binary.Write(buf, binary.BigEndian, &updMsgLen) 674 | encodedUpdate = append(encodedUpdate, buf.Bytes()...) 675 | msgHdr := MsgHeader{Type: BGP_UPDATE_MSG, Length: MSG_HDR_SIZE + uint16(len(encodedUpdate))} 676 | encMsgHdr, _ := EncodeMsgHeader(&msgHdr) 677 | encodedUpdate = append(encMsgHdr, encodedUpdate...) 678 | return encodedUpdate 679 | } 680 | -------------------------------------------------------------------------------- /bgp_msgs_test.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | const ( 10 | hexOpenMsg = "ffffffffffffffffffffffffffffffff003b0104fde8005a0a0000021e02060104000100010202800002020200020440020078020641040000fde8" 11 | hexUpdate1 = "ffffffffffffffffffffffffffffffff00360200000015400101004002004003040a0000024005040000006420010101012001010102" 12 | hexUpdate2 = "ffffffffffffffffffffffffffffffff0038020000001c400101004002004003040a00000280040400000078400504000000642001010103" 13 | hexUpdate3 = "ffffffffffffffffffffffffffffffff00170200000000" 14 | hexUpdate4 = "ffffffffffffffffffffffffffffffff005102000000364001010240021a02060000000100000002000000030000000400000005000000064003040a00000240050400000064c00804ffff000118010b01" 15 | hexKA = "ffffffffffffffffffffffffffffffff001304" 16 | hexNotification = "ffffffffffffffffffffffffffffffff0015030607" 17 | hexIPv6NLRI = "302a00bdc0e003" 18 | hexIPv6_MP_REACH = "00020110200107f800200101000000000245018000302a00bdc0e003" 19 | hexIPv6_MP_REACH_NLRI_PA = "900e001c00020110200107f800200101000000000245018000302a00bdc0e003" 20 | hexLabeledIPv4_MP_REACH_NLRI = "ffffffffffffffffffffffffffffffff007702000000604001010040020602010000ff7880040400000001c0080cff780001ff780002ff780064900e0039000104040a004e070038494701c0a8010638494401c0a8010338494501c0a8010438494601c0a8010538494301c0a8010238494201c0a80101" 21 | hexJuniperOpen = "ffffffffffffffffffffffffffffffff003b0104ff79005ac0a801081e02060104000100040202800002020200020440020078020641040000ff79" 22 | hexEndOfRibv4 = "ffffffffffffffffffffffffffffffff001e0200000007900f0003000104" 23 | ) 24 | 25 | func TestDecodeMsgHeader(t *testing.T) { 26 | encodedOpen, _ := hex.DecodeString(hexOpenMsg) 27 | _, err := DecodeMsgHeader(encodedOpen) 28 | if err != nil { 29 | fmt.Println(err) 30 | t.Errorf("error during bgp msg header decoding") 31 | return 32 | } 33 | } 34 | 35 | func TestEncodeMsgHeader(t *testing.T) { 36 | encodedOpen, _ := hex.DecodeString(hexOpenMsg) 37 | msgHdr := MsgHeader{Length: 59, Type: 1} 38 | encMsgHdr, err := EncodeMsgHeader(&msgHdr) 39 | if err != nil { 40 | fmt.Println(err) 41 | t.Errorf("error during bgp msg header encoding") 42 | return 43 | } 44 | if len(encMsgHdr) != MSG_HDR_SIZE { 45 | fmt.Println(len(encMsgHdr)) 46 | fmt.Println(encMsgHdr) 47 | t.Errorf("error in len of encoded hdr") 48 | return 49 | } 50 | for cntr := 0; cntr < len(encMsgHdr); cntr++ { 51 | if encMsgHdr[cntr] != encodedOpen[cntr] { 52 | t.Errorf("byte of encoded msg is not equal to etalon's msg") 53 | return 54 | } 55 | } 56 | } 57 | 58 | func TestDecodeOpenMsg(t *testing.T) { 59 | encodedOpen, _ := hex.DecodeString(hexOpenMsg) 60 | openMsg, err := DecodeOpenMsg(encodedOpen[MSG_HDR_SIZE:]) 61 | if err != nil { 62 | fmt.Println(err) 63 | t.Errorf("error during open msg decoding: %v\n", err) 64 | return 65 | } 66 | fmt.Printf("%#v\n", openMsg) 67 | } 68 | 69 | func TestDecodeJuniperOpenMsg(t *testing.T) { 70 | encodedOpen, _ := hex.DecodeString(hexJuniperOpen) 71 | openMsg, err := DecodeOpenMsg(encodedOpen[MSG_HDR_SIZE:]) 72 | if err != nil { 73 | fmt.Println(err) 74 | t.Errorf("error during open msg decoding: %v\n", err) 75 | return 76 | } 77 | fmt.Printf("%#v\n", openMsg) 78 | } 79 | 80 | func TestEncodeMPcapability(t *testing.T) { 81 | mpCap := MPCapability{AFI: 1, SAFI: 1} 82 | encMpCap, err := EncodeMPCapability(mpCap) 83 | if err != nil { 84 | t.Errorf("cant encode mpCap") 85 | return 86 | } 87 | encCap, err := EncodeCapability(Capability{Code: CAPABILITY_MP_EXTENSION}, encMpCap) 88 | if err != nil { 89 | t.Errorf("cant encode capability") 90 | return 91 | } 92 | capability, data, err := DecodeCapability(encCap) 93 | if capability.Code != CAPABILITY_MP_EXTENSION { 94 | t.Errorf("error during capability decoding") 95 | return 96 | } 97 | if err != nil { 98 | t.Errorf("can decode encoded capability") 99 | return 100 | } 101 | decMpCap, err := DecodeMPCapability(data) 102 | if err != nil { 103 | t.Errorf("cant decode encoded mp capability") 104 | return 105 | } 106 | if decMpCap.AFI != mpCap.AFI || decMpCap.SAFI != mpCap.SAFI { 107 | t.Errorf("error during enc/dec of mp cap") 108 | return 109 | } 110 | } 111 | 112 | func TestEncodeOpenWithMPcapabilityAndASN4(t *testing.T) { 113 | capList := []MPCapability{ 114 | MPCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST}, 115 | MPCapability{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST}} 116 | openMsg := OpenMsg{Hdr: OpenMsgHdr{Version: 4, MyASN: 65000, HoldTime: 90, BGPID: 167772162}} 117 | openMsg.MPCaps = append(openMsg.MPCaps, capList...) 118 | openMsg.Caps.SupportASN4 = true 119 | openMsg.Caps.ASN4 = 65000 120 | data, err := EncodeOpenMsg(&openMsg) 121 | if err != nil { 122 | t.Errorf("cant encode open msg: %v\n", err) 123 | return 124 | } 125 | _, err = DecodeOpenMsg(data[MSG_HDR_SIZE:]) 126 | if err != nil { 127 | t.Errorf("cant decoded encoded msg: %v\n", err) 128 | return 129 | } 130 | } 131 | 132 | func TestEncodeOpenMsg(t *testing.T) { 133 | encodedOpen, _ := hex.DecodeString(hexOpenMsg) 134 | openMsg := OpenMsg{Hdr: OpenMsgHdr{Version: 4, MyASN: 65000, HoldTime: 90, BGPID: 167772162, OptParamLength: 30}} 135 | encOpenMsg, err := EncodeOpenMsg(&openMsg) 136 | if err != nil { 137 | fmt.Println(err) 138 | t.Errorf("error during open msg encoding") 139 | return 140 | } 141 | //HACKISH TEST; we dont know how to encode all of the opt params and caps in etalon msg 142 | //so here we only tests how we have encoded ans,holdtime etc 143 | for cntr := MSG_HDR_SIZE; cntr < MIN_OPEN_MSG_SIZE-2; cntr++ { 144 | if encOpenMsg[cntr] != encodedOpen[cntr] { 145 | t.Errorf("byte of encoded msg is not equal to etalon's msg") 146 | return 147 | } 148 | } 149 | } 150 | 151 | func TestDecodeEncodeGR(t *testing.T) { 152 | encodedOpen, _ := hex.DecodeString(hexOpenMsg) 153 | openMsg, err := DecodeOpenMsg(encodedOpen[MSG_HDR_SIZE:]) 154 | if err != nil { 155 | fmt.Println(err) 156 | t.Errorf("error during open msg decoding: %v\n", err) 157 | return 158 | } 159 | if openMsg.Caps.SupportGR != true { 160 | t.Errorf("this open msg suppose to have GR enabled\n") 161 | return 162 | } 163 | reEncodedOpen, err := EncodeOpenMsg(&openMsg) 164 | if err != nil { 165 | fmt.Println(err) 166 | t.Errorf("error during open msg w/GR encoding: %v\n", err) 167 | return 168 | } 169 | fmt.Println(reEncodedOpen) 170 | newOpenMsg, err := DecodeOpenMsg(reEncodedOpen[MSG_HDR_SIZE:]) 171 | if err != nil { 172 | t.Errorf("error during open msg w/GR decoding: %v\n", err) 173 | return 174 | } 175 | if newOpenMsg.Caps.SupportGR != true { 176 | t.Errorf("error durign GR cap encoding/decoding\n") 177 | return 178 | } 179 | } 180 | 181 | func TestDecodeUpdateMsg(t *testing.T) { 182 | encodedUpdate, _ := hex.DecodeString(hexUpdate1) 183 | _, err := DecodeUpdateMsg(encodedUpdate, &BGPCapabilities{}) 184 | if err != nil { 185 | fmt.Println(err) 186 | t.Errorf("error during update msg decoding") 187 | return 188 | } 189 | //PrintBgpUpdate(&bgpRoute) 190 | encodedUpdate, _ = hex.DecodeString(hexUpdate2) 191 | _, err = DecodeUpdateMsg(encodedUpdate, &BGPCapabilities{}) 192 | if err != nil { 193 | fmt.Println(err) 194 | t.Errorf("error during update msg decoding") 195 | return 196 | } 197 | //PrintBgpUpdate(&bgpRoute) 198 | } 199 | 200 | func TestDecodeUpdMsgWithAsPath(t *testing.T) { 201 | encodedUpdate, _ := hex.DecodeString(hexUpdate4) 202 | _, err := DecodeUpdateMsg(encodedUpdate, &BGPCapabilities{SupportASN4: true}) 203 | if err != nil { 204 | fmt.Println(err) 205 | t.Errorf("error during update msg decoding") 206 | return 207 | } 208 | //PrintBgpUpdate(&bgpRoute) 209 | 210 | } 211 | 212 | func TestEncodeKeepaliveMsg(t *testing.T) { 213 | encodedKA, _ := hex.DecodeString(hexKA) 214 | encKA := GenerateKeepalive() 215 | for cntr := 0; cntr < len(encKA); cntr++ { 216 | if encKA[cntr] != encodedKA[cntr] { 217 | t.Errorf("byte of encoded msg is not equal to etalon's msg") 218 | return 219 | } 220 | } 221 | } 222 | 223 | func TestDecodeNotificationMsg(t *testing.T) { 224 | encodedNotification, _ := hex.DecodeString(hexNotification) 225 | notification, err := DecodeNotificationMsg(encodedNotification) 226 | if err != nil { 227 | t.Errorf("error during notification decoding") 228 | return 229 | } 230 | if notification.ErrorCode != 6 && notification.ErrorSubcode != 7 { 231 | t.Errorf("error during notification decoding(code and subcode are not equal to etalon)") 232 | return 233 | } 234 | } 235 | 236 | func TestEncodeNotificationMsg(t *testing.T) { 237 | encodedNotification, _ := hex.DecodeString(hexNotification) 238 | notification := NotificationMsg{ErrorCode: BGP_CASE_ERROR, ErrorSubcode: BGP_CASE_ERROR_COLLISION} 239 | encNotification, err := EncodeNotificationMsg(¬ification) 240 | if err != nil { 241 | fmt.Println(err) 242 | t.Errorf("error during notification encoding") 243 | return 244 | } 245 | for cntr := 0; cntr < len(encNotification); cntr++ { 246 | if encNotification[cntr] != encodedNotification[cntr] { 247 | t.Errorf("byte of encoded msg is not equal to etalon's msg") 248 | return 249 | } 250 | } 251 | 252 | } 253 | 254 | func TestEncodeUpdateMsg1(t *testing.T) { 255 | bgpRoute := BGPRoute{ 256 | ORIGIN: ORIGIN_IGP, 257 | MULTI_EXIT_DISC: uint32(123), 258 | LOCAL_PREF: uint32(11), 259 | ATOMIC_AGGR: true, 260 | } 261 | p1, _ := IPv4ToUint32("1.92.0.0") 262 | p2, _ := IPv4ToUint32("11.92.128.0") 263 | p3, _ := IPv4ToUint32("1.1.1.10") 264 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 12, Prefix: p1}) 265 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 22, Prefix: p2}) 266 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 32, Prefix: p3}) 267 | err := bgpRoute.AddV4NextHop("10.0.0.2") 268 | if err != nil { 269 | fmt.Println(err) 270 | t.Errorf("cant encode update msg") 271 | return 272 | } 273 | data, err := EncodeUpdateMsg(&bgpRoute) 274 | if err != nil { 275 | fmt.Println(err) 276 | t.Errorf("cant encode update msg") 277 | return 278 | } 279 | bgpRoute2, err := DecodeUpdateMsg(data, &BGPCapabilities{}) 280 | if err != nil { 281 | fmt.Println(err) 282 | t.Errorf("cant decode encoded update") 283 | return 284 | } 285 | data2, _ := EncodeUpdateMsg(&bgpRoute2) 286 | if len(data) != len(data2) { 287 | t.Errorf("error in encoding/decoding of the same msg") 288 | return 289 | } 290 | for cntr := 0; cntr < len(data); cntr++ { 291 | if data[cntr] != data2[cntr] { 292 | t.Errorf("error in encoding/decoding of the same msg") 293 | return 294 | } 295 | } 296 | } 297 | 298 | func TestEncodeWithdrawUpdateMsg1(t *testing.T) { 299 | bgpRoute := BGPRoute{} 300 | bgpRoute.Community = []uint32{1, 2, 3, 4} 301 | p4, _ := IPv4ToUint32("192.168.0.0") 302 | bgpRoute.WithdrawRoutes = append(bgpRoute.WithdrawRoutes, IPV4_NLRI{Length: 16, Prefix: p4}) 303 | data, err := EncodeWithdrawUpdateMsg(&bgpRoute) 304 | if err != nil { 305 | fmt.Println(err) 306 | t.Errorf("cant encode withdraw update msg") 307 | return 308 | } 309 | bgpRoute2, err := DecodeUpdateMsg(data, &BGPCapabilities{}) 310 | if err != nil { 311 | fmt.Println(err) 312 | t.Errorf("cant decode withdraw encoded update") 313 | return 314 | } 315 | data2, _ := EncodeWithdrawUpdateMsg(&bgpRoute2) 316 | if len(data) != len(data2) { 317 | t.Errorf("error in encoding/decoding of the same withdraw msg") 318 | return 319 | } 320 | for cntr := 0; cntr < len(data); cntr++ { 321 | if data[cntr] != data2[cntr] { 322 | t.Errorf("error in encoding/decoding of the same withdraw msg") 323 | return 324 | } 325 | } 326 | data3, _ := EncodeUpdateMsg(&bgpRoute) 327 | for cntr := 0; cntr < len(data); cntr++ { 328 | if data[cntr] != data3[cntr] { 329 | t.Errorf("error in encoding/decoding of the same withdraw msg") 330 | return 331 | } 332 | } 333 | 334 | } 335 | 336 | func TestEncodeEndOfRIB(t *testing.T) { 337 | eor := GenerateEndOfRIB() 338 | if len(eor) != 23 { 339 | fmt.Println(eor) 340 | t.Errorf("error during EndOfRib marker generation") 341 | return 342 | } 343 | } 344 | 345 | func TestDecodeEndOfRIB(t *testing.T) { 346 | encodedUpdateEOR, _ := hex.DecodeString(hexEndOfRibv4) 347 | _, err := DecodeUpdateMsg(encodedUpdateEOR, &BGPCapabilities{SupportASN4: true}) 348 | if err != nil { 349 | switch err.(type) { 350 | case EndOfRib: 351 | default: 352 | t.Errorf("error during update msg decoding: %v\n", err) 353 | return 354 | } 355 | } 356 | } 357 | 358 | func TestAddPathEncodingDecoding(t *testing.T) { 359 | addPathList := []AddPathCapability{AddPathCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST, Flags: uint8(3)}} 360 | encAddPath, err := EncodeAddPathCapability(addPathList) 361 | if err != nil { 362 | t.Errorf("error during add path encoding: %v\n", err) 363 | } 364 | _, err = DecodeAddPathCapability(encAddPath[2:]) 365 | if err != nil { 366 | t.Errorf("error during add path encoding: %v\n", err) 367 | return 368 | } 369 | 370 | } 371 | 372 | /* MP-BGP MP_REACH/UNREACH_NLRI testing */ 373 | /* ipv6 */ 374 | func TestIPv6StringToUint(t *testing.T) { 375 | _, err := IPv6StringToAddr("::") 376 | if err != nil { 377 | t.Errorf("cant convert ipv6 to ipv6addr\n") 378 | return 379 | } 380 | addr, err := IPv6StringToAddr("fc1:2:3::1") 381 | if err != nil { 382 | t.Errorf("cant convert ipv6 to ipv6addr\n") 383 | return 384 | } 385 | ipv6 := IPv6AddrToString(addr) 386 | fmt.Println(ipv6) 387 | } 388 | 389 | func TestIPv6NLRIEncodingDecoding(t *testing.T) { 390 | encodedIPv6NLRI, _ := hex.DecodeString(hexIPv6NLRI) 391 | nlri := IPV6_NLRI{Length: 48} 392 | v6addr, err := IPv6StringToAddr("2a00:bdc0:e003::") 393 | if err != nil { 394 | t.Errorf("error during ipv6 addr converting: %v\n", err) 395 | return 396 | } 397 | nlri.Prefix = v6addr 398 | encIPv6NLRI, err := EncodeIPv6NLRI([]IPV6_NLRI{nlri}) 399 | if err != nil { 400 | t.Errorf("cant encode ipv6 nlri: %v\n", err) 401 | return 402 | } 403 | fmt.Println(encodedIPv6NLRI) 404 | fmt.Println(encIPv6NLRI) 405 | if len(encodedIPv6NLRI) != len(encIPv6NLRI) { 406 | t.Errorf("len of encoded ipv6 nlri is not equal to len of etalon\n") 407 | return 408 | } 409 | for i := 0; i < len(encIPv6NLRI); i++ { 410 | if encIPv6NLRI[i] != encodedIPv6NLRI[i] { 411 | t.Errorf("encoded ipv6 nlri is not equal to etalon") 412 | return 413 | } 414 | } 415 | decIpv6nlri, err := DecodeIPv6NLRI(encIPv6NLRI) 416 | if err != nil { 417 | t.Errorf("cant decode encoded nlri: %v\n", err) 418 | return 419 | } 420 | if decIpv6nlri[0].Length != nlri.Length && decIpv6nlri[0].Prefix != nlri.Prefix { 421 | fmt.Println(decIpv6nlri) 422 | fmt.Println(nlri) 423 | t.Errorf("decoded nlri not equal to original") 424 | return 425 | } 426 | } 427 | 428 | func TestIPv6MP_REACH_EncodingDecoding(t *testing.T) { 429 | encodedIPv6MPREACH, _ := hex.DecodeString(hexIPv6_MP_REACH) 430 | nlri := IPV6_NLRI{Length: 48} 431 | v6addr, _ := IPv6StringToAddr("2a00:bdc0:e003::") 432 | v6nh, _ := IPv6StringToAddr("2001:7f8:20:101::245:180") 433 | nlri.Prefix = v6addr 434 | encIPv6MPREACH, err := EncodeIPV6_MP_REACH_NLRI(v6nh, []IPV6_NLRI{nlri}) 435 | if err != nil { 436 | t.Errorf("cant encode ipv6 mp reach nlri: %v\n", err) 437 | return 438 | } 439 | if len(encodedIPv6MPREACH) != len(encIPv6MPREACH) { 440 | t.Errorf("len of encoded ipv6 mp reach nlri is not equal to len of etalon\n") 441 | return 442 | } 443 | for i := 0; i < len(encIPv6MPREACH); i++ { 444 | if encIPv6MPREACH[i] != encodedIPv6MPREACH[i] { 445 | t.Errorf("encoded ipv6 mp reach nlri is not equal to etalon") 446 | return 447 | } 448 | } 449 | mpReachHdr, err := DecodeMP_REACH_NLRI_HDR(encIPv6MPREACH) 450 | if err != nil { 451 | t.Errorf("cant decode mp_reach_nlri hdr: %v\n", err) 452 | return 453 | } 454 | decIPv6MPREACHnh, decIPv6MPREACHnlri, err := DecodeIPV6_MP_REACH_NLRI(encIPv6MPREACH[FOUR_OCTETS:], 455 | mpReachHdr) 456 | if err != nil { 457 | t.Errorf("cant decode encoded mp_reach_nlri for ipv6: %v\n", err) 458 | } 459 | if decIPv6MPREACHnlri[0].Prefix != nlri.Prefix || 460 | decIPv6MPREACHnlri[0].Length != nlri.Length || 461 | decIPv6MPREACHnh != v6nh { 462 | fmt.Printf("%#v\n", nlri) 463 | fmt.Printf("%#v\n", decIPv6MPREACHnlri) 464 | fmt.Printf("%#v\n", v6nh) 465 | fmt.Printf("%#v\n", decIPv6MPREACHnh) 466 | t.Errorf("decoded nlri not equal to original\n") 467 | return 468 | } 469 | } 470 | 471 | func TestIPv6MP_UNREACH_Encoding(t *testing.T) { 472 | nlri := IPV6_NLRI{Length: 48} 473 | v6addr, _ := IPv6StringToAddr("2a00:bdc0:e003::") 474 | nlri.Prefix = v6addr 475 | encIPv6MPUNREACH, err := EncodeIPV6_MP_UNREACH_NLRI([]IPV6_NLRI{nlri}) 476 | if err != nil { 477 | t.Errorf("cant encode ipv6 mp reach nlri: %v\n", err) 478 | return 479 | } 480 | fmt.Println(encIPv6MPUNREACH) 481 | } 482 | 483 | func TestIPv6MP_REACH_PathAttrEncoding(t *testing.T) { 484 | encodedIPv6MPREACHPA, _ := hex.DecodeString(hexIPv6_MP_REACH_NLRI_PA) 485 | nlri := IPV6_NLRI{Length: 48} 486 | v6addr, _ := IPv6StringToAddr("2a00:bdc0:e003::") 487 | v6nh, _ := IPv6StringToAddr("2001:7f8:20:101::245:180") 488 | nlri.Prefix = v6addr 489 | pa := PathAttr{} 490 | encIPv6MPREACHPA, err := EncodeV6MPRNLRI(v6nh, []IPV6_NLRI{nlri}, &pa) 491 | if err != nil { 492 | t.Errorf("cant encode ipv6 mp reach nlri: %v\n", err) 493 | return 494 | } 495 | if len(encodedIPv6MPREACHPA) != len(encIPv6MPREACHPA) { 496 | t.Errorf("len of encoded ipv6 mp reach nlri is not equal to len of etalon\n") 497 | return 498 | } 499 | for i := 0; i < len(encIPv6MPREACHPA); i++ { 500 | if encIPv6MPREACHPA[i] != encodedIPv6MPREACHPA[i] { 501 | fmt.Println(encodedIPv6MPREACHPA) 502 | fmt.Println(encIPv6MPREACHPA) 503 | t.Errorf("encoded ipv6 mp reach nlri is not equal to etalon") 504 | return 505 | } 506 | } 507 | } 508 | 509 | func TestIPv6MP_UNREACH_PathAttrEncoding(t *testing.T) { 510 | nlri := IPV6_NLRI{Length: 48} 511 | v6addr, _ := IPv6StringToAddr("2a00:bdc0:e003::") 512 | nlri.Prefix = v6addr 513 | pa := PathAttr{} 514 | encIPv6MPUNREACHPA, err := EncodeV6MPUNRNLRI([]IPV6_NLRI{nlri}, &pa) 515 | if err != nil { 516 | t.Errorf("cant encode ipv6 mp unreach nlri: %v\n", err) 517 | return 518 | } 519 | fmt.Println(encIPv6MPUNREACHPA) 520 | } 521 | 522 | func TestEncodeDecodeUpdateMsgV6(t *testing.T) { 523 | bgpRoute := BGPRoute{ 524 | ORIGIN: ORIGIN_IGP, 525 | MULTI_EXIT_DISC: uint32(123), 526 | LOCAL_PREF: uint32(11), 527 | ATOMIC_AGGR: true, 528 | } 529 | bgpRoute.NEXT_HOPv6, _ = IPv6StringToAddr("fc00::1") 530 | p1, _ := IPv6StringToAddr("2a02:6b8::") 531 | p2, _ := IPv6StringToAddr("2a00:1450:4010::") 532 | p3, _ := IPv6StringToAddr("2a03:2880:2130:cf05:face:b00c::1") 533 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 32, Prefix: p1}) 534 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 48, Prefix: p2}) 535 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 128, Prefix: p3}) 536 | msg, err := EncodeUpdateMsg(&bgpRoute) 537 | if err != nil { 538 | t.Errorf("cant encode update msg with ipv6 mp_reach_nlri attr: %v\n", err) 539 | return 540 | } 541 | bgpRouteDec, err := DecodeUpdateMsg(msg, &BGPCapabilities{}) 542 | if err != nil { 543 | t.Errorf("cant decode encoded v6 route: %v\n", err) 544 | return 545 | } 546 | if len(bgpRouteDec.RoutesV6) != 3 { 547 | t.Errorf("error in ipv6 mp_nlri decoding:wrong len\n") 548 | return 549 | } 550 | if bgpRouteDec.RoutesV6[0].Prefix != p1 && 551 | bgpRouteDec.RoutesV6[1].Prefix != p2 && 552 | bgpRouteDec.RoutesV6[2].Prefix != p3 { 553 | fmt.Println(bgpRouteDec.RoutesV6) 554 | fmt.Println(p1) 555 | fmt.Println(p2) 556 | fmt.Println(p3) 557 | t.Errorf("error in ipv6 mp_nlri decoding: prefix dont match\n") 558 | return 559 | } 560 | } 561 | 562 | func TestEncodeDecodeWithdrawUpdateMsgV6(t *testing.T) { 563 | var bgpRoute BGPRoute 564 | p1, _ := IPv6StringToAddr("2a02:6b8::") 565 | p2, _ := IPv6StringToAddr("2a00:1450:4010::") 566 | p3, _ := IPv6StringToAddr("2a03:2880:2130:cf05:face:b00c::1") 567 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, IPV6_NLRI{Length: 32, Prefix: p1}) 568 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, IPV6_NLRI{Length: 48, Prefix: p2}) 569 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, IPV6_NLRI{Length: 128, Prefix: p3}) 570 | msg, err := EncodeUpdateMsg(&bgpRoute) 571 | if err != nil { 572 | t.Errorf("cant encode update msg with ipv6 mp_reach_nlri attr: %v\n", err) 573 | return 574 | } 575 | bgpRouteDec, err := DecodeUpdateMsg(msg, &BGPCapabilities{}) 576 | if err != nil { 577 | t.Errorf("cant decode encoded v6 route: %v\n", err) 578 | return 579 | } 580 | fmt.Printf("%#v\n", bgpRouteDec) 581 | } 582 | 583 | /* ipv4 */ 584 | 585 | func TestIPv4NLRIEncodingDecoding(t *testing.T) { 586 | //encodedIPv6NLRI, _ := hex.DecodeString(hexIPv6NLRI) 587 | nlri := IPV4_NLRI{Length: 22} 588 | v4addr, err := IPv4ToUint32("10.10.252.0") 589 | if err != nil { 590 | t.Errorf("error during ipv4 addr converting: %v\n", err) 591 | return 592 | } 593 | nlri.Prefix = v4addr 594 | encIPv4NLRI, err := EncodeIPv4NLRI(RouteFlags{}, []IPV4_NLRI{nlri}) 595 | if err != nil { 596 | t.Errorf("cant encode ipv4 nlri: %v\n", err) 597 | return 598 | } 599 | decIpv4nlri, err := DecodeIPv4NLRI(RouteFlags{}, encIPv4NLRI) 600 | if err != nil { 601 | t.Errorf("cant decode encoded nlri: %v\n", err) 602 | return 603 | } 604 | if decIpv4nlri[0].Length != nlri.Length && decIpv4nlri[0].Prefix != nlri.Prefix { 605 | fmt.Println(decIpv4nlri) 606 | fmt.Println(nlri) 607 | t.Errorf("decoded nlri not equal to original") 608 | return 609 | } 610 | } 611 | 612 | func TestIPv4MP_REACH_EncodingDecoding(t *testing.T) { 613 | //encodedIPv6MPREACH, _ := hex.DecodeString(hexIPv6_MP_REACH) 614 | nlri := IPV4_NLRI{Length: 22} 615 | v4addr, _ := IPv4ToUint32("10.10.252.0") 616 | v4nh, _ := IPv4ToUint32("172.16.1.1") 617 | nlri.Prefix = v4addr 618 | encIPv4MPREACH, err := EncodeIPV4_MP_REACH_NLRI(v4nh, RouteFlags{}, 619 | []IPV4_NLRI{nlri}) 620 | if err != nil { 621 | t.Errorf("cant encode ipv4 mp reach nlri: %v\n", err) 622 | return 623 | } 624 | mpReachHdr, err := DecodeMP_REACH_NLRI_HDR(encIPv4MPREACH) 625 | if err != nil { 626 | t.Errorf("cant decode mp_reach_nlri hdr: %v\n", err) 627 | return 628 | } 629 | decIPv4MPREACHnh, decIPv4MPREACHnlri, err := DecodeIPV4_MP_REACH_NLRI( 630 | RouteFlags{}, 631 | encIPv4MPREACH[FOUR_OCTETS:], 632 | mpReachHdr) 633 | if err != nil { 634 | t.Errorf("cant decode encoded mp_reach_nlri for ipv4: %v\n", err) 635 | return 636 | } 637 | if len(decIPv4MPREACHnlri) != 1 { 638 | t.Errorf("error in decoding of mp_reach_nlri for ipv4. nlri's length not equal to 1 in this testcase") 639 | return 640 | } 641 | if decIPv4MPREACHnlri[0].Prefix != nlri.Prefix || 642 | decIPv4MPREACHnlri[0].Length != nlri.Length || 643 | decIPv4MPREACHnh != v4nh { 644 | fmt.Printf("%#v\n", nlri) 645 | fmt.Printf("%#v\n", decIPv4MPREACHnlri) 646 | fmt.Printf("%#v\n", v4nh) 647 | fmt.Printf("%#v\n", decIPv4MPREACHnh) 648 | t.Errorf("decoded nlri not equal to original\n") 649 | return 650 | } 651 | } 652 | 653 | func TestIPv4MP_UNREACH_Encoding(t *testing.T) { 654 | nlri := IPV4_NLRI{Length: 22} 655 | v4addr, _ := IPv4ToUint32("10.10.252.0") 656 | nlri.Prefix = v4addr 657 | encIPv4MPUNREACH, err := EncodeIPV4_MP_UNREACH_NLRI(RouteFlags{}, 658 | []IPV4_NLRI{nlri}) 659 | if err != nil { 660 | t.Errorf("cant encode ipv4 mp unreach nlri: %v\n", err) 661 | return 662 | } 663 | fmt.Println(encIPv4MPUNREACH) 664 | } 665 | 666 | func TestIPv4MP_REACH_PathAttrEncoding(t *testing.T) { 667 | //encodedIPv6MPREACHPA, _ := hex.DecodeString(hexIPv6_MP_REACH_NLRI_PA) 668 | nlri := IPV4_NLRI{Length: 22} 669 | v4addr, _ := IPv4ToUint32("10.10.252.0") 670 | v4nh, _ := IPv4ToUint32("172.16.1.1") 671 | nlri.Prefix = v4addr 672 | pa := PathAttr{} 673 | _, err := EncodeV4MPRNLRI(v4nh, RouteFlags{}, 674 | []IPV4_NLRI{nlri}, &pa) 675 | if err != nil { 676 | t.Errorf("cant encode ipv4 mp reach nlri: %v\n", err) 677 | return 678 | } 679 | } 680 | 681 | func TestIPv4MP_UNREACH_PathAttrEncoding(t *testing.T) { 682 | nlri := IPV4_NLRI{Length: 22} 683 | v4addr, _ := IPv4ToUint32("10.10.252.0") 684 | nlri.Prefix = v4addr 685 | pa := PathAttr{} 686 | encIPv4MPUNREACHPA, err := EncodeV4MPUNRNLRI(RouteFlags{}, 687 | []IPV4_NLRI{nlri}, &pa) 688 | if err != nil { 689 | t.Errorf("cant encode ipv4 mp unreach nlri: %v\n", err) 690 | return 691 | } 692 | fmt.Println(encIPv4MPUNREACHPA) 693 | } 694 | 695 | /* ipv4 w/ AddPath */ 696 | 697 | func TestIPv4AddPathMP_REACH_EncodingDecoding(t *testing.T) { 698 | //encodedIPv6MPREACH, _ := hex.DecodeString(hexIPv6_MP_REACH) 699 | nlri := IPV4_NLRI{Length: 22, PathID: 10} 700 | v4addr, _ := IPv4ToUint32("10.10.252.0") 701 | v4nh, _ := IPv4ToUint32("172.16.1.1") 702 | nlri.Prefix = v4addr 703 | encIPv4MPREACH, err := EncodeIPV4_MP_REACH_NLRI(v4nh, RouteFlags{WithPathId: true}, 704 | []IPV4_NLRI{nlri}) 705 | if err != nil { 706 | t.Errorf("cant encode ipv4 mp reach nlri: %v\n", err) 707 | return 708 | } 709 | mpReachHdr, err := DecodeMP_REACH_NLRI_HDR(encIPv4MPREACH) 710 | if err != nil { 711 | t.Errorf("cant decode mp_reach_nlri hdr: %v\n", err) 712 | return 713 | } 714 | decIPv4MPREACHnh, decIPv4MPREACHnlri, err := DecodeIPV4_MP_REACH_NLRI( 715 | RouteFlags{WithPathId: true}, 716 | encIPv4MPREACH[FOUR_OCTETS:], 717 | mpReachHdr) 718 | if err != nil { 719 | t.Errorf("cant decode encoded mp_reach_nlri for ipv4: %v\n", err) 720 | return 721 | } 722 | if len(decIPv4MPREACHnlri) != 1 { 723 | t.Errorf("error in decoding of mp_reach_nlri for ipv4. nlri's length not equal to 1 in this testcase") 724 | return 725 | } 726 | if decIPv4MPREACHnlri[0].Prefix != nlri.Prefix || 727 | decIPv4MPREACHnlri[0].Length != nlri.Length || 728 | decIPv4MPREACHnh != v4nh || decIPv4MPREACHnlri[0].PathID != nlri.PathID { 729 | fmt.Printf("%#v\n", nlri) 730 | fmt.Printf("%#v\n", decIPv4MPREACHnlri) 731 | fmt.Printf("%#v\n", v4nh) 732 | fmt.Printf("%#v\n", decIPv4MPREACHnh) 733 | fmt.Printf("%#v\n", decIPv4MPREACHnlri[0].PathID) 734 | t.Errorf("decoded nlri not equal to original\n") 735 | return 736 | } 737 | fmt.Printf("%#v\n", decIPv4MPREACHnlri) 738 | } 739 | 740 | func TestIPv4AddPathMP_UNREACH_Encoding(t *testing.T) { 741 | nlri := IPV4_NLRI{Length: 22, PathID: 10} 742 | v4addr, _ := IPv4ToUint32("10.10.252.0") 743 | nlri.Prefix = v4addr 744 | encIPv4MPUNREACH, err := EncodeIPV4_MP_UNREACH_NLRI(RouteFlags{WithPathId: true}, 745 | []IPV4_NLRI{nlri}) 746 | if err != nil { 747 | t.Errorf("cant encode ipv4 w/ path id mp unreach nlri: %v\n", err) 748 | return 749 | } 750 | fmt.Println(encIPv4MPUNREACH) 751 | } 752 | 753 | /* ipv4 labeled unicast */ 754 | 755 | func TestIPv4LabeledMP_REACH_EncodingDecoding(t *testing.T) { 756 | //encodedIPv6MPREACH, _ := hex.DecodeString(hexIPv6_MP_REACH) 757 | nlri := IPV4_NLRI{Length: 23, Label: 1888} 758 | v4addr, _ := IPv4ToUint32("10.10.252.0") 759 | v4nh, _ := IPv4ToUint32("172.16.1.1") 760 | nlri.Prefix = v4addr 761 | encIPv4MPREACH, err := EncodeLabeledIPV4_MP_REACH_NLRI(v4nh, RouteFlags{Labeled: true}, 762 | []IPV4_NLRI{nlri}) 763 | if err != nil { 764 | t.Errorf("cant encode ipv4 labeled mp reach nlri: %v\n", err) 765 | return 766 | } 767 | mpReachHdr, err := DecodeMP_REACH_NLRI_HDR(encIPv4MPREACH) 768 | if err != nil { 769 | t.Errorf("cant decode mp_reach_nlri hdr: %v\n", err) 770 | return 771 | } 772 | if mpReachHdr.SAFI != MP_SAFI_LABELED { 773 | t.Errorf("error in mp_reach_nlri labeled ipv4 hdr decoding\n") 774 | return 775 | } 776 | decIPv4MPREACHnh, decIPv4MPREACHnlri, err := DecodeIPV4_MP_REACH_NLRI( 777 | RouteFlags{Labeled: true}, 778 | encIPv4MPREACH[FOUR_OCTETS:], 779 | mpReachHdr) 780 | if err != nil { 781 | t.Errorf("cant decode encoded mp_reach_nlri for labeled ipv4: %v\n", err) 782 | return 783 | } 784 | if len(decIPv4MPREACHnlri) != 1 { 785 | t.Errorf("error in decoding of mp_reach_nlri for ipv4. nlri's length not equal to 1 in this testcase") 786 | return 787 | } 788 | if decIPv4MPREACHnlri[0].Prefix != nlri.Prefix || 789 | decIPv4MPREACHnlri[0].Length != nlri.Length || 790 | decIPv4MPREACHnh != v4nh || decIPv4MPREACHnlri[0].Label != nlri.Label { 791 | fmt.Printf("%#v\n", nlri) 792 | fmt.Printf("%#v\n", decIPv4MPREACHnlri) 793 | fmt.Printf("%#v\n", v4nh) 794 | fmt.Printf("%#v\n", decIPv4MPREACHnh) 795 | fmt.Printf("%#v\n", decIPv4MPREACHnlri[0].Label) 796 | t.Errorf("decoded nlri not equal to original\n") 797 | return 798 | } 799 | fmt.Printf("%#v\n", decIPv4MPREACHnlri) 800 | } 801 | 802 | func TestIPv4LabeledMP_UNREACH_Encoding(t *testing.T) { 803 | nlri := IPV4_NLRI{Length: 22, Label: 1888} 804 | v4addr, _ := IPv4ToUint32("10.10.252.0") 805 | nlri.Prefix = v4addr 806 | encIPv4MPUNREACH, err := EncodeLabeledIPV4_MP_UNREACH_NLRI(RouteFlags{Labeled: true}, 807 | []IPV4_NLRI{nlri}) 808 | if err != nil { 809 | t.Errorf("cant encode labled ipv4 mp unreach nlri: %v\n", err) 810 | return 811 | } 812 | fmt.Println(encIPv4MPUNREACH) 813 | } 814 | 815 | /* ipv4 labeled unicast w/ 6 routes and communities generated at Juniper */ 816 | func TestIPv4LabeledDecodeUpdate(t *testing.T) { 817 | encodedUpdate, _ := hex.DecodeString(hexLabeledIPv4_MP_REACH_NLRI) 818 | bgpRoute, err := DecodeUpdateMsg(encodedUpdate, &BGPCapabilities{SupportASN4: true}) 819 | if err != nil { 820 | fmt.Println(err) 821 | t.Errorf("error during update msg decoding") 822 | return 823 | } 824 | fmt.Println("###### decoded labeled IPv4 #####") 825 | fmt.Printf("%#v\n", bgpRoute) 826 | PrintBgpUpdate(&bgpRoute) 827 | } 828 | 829 | //Benchmarking 830 | 831 | func BenchmarkDecodeUpdMsgWithAsPath(b *testing.B) { 832 | encodedUpdate, _ := hex.DecodeString(hexUpdate4) 833 | caps := BGPCapabilities{} 834 | caps.SupportASN4 = true 835 | for i := 1; i < b.N; i++ { 836 | DecodeUpdateMsg(encodedUpdate, &caps) 837 | } 838 | //PrintBgpUpdate(&bgpRoute) 839 | } 840 | 841 | func BenchmarkEncodeUpdateMsg1(b *testing.B) { 842 | bgpRoute := BGPRoute{ 843 | ORIGIN: ORIGIN_IGP, 844 | MULTI_EXIT_DISC: uint32(123), 845 | LOCAL_PREF: uint32(11), 846 | ATOMIC_AGGR: true, 847 | } 848 | p1, _ := IPv4ToUint32("1.92.0.0") 849 | p2, _ := IPv4ToUint32("11.92.128.0") 850 | p3, _ := IPv4ToUint32("1.1.1.10") 851 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 12, Prefix: p1}) 852 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 22, Prefix: p2}) 853 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 32, Prefix: p3}) 854 | bgpRoute.AddV4NextHop("10.0.0.2") 855 | for i := 0; i < b.N; i++ { 856 | EncodeUpdateMsg(&bgpRoute) 857 | } 858 | } 859 | 860 | func BenchmarkEncodeUpdateMsgMPINET(b *testing.B) { 861 | bgpRoute := BGPRoute{ 862 | ORIGIN: ORIGIN_IGP, 863 | MULTI_EXIT_DISC: uint32(123), 864 | LOCAL_PREF: uint32(11), 865 | ATOMIC_AGGR: true, 866 | } 867 | p1, _ := IPv4ToUint32("1.92.0.0") 868 | p2, _ := IPv4ToUint32("11.92.128.0") 869 | p3, _ := IPv4ToUint32("1.1.1.10") 870 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 12, Prefix: p1}) 871 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 22, Prefix: p2}) 872 | bgpRoute.Routes = append(bgpRoute.Routes, IPV4_NLRI{Length: 32, Prefix: p3}) 873 | bgpRoute.NEXT_HOPv4, _ = IPv4ToUint32("10.0.0.2") 874 | bgpRoute.MPINET = true 875 | for i := 0; i < b.N; i++ { 876 | EncodeUpdateMsg(&bgpRoute) 877 | } 878 | } 879 | 880 | func BenchmarkEncodeUpdateMsgV6(b *testing.B) { 881 | bgpRoute := BGPRoute{ 882 | ORIGIN: ORIGIN_IGP, 883 | MULTI_EXIT_DISC: uint32(123), 884 | LOCAL_PREF: uint32(11), 885 | ATOMIC_AGGR: true, 886 | } 887 | bgpRoute.NEXT_HOPv6, _ = IPv6StringToAddr("fc00::1") 888 | p1, _ := IPv6StringToAddr("2a02:6b8::") 889 | p2, _ := IPv6StringToAddr("2a00:1450:4010::") 890 | p3, _ := IPv6StringToAddr("2a03:2880:2130:cf05:face:b00c::1") 891 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 32, Prefix: p1}) 892 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 48, Prefix: p2}) 893 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, IPV6_NLRI{Length: 128, Prefix: p3}) 894 | for i := 0; i < b.N; i++ { 895 | EncodeUpdateMsg(&bgpRoute) 896 | } 897 | } 898 | 899 | func BenchmarkEncodeOpen(b *testing.B) { 900 | capList := []MPCapability{ 901 | MPCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST}, 902 | MPCapability{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST}} 903 | openMsg := OpenMsg{Hdr: OpenMsgHdr{Version: 4, MyASN: 65000, HoldTime: 90, BGPID: 167772162}} 904 | openMsg.MPCaps = append(openMsg.MPCaps, capList...) 905 | for i := 0; i < b.N; i++ { 906 | EncodeOpenMsg(&openMsg) 907 | } 908 | } 909 | 910 | func BenchmarkDecodeOpen(b *testing.B) { 911 | capList := []MPCapability{ 912 | MPCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST}, 913 | MPCapability{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST}} 914 | openMsg := OpenMsg{Hdr: OpenMsgHdr{Version: 4, MyASN: 65000, HoldTime: 90, BGPID: 167772162}} 915 | openMsg.MPCaps = append(openMsg.MPCaps, capList...) 916 | data, _ := EncodeOpenMsg(&openMsg) 917 | for i := 0; i < b.N; i++ { 918 | DecodeOpenMsg(data[MSG_HDR_SIZE:]) 919 | } 920 | } 921 | -------------------------------------------------------------------------------- /simple_bgp_injector.go: -------------------------------------------------------------------------------- 1 | package bgp2go 2 | 3 | /* 4 | simple bgp injector. main purpose is to inject/withdraw 5 | routes into/from bgp domain (for example in any slb's 6 | keepalive daemons) 7 | */ 8 | //TODO: logging everywhere 9 | 10 | import ( 11 | "fmt" 12 | "regexp" 13 | "strconv" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | var ( 19 | name2AFI = map[string]MPCapability{ 20 | "inet": MPCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST}, 21 | "inet6": MPCapability{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST}, 22 | } 23 | 24 | mpCapInet = MPCapability{AFI: MP_AFI_IPV4, SAFI: MP_SAFI_UCAST} 25 | mpCapInet6 = MPCapability{AFI: MP_AFI_IPV6, SAFI: MP_SAFI_UCAST} 26 | ) 27 | 28 | /* 29 | Generic per bgp process data 30 | */ 31 | type BGPContext struct { 32 | ASN uint32 33 | RouterID uint32 34 | //TODO: rib per afi/safi 35 | RIBv4 []IPV4_NLRI 36 | RIBv6 []IPV6_NLRI 37 | ListenLocal bool 38 | Neighbours []BGPNeighbour 39 | ToMainContext chan BGPCommand 40 | } 41 | 42 | /* 43 | Struct, which contains all metadata about the neighbour 44 | */ 45 | type BGPNeighbour struct { 46 | Address string 47 | State string 48 | CmndChan chan BGPCommand 49 | toPassiveNeighbourContext chan BGPCommand 50 | //afi & safi, which can be sended to neighbour 51 | AFIs []string 52 | //for active/passive collision detection 53 | passiveExist bool 54 | activeConnected bool 55 | /* 56 | right now i'm thinking that it will be easier to have one 57 | struct with loots of bool fields that list inside of struct 58 | in which we will need to search each time 59 | */ 60 | speaksInet bool 61 | speaksInet6 bool 62 | as4 bool 63 | } 64 | 65 | /* 66 | struct, to which we add external info about neighbour 67 | while we parsing a command from external source 68 | */ 69 | type BGPNeighbourCfg struct { 70 | Address string 71 | MPCaps []MPCapability 72 | } 73 | 74 | type BGPCommand struct { 75 | From string 76 | Cmnd string 77 | CmndData string 78 | Route BGPRoute 79 | //For anonymous connections 80 | ResponseChan chan string 81 | //for passive(when someone connected to us) connection to start 82 | sockChans SockControlChans 83 | } 84 | 85 | type BGPNeighbourContext struct { 86 | ToMainContext chan BGPCommand 87 | ToNeighbourContext chan BGPCommand 88 | /* 89 | used when we have both inboud and outbound coonnection to the same 90 | peer and yet do not know which one is going to be threated as collision 91 | */ 92 | NeighbourAddr string 93 | ASN uint32 94 | RouterID uint32 95 | NextHop string 96 | NextHopV6 IPv6Addr 97 | asn4 bool 98 | fsm FSM 99 | MPCaps []MPCapability 100 | /* 101 | we are going to use this to decide should we adv routes 102 | of such families to this neighbour or not. 103 | TODO: mb separate struct will be better 104 | */ 105 | speaksInet bool 106 | speaksInet6 bool 107 | as4 bool 108 | //placeholders, not yet implemented 109 | InboundPolicy string 110 | OutboundPolicy string 111 | } 112 | 113 | /* 114 | used to communicate w/ main bgp process from external apps. 115 | For example: 116 | Cmnd: Advertise 117 | Data: ipv4/ipv6 address/mask 118 | or 119 | Cmnd: Withdraw 120 | Data: ipv4/ipv6 address/mask 121 | */ 122 | type BGPProcessMsg struct { 123 | Cmnd string 124 | /* 125 | TODO: mb it's better to use []byte instead of string 126 | for Data field (for example we can pass json etc) 127 | */ 128 | Data string 129 | } 130 | 131 | func StartBGPProcess(toBGPProcess, fromBGPProcess chan BGPProcessMsg, 132 | bgpContext BGPContext) { 133 | bgpContext.ToMainContext = make(chan BGPCommand) 134 | //we need root access to bind @ < 1024 port 135 | if bgpContext.ListenLocal { 136 | go BGPListenForConnection(bgpContext.ToMainContext) 137 | } 138 | loop := 1 139 | for loop == 1 { 140 | select { 141 | case cmndToBGPProcess := <-toBGPProcess: 142 | (&bgpContext).ProcessExternalCommand(cmndToBGPProcess, fromBGPProcess) 143 | case cmndFromNeighbourContext := <-bgpContext.ToMainContext: 144 | (&bgpContext).ProcessNeighbourCommand(cmndFromNeighbourContext) 145 | } 146 | } 147 | 148 | } 149 | 150 | func (context *BGPContext) ProcessExternalCommand(cmnd BGPProcessMsg, 151 | responseChan chan BGPProcessMsg) { 152 | switch cmnd.Cmnd { 153 | case "AddNeighbour": 154 | context.AddNeighbour(cmnd.Data) 155 | case "RemoveNeighbour": 156 | context.RemoveNeighbour(cmnd.Data) 157 | case "AddV4Route": 158 | context.AddV4Route(cmnd.Data) 159 | case "WithdrawV4Route": 160 | context.WithdrawV4Route(cmnd.Data) 161 | case "AddV6Route": 162 | context.AddV6Route(cmnd.Data) 163 | case "WithdrawV6Route": 164 | context.WithdrawV6Route(cmnd.Data) 165 | } 166 | } 167 | 168 | func (context *BGPContext) ProcessNeighbourCommand(cmnd BGPCommand) { 169 | switch cmnd.Cmnd { 170 | case "NewRouterID": 171 | if context.RouterID == 0 { 172 | rid, err := IPv4ToUint32(cmnd.CmndData) 173 | if err != nil { 174 | return 175 | } 176 | context.RouterID = rid 177 | } 178 | 179 | case "NewConnection": 180 | neighbour, err, _ := context.FindNeighbour(cmnd.CmndData) 181 | if err != nil { 182 | cmnd.ResponseChan <- "teardown" 183 | return 184 | } 185 | if neighbour.State == "Established" { 186 | cmnd.ResponseChan <- "teardown" 187 | return 188 | } 189 | cmnd.ResponseChan <- "continue" 190 | return 191 | 192 | case "GetRouterID": 193 | neighbour, err, _ := context.FindNeighbour(cmnd.From) 194 | if err != nil { 195 | return 196 | } 197 | neighbour.CmndChan <- BGPCommand{Cmnd: "RouterID", 198 | CmndData: strconv.FormatUint(uint64(context.RouterID), 10)} 199 | 200 | case "GetRouterIDPassive": 201 | neighbour, err, _ := context.FindNeighbour(cmnd.From) 202 | if err != nil { 203 | return 204 | } 205 | neighbour.toPassiveNeighbourContext <- BGPCommand{Cmnd: "RouterID", 206 | CmndData: strconv.FormatUint(uint64(context.RouterID), 10)} 207 | 208 | case "AddPassiveNeighbour": 209 | context.AddPassiveNeighbour(cmnd.CmndData, cmnd.sockChans) 210 | 211 | case "PassiveCollisionCheck": 212 | context.ShouldCheckCollision(cmnd.From, true) 213 | 214 | case "CollisionCheck": 215 | context.ShouldCheckCollision(cmnd.From, false) 216 | 217 | case "PassiveWonCollisionDetection", "PassiveClossed", "ActiveClossed", 218 | "ActiveConnected", "Down", "Established", "PassiveEstablished", 219 | "speaksInet", "speaksInet6": 220 | context.ChangeNeighbourInfo(cmnd.From, cmnd.Cmnd) 221 | 222 | case "PassiveTeardown": 223 | context.RestartActiveNeighbour(cmnd.From) 224 | 225 | case "ActiveStartConnection": 226 | context.CheckNeighbourInfo(&cmnd) 227 | } 228 | } 229 | 230 | func (context *BGPContext) FindNeighbour(neighbour string) (*BGPNeighbour, error, int) { 231 | for i, existingNeighbour := range context.Neighbours { 232 | if existingNeighbour.Address == neighbour { 233 | return &context.Neighbours[i], nil, i 234 | } 235 | } 236 | return nil, fmt.Errorf("Neighbour doesnt exists"), -1 237 | } 238 | 239 | func parseNeighbourData(data []string, neighbourCfg *BGPNeighbourCfg) { 240 | /* 241 | TODO: i dont like how it's looks like; prob gonna rewrite it in future 242 | e.g we will recv json with all the data from external point (Data will be []byte 243 | instead of string) 244 | */ 245 | 246 | for _, field := range data { 247 | if val, exists := name2AFI[field]; exists { 248 | neighbourCfg.MPCaps = append(neighbourCfg.MPCaps, val) 249 | } 250 | } 251 | } 252 | 253 | func (context *BGPContext) AddNeighbour(neighbourData string) { 254 | /* 255 | IMPORTANT: for v6 peering to work, neighbours address 256 | must be in format []. right now i'm thinking 257 | that it's better to create such address in external 258 | application (dont wanna add regexp checks right now into 259 | this lib; mb will change my mind in future) 260 | for example check: go_keepalived/notifier/bgp_nitifier.go 261 | */ 262 | var neighbourCfg BGPNeighbourCfg 263 | dataFields := strings.Fields(neighbourData) 264 | neighbourCfg.Address = dataFields[0] 265 | if len(dataFields) > 1 { 266 | parseNeighbourData(dataFields, &neighbourCfg) 267 | } 268 | _, err, _ := context.FindNeighbour(neighbourCfg.Address) 269 | if err == nil { 270 | //neighbour already exists 271 | return 272 | } 273 | cmndChan := make(chan BGPCommand, 1) 274 | passiveCmndChan := make(chan BGPCommand, 1) 275 | context.Neighbours = append(context.Neighbours, BGPNeighbour{ 276 | Address: neighbourCfg.Address, 277 | State: "Idle", CmndChan: cmndChan, 278 | toPassiveNeighbourContext: passiveCmndChan}) 279 | bgpNeighbourContext := BGPNeighbourContext{RouterID: context.RouterID, 280 | ASN: context.ASN, ToMainContext: context.ToMainContext, 281 | ToNeighbourContext: cmndChan, 282 | NeighbourAddr: neighbourCfg.Address} 283 | bgpNeighbourContext.MPCaps = append(bgpNeighbourContext.MPCaps, neighbourCfg.MPCaps...) 284 | go StartBGPNeighbourContext(&bgpNeighbourContext, false, SockControlChans{}) 285 | } 286 | 287 | func (context *BGPContext) RemoveNeighbour(neighbourData string) { 288 | /* 289 | IMPORTANT: for v6 peering to work, check notice @ AddNeighbour routine 290 | */ 291 | var neighbourCfg BGPNeighbourCfg 292 | dataFields := strings.Fields(neighbourData) 293 | neighbourCfg.Address = dataFields[0] 294 | neighbour, err, i := context.FindNeighbour(neighbourCfg.Address) 295 | if err != nil { 296 | //neighbour doesnt exists 297 | return 298 | } 299 | neighbour.CmndChan <- BGPCommand{Cmnd: "Shutdown"} 300 | if i == (len(context.Neighbours) - 1) { 301 | context.Neighbours = context.Neighbours[:i] 302 | } else { 303 | context.Neighbours = append(context.Neighbours[:i], context.Neighbours[i+1:]...) 304 | } 305 | } 306 | 307 | func (context *BGPContext) RestartActiveNeighbour(neighbour string) { 308 | bgpNeighbour, err, _ := context.FindNeighbour(neighbour) 309 | if err != nil { 310 | /* 311 | should never fails, coz we restarts already existing neighbour context 312 | */ 313 | return 314 | } 315 | if bgpNeighbour.CmndChan == bgpNeighbour.toPassiveNeighbourContext { 316 | cmndChan := make(chan BGPCommand, 1) 317 | bgpNeighbour.CmndChan = cmndChan 318 | } 319 | bgpNeighbourContext := BGPNeighbourContext{RouterID: context.RouterID, 320 | ASN: context.ASN, ToMainContext: context.ToMainContext, 321 | ToNeighbourContext: bgpNeighbour.CmndChan, 322 | NeighbourAddr: neighbour} 323 | 324 | go StartBGPNeighbourContext(&bgpNeighbourContext, false, SockControlChans{}) 325 | 326 | } 327 | 328 | func (context *BGPContext) AddPassiveNeighbour(neighbourAddr string, sockChans SockControlChans) { 329 | neighbour, err, _ := context.FindNeighbour(neighbourAddr) 330 | if err != nil { 331 | /* 332 | FIXME: possible leak; this is very unlikely situation 333 | when we have passed FindNeighbour test during "NewConnection" phase; 334 | but somehow after that neighbour was deleted. in this situation proper 335 | actions would be to close sockets etc (we can send cmnds to chans from 336 | SockControllChans struct) 337 | */ 338 | return 339 | } 340 | neighbour.passiveExist = true 341 | bgpNeighbourContext := BGPNeighbourContext{RouterID: context.RouterID, 342 | ASN: context.ASN, ToMainContext: context.ToMainContext, 343 | ToNeighbourContext: neighbour.toPassiveNeighbourContext, 344 | NeighbourAddr: neighbourAddr} 345 | go StartBGPNeighbourContext(&bgpNeighbourContext, true, sockChans) 346 | } 347 | 348 | func (context *BGPContext) ShouldCheckCollision(neighbourAddr string, passive bool) { 349 | neighbour, err, _ := context.FindNeighbour(neighbourAddr) 350 | if err != nil { 351 | //TODO: proper handling 352 | return 353 | } 354 | bgpCmnd := BGPCommand{} 355 | if passive { 356 | if neighbour.State != "Established" && neighbour.activeConnected == true { 357 | bgpCmnd.Cmnd = "PerformCollisionCheck" 358 | } else { 359 | bgpCmnd.Cmnd = "NoCollision" 360 | } 361 | neighbour.toPassiveNeighbourContext <- bgpCmnd 362 | return 363 | } else { 364 | if neighbour.State != "Established" && neighbour.passiveExist == true { 365 | bgpCmnd.Cmnd = "PerformCollisionCheck" 366 | } else { 367 | bgpCmnd.Cmnd = "NoCollision" 368 | } 369 | neighbour.CmndChan <- bgpCmnd 370 | } 371 | } 372 | 373 | func (context *BGPContext) ChangeNeighbourInfo(neighbourAddr string, cmnd string) { 374 | neighbour, err, _ := context.FindNeighbour(neighbourAddr) 375 | if err != nil { 376 | //TODO: proper handling 377 | return 378 | } 379 | 380 | switch cmnd { 381 | case "PassiveWonCollisionDetection": 382 | neighbour.CmndChan = neighbour.toPassiveNeighbourContext 383 | case "PassiveClossed": 384 | neighbour.passiveExist = false 385 | case "ActiveClossed": 386 | neighbour.activeConnected = false 387 | case "ActiveConnected": 388 | neighbour.activeConnected = true 389 | case "Established": 390 | neighbour.State = "Established" 391 | if neighbour.speaksInet { 392 | context.AdvertiseAllRoutesV4(neighbour.CmndChan) 393 | } 394 | if neighbour.speaksInet6 { 395 | context.AdvertiseAllRoutesV6(neighbour.CmndChan) 396 | } 397 | case "PassiveEstablished": 398 | neighbour.State = "Established" 399 | neighbour.CmndChan = neighbour.toPassiveNeighbourContext 400 | if neighbour.speaksInet { 401 | context.AdvertiseAllRoutesV4(neighbour.CmndChan) 402 | } 403 | if neighbour.speaksInet6 { 404 | context.AdvertiseAllRoutesV6(neighbour.CmndChan) 405 | } 406 | case "Down": 407 | neighbour.State = "Down" 408 | neighbour.speaksInet = false 409 | neighbour.speaksInet6 = false 410 | case "speaksInet": 411 | neighbour.speaksInet = true 412 | case "speaksInet6": 413 | neighbour.speaksInet6 = true 414 | } 415 | 416 | } 417 | 418 | func (context *BGPContext) CheckNeighbourInfo(cmnd *BGPCommand) { 419 | neighbour, err, _ := context.FindNeighbour(cmnd.From) 420 | if err != nil { 421 | return 422 | } 423 | switch cmnd.Cmnd { 424 | case "ActiveStartConnection": 425 | if neighbour.State == "Established" { 426 | cmnd.ResponseChan <- "teardown" 427 | } else { 428 | cmnd.ResponseChan <- "continue" 429 | } 430 | } 431 | } 432 | 433 | /* 434 | TODO: think about how to reduce boilerplate code (to many copy/paste right now; 435 | once per each afi/safi). or mb move it to sep files, like simple_injector_v4/v6 etc 436 | */ 437 | 438 | func (context *BGPContext) AddV4Route(route string) { 439 | //TODO:check/parse route 440 | splittedRoute := strings.Split(route, "/") 441 | if len(splittedRoute) != 2 { 442 | return 443 | } 444 | val, err := strconv.ParseUint(splittedRoute[1], 10, 8) 445 | if err != nil { 446 | return 447 | } 448 | mask := uint8(val) 449 | ipv4, err := IPv4ToUint32(splittedRoute[0]) 450 | if err != nil { 451 | return 452 | } 453 | 454 | _, err = context.FindV4Route(ipv4, mask) 455 | if err == nil { 456 | //this means that route already exists 457 | return 458 | } 459 | 460 | newRoute := IPV4_NLRI{Length: mask, Prefix: ipv4} 461 | context.RIBv4 = append(context.RIBv4, newRoute) 462 | context.AdvertiseRouteV4(newRoute) 463 | 464 | } 465 | 466 | func (context *BGPContext) AddV6Route(route string) { 467 | //TODO:check/parse route 468 | splittedRoute := strings.Split(route, "/") 469 | if len(splittedRoute) != 2 { 470 | return 471 | } 472 | val, err := strconv.ParseUint(splittedRoute[1], 10, 8) 473 | if err != nil { 474 | return 475 | } 476 | mask := uint8(val) 477 | ipv6, err := IPv6StringToAddr(splittedRoute[0]) 478 | if err != nil { 479 | return 480 | } 481 | 482 | _, err = context.FindV6Route(ipv6, mask) 483 | if err == nil { 484 | //this means that route already exists 485 | return 486 | } 487 | 488 | newRoute := IPV6_NLRI{Length: mask, Prefix: ipv6} 489 | context.RIBv6 = append(context.RIBv6, newRoute) 490 | context.AdvertiseRouteV6(newRoute) 491 | } 492 | 493 | func (context *BGPContext) WithdrawV4Route(route string) { 494 | //TODO:check/parse route 495 | splittedRoute := strings.Split(route, "/") 496 | if len(splittedRoute) != 2 { 497 | return 498 | } 499 | val, err := strconv.ParseUint(splittedRoute[1], 10, 8) 500 | if err != nil { 501 | return 502 | } 503 | mask := uint8(val) 504 | ipv4, err := IPv4ToUint32(splittedRoute[0]) 505 | if err != nil { 506 | return 507 | } 508 | 509 | err = context.DeleteV4Route(ipv4, mask) 510 | if err != nil { 511 | //this means that route doesnt exists 512 | return 513 | } 514 | 515 | wRoute := IPV4_NLRI{Length: mask, Prefix: ipv4} 516 | context.WithdrawRouteV4(wRoute) 517 | 518 | } 519 | 520 | func (context *BGPContext) WithdrawV6Route(route string) { 521 | //TODO:check/parse route 522 | splittedRoute := strings.Split(route, "/") 523 | if len(splittedRoute) != 2 { 524 | return 525 | } 526 | val, err := strconv.ParseUint(splittedRoute[1], 10, 8) 527 | if err != nil { 528 | return 529 | } 530 | mask := uint8(val) 531 | ipv6, err := IPv6StringToAddr(splittedRoute[0]) 532 | if err != nil { 533 | return 534 | } 535 | 536 | err = context.DeleteV6Route(ipv6, mask) 537 | if err != nil { 538 | //this means that route doesnt exists 539 | return 540 | } 541 | 542 | wRoute := IPV6_NLRI{Length: mask, Prefix: ipv6} 543 | context.WithdrawRouteV6(wRoute) 544 | 545 | } 546 | 547 | func (context *BGPContext) FindV4Route(ipv4 uint32, mask uint8) (IPV4_NLRI, error) { 548 | for _, nlri := range context.RIBv4 { 549 | if nlri.Prefix == ipv4 && nlri.Length == mask { 550 | return nlri, nil 551 | } 552 | } 553 | return IPV4_NLRI{}, fmt.Errorf("route doesnt exists") 554 | } 555 | 556 | func (context *BGPContext) FindV6Route(ipv6 IPv6Addr, mask uint8) (IPV6_NLRI, error) { 557 | for _, nlri := range context.RIBv6 { 558 | if nlri.Prefix.isEqual(ipv6) && nlri.Length == mask { 559 | return nlri, nil 560 | } 561 | } 562 | return IPV6_NLRI{}, fmt.Errorf("route doesnt exists") 563 | } 564 | 565 | func (context *BGPContext) DeleteV4Route(ipv4 uint32, mask uint8) error { 566 | for n, nlri := range context.RIBv4 { 567 | if nlri.Prefix == ipv4 && nlri.Length == mask { 568 | if n == (len(context.RIBv4) - 1) { 569 | context.RIBv4 = context.RIBv4[:n] 570 | } else { 571 | context.RIBv4 = append(context.RIBv4[:n], context.RIBv4[n+1:]...) 572 | } 573 | return nil 574 | } 575 | } 576 | return fmt.Errorf("route doesnt exist") 577 | } 578 | 579 | func (context *BGPContext) DeleteV6Route(ipv6 IPv6Addr, mask uint8) error { 580 | for n, nlri := range context.RIBv6 { 581 | if nlri.Prefix.isEqual(ipv6) && nlri.Length == mask { 582 | if n == (len(context.RIBv6) - 1) { 583 | context.RIBv6 = context.RIBv6[:n] 584 | } else { 585 | context.RIBv6 = append(context.RIBv6[:n], context.RIBv6[n+1:]...) 586 | } 587 | return nil 588 | } 589 | } 590 | return fmt.Errorf("route doesnt exist") 591 | } 592 | 593 | /* 594 | This is BGPContext's func because in future we could use info from context(for global lp, 595 | aspath etc 596 | */ 597 | func (context *BGPContext) GenerateUpdateRouteV4(ipv4 IPV4_NLRI) BGPRoute { 598 | bgpRoute := BGPRoute{ 599 | ORIGIN: ORIGIN_IGP, 600 | LOCAL_PREF: 100, 601 | } 602 | bgpRoute.Routes = append(bgpRoute.Routes, ipv4) 603 | return bgpRoute 604 | } 605 | 606 | func (context *BGPContext) GenerateUpdateRouteV6(ipv6 IPV6_NLRI) BGPRoute { 607 | bgpRoute := BGPRoute{ 608 | ORIGIN: ORIGIN_IGP, 609 | LOCAL_PREF: 100, 610 | } 611 | bgpRoute.RoutesV6 = append(bgpRoute.RoutesV6, ipv6) 612 | return bgpRoute 613 | } 614 | 615 | func (context *BGPContext) GenerateWithdrawRouteV4(ipv4 IPV4_NLRI) BGPRoute { 616 | bgpRoute := BGPRoute{} 617 | bgpRoute.WithdrawRoutes = append(bgpRoute.WithdrawRoutes, ipv4) 618 | return bgpRoute 619 | } 620 | 621 | func (context *BGPContext) GenerateWithdrawRouteV6(ipv6 IPV6_NLRI) BGPRoute { 622 | bgpRoute := BGPRoute{} 623 | bgpRoute.WithdrawRoutesV6 = append(bgpRoute.WithdrawRoutesV6, ipv6) 624 | return bgpRoute 625 | } 626 | 627 | func (context *BGPContext) AdvertiseRouteV4(ipv4 IPV4_NLRI) { 628 | for _, neighbour := range context.Neighbours { 629 | if neighbour.State == "Established" && neighbour.speaksInet { 630 | neighbour.CmndChan <- BGPCommand{ 631 | Cmnd: "AdvertiseRouteV4", 632 | Route: context.GenerateUpdateRouteV4(ipv4)} 633 | } 634 | } 635 | } 636 | 637 | func (context *BGPContext) AdvertiseRouteV6(ipv6 IPV6_NLRI) { 638 | for _, neighbour := range context.Neighbours { 639 | if neighbour.State == "Established" && neighbour.speaksInet6 { 640 | neighbour.CmndChan <- BGPCommand{ 641 | Cmnd: "AdvertiseRouteV6", 642 | Route: context.GenerateUpdateRouteV6(ipv6)} 643 | } 644 | } 645 | } 646 | 647 | func (context *BGPContext) WithdrawRouteV4(ipv4 IPV4_NLRI) { 648 | for _, neighbour := range context.Neighbours { 649 | if neighbour.State == "Established" && neighbour.speaksInet { 650 | neighbour.CmndChan <- BGPCommand{ 651 | Cmnd: "WithdrawRouteV4", 652 | Route: context.GenerateWithdrawRouteV4(ipv4)} 653 | } 654 | } 655 | } 656 | 657 | func (context *BGPContext) WithdrawRouteV6(ipv6 IPV6_NLRI) { 658 | for _, neighbour := range context.Neighbours { 659 | if neighbour.State == "Established" && neighbour.speaksInet6 { 660 | neighbour.CmndChan <- BGPCommand{ 661 | Cmnd: "WithdrawRouteV6", 662 | Route: context.GenerateWithdrawRouteV6(ipv6)} 663 | } 664 | } 665 | } 666 | 667 | func (context *BGPContext) AdvertiseAllRoutesV4(cmndChan chan BGPCommand) { 668 | for _, route := range context.RIBv4 { 669 | /* 670 | TODO: pack more that one route per update; implement check, that msg size is less then 671 | bpg_max_msg_len 672 | */ 673 | cmndChan <- BGPCommand{ 674 | Cmnd: "AdvertiseRouteV4", 675 | Route: context.GenerateUpdateRouteV4(route)} 676 | } 677 | } 678 | 679 | func (context *BGPContext) AdvertiseAllRoutesV6(cmndChan chan BGPCommand) { 680 | for _, route := range context.RIBv6 { 681 | /* 682 | TODO: pack more that one route per update; implement check, that msg size is less then 683 | bpg_max_msg_len 684 | */ 685 | cmndChan <- BGPCommand{ 686 | Cmnd: "AdvertiseRouteV6", 687 | Route: context.GenerateUpdateRouteV6(route)} 688 | } 689 | } 690 | 691 | func (context *BGPNeighbourContext) GetRouterID(fromConnect chan string) { 692 | //TODO: error handling 693 | ladr := <-fromConnect 694 | if ladr == "exit" { 695 | return 696 | } 697 | if v4, _ := regexp.MatchString(`^(\d{1,3}\.){3}\d{1,3}$`, ladr); v4 { 698 | context.NextHop = ladr 699 | context.ToMainContext <- BGPCommand{Cmnd: "NewRouterID", CmndData: ladr} 700 | } else { 701 | context.NextHopV6, _ = IPv6StringToAddr(ladr) 702 | } 703 | } 704 | 705 | func (context *BGPNeighbourContext) AddCapabilityFlag(mpCap MPCapability) { 706 | if isMPCapabilityEqual(mpCap, mpCapInet) { 707 | context.speaksInet = true 708 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, Cmnd: "speaksInet"} 709 | } else if isMPCapabilityEqual(mpCap, mpCapInet6) { 710 | context.speaksInet6 = true 711 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, Cmnd: "speaksInet6"} 712 | } 713 | } 714 | 715 | func (context *BGPNeighbourContext) removeAllCapabilityFlags() { 716 | context.speaksInet = false 717 | context.speaksInet6 = false 718 | } 719 | 720 | func (context *BGPNeighbourContext) parseValidOpen(openMsg OpenMsg) { 721 | if openMsg.Caps.SupportASN4 { 722 | context.asn4 = true 723 | } else { 724 | context.asn4 = false 725 | } 726 | if len(context.MPCaps) == 0 { 727 | /* 728 | if we dont support any mp caps we can talk at least inet4 729 | however, in theory, you can speak v4 "in old way", and any other family as mp; 730 | right now we dont support it. if we have atleast one mp family, v4 MUST be advertised 731 | as mp_reach/unreach as well. TODO: mb, depends on actual use casses, gona change it 732 | */ 733 | context.speaksInet = true 734 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, Cmnd: "speaksInet"} 735 | return 736 | } 737 | for _, mpCap := range openMsg.MPCaps { 738 | if capInList(mpCap, context.MPCaps) { 739 | context.AddCapabilityFlag(mpCap) 740 | } 741 | } 742 | } 743 | 744 | func StartBGPNeighbourContext(context *BGPNeighbourContext, passive bool, 745 | sockChans SockControlChans) { 746 | context.fsm.State = "Idle" 747 | //TODO: add/change caps depends @ info in open msg 748 | bgpCaps := BGPCapabilities{ASN4: context.ASN} 749 | shutdown := false 750 | var localSockChans SockControlChans 751 | if !passive { 752 | localSockChans.fromWriteError = make(chan uint8) 753 | localSockChans.toWriteError = make(chan uint8) 754 | localSockChans.readError = make(chan uint8) 755 | localSockChans.toReadError = make(chan uint8) 756 | localSockChans.readChan = make(chan []byte) 757 | localSockChans.writeChan = make(chan []byte) 758 | localSockChans.controlChan = make(chan string) 759 | } else { 760 | localSockChans.fromWriteError = sockChans.fromWriteError 761 | localSockChans.toWriteError = sockChans.toWriteError 762 | localSockChans.readError = sockChans.readError 763 | localSockChans.toReadError = sockChans.toReadError 764 | localSockChans.readChan = sockChans.readChan 765 | localSockChans.writeChan = sockChans.writeChan 766 | localSockChans.controlChan = sockChans.controlChan 767 | if v4, _ := regexp.MatchString(`^(\d{1,3}\.){3}\d{1,3}$`, 768 | sockChans.localAddr); v4 { 769 | context.NextHop = sockChans.localAddr 770 | } else { 771 | context.NextHopV6, _ = IPv6StringToAddr(sockChans.localAddr) 772 | } 773 | } 774 | keepaliveFeedback := make(chan uint8) 775 | localSockChans.keepaliveFeedback = keepaliveFeedback 776 | msgBuf := make([]byte, 0) 777 | context.fsm.Event("Start") 778 | context.fsm.KeepaliveTime = 30 779 | context.fsm.DelayOpenTime = 5 780 | RECONNECT: 781 | context.removeAllCapabilityFlags() 782 | if !passive { 783 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 784 | Cmnd: "ActiveStartConnection", 785 | ResponseChan: localSockChans.controlChan} 786 | /* 787 | we cant rcv resp from ToNeighbourContext chan, in case, when passiveConnection in established state 788 | (it rewrites ToNeighbourContext chan in bgpneighbour struct) 789 | */ 790 | response := <-localSockChans.controlChan 791 | if response == "teardown" { 792 | return 793 | } 794 | go context.GetRouterID(localSockChans.controlChan) 795 | err := ConnectToNeighbour(context.NeighbourAddr, 796 | localSockChans.fromWriteError, 797 | localSockChans.toWriteError, 798 | localSockChans.readError, 799 | localSockChans.toReadError, 800 | localSockChans.readChan, 801 | localSockChans.writeChan, 802 | localSockChans.controlChan) 803 | if err != nil { 804 | if err == CANT_CONNECT_ERROR { 805 | localSockChans.controlChan <- "exit" 806 | context.fsm.ConnectRetryCounter++ 807 | //TODO: fsm.ConnectionRetryTime 808 | time.Sleep(10 * time.Second) 809 | goto RECONNECT 810 | } else { 811 | /* 812 | TODO: that means we wasnt able to parse neighbours address. 813 | we need to inform about it main context and delete this neigbour from the list 814 | */ 815 | return 816 | } 817 | } 818 | } 819 | 820 | loop := 1 821 | if context.RouterID == 0 { 822 | for loop == 1 { 823 | if !passive { 824 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 825 | Cmnd: "GetRouterID"} 826 | } else { 827 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 828 | Cmnd: "GetRouterIDPassive"} 829 | 830 | } 831 | resp := <-context.ToNeighbourContext 832 | 833 | switch resp.Cmnd { 834 | case "RouterID": 835 | if resp.CmndData != "0" { 836 | loop = 0 837 | id, _ := strconv.ParseUint(resp.CmndData, 10, 32) 838 | context.RouterID = uint32(id) 839 | } else { 840 | time.Sleep(1 * time.Second) 841 | } 842 | } 843 | } 844 | } 845 | if !passive { 846 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, Cmnd: "ActiveConnected"} 847 | GenerateOpenMsg(context, localSockChans.writeChan, "OpenSent") 848 | } 849 | loop = 1 850 | for loop == 1 { 851 | select { 852 | case msgFromMainContext := <-context.ToNeighbourContext: 853 | if msgFromMainContext.Cmnd == "Shutdown" { 854 | shutdown = true 855 | //FIXME: send notification if established 856 | goto CLOSE_CONNECTION 857 | } 858 | if context.fsm.State == "Established" { 859 | /* 860 | it's more practical from implementation point of view 861 | not to mix advertise and withdraw routes 862 | into the same update 863 | */ 864 | if msgFromMainContext.Cmnd == "AdvertiseRouteV4" { 865 | route := msgFromMainContext.Route 866 | err := route.AddV4NextHop(context.NextHop) 867 | if err != nil { 868 | continue 869 | } 870 | data, err := EncodeUpdateMsg(&route) 871 | if err != nil { 872 | continue 873 | } 874 | 875 | localSockChans.writeChan <- data 876 | } else if msgFromMainContext.Cmnd == "AdvertiseRouteV6" { 877 | route := msgFromMainContext.Route 878 | route.NEXT_HOPv6 = context.NextHopV6 879 | data, err := EncodeUpdateMsg(&route) 880 | if err != nil { 881 | continue 882 | } 883 | 884 | localSockChans.writeChan <- data 885 | } else if msgFromMainContext.Cmnd == "WithdrawRouteV4" || 886 | msgFromMainContext.Cmnd == "WithdrawRouteV6" { 887 | route := msgFromMainContext.Route 888 | data, err := EncodeUpdateMsg(&route) 889 | if err != nil { 890 | continue 891 | } 892 | 893 | localSockChans.writeChan <- data 894 | } 895 | 896 | } 897 | case bgpMsg := <-localSockChans.readChan: 898 | msgBuf = append(msgBuf, bgpMsg...) 899 | for { 900 | if len(msgBuf) < MSG_HDR_SIZE { 901 | break 902 | } 903 | hdr, err := DecodeMsgHeader(msgBuf) 904 | if err != nil { 905 | SendNotification(context, "MsgHeaderError", localSockChans, 906 | BGP_MSG_HEADER_ERROR, BGP_MH_ERROR_BADTYPE) 907 | msgBuf = msgBuf[:0] 908 | //TODO: here and bellow: lots of copy-paste. find a better way to deal with 909 | if passive { 910 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 911 | Cmnd: "PassiveClossed"} 912 | goto PASSIVE_TEARDOWN 913 | } else { 914 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 915 | Cmnd: "ActiveClossed"} 916 | goto RECONNECT 917 | } 918 | } 919 | if len(msgBuf) < int(hdr.Length) { 920 | break 921 | } 922 | 923 | switch hdr.Type { 924 | case BGP_OPEN_MSG: 925 | openMsg, err := DecodeOpenMsg(msgBuf[MSG_HDR_SIZE:hdr.Length]) 926 | if err != nil { 927 | //TODO: proper error subcodes; here and below 928 | SendNotification(context, "OpenError", localSockChans, 929 | BGP_OPEN_MSG_ERROR, BGP_GENERIC_ERROR) 930 | msgBuf = msgBuf[:0] 931 | if passive { 932 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 933 | Cmnd: "PassiveClossed"} 934 | goto PASSIVE_TEARDOWN 935 | 936 | } else { 937 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 938 | Cmnd: "ActiveClossed"} 939 | goto RECONNECT 940 | } 941 | } 942 | state := context.fsm.Event("OpenRcv") 943 | chckResult := PerformCollisionCheck(context, passive, &openMsg) 944 | if chckResult == "teardown" { 945 | SendNotification(context, "Collision", localSockChans, 946 | BGP_CASE_ERROR, BGP_CASE_ERROR_COLLISION) 947 | msgBuf = msgBuf[:0] 948 | if passive { 949 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 950 | Cmnd: "PassiveClossed"} 951 | } else { 952 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 953 | Cmnd: "ActiveClossed"} 954 | } 955 | return 956 | } 957 | context.parseValidOpen(openMsg) 958 | bgpCaps.SupportASN4 = context.asn4 959 | switch state { 960 | case "OpenKA": 961 | context.fsm.KeepaliveTime = uint32(openMsg.Hdr.HoldTime / 3) 962 | context.fsm.HoldTime = uint32(openMsg.Hdr.HoldTime) 963 | err := GenerateOpenMsg(context, localSockChans.writeChan, "") 964 | if err != nil { 965 | SendNotification(context, "OpenSendError", localSockChans, 966 | BGP_OPEN_MSG_ERROR, BGP_GENERIC_ERROR) 967 | msgBuf = msgBuf[:0] 968 | if passive { 969 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 970 | Cmnd: "PassiveClossed"} 971 | goto PASSIVE_TEARDOWN 972 | 973 | } else { 974 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 975 | Cmnd: "ActiveClossed"} 976 | goto RECONNECT 977 | } 978 | } 979 | encodedKA := GenerateKeepalive() 980 | localSockChans.writeChan <- encodedKA 981 | case "Keepalive": 982 | encodedKA := GenerateKeepalive() 983 | localSockChans.writeChan <- encodedKA 984 | default: 985 | SendNotification(context, "OpenError", localSockChans, 986 | BGP_FSM_ERROR, BGP_GENERIC_ERROR) 987 | msgBuf = msgBuf[:0] 988 | if passive { 989 | context.ToMainContext <- BGPCommand{ 990 | From: context.NeighbourAddr, 991 | Cmnd: "PassiveClossed"} 992 | goto PASSIVE_TEARDOWN 993 | 994 | } else { 995 | context.ToMainContext <- BGPCommand{ 996 | From: context.NeighbourAddr, 997 | Cmnd: "ActiveClossed"} 998 | goto RECONNECT 999 | } 1000 | } 1001 | case BGP_UPDATE_MSG: 1002 | /* right now we dont care about rcved msg */ 1003 | _, err := DecodeUpdateMsg(msgBuf[:hdr.Length], &bgpCaps) 1004 | if err != nil { 1005 | switch err.(type) { 1006 | case EndOfRib: 1007 | default: 1008 | SendNotification(context, "UpdateError", 1009 | localSockChans, 1010 | BGP_UPDATE_MSG_ERROR, BGP_GENERIC_ERROR) 1011 | msgBuf = msgBuf[:0] 1012 | if passive { 1013 | context.ToMainContext <- BGPCommand{ 1014 | From: context.NeighbourAddr, 1015 | Cmnd: "PassiveClossed"} 1016 | goto PASSIVE_TEARDOWN 1017 | } else { 1018 | context.ToMainContext <- BGPCommand{ 1019 | From: context.NeighbourAddr, 1020 | Cmnd: "ActiveClossed"} 1021 | goto RECONNECT 1022 | } 1023 | } 1024 | } 1025 | state := context.fsm.Event("Update") 1026 | if state != "Established" { 1027 | SendNotification(context, "UpdateError", localSockChans, 1028 | BGP_FSM_ERROR, BGP_GENERIC_ERROR) 1029 | msgBuf = msgBuf[:0] 1030 | if passive { 1031 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1032 | Cmnd: "PassiveClossed"} 1033 | goto PASSIVE_TEARDOWN 1034 | } else { 1035 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1036 | Cmnd: "ActiveClossed"} 1037 | goto RECONNECT 1038 | } 1039 | } 1040 | case BGP_NOTIFICATION_MSG: 1041 | goto CLOSE_CONNECTION 1042 | case BGP_KEEPALIVE_MSG: 1043 | state := context.fsm.Event("Keepalive") 1044 | if state == "Established" { 1045 | if passive { 1046 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1047 | Cmnd: "PassiveEstablished"} 1048 | } else { 1049 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1050 | Cmnd: "Established"} 1051 | } 1052 | go SendKeepalive(localSockChans.writeChan, 1053 | context.fsm.KeepaliveTime, 1054 | keepaliveFeedback) 1055 | } 1056 | } 1057 | msgBuf = msgBuf[hdr.Length:] 1058 | } 1059 | case <-localSockChans.readError: 1060 | goto CLOSE_CONNECTION 1061 | case <-localSockChans.toWriteError: 1062 | goto CLOSE_CONNECTION 1063 | } 1064 | } 1065 | 1066 | CLOSE_CONNECTION: 1067 | CloseSockets(context, localSockChans) 1068 | if context.fsm.State == "Established" { 1069 | keepaliveFeedback <- uint8(1) 1070 | } 1071 | msgBuf = msgBuf[:0] 1072 | context.fsm.Event("Start") 1073 | if shutdown { 1074 | return 1075 | } 1076 | if passive { 1077 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1078 | Cmnd: "PassiveClossed"} 1079 | goto PASSIVE_TEARDOWN 1080 | } else { 1081 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1082 | Cmnd: "ActiveClossed"} 1083 | //TODO: fix hardcode 1084 | time.Sleep(10 * time.Second) 1085 | goto RECONNECT 1086 | } 1087 | 1088 | PASSIVE_TEARDOWN: 1089 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1090 | Cmnd: "PassiveTeardown"} 1091 | return 1092 | 1093 | } 1094 | 1095 | func SendKeepalive(writeChan chan []byte, sleepTime uint32, feedbackChan chan uint8) { 1096 | loop := 1 1097 | ka := GenerateKeepalive() 1098 | for loop == 1 { 1099 | select { 1100 | case <-time.After(time.Duration(sleepTime) * time.Second): 1101 | case <-feedbackChan: 1102 | loop = 0 1103 | continue 1104 | } 1105 | select { 1106 | case writeChan <- ka: 1107 | continue 1108 | case <-feedbackChan: 1109 | loop = 0 1110 | continue 1111 | } 1112 | } 1113 | } 1114 | 1115 | func GenerateOpenMsg(context *BGPNeighbourContext, writeChan chan []byte, 1116 | event string) error { 1117 | //TODO: check if context.ASN > 2^16; then MyASN must be AS_TRANS 1118 | openMsg := OpenMsg{Hdr: OpenMsgHdr{Version: uint8(4), MyASN: uint16(context.ASN), 1119 | BGPID: context.RouterID, HoldTime: uint16(context.fsm.HoldTime)}} 1120 | openMsg.MPCaps = append(openMsg.MPCaps, context.MPCaps...) 1121 | openMsg.Caps.SupportASN4 = true 1122 | openMsg.Caps.ASN4 = context.ASN 1123 | encodedOpen, err := EncodeOpenMsg(&openMsg) 1124 | if err != nil { 1125 | return err 1126 | } 1127 | writeChan <- encodedOpen 1128 | if event != "" { 1129 | context.fsm.Event(event) 1130 | } 1131 | return nil 1132 | } 1133 | 1134 | func SendNotification(context *BGPNeighbourContext, event string, 1135 | sockChans SockControlChans, eCode, eSubcode uint8) { 1136 | notificationMsg := NotificationMsg{ 1137 | ErrorCode: eCode, 1138 | ErrorSubcode: eSubcode} 1139 | encodedNotification, err := EncodeNotificationMsg(¬ificationMsg) 1140 | if err != nil { 1141 | return 1142 | } 1143 | sockChans.writeChan <- encodedNotification 1144 | sockChans.toWriteError <- 0 1145 | sockChans.toReadError <- 1 1146 | if context.fsm.State == "Established" { 1147 | sockChans.keepaliveFeedback <- uint8(1) 1148 | /* 1149 | HACK. trying to protect ourself from deadlock, when main context trying to send something 1150 | for us.TODO: to think mb there is a better solution for that 1151 | */ 1152 | LOOP: 1153 | for { 1154 | select { 1155 | case <-context.ToNeighbourContext: 1156 | default: 1157 | break LOOP 1158 | } 1159 | } 1160 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1161 | Cmnd: "Down"} 1162 | 1163 | } 1164 | context.fsm.Event("Start") 1165 | } 1166 | 1167 | func CloseSockets(context *BGPNeighbourContext, sockChans SockControlChans) { 1168 | sockChans.toWriteError <- 0 1169 | //TODO: poc this; proper sync 1170 | sockChans.toReadError <- 1 1171 | if context.fsm.State == "Established" { 1172 | LOOP: 1173 | for { 1174 | select { 1175 | case <-context.ToNeighbourContext: 1176 | default: 1177 | break LOOP 1178 | } 1179 | } 1180 | context.ToMainContext <- BGPCommand{From: context.NeighbourAddr, 1181 | Cmnd: "Down"} 1182 | 1183 | } 1184 | 1185 | } 1186 | 1187 | func PerformCollisionCheck(context *BGPNeighbourContext, passive bool, openMsg *OpenMsg) string { 1188 | bgpCmnd := BGPCommand{From: context.NeighbourAddr, Cmnd: "CollisionCheck"} 1189 | if passive { 1190 | bgpCmnd.Cmnd = "PassiveCollisionCheck" 1191 | } 1192 | context.ToMainContext <- bgpCmnd 1193 | response := <-context.ToNeighbourContext 1194 | if response.Cmnd == "NoCollision" { 1195 | return response.Cmnd 1196 | } 1197 | if context.RouterID < openMsg.Hdr.BGPID { 1198 | if !passive { 1199 | return "teardown" 1200 | } else { 1201 | bgpCmnd.Cmnd = "PassiveWonCollisionDetection" 1202 | context.ToMainContext <- bgpCmnd 1203 | return "CollisionResolved" 1204 | } 1205 | } else { 1206 | if !passive { 1207 | return "CollisionResolved" 1208 | } else { 1209 | return "teardown" 1210 | } 1211 | } 1212 | } 1213 | --------------------------------------------------------------------------------