SEBA-910 Implementation of Create/Remove TrafficSchedulers
fix formating issue and bump verison to 0.0.16-dev
Updated Makefile fix proto dependency
print in table format
resolve merge conflict with igmp file
bump to 0.0.18-dev
remove overriding onu port no
rebase and update
Change-Id: Ie0dce516a7044cd4ed1de7bafcdcd292e5daf689
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 2c16872..b9c697c 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -53,7 +53,6 @@
 
 func (s BBSimServer) GetONU(ctx context.Context, req *bbsim.ONURequest) (*bbsim.ONU, error) {
 	olt := devices.GetOLT()
-
 	onu, err := olt.FindOnuBySn(req.SerialNumber)
 
 	if err != nil {
@@ -76,7 +75,7 @@
 }
 
 func (s BBSimServer) ShutdownONU(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
-	// NOTE this method is now sendying a Dying Gasp and then disabling the device (operState: down, adminState: up),
+	// NOTE this method is now sending a Dying Gasp and then disabling the device (operState: down, adminState: up),
 	// is this the only way to do? Should we address other cases?
 	// Investigate what happens when:
 	// - a fiber is pulled
@@ -209,8 +208,8 @@
 			event = "igmp_join_start"
 		case bbsim.SubActionTypes_LEAVE:
 			event = "igmp_leave"
-                case bbsim.SubActionTypes_JOINV3:
-                        event = "igmp_join_startv3"
+		case bbsim.SubActionTypes_JOINV3:
+			event = "igmp_join_startv3"
 		}
 
 		if igmpErr := onu.InternalState.Event(event); igmpErr != nil {
@@ -295,3 +294,21 @@
 
 	return res, nil
 }
+
+func (s BBSimServer) GetOnuTrafficSchedulers(ctx context.Context, req *bbsim.ONURequest) (*bbsim.ONUTrafficSchedulers, error) {
+	olt := devices.GetOLT()
+	ts := bbsim.ONUTrafficSchedulers{}
+
+	onu, err := olt.FindOnuBySn(req.SerialNumber)
+	if err != nil {
+		return &ts, err
+	}
+
+	if onu.TrafficSchedulers != nil {
+		ts.TraffSchedulers = onu.TrafficSchedulers
+		return &ts, nil
+	} else {
+		ts.TraffSchedulers = nil
+		return &ts, nil
+	}
+}
diff --git a/internal/bbsim/devices/messageTypes.go b/internal/bbsim/devices/messageTypes.go
index 31a09c5..4872af0 100644
--- a/internal/bbsim/devices/messageTypes.go
+++ b/internal/bbsim/devices/messageTypes.go
@@ -47,8 +47,8 @@
 	IGMPMembershipReportV2 MessageType = 15 // Version 2 Membership Report (JOIN)
 	IGMPLeaveGroup         MessageType = 16 // Leave Group
 
-	AlarmIndication MessageType = 17 // message data is an openolt.AlarmIndication
-        IGMPMembershipReportV3 MessageType = 18// Version 3 Membership Report
+	AlarmIndication        MessageType = 17 // message data is an openolt.AlarmIndication
+	IGMPMembershipReportV3 MessageType = 18 // Version 3 Membership Report
 )
 
 func (m MessageType) String() string {
@@ -70,7 +70,7 @@
 		"OnuPacketIn",
 		"IGMPMembershipReportV2",
 		"IGMPLeaveGroup",
-                "IGMPMembershipReportV3",
+		"IGMPMembershipReportV3",
 	}
 	return names[m]
 }
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 9acee9f..955d2ad 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -33,7 +33,7 @@
 	"github.com/opencord/bbsim/internal/common"
 	omcisim "github.com/opencord/omci-sim"
 	"github.com/opencord/voltha-protos/v2/go/openolt"
-	"github.com/opencord/voltha-protos/v2/go/tech_profile"
+	tech_profile "github.com/opencord/voltha-protos/v2/go/tech_profile"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/reflection"
@@ -69,6 +69,7 @@
 	enableContextCancel context.CancelFunc
 
 	OpenoltStream *openolt.Openolt_EnableIndicationServer
+	enablePerf    bool
 }
 
 var olt OltDevice
@@ -78,7 +79,7 @@
 	return &olt
 }
 
-func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, ca string, isMock bool) *OltDevice {
+func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, ca string, enablePerf bool, isMock bool) *OltDevice {
 	oltLogger.WithFields(log.Fields{
 		"ID":           oltId,
 		"NumNni":       nni,
@@ -98,6 +99,7 @@
 		Pons:         []*PonPort{},
 		Nnis:         []*NniPort{},
 		Delay:        delay,
+		enablePerf:   enablePerf,
 	}
 
 	if val, ok := ControlledActivationModes[ca]; ok {
@@ -1069,13 +1071,49 @@
 	return new(openolt.Empty), nil
 }
 
-func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
-	oltLogger.Info("received CreateTrafficSchedulers")
+func (s OltDevice) CreateTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
+	oltLogger.WithFields(log.Fields{
+		"OnuId":     trafficSchedulers.OnuId,
+		"IntfId":    trafficSchedulers.IntfId,
+		"OnuPortNo": trafficSchedulers.PortNo,
+	}).Info("received CreateTrafficSchedulers")
+
+	if !s.enablePerf {
+		pon, err := s.GetPonById(trafficSchedulers.IntfId)
+		if err != nil {
+			oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
+			return new(openolt.Empty), err
+		}
+		onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
+		if err != nil {
+			oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
+			return new(openolt.Empty), err
+		}
+		onu.TrafficSchedulers = trafficSchedulers
+	}
 	return new(openolt.Empty), nil
 }
 
-func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
-	oltLogger.Info("received RemoveTrafficSchedulers")
+func (s OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
+	oltLogger.WithFields(log.Fields{
+		"OnuId":     trafficSchedulers.OnuId,
+		"IntfId":    trafficSchedulers.IntfId,
+		"OnuPortNo": trafficSchedulers.PortNo,
+	}).Info("received RemoveTrafficSchedulers")
+	if !s.enablePerf {
+		pon, err := s.GetPonById(trafficSchedulers.IntfId)
+		if err != nil {
+			oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
+			return new(openolt.Empty), err
+		}
+		onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
+		if err != nil {
+			oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
+			return new(openolt.Empty), err
+		}
+
+		onu.TrafficSchedulers = nil
+	}
 	return new(openolt.Empty), nil
 }
 
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 3415083..c0bdb46 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -35,6 +35,7 @@
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
 	omcisim "github.com/opencord/omci-sim"
 	"github.com/opencord/voltha-protos/v2/go/openolt"
+	tech_profile "github.com/opencord/voltha-protos/v2/go/tech_profile"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -73,7 +74,8 @@
 	seqNumber  uint16
 	HasGemPort bool
 
-	DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
+	DoneChannel       chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
+	TrafficSchedulers *tech_profile.TrafficSchedulers
 }
 
 func (o *Onu) Sn() string {
@@ -256,12 +258,12 @@
 					Type: IGMPLeaveGroup}
 				o.Channel <- msg
 			},
-                        "igmp_join_startv3": func(e *fsm.Event) {
-                                msg := Message{
-                                        Type: IGMPMembershipReportV3,
-                                }
-                                o.Channel <- msg
-                        },
+			"igmp_join_startv3": func(e *fsm.Event) {
+				msg := Message{
+					Type: IGMPMembershipReportV3,
+				}
+				o.Channel <- msg
+			},
 		},
 	)
 
@@ -379,9 +381,9 @@
 			case IGMPLeaveGroup:
 				log.Infof("Recieved IGMPLeaveGroupV2 message on ONU channel")
 				igmp.SendIGMPLeaveGroupV2(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
-                        case IGMPMembershipReportV3:
-                                log.Infof("Recieved IGMPMembershipReportV3 message on ONU channel")
-                                igmp.SendIGMPMembershipReportV3(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
+			case IGMPMembershipReportV3:
+				log.Infof("Recieved IGMPMembershipReportV3 message on ONU channel")
+				igmp.SendIGMPMembershipReportV3(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
 			default:
 				onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
 			}
@@ -758,7 +760,7 @@
 		"OnuSn":   common.OnuSnToString(o.SerialNumber),
 		"Pkt":     msg.OmciInd.Pkt,
 		"msgType": msgType,
-	}).Trace("ONU Receveives OMCI Msg")
+	}).Trace("ONU Receives OMCI Msg")
 	switch msgType {
 	default:
 		log.WithFields(log.Fields{
diff --git a/internal/bbsim/responders/igmp/igmp.go b/internal/bbsim/responders/igmp/igmp.go
index a57810e..75f2759 100644
--- a/internal/bbsim/responders/igmp/igmp.go
+++ b/internal/bbsim/responders/igmp/igmp.go
@@ -15,14 +15,15 @@
 
 import (
 	"encoding/binary"
+	"net"
+	"time"
+
 	"github.com/google/gopacket"
 	"github.com/google/gopacket/layers"
 	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 	omci "github.com/opencord/omci-sim"
 	"github.com/opencord/voltha-protos/v2/go/openolt"
 	log "github.com/sirupsen/logrus"
-	"net"
-	"time"
 )
 
 func SendIGMPLeaveGroupV2(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, stream bbsim.Stream) error {
@@ -128,86 +129,86 @@
 }
 
 func SendIGMPMembershipReportV3(ponPortId uint32, onuId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, stream bbsim.Stream) error {
-       log.WithFields(log.Fields{
-               "OnuId": onuId,
-               "SerialNumber": serialNumber,
-               "PortNo": portNo,
-    }).Debugf("Entered SendIGMPMembershipReportV3")
-    igmp := createIGMPV3MembershipReportPacket()
-       pkt, err := serializeIgmpPacket(ponPortId, onuId, macAddress, igmp)
+	log.WithFields(log.Fields{
+		"OnuId":        onuId,
+		"SerialNumber": serialNumber,
+		"PortNo":       portNo,
+	}).Debugf("Entered SendIGMPMembershipReportV3")
+	igmp := createIGMPV3MembershipReportPacket()
+	pkt, err := serializeIgmpPacket(ponPortId, onuId, macAddress, igmp)
 
-       if err != nil {
-               log.WithFields(log.Fields{
-                        "OnuId":  onuId,
-                        "IntfId": ponPortId,
-                        "SerialNumber": serialNumber,
-                }).Errorf("Seriliazation of igmp packet failed :  %s", err)
-                return err
-       }
+	if err != nil {
+		log.WithFields(log.Fields{
+			"OnuId":        onuId,
+			"IntfId":       ponPortId,
+			"SerialNumber": serialNumber,
+		}).Errorf("Seriliazation of igmp packet failed :  %s", err)
+		return err
+	}
 
-       gemid, err := omci.GetGemPortId(ponPortId, onuId)
-       if err != nil {
-               log.WithFields(log.Fields{
-                       "OnuId":  onuId,
-                       "IntfId": ponPortId,
-                        "SerialNumber": serialNumber,
-               }).Errorf("Can't retrieve GemPortId for IGMP: %s", err)
-               return err
-       }
+	gemid, err := omci.GetGemPortId(ponPortId, onuId)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"OnuId":        onuId,
+			"IntfId":       ponPortId,
+			"SerialNumber": serialNumber,
+		}).Errorf("Can't retrieve GemPortId for IGMP: %s", err)
+		return err
+	}
 
-       data := &openolt.Indication_PktInd{
-               PktInd: &openolt.PacketIndication{
-                       IntfType:  "pon",
-                       IntfId:    ponPortId,
-                       GemportId: uint32(gemid),
-                       Pkt:       pkt,
-                       PortNo:    portNo,
-               },
-       }
-        //Sending IGMP packets
-        if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
-                log.Errorf("Fail to send IGMP PktInd indication for ONU: %s, IntfId: %s, SerialNumber: %s,  error: %v", onuId, ponPortId, serialNumber, err)
-                return err
-        }
-        return nil
+	data := &openolt.Indication_PktInd{
+		PktInd: &openolt.PacketIndication{
+			IntfType:  "pon",
+			IntfId:    ponPortId,
+			GemportId: uint32(gemid),
+			Pkt:       pkt,
+			PortNo:    portNo,
+		},
+	}
+	//Sending IGMP packets
+	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+		log.Errorf("Fail to send IGMP PktInd indication for ONU: %s, IntfId: %s, SerialNumber: %s,  error: %v", onuId, ponPortId, serialNumber, err)
+		return err
+	}
+	return nil
 }
 
 func createIGMPV3MembershipReportPacket() IGMP {
 
-       groupRecord1:= IGMPv3GroupRecord{
-           Type:             IGMPv3GroupRecordType(IGMPIsIn),
-           AuxDataLen:       0, // this should always be 0 as per IGMPv3 spec.
-           NumberOfSources:  3,
-           MulticastAddress: net.IPv4(224, 0, 0, 22),
-           SourceAddresses:  []net.IP{net.IPv4(15, 14, 20, 24), net.IPv4(15, 14, 20, 26), net.IPv4(15, 14, 20, 25)},
-           AuxData:          0, // NOT USED
-       }
+	groupRecord1 := IGMPv3GroupRecord{
+		Type:             IGMPv3GroupRecordType(IGMPIsIn),
+		AuxDataLen:       0, // this should always be 0 as per IGMPv3 spec.
+		NumberOfSources:  3,
+		MulticastAddress: net.IPv4(224, 0, 0, 22),
+		SourceAddresses:  []net.IP{net.IPv4(15, 14, 20, 24), net.IPv4(15, 14, 20, 26), net.IPv4(15, 14, 20, 25)},
+		AuxData:          0, // NOT USED
+	}
 
-       groupRecord2:= IGMPv3GroupRecord{
-           Type:             IGMPv3GroupRecordType(IGMPIsIn),
-           AuxDataLen:       0, // this should always be 0 as per IGMPv3 spec.
-           NumberOfSources:  2,
-           MulticastAddress: net.IPv4(224, 0, 0, 25),
-           SourceAddresses:  []net.IP{net.IPv4(15, 14, 20, 30), net.IPv4(15, 14, 20, 31)},
-           AuxData:          0, // NOT USED
-       }
+	groupRecord2 := IGMPv3GroupRecord{
+		Type:             IGMPv3GroupRecordType(IGMPIsIn),
+		AuxDataLen:       0, // this should always be 0 as per IGMPv3 spec.
+		NumberOfSources:  2,
+		MulticastAddress: net.IPv4(224, 0, 0, 25),
+		SourceAddresses:  []net.IP{net.IPv4(15, 14, 20, 30), net.IPv4(15, 14, 20, 31)},
+		AuxData:          0, // NOT USED
+	}
 
-       igmpDefault := IGMP{
-               Type:                    0x22, //IGMPV3 Membership Report
-               MaxResponseTime:         time.Duration(1),
-               Checksum:                0,
-               GroupAddress:            net.IPv4(224, 0, 0, 22),
-               SupressRouterProcessing: false,
-               RobustnessValue:         0,
-               IntervalTime:            time.Duration(1),
-               SourceAddresses:         []net.IP{net.IPv4(224, 0, 0, 24)},
-               NumberOfGroupRecords:    2,
-               NumberOfSources:         1,
-               GroupRecords:            []IGMPv3GroupRecord{groupRecord1, groupRecord2},
-               Version:                 3,
-       }
+	igmpDefault := IGMP{
+		Type:                    0x22, //IGMPV3 Membership Report
+		MaxResponseTime:         time.Duration(1),
+		Checksum:                0,
+		GroupAddress:            net.IPv4(224, 0, 0, 22),
+		SupressRouterProcessing: false,
+		RobustnessValue:         0,
+		IntervalTime:            time.Duration(1),
+		SourceAddresses:         []net.IP{net.IPv4(224, 0, 0, 24)},
+		NumberOfGroupRecords:    2,
+		NumberOfSources:         1,
+		GroupRecords:            []IGMPv3GroupRecord{groupRecord1, groupRecord2},
+		Version:                 3,
+	}
 
-       return igmpDefault
+	return igmpDefault
 }
 
 //func serializeIgmpPacket(intfId uint32, onuId uint32, srcMac net.HardwareAddr, igmp *layers.IGMP) ([]byte, error) {
@@ -290,96 +291,96 @@
 	SourceAddresses         []net.IP
 	NumberOfGroupRecords    uint16
 	NumberOfSources         uint16
-        GroupRecords            []IGMPv3GroupRecord
+	GroupRecords            []IGMPv3GroupRecord
 	Version                 uint8 // IGMP protocol version
 }
 
 // IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
 type IGMPv3GroupRecord struct {
-       Type             IGMPv3GroupRecordType
-       AuxDataLen       uint8 // this should always be 0 as per IGMPv3 spec.
-       NumberOfSources  uint16
-       MulticastAddress net.IP
-       SourceAddresses  []net.IP
-       AuxData          uint32 // NOT USED
+	Type             IGMPv3GroupRecordType
+	AuxDataLen       uint8 // this should always be 0 as per IGMPv3 spec.
+	NumberOfSources  uint16
+	MulticastAddress net.IP
+	SourceAddresses  []net.IP
+	AuxData          uint32 // NOT USED
 }
 
 type IGMPv3GroupRecordType uint8
 
 const (
-       IGMPIsIn  IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
-       IGMPIsEx  IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
-       IGMPToIn  IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
-       IGMPToEx  IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
-       IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
-       IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
+	IGMPIsIn  IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
+	IGMPIsEx  IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
+	IGMPToIn  IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
+	IGMPToEx  IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
+	IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
+	IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
 )
 
 func (i IGMPv3GroupRecordType) String() string {
-       switch i {
-       case IGMPIsIn:
-               return "MODE_IS_INCLUDE"
-       case IGMPIsEx:
-               return "MODE_IS_EXCLUDE"
-       case IGMPToIn:
-               return "CHANGE_TO_INCLUDE_MODE"
-       case IGMPToEx:
-               return "CHANGE_TO_EXCLUDE_MODE"
-       case IGMPAllow:
-               return "ALLOW_NEW_SOURCES"
-       case IGMPBlock:
-               return "BLOCK_OLD_SOURCES"
-       default:
-               return ""
-       }
+	switch i {
+	case IGMPIsIn:
+		return "MODE_IS_INCLUDE"
+	case IGMPIsEx:
+		return "MODE_IS_EXCLUDE"
+	case IGMPToIn:
+		return "CHANGE_TO_INCLUDE_MODE"
+	case IGMPToEx:
+		return "CHANGE_TO_EXCLUDE_MODE"
+	case IGMPAllow:
+		return "ALLOW_NEW_SOURCES"
+	case IGMPBlock:
+		return "BLOCK_OLD_SOURCES"
+	default:
+		return ""
+	}
 }
 
 // SerializeTo writes the serialized form of this layer into the
 // SerializationBuffer, implementing gopacket.SerializableLayer.
 // See the docs for gopacket.SerializableLayer for more info.
 func (igmp IGMP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
-        log.Debugf("Serializing IGMP Packet")
+	log.Debugf("Serializing IGMP Packet")
 	data, err := b.PrependBytes(8915)
-        if err != nil {
-                return err
-        }
-        if igmp.Version == 2 {
-                data[0] = byte(igmp.Type)
-                data[1] = byte(igmp.MaxResponseTime)
-                data[2] = 0
-                data[3] = 0
-                copy(data[4:8], igmp.GroupAddress.To4())
-                if opts.ComputeChecksums {
-                        igmp.Checksum = tcpipChecksum(data, 0)
-                        binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
-                }
-        } else if igmp.Version ==3{
+	if err != nil {
+		return err
+	}
+	if igmp.Version == 2 {
+		data[0] = byte(igmp.Type)
+		data[1] = byte(igmp.MaxResponseTime)
+		data[2] = 0
+		data[3] = 0
+		copy(data[4:8], igmp.GroupAddress.To4())
+		if opts.ComputeChecksums {
+			igmp.Checksum = tcpipChecksum(data, 0)
+			binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
+		}
+	} else if igmp.Version == 3 {
 
-                data[0] = byte(igmp.Type)
-                data[1] = 0
-                data[2] = 0
-                data[3] = 0
-                data[4] = 0
-                data[5] = 0
-                binary.BigEndian.PutUint16(data[6:8], igmp.NumberOfGroupRecords)
-                j := 8
-                for i := uint16(0); i < igmp.NumberOfGroupRecords; i++ {
-                        data[j] = byte(igmp.GroupRecords[i].Type)
-                        data[j+1] = byte(0)
-                        binary.BigEndian.PutUint16(data[j+2:j+4], igmp.GroupRecords[i].NumberOfSources)
-                        copy(data[j+4:j+8], igmp.GroupRecords[i].MulticastAddress.To4())
-                        j=j+8
-                        for m := uint16(0); m < igmp.GroupRecords[i].NumberOfSources; m++ {
-                                copy(data[j:(j+4)], igmp.GroupRecords[i].SourceAddresses[m].To4())
-                                j=j+4
-                        }
-                }
-                if opts.ComputeChecksums {
-                        igmp.Checksum = tcpipChecksum(data, 0)
-                        binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
-                }
-        }
-        return nil
+		data[0] = byte(igmp.Type)
+		data[1] = 0
+		data[2] = 0
+		data[3] = 0
+		data[4] = 0
+		data[5] = 0
+		binary.BigEndian.PutUint16(data[6:8], igmp.NumberOfGroupRecords)
+		j := 8
+		for i := uint16(0); i < igmp.NumberOfGroupRecords; i++ {
+			data[j] = byte(igmp.GroupRecords[i].Type)
+			data[j+1] = byte(0)
+			binary.BigEndian.PutUint16(data[j+2:j+4], igmp.GroupRecords[i].NumberOfSources)
+			copy(data[j+4:j+8], igmp.GroupRecords[i].MulticastAddress.To4())
+			j = j + 8
+			for m := uint16(0); m < igmp.GroupRecords[i].NumberOfSources; m++ {
+				copy(data[j:(j+4)], igmp.GroupRecords[i].SourceAddresses[m].To4())
+				j = j + 4
+			}
+		}
+		if opts.ComputeChecksums {
+			igmp.Checksum = tcpipChecksum(data, 0)
+			binary.BigEndian.PutUint16(data[2:4], igmp.Checksum)
+		}
+	}
+	return nil
 }
 
 // Calculate the TCP/IP checksum defined in rfc1071.  The passed-in csum is any
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index fec47ed..9e41990 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -20,14 +20,17 @@
 import (
 	"context"
 	"fmt"
+	"os"
+	"strconv"
+	"strings"
+
 	"github.com/jessevdk/go-flags"
+	"github.com/olekukonko/tablewriter"
 	pb "github.com/opencord/bbsim/api/bbsim"
 	"github.com/opencord/bbsim/internal/bbsimctl/config"
 	"github.com/opencord/cordctl/pkg/format"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
-	"os"
-	"strings"
 )
 
 const (
@@ -81,13 +84,20 @@
 }
 
 type ONUOptions struct {
-	List         ONUList         `command:"list"`
-	Get          ONUGet          `command:"get"`
-	ShutDown     ONUShutDown     `command:"shutdown"`
-	PowerOn      ONUPowerOn      `command:"poweron"`
-	RestartEapol ONUEapolRestart `command:"auth_restart"`
-	RestartDchp  ONUDhcpRestart  `command:"dhcp_restart"`
-	Igmp         ONUIgmp         `command:"igmp"`
+	List              ONUList              `command:"list"`
+	Get               ONUGet               `command:"get"`
+	ShutDown          ONUShutDown          `command:"shutdown"`
+	PowerOn           ONUPowerOn           `command:"poweron"`
+	RestartEapol      ONUEapolRestart      `command:"auth_restart"`
+	RestartDchp       ONUDhcpRestart       `command:"dhcp_restart"`
+	Igmp              ONUIgmp              `command:"igmp"`
+	TrafficSchedulers ONUTrafficSchedulers `command:"traffic_schedulers"`
+}
+
+type ONUTrafficSchedulers struct {
+	Args struct {
+		OnuSn OnuSnString
+	} `positional-args:"yes" required:"yes"`
 }
 
 func RegisterONUCommands(parser *flags.Parser) {
@@ -258,9 +268,9 @@
 		subActionVal = pb.SubActionTypes_JOIN
 	} else if string(options.Args.SubAction) == IgmpLeaveKey {
 		subActionVal = pb.SubActionTypes_LEAVE
-        } else if string(options.Args.SubAction) == IgmpJoinKeyV3 {
-                subActionVal = pb.SubActionTypes_JOINV3
-        }
+	} else if string(options.Args.SubAction) == IgmpJoinKeyV3 {
+		subActionVal = pb.SubActionTypes_JOINV3
+	}
 
 	igmpReq := pb.IgmpRequest{
 		OnuReq:       &req,
@@ -313,3 +323,86 @@
 
 	return list
 }
+
+func (options *ONUTrafficSchedulers) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+	req := pb.ONURequest{
+		SerialNumber: string(options.Args.OnuSn),
+	}
+	res, err := client.GetOnuTrafficSchedulers(ctx, &req)
+	if err != nil {
+		log.Fatalf("Cannot get traffic schedulers for ONU %s: %v", options.Args.OnuSn, err)
+		return err
+	}
+
+	if res.TraffSchedulers == nil {
+		log.Fatalf("Cannot get traffic schedulers for ONU: %s (unavailable)", options.Args.OnuSn)
+		return nil
+	}
+
+	SchedulerHeader := []string{"Direction",
+		"AllocId",
+		"Scheduler.Direction",
+		"Scheduler.AdditionalBw",
+		"Scheduler.Priority",
+		"Scheduler.Weight",
+		"Scheduler.SchedPolicy",
+	}
+
+	ShapingInfoHeader := []string{"InferredAdditionBwIndication",
+		"Cbs",
+		"Cir",
+		"Gir",
+		"Pbs",
+		"Pir",
+	}
+
+	SchedulerVals := []string{}
+	ShapingInfoVals := []string{}
+	for _, v := range res.TraffSchedulers.TrafficScheds {
+		SchedulerVals = append(SchedulerVals,
+			v.GetDirection().String(),
+			strconv.Itoa(int(v.GetAllocId())),
+			v.Scheduler.GetDirection().String(),
+			v.Scheduler.GetAdditionalBw().String(),
+			strconv.Itoa(int(v.Scheduler.GetPriority())),
+			strconv.Itoa(int(v.Scheduler.GetWeight())),
+			v.GetScheduler().GetSchedPolicy().String(),
+		)
+
+		ShapingInfoVals = append(ShapingInfoVals,
+			v.TrafficShapingInfo.GetAddBwInd().String(),
+			strconv.Itoa(int(v.TrafficShapingInfo.GetCbs())),
+			strconv.Itoa(int(v.TrafficShapingInfo.GetCir())),
+			strconv.Itoa(int(v.TrafficShapingInfo.GetGir())),
+			strconv.Itoa(int(v.TrafficShapingInfo.GetPbs())),
+			strconv.Itoa(int(v.TrafficShapingInfo.GetPir())),
+		)
+	}
+
+	fmt.Fprintf(os.Stdout, "OnuId: %d \n", int(res.TraffSchedulers.OnuId))
+	fmt.Fprintf(os.Stdout, "IntfId: %d \n", int(res.TraffSchedulers.IntfId))
+	fmt.Fprintf(os.Stdout, "UniId: %d \n", int(res.TraffSchedulers.UniId))
+	fmt.Fprintf(os.Stdout, "OnuPortNo: %d \n", int(res.TraffSchedulers.PortNo))
+
+	tableSched := tablewriter.NewWriter(os.Stdout)
+	tableSched.SetRowLine(true)
+	fmt.Fprintf(os.Stdout, "Traffic Schedulers Info:\n")
+	tableSched.SetHeader(SchedulerHeader)
+	tableSched.Append(SchedulerVals)
+	tableSched.Render()
+	tableSched.SetNewLine("")
+
+	tableShap := tablewriter.NewWriter(os.Stdout)
+	tableShap.SetRowLine(true)
+	fmt.Fprintf(os.Stdout, "Traffic Shaping Info:\n")
+	tableShap.SetHeader(ShapingInfoHeader)
+	tableShap.Append(ShapingInfoVals)
+	tableShap.Render()
+
+	return nil
+}
diff --git a/internal/common/options.go b/internal/common/options.go
index 648c5cf..d5317e1 100644
--- a/internal/common/options.go
+++ b/internal/common/options.go
@@ -71,6 +71,7 @@
 	SadisRestAddress     string  `yaml:"sadis_rest_address"`
 	SadisServer          bool    `yaml:"sadis_server"`
 	ControlledActivation string  `yaml:"controlled_activation"`
+	EnablePerf           bool    `yaml:"enable_perf"`
 }
 
 type BBRConfig struct {
@@ -105,6 +106,7 @@
 			SadisRestAddress:     ":50074",
 			SadisServer:          true,
 			ControlledActivation: "default",
+			EnablePerf:           false,
 		},
 		OltConfig{
 			Vendor:             "BBSim",
@@ -145,7 +147,7 @@
 	return yamlConfig, nil
 }
 
-// GetBBSimOpts loads the BBSim configuration file and overides options with corresponding CLI flags if set
+// GetBBSimOpts loads the BBSim configuration file and over-rides options with corresponding CLI flags if set
 func GetBBSimOpts() *BBSimYamlConfig {
 	conf := Options
 
@@ -168,6 +170,7 @@
 	delay := flag.Int("delay", conf.BBSim.Delay, "The delay between ONU DISCOVERY batches in milliseconds (1 ONU per each PON PORT at a time")
 
 	controlledActivation := flag.String("ca", conf.BBSim.ControlledActivation, "Set the mode for controlled activation of PON ports and ONUs")
+	enablePerf := flag.Bool("enableperf", conf.BBSim.EnablePerf, "Setting this flag will cause BBSim to not store data like traffic schedulers, flows of ONUs etc..")
 	flag.Parse()
 
 	conf.Olt.ID = int(*olt_id)
@@ -183,6 +186,7 @@
 	conf.BBSim.EnableDhcp = *dhcp
 	conf.BBSim.Delay = *delay
 	conf.BBSim.ControlledActivation = *controlledActivation
+	conf.BBSim.EnablePerf = *enablePerf
 
 	// update device id if not set
 	if conf.Olt.DeviceId == "" {