func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) { notAllBytesAvail := fmt.Errorf("not all RibEntry bytes are available") if len(data) < 8 { return nil, notAllBytesAvail } e.PeerIndex = binary.BigEndian.Uint16(data[:2]) e.OriginatedTime = binary.BigEndian.Uint32(data[2:6]) totalLen := binary.BigEndian.Uint16(data[6:8]) data = data[8:] for attrLen := totalLen; attrLen > 0; { p, err := bgp.GetPathAttribute(data) if err != nil { return nil, err } err = p.DecodeFromBytes(data) if err != nil { return nil, err } attrLen -= uint16(p.Len()) if len(data) < p.Len() { return nil, notAllBytesAvail } data = data[p.Len():] e.PathAttributes = append(e.PathAttributes, p) } return data, nil }
func ApiStruct2Path(p *gobgpapi.Path) ([]*Path, error) { nlris := make([]bgp.AddrPrefixInterface, 0, 1) data := p.Nlri if p.Family == uint32(bgp.RF_IPv4_UC) && len(data) > 0 { nlri := &bgp.IPAddrPrefix{} err := nlri.DecodeFromBytes(data) if err != nil { return nil, err } nlris = append(nlris, nlri) } pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) for _, attr := range p.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } switch p.GetType() { case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: mpreach := p.(*bgp.PathAttributeMpReachNLRI) for _, nlri := range mpreach.Value { nlris = append(nlris, nlri) } } pattr = append(pattr, p) } paths := make([]*Path, 0, len(nlris)) for _, nlri := range nlris { paths = append(paths, &Path{ Nlri: nlri, PathAttrs: pattr, Age: p.Age, Best: p.Best, IsWithdraw: p.IsWithdraw, Validation: p.Validation, SourceId: p.SourceId, NeighborIp: p.NeighborIp, Filtered: p.Filtered, Stale: p.Stale, }) } return paths, nil }
func ApiStruct2Path(p *gobgpapi.Path) ([]*Path, error) { nlris := make([]bgp.AddrPrefixInterface, 0, 1) if len(p.Nlri) == 0 { return nil, fmt.Errorf("path doesn't have nlri") } afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(p.Family)) nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi) if err != nil { return nil, err } if err := nlri.DecodeFromBytes(p.Nlri); err != nil { return nil, err } nlris = append(nlris, nlri) pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) for _, attr := range p.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } pattr = append(pattr, p) } paths := make([]*Path, 0, len(nlris)) for _, nlri := range nlris { paths = append(paths, &Path{ Nlri: nlri, PathAttrs: pattr, Age: p.Age, Best: p.Best, IsWithdraw: p.IsWithdraw, Validation: p.Validation, SourceId: p.SourceId, NeighborIp: p.NeighborIp, Filtered: p.Filtered, Stale: p.Stale, }) } return paths, nil }
//export decode_path func decode_path(p *C.path) *C.char { var buf []byte var nlri bgp.AddrPrefixInterface if p.nlri.len > 0 { buf = []byte(C.GoStringN(p.nlri.value, p.nlri.len)) nlri = &bgp.IPAddrPrefix{} err := nlri.DecodeFromBytes(buf) if err != nil { return nil } } pattrs := make([]bgp.PathAttributeInterface, 0, int(p.path_attributes_len)) for i := 0; i < int(p.path_attributes_len); i++ { b := C.get_path_attribute(p, C.int(i)) buf = []byte(C.GoStringN(b.value, b.len)) pattr, err := bgp.GetPathAttribute(buf) if err != nil { return nil } err = pattr.DecodeFromBytes(buf) if err != nil { return nil } switch pattr.GetType() { case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: mpreach := pattr.(*bgp.PathAttributeMpReachNLRI) if len(mpreach.Value) != 1 { return nil } nlri = mpreach.Value[0] } pattrs = append(pattrs, pattr) } j, _ := json.Marshal(struct { Nlri bgp.AddrPrefixInterface `json:"nlri"` PathAttrs []bgp.PathAttributeInterface `json:"attrs"` }{ Nlri: nlri, PathAttrs: pattrs, }) return C.CString(string(j)) }
func (p *Path) ToNativePath(option ...ToNativeOption) (*table.Path, error) { info := &table.PeerInfo{ AS: p.SourceAsn, ID: net.ParseIP(p.SourceId), Address: net.ParseIP(p.NeighborIp), } var nlri bgp.AddrPrefixInterface for _, o := range option { info.LocalAS = o.LocalAS info.LocalID = o.LocalID info.RouteReflectorClient = o.RouteReflectorClient info.RouteReflectorClusterID = o.RouteReflectorClusterID nlri = o.NLRI } if nlri == nil { var err error nlri, err = getNLRI(bgp.RouteFamily(p.Family), p.Nlri) if err != nil { return nil, err } } pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs)) for _, attr := range p.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } pattr = append(pattr, p) } t := time.Unix(p.Age, 0) path := table.NewPath(info, nlri, p.IsWithdraw, pattr, t, false) path.SetValidation(config.IntToRpkiValidationResultTypeMap[int(p.Validation)]) path.MarkStale(p.Stale) if p.Filtered { path.Filter("", table.POLICY_DIRECTION_IN) } return path, nil }
func (s *Server) api2PathList(resource Resource, ApiPathList []*Path) ([]*table.Path, error) { var nlri bgp.AddrPrefixInterface var nexthop string var pi *table.PeerInfo pathList := make([]*table.Path, 0, len(ApiPathList)) for _, path := range ApiPathList { seen := make(map[bgp.BGPAttrType]bool) pattr := make([]bgp.PathAttributeInterface, 0) extcomms := make([]bgp.ExtendedCommunityInterface, 0) if path.SourceAsn != 0 { pi = &table.PeerInfo{ AS: path.SourceAsn, LocalID: net.ParseIP(path.SourceId), } } if len(path.Nlri) > 0 { nlri = &bgp.IPAddrPrefix{} err := nlri.DecodeFromBytes(path.Nlri) if err != nil { return nil, err } } for _, attr := range path.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return nil, err } err = p.DecodeFromBytes(attr) if err != nil { return nil, err } if _, ok := seen[p.GetType()]; !ok { seen[p.GetType()] = true } else { return nil, fmt.Errorf("the path attribute apears twice. Type : " + strconv.Itoa(int(p.GetType()))) } switch p.GetType() { case bgp.BGP_ATTR_TYPE_NEXT_HOP: nexthop = p.(*bgp.PathAttributeNextHop).Value.String() case bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: value := p.(*bgp.PathAttributeExtendedCommunities).Value if len(value) > 0 { extcomms = append(extcomms, value...) } case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: mpreach := p.(*bgp.PathAttributeMpReachNLRI) if len(mpreach.Value) != 1 { return nil, fmt.Errorf("include only one route in mp_reach_nlri") } nlri = mpreach.Value[0] nexthop = mpreach.Nexthop.String() default: pattr = append(pattr, p) } } if nlri == nil || nexthop == "" { return nil, fmt.Errorf("not found nlri or nexthop") } rf := bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) if resource != Resource_VRF && rf == bgp.RF_IPv4_UC { pattr = append(pattr, bgp.NewPathAttributeNextHop(nexthop)) } else { pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) } if len(extcomms) > 0 { pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities(extcomms)) } newPath := table.NewPath(pi, nlri, path.IsWithdraw, pattr, time.Now(), path.NoImplicitWithdraw) newPath.SetIsFromExternal(path.IsFromExternal) pathList = append(pathList, newPath) } return pathList, nil }
//modrib receives route updates from BGP server and adds the endpoint func (self *OfnetBgp) modRib(path *api.Path) error { var nlri bgp.AddrPrefixInterface var nextHop string var macAddrStr string var portNo uint32 if len(path.Nlri) > 0 { nlri = &bgp.IPAddrPrefix{} err := nlri.DecodeFromBytes(path.Nlri) if err != nil { return err } } for _, attr := range path.Pattrs { p, err := bgp.GetPathAttribute(attr) if err != nil { return err } err = p.DecodeFromBytes(attr) if err != nil { return err } if p.GetType() == bgp.BGP_ATTR_TYPE_NEXT_HOP { nextHop = p.(*bgp.PathAttributeNextHop).Value.String() break } } if nextHop == "0.0.0.0" { return nil } if nlri == nil { return fmt.Errorf("no nlri") } endpointIPNet, _ := netlink.ParseIPNet(nlri.String()) log.Infof("Bgp Rib Received endpoint update for %v , with nexthop %v", endpointIPNet, nextHop) if endpointIPNet == nil { return nil } //check if bgp published a route local to the host epid := self.agent.getEndpointIdByIpVrf(endpointIPNet.IP.Mask(endpointIPNet.Mask), "default") //Check if the route is local if nextHop == self.routerIP { log.Info("This is a local route skipping endpoint create! ") return nil } else if self.agent.endpointDb[epid] != nil { if self.agent.endpointDb[epid].EndpointType != "external" { log.Info("Endpoint was learnt via internal protocol. skipping update! ") return nil } } nhEpid := self.agent.getEndpointIdByIpVrf(net.ParseIP(nextHop), "default") if self.agent.endpointDb[nhEpid] == nil { //the nexthop is not the directly connected eBgp peer macAddrStr = "" portNo = 0 } else { macAddrStr = self.agent.endpointDb[nhEpid].MacAddrStr portNo = self.agent.endpointDb[nhEpid].PortNo } ipmask := net.ParseIP("255.255.255.255").Mask(endpointIPNet.Mask) if path.IsWithdraw != true { epreg := &OfnetEndpoint{ EndpointID: epid, EndpointType: "external", IpAddr: endpointIPNet.IP, IpMask: ipmask, Vrf: "default", // FIXME set VRF correctly MacAddrStr: macAddrStr, Vlan: 1, OriginatorIp: self.agent.localIp, PortNo: portNo, Timestamp: time.Now(), } // Install the endpoint in datapath // First, add the endpoint to local routing table self.agent.endpointDb[epreg.EndpointID] = epreg err := self.agent.datapath.AddEndpoint(epreg) if err != nil { log.Errorf("Error adding endpoint: {%+v}. Err: %v", epreg, err) return err } } else { log.Info("Received route withdraw from BGP for ", endpointIPNet) endpoint := self.agent.getEndpointByIpVrf(endpointIPNet.IP, "default") if endpoint != nil { self.agent.datapath.RemoveEndpoint(endpoint) delete(self.agent.endpointDb, endpoint.EndpointID) } } return nil }