//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 (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 }