func (m *OpsManager) handleBgpRouterUpdate(update ovsdb.TableUpdate) []*server.GrpcRequest { asn, id, err := m.getBGPRouterUUID() if err != nil { log.Debugf("%s", err) return nil } reqs := []*server.GrpcRequest{} for k, v := range update.Rows { if uuid.Equal(id, uuid.FromStringOrNil(k)) { initial := false if len(v.Old.Fields) == 0 { log.WithFields(log.Fields{ "Topic": "openswitch", }).Debug("new bgp router") initial = true } if _, ok := v.Old.Fields["router_id"]; initial || ok { r, ok := v.New.Fields["router_id"].(string) if !ok { log.WithFields(log.Fields{ "Topic": "openswitch", }).Debug("router-id is not configured yet") return nil } reqs = append(reqs, server.NewGrpcRequest(server.REQ_START_SERVER, "", bgp.RouteFamily(0), &api.StartServerRequest{ Global: &api.Global{ As: asn, RouterId: r, }, })) } if o, ok := v.Old.Fields["bgp_neighbors"]; ok { oldNeighMap := o.(ovsdb.OvsMap).GoMap newNeighMap := v.New.Fields["bgp_neighbors"].(ovsdb.OvsMap).GoMap for k, _ := range oldNeighMap { if _, ok := newNeighMap[k]; !ok { reqs = append(reqs, server.NewGrpcRequest(server.REQ_GRPC_DELETE_NEIGHBOR, "", bgp.RouteFamily(0), &api.DeleteNeighborRequest{ Peer: &api.Peer{ Conf: &api.PeerConf{ NeighborAddress: k.(string), }, }, })) } } } } } return reqs }
func (s *Server) InjectMrt(stream api.GobgpApi_InjectMrtServer) error { for { arg, err := stream.Recv() if err == io.EOF { break } else if err != nil { return err } if arg.Resource != api.Resource_GLOBAL && arg.Resource != api.Resource_VRF { return fmt.Errorf("unsupported resource: %s", arg.Resource) } req := NewGrpcRequest(REQ_INJECT_MRT, "", bgp.RouteFamily(0), arg) s.bgpServerCh <- req res := <-req.ResponseCh if err := res.Err(); err != nil { log.Debug(err.Error()) return err } } return stream.SendAndClose(&api.InjectMrtResponse{}) }
func (m *OpsManager) handleNeighborUpdate(update ovsdb.TableUpdate) []*server.GrpcRequest { _, id, _ := m.getBGPRouterUUID() addrs, ids, err := m.getBGPNeighborUUIDs(id) if err != nil { return nil } reqs := make([]*server.GrpcRequest, 0, len(addrs)) for k, v := range update.Rows { for idx, id := range ids { if uuid.Equal(id, uuid.FromStringOrNil(k)) { asn, ok := v.New.Fields["remote_as"].(float64) if !ok { log.WithFields(log.Fields{ "Topic": "openswitch", }).Debug("remote-as is not configured yet") continue } reqs = append(reqs, server.NewGrpcRequest(server.REQ_GRPC_ADD_NEIGHBOR, "", bgp.RouteFamily(0), &api.AddNeighborRequest{ Peer: &api.Peer{ Conf: &api.PeerConf{ NeighborAddress: addrs[idx].String(), PeerAs: uint32(asn), }, }, })) } } } return reqs }
func (s *Server) StartServer(ctx context.Context, arg *StartServerRequest) (*StartServerResponse, error) { g := arg.Global if net.ParseIP(g.RouterId) == nil { return nil, fmt.Errorf("invalid router-id format: %s", g.RouterId) } families := make([]config.AfiSafi, 0, len(g.Families)) for _, f := range g.Families { name := config.AfiSafiType(bgp.RouteFamily(f).String()) families = append(families, config.AfiSafi{ Config: config.AfiSafiConfig{ AfiSafiName: name, Enabled: true, }, State: config.AfiSafiState{ AfiSafiName: name, }, }) } b := &config.BgpConfigSet{ Global: config.Global{ Config: config.GlobalConfig{ As: g.As, RouterId: g.RouterId, Port: g.ListenPort, LocalAddressList: g.ListenAddresses, }, MplsLabelRange: config.MplsLabelRange{ MinLabel: g.MplsLabelMin, MaxLabel: g.MplsLabelMax, }, AfiSafis: families, }, } return &StartServerResponse{}, s.bgpServer.Start(&b.Global) }
func showRPKITable(args []string) error { family, err := checkAddressFamily(bgp.RouteFamily(0)) if err != nil { exitWithError(err) } arg := &api.GetRoaRequest{ Family: uint32(family), } rsp, err := client.GetRoa(context.Background(), arg) if err != nil { fmt.Println(err) return err } var format string afi, _ := bgp.RouteFamilyToAfiSafi(family) if afi == bgp.AFI_IP { format = "%-18s %-6s %-10s %s\n" } else { format = "%-42s %-6s %-10s %s\n" } fmt.Printf(format, "Network", "Maxlen", "AS", "Server") for _, r := range rsp.Roas { if len(args) > 0 && args[0] != r.Conf.Address { continue } server := net.JoinHostPort(r.Conf.Address, r.Conf.RemotePort) fmt.Printf(format, fmt.Sprintf("%s/%d", r.Prefix, r.Prefixlen), fmt.Sprint(r.Maxlen), fmt.Sprint(r.As), server) } return nil }
func showRPKITable(args []string) error { family, err := checkAddressFamily(bgp.RouteFamily(0)) if err != nil { exitWithError(err) } roas, err := client.GetROA(family) if err != nil { exitWithError(err) } var format string afi, _ := bgp.RouteFamilyToAfiSafi(family) if afi == bgp.AFI_IP { format = "%-18s %-6s %-10s %s\n" } else { format = "%-42s %-6s %-10s %s\n" } fmt.Printf(format, "Network", "Maxlen", "AS", "Server") for _, r := range roas { host, _, _ := net.SplitHostPort(r.Src) if len(args) > 0 && args[0] != host { continue } fmt.Printf(format, r.Prefix.String(), fmt.Sprint(r.MaxLen), fmt.Sprint(r.AS), r.Src) } return nil }
func addr2AddressFamily(a net.IP) bgp.RouteFamily { if a.To4() != nil { return bgp.RF_IPv4_UC } else if a.To16() != nil { return bgp.RF_IPv6_UC } return bgp.RouteFamily(0) }
func (s *Server) GetVrf(ctx context.Context, arg *api.GetVrfRequest) (*api.GetVrfResponse, error) { req := NewGrpcRequest(REQ_GET_VRF, "", bgp.RouteFamily(0), nil) s.bgpServerCh <- req res := <-req.ResponseCh if res.Err() != nil { return nil, res.Err() } return res.Data.(*api.GetVrfResponse), res.Err() }
func (t *Table) ToNativeTable(option ...ToNativeOption) (*table.Table, error) { dsts := make([]*table.Destination, 0, len(t.Destinations)) for _, d := range t.Destinations { dst, err := d.ToNativeDestination(option...) if err != nil { return nil, err } dsts = append(dsts, dst) } return table.NewTable(bgp.RouteFamily(t.Family), dsts...), nil }
func getNLRI(family bgp.RouteFamily, buf []byte) (bgp.AddrPrefixInterface, error) { afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(family)) nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi) if err != nil { return nil, err } if err := nlri.DecodeFromBytes(buf); err != nil { return nil, err } return nlri, nil }
func (s *Server) DeletePath(ctx context.Context, arg *DeletePathRequest) (*DeletePathResponse, error) { pathList, err := func() ([]*table.Path, error) { if arg.Path != nil { arg.Path.IsWithdraw = true return s.api2PathList(arg.Resource, []*Path{arg.Path}) } return []*table.Path{}, nil }() if err != nil { return nil, err } return &DeletePathResponse{}, s.bgpServer.DeletePath(arg.Uuid, bgp.RouteFamily(arg.Family), arg.VrfId, pathList) }
func (s *Server) MonitorRib(arg *api.Table, stream api.GobgpApi_MonitorRibServer) error { switch arg.Type { case api.Resource_ADJ_IN, api.Resource_GLOBAL: default: return fmt.Errorf("unsupported resource type: %v", arg.Type) } req := NewGrpcRequest(REQ_MONITOR_RIB, arg.Name, bgp.RouteFamily(arg.Family), arg) s.bgpServerCh <- req return handleMultipleResponses(req, func(res *GrpcResponse) error { return stream.Send(res.Data.(*api.Destination)) }) }
func resetNeighbor(cmd string, remoteIP string, args []string) error { family := bgp.RouteFamily(0) switch cmd { case CMD_RESET: return client.ResetNeighbor(remoteIP) case CMD_SOFT_RESET: return client.SoftReset(remoteIP, family) case CMD_SOFT_RESET_IN: return client.SoftResetIn(remoteIP, family) case CMD_SOFT_RESET_OUT: return client.SoftResetOut(remoteIP, family) } return nil }
func (m *OpsManager) handleRouteUpdate(update ovsdb.TableUpdate) []*server.GrpcRequest { id, _ := m.getVrfUUID() reqs := []*server.GrpcRequest{} for _, v := range update.Rows { vrf := v.New.Fields["vrf"] if vrf == nil { continue } idx := vrf.(ovsdb.UUID).GoUUID if uuid.Equal(id, uuid.FromStringOrNil(idx)) { path, isWithdraw, isFromGobgp, err := parseRouteToGobgp(v, m.cache["BGP_Nexthop"]) if err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", "Path": path, "Err": err, }).Debug("failed to parse path") return nil } if isWithdraw { reqs = append(reqs, server.NewGrpcRequest(server.REQ_DELETE_PATH, "", bgp.RouteFamily(0), &api.AddPathRequest{ Resource: api.Resource_GLOBAL, Path: path, })) } else { if isFromGobgp { return nil } reqs = append(reqs, server.NewGrpcRequest(server.REQ_ADD_PATH, "", bgp.RouteFamily(0), &api.AddPathRequest{ Resource: api.Resource_GLOBAL, Path: path, })) } } } return reqs }
func (m *OpsManager) handleVrfUpdate(update ovsdb.TableUpdate) *server.GrpcRequest { for _, v := range update.Rows { if len(v.Old.Fields) == 0 { log.WithFields(log.Fields{ "Topic": "openswitch", }).Debug("new vrf") } else if _, ok := v.Old.Fields["bgp_routers"]; ok { _, _, err := m.getBGPRouterUUID() if err != nil { return server.NewGrpcRequest(server.REQ_STOP_SERVER, "", bgp.RouteFamily(0), &api.StopServerRequest{}) } } } return nil }
//export serialize_path func serialize_path(rf C.int, input *C.char) *C.path { args := strings.Split(C.GoString(input), " ") p, err := cmd.ParsePath(bgp.RouteFamily(rf), args) if err != nil { return nil } path := C.new_path() if len(p.Nlri) > 0 { path.nlri.len = C.int(len(p.Nlri)) path.nlri.value = C.CString(string(p.Nlri)) } for _, attr := range p.Pattrs { C.append_path_attribute(path, C.int(len(attr)), C.CString(string(attr))) } return path }
func (s *Server) MonitorBestChanged(arg *api.Arguments, stream api.GobgpApi_MonitorBestChangedServer) error { var reqType int switch arg.Resource { case api.Resource_GLOBAL: reqType = REQ_MONITOR_GLOBAL_BEST_CHANGED default: return fmt.Errorf("unsupported resource type: %v", arg.Resource) } req := NewGrpcRequest(reqType, "", bgp.RouteFamily(arg.Family), nil) s.bgpServerCh <- req return handleMultipleResponses(req, func(res *GrpcResponse) error { return stream.Send(res.Data.(*api.Destination)) }) }
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 }
func (m *OpsManager) GobgpMonitor(ready *bool) { time.Sleep(time.Duration(time.Second * 2)) reqCh := m.grpcCh family := bgp.RF_IPv4_UC arg := &api.Arguments{ Resource: api.Resource_GLOBAL, Family: uint32(family), } for { if !*ready { return } req := server.NewGrpcRequest(server.REQ_MONITOR_GLOBAL_BEST_CHANGED, "", bgp.RouteFamily(0), arg) reqCh <- req res := <-req.ResponseCh if err := res.Err(); err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", "Type": "Monitor", "RequestType": req.RequestType, "Err": err, }).Error("grpc operation failed") } d := res.Data.(*api.Destination) bPath := d.Paths[0] if bPath.IsFromExternal && !bPath.IsWithdraw { continue } p, err := cmd.ApiStruct2Path(bPath) if err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", "Type": "MonitorRequest", "Err": err, }).Error("failed parse path of gobgp") } o, err := m.TransactPreparation(p) if err != nil { log.WithFields(log.Fields{ "Topic": "openswitch", "Type": "Monitor", "Err": err, }).Error("failed transact preparation of ops") } m.opsCh <- o } }
func (s *Server) SoftResetNeighbor(ctx context.Context, arg *SoftResetNeighborRequest) (*SoftResetNeighborResponse, error) { var err error addr := arg.Address if addr == "all" { addr = "" } family := bgp.RouteFamily(0) switch arg.Direction { case SoftResetNeighborRequest_IN: err = s.bgpServer.SoftResetIn(addr, family) case SoftResetNeighborRequest_OUT: err = s.bgpServer.SoftResetOut(addr, family) default: err = s.bgpServer.SoftReset(addr, family) } return &SoftResetNeighborResponse{}, err }
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) GetRoa(ctx context.Context, arg *GetRoaRequest) (*GetRoaResponse, error) { roas, err := s.bgpServer.GetRoa(bgp.RouteFamily(arg.Family)) if err != nil { return nil, err } l := make([]*Roa, 0, len(roas)) for _, r := range roas { host, port, _ := net.SplitHostPort(r.Src) l = append(l, &Roa{ As: r.AS, Maxlen: uint32(r.MaxLen), Prefixlen: uint32(r.Prefix.Length), Prefix: r.Prefix.Prefix.String(), Conf: &RPKIConf{ Address: host, RemotePort: port, }, }) } return &GetRoaResponse{Roas: l}, nil }
func (d *Destination) ToNativeDestination(option ...ToNativeOption) (*table.Destination, error) { if len(d.Paths) == 0 { return nil, fmt.Errorf("no path in destination") } nlri, err := getNLRI(bgp.RouteFamily(d.Paths[0].Family), d.Paths[0].Nlri) if err != nil { return nil, err } option = append(option, ToNativeOption{ NLRI: nlri, }) paths := make([]*table.Path, 0, len(d.Paths)) for _, p := range d.Paths { path, err := p.ToNativePath(option...) if err != nil { return nil, err } paths = append(paths, path) } return table.NewDestination(nlri, paths...), nil }
func (w *grpcIncomingWatcher) loop() error { for { select { case <-w.t.Dying(): for _, req := range w.reqs { close(req.ResponseCh) } return nil case req := <-w.ctlCh: w.reqs = append(w.reqs, req) case ev := <-w.ch: msg := ev.(*watcherEventUpdateMsg) for _, path := range msg.pathList { remains := make([]*GrpcRequest, 0, len(w.reqs)) result := &GrpcResponse{ Data: &api.Destination{ Prefix: path.GetNlri().String(), Paths: []*api.Path{path.ToApiStruct(table.GLOBAL_RIB_NAME)}, }, } for _, req := range w.reqs { select { case <-req.EndCh: continue default: } remains = append(remains, req) if req.RouteFamily != bgp.RouteFamily(0) && req.RouteFamily != path.GetRouteFamily() { continue } if req.Name != "" && req.Name != path.GetSource().Address.String() { continue } req.ResponseCh <- result } w.reqs = remains } } } }
func (s *Server) neighbor(reqType int, address string, d interface{}) (interface{}, error) { req := NewGrpcRequest(reqType, address, bgp.RouteFamily(0), d) s.bgpServerCh <- req res := <-req.ResponseCh return res.Data, res.Err() }
func (s *Server) get(typ int, d interface{}) (interface{}, error) { req := NewGrpcRequest(typ, "", bgp.RouteFamily(0), d) s.bgpServerCh <- req res := <-req.ResponseCh return res.Data, res.Err() }
func (w *grpcWatcher) loop() error { for { select { case <-w.t.Dying(): for _, rs := range w.reqs { for _, req := range rs { close(req.ResponseCh) } } return nil case req := <-w.ctlCh: var reqType watcherEventType switch req.RequestType { case REQ_MONITOR_RIB: tbl := req.Data.(*api.Table) switch tbl.Type { case api.Resource_GLOBAL: reqType = WATCHER_EVENT_BESTPATH_CHANGE case api.Resource_ADJ_IN: if tbl.PostPolicy { reqType = WATCHER_EVENT_POST_POLICY_UPDATE_MSG } else { reqType = WATCHER_EVENT_UPDATE_MSG } } case REQ_MONITOR_NEIGHBOR_PEER_STATE: reqType = WATCHER_EVENT_STATE_CHANGE } reqs := w.reqs[reqType] if reqs == nil { reqs = make([]*GrpcRequest, 0, 16) } reqs = append(reqs, req) w.reqs[reqType] = reqs case ev := <-w.ch: sendMultiPaths := func(reqType watcherEventType, dsts [][]*table.Path) { for _, dst := range dsts { paths := make([]*api.Path, 0, len(dst)) for _, path := range dst { paths = append(paths, path.ToApiStruct(table.GLOBAL_RIB_NAME)) } if len(paths) == 0 { continue } remains := make([]*GrpcRequest, 0, len(w.reqs[reqType])) result := &GrpcResponse{ Data: &api.Destination{ Prefix: dst[0].GetNlri().String(), Paths: paths, }, } for _, req := range w.reqs[reqType] { select { case <-req.EndCh: continue default: } remains = append(remains, req) if req.RouteFamily != bgp.RouteFamily(0) && req.RouteFamily != dst[0].GetRouteFamily() { continue } if req.Name != "" && req.Name != paths[0].NeighborIp { continue } req.ResponseCh <- result } w.reqs[reqType] = remains } } sendPaths := func(reqType watcherEventType, paths []*table.Path) { dsts := make([][]*table.Path, 0, len(paths)) for _, path := range paths { if path == nil { continue } dsts = append(dsts, []*table.Path{path}) } sendMultiPaths(reqType, dsts) } switch msg := ev.(type) { case *watcherEventBestPathMsg: if table.UseMultiplePaths.Enabled { sendMultiPaths(WATCHER_EVENT_BESTPATH_CHANGE, msg.multiPathList) } else { sendPaths(WATCHER_EVENT_BESTPATH_CHANGE, msg.pathList) } case *watcherEventUpdateMsg: if msg.postPolicy { sendPaths(WATCHER_EVENT_POST_POLICY_UPDATE_MSG, msg.pathList) } else { sendPaths(WATCHER_EVENT_UPDATE_MSG, msg.pathList) } case *watcherEventStateChangedMsg: peer := &api.Peer{ Conf: &api.PeerConf{ PeerAs: msg.peerAS, LocalAs: msg.localAS, NeighborAddress: msg.peerAddress.String(), Id: msg.peerID.String(), }, Info: &api.PeerState{ PeerAs: msg.peerAS, LocalAs: msg.localAS, NeighborAddress: msg.peerAddress.String(), BgpState: msg.state.String(), AdminState: msg.adminState.String(), }, Transport: &api.Transport{ LocalAddress: msg.localAddress.String(), LocalPort: uint32(msg.localPort), RemotePort: uint32(msg.peerPort), }, } reqType := WATCHER_EVENT_STATE_CHANGE remains := make([]*GrpcRequest, 0, len(w.reqs[reqType])) result := &GrpcResponse{ Data: peer, } for _, req := range w.reqs[reqType] { select { case <-req.EndCh: continue default: } remains = append(remains, req) if req.Name != "" && req.Name != peer.Conf.NeighborAddress { continue } req.ResponseCh <- result } w.reqs[reqType] = remains } } } }
func showNeighbor(args []string) error { p, e := getNeighbor(args[0]) if e != nil { return e } if globalOpts.Json { j, _ := json.Marshal(p) fmt.Println(string(j)) return nil } fmt.Printf("BGP neighbor is %s, remote AS %d\n", p.Conf.RemoteIp, p.Conf.RemoteAs) id := "unknown" if p.Conf.Id != nil { id = p.Conf.Id.String() } fmt.Printf(" BGP version 4, remote router ID %s\n", id) fmt.Printf(" BGP state = %s, up for %s\n", p.Info.BgpState, formatTimedelta(int64(p.Timers.State.Uptime)-time.Now().Unix())) fmt.Printf(" BGP OutQ = %d, Flops = %d\n", p.Info.OutQ, p.Info.Flops) fmt.Printf(" Hold time is %d, keepalive interval is %d seconds\n", p.Timers.State.NegotiatedHoldTime, p.Timers.State.KeepaliveInterval) fmt.Printf(" Configured hold time is %d, keepalive interval is %d seconds\n", p.Timers.Config.HoldTime, p.Timers.Config.KeepaliveInterval) fmt.Printf(" Neighbor capabilities:\n") caps := capabilities{} lookup := func(val bgp.ParameterCapabilityInterface, l capabilities) bgp.ParameterCapabilityInterface { for _, v := range l { if v.Code() == val.Code() { if v.Code() == bgp.BGP_CAP_MULTIPROTOCOL { lhs := v.(*bgp.CapMultiProtocol).CapValue rhs := val.(*bgp.CapMultiProtocol).CapValue if lhs == rhs { return v } continue } return v } } return nil } for _, c := range p.Conf.LocalCap { caps = append(caps, c) } for _, c := range p.Conf.RemoteCap { if lookup(c, caps) == nil { caps = append(caps, c) } } sort.Sort(caps) firstMp := true for _, c := range caps { support := "" if m := lookup(c, p.Conf.LocalCap); m != nil { support += "advertised" } if lookup(c, p.Conf.RemoteCap) != nil { if len(support) != 0 { support += " and " } support += "received" } switch c.Code() { case bgp.BGP_CAP_MULTIPROTOCOL: if firstMp { fmt.Printf(" %s:\n", c.Code()) firstMp = false } m := c.(*bgp.CapMultiProtocol).CapValue fmt.Printf(" %s:\t%s\n", m, support) case bgp.BGP_CAP_GRACEFUL_RESTART: fmt.Printf(" %s:\t%s\n", c.Code(), support) grStr := func(g *bgp.CapGracefulRestart) string { str := "" if len(g.Tuples) > 0 { str += fmt.Sprintf("restart time %d sec", g.Time) } if g.Flags == 0x08 { if len(str) > 0 { str += ", " } str += "restart flag set" } if len(str) > 0 { str += "\n" } for _, t := range g.Tuples { str += fmt.Sprintf(" %s", bgp.AfiSafiToRouteFamily(t.AFI, t.SAFI)) if t.Flags == 0x80 { str += ", forward flag set" } str += "\n" } return str } if m := lookup(c, p.Conf.LocalCap); m != nil { g := m.(*bgp.CapGracefulRestart) if s := grStr(g); len(s) > 0 { fmt.Printf(" Local: %s", s) } } if m := lookup(c, p.Conf.RemoteCap); m != nil { g := m.(*bgp.CapGracefulRestart) if s := grStr(g); len(s) > 0 { fmt.Printf(" Remote: %s", s) } } default: fmt.Printf(" %s:\t%s\n", c.Code(), support) } } fmt.Print(" Message statistics:\n") fmt.Print(" Sent Rcvd\n") fmt.Printf(" Opens: %10d %10d\n", p.Info.Messages.Sent.OPEN, p.Info.Messages.Received.OPEN) fmt.Printf(" Notifications: %10d %10d\n", p.Info.Messages.Sent.NOTIFICATION, p.Info.Messages.Received.NOTIFICATION) fmt.Printf(" Updates: %10d %10d\n", p.Info.Messages.Sent.UPDATE, p.Info.Messages.Received.UPDATE) fmt.Printf(" Keepalives: %10d %10d\n", p.Info.Messages.Sent.KEEPALIVE, p.Info.Messages.Received.KEEPALIVE) fmt.Printf(" Route Refesh: %10d %10d\n", p.Info.Messages.Sent.REFRESH, p.Info.Messages.Received.REFRESH) fmt.Printf(" Discarded: %10d %10d\n", p.Info.Messages.Sent.DISCARDED, p.Info.Messages.Received.DISCARDED) fmt.Printf(" Total: %10d %10d\n", p.Info.Messages.Sent.TOTAL, p.Info.Messages.Received.TOTAL) fmt.Print(" Route statistics:\n") fmt.Printf(" Advertised: %10d\n", p.Info.Advertised) fmt.Printf(" Received: %10d\n", p.Info.Received) fmt.Printf(" Accepted: %10d\n", p.Info.Accepted) if len(p.Conf.PrefixLimits) > 0 { fmt.Println(" Prefix Limits:") for _, c := range p.Conf.PrefixLimits { fmt.Printf(" %s:\tMaximum prefixes allowed %d", bgp.RouteFamily(c.Family), c.MaxPrefixes) if c.ShutdownThresholdPct > 0 { fmt.Printf(", Threshold for warning message %d%%\n", c.ShutdownThresholdPct) } else { fmt.Printf("\n") } } } return nil }
func NewMonitorCmd() *cobra.Command { monitor := func(recver interface { Recv() (*table.Destination, error) }) { for { dst, err := recver.Recv() if err == io.EOF { break } else if err != nil { exitWithError(err) } if globalOpts.Json { j, _ := json.Marshal(dst.GetAllKnownPathList()) fmt.Println(string(j)) } else { ShowRoute(dst.GetAllKnownPathList(), false, false, false, true, false) } } } ribCmd := &cobra.Command{ Use: CMD_RIB, Run: func(cmd *cobra.Command, args []string) { family, err := checkAddressFamily(bgp.RouteFamily(0)) if err != nil { exitWithError(err) } recver, err := client.MonitorRIB(family) if err != nil { exitWithError(err) } monitor(recver) }, } ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family") globalCmd := &cobra.Command{ Use: CMD_GLOBAL, } globalCmd.AddCommand(ribCmd) neighborCmd := &cobra.Command{ Use: CMD_NEIGHBOR, Run: func(cmd *cobra.Command, args []string) { var names []string if len(args) > 0 { names = []string{args[0]} } stream, err := client.MonitorNeighborState(names...) if err != nil { exitWithError(err) } for { s, err := stream.Recv() if err == io.EOF { break } else if err != nil { exitWithError(err) } if globalOpts.Json { j, _ := json.Marshal(s) fmt.Println(string(j)) } else { fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Config.NeighborAddress, s.State.SessionState, s.State.AdminState) } } }, } adjInCmd := &cobra.Command{ Use: CMD_ADJ_IN, Run: func(cmd *cobra.Command, args []string) { name := "" if len(args) > 0 { remoteIP := net.ParseIP(args[0]) if remoteIP == nil { exitWithError(fmt.Errorf("invalid ip address: %s", args[0])) } name = args[0] } family, err := checkAddressFamily(bgp.RouteFamily(0)) if err != nil { exitWithError(err) } recver, err := client.MonitorAdjRIBIn(name, family) if err != nil { exitWithError(err) } monitor(recver) }, } adjInCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family") monitorCmd := &cobra.Command{ Use: CMD_MONITOR, } monitorCmd.AddCommand(globalCmd) monitorCmd.AddCommand(neighborCmd) monitorCmd.AddCommand(adjInCmd) return monitorCmd }
func main() { sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGUSR1) var opts struct { ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"` ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"` LogLevel string `short:"l" long:"log-level" description:"specifying log level"` LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"` UseSyslog string `short:"s" long:"syslog" description:"use syslogd"` Facility string `long:"syslog-facility" description:"specify syslog facility"` DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"` CPUs int `long:"cpus" description:"specify the number of CPUs to be used"` Ops bool `long:"openswitch" description:"openswitch mode"` GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"` GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"` Dry bool `short:"d" long:"dry-run" description:"check configuration"` PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof" default:"localhost:6060"` PProfDisable bool `long:"pprof-disable" description:"disable pprof profiling"` } _, err := flags.Parse(&opts) if err != nil { os.Exit(1) } if opts.CPUs == 0 { runtime.GOMAXPROCS(runtime.NumCPU()) } else { if runtime.NumCPU() < opts.CPUs { log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs) os.Exit(1) } runtime.GOMAXPROCS(opts.CPUs) } if !opts.PProfDisable { go func() { log.Println(http.ListenAndServe(opts.PProfHost, nil)) }() } switch opts.LogLevel { case "debug": log.SetLevel(log.DebugLevel) case "info": log.SetLevel(log.InfoLevel) default: log.SetLevel(log.InfoLevel) } if opts.DisableStdlog == true { log.SetOutput(ioutil.Discard) } else { log.SetOutput(os.Stdout) } if opts.UseSyslog != "" { dst := strings.SplitN(opts.UseSyslog, ":", 2) network := "" addr := "" if len(dst) == 2 { network = dst[0] addr = dst[1] } facility := syslog.Priority(0) switch opts.Facility { case "kern": facility = syslog.LOG_KERN case "user": facility = syslog.LOG_USER case "mail": facility = syslog.LOG_MAIL case "daemon": facility = syslog.LOG_DAEMON case "auth": facility = syslog.LOG_AUTH case "syslog": facility = syslog.LOG_SYSLOG case "lpr": facility = syslog.LOG_LPR case "news": facility = syslog.LOG_NEWS case "uucp": facility = syslog.LOG_UUCP case "cron": facility = syslog.LOG_CRON case "authpriv": facility = syslog.LOG_AUTHPRIV case "ftp": facility = syslog.LOG_FTP case "local0": facility = syslog.LOG_LOCAL0 case "local1": facility = syslog.LOG_LOCAL1 case "local2": facility = syslog.LOG_LOCAL2 case "local3": facility = syslog.LOG_LOCAL3 case "local4": facility = syslog.LOG_LOCAL4 case "local5": facility = syslog.LOG_LOCAL5 case "local6": facility = syslog.LOG_LOCAL6 case "local7": facility = syslog.LOG_LOCAL7 } hook, err := logrus_syslog.NewSyslogHook(network, addr, syslog.LOG_INFO|facility, "bgpd") if err != nil { log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog) os.Exit(1) } else { log.AddHook(hook) } } if opts.LogPlain { if opts.DisableStdlog { log.SetFormatter(&log.TextFormatter{ DisableColors: true, }) } } else { log.SetFormatter(&log.JSONFormatter{}) } configCh := make(chan *config.BgpConfigSet) if opts.Dry { go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh) c := <-configCh if opts.LogLevel == "debug" { p.Println(c) } os.Exit(0) } log.Info("gobgpd started") bgpServer := server.NewBgpServer() go bgpServer.Serve() // start grpc Server grpcServer := api.NewGrpcServer(bgpServer, opts.GrpcHosts) go func() { if err := grpcServer.Serve(); err != nil { log.Fatalf("failed to listen grpc port: %s", err) } }() if opts.Ops { m, err := ops.NewOpsManager(opts.GrpcHosts) if err != nil { log.Errorf("Failed to start ops config manager: %s", err) os.Exit(1) } log.Info("Coordination with OpenSwitch") m.Serve() } else if opts.ConfigFile != "" { go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh) } var c *config.BgpConfigSet = nil for { select { case newConfig := <-configCh: var added, deleted, updated []config.Neighbor var updatePolicy bool if c == nil { c = newConfig if err := bgpServer.Start(&newConfig.Global); err != nil { log.Fatalf("failed to set global config: %s", err) } if newConfig.Zebra.Config.Enabled { if err := bgpServer.StartZebraClient(&newConfig.Zebra); err != nil { log.Fatalf("failed to set zebra config: %s", err) } } if len(newConfig.Collector.Config.Url) > 0 { if err := bgpServer.StartCollector(&newConfig.Collector.Config); err != nil { log.Fatalf("failed to set collector config: %s", err) } } for _, c := range newConfig.RpkiServers { if err := bgpServer.AddRpki(&c.Config); err != nil { log.Fatalf("failed to set rpki config: %s", err) } } for _, c := range newConfig.BmpServers { if err := bgpServer.AddBmp(&c.Config); err != nil { log.Fatalf("failed to set bmp config: %s", err) } } for _, c := range newConfig.MrtDump { if len(c.Config.FileName) == 0 { continue } if err := bgpServer.EnableMrt(&c.Config); err != nil { log.Fatalf("failed to set mrt config: %s", err) } } p := config.ConfigSetToRoutingPolicy(newConfig) if err := bgpServer.UpdatePolicy(*p); err != nil { log.Fatalf("failed to set routing policy: %s", err) } added = newConfig.Neighbors if opts.GracefulRestart { for i, n := range added { if n.GracefulRestart.Config.Enabled { added[i].GracefulRestart.State.LocalRestarting = true } } } } else { added, deleted, updated, updatePolicy = config.UpdateConfig(c, newConfig) if updatePolicy { log.Info("Policy config is updated") p := config.ConfigSetToRoutingPolicy(newConfig) bgpServer.UpdatePolicy(*p) } c = newConfig } for i, p := range added { log.Infof("Peer %v is added", p.Config.NeighborAddress) bgpServer.AddNeighbor(&added[i]) } for i, p := range deleted { log.Infof("Peer %v is deleted", p.Config.NeighborAddress) bgpServer.DeleteNeighbor(&deleted[i]) } for i, p := range updated { log.Infof("Peer %v is updated", p.Config.NeighborAddress) u, _ := bgpServer.UpdateNeighbor(&updated[i]) updatePolicy = updatePolicy || u } if updatePolicy { bgpServer.SoftResetIn("", bgp.RouteFamily(0)) } case sig := <-sigCh: switch sig { case syscall.SIGKILL, syscall.SIGTERM: bgpServer.Shutdown() case syscall.SIGUSR1: runtime.GC() debug.FreeOSMemory() } } } }